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.catalina.startup;
019:
020: import java.io.File;
021: import java.lang.reflect.Method;
022: import java.net.MalformedURLException;
023: import java.net.URL;
024: import java.util.ArrayList;
025: import java.util.StringTokenizer;
026:
027: import javax.management.MBeanServer;
028: import javax.management.MBeanServerFactory;
029: import javax.management.ObjectName;
030:
031: import org.apache.catalina.security.SecurityClassLoad;
032: import org.apache.juli.logging.Log;
033: import org.apache.juli.logging.LogFactory;
034:
035: /**
036: * Boostrap loader for Catalina. This application constructs a class loader
037: * for use in loading the Catalina internal classes (by accumulating all of the
038: * JAR files found in the "server" directory under "catalina.home"), and
039: * starts the regular execution of the container. The purpose of this
040: * roundabout approach is to keep the Catalina internal classes (and any
041: * other classes they depend on, such as an XML parser) out of the system
042: * class path and therefore not visible to application level classes.
043: *
044: * @author Craig R. McClanahan
045: * @author Remy Maucherat
046: * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
047: */
048:
049: public final class Bootstrap {
050:
051: private static Log log = LogFactory.getLog(Bootstrap.class);
052:
053: // -------------------------------------------------------------- Constants
054:
055: protected static final String CATALINA_HOME_TOKEN = "${catalina.home}";
056: protected static final String CATALINA_BASE_TOKEN = "${catalina.base}";
057:
058: // ------------------------------------------------------- Static Variables
059:
060: /**
061: * Daemon object used by main.
062: */
063: private static Bootstrap daemon = null;
064:
065: // -------------------------------------------------------------- Variables
066:
067: /**
068: * Daemon reference.
069: */
070: private Object catalinaDaemon = null;
071:
072: protected ClassLoader commonLoader = null;
073: protected ClassLoader catalinaLoader = null;
074: protected ClassLoader sharedLoader = null;
075:
076: // -------------------------------------------------------- Private Methods
077:
078: private void initClassLoaders() {
079: try {
080: commonLoader = createClassLoader("common", null);
081: if (commonLoader == null) {
082: // no config file, default to this loader - we might be in a 'single' env.
083: commonLoader = this .getClass().getClassLoader();
084: }
085: catalinaLoader = createClassLoader("server", commonLoader);
086: sharedLoader = createClassLoader("shared", commonLoader);
087: } catch (Throwable t) {
088: log.error("Class loader creation threw exception", t);
089: System.exit(1);
090: }
091: }
092:
093: private ClassLoader createClassLoader(String name,
094: ClassLoader parent) throws Exception {
095:
096: String value = CatalinaProperties.getProperty(name + ".loader");
097: if ((value == null) || (value.equals("")))
098: return parent;
099:
100: ArrayList repositoryLocations = new ArrayList();
101: ArrayList repositoryTypes = new ArrayList();
102: int i;
103:
104: StringTokenizer tokenizer = new StringTokenizer(value, ",");
105: while (tokenizer.hasMoreElements()) {
106: String repository = tokenizer.nextToken();
107:
108: // Local repository
109: boolean replace = false;
110: String before = repository;
111: while ((i = repository.indexOf(CATALINA_HOME_TOKEN)) >= 0) {
112: replace = true;
113: if (i > 0) {
114: repository = repository.substring(0, i)
115: + getCatalinaHome()
116: + repository.substring(i
117: + CATALINA_HOME_TOKEN.length());
118: } else {
119: repository = getCatalinaHome()
120: + repository.substring(CATALINA_HOME_TOKEN
121: .length());
122: }
123: }
124: while ((i = repository.indexOf(CATALINA_BASE_TOKEN)) >= 0) {
125: replace = true;
126: if (i > 0) {
127: repository = repository.substring(0, i)
128: + getCatalinaBase()
129: + repository.substring(i
130: + CATALINA_BASE_TOKEN.length());
131: } else {
132: repository = getCatalinaBase()
133: + repository.substring(CATALINA_BASE_TOKEN
134: .length());
135: }
136: }
137: if (replace && log.isDebugEnabled())
138: log.debug("Expanded " + before + " to " + replace);
139:
140: // Check for a JAR URL repository
141: try {
142: URL url = new URL(repository);
143: repositoryLocations.add(repository);
144: repositoryTypes.add(ClassLoaderFactory.IS_URL);
145: continue;
146: } catch (MalformedURLException e) {
147: // Ignore
148: }
149:
150: if (repository.endsWith("*.jar")) {
151: repository = repository.substring(0, repository
152: .length()
153: - "*.jar".length());
154: repositoryLocations.add(repository);
155: repositoryTypes.add(ClassLoaderFactory.IS_GLOB);
156: } else if (repository.endsWith(".jar")) {
157: repositoryLocations.add(repository);
158: repositoryTypes.add(ClassLoaderFactory.IS_JAR);
159: } else {
160: repositoryLocations.add(repository);
161: repositoryTypes.add(ClassLoaderFactory.IS_DIR);
162: }
163: }
164:
165: String[] locations = (String[]) repositoryLocations
166: .toArray(new String[0]);
167: Integer[] types = (Integer[]) repositoryTypes
168: .toArray(new Integer[0]);
169:
170: ClassLoader classLoader = ClassLoaderFactory.createClassLoader(
171: locations, types, parent);
172:
173: // Retrieving MBean server
174: MBeanServer mBeanServer = null;
175: if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
176: mBeanServer = (MBeanServer) MBeanServerFactory
177: .findMBeanServer(null).get(0);
178: } else {
179: mBeanServer = MBeanServerFactory.createMBeanServer();
180: }
181:
182: // Register the server classloader
183: ObjectName objectName = new ObjectName(
184: "Catalina:type=ServerClassLoader,name=" + name);
185: mBeanServer.registerMBean(classLoader, objectName);
186:
187: return classLoader;
188:
189: }
190:
191: /**
192: * Initialize daemon.
193: */
194: public void init() throws Exception {
195:
196: // Set Catalina path
197: setCatalinaHome();
198: setCatalinaBase();
199:
200: initClassLoaders();
201:
202: Thread.currentThread().setContextClassLoader(catalinaLoader);
203:
204: SecurityClassLoad.securityClassLoad(catalinaLoader);
205:
206: // Load our startup class and call its process() method
207: if (log.isDebugEnabled())
208: log.debug("Loading startup class");
209: Class startupClass = catalinaLoader
210: .loadClass("org.apache.catalina.startup.Catalina");
211: Object startupInstance = startupClass.newInstance();
212:
213: // Set the shared extensions class loader
214: if (log.isDebugEnabled())
215: log.debug("Setting startup class properties");
216: String methodName = "setParentClassLoader";
217: Class paramTypes[] = new Class[1];
218: paramTypes[0] = Class.forName("java.lang.ClassLoader");
219: Object paramValues[] = new Object[1];
220: paramValues[0] = sharedLoader;
221: Method method = startupInstance.getClass().getMethod(
222: methodName, paramTypes);
223: method.invoke(startupInstance, paramValues);
224:
225: catalinaDaemon = startupInstance;
226:
227: }
228:
229: /**
230: * Load daemon.
231: */
232: private void load(String[] arguments) throws Exception {
233:
234: // Call the load() method
235: String methodName = "load";
236: Object param[];
237: Class paramTypes[];
238: if (arguments == null || arguments.length == 0) {
239: paramTypes = null;
240: param = null;
241: } else {
242: paramTypes = new Class[1];
243: paramTypes[0] = arguments.getClass();
244: param = new Object[1];
245: param[0] = arguments;
246: }
247: Method method = catalinaDaemon.getClass().getMethod(methodName,
248: paramTypes);
249: if (log.isDebugEnabled())
250: log.debug("Calling startup class " + method);
251: method.invoke(catalinaDaemon, param);
252:
253: }
254:
255: // ----------------------------------------------------------- Main Program
256:
257: /**
258: * Load the Catalina daemon.
259: */
260: public void init(String[] arguments) throws Exception {
261:
262: init();
263: load(arguments);
264:
265: }
266:
267: /**
268: * Start the Catalina daemon.
269: */
270: public void start() throws Exception {
271: if (catalinaDaemon == null)
272: init();
273:
274: Method method = catalinaDaemon.getClass().getMethod("start",
275: (Class[]) null);
276: method.invoke(catalinaDaemon, (Object[]) null);
277:
278: }
279:
280: /**
281: * Stop the Catalina Daemon.
282: */
283: public void stop() throws Exception {
284:
285: Method method = catalinaDaemon.getClass().getMethod("stop",
286: (Class[]) null);
287: method.invoke(catalinaDaemon, (Object[]) null);
288:
289: }
290:
291: /**
292: * Stop the standlone server.
293: */
294: public void stopServer() throws Exception {
295:
296: Method method = catalinaDaemon.getClass().getMethod(
297: "stopServer", (Class[]) null);
298: method.invoke(catalinaDaemon, (Object[]) null);
299:
300: }
301:
302: /**
303: * Stop the standlone server.
304: */
305: public void stopServer(String[] arguments) throws Exception {
306:
307: Object param[];
308: Class paramTypes[];
309: if (arguments == null || arguments.length == 0) {
310: paramTypes = null;
311: param = null;
312: } else {
313: paramTypes = new Class[1];
314: paramTypes[0] = arguments.getClass();
315: param = new Object[1];
316: param[0] = arguments;
317: }
318: Method method = catalinaDaemon.getClass().getMethod(
319: "stopServer", paramTypes);
320: method.invoke(catalinaDaemon, param);
321:
322: }
323:
324: /**
325: * Set flag.
326: */
327: public void setAwait(boolean await) throws Exception {
328:
329: Class paramTypes[] = new Class[1];
330: paramTypes[0] = Boolean.TYPE;
331: Object paramValues[] = new Object[1];
332: paramValues[0] = new Boolean(await);
333: Method method = catalinaDaemon.getClass().getMethod("setAwait",
334: paramTypes);
335: method.invoke(catalinaDaemon, paramValues);
336:
337: }
338:
339: public boolean getAwait() throws Exception {
340: Class paramTypes[] = new Class[0];
341: Object paramValues[] = new Object[0];
342: Method method = catalinaDaemon.getClass().getMethod("getAwait",
343: paramTypes);
344: Boolean b = (Boolean) method
345: .invoke(catalinaDaemon, paramValues);
346: return b.booleanValue();
347: }
348:
349: /**
350: * Destroy the Catalina Daemon.
351: */
352: public void destroy() {
353:
354: // FIXME
355:
356: }
357:
358: /**
359: * Main method, used for testing only.
360: *
361: * @param args Command line arguments to be processed
362: */
363: public static void main(String args[]) {
364:
365: if (daemon == null) {
366: daemon = new Bootstrap();
367: try {
368: daemon.init();
369: } catch (Throwable t) {
370: t.printStackTrace();
371: return;
372: }
373: }
374:
375: try {
376: String command = "start";
377: if (args.length > 0) {
378: command = args[args.length - 1];
379: }
380:
381: if (command.equals("startd")) {
382: args[0] = "start";
383: daemon.load(args);
384: daemon.start();
385: } else if (command.equals("stopd")) {
386: args[0] = "stop";
387: daemon.stop();
388: } else if (command.equals("start")) {
389: daemon.setAwait(true);
390: daemon.load(args);
391: daemon.start();
392: } else if (command.equals("stop")) {
393: daemon.stopServer(args);
394: } else {
395: log.warn("Bootstrap: command \"" + command
396: + "\" does not exist.");
397: }
398: } catch (Throwable t) {
399: t.printStackTrace();
400: }
401:
402: }
403:
404: public void setCatalinaHome(String s) {
405: System.setProperty("catalina.home", s);
406: }
407:
408: public void setCatalinaBase(String s) {
409: System.setProperty("catalina.base", s);
410: }
411:
412: /**
413: * Set the <code>catalina.base</code> System property to the current
414: * working directory if it has not been set.
415: */
416: private void setCatalinaBase() {
417:
418: if (System.getProperty("catalina.base") != null)
419: return;
420: if (System.getProperty("catalina.home") != null)
421: System.setProperty("catalina.base", System
422: .getProperty("catalina.home"));
423: else
424: System.setProperty("catalina.base", System
425: .getProperty("user.dir"));
426:
427: }
428:
429: /**
430: * Set the <code>catalina.home</code> System property to the current
431: * working directory if it has not been set.
432: */
433: private void setCatalinaHome() {
434:
435: if (System.getProperty("catalina.home") != null)
436: return;
437: File bootstrapJar = new File(System.getProperty("user.dir"),
438: "bootstrap.jar");
439: if (bootstrapJar.exists()) {
440: try {
441: System.setProperty("catalina.home", (new File(System
442: .getProperty("user.dir"), ".."))
443: .getCanonicalPath());
444: } catch (Exception e) {
445: // Ignore
446: System.setProperty("catalina.home", System
447: .getProperty("user.dir"));
448: }
449: } else {
450: System.setProperty("catalina.home", System
451: .getProperty("user.dir"));
452: }
453:
454: }
455:
456: /**
457: * Get the value of the catalina.home environment variable.
458: */
459: public static String getCatalinaHome() {
460: return System.getProperty("catalina.home", System
461: .getProperty("user.dir"));
462: }
463:
464: /**
465: * Get the value of the catalina.base environment variable.
466: */
467: public static String getCatalinaBase() {
468: return System.getProperty("catalina.base", getCatalinaHome());
469: }
470:
471: }
|