1
17 package org.apache.catalina.startup;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.net.MalformedURLException;
24 import java.net.URL;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.regex.Matcher;
28 import java.util.regex.Pattern;
29
30 import org.apache.catalina.Globals;
31 import org.apache.catalina.security.SecurityClassLoad;
32 import org.apache.catalina.startup.ClassLoaderFactory.Repository;
33 import org.apache.catalina.startup.ClassLoaderFactory.RepositoryType;
34 import org.apache.juli.logging.Log;
35 import org.apache.juli.logging.LogFactory;
36
37
49 public final class Bootstrap {
50
51 private static final Log log = LogFactory.getLog(Bootstrap.class);
52
53
56 private static final Object daemonLock = new Object();
57 private static volatile Bootstrap daemon = null;
58
59 private static final File catalinaBaseFile;
60 private static final File catalinaHomeFile;
61
62 private static final Pattern PATH_PATTERN = Pattern.compile("(\".*?\")|(([^,])*)");
63
64 static {
65
66 String userDir = System.getProperty("user.dir");
67
68
69 String home = System.getProperty(Globals.CATALINA_HOME_PROP);
70 File homeFile = null;
71
72 if (home != null) {
73 File f = new File(home);
74 try {
75 homeFile = f.getCanonicalFile();
76 } catch (IOException ioe) {
77 homeFile = f.getAbsoluteFile();
78 }
79 }
80
81 if (homeFile == null) {
82
83
84 File bootstrapJar = new File(userDir, "bootstrap.jar");
85
86 if (bootstrapJar.exists()) {
87 File f = new File(userDir, "..");
88 try {
89 homeFile = f.getCanonicalFile();
90 } catch (IOException ioe) {
91 homeFile = f.getAbsoluteFile();
92 }
93 }
94 }
95
96 if (homeFile == null) {
97
98 File f = new File(userDir);
99 try {
100 homeFile = f.getCanonicalFile();
101 } catch (IOException ioe) {
102 homeFile = f.getAbsoluteFile();
103 }
104 }
105
106 catalinaHomeFile = homeFile;
107 System.setProperty(
108 Globals.CATALINA_HOME_PROP, catalinaHomeFile.getPath());
109
110
111 String base = System.getProperty(Globals.CATALINA_BASE_PROP);
112 if (base == null) {
113 catalinaBaseFile = catalinaHomeFile;
114 } else {
115 File baseFile = new File(base);
116 try {
117 baseFile = baseFile.getCanonicalFile();
118 } catch (IOException ioe) {
119 baseFile = baseFile.getAbsoluteFile();
120 }
121 catalinaBaseFile = baseFile;
122 }
123 System.setProperty(
124 Globals.CATALINA_BASE_PROP, catalinaBaseFile.getPath());
125 }
126
127
128
129
130
133 private Object catalinaDaemon = null;
134
135 ClassLoader commonLoader = null;
136 ClassLoader catalinaLoader = null;
137 ClassLoader sharedLoader = null;
138
139
140
141
142
143 private void initClassLoaders() {
144 try {
145 commonLoader = createClassLoader("common", null);
146 if (commonLoader == null) {
147
148 commonLoader = this.getClass().getClassLoader();
149 }
150 catalinaLoader = createClassLoader("server", commonLoader);
151 sharedLoader = createClassLoader("shared", commonLoader);
152 } catch (Throwable t) {
153 handleThrowable(t);
154 log.error("Class loader creation threw exception", t);
155 System.exit(1);
156 }
157 }
158
159
160 private ClassLoader createClassLoader(String name, ClassLoader parent)
161 throws Exception {
162
163 String value = CatalinaProperties.getProperty(name + ".loader");
164 if ((value == null) || (value.equals("")))
165 return parent;
166
167 value = replace(value);
168
169 List<Repository> repositories = new ArrayList<>();
170
171 String[] repositoryPaths = getPaths(value);
172
173 for (String repository : repositoryPaths) {
174
175 try {
176 @SuppressWarnings("unused")
177 URL url = new URL(repository);
178 repositories.add(new Repository(repository, RepositoryType.URL));
179 continue;
180 } catch (MalformedURLException e) {
181
182 }
183
184
185 if (repository.endsWith("*.jar")) {
186 repository = repository.substring
187 (0, repository.length() - "*.jar".length());
188 repositories.add(new Repository(repository, RepositoryType.GLOB));
189 } else if (repository.endsWith(".jar")) {
190 repositories.add(new Repository(repository, RepositoryType.JAR));
191 } else {
192 repositories.add(new Repository(repository, RepositoryType.DIR));
193 }
194 }
195
196 return ClassLoaderFactory.createClassLoader(repositories, parent);
197 }
198
199
200
206 protected String replace(String str) {
207
208
209 String result = str;
210 int pos_start = str.indexOf("${");
211 if (pos_start >= 0) {
212 StringBuilder builder = new StringBuilder();
213 int pos_end = -1;
214 while (pos_start >= 0) {
215 builder.append(str, pos_end + 1, pos_start);
216 pos_end = str.indexOf('}', pos_start + 2);
217 if (pos_end < 0) {
218 pos_end = pos_start - 1;
219 break;
220 }
221 String propName = str.substring(pos_start + 2, pos_end);
222 String replacement;
223 if (propName.length() == 0) {
224 replacement = null;
225 } else if (Globals.CATALINA_HOME_PROP.equals(propName)) {
226 replacement = getCatalinaHome();
227 } else if (Globals.CATALINA_BASE_PROP.equals(propName)) {
228 replacement = getCatalinaBase();
229 } else {
230 replacement = System.getProperty(propName);
231 }
232 if (replacement != null) {
233 builder.append(replacement);
234 } else {
235 builder.append(str, pos_start, pos_end + 1);
236 }
237 pos_start = str.indexOf("${", pos_end + 1);
238 }
239 builder.append(str, pos_end + 1, str.length());
240 result = builder.toString();
241 }
242 return result;
243 }
244
245
246
250 public void init() throws Exception {
251
252 initClassLoaders();
253
254 Thread.currentThread().setContextClassLoader(catalinaLoader);
255
256 SecurityClassLoad.securityClassLoad(catalinaLoader);
257
258
259 if (log.isDebugEnabled())
260 log.debug("Loading startup class");
261 Class<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
262 Object startupInstance = startupClass.getConstructor().newInstance();
263
264
265 if (log.isDebugEnabled())
266 log.debug("Setting startup class properties");
267 String methodName = "setParentClassLoader";
268 Class<?> paramTypes[] = new Class[1];
269 paramTypes[0] = Class.forName("java.lang.ClassLoader");
270 Object paramValues[] = new Object[1];
271 paramValues[0] = sharedLoader;
272 Method method =
273 startupInstance.getClass().getMethod(methodName, paramTypes);
274 method.invoke(startupInstance, paramValues);
275
276 catalinaDaemon = startupInstance;
277 }
278
279
280
283 private void load(String[] arguments) throws Exception {
284
285
286 String methodName = "load";
287 Object param[];
288 Class<?> paramTypes[];
289 if (arguments==null || arguments.length==0) {
290 paramTypes = null;
291 param = null;
292 } else {
293 paramTypes = new Class[1];
294 paramTypes[0] = arguments.getClass();
295 param = new Object[1];
296 param[0] = arguments;
297 }
298 Method method =
299 catalinaDaemon.getClass().getMethod(methodName, paramTypes);
300 if (log.isDebugEnabled()) {
301 log.debug("Calling startup class " + method);
302 }
303 method.invoke(catalinaDaemon, param);
304 }
305
306
307
310 private Object getServer() throws Exception {
311
312 String methodName = "getServer";
313 Method method = catalinaDaemon.getClass().getMethod(methodName);
314 return method.invoke(catalinaDaemon);
315 }
316
317
318
319
320
321
326 public void init(String[] arguments) throws Exception {
327
328 init();
329 load(arguments);
330 }
331
332
333
337 public void start() throws Exception {
338 if (catalinaDaemon == null) {
339 init();
340 }
341
342 Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);
343 method.invoke(catalinaDaemon, (Object [])null);
344 }
345
346
347
351 public void stop() throws Exception {
352 Method method = catalinaDaemon.getClass().getMethod("stop", (Class []) null);
353 method.invoke(catalinaDaemon, (Object []) null);
354 }
355
356
357
361 public void stopServer() throws Exception {
362
363 Method method =
364 catalinaDaemon.getClass().getMethod("stopServer", (Class []) null);
365 method.invoke(catalinaDaemon, (Object []) null);
366 }
367
368
369
374 public void stopServer(String[] arguments) throws Exception {
375
376 Object param[];
377 Class<?> paramTypes[];
378 if (arguments == null || arguments.length == 0) {
379 paramTypes = null;
380 param = null;
381 } else {
382 paramTypes = new Class[1];
383 paramTypes[0] = arguments.getClass();
384 param = new Object[1];
385 param[0] = arguments;
386 }
387 Method method =
388 catalinaDaemon.getClass().getMethod("stopServer", paramTypes);
389 method.invoke(catalinaDaemon, param);
390 }
391
392
393
398 public void setAwait(boolean await)
399 throws Exception {
400
401 Class<?> paramTypes[] = new Class[1];
402 paramTypes[0] = Boolean.TYPE;
403 Object paramValues[] = new Object[1];
404 paramValues[0] = Boolean.valueOf(await);
405 Method method =
406 catalinaDaemon.getClass().getMethod("setAwait", paramTypes);
407 method.invoke(catalinaDaemon, paramValues);
408 }
409
410 public boolean getAwait() throws Exception {
411 Class<?> paramTypes[] = new Class[0];
412 Object paramValues[] = new Object[0];
413 Method method =
414 catalinaDaemon.getClass().getMethod("getAwait", paramTypes);
415 Boolean b=(Boolean)method.invoke(catalinaDaemon, paramValues);
416 return b.booleanValue();
417 }
418
419
420
423 public void destroy() {
424
425
426
427 }
428
429
430
436 public static void main(String args[]) {
437
438 synchronized (daemonLock) {
439 if (daemon == null) {
440
441 Bootstrap bootstrap = new Bootstrap();
442 try {
443 bootstrap.init();
444 } catch (Throwable t) {
445 handleThrowable(t);
446 t.printStackTrace();
447 return;
448 }
449 daemon = bootstrap;
450 } else {
451
452
453
454 Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
455 }
456 }
457
458 try {
459 String command = "start";
460 if (args.length > 0) {
461 command = args[args.length - 1];
462 }
463
464 if (command.equals("startd")) {
465 args[args.length - 1] = "start";
466 daemon.load(args);
467 daemon.start();
468 } else if (command.equals("stopd")) {
469 args[args.length - 1] = "stop";
470 daemon.stop();
471 } else if (command.equals("start")) {
472 daemon.setAwait(true);
473 daemon.load(args);
474 daemon.start();
475 if (null == daemon.getServer()) {
476 System.exit(1);
477 }
478 } else if (command.equals("stop")) {
479 daemon.stopServer(args);
480 } else if (command.equals("configtest")) {
481 daemon.load(args);
482 if (null == daemon.getServer()) {
483 System.exit(1);
484 }
485 System.exit(0);
486 } else {
487 log.warn("Bootstrap: command \"" + command + "\" does not exist.");
488 }
489 } catch (Throwable t) {
490
491 if (t instanceof InvocationTargetException &&
492 t.getCause() != null) {
493 t = t.getCause();
494 }
495 handleThrowable(t);
496 t.printStackTrace();
497 System.exit(1);
498 }
499 }
500
501
502
507 public static String getCatalinaHome() {
508 return catalinaHomeFile.getPath();
509 }
510
511
512
518 public static String getCatalinaBase() {
519 return catalinaBaseFile.getPath();
520 }
521
522
523
528 public static File getCatalinaHomeFile() {
529 return catalinaHomeFile;
530 }
531
532
533
539 public static File getCatalinaBaseFile() {
540 return catalinaBaseFile;
541 }
542
543
544
545 private static void handleThrowable(Throwable t) {
546 if (t instanceof ThreadDeath) {
547 throw (ThreadDeath) t;
548 }
549 if (t instanceof VirtualMachineError) {
550 throw (VirtualMachineError) t;
551 }
552
553 }
554
555
556
557 protected static String[] getPaths(String value) {
558
559 List<String> result = new ArrayList<>();
560 Matcher matcher = PATH_PATTERN.matcher(value);
561
562 while (matcher.find()) {
563 String path = value.substring(matcher.start(), matcher.end());
564
565 path = path.trim();
566 if (path.length() == 0) {
567 continue;
568 }
569
570 char first = path.charAt(0);
571 char last = path.charAt(path.length() - 1);
572
573 if (first == '"' && last == '"' && path.length() > 1) {
574 path = path.substring(1, path.length() - 1);
575 path = path.trim();
576 if (path.length() == 0) {
577 continue;
578 }
579 } else if (path.contains("\"")) {
580
581
582
583 throw new IllegalArgumentException(
584 "The double quote [\"] character only be used to quote paths. It must " +
585 "not appear in a path. This loader path is not valid: [" + value + "]");
586 } else {
587
588 }
589
590 result.add(path);
591 }
592
593 return result.toArray(new String[result.size()]);
594 }
595 }
596