001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018 package org.apache.geronimo.system.main;
019
020 import org.apache.commons.logging.Log;
021 import org.apache.commons.logging.LogFactory;
022 import org.apache.geronimo.common.GeronimoEnvironment;
023 import org.apache.geronimo.gbean.AbstractName;
024 import org.apache.geronimo.gbean.AbstractNameQuery;
025 import org.apache.geronimo.kernel.Kernel;
026 import org.apache.geronimo.kernel.KernelFactory;
027 import org.apache.geronimo.kernel.config.ConfigurationManager;
028 import org.apache.geronimo.kernel.config.ConfigurationUtil;
029 import org.apache.geronimo.kernel.config.PersistentConfigurationList;
030 import org.apache.geronimo.kernel.log.GeronimoLogging;
031 import org.apache.geronimo.kernel.repository.Artifact;
032 import org.apache.geronimo.system.serverinfo.DirectoryUtils;
033
034 import java.io.File;
035 import java.io.IOException;
036 import java.io.InputStream;
037 import java.io.PrintStream;
038 import java.util.ArrayList;
039 import java.util.Iterator;
040 import java.util.List;
041 import java.util.Set;
042
043 /**
044 * @version $Rev:385659 $ $Date: 2006-12-14 03:10:31 -0800 (Thu, 14 Dec 2006) $
045 */
046 public class Daemon {
047 private final static String ARGUMENT_NO_PROGRESS = "--quiet";
048 private final static String ARGUMENT_LONG_PROGRESS = "--long";
049 private final static String ARGUMENT_VERBOSE_SHORTFORM = "-v";
050 private final static String ARGUMENT_VERBOSE = "--verbose";
051 private final static String ARGUMENT_MORE_VERBOSE_SHORTFORM = "-vv";
052 private final static String ARGUMENT_MORE_VERBOSE = "--veryverbose";
053 private final static String ARGUMENT_MODULE_OVERRIDE = "--override";
054 private static boolean started = false;
055 private static Log log;
056 private StartupMonitor monitor;
057 private List configs = new ArrayList();
058 private String verboseArg = null;
059 private String noProgressArg = null;
060 private String longProgressArg = null;
061
062 private Daemon(String[] args) {
063 // Very first startup tasks
064 long start = System.currentTimeMillis();
065 // Command line arguments affect logging configuration, etc.
066 if(processArguments(args)) {
067 System.out.println("Booting Geronimo Kernel (in Java " + System.getProperty("java.version") + ")...");
068 System.out.flush();
069
070 // Initialization tasks that must run before anything else
071 initializeSystem();
072
073 monitor.systemStarting(start);
074 doStartup();
075 } else {
076 System.exit(1);
077 throw new AssertionError();
078 }
079 }
080
081 private void printHelp(PrintStream out) {
082 out.println();
083 out.println("Syntax: java -jar bin/server.jar [options]");
084 out.println();
085 out.println("Available options are: ");
086 out.println(" "+ARGUMENT_NO_PROGRESS);
087 out.println(" Suppress the normal startup progress bar. This is typically\n" +
088 " used when redirecting console output to a file, or starting\n" +
089 " the server from an IDE or other tool.");
090 out.println(" "+ARGUMENT_LONG_PROGRESS);
091 out.println(" Write startup progress to the console in a format that is\n" +
092 " suitable for redirecting console output to a file, or starting\n" +
093 " the server from an IDE or other tool (doesn't use linefeeds to\n" +
094 " update the progress information that is used by default if you\n" +
095 " don't specify " +ARGUMENT_NO_PROGRESS +" or "+ARGUMENT_LONG_PROGRESS+").\n");
096 out.println(" "+ARGUMENT_VERBOSE_SHORTFORM +" " +ARGUMENT_VERBOSE);
097 out.println(" Reduces the console log level to DEBUG, resulting in more\n" +
098 " console output than is normally present.");
099 out.println(" "+ARGUMENT_MORE_VERBOSE_SHORTFORM +" " +ARGUMENT_MORE_VERBOSE);
100 out.println(" Reduces the console log level to TRACE, resulting in still\n" +
101 " more console output.");
102 out.println();
103 out.println(" "+ARGUMENT_MODULE_OVERRIDE+" [moduleId] [moduleId] ...");
104 out.println(" USE WITH CAUTION! Overrides the modules in\n" +
105 " var/config/config.xml such that only the modules listed on\n" +
106 " the command line will be started. Note that many J2EE\n" +
107 " features depend on certain modules being started, so you\n" +
108 " should be very careful what you omit. Any arguments after\n" +
109 " this are assumed to be module names.");
110 out.println();
111 out.println("In addition you may specify a replacement for var/config/config.xml using by setting the property\n" +
112 "-Dorg.apache.geronimo.config.file=var/config/<my-config.xml>\n" +
113 "This is resolved relative to the geronimo base directory.");
114 out.println();
115 }
116
117 /**
118 * @return true if the server startup should proceed (all arguments
119 * make sense and the user didn't ask for help)
120 */
121 private boolean processArguments(String[] args) {
122 boolean override = false;
123 boolean help = false;
124 for (int i = 0; i < args.length; i++) {
125 if(override) {
126 configs.add(Artifact.create(args[i]));
127 } else if (args[i].equals(ARGUMENT_NO_PROGRESS)) {
128 noProgressArg = ARGUMENT_NO_PROGRESS;
129 } else if (args[i].equals(ARGUMENT_LONG_PROGRESS)) {
130 longProgressArg = ARGUMENT_LONG_PROGRESS;
131 } else if (args[i].equals(ARGUMENT_VERBOSE_SHORTFORM) ||
132 args[i].equals(ARGUMENT_VERBOSE)) {
133 if (verboseArg == null) {
134 verboseArg = ARGUMENT_VERBOSE;
135 }
136 } else if (args[i].equals(ARGUMENT_MORE_VERBOSE_SHORTFORM) ||
137 args[i].equals(ARGUMENT_MORE_VERBOSE)) {
138 if (verboseArg == null) {
139 verboseArg = ARGUMENT_MORE_VERBOSE;
140 }
141 } else if (args[i].equals(ARGUMENT_MODULE_OVERRIDE)) {
142 override = true;
143 } else if(args[i].equalsIgnoreCase("-help") || args[i].equalsIgnoreCase("--help") ||
144 args[i].equalsIgnoreCase("-h") || args[i].equalsIgnoreCase("/?")) {
145 help = true;
146 } else {
147 System.out.println("Unrecognized argument: "+args[i]);
148 help = true;
149 }
150 }
151 if(help) {
152 printHelp(System.out);
153 }
154 return !help;
155 }
156
157 private void initializeSystem() {
158 if (!started) {
159 started = true;
160
161 // Perform initialization tasks common with the various Geronimo environments
162 GeronimoEnvironment.init();
163
164 // This MUST be done before the first log is acquired (WHICH THE STARTUP MONITOR 5 LINES LATER DOES!)
165 // Generally we want to suppress anything but WARN until the log GBean starts up
166 GeronimoLogging.initialize(verboseArg == null || verboseArg.equals(ARGUMENT_VERBOSE) ? GeronimoLogging.WARN : GeronimoLogging.DEBUG);
167 // The following will be used once the log GBean starts up
168 GeronimoLogging.setConsoleLogLevel(verboseArg == null ? GeronimoLogging.INFO : verboseArg.equals(ARGUMENT_VERBOSE) ? GeronimoLogging.DEBUG : GeronimoLogging.TRACE);
169 log = LogFactory.getLog(Daemon.class.getName());
170 }
171
172 if (verboseArg != null || noProgressArg != null) {
173 monitor = new SilentStartupMonitor();
174 } else {
175 if (longProgressArg != null)
176 monitor = new LongStartupMonitor();
177 else
178 monitor = new ProgressBarStartupMonitor();
179 }
180
181 // JVMCheck(); // Removed for 1.1
182 }
183
184 private void JVMCheck() {
185 String jvmVersion = System.getProperty("java.specification.version");
186 if (! jvmVersion.equals("1.4"))
187 log.warn("\n====================================== Warning =======================================\n" +
188 " Geronimo is currently only certified on version 1.4 of the Java Virtual Machine.\n" +
189 " Use of version " + jvmVersion + " is not currently supported. Use at your own risk.\n" +
190 " Check http://geronimo.apache.org for current information on JDK certification level.\n" +
191 "====================================== Warning =======================================");
192 }
193
194 private void doStartup() {
195 try {
196 // Check that the tmpdir exists - if not give friendly msg and exit
197 // since we allow it to be configured in geronimo.bat and geronimo.sh
198 // (since 1.0 release) the same way Tomcat allows it to be configured.
199 String tmpDir = System.getProperty("java.io.tmpdir");
200 if (tmpDir == null || (!(new File(tmpDir)).exists()) ||
201 (!(new File(tmpDir)).isDirectory())) {
202 System.err.println("The java.io.tmpdir system property specifies the "+
203 "non-existent directory " +tmpDir);
204 System.exit(1);
205 throw new AssertionError();
206 }
207
208 // Determine the geronimo installation directory
209 File geronimoInstallDirectory = DirectoryUtils.getGeronimoInstallDirectory();
210 if (geronimoInstallDirectory == null) {
211 System.err.println("Could not determine geronimo installation directory");
212 System.exit(1);
213 throw new AssertionError();
214 }
215
216 ClassLoader classLoader = Daemon.class.getClassLoader();
217
218 // create the kernel
219 final Kernel kernel = KernelFactory.newInstance().createKernel("geronimo");
220
221 // boot the kernel
222 try {
223 kernel.boot();
224 } catch (Exception e) {
225 e.printStackTrace();
226 System.exit(1);
227 throw new AssertionError();
228 }
229
230 // add our shutdown hook
231 Runtime.getRuntime().addShutdownHook(new Thread("Geronimo shutdown thread") {
232 public void run() {
233 System.out.println("\rServer shutdown begun ");
234 kernel.shutdown();
235 System.out.println("Server shutdown completed");
236 }
237 });
238
239 // load this configuration
240 InputStream in = classLoader.getResourceAsStream("META-INF/config.ser");
241 try {
242 ConfigurationUtil.loadBootstrapConfiguration(kernel, in, classLoader);
243 } finally {
244 if (in != null) {
245 try {
246 in.close();
247 } catch (IOException ignored) {
248 // ignored
249 }
250 }
251 }
252
253 monitor.systemStarted(kernel);
254
255 AbstractNameQuery query = new AbstractNameQuery(PersistentConfigurationList.class.getName());
256
257 if (configs.isEmpty()) {
258 // --override wasn't used (nothing explicit), see what was running before
259 Set configLists = kernel.listGBeans(query);
260 for (Iterator i = configLists.iterator(); i.hasNext();) {
261 AbstractName configListName = (AbstractName) i.next();
262 try {
263 configs.addAll((List) kernel.invoke(configListName, "restore"));
264 } catch (IOException e) {
265 System.err.println("Unable to restore last known configurations");
266 e.printStackTrace();
267 kernel.shutdown();
268 System.exit(1);
269 throw new AssertionError();
270 }
271 }
272 }
273
274 monitor.foundModules((Artifact[]) configs.toArray(new Artifact[configs.size()]));
275
276 // load the rest of the configurations
277 try {
278 ConfigurationManager configurationManager = ConfigurationUtil.getConfigurationManager(kernel);
279 try {
280 for (Iterator i = configs.iterator(); i.hasNext();) {
281 Artifact configID = (Artifact) i.next();
282 monitor.moduleLoading(configID);
283 configurationManager.loadConfiguration(configID);
284 monitor.moduleLoaded(configID);
285 monitor.moduleStarting(configID);
286 configurationManager.startConfiguration(configID);
287 monitor.moduleStarted(configID);
288 }
289 } finally {
290 ConfigurationUtil.releaseConfigurationManager(kernel, configurationManager);
291 }
292 } catch (Exception e) {
293 //Exception caught when starting configurations, starting kernel shutdown
294 monitor.serverStartFailed(e);
295 try {
296 kernel.shutdown();
297 } catch (Exception e1) {
298 System.err.println("Exception caught during kernel shutdown");
299 e1.printStackTrace();
300 }
301 System.exit(1);
302 throw new AssertionError();
303 }
304
305 // Tell every persistent configuration list that the kernel is now fully started
306 Set configLists = kernel.listGBeans(query);
307 for (Iterator i = configLists.iterator(); i.hasNext();) {
308 AbstractName configListName = (AbstractName) i.next();
309 kernel.setAttribute(configListName, "kernelFullyStarted", Boolean.TRUE);
310 }
311
312 // Startup sequence is finished
313 monitor.startupFinished();
314 monitor = null;
315
316 // capture this thread until the kernel is ready to exit
317 while (kernel.isRunning()) {
318 try {
319 synchronized (kernel) {
320 kernel.wait();
321 }
322 } catch (InterruptedException e) {
323 // continue
324 }
325 }
326 } catch (Exception e) {
327 if (monitor != null) {
328 monitor.serverStartFailed(e);
329 }
330 e.printStackTrace();
331 System.exit(1);
332 throw new AssertionError();
333 }
334 }
335
336 private void AddToSystemProperty(String propertyName, List dirsFromManifest, File geronimoInstallDirectory) {
337 String dirs = System.getProperty(propertyName, "");
338 for (Iterator iterator = dirsFromManifest.iterator(); iterator.hasNext();) {
339 String directoryName = (String) iterator.next();
340 File directory = new File(directoryName);
341 if (!directory.isAbsolute()) {
342 directory = new File(geronimoInstallDirectory, directoryName);
343 }
344
345 if (dirs.length() > 0) {
346 dirs += File.pathSeparatorChar;
347 }
348 dirs += directory.getAbsolutePath();
349 }
350 if (dirs.length() > 0) {
351 System.setProperty(propertyName, dirs);
352 }
353 log.debug(propertyName + "=" + System.getProperty(propertyName));
354 }
355
356 /**
357 * Static entry point allowing a Kernel to be run from the command line.
358 *
359 * Once the Kernel is booted and the configuration is loaded, the process
360 * will remain running until the shutdown() method on the kernel is
361 * invoked or until the JVM exits.
362 *
363 * @param args the command line arguments
364 */
365 public static void main(String[] args) {
366 new Daemon(args);
367 }
368
369 }