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 }