1
17 package org.apache.catalina.startup;
18
19
20 import java.io.File;
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.lang.reflect.Constructor;
26 import java.net.ConnectException;
27 import java.net.Socket;
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.logging.LogManager;
33
34 import org.apache.catalina.Container;
35 import org.apache.catalina.LifecycleException;
36 import org.apache.catalina.LifecycleState;
37 import org.apache.catalina.Server;
38 import org.apache.catalina.connector.Connector;
39 import org.apache.catalina.core.StandardContext;
40 import org.apache.catalina.security.SecurityConfig;
41 import org.apache.juli.ClassLoaderLogManager;
42 import org.apache.juli.logging.Log;
43 import org.apache.juli.logging.LogFactory;
44 import org.apache.tomcat.util.ExceptionUtils;
45 import org.apache.tomcat.util.digester.Digester;
46 import org.apache.tomcat.util.digester.Rule;
47 import org.apache.tomcat.util.digester.RuleSet;
48 import org.apache.tomcat.util.file.ConfigFileLoader;
49 import org.apache.tomcat.util.file.ConfigurationSource;
50 import org.apache.tomcat.util.log.SystemLogHandler;
51 import org.apache.tomcat.util.res.StringManager;
52 import org.xml.sax.Attributes;
53 import org.xml.sax.InputSource;
54
55
56
74 public class Catalina {
75
76
77
80 protected static final StringManager sm =
81 StringManager.getManager(Constants.Package);
82
83 public static final String SERVER_XML = "conf/server.xml";
84
85
86
87
90 protected boolean await = false;
91
92
95 protected String configFile = SERVER_XML;
96
97
98
101 protected ClassLoader parentClassLoader =
102 Catalina.class.getClassLoader();
103
104
105
108 protected Server server = null;
109
110
111
114 protected boolean useShutdownHook = true;
115
116
117
120 protected Thread shutdownHook = null;
121
122
123
126 protected boolean useNaming = true;
127
128
129
132 protected boolean loaded = false;
133
134
135
136
137 public Catalina() {
138 setSecurityProtection();
139 ExceptionUtils.preload();
140 }
141
142
143
144
145 public void setConfigFile(String file) {
146 configFile = file;
147 }
148
149
150 public String getConfigFile() {
151 return configFile;
152 }
153
154
155 public void setUseShutdownHook(boolean useShutdownHook) {
156 this.useShutdownHook = useShutdownHook;
157 }
158
159
160 public boolean getUseShutdownHook() {
161 return useShutdownHook;
162 }
163
164
165
170 public void setParentClassLoader(ClassLoader parentClassLoader) {
171 this.parentClassLoader = parentClassLoader;
172 }
173
174 public ClassLoader getParentClassLoader() {
175 if (parentClassLoader != null) {
176 return parentClassLoader;
177 }
178 return ClassLoader.getSystemClassLoader();
179 }
180
181 public void setServer(Server server) {
182 this.server = server;
183 }
184
185
186 public Server getServer() {
187 return server;
188 }
189
190
191
194 public boolean isUseNaming() {
195 return this.useNaming;
196 }
197
198
199
204 public void setUseNaming(boolean useNaming) {
205 this.useNaming = useNaming;
206 }
207
208 public void setAwait(boolean b) {
209 await = b;
210 }
211
212 public boolean isAwait() {
213 return await;
214 }
215
216
217
218
219
225 protected boolean arguments(String args[]) {
226
227 boolean isConfig = false;
228
229 if (args.length < 1) {
230 usage();
231 return false;
232 }
233
234 for (int i = 0; i < args.length; i++) {
235 if (isConfig) {
236 configFile = args[i];
237 isConfig = false;
238 } else if (args[i].equals("-config")) {
239 isConfig = true;
240 } else if (args[i].equals("-nonaming")) {
241 setUseNaming(false);
242 } else if (args[i].equals("-help")) {
243 usage();
244 return false;
245 } else if (args[i].equals("start")) {
246
247 } else if (args[i].equals("configtest")) {
248
249 } else if (args[i].equals("stop")) {
250
251 } else {
252 usage();
253 return false;
254 }
255 }
256
257 return true;
258 }
259
260
261
265 protected File configFile() {
266
267 File file = new File(configFile);
268 if (!file.isAbsolute()) {
269 file = new File(Bootstrap.getCatalinaBase(), configFile);
270 }
271 return file;
272
273 }
274
275
276
280 protected Digester createStartDigester() {
281 long t1=System.currentTimeMillis();
282
283 Digester digester = new Digester();
284 digester.setValidating(false);
285 digester.setRulesValidation(true);
286 Map<Class<?>, List<String>> fakeAttributes = new HashMap<>();
287
288 List<String> objectAttrs = new ArrayList<>();
289 objectAttrs.add("className");
290 fakeAttributes.put(Object.class, objectAttrs);
291
292 List<String> contextAttrs = new ArrayList<>();
293 contextAttrs.add("source");
294 fakeAttributes.put(StandardContext.class, contextAttrs);
295
296 List<String> connectorAttrs = new ArrayList<>();
297 connectorAttrs.add("portOffset");
298 fakeAttributes.put(Connector.class, connectorAttrs);
299 digester.setFakeAttributes(fakeAttributes);
300 digester.setUseContextClassLoader(true);
301
302
303 digester.addObjectCreate("Server",
304 "org.apache.catalina.core.StandardServer",
305 "className");
306 digester.addSetProperties("Server");
307 digester.addSetNext("Server",
308 "setServer",
309 "org.apache.catalina.Server");
310
311 digester.addObjectCreate("Server/GlobalNamingResources",
312 "org.apache.catalina.deploy.NamingResourcesImpl");
313 digester.addSetProperties("Server/GlobalNamingResources");
314 digester.addSetNext("Server/GlobalNamingResources",
315 "setGlobalNamingResources",
316 "org.apache.catalina.deploy.NamingResourcesImpl");
317
318 digester.addRule("Server/Listener",
319 new ListenerCreateRule(null, "className"));
320 digester.addSetProperties("Server/Listener");
321 digester.addSetNext("Server/Listener",
322 "addLifecycleListener",
323 "org.apache.catalina.LifecycleListener");
324
325 digester.addObjectCreate("Server/Service",
326 "org.apache.catalina.core.StandardService",
327 "className");
328 digester.addSetProperties("Server/Service");
329 digester.addSetNext("Server/Service",
330 "addService",
331 "org.apache.catalina.Service");
332
333 digester.addObjectCreate("Server/Service/Listener",
334 null,
335 "className");
336 digester.addSetProperties("Server/Service/Listener");
337 digester.addSetNext("Server/Service/Listener",
338 "addLifecycleListener",
339 "org.apache.catalina.LifecycleListener");
340
341
342 digester.addObjectCreate("Server/Service/Executor",
343 "org.apache.catalina.core.StandardThreadExecutor",
344 "className");
345 digester.addSetProperties("Server/Service/Executor");
346
347 digester.addSetNext("Server/Service/Executor",
348 "addExecutor",
349 "org.apache.catalina.Executor");
350
351
352 digester.addRule("Server/Service/Connector",
353 new ConnectorCreateRule());
354 digester.addRule("Server/Service/Connector", new SetAllPropertiesRule(
355 new String[]{"executor", "sslImplementationName", "protocol"}));
356 digester.addSetNext("Server/Service/Connector",
357 "addConnector",
358 "org.apache.catalina.connector.Connector");
359
360 digester.addRule("Server/Service/Connector", new AddPortOffsetRule());
361
362 digester.addObjectCreate("Server/Service/Connector/SSLHostConfig",
363 "org.apache.tomcat.util.net.SSLHostConfig");
364 digester.addSetProperties("Server/Service/Connector/SSLHostConfig");
365 digester.addSetNext("Server/Service/Connector/SSLHostConfig",
366 "addSslHostConfig",
367 "org.apache.tomcat.util.net.SSLHostConfig");
368
369 digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
370 new CertificateCreateRule());
371 digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",
372 new SetAllPropertiesRule(new String[]{"type"}));
373 digester.addSetNext("Server/Service/Connector/SSLHostConfig/Certificate",
374 "addCertificate",
375 "org.apache.tomcat.util.net.SSLHostConfigCertificate");
376
377 digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
378 "org.apache.tomcat.util.net.openssl.OpenSSLConf");
379 digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf");
380 digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf",
381 "setOpenSslConf",
382 "org.apache.tomcat.util.net.openssl.OpenSSLConf");
383
384 digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
385 "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
386 digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd");
387 digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd",
388 "addCmd",
389 "org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");
390
391 digester.addObjectCreate("Server/Service/Connector/Listener",
392 null,
393 "className");
394 digester.addSetProperties("Server/Service/Connector/Listener");
395 digester.addSetNext("Server/Service/Connector/Listener",
396 "addLifecycleListener",
397 "org.apache.catalina.LifecycleListener");
398
399 digester.addObjectCreate("Server/Service/Connector/UpgradeProtocol",
400 null,
401 "className");
402 digester.addSetProperties("Server/Service/Connector/UpgradeProtocol");
403 digester.addSetNext("Server/Service/Connector/UpgradeProtocol",
404 "addUpgradeProtocol",
405 "org.apache.coyote.UpgradeProtocol");
406
407
408 digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/"));
409 digester.addRuleSet(new EngineRuleSet("Server/Service/"));
410 digester.addRuleSet(new HostRuleSet("Server/Service/Engine/"));
411 digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/"));
412 addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
413 digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/"));
414
415
416 digester.addRule("Server/Service/Engine",
417 new SetParentClassLoaderRule(parentClassLoader));
418 addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");
419
420 long t2=System.currentTimeMillis();
421 if (log.isDebugEnabled()) {
422 log.debug("Digester for server.xml created " + ( t2-t1 ));
423 }
424 return digester;
425
426 }
427
428
431 private void addClusterRuleSet(Digester digester, String prefix) {
432 Class<?> clazz = null;
433 Constructor<?> constructor = null;
434 try {
435 clazz = Class.forName("org.apache.catalina.ha.ClusterRuleSet");
436 constructor = clazz.getConstructor(String.class);
437 RuleSet ruleSet = (RuleSet) constructor.newInstance(prefix);
438 digester.addRuleSet(ruleSet);
439 } catch (Exception e) {
440 if (log.isDebugEnabled()) {
441 log.debug(sm.getString("catalina.noCluster",
442 e.getClass().getName() + ": " + e.getMessage()), e);
443 } else if (log.isInfoEnabled()) {
444 log.info(sm.getString("catalina.noCluster",
445 e.getClass().getName() + ": " + e.getMessage()));
446 }
447 }
448 }
449
450
454 protected Digester createStopDigester() {
455
456
457 Digester digester = new Digester();
458 digester.setUseContextClassLoader(true);
459
460
461 digester.addObjectCreate("Server",
462 "org.apache.catalina.core.StandardServer",
463 "className");
464 digester.addSetProperties("Server");
465 digester.addSetNext("Server",
466 "setServer",
467 "org.apache.catalina.Server");
468
469 return digester;
470
471 }
472
473
474 public void stopServer() {
475 stopServer(null);
476 }
477
478 public void stopServer(String[] arguments) {
479
480 if (arguments != null) {
481 arguments(arguments);
482 }
483
484 Server s = getServer();
485 if (s == null) {
486
487 Digester digester = createStopDigester();
488 File file = configFile();
489 try (FileInputStream fis = new FileInputStream(file)) {
490 InputSource is =
491 new InputSource(file.toURI().toURL().toString());
492 is.setByteStream(fis);
493 digester.push(this);
494 digester.parse(is);
495 } catch (Exception e) {
496 log.error(sm.getString("catalina.stopError"), e);
497 System.exit(1);
498 }
499 } else {
500
501 try {
502 s.stop();
503 s.destroy();
504 } catch (LifecycleException e) {
505 log.error(sm.getString("catalina.stopError"), e);
506 }
507 return;
508 }
509
510
511 s = getServer();
512 if (s.getPortWithOffset() > 0) {
513 try (Socket socket = new Socket(s.getAddress(), s.getPortWithOffset());
514 OutputStream stream = socket.getOutputStream()) {
515 String shutdown = s.getShutdown();
516 for (int i = 0; i < shutdown.length(); i++) {
517 stream.write(shutdown.charAt(i));
518 }
519 stream.flush();
520 } catch (ConnectException ce) {
521 log.error(sm.getString("catalina.stopServer.connectException", s.getAddress(),
522 String.valueOf(s.getPortWithOffset()), String.valueOf(s.getPort()),
523 String.valueOf(s.getPortOffset())));
524 log.error(sm.getString("catalina.stopError"), ce);
525 System.exit(1);
526 } catch (IOException e) {
527 log.error(sm.getString("catalina.stopError"), e);
528 System.exit(1);
529 }
530 } else {
531 log.error(sm.getString("catalina.stopServer"));
532 System.exit(1);
533 }
534 }
535
536
537
540 public void load() {
541
542 if (loaded) {
543 return;
544 }
545 loaded = true;
546
547 long t1 = System.nanoTime();
548
549 initDirs();
550
551
552 initNaming();
553
554
555 ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), getConfigFile()));
556 File file = configFile();
557
558
559 Digester digester = createStartDigester();
560
561 try (ConfigurationSource.Resource resource = ConfigFileLoader.getSource().getServerXml()) {
562 InputStream inputStream = resource.getInputStream();
563 InputSource inputSource = new InputSource(resource.getURI().toURL().toString());
564 inputSource.setByteStream(inputStream);
565 digester.push(this);
566 digester.parse(inputSource);
567 } catch (Exception e) {
568 log.warn(sm.getString("catalina.configFail", file.getAbsolutePath()), e);
569 if (file.exists() && !file.canRead()) {
570 log.warn(sm.getString("catalina.incorrectPermissions"));
571 }
572 return;
573 }
574
575 getServer().setCatalina(this);
576 getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());
577 getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());
578
579
580 initStreams();
581
582
583 try {
584 getServer().init();
585 } catch (LifecycleException e) {
586 if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
587 throw new java.lang.Error(e);
588 } else {
589 log.error(sm.getString("catalina.initError"), e);
590 }
591 }
592
593 long t2 = System.nanoTime();
594 if(log.isInfoEnabled()) {
595 log.info(sm.getString("catalina.init", Long.valueOf((t2 - t1) / 1000000)));
596 }
597 }
598
599
600
603 public void load(String args[]) {
604
605 try {
606 if (arguments(args)) {
607 load();
608 }
609 } catch (Exception e) {
610 e.printStackTrace(System.out);
611 }
612 }
613
614
615
618 public void start() {
619
620 if (getServer() == null) {
621 load();
622 }
623
624 if (getServer() == null) {
625 log.fatal(sm.getString("catalina.noServer"));
626 return;
627 }
628
629 long t1 = System.nanoTime();
630
631
632 try {
633 getServer().start();
634 } catch (LifecycleException e) {
635 log.fatal(sm.getString("catalina.serverStartFail"), e);
636 try {
637 getServer().destroy();
638 } catch (LifecycleException e1) {
639 log.debug("destroy() failed for failed Server ", e1);
640 }
641 return;
642 }
643
644 long t2 = System.nanoTime();
645 if(log.isInfoEnabled()) {
646 log.info(sm.getString("catalina.startup", Long.valueOf((t2 - t1) / 1000000)));
647 }
648
649
650 if (useShutdownHook) {
651 if (shutdownHook == null) {
652 shutdownHook = new CatalinaShutdownHook();
653 }
654 Runtime.getRuntime().addShutdownHook(shutdownHook);
655
656
657
658
659 LogManager logManager = LogManager.getLogManager();
660 if (logManager instanceof ClassLoaderLogManager) {
661 ((ClassLoaderLogManager) logManager).setUseShutdownHook(
662 false);
663 }
664 }
665
666 if (await) {
667 await();
668 stop();
669 }
670 }
671
672
673
676 public void stop() {
677
678 try {
679
680
681 if (useShutdownHook) {
682 Runtime.getRuntime().removeShutdownHook(shutdownHook);
683
684
685
686 LogManager logManager = LogManager.getLogManager();
687 if (logManager instanceof ClassLoaderLogManager) {
688 ((ClassLoaderLogManager) logManager).setUseShutdownHook(
689 true);
690 }
691 }
692 } catch (Throwable t) {
693 ExceptionUtils.handleThrowable(t);
694
695
696 }
697
698
699 try {
700 Server s = getServer();
701 LifecycleState state = s.getState();
702 if (LifecycleState.STOPPING_PREP.compareTo(state) <= 0
703 && LifecycleState.DESTROYED.compareTo(state) >= 0) {
704
705 } else {
706 s.stop();
707 s.destroy();
708 }
709 } catch (LifecycleException e) {
710 log.error(sm.getString("catalina.stopError"), e);
711 }
712
713 }
714
715
716
719 public void await() {
720
721 getServer().await();
722
723 }
724
725
726
729 protected void usage() {
730
731 System.out.println(sm.getString("catalina.usage"));
732
733 }
734
735
736 protected void initDirs() {
737 String temp = System.getProperty("java.io.tmpdir");
738 if (temp == null || (!(new File(temp)).isDirectory())) {
739 log.error(sm.getString("embedded.notmp", temp));
740 }
741 }
742
743
744 protected void initStreams() {
745
746 System.setOut(new SystemLogHandler(System.out));
747 System.setErr(new SystemLogHandler(System.err));
748 }
749
750
751 protected void initNaming() {
752
753 if (!useNaming) {
754 log.info(sm.getString("catalina.noNatming"));
755 System.setProperty("catalina.useNaming", "false");
756 } else {
757 System.setProperty("catalina.useNaming", "true");
758 String value = "org.apache.naming";
759 String oldValue =
760 System.getProperty(javax.naming.Context.URL_PKG_PREFIXES);
761 if (oldValue != null) {
762 value = value + ":" + oldValue;
763 }
764 System.setProperty(javax.naming.Context.URL_PKG_PREFIXES, value);
765 if( log.isDebugEnabled() ) {
766 log.debug("Setting naming prefix=" + value);
767 }
768 value = System.getProperty
769 (javax.naming.Context.INITIAL_CONTEXT_FACTORY);
770 if (value == null) {
771 System.setProperty
772 (javax.naming.Context.INITIAL_CONTEXT_FACTORY,
773 "org.apache.naming.java.javaURLContextFactory");
774 } else {
775 log.debug("INITIAL_CONTEXT_FACTORY already set " + value );
776 }
777 }
778 }
779
780
781
784 protected void setSecurityProtection(){
785 SecurityConfig securityConfig = SecurityConfig.newInstance();
786 securityConfig.setPackageDefinition();
787 securityConfig.setPackageAccess();
788 }
789
790
791
792
793
794
797 protected class CatalinaShutdownHook extends Thread {
798
799 @Override
800 public void run() {
801 try {
802 if (getServer() != null) {
803 Catalina.this.stop();
804 }
805 } catch (Throwable ex) {
806 ExceptionUtils.handleThrowable(ex);
807 log.error(sm.getString("catalina.shutdownHookFail"), ex);
808 } finally {
809
810
811 LogManager logManager = LogManager.getLogManager();
812 if (logManager instanceof ClassLoaderLogManager) {
813 ((ClassLoaderLogManager) logManager).shutdown();
814 }
815 }
816 }
817 }
818
819
820 private static final Log log = LogFactory.getLog(Catalina.class);
821
822 }
823
824
825
826
827
828
832
833 final class SetParentClassLoaderRule extends Rule {
834
835 public SetParentClassLoaderRule(ClassLoader parentClassLoader) {
836
837 this.parentClassLoader = parentClassLoader;
838
839 }
840
841 ClassLoader parentClassLoader = null;
842
843 @Override
844 public void begin(String namespace, String name, Attributes attributes)
845 throws Exception {
846
847 if (digester.getLogger().isDebugEnabled()) {
848 digester.getLogger().debug("Setting parent class loader");
849 }
850
851 Container top = (Container) digester.peek();
852 top.setParentClassLoader(parentClassLoader);
853
854 }
855
856
857 }
858