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