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: 552399 $ $Date: 2007-07-02 00:31:56 -0400 (Mon, 02 Jul 2007) $ 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 * @paramter 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 log.debug("Propagating: " + name + "=" + value); 208 setSystemProperty(java, name, value); 209 } 210 } 211 } 212 213 // Apply option sets 214 if (options != null && (optionSets == null || optionSets.length == 0)) { 215 throw new MojoExecutionException("At least one optionSet must be defined to select one using options"); 216 } 217 else if (options == null) { 218 options = "default"; 219 } 220 221 if (optionSets != null && optionSets.length != 0) { 222 OptionSet[] sets = selectOptionSets(); 223 224 for (int i=0; i < sets.length; i++) { 225 if (log.isDebugEnabled()) { 226 log.debug("Selected option set: " + sets[i]); 227 } 228 else { 229 log.info("Selected option set: " + sets[i].getId()); 230 } 231 232 String[] options = sets[i].getOptions(); 233 if (options != null) { 234 for (int j=0; j < options.length; j++) { 235 java.createJvmarg().setValue(options[j]); 236 } 237 } 238 239 Properties props = sets[i].getProperties(); 240 if (props != null) { 241 Iterator iter = props.keySet().iterator(); 242 while (iter.hasNext()) { 243 String name = (String)iter.next(); 244 String value = props.getProperty(name); 245 246 setSystemProperty(java, name, value); 247 } 248 } 249 } 250 } 251 252 // Set the properties which we pass to the JVM from the startup script 253 setSystemProperty(java, "org.apache.geronimo.base.dir", geronimoHome); 254 // Use relative path 255 setSystemProperty(java, "java.io.tmpdir", "var/temp"); 256 setSystemProperty(java, "java.endorsed.dirs", prefixSystemPath("java.endorsed.dirs", new File(geronimoHome, "lib/endorsed"))); 257 setSystemProperty(java, "java.ext.dirs", prefixSystemPath("java.ext.dirs", new File(geronimoHome, "lib/ext"))); 258 259 if (quiet) { 260 java.createArg().setValue("--quiet"); 261 } 262 else { 263 java.createArg().setValue("--long"); 264 } 265 266 if (verbose) { 267 java.createArg().setValue("--verbose"); 268 } 269 270 if (veryverbose) { 271 java.createArg().setValue("--veryverbose"); 272 } 273 274 if (startModules != null) { 275 if (startModules.length == 0) { 276 throw new MojoExecutionException("At least one module name must be configured with startModule"); 277 } 278 279 log.info("Overriding the set of modules to be started"); 280 281 java.createArg().setValue("--override"); 282 283 for (int i=0; i < startModules.length; i++) { 284 java.createArg().setValue(startModules[i]); 285 } 286 } 287 288 // 289 // TODO: Check if this really does capture STDERR or not! 290 // 291 292 if (logOutput) { 293 File file = getLogFile(); 294 FileUtils.forceMkdir(file.getParentFile()); 295 296 log.info("Redirecting output to: " + file); 297 298 java.setOutput(file); 299 } 300 301 // Holds any exception that was thrown during startup 302 final ObjectHolder errorHolder = new ObjectHolder(); 303 304 StopWatch watch = new StopWatch(); 305 watch.start(); 306 307 // Start the server int a seperate thread 308 Thread t = new Thread("Geronimo Server Runner") { 309 public void run() { 310 try { 311 java.execute(); 312 } 313 catch (Exception e) { 314 errorHolder.set(e); 315 316 // 317 // NOTE: Don't log here, as when the JVM exists an exception will get thrown by Ant 318 // but that should be fine. 319 // 320 } 321 } 322 }; 323 t.start(); 324 325 log.info("Waiting for Geronimo server..."); 326 327 // Setup a callback to time out verification 328 final ObjectHolder verifyTimedOut = new ObjectHolder(); 329 330 TimerTask timeoutTask = new TimerTask() { 331 public void run() { 332 verifyTimedOut.set(Boolean.TRUE); 333 } 334 }; 335 336 if (verifyTimeout > 0) { 337 log.debug("Starting verify timeout task; triggers in: " + verifyTimeout + " seconds"); 338 timer.schedule(timeoutTask, verifyTimeout * 1000); 339 } 340 341 // Verify server started 342 ServerProxy server = new ServerProxy(hostname, port, username, password); 343 boolean started = false; 344 while (!started) { 345 if (verifyTimedOut.isSet()) { 346 throw new MojoExecutionException("Unable to verify if the server was started in the given time (" + verifyTimeout + " seconds)"); 347 } 348 349 if (errorHolder.isSet()) { 350 throw new MojoExecutionException("Failed to start Geronimo server", (Throwable)errorHolder.get()); 351 } 352 353 started = server.isFullyStarted(); 354 355 if (!started) { 356 Throwable error = server.getLastError(); 357 if (error != null) { 358 log.debug("Server query failed; ignoring", error); 359 } 360 361 Thread.sleep(1000); 362 } 363 } 364 365 // Stop the timer, server should be up now 366 timeoutTask.cancel(); 367 368 log.info("Geronimo server started in " + watch); 369 370 if (!background) { 371 log.info("Waiting for Geronimo server to shutdown..."); 372 373 t.join(); 374 } 375 } 376 377 private String prefixSystemPath(final String name, final File file) { 378 assert name != null; 379 assert file != null; 380 381 String dirs = file.getPath(); 382 String prop = System.getProperty(name, ""); 383 if (prop.length() > 0) { 384 dirs += File.pathSeparator; 385 dirs += prop; 386 } 387 return dirs; 388 } 389 390 private OptionSet[] selectOptionSets() throws MojoExecutionException { 391 // Make a map of the option sets and validate ids 392 Map map = new HashMap(); 393 for (int i=0; i<optionSets.length; i++) { 394 if (log.isDebugEnabled()) { 395 log.debug("Checking option set: " + optionSets[i]); 396 } 397 398 String id = optionSets[i].getId(); 399 400 if (id == null && optionSets.length > 1) { 401 throw new MojoExecutionException("Must specify id for optionSet when more than one optionSet is configured"); 402 } 403 else if (id == null && optionSets.length == 1) { 404 id = "default"; 405 optionSets[i].setId(id); 406 } 407 408 assert id != null; 409 id = id.trim(); 410 411 if (map.containsKey(id)) { 412 throw new MojoExecutionException("Must specify unique id for optionSet: " + id); 413 } 414 map.put(id, optionSets[i]); 415 } 416 417 StringTokenizer stok = new StringTokenizer(options, ","); 418 419 List selected = new ArrayList(); 420 while (stok.hasMoreTokens()) { 421 String id = stok.nextToken(); 422 OptionSet set = (OptionSet)map.get(id); 423 424 if (set == null) { 425 if ("default".equals(id)) { 426 log.debug("Default optionSet selected, but no optionSet defined with that id; ignoring"); 427 } 428 else { 429 log.warn("Missing optionSet for id: " + id); 430 } 431 } 432 else { 433 selected.add(set); 434 } 435 } 436 437 return (OptionSet[]) selected.toArray(new OptionSet[selected.size()]); 438 } 439 440 protected String getFullClassName() { 441 return this.getClass().getName(); 442 } 443 }