1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19 package org.apache.catalina.startup;
20
21
22 import java.io.File;
23 import java.lang.reflect.Method;
24 import java.net.MalformedURLException;
25 import java.net.URL;
26 import java.util.ArrayList;
27 import java.util.StringTokenizer;
28
29 import javax.management.MBeanServer;
30 import javax.management.MBeanServerFactory;
31 import javax.management.ObjectName;
32
33 import org.apache.catalina.security.SecurityClassLoad;
34 import org.apache.juli.logging.Log;
35 import org.apache.juli.logging.LogFactory;
36
37
38 /**
39 * Boostrap loader for Catalina. This application constructs a class loader
40 * for use in loading the Catalina internal classes (by accumulating all of the
41 * JAR files found in the "server" directory under "catalina.home"), and
42 * starts the regular execution of the container. The purpose of this
43 * roundabout approach is to keep the Catalina internal classes (and any
44 * other classes they depend on, such as an XML parser) out of the system
45 * class path and therefore not visible to application level classes.
46 *
47 * @author Craig R. McClanahan
48 * @author Remy Maucherat
49 * @version $Revision: 467222 $ $Date: 2006-10-24 05:17:11 +0200 (mar., 24 oct. 2006) $
50 */
51
52 public final class Bootstrap {
53
54 private static Log log = LogFactory.getLog(Bootstrap.class);
55
56 // -------------------------------------------------------------- Constants
57
58
59 protected static final String CATALINA_HOME_TOKEN = "${catalina.home}";
60 protected static final String CATALINA_BASE_TOKEN = "${catalina.base}";
61
62
63 // ------------------------------------------------------- Static Variables
64
65
66 /**
67 * Daemon object used by main.
68 */
69 private static Bootstrap daemon = null;
70
71
72 // -------------------------------------------------------------- Variables
73
74
75 /**
76 * Daemon reference.
77 */
78 private Object catalinaDaemon = null;
79
80
81 protected ClassLoader commonLoader = null;
82 protected ClassLoader catalinaLoader = null;
83 protected ClassLoader sharedLoader = null;
84
85
86 // -------------------------------------------------------- Private Methods
87
88
89 private void initClassLoaders() {
90 try {
91 commonLoader = createClassLoader("common", null);
92 if( commonLoader == null ) {
93 // no config file, default to this loader - we might be in a 'single' env.
94 commonLoader=this.getClass().getClassLoader();
95 }
96 catalinaLoader = createClassLoader("server", commonLoader);
97 sharedLoader = createClassLoader("shared", commonLoader);
98 } catch (Throwable t) {
99 log.error("Class loader creation threw exception", t);
100 System.exit(1);
101 }
102 }
103
104
105 private ClassLoader createClassLoader(String name, ClassLoader parent)
106 throws Exception {
107
108 String value = CatalinaProperties.getProperty(name + ".loader");
109 if ((value == null) || (value.equals("")))
110 return parent;
111
112 ArrayList repositoryLocations = new ArrayList();
113 ArrayList repositoryTypes = new ArrayList();
114 int i;
115
116 StringTokenizer tokenizer = new StringTokenizer(value, ",");
117 while (tokenizer.hasMoreElements()) {
118 String repository = tokenizer.nextToken();
119
120 // Local repository
121 boolean replace = false;
122 String before = repository;
123 while ((i=repository.indexOf(CATALINA_HOME_TOKEN))>=0) {
124 replace=true;
125 if (i>0) {
126 repository = repository.substring(0,i) + getCatalinaHome()
127 + repository.substring(i+CATALINA_HOME_TOKEN.length());
128 } else {
129 repository = getCatalinaHome()
130 + repository.substring(CATALINA_HOME_TOKEN.length());
131 }
132 }
133 while ((i=repository.indexOf(CATALINA_BASE_TOKEN))>=0) {
134 replace=true;
135 if (i>0) {
136 repository = repository.substring(0,i) + getCatalinaBase()
137 + repository.substring(i+CATALINA_BASE_TOKEN.length());
138 } else {
139 repository = getCatalinaBase()
140 + repository.substring(CATALINA_BASE_TOKEN.length());
141 }
142 }
143 if (replace && log.isDebugEnabled())
144 log.debug("Expanded " + before + " to " + replace);
145
146 // Check for a JAR URL repository
147 try {
148 URL url=new URL(repository);
149 repositoryLocations.add(repository);
150 repositoryTypes.add(ClassLoaderFactory.IS_URL);
151 continue;
152 } catch (MalformedURLException e) {
153 // Ignore
154 }
155
156 if (repository.endsWith("*.jar")) {
157 repository = repository.substring
158 (0, repository.length() - "*.jar".length());
159 repositoryLocations.add(repository);
160 repositoryTypes.add(ClassLoaderFactory.IS_GLOB);
161 } else if (repository.endsWith(".jar")) {
162 repositoryLocations.add(repository);
163 repositoryTypes.add(ClassLoaderFactory.IS_JAR);
164 } else {
165 repositoryLocations.add(repository);
166 repositoryTypes.add(ClassLoaderFactory.IS_DIR);
167 }
168 }
169
170 String[] locations = (String[]) repositoryLocations.toArray(new String[0]);
171 Integer[] types = (Integer[]) repositoryTypes.toArray(new Integer[0]);
172
173 ClassLoader classLoader = ClassLoaderFactory.createClassLoader
174 (locations, types, parent);
175
176 // Retrieving MBean server
177 MBeanServer mBeanServer = null;
178 if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
179 mBeanServer =
180 (MBeanServer) MBeanServerFactory.findMBeanServer(null).get(0);
181 } else {
182 mBeanServer = MBeanServerFactory.createMBeanServer();
183 }
184
185 // Register the server classloader
186 ObjectName objectName =
187 new ObjectName("Catalina:type=ServerClassLoader,name=" + name);
188 mBeanServer.registerMBean(classLoader, objectName);
189
190 return classLoader;
191
192 }
193
194
195 /**
196 * Initialize daemon.
197 */
198 public void init()
199 throws Exception
200 {
201
202 // Set Catalina path
203 setCatalinaHome();
204 setCatalinaBase();
205
206 initClassLoaders();
207
208 Thread.currentThread().setContextClassLoader(catalinaLoader);
209
210 SecurityClassLoad.securityClassLoad(catalinaLoader);
211
212 // Load our startup class and call its process() method
213 if (log.isDebugEnabled())
214 log.debug("Loading startup class");
215 Class startupClass =
216 catalinaLoader.loadClass
217 ("org.apache.catalina.startup.Catalina");
218 Object startupInstance = startupClass.newInstance();
219
220 // Set the shared extensions class loader
221 if (log.isDebugEnabled())
222 log.debug("Setting startup class properties");
223 String methodName = "setParentClassLoader";
224 Class paramTypes[] = new Class[1];
225 paramTypes[0] = Class.forName("java.lang.ClassLoader");
226 Object paramValues[] = new Object[1];
227 paramValues[0] = sharedLoader;
228 Method method =
229 startupInstance.getClass().getMethod(methodName, paramTypes);
230 method.invoke(startupInstance, paramValues);
231
232 catalinaDaemon = startupInstance;
233
234 }
235
236
237 /**
238 * Load daemon.
239 */
240 private void load(String[] arguments)
241 throws Exception {
242
243 // Call the load() method
244 String methodName = "load";
245 Object param[];
246 Class paramTypes[];
247 if (arguments==null || arguments.length==0) {
248 paramTypes = null;
249 param = null;
250 } else {
251 paramTypes = new Class[1];
252 paramTypes[0] = arguments.getClass();
253 param = new Object[1];
254 param[0] = arguments;
255 }
256 Method method =
257 catalinaDaemon.getClass().getMethod(methodName, paramTypes);
258 if (log.isDebugEnabled())
259 log.debug("Calling startup class " + method);
260 method.invoke(catalinaDaemon, param);
261
262 }
263
264
265 // ----------------------------------------------------------- Main Program
266
267
268 /**
269 * Load the Catalina daemon.
270 */
271 public void init(String[] arguments)
272 throws Exception {
273
274 init();
275 load(arguments);
276
277 }
278
279
280 /**
281 * Start the Catalina daemon.
282 */
283 public void start()
284 throws Exception {
285 if( catalinaDaemon==null ) init();
286
287 Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
288 method.invoke(catalinaDaemon, (Object [])null);
289
290 }
291
292
293 /**
294 * Stop the Catalina Daemon.
295 */
296 public void stop()
297 throws Exception {
298
299 Method method = catalinaDaemon.getClass().getMethod("stop", (Class [] ) null);
300 method.invoke(catalinaDaemon, (Object [] ) null);
301
302 }
303
304
305 /**
306 * Stop the standlone server.
307 */
308 public void stopServer()
309 throws Exception {
310
311 Method method =
312 catalinaDaemon.getClass().getMethod("stopServer", (Class []) null);
313 method.invoke(catalinaDaemon, (Object []) null);
314
315 }
316
317
318 /**
319 * Stop the standlone server.
320 */
321 public void stopServer(String[] arguments)
322 throws Exception {
323
324 Object param[];
325 Class paramTypes[];
326 if (arguments==null || arguments.length==0) {
327 paramTypes = null;
328 param = null;
329 } else {
330 paramTypes = new Class[1];
331 paramTypes[0] = arguments.getClass();
332 param = new Object[1];
333 param[0] = arguments;
334 }
335 Method method =
336 catalinaDaemon.getClass().getMethod("stopServer", paramTypes);
337 method.invoke(catalinaDaemon, param);
338
339 }
340
341
342 /**
343 * Set flag.
344 */
345 public void setAwait(boolean await)
346 throws Exception {
347
348 Class paramTypes[] = new Class[1];
349 paramTypes[0] = Boolean.TYPE;
350 Object paramValues[] = new Object[1];
351 paramValues[0] = new Boolean(await);
352 Method method =
353 catalinaDaemon.getClass().getMethod("setAwait", paramTypes);
354 method.invoke(catalinaDaemon, paramValues);
355
356 }
357
358 public boolean getAwait()
359 throws Exception
360 {
361 Class paramTypes[] = new Class[0];
362 Object paramValues[] = new Object[0];
363 Method method =
364 catalinaDaemon.getClass().getMethod("getAwait", paramTypes);
365 Boolean b=(Boolean)method.invoke(catalinaDaemon, paramValues);
366 return b.booleanValue();
367 }
368
369
370 /**
371 * Destroy the Catalina Daemon.
372 */
373 public void destroy() {
374
375 // FIXME
376
377 }
378
379
380 /**
381 * Main method, used for testing only.
382 *
383 * @param args Command line arguments to be processed
384 */
385 public static void main(String args[]) {
386
387 if (daemon == null) {
388 daemon = new Bootstrap();
389 try {
390 daemon.init();
391 } catch (Throwable t) {
392 t.printStackTrace();
393 return;
394 }
395 }
396
397 try {
398 String command = "start";
399 if (args.length > 0) {
400 command = args[args.length - 1];
401 }
402
403 if (command.equals("startd")) {
404 args[0] = "start";
405 daemon.load(args);
406 daemon.start();
407 } else if (command.equals("stopd")) {
408 args[0] = "stop";
409 daemon.stop();
410 } else if (command.equals("start")) {
411 daemon.setAwait(true);
412 daemon.load(args);
413 daemon.start();
414 } else if (command.equals("stop")) {
415 daemon.stopServer(args);
416 } else {
417 log.warn("Bootstrap: command \"" + command + "\" does not exist.");
418 }
419 } catch (Throwable t) {
420 t.printStackTrace();
421 }
422
423 }
424
425 public void setCatalinaHome(String s) {
426 System.setProperty( "catalina.home", s );
427 }
428
429 public void setCatalinaBase(String s) {
430 System.setProperty( "catalina.base", s );
431 }
432
433
434 /**
435 * Set the <code>catalina.base</code> System property to the current
436 * working directory if it has not been set.
437 */
438 private void setCatalinaBase() {
439
440 if (System.getProperty("catalina.base") != null)
441 return;
442 if (System.getProperty("catalina.home") != null)
443 System.setProperty("catalina.base",
444 System.getProperty("catalina.home"));
445 else
446 System.setProperty("catalina.base",
447 System.getProperty("user.dir"));
448
449 }
450
451
452 /**
453 * Set the <code>catalina.home</code> System property to the current
454 * working directory if it has not been set.
455 */
456 private void setCatalinaHome() {
457
458 if (System.getProperty("catalina.home") != null)
459 return;
460 File bootstrapJar =
461 new File(System.getProperty("user.dir"), "bootstrap.jar");
462 if (bootstrapJar.exists()) {
463 try {
464 System.setProperty
465 ("catalina.home",
466 (new File(System.getProperty("user.dir"), ".."))
467 .getCanonicalPath());
468 } catch (Exception e) {
469 // Ignore
470 System.setProperty("catalina.home",
471 System.getProperty("user.dir"));
472 }
473 } else {
474 System.setProperty("catalina.home",
475 System.getProperty("user.dir"));
476 }
477
478 }
479
480
481 /**
482 * Get the value of the catalina.home environment variable.
483 */
484 public static String getCatalinaHome() {
485 return System.getProperty("catalina.home",
486 System.getProperty("user.dir"));
487 }
488
489
490 /**
491 * Get the value of the catalina.base environment variable.
492 */
493 public static String getCatalinaBase() {
494 return System.getProperty("catalina.base", getCatalinaHome());
495 }
496
497
498 }