View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *  http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.geronimo.mavenplugins.geronimo.server;
21  
22  import java.io.File;
23  
24  import java.util.Timer;
25  import java.util.TimerTask;
26  import java.util.Map;
27  import java.util.HashMap;
28  import java.util.Properties;
29  import java.util.Iterator;
30  import java.util.StringTokenizer;
31  import java.util.List;
32  import java.util.ArrayList;
33  
34  import org.apache.maven.plugin.MojoExecutionException;
35  
36  import org.apache.tools.ant.taskdefs.Java;
37  import org.apache.tools.ant.types.Environment;
38  
39  import org.apache.geronimo.genesis.ObjectHolder;
40  import org.apache.geronimo.mavenplugins.geronimo.ServerProxy;
41  
42  import org.codehaus.plexus.util.FileUtils;
43  
44  /**
45   * Start the Geronimo server.
46   *
47   * @goal start-server
48   *
49   * @version $Rev: 453468 $ $Date: 2006-10-05 19:27:06 -0700 (Thu, 05 Oct 2006) $
50   */
51  public class StartServerMojo
52      extends InstallerMojoSupport
53  {
54      /**
55       * Flag to control if we background the server or block Maven execution.
56       *
57       * @parameter expression="${background}" default-value="false"
58       */
59      private boolean background = false;
60  
61      /**
62       * Set the maximum memory for the forked JVM.
63       *
64       * @parameter expression="${maximumMemory}"
65       */
66      private String maximumMemory = null;
67  
68      /**
69       * Enable quiet mode.
70       *
71       * @parameter expression="${quiet}" default-value="false"
72       */
73      private boolean quiet = false;
74  
75      /**
76       * Enable verbose mode.
77       *
78       * @parameter expression="${verbose}" default-value="false"
79       */
80      private boolean verbose = false;
81  
82      /**
83       * Enable veryverbose mode.
84       *
85       * @parameter expression="${veryverbose}" default-value="false"
86       */
87      private boolean veryverbose = false;
88  
89      /**
90       * Time in seconds to wait before terminating the forked JVM.
91       *
92       * @parameter expression="${timeout}" default-value="-1"
93       */
94      private int timeout = -1;
95  
96      /**
97       * Time in seconds to wait while verifing that the server has started.
98       *
99       * @parameter expression="${verifyTimeout}" default-value="-1"
100      */
101     private int verifyTimeout = -1;
102 
103     /**
104      * An array of option sets which can be enabled by setting optionSetId.
105      *
106      * @parameter
107      */
108     private OptionSet[] optionSets = null;
109 
110     /**
111      * A comma seperated list of optionSets to enabled.
112      *
113      * @parameter expression="${options}"
114      */
115     private String options = null;
116 
117     /**
118      * A list of module names to be started using --override.
119      *
120      * @parameter
121      */
122     private String[] startModules = null;
123 
124     private Timer timer = new Timer(true);
125 
126     protected void doExecute() throws Exception {
127         installAssembly();
128 
129         log.info("Starting Geronimo server...");
130         
131         // Setup the JVM to start the server with
132         final Java java = (Java)createTask("java");
133         java.setJar(new File(geronimoHome, "bin/server.jar"));
134         java.setDir(geronimoHome);
135         java.setFailonerror(true);
136         java.setFork(true);
137         
138         if (timeout > 0) {
139             java.setTimeout(new Long(timeout * 1000));
140         }
141 
142         if (maximumMemory != null) {
143             java.setMaxmemory(maximumMemory);
144         }
145 
146         // Apply option sets
147         if (options != null  && (optionSets == null || optionSets.length == 0)) {
148             throw new MojoExecutionException("At least one optionSet must be defined to select one using options");
149         }
150         else if (options == null) {
151             options = "default";
152         }
153         
154         if (optionSets != null && optionSets.length != 0) {
155             OptionSet[] sets = selectOptionSets();
156 
157             for (int i=0; i < sets.length; i++) {
158                 if (log.isDebugEnabled()) {
159                     log.debug("Selected option set: " + sets[i]);
160                 }
161                 else {
162                     log.info("Selected option set: " + sets[i].getId());
163                 }
164 
165                 String[] options = sets[i].getOptions();
166                 if (options != null) {
167                     for (int j=0; j < options.length; j++) {
168                         java.createJvmarg().setValue(options[j]);
169                     }
170                 }
171 
172                 Properties props = sets[i].getProperties();
173                 if (props != null) {
174                     Iterator iter = props.keySet().iterator();
175                     while (iter.hasNext()) {
176                         String name = (String)iter.next();
177                         String value = props.getProperty(name);
178 
179                         setSystemProperty(java, name, value);
180                     }
181                 }
182             }
183         }
184 
185         // Set the properties which we pass to the JVM from the startup script
186         setSystemProperty(java, "org.apache.geronimo.base.dir", geronimoHome);
187         setSystemProperty(java, "java.io.tmpdir", new File(geronimoHome, "var/temp"));
188         setSystemProperty(java, "java.endorsed.dirs", appendSystemPath("java.endorsed.dirs", new File(geronimoHome, "lib/endorsed")));
189         setSystemProperty(java, "java.ext.dirs", appendSystemPath("java.ext.dirs", new File(geronimoHome, "lib/ext")));
190         
191         if (quiet) {
192             java.createArg().setValue("--quiet");
193         }
194         else {
195             java.createArg().setValue("--long");
196         }
197 
198         if (verbose) {
199             java.createArg().setValue("--verbose");
200         }
201 
202         if (veryverbose) {
203             java.createArg().setValue("--veryverbose");
204         }
205 
206         if (startModules != null) {
207             if (startModules.length == 0) {
208                 throw new MojoExecutionException("At least one module name must be configured with startModule");
209             }
210 
211             log.info("Overriding the set of modules to be started");
212 
213             java.createArg().setValue("--override");
214 
215             for (int i=0; i < startModules.length; i++) {
216                 java.createArg().setValue(startModules[i]);
217             }
218         }
219 
220         //
221         // TODO: Check if this really does capture STDERR or not!
222         //
223 
224         if (logOutput) {
225             File file = getLogFile();
226             FileUtils.forceMkdir(file.getParentFile());
227 
228             log.info("Redirecting output to: " + file);
229             
230             java.setLogError(true);
231             java.setOutput(file);
232         }
233 
234         // Holds any exception that was thrown during startup
235         final ObjectHolder errorHolder = new ObjectHolder();
236 
237         // Start the server int a seperate thread
238         Thread t = new Thread("Geronimo Server Runner") {
239             public void run() {
240                 try {
241                     java.execute();
242                 }
243                 catch (Exception e) {
244                     errorHolder.set(e);
245 
246                     //
247                     // NOTE: Don't log here, as when the JVM exists an exception will get thrown by Ant
248                     //       but that should be fine.
249                     //
250                 }
251             }
252         };
253         t.start();
254 
255         log.debug("Waiting for Geronimo server...");
256 
257         // Setup a callback to time out verification
258         final ObjectHolder verifyTimedOut = new ObjectHolder();
259 
260         TimerTask timeoutTask = new TimerTask() {
261             public void run() {
262                 verifyTimedOut.set(Boolean.TRUE);
263             }
264         };
265 
266         if (verifyTimeout > 0) {
267             log.debug("Starting verify timeout task; triggers in: " + verifyTimeout + "s");
268             timer.schedule(timeoutTask, verifyTimeout * 1000);
269         }
270 
271         // Verify server started
272         ServerProxy server = new ServerProxy(hostname, port, username, password);
273         boolean started = false;
274         while (!started) {
275             if (verifyTimedOut.isSet()) {
276                 throw new MojoExecutionException("Unable to verify if the server was started in the given time");
277             }
278 
279             if (errorHolder.isSet()) {
280                 throw new MojoExecutionException("Failed to start Geronimo server", (Throwable)errorHolder.get());
281             }
282 
283             started = server.isFullyStarted();
284 
285             if (!started) {
286                 Throwable error = server.getLastError();
287                 if (error != null) {
288                     log.debug("Server query failed; ignoring", error);
289                 }
290 
291                 Thread.sleep(1000);
292             }
293         }
294 
295         // Stop the timer, server should be up now
296         timeoutTask.cancel();
297         
298         log.info("Geronimo server started");
299 
300         if (!background) {
301             log.info("Waiting for Geronimo server to shutdown...");
302 
303             t.join();
304         }
305     }
306 
307     private String appendSystemPath(final String name, final File file) {
308         assert name != null;
309         assert file != null;
310 
311         return System.getProperty(name) + File.pathSeparator + file.getPath();
312     }
313 
314     private OptionSet[] selectOptionSets() throws MojoExecutionException {
315         // Make a map of the option sets and validate ids
316         Map map = new HashMap();
317         for (int i=0; i<optionSets.length; i++) {
318             if (log.isDebugEnabled()) {
319                 log.debug("Checking option set: " + optionSets[i]);
320             }
321             
322             String id = optionSets[i].getId();
323 
324             if (id == null && optionSets.length > 1) {
325                 throw new MojoExecutionException("Must specify id for optionSet when more than one optionSet is configured");
326             }
327             else if (id == null && optionSets.length == 1) {
328                 id = "default";
329                 optionSets[i].setId(id);
330             }
331 
332             assert id != null;
333             id = id.trim();
334 
335             if (map.containsKey(id)) {
336                 throw new MojoExecutionException("Must specify unique id for optionSet: " + id);
337             }
338             map.put(id, optionSets[i]);
339         }
340 
341         StringTokenizer stok = new StringTokenizer(options, ",");
342 
343         List selected = new ArrayList();
344         while (stok.hasMoreTokens()) {
345             String id = stok.nextToken();
346             OptionSet set = (OptionSet)map.get(options);
347             
348             if (set == null) {
349                 if ("default".equals(options)) {
350                     log.debug("Default optionSet selected, but no optionSet defined with that id; ignoring");
351                 }
352                 else {
353                     throw new MojoExecutionException("Missing optionSet for id: " + id);
354                 }
355             }
356             else {
357                 selected.add(set);
358             }
359         }
360 
361         return (OptionSet[]) selected.toArray(new OptionSet[selected.size()]);
362     }
363 
364     private void setSystemProperty(final Java java, final String name, final String value) {
365         Environment.Variable var = new Environment.Variable();
366         var.setKey(name);
367         var.setValue(value);
368         java.addSysproperty(var);
369     }
370 
371     private void setSystemProperty(final Java java, final String name, final File value) {
372         Environment.Variable var = new Environment.Variable();
373         var.setKey(name);
374         var.setFile(value);
375         java.addSysproperty(var);
376     }
377 
378     protected String getGoalName() {
379         //
380         //FIXME: There has to be way this can be computed instead of hardcoded absolutely.
381         //
382         return "start-server";
383     }
384 }