001: /*
002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/Catalina.java,v 1.48 2002/05/23 17:22:37 glenn Exp $
003: * $Revision: 1.48 $
004: * $Date: 2002/05/23 17:22:37 $
005: *
006: * ====================================================================
007: *
008: * The Apache Software License, Version 1.1
009: *
010: * Copyright (c) 1999 The Apache Software Foundation. All rights
011: * reserved.
012: *
013: * Redistribution and use in source and binary forms, with or without
014: * modification, are permitted provided that the following conditions
015: * are met:
016: *
017: * 1. Redistributions of source code must retain the above copyright
018: * notice, this list of conditions and the following disclaimer.
019: *
020: * 2. Redistributions in binary form must reproduce the above copyright
021: * notice, this list of conditions and the following disclaimer in
022: * the documentation and/or other materials provided with the
023: * distribution.
024: *
025: * 3. The end-user documentation included with the redistribution, if
026: * any, must include the following acknowlegement:
027: * "This product includes software developed by the
028: * Apache Software Foundation (http://www.apache.org/)."
029: * Alternately, this acknowlegement may appear in the software itself,
030: * if and wherever such third-party acknowlegements normally appear.
031: *
032: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
033: * Foundation" must not be used to endorse or promote products derived
034: * from this software without prior written permission. For written
035: * permission, please contact apache@apache.org.
036: *
037: * 5. Products derived from this software may not be called "Apache"
038: * nor may "Apache" appear in their names without prior written
039: * permission of the Apache Group.
040: *
041: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
042: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
043: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
044: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
045: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
046: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
047: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
048: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
049: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
050: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
051: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
052: * SUCH DAMAGE.
053: * ====================================================================
054: *
055: * This software consists of voluntary contributions made by many
056: * individuals on behalf of the Apache Software Foundation. For more
057: * information on the Apache Software Foundation, please see
058: * <http://www.apache.org/>.
059: *
060: * [Additional notices, if required by prior licensing conditions]
061: *
062: */
063:
064: package org.apache.catalina.startup;
065:
066: import java.io.File;
067: import java.io.FileInputStream;
068: import java.io.IOException;
069: import java.io.OutputStream;
070: import java.lang.reflect.InvocationTargetException;
071: import java.lang.reflect.Constructor;
072: import java.net.Socket;
073: import java.security.Security;
074: import java.util.Stack;
075: import org.apache.catalina.Container;
076: import org.apache.catalina.Lifecycle;
077: import org.apache.catalina.LifecycleException;
078: import org.apache.catalina.LifecycleListener;
079: import org.apache.catalina.Server;
080: import org.apache.catalina.Loader;
081: import org.apache.commons.digester.Digester;
082: import org.apache.commons.digester.Rule;
083: import org.apache.tomcat.util.log.SystemLogHandler;
084: import org.xml.sax.Attributes;
085: import org.xml.sax.InputSource;
086:
087: /**
088: * Startup/Shutdown shell program for Catalina. The following command line
089: * options are recognized:
090: * <ul>
091: * <li><b>-config {pathname}</b> - Set the pathname of the configuration file
092: * to be processed. If a relative path is specified, it will be
093: * interpreted as relative to the directory pathname specified by the
094: * "catalina.base" system property. [conf/server.xml]
095: * <li><b>-help</b> - Display usage information.
096: * <li><b>-stop</b> - Stop the currently running instance of Catalina.
097: * </u>
098: *
099: * @author Craig R. McClanahan
100: * @version $Revision: 1.48 $ $Date: 2002/05/23 17:22:37 $
101: */
102:
103: public class Catalina {
104:
105: // ----------------------------------------------------- Instance Variables
106:
107: /**
108: * Pathname to the server configuration file.
109: */
110: protected String configFile = "conf/server.xml";
111:
112: /**
113: * Set the debugging detail level on our Digester.
114: */
115: protected boolean debug = false;
116:
117: /**
118: * The shared extensions class loader for this server.
119: */
120: protected ClassLoader parentClassLoader = ClassLoader
121: .getSystemClassLoader();
122:
123: /**
124: * The server component we are starting or stopping
125: */
126: protected Server server = null;
127:
128: /**
129: * Are we starting a new server?
130: */
131: protected boolean starting = false;
132:
133: /**
134: * Are we stopping an existing server?
135: */
136: protected boolean stopping = false;
137:
138: /**
139: * Are we using naming ?
140: */
141: protected boolean useNaming = true;
142:
143: // ----------------------------------------------------------- Main Program
144:
145: /**
146: * The application main program.
147: *
148: * @param args Command line arguments
149: */
150: public static void main(String args[]) {
151:
152: (new Catalina()).process(args);
153: }
154:
155: /**
156: * The instance main program.
157: *
158: * @param args Command line arguments
159: */
160: public void process(String args[]) {
161:
162: setCatalinaHome();
163: setCatalinaBase();
164: try {
165: if (arguments(args))
166: execute();
167: } catch (Exception e) {
168: e.printStackTrace(System.out);
169: }
170: }
171:
172: // --------------------------------------------------------- Public Methods
173:
174: /**
175: * Set the shared extensions class loader.
176: *
177: * @param parentClassLoader The shared extensions class loader.
178: */
179: public void setParentClassLoader(ClassLoader parentClassLoader) {
180:
181: this .parentClassLoader = parentClassLoader;
182:
183: }
184:
185: /**
186: * Set the server instance we are configuring.
187: *
188: * @param server The new server
189: */
190: public void setServer(Server server) {
191:
192: this .server = server;
193:
194: }
195:
196: // ------------------------------------------------------ Protected Methods
197:
198: /**
199: * Process the specified command line arguments, and return
200: * <code>true</code> if we should continue processing; otherwise
201: * return <code>false</code>.
202: *
203: * @param args Command line arguments to process
204: */
205: protected boolean arguments(String args[]) {
206:
207: boolean isConfig = false;
208:
209: if (args.length < 1) {
210: usage();
211: return (false);
212: }
213:
214: for (int i = 0; i < args.length; i++) {
215: if (isConfig) {
216: configFile = args[i];
217: isConfig = false;
218: } else if (args[i].equals("-config")) {
219: isConfig = true;
220: } else if (args[i].equals("-debug")) {
221: debug = true;
222: } else if (args[i].equals("-nonaming")) {
223: useNaming = false;
224: } else if (args[i].equals("-help")) {
225: usage();
226: return (false);
227: } else if (args[i].equals("start")) {
228: starting = true;
229: } else if (args[i].equals("stop")) {
230: stopping = true;
231: } else {
232: usage();
233: return (false);
234: }
235: }
236:
237: return (true);
238:
239: }
240:
241: /**
242: * Return a File object representing our configuration file.
243: */
244: protected File configFile() {
245:
246: File file = new File(configFile);
247: if (!file.isAbsolute())
248: file = new File(System.getProperty("catalina.base"),
249: configFile);
250: return (file);
251:
252: }
253:
254: /**
255: * Create and configure the Digester we will be using for startup.
256: */
257: protected Digester createStartDigester() {
258:
259: // Initialize the digester
260: Digester digester = new Digester();
261: if (debug)
262: digester.setDebug(999);
263: digester.setValidating(false);
264:
265: // Configure the actions we will be using
266: digester.addObjectCreate("Server",
267: "org.apache.catalina.core.StandardServer", "className");
268: digester.addSetProperties("Server");
269: digester.addSetNext("Server", "setServer",
270: "org.apache.catalina.Server");
271:
272: digester.addObjectCreate("Server/GlobalNamingResources",
273: "org.apache.catalina.deploy.NamingResources");
274: digester.addSetProperties("Server/GlobalNamingResources");
275: digester.addSetNext("Server/GlobalNamingResources",
276: "setGlobalNamingResources",
277: "org.apache.catalina.deploy.NamingResources");
278:
279: digester.addObjectCreate("Server/Listener", null, // MUST be specified in the element
280: "className");
281: digester.addSetProperties("Server/Listener");
282: digester.addSetNext("Server/Listener", "addLifecycleListener",
283: "org.apache.catalina.LifecycleListener");
284:
285: digester
286: .addObjectCreate("Server/Service",
287: "org.apache.catalina.core.StandardService",
288: "className");
289: digester.addSetProperties("Server/Service");
290: digester.addSetNext("Server/Service", "addService",
291: "org.apache.catalina.Service");
292:
293: digester.addObjectCreate("Server/Service/Listener", null, // MUST be specified in the element
294: "className");
295: digester.addSetProperties("Server/Service/Listener");
296: digester.addSetNext("Server/Service/Listener",
297: "addLifecycleListener",
298: "org.apache.catalina.LifecycleListener");
299:
300: digester.addObjectCreate("Server/Service/Connector",
301: "org.apache.catalina.connector.http.HttpConnector",
302: "className");
303: digester.addSetProperties("Server/Service/Connector");
304: digester.addSetNext("Server/Service/Connector", "addConnector",
305: "org.apache.catalina.Connector");
306:
307: digester.addObjectCreate("Server/Service/Connector/Factory",
308: "org.apache.catalina.net.DefaultServerSocketFactory",
309: "className");
310: digester.addSetProperties("Server/Service/Connector/Factory");
311: digester.addSetNext("Server/Service/Connector/Factory",
312: "setFactory",
313: "org.apache.catalina.net.ServerSocketFactory");
314:
315: digester.addObjectCreate("Server/Service/Connector/Listener",
316: null, // MUST be specified in the element
317: "className");
318: digester.addSetProperties("Server/Service/Connector/Listener");
319: digester.addSetNext("Server/Service/Connector/Listener",
320: "addLifecycleListener",
321: "org.apache.catalina.LifecycleListener");
322:
323: // Add RuleSets for nested elements
324: digester.addRuleSet(new NamingRuleSet(
325: "Server/GlobalNamingResources/"));
326: digester.addRuleSet(new EngineRuleSet("Server/Service/"));
327: digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
328: digester.addRuleSet(new ContextRuleSet(
329: "Server/Service/Engine/Default"));
330: digester.addRuleSet(new NamingRuleSet(
331: "Server/Service/Engine/DefaultContext/"));
332: digester.addRuleSet(new ContextRuleSet(
333: "Server/Service/Engine/Host/Default"));
334: digester.addRuleSet(new NamingRuleSet(
335: "Server/Service/Engine/Host/DefaultContext/"));
336: digester.addRuleSet(new ContextRuleSet(
337: "Server/Service/Engine/Host/"));
338: digester.addRuleSet(new NamingRuleSet(
339: "Server/Service/Engine/Host/Context/"));
340:
341: digester.addRule("Server/Service/Engine",
342: new SetParentClassLoaderRule(digester,
343: parentClassLoader));
344:
345: return (digester);
346:
347: }
348:
349: /**
350: * Create and configure the Digester we will be using for shutdown.
351: */
352: protected Digester createStopDigester() {
353:
354: // Initialize the digester
355: Digester digester = new Digester();
356: if (debug)
357: digester.setDebug(999);
358:
359: // Configure the rules we need for shutting down
360: digester.addObjectCreate("Server",
361: "org.apache.catalina.core.StandardServer", "className");
362: digester.addSetProperties("Server");
363: digester.addSetNext("Server", "setServer",
364: "org.apache.catalina.Server");
365:
366: return (digester);
367:
368: }
369:
370: /**
371: * Execute the processing that has been configured from the command line.
372: */
373: protected void execute() throws Exception {
374:
375: if (starting)
376: start();
377: else if (stopping)
378: stop();
379:
380: }
381:
382: /**
383: * Set the <code>catalina.base</code> System property to the current
384: * working directory if it has not been set.
385: */
386: protected void setCatalinaBase() {
387:
388: if (System.getProperty("catalina.base") != null)
389: return;
390: System.setProperty("catalina.base", System
391: .getProperty("catalina.home"));
392:
393: }
394:
395: /**
396: * Set the <code>catalina.home</code> System property to the current
397: * working directory if it has not been set.
398: */
399: protected void setCatalinaHome() {
400:
401: if (System.getProperty("catalina.home") != null)
402: return;
403: System.setProperty("catalina.home", System
404: .getProperty("user.dir"));
405:
406: }
407:
408: /**
409: * Start a new server instance.
410: */
411: protected void start() {
412:
413: // Create and execute our Digester
414: Digester digester = createStartDigester();
415: File file = configFile();
416: try {
417: InputSource is = new InputSource("file://"
418: + file.getAbsolutePath());
419: FileInputStream fis = new FileInputStream(file);
420: is.setByteStream(fis);
421: digester.push(this );
422: digester.parse(is);
423: fis.close();
424: } catch (Exception e) {
425: System.out.println("Catalina.start: " + e);
426: e.printStackTrace(System.out);
427: System.exit(1);
428: }
429:
430: // Setting additional variables
431: if (!useNaming) {
432: System.setProperty("catalina.useNaming", "false");
433: } else {
434: System.setProperty("catalina.useNaming", "true");
435: String value = "org.apache.naming";
436: String oldValue = System
437: .getProperty(javax.naming.Context.URL_PKG_PREFIXES);
438: if (oldValue != null) {
439: value = value + ":" + oldValue;
440: }
441: System.setProperty(javax.naming.Context.URL_PKG_PREFIXES,
442: value);
443: value = System
444: .getProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY);
445: if (value == null) {
446: System.setProperty(
447: javax.naming.Context.INITIAL_CONTEXT_FACTORY,
448: "org.apache.naming.java.javaURLContextFactory");
449: }
450: }
451:
452: // If a SecurityManager is being used, set properties for
453: // checkPackageAccess() and checkPackageDefinition
454: if (System.getSecurityManager() != null) {
455: String access = Security.getProperty("package.access");
456: if (access != null && access.length() > 0)
457: access += ",";
458: else
459: access = "sun.,";
460: Security.setProperty("package.access", access
461: + "org.apache.catalina.,org.apache.jasper.");
462: String definition = Security
463: .getProperty("package.definition");
464: if (definition != null && definition.length() > 0)
465: definition += ",";
466: else
467: definition = "sun.,";
468: Security
469: .setProperty("package.definition",
470: // FIX ME package "javax." was removed to prevent HotSpot
471: // fatal internal errors
472: definition
473: + "java.,org.apache.catalina.,org.apache.jasper.");
474: }
475:
476: // Replace System.out and System.err with a custom PrintStream
477: SystemLogHandler log = new SystemLogHandler(System.out);
478: System.setOut(log);
479: System.setErr(log);
480:
481: Thread shutdownHook = new CatalinaShutdownHook();
482:
483: // Start the new server
484: if (server instanceof Lifecycle) {
485: try {
486: server.initialize();
487: ((Lifecycle) server).start();
488: try {
489: // Register shutdown hook
490: Runtime.getRuntime().addShutdownHook(shutdownHook);
491: } catch (Throwable t) {
492: // This will fail on JDK 1.2. Ignoring, as Tomcat can run
493: // fine without the shutdown hook.
494: }
495: // Wait for the server to be told to shut down
496: server.await();
497: } catch (LifecycleException e) {
498: System.out.println("Catalina.start: " + e);
499: e.printStackTrace(System.out);
500: if (e.getThrowable() != null) {
501: System.out.println("----- Root Cause -----");
502: e.getThrowable().printStackTrace(System.out);
503: }
504: }
505: }
506:
507: // Shut down the server
508: if (server instanceof Lifecycle) {
509: try {
510: try {
511: // Remove the ShutdownHook first so that server.stop()
512: // doesn't get invoked twice
513: Runtime.getRuntime().removeShutdownHook(
514: shutdownHook);
515: } catch (Throwable t) {
516: // This will fail on JDK 1.2. Ignoring, as Tomcat can run
517: // fine without the shutdown hook.
518: }
519: ((Lifecycle) server).stop();
520: } catch (LifecycleException e) {
521: System.out.println("Catalina.stop: " + e);
522: e.printStackTrace(System.out);
523: if (e.getThrowable() != null) {
524: System.out.println("----- Root Cause -----");
525: e.getThrowable().printStackTrace(System.out);
526: }
527: }
528: }
529:
530: }
531:
532: /**
533: * Stop an existing server instance.
534: */
535: protected void stop() {
536:
537: // Create and execute our Digester
538: Digester digester = createStopDigester();
539: File file = configFile();
540: try {
541: InputSource is = new InputSource("file://"
542: + file.getAbsolutePath());
543: FileInputStream fis = new FileInputStream(file);
544: is.setByteStream(fis);
545: digester.push(this );
546: digester.parse(is);
547: fis.close();
548: } catch (Exception e) {
549: System.out.println("Catalina.stop: " + e);
550: e.printStackTrace(System.out);
551: System.exit(1);
552: }
553:
554: // Stop the existing server
555: try {
556: Socket socket = new Socket("127.0.0.1", server.getPort());
557: OutputStream stream = socket.getOutputStream();
558: String shutdown = server.getShutdown();
559: for (int i = 0; i < shutdown.length(); i++)
560: stream.write(shutdown.charAt(i));
561: stream.flush();
562: stream.close();
563: socket.close();
564: } catch (IOException e) {
565: System.out.println("Catalina.stop: " + e);
566: e.printStackTrace(System.out);
567: System.exit(1);
568: }
569:
570: }
571:
572: /**
573: * Print usage information for this application.
574: */
575: protected void usage() {
576:
577: System.out
578: .println("usage: java org.apache.catalina.startup.Catalina"
579: + " [ -config {pathname} ] [ -debug ]"
580: + " [ -nonaming ] { start | stop }");
581:
582: }
583:
584: // --------------------------------------- CatalinaShutdownHook Inner Class
585:
586: /**
587: * Shutdown hook which will perform a clean shutdown of Catalina if needed.
588: */
589: protected class CatalinaShutdownHook extends Thread {
590:
591: public void run() {
592:
593: if (server != null) {
594: try {
595: ((Lifecycle) server).stop();
596: } catch (LifecycleException e) {
597: System.out.println("Catalina.stop: " + e);
598: e.printStackTrace(System.out);
599: if (e.getThrowable() != null) {
600: System.out.println("----- Root Cause -----");
601: e.getThrowable().printStackTrace(System.out);
602: }
603: }
604: }
605:
606: }
607:
608: }
609:
610: }
611:
612: // ------------------------------------------------------------ Private Classes
613:
614: /**
615: * Rule that sets the parent class loader for the top object on the stack,
616: * which must be a <code>Container</code>.
617: */
618:
619: final class SetParentClassLoaderRule extends Rule {
620:
621: public SetParentClassLoaderRule(Digester digester,
622: ClassLoader parentClassLoader) {
623:
624: super (digester);
625: this .parentClassLoader = parentClassLoader;
626:
627: }
628:
629: ClassLoader parentClassLoader = null;
630:
631: public void begin(Attributes attributes) throws Exception {
632:
633: if (digester.getDebug() >= 1)
634: digester.log("Setting parent class loader");
635:
636: Container top = (Container) digester.peek();
637: top.setParentClassLoader(parentClassLoader);
638:
639: }
640:
641: }
|