001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020 package org.apache.geronimo.mavenplugins.geronimo.server; 021 022 import java.io.File; 023 024 import java.util.Timer; 025 import java.util.TimerTask; 026 import java.util.Map; 027 import java.util.HashMap; 028 import java.util.Properties; 029 import java.util.Iterator; 030 import java.util.StringTokenizer; 031 import java.util.List; 032 import java.util.ArrayList; 033 034 import org.apache.maven.plugin.MojoExecutionException; 035 036 import org.apache.tools.ant.taskdefs.Java; 037 038 import org.codehaus.mojo.pluginsupport.util.ObjectHolder; 039 040 import org.apache.geronimo.mavenplugins.geronimo.ServerProxy; 041 042 import org.codehaus.plexus.util.FileUtils; 043 044 import org.apache.commons.lang.time.StopWatch; 045 046 /** 047 * Start the Geronimo server. 048 * 049 * @goal start-server 050 * 051 * @version $Rev: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $ 052 */ 053 public class StartServerMojo 054 extends InstallerMojoSupport 055 { 056 /** 057 * Set the false to skip the installation of the assembly, re-using anything 058 * that is already there. 059 * 060 * @parameter expression="${install}" default-value="true" 061 */ 062 private boolean install = true; 063 064 /** 065 * Flag to control if we background the server or block Maven execution. 066 * 067 * @parameter expression="${background}" default-value="false" 068 */ 069 private boolean background = false; 070 071 /** 072 * Set the maximum memory for the forked JVM. 073 * 074 * @parameter expression="${maximumMemory}" 075 */ 076 private String maximumMemory = null; 077 078 /** 079 * The location of the Java Virtual Machine executable to launch the server with. 080 * 081 * @parameter 082 */ 083 private File javaVirtualMachine; 084 085 /** 086 * Enable quiet mode. 087 * 088 * @parameter expression="${quiet}" default-value="false" 089 */ 090 private boolean quiet = false; 091 092 /** 093 * Enable verbose mode. 094 * 095 * @parameter expression="${verbose}" default-value="false" 096 */ 097 private boolean verbose = false; 098 099 /** 100 * Enable veryverbose mode. 101 * 102 * @parameter expression="${veryverbose}" default-value="false" 103 */ 104 private boolean veryverbose = false; 105 106 /** 107 * Time in seconds to wait before terminating the forked JVM. 108 * 109 * @parameter expression="${timeout}" default-value="-1" 110 */ 111 private int timeout = -1; 112 113 /** 114 * Time in seconds to wait while verifing that the server has started. 115 * 116 * @parameter expression="${verifyTimeout}" default-value="-1" 117 */ 118 private int verifyTimeout = -1; 119 120 /** 121 * Enable propagation of <tt>org.apache.geronimo.*</tt> and <tt>geronimo.*</tt> 122 * properties from Maven to the forked server process. 123 * 124 * @parameter expression="${propagateGeronimoProperties}" default-value="true" 125 */ 126 private boolean propagateGeronimoProperties; 127 128 /** 129 * An array of option sets which can be enabled by setting optionSetId. 130 * 131 * @parameter 132 */ 133 private OptionSet[] optionSets = null; 134 135 /** 136 * A comma seperated list of optionSets to enabled. 137 * 138 * @parameter expression="${options}" 139 */ 140 private String options = null; 141 142 /** 143 * A list of module names to be started using --override. 144 * 145 * @parameter 146 */ 147 private String[] startModules = null; 148 149 private Timer timer = new Timer(true); 150 151 protected void doExecute() throws Exception { 152 if (install) { 153 installAssembly(); 154 } 155 else { 156 log.info("Skipping assembly installation"); 157 158 if (!geronimoHome.exists()) { 159 throw new MojoExecutionException("Missing pre-installed assembly directory: " + geronimoHome); 160 } 161 } 162 163 log.info("Starting Geronimo server..."); 164 165 // Setup the JVM to start the server with 166 final Java java = (Java)createTask("java"); 167 java.setJar(new File(geronimoHome, "bin/server.jar")); 168 java.setDir(geronimoHome); 169 java.setFailonerror(true); 170 java.setFork(true); 171 172 if (javaVirtualMachine != null) { 173 if (!javaVirtualMachine.exists()) { 174 throw new MojoExecutionException("Java virtual machine is not valid: " + javaVirtualMachine); 175 } 176 177 log.info("Using Java virtual machine: " + javaVirtualMachine); 178 java.setJvm(javaVirtualMachine.getCanonicalPath()); 179 } 180 181 if (timeout > 0) { 182 java.setTimeout(new Long(timeout * 1000)); 183 } 184 185 if (maximumMemory != null) { 186 java.setMaxmemory(maximumMemory); 187 } 188 189 // Load the Java programming language agent for JPA 190 File javaAgentJar = new File(geronimoHome, "bin/jpa.jar"); 191 if (javaAgentJar.exists()) { 192 java.createJvmarg().setValue("-javaagent:" + javaAgentJar.getCanonicalPath()); 193 } 194 195 // Propagate some properties from Maven to the server if enabled 196 if (propagateGeronimoProperties) { 197 Properties props = System.getProperties(); 198 Iterator iter = props.keySet().iterator(); 199 while (iter.hasNext()) { 200 String name = (String)iter.next(); 201 String value = System.getProperty(name); 202 203 if (name.equals("geronimo.bootstrap.logging.enabled")) { 204 // Skip this property, never propagate it 205 } 206 else if (name.startsWith("org.apache.geronimo") || name.startsWith("geronimo")) { 207 if (log.isDebugEnabled()) { 208 log.debug("Propagating: " + name + "=" + value); 209 } 210 setSystemProperty(java, name, value); 211 } 212 } 213 } 214 215 // Apply option sets 216 if (options != null && (optionSets == null || optionSets.length == 0)) { 217 throw new MojoExecutionException("At least one optionSet must be defined to select one using options"); 218 } 219 else if (options == null) { 220 options = "default"; 221 } 222 223 if (optionSets != null && optionSets.length != 0) { 224 OptionSet[] sets = selectOptionSets(); 225 226 for (int i=0; i < sets.length; i++) { 227 if (log.isDebugEnabled()) { 228 log.debug("Selected option set: " + sets[i]); 229 } 230 else { 231 log.info("Selected option set: " + sets[i].getId()); 232 } 233 234 String[] options = sets[i].getOptions(); 235 if (options != null) { 236 for (int j=0; j < options.length; j++) { 237 java.createJvmarg().setValue(options[j]); 238 } 239 } 240 241 Properties props = sets[i].getProperties(); 242 if (props != null) { 243 Iterator iter = props.keySet().iterator(); 244 while (iter.hasNext()) { 245 String name = (String)iter.next(); 246 String value = props.getProperty(name); 247 248 setSystemProperty(java, name, value); 249 } 250 } 251 } 252 } 253 254 // Set the properties which we pass to the JVM from the startup script 255 setSystemProperty(java, "org.apache.geronimo.base.dir", geronimoHome); 256 // Use relative path 257 setSystemProperty(java, "java.io.tmpdir", "var/temp"); 258 setSystemProperty(java, "java.endorsed.dirs", prefixSystemPath("java.endorsed.dirs", new File(geronimoHome, "lib/endorsed"))); 259 setSystemProperty(java, "java.ext.dirs", prefixSystemPath("java.ext.dirs", new File(geronimoHome, "lib/ext"))); 260 261 if (quiet) { 262 java.createArg().setValue("--quiet"); 263 } 264 else { 265 java.createArg().setValue("--long"); 266 } 267 268 if (verbose) { 269 java.createArg().setValue("--verbose"); 270 } 271 272 if (veryverbose) { 273 java.createArg().setValue("--veryverbose"); 274 } 275 276 if (startModules != null) { 277 if (startModules.length == 0) { 278 throw new MojoExecutionException("At least one module name must be configured with startModule"); 279 } 280 281 log.info("Overriding the set of modules to be started"); 282 283 java.createArg().setValue("--override"); 284 285 for (int i=0; i < startModules.length; i++) { 286 java.createArg().setValue(startModules[i]); 287 } 288 } 289 290 // 291 // TODO: Check if this really does capture STDERR or not! 292 // 293 294 if (logOutput) { 295 File file = getLogFile(); 296 FileUtils.forceMkdir(file.getParentFile()); 297 298 log.info("Redirecting output to: " + file); 299 300 java.setOutput(file); 301 } 302 303 // Holds any exception that was thrown during startup 304 final ObjectHolder errorHolder = new ObjectHolder(); 305 306 StopWatch watch = new StopWatch(); 307 watch.start(); 308 309 // Start the server int a seperate thread 310 Thread t = new Thread("Geronimo Server Runner") { 311 public void run() { 312 try { 313 java.execute(); 314 } 315 catch (Exception e) { 316 errorHolder.set(e); 317 318 // 319 // NOTE: Don't log here, as when the JVM exists an exception will get thrown by Ant 320 // but that should be fine. 321 // 322 } 323 } 324 }; 325 t.start(); 326 327 log.info("Waiting for Geronimo server..."); 328 329 // Setup a callback to time out verification 330 final ObjectHolder verifyTimedOut = new ObjectHolder(); 331 332 TimerTask timeoutTask = new TimerTask() { 333 public void run() { 334 verifyTimedOut.set(Boolean.TRUE); 335 } 336 }; 337 338 if (verifyTimeout > 0) { 339 if (log.isDebugEnabled()) { 340 log.debug("Starting verify timeout task; triggers in: " + verifyTimeout + " seconds"); 341 } 342 timer.schedule(timeoutTask, verifyTimeout * 1000); 343 } 344 345 // Verify server started 346 ServerProxy server = new ServerProxy(hostname, port, username, password); 347 boolean started = false; 348 while (!started) { 349 if (verifyTimedOut.isSet()) { 350 throw new MojoExecutionException("Unable to verify if the server was started in the given time (" + verifyTimeout + " seconds)"); 351 } 352 353 if (errorHolder.isSet()) { 354 throw new MojoExecutionException("Failed to start Geronimo server", (Throwable)errorHolder.get()); 355 } 356 357 started = server.isFullyStarted(); 358 359 if (!started) { 360 Throwable error = server.getLastError(); 361 if ((error != null) && (log.isDebugEnabled())) { 362 log.debug("Server query failed; ignoring", error); 363 } 364 365 Thread.sleep(1000); 366 } 367 } 368 server.closeConnection(); 369 370 // Stop the timer, server should be up now 371 timeoutTask.cancel(); 372 373 log.info("Geronimo server started in " + watch); 374 375 if (!background) { 376 log.info("Waiting for Geronimo server to shutdown..."); 377 378 t.join(); 379 } 380 } 381 382 private String prefixSystemPath(final String name, final File file) { 383 assert name != null; 384 assert file != null; 385 386 String dirs = file.getPath(); 387 String prop = System.getProperty(name, ""); 388 if (prop.length() > 0) { 389 dirs += File.pathSeparator; 390 dirs += prop; 391 } 392 return dirs; 393 } 394 395 private OptionSet[] selectOptionSets() throws MojoExecutionException { 396 // Make a map of the option sets and validate ids 397 Map map = new HashMap(); 398 for (int i=0; i<optionSets.length; i++) { 399 if (log.isDebugEnabled()) { 400 log.debug("Checking option set: " + optionSets[i]); 401 } 402 403 String id = optionSets[i].getId(); 404 405 if (id == null && optionSets.length > 1) { 406 throw new MojoExecutionException("Must specify id for optionSet when more than one optionSet is configured"); 407 } 408 else if (id == null && optionSets.length == 1) { 409 id = "default"; 410 optionSets[i].setId(id); 411 } 412 413 assert id != null; 414 id = id.trim(); 415 416 if (map.containsKey(id)) { 417 throw new MojoExecutionException("Must specify unique id for optionSet: " + id); 418 } 419 map.put(id, optionSets[i]); 420 } 421 422 StringTokenizer stok = new StringTokenizer(options, ","); 423 424 List selected = new ArrayList(); 425 while (stok.hasMoreTokens()) { 426 String id = stok.nextToken(); 427 OptionSet set = (OptionSet)map.get(id); 428 429 if (set == null) { 430 if ("default".equals(id)) { 431 if (log.isDebugEnabled()) { 432 log.debug("Default optionSet selected, but no optionSet defined with that id; ignoring"); 433 } 434 } 435 else { 436 log.warn("Missing optionSet for id: " + id); 437 } 438 } 439 else { 440 selected.add(set); 441 } 442 } 443 444 return (OptionSet[]) selected.toArray(new OptionSet[selected.size()]); 445 } 446 447 protected String getFullClassName() { 448 return this.getClass().getName(); 449 } 450 }