001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.startup;
018:
019: import java.io.File;
020: import java.lang.reflect.Method;
021: import java.net.MalformedURLException;
022: import java.net.URL;
023: import java.util.ArrayList;
024: import java.util.StringTokenizer;
025:
026: import javax.management.MBeanServer;
027: import javax.management.MBeanServerFactory;
028: import javax.management.ObjectName;
029:
030: import org.apache.catalina.security.SecurityClassLoad;
031:
032: /**
033: * Boostrap loader for Catalina. This application constructs a class loader
034: * for use in loading the Catalina internal classes (by accumulating all of the
035: * JAR files found in the "server" directory under "catalina.home"), and
036: * starts the regular execution of the container. The purpose of this
037: * roundabout approach is to keep the Catalina internal classes (and any
038: * other classes they depend on, such as an XML parser) out of the system
039: * class path and therefore not visible to application level classes.
040: *
041: * @author Craig R. McClanahan
042: * @author Remy Maucherat
043: * @version $Revision: 1.18.2.1 $ $Date: 2004/08/21 19:31:56 $
044: */
045:
046: public final class Bootstrap {
047:
048: // -------------------------------------------------------------- Constants
049:
050: protected static final String CATALINA_HOME_TOKEN = "${catalina.home}";
051: protected static final String CATALINA_BASE_TOKEN = "${catalina.base}";
052:
053: // ------------------------------------------------------- Static Variables
054:
055: private static final String JMX_ERROR_MESSAGE = "Due to new licensing guidelines mandated by the Apache Software\n"
056: + "Foundation Board of Directors, a JMX implementation can no longer\n"
057: + "be distributed with the Apache Tomcat binaries. As a result, you \n"
058: + "must download a JMX 1.2 implementation (such as the Sun Reference\n"
059: + "Implementation) and copy the JAR containing the API and \n"
060: + "implementation of the JMX specification to: \n"
061: + "${catalina.home}/bin/jmx.jar";
062:
063: /**
064: * Daemon object used by main.
065: */
066: private static Bootstrap daemon = null;
067:
068: // -------------------------------------------------------------- Variables
069:
070: /**
071: * Debugging detail level for processing the startup.
072: */
073: protected int debug = 0;
074:
075: /**
076: * Daemon reference.
077: */
078: private Object catalinaDaemon = null;
079:
080: protected ClassLoader commonLoader = null;
081: protected ClassLoader catalinaLoader = null;
082: protected ClassLoader sharedLoader = null;
083:
084: // -------------------------------------------------------- Private Methods
085:
086: private void initClassLoaders() {
087: try {
088: ClassLoaderFactory.setDebug(debug);
089: commonLoader = createClassLoader("common", null);
090: catalinaLoader = createClassLoader("server", commonLoader);
091: sharedLoader = createClassLoader("shared", commonLoader);
092: } catch (Throwable t) {
093: log("Class loader creation threw exception", t);
094: System.exit(1);
095: }
096: }
097:
098: private ClassLoader createClassLoader(String name,
099: ClassLoader parent) throws Exception {
100:
101: String value = CatalinaProperties.getProperty(name + ".loader");
102: if ((value == null) || (value.equals("")))
103: return parent;
104:
105: ArrayList unpackedList = new ArrayList();
106: ArrayList packedList = new ArrayList();
107: ArrayList urlList = new ArrayList();
108:
109: StringTokenizer tokenizer = new StringTokenizer(value, ",");
110: while (tokenizer.hasMoreElements()) {
111: String repository = tokenizer.nextToken();
112:
113: // Local repository
114: boolean packed = false;
115: if (repository.startsWith(CATALINA_HOME_TOKEN)) {
116: repository = getCatalinaHome()
117: + repository.substring(CATALINA_HOME_TOKEN
118: .length());
119: } else if (repository.startsWith(CATALINA_BASE_TOKEN)) {
120: repository = getCatalinaBase()
121: + repository.substring(CATALINA_BASE_TOKEN
122: .length());
123: }
124:
125: // Check for a JAR URL repository
126: try {
127: urlList.add(new URL(repository));
128: continue;
129: } catch (MalformedURLException e) {
130: // Ignore
131: }
132:
133: if (repository.endsWith("*.jar")) {
134: packed = true;
135: repository = repository.substring(0, repository
136: .length()
137: - "*.jar".length());
138: }
139: if (packed) {
140: packedList.add(new File(repository));
141: } else {
142: unpackedList.add(new File(repository));
143: }
144: }
145:
146: File[] unpacked = (File[]) unpackedList.toArray(new File[0]);
147: File[] packed = (File[]) packedList.toArray(new File[0]);
148: URL[] urls = (URL[]) urlList.toArray(new URL[0]);
149:
150: ClassLoader classLoader = ClassLoaderFactory.createClassLoader(
151: unpacked, packed, urls, parent);
152:
153: // Retrieving MBean server
154: MBeanServer mBeanServer = null;
155: if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
156: mBeanServer = (MBeanServer) MBeanServerFactory
157: .findMBeanServer(null).get(0);
158: } else {
159: mBeanServer = MBeanServerFactory.createMBeanServer();
160: }
161:
162: // Register the server classloader
163: ObjectName objectName = new ObjectName(
164: "Catalina:type=ServerClassLoader,name=" + name);
165: mBeanServer.registerMBean(classLoader, objectName);
166:
167: return classLoader;
168:
169: }
170:
171: /**
172: * Initialize daemon.
173: */
174: public void init() throws Exception {
175:
176: // Set Catalina path
177: setCatalinaHome();
178: setCatalinaBase();
179:
180: initClassLoaders();
181:
182: Thread.currentThread().setContextClassLoader(catalinaLoader);
183:
184: SecurityClassLoad.securityClassLoad(catalinaLoader);
185:
186: // Load our startup class and call its process() method
187: if (debug >= 1)
188: log("Loading startup class");
189: Class startupClass = catalinaLoader
190: .loadClass("org.apache.catalina.startup.Catalina");
191: Object startupInstance = startupClass.newInstance();
192:
193: // Set the shared extensions class loader
194: if (debug >= 1)
195: log("Setting startup class properties");
196: String methodName = "setParentClassLoader";
197: Class paramTypes[] = new Class[1];
198: paramTypes[0] = Class.forName("java.lang.ClassLoader");
199: Object paramValues[] = new Object[1];
200: paramValues[0] = sharedLoader;
201: Method method = startupInstance.getClass().getMethod(
202: methodName, paramTypes);
203: method.invoke(startupInstance, paramValues);
204:
205: catalinaDaemon = startupInstance;
206:
207: }
208:
209: /**
210: * Load daemon.
211: */
212: private void load(String[] arguments) throws Exception {
213:
214: // Call the load() method
215: String methodName = "load";
216: Object param[];
217: Class paramTypes[];
218: if (arguments == null || arguments.length == 0) {
219: paramTypes = null;
220: param = null;
221: } else {
222: paramTypes = new Class[1];
223: paramTypes[0] = arguments.getClass();
224: param = new Object[1];
225: param[0] = arguments;
226: }
227: Method method = catalinaDaemon.getClass().getMethod(methodName,
228: paramTypes);
229: if (debug >= 1)
230: log("Calling startup class " + method);
231: method.invoke(catalinaDaemon, param);
232:
233: }
234:
235: // ----------------------------------------------------------- Main Program
236:
237: /**
238: * Load the Catalina daemon.
239: */
240: public void init(String[] arguments) throws Exception {
241:
242: // Read the arguments
243: if (arguments != null) {
244: for (int i = 0; i < arguments.length; i++) {
245: if (arguments[i].equals("-debug")) {
246: debug = 1;
247: }
248: }
249: }
250:
251: init();
252: load(arguments);
253:
254: }
255:
256: /**
257: * Start the Catalina daemon.
258: */
259: public void start() throws Exception {
260: if (catalinaDaemon == null)
261: init();
262:
263: Method method = catalinaDaemon.getClass().getMethod("start",
264: null);
265: method.invoke(catalinaDaemon, null);
266:
267: }
268:
269: /**
270: * Stop the Catalina Daemon.
271: */
272: public void stop() throws Exception {
273:
274: Method method = catalinaDaemon.getClass().getMethod("stop",
275: null);
276: method.invoke(catalinaDaemon, null);
277:
278: }
279:
280: /**
281: * Stop the standlone server.
282: */
283: public void stopServer() throws Exception {
284:
285: Method method = catalinaDaemon.getClass().getMethod(
286: "stopServer", null);
287: method.invoke(catalinaDaemon, null);
288:
289: }
290:
291: /**
292: * Stop the standlone server.
293: */
294: public void stopServer(String[] arguments) throws Exception {
295:
296: Object param[];
297: Class paramTypes[];
298: if (arguments == null || arguments.length == 0) {
299: paramTypes = null;
300: param = null;
301: } else {
302: paramTypes = new Class[1];
303: paramTypes[0] = arguments.getClass();
304: param = new Object[1];
305: param[0] = arguments;
306: }
307: Method method = catalinaDaemon.getClass().getMethod(
308: "stopServer", paramTypes);
309: method.invoke(catalinaDaemon, param);
310:
311: }
312:
313: /**
314: * Set flag.
315: */
316: public void setAwait(boolean await) throws Exception {
317:
318: Class paramTypes[] = new Class[1];
319: paramTypes[0] = Boolean.TYPE;
320: Object paramValues[] = new Object[1];
321: paramValues[0] = new Boolean(await);
322: Method method = catalinaDaemon.getClass().getMethod("setAwait",
323: paramTypes);
324: method.invoke(catalinaDaemon, paramValues);
325:
326: }
327:
328: public boolean getAwait() throws Exception {
329: Class paramTypes[] = new Class[0];
330: Object paramValues[] = new Object[0];
331: Method method = catalinaDaemon.getClass().getMethod("getAwait",
332: paramTypes);
333: Boolean b = (Boolean) method
334: .invoke(catalinaDaemon, paramValues);
335: return b.booleanValue();
336: }
337:
338: /**
339: * Destroy the Catalina Daemon.
340: */
341: public void destroy() {
342:
343: // FIXME
344:
345: }
346:
347: /**
348: * Main method, used for testing only.
349: *
350: * @param args Command line arguments to be processed
351: */
352: public static void main(String args[]) {
353:
354: try {
355: // Attempt to load JMX class
356: new ObjectName("test:foo=bar");
357: } catch (Throwable t) {
358: System.out.println(JMX_ERROR_MESSAGE);
359: try {
360: // Give users some time to read the message before exiting
361: Thread.sleep(5000);
362: } catch (Exception ex) {
363: }
364: return;
365: }
366:
367: if (daemon == null) {
368: daemon = new Bootstrap();
369: try {
370: daemon.init();
371: } catch (Throwable t) {
372: t.printStackTrace();
373: return;
374: }
375: }
376:
377: try {
378: String command = "start";
379: if (args.length > 0) {
380: command = args[args.length - 1];
381: }
382:
383: if (command.equals("startd")) {
384: args[0] = "start";
385: daemon.load(args);
386: daemon.start();
387: } else if (command.equals("stopd")) {
388: args[0] = "stop";
389: daemon.stop();
390: } else if (command.equals("start")) {
391: daemon.setAwait(true);
392: daemon.load(args);
393: daemon.start();
394: } else if (command.equals("stop")) {
395: daemon.stopServer(args);
396: }
397: } catch (Throwable t) {
398: t.printStackTrace();
399: }
400:
401: }
402:
403: public void setCatalinaHome(String s) {
404: System.setProperty("catalina.home", s);
405: }
406:
407: public void setCatalinaBase(String s) {
408: System.setProperty("catalina.base", s);
409: }
410:
411: /**
412: * Set the <code>catalina.base</code> System property to the current
413: * working directory if it has not been set.
414: */
415: private void setCatalinaBase() {
416:
417: if (System.getProperty("catalina.base") != null)
418: return;
419: if (System.getProperty("catalina.home") != null)
420: System.setProperty("catalina.base", System
421: .getProperty("catalina.home"));
422: else
423: System.setProperty("catalina.base", System
424: .getProperty("user.dir"));
425:
426: }
427:
428: /**
429: * Set the <code>catalina.home</code> System property to the current
430: * working directory if it has not been set.
431: */
432: private void setCatalinaHome() {
433:
434: if (System.getProperty("catalina.home") != null)
435: return;
436: File bootstrapJar = new File(System.getProperty("user.dir"),
437: "bootstrap.jar");
438: if (bootstrapJar.exists()) {
439: try {
440: System.setProperty("catalina.home", (new File(System
441: .getProperty("user.dir"), ".."))
442: .getCanonicalPath());
443: } catch (Exception e) {
444: // Ignore
445: System.setProperty("catalina.home", System
446: .getProperty("user.dir"));
447: }
448: } else {
449: System.setProperty("catalina.home", System
450: .getProperty("user.dir"));
451: }
452:
453: }
454:
455: /**
456: * Get the value of the catalina.home environment variable.
457: */
458: public static String getCatalinaHome() {
459: return System.getProperty("catalina.home", System
460: .getProperty("user.dir"));
461: }
462:
463: /**
464: * Get the value of the catalina.base environment variable.
465: */
466: public static String getCatalinaBase() {
467: return System.getProperty("catalina.base", getCatalinaHome());
468: }
469:
470: /**
471: * Log a debugging detail message.
472: *
473: * @param message The message to be logged
474: */
475: protected static void log(String message) {
476:
477: System.out.print("Bootstrap: ");
478: System.out.println(message);
479:
480: }
481:
482: /**
483: * Log a debugging detail message with an exception.
484: *
485: * @param message The message to be logged
486: * @param exception The exception to be logged
487: */
488: protected static void log(String message, Throwable exception) {
489:
490: log(message);
491: exception.printStackTrace(System.out);
492:
493: }
494:
495: }
|