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 com.salmonllc.ideTools;
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: import org.apache.catalina.startup.CatalinaProperties;
032: import org.apache.catalina.startup.ClassLoaderFactory;
033:
034: /**
035: * Boostrap loader for Catalina. This application constructs a class loader
036: * for use in loading the Catalina internal classes (by accumulating all of the
037: * JAR files found in the "server" directory under "catalina.home"), and
038: * starts the regular execution of the container. The purpose of this
039: * roundabout approach is to keep the Catalina internal classes (and any
040: * other classes they depend on, such as an XML parser) out of the system
041: * class path and therefore not visible to application level classes.
042: *
043: * @author Craig R. McClanahan
044: * @author Remy Maucherat
045: * @version $Revision: 1 $ $Date: 8/05/04 2:55p $
046: */
047:
048: public final class Tomcat50Bootstrap {
049:
050: // -------------------------------------------------------------- Constants
051:
052: protected static final String CATALINA_HOME_TOKEN = "${catalina.home}";
053: protected static final String CATALINA_BASE_TOKEN = "${catalina.base}";
054:
055: // ------------------------------------------------------- Static Variables
056:
057: private static final String JMX_ERROR_MESSAGE = "Due to new licensing guidelines mandated by the Apache Software\n"
058: + "Foundation Board of Directors, a JMX implementation can no longer\n"
059: + "be distributed with the Apache Tomcat binaries. As a result, you \n"
060: + "must download a JMX 1.2 implementation (such as the Sun Reference\n"
061: + "Implementation) and copy the JAR containing the API and \n"
062: + "implementation of the JMX specification to: \n"
063: + "${catalina.home}/bin/jmx.jar";
064:
065: /**
066: * Daemon object used by main.
067: */
068: private static Tomcat50Bootstrap _daemon = null;
069:
070: // -------------------------------------------------------------- Variables
071:
072: /**
073: * Debugging detail level for processing the startup.
074: */
075: protected int _debug = 0;
076:
077: /**
078: * Daemon reference.
079: */
080: private Object _catalinaDaemon = null;
081:
082: protected ClassLoader _commonLoader = null;
083: protected ClassLoader _catalinaLoader = null;
084: protected ClassLoader _sharedLoader = null;
085:
086: private boolean _restart = false;
087: private String _extraCom = null;
088: private String _extraArgs = null;
089:
090: public static int START = 1;
091: public static int STOP = 2;
092: public static int RESTART = 3;
093:
094: /**
095: * Create a new bootstrap object, extraCom and extraArgs are so the browser can start after the server starts
096: */
097: private Tomcat50Bootstrap(boolean restart, String extraCom,
098: String extraArgs) {
099: _restart = restart;
100: _extraCom = extraCom;
101: _extraArgs = extraArgs;
102: }
103:
104: /*
105: * Start, stop or restart the local tomcat server. Optionally launch the browser as well.
106: * @param process constants START, STOP or RESTART
107: * @param browserPath - The full path to the browser executable
108: * @param webPage - The URL of the web page to run
109: */
110: public static void execute(int process, String browserPath,
111: String webPage) {
112: Tomcat50Bootstrap tb = new Tomcat50Bootstrap(
113: process == RESTART, browserPath, webPage);
114: if (process == START)
115: executeCommand("start", tb);
116: else if (process == STOP || process == RESTART)
117: executeCommand("stop", tb);
118:
119: }
120:
121: private static void executeCommand(String command,
122: Tomcat50Bootstrap tb) {
123: if (_daemon == null) {
124: _daemon = tb;
125: try {
126: _daemon.init();
127: } catch (Throwable t) {
128: t.printStackTrace();
129: return;
130: }
131: }
132:
133: String args[] = { command };
134: try {
135: if (command.equals("start")) {
136: _daemon.setAwait(true);
137: _daemon.load(args);
138: _daemon.start();
139: } else if (command.equals("stop")) {
140: _daemon.stopServer(args);
141: }
142: } catch (Throwable t) {
143: t.printStackTrace();
144: }
145: }
146:
147: String getBrowserExe() {
148: return _extraCom;
149: }
150:
151: String getBrowserURL() {
152: return _extraArgs;
153: }
154:
155: /**
156: * This method gets fired when a process is executed
157: */
158: void notifyComplete() {
159: if (_restart) {
160: _restart = false;
161: executeCommand("start", this );
162: }
163: }
164:
165: // -------------------------------------------------------- Private Methods
166:
167: private void initClassLoaders() {
168: try {
169: ClassLoaderFactory.setDebug(_debug);
170: _commonLoader = createClassLoader("common", null);
171: _catalinaLoader = createClassLoader("server", _commonLoader);
172: _sharedLoader = createClassLoader("shared", _commonLoader);
173: } catch (Throwable t) {
174: log("Class loader creation threw exception", t);
175: System.exit(1);
176: }
177: }
178:
179: private ClassLoader createClassLoader(String name,
180: ClassLoader parent) throws Exception {
181:
182: String value = CatalinaProperties.getProperty(name + ".loader");
183: if ((value == null) || (value.equals("")))
184: return parent;
185:
186: ArrayList unpackedList = new ArrayList();
187: ArrayList packedList = new ArrayList();
188: ArrayList urlList = new ArrayList();
189:
190: StringTokenizer tokenizer = new StringTokenizer(value, ",");
191: while (tokenizer.hasMoreElements()) {
192: String repository = tokenizer.nextToken();
193: // Check for a JAR URL repository
194: try {
195: urlList.add(new URL(repository));
196: continue;
197: } catch (MalformedURLException e) {
198: // Ignore
199: }
200: // Local repository
201: boolean packed = false;
202: if (repository.startsWith(CATALINA_HOME_TOKEN)) {
203: repository = getCatalinaHome()
204: + repository.substring(CATALINA_HOME_TOKEN
205: .length());
206: } else if (repository.startsWith(CATALINA_BASE_TOKEN)) {
207: repository = getCatalinaBase()
208: + repository.substring(CATALINA_BASE_TOKEN
209: .length());
210: }
211: if (repository.endsWith("*.jar")) {
212: packed = true;
213: repository = repository.substring(0, repository
214: .length()
215: - "*.jar".length());
216: }
217: if (packed) {
218: packedList.add(new File(repository));
219: } else {
220: unpackedList.add(new File(repository));
221: }
222: }
223:
224: File[] unpacked = (File[]) unpackedList.toArray(new File[0]);
225: File[] packed = (File[]) packedList.toArray(new File[0]);
226: URL[] urls = (URL[]) urlList.toArray(new URL[0]);
227:
228: ClassLoader classLoader = ClassLoaderFactory.createClassLoader(
229: unpacked, packed, urls, parent);
230:
231: // Retrieving MBean server
232: MBeanServer mBeanServer = null;
233: if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
234: mBeanServer = (MBeanServer) MBeanServerFactory
235: .findMBeanServer(null).get(0);
236: } else {
237: mBeanServer = MBeanServerFactory.createMBeanServer();
238: }
239:
240: // Register the server classloader
241: ObjectName objectName = new ObjectName(
242: "Catalina:type=ServerClassLoader,name=" + name);
243: mBeanServer.registerMBean(classLoader, objectName);
244:
245: return classLoader;
246:
247: }
248:
249: /**
250: * Initialize daemon.
251: */
252: public void init() throws Exception {
253:
254: // Set Catalina path
255: setCatalinaHome();
256: setCatalinaBase();
257:
258: initClassLoaders();
259:
260: Thread.currentThread().setContextClassLoader(_catalinaLoader);
261:
262: SecurityClassLoad.securityClassLoad(_catalinaLoader);
263:
264: // Load our startup class and call its process() method
265: if (_debug >= 1)
266: log("Loading startup class");
267: Class startupClass = _catalinaLoader
268: .loadClass("com.salmonllc.ideTools.Tomcat50Engine");
269: Object startupInstance = startupClass.newInstance();
270:
271: // Set the shared extensions class loader
272: if (_debug >= 1)
273: log("Setting startup class properties");
274: String methodName = "setParentClassLoader";
275: Class paramTypes[] = new Class[1];
276: paramTypes[0] = Class.forName("java.lang.ClassLoader");
277: Object paramValues[] = new Object[1];
278: paramValues[0] = _sharedLoader;
279: Method method = startupInstance.getClass().getMethod(
280: methodName, paramTypes);
281: method.invoke(startupInstance, paramValues);
282:
283: _catalinaDaemon = startupInstance;
284:
285: }
286:
287: /**
288: * Load daemon.
289: */
290: private void load(String[] arguments) throws Exception {
291:
292: // Call the load() method
293: String methodName = "load";
294: Object param[];
295: Class paramTypes[];
296: if (arguments == null || arguments.length == 0) {
297: paramTypes = null;
298: param = null;
299: } else {
300: paramTypes = new Class[1];
301: paramTypes[0] = arguments.getClass();
302: param = new Object[1];
303: param[0] = arguments;
304: }
305: Method method = _catalinaDaemon.getClass().getMethod(
306: methodName, paramTypes);
307: if (_debug >= 1)
308: log("Calling startup class " + method);
309: method.invoke(_catalinaDaemon, param);
310:
311: }
312:
313: // ----------------------------------------------------------- Main Program
314:
315: /**
316: * Load the Catalina daemon.
317: */
318: public void init(String[] arguments) throws Exception {
319:
320: // Read the arguments
321: if (arguments != null) {
322: for (int i = 0; i < arguments.length; i++) {
323: if (arguments[i].equals("-debug")) {
324: _debug = 1;
325: }
326: }
327: }
328:
329: init();
330: load(arguments);
331:
332: }
333:
334: /**
335: * Start the Catalina daemon.
336: */
337: public void start() throws Exception {
338: if (_catalinaDaemon == null)
339: init();
340:
341: Class classes[] = { getClass() };
342: Object parms[] = { this };
343: Method method = _catalinaDaemon.getClass().getMethod("start",
344: classes);
345: method.invoke(_catalinaDaemon, parms);
346:
347: }
348:
349: /**
350: * Stop the Catalina Daemon.
351: */
352: public void stop() throws Exception {
353:
354: Method method = _catalinaDaemon.getClass().getMethod("stop",
355: null);
356: method.invoke(_catalinaDaemon, null);
357:
358: }
359:
360: /**
361: * Stop the standlone server.
362: */
363: public void stopServer(String[] arguments) throws Exception {
364:
365: Object param[];
366: Class paramTypes[];
367: if (arguments == null || arguments.length == 0) {
368: paramTypes = null;
369: param = null;
370: } else {
371: paramTypes = new Class[2];
372: paramTypes[0] = arguments.getClass();
373: paramTypes[1] = getClass();
374: param = new Object[2];
375: param[0] = arguments;
376: param[1] = this ;
377: }
378: Method method = _catalinaDaemon.getClass().getMethod(
379: "stopServer", paramTypes);
380: method.invoke(_catalinaDaemon, param);
381:
382: }
383:
384: /**
385: * Set flag.
386: */
387: public void setAwait(boolean await) throws Exception {
388:
389: Class paramTypes[] = new Class[1];
390: paramTypes[0] = Boolean.TYPE;
391: Object paramValues[] = new Object[1];
392: paramValues[0] = new Boolean(await);
393: Method method = _catalinaDaemon.getClass().getMethod(
394: "setAwait", paramTypes);
395: method.invoke(_catalinaDaemon, paramValues);
396:
397: }
398:
399: public boolean getAwait() throws Exception {
400: Class paramTypes[] = new Class[0];
401: Object paramValues[] = new Object[0];
402: Method method = _catalinaDaemon.getClass().getMethod(
403: "getAwait", paramTypes);
404: Boolean b = (Boolean) method.invoke(_catalinaDaemon,
405: paramValues);
406: return b.booleanValue();
407: }
408:
409: /**
410: * Destroy the Catalina Daemon.
411: */
412: public void destroy() {
413:
414: // FIXME
415:
416: }
417:
418: public static void main(String args[]) {
419: execute(RESTART,
420: "C:\\Program Files\\Internet Explorer\\iexplore.exe",
421: "http://localhost:8080");
422: }
423:
424: public void setCatalinaHome(String s) {
425: System.setProperty("catalina.home", s);
426: }
427:
428: public void setCatalinaBase(String s) {
429: System.setProperty("catalina.base", s);
430: }
431:
432: /**
433: * Set the <code>catalina.base</code> System property to the current
434: * working directory if it has not been set.
435: */
436: private void setCatalinaBase() {
437:
438: if (System.getProperty("catalina.base") != null)
439: return;
440: if (System.getProperty("catalina.home") != null)
441: System.setProperty("catalina.base", System
442: .getProperty("catalina.home"));
443: else
444: System.setProperty("catalina.base", System
445: .getProperty("user.dir"));
446:
447: }
448:
449: /**
450: * Set the <code>catalina.home</code> System property to the current
451: * working directory if it has not been set.
452: */
453: private void setCatalinaHome() {
454:
455: if (System.getProperty("catalina.home") != null)
456: return;
457: File bootstrapJar = new File(System.getProperty("user.dir"),
458: "bootstrap.jar");
459: if (bootstrapJar.exists()) {
460: try {
461: System.setProperty("catalina.home", (new File(System
462: .getProperty("user.dir"), ".."))
463: .getCanonicalPath());
464: } catch (Exception e) {
465: // Ignore
466: System.setProperty("catalina.home", System
467: .getProperty("user.dir"));
468: }
469: } else {
470: System.setProperty("catalina.home", System
471: .getProperty("user.dir"));
472: }
473:
474: }
475:
476: /**
477: * Get the value of the catalina.home environment variable.
478: */
479: public static String getCatalinaHome() {
480: return System.getProperty("catalina.home", System
481: .getProperty("user.dir"));
482: }
483:
484: /**
485: * Get the value of the catalina.base environment variable.
486: */
487: public static String getCatalinaBase() {
488: return System.getProperty("catalina.base", getCatalinaHome());
489: }
490:
491: /**
492: * Log a debugging detail message.
493: *
494: * @param message The message to be logged
495: */
496: protected static void log(String message) {
497:
498: System.out.print("Bootstrap: ");
499: System.out.println(message);
500:
501: }
502:
503: /**
504: * Log a debugging detail message with an exception.
505: *
506: * @param message The message to be logged
507: * @param exception The exception to be logged
508: */
509: protected static void log(String message, Throwable exception) {
510:
511: log(message);
512: exception.printStackTrace(System.out);
513:
514: }
515:
516: }
|