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