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