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 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 /**
57  * Startup/Shutdown shell program for Catalina.  The following command line
58  * options are recognized:
59  * <ul>
60  * <li><b>-config {pathname}</b> - Set the pathname of the configuration file
61  *     to be processed.  If a relative path is specified, it will be
62  *     interpreted as relative to the directory pathname specified by the
63  *     "catalina.base" system property.   [conf/server.xml]</li>
64  * <li><b>-help</b>      - Display usage information.</li>
65  * <li><b>-nonaming</b>  - Disable naming support.</li>
66  * <li><b>configtest</b> - Try to test the config</li>
67  * <li><b>start</b>      - Start an instance of Catalina.</li>
68  * <li><b>stop</b>       - Stop the currently running instance of Catalina.</li>
69  * </ul>
70  *
71  * @author Craig R. McClanahan
72  * @author Remy Maucherat
73  */

74 public class Catalina {
75
76
77     /**
78      * The string manager for this package.
79      */

80     protected static final StringManager sm =
81         StringManager.getManager(Constants.Package);
82
83     public static final String SERVER_XML = "conf/server.xml";
84
85     // ----------------------------------------------------- Instance Variables
86
87     /**
88      * Use await.
89      */

90     protected boolean await = false;
91
92     /**
93      * Pathname to the server configuration file.
94      */

95     protected String configFile = SERVER_XML;
96
97     // XXX Should be moved to embedded
98     /**
99      * The shared extensions class loader for this server.
100      */

101     protected ClassLoader parentClassLoader =
102         Catalina.class.getClassLoader();
103
104
105     /**
106      * The server component we are starting or stopping.
107      */

108     protected Server server = null;
109
110
111     /**
112      * Use shutdown hook flag.
113      */

114     protected boolean useShutdownHook = true;
115
116
117     /**
118      * Shutdown hook.
119      */

120     protected Thread shutdownHook = null;
121
122
123     /**
124      * Is naming enabled ?
125      */

126     protected boolean useNaming = true;
127
128
129     /**
130      * Prevent duplicate loads.
131      */

132     protected boolean loaded = false;
133
134
135     // ----------------------------------------------------------- Constructors
136
137     public Catalina() {
138         setSecurityProtection();
139         ExceptionUtils.preload();
140     }
141
142
143     // ------------------------------------------------------------- Properties
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     /**
166      * Set the shared extensions class loader.
167      *
168      * @param parentClassLoader The shared extensions class loader.
169      */

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     /**
192      * @return <code>true</code> if naming is enabled.
193      */

194     public boolean isUseNaming() {
195         return this.useNaming;
196     }
197
198
199     /**
200      * Enables or disables naming support.
201      *
202      * @param useNaming The new use naming value
203      */

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     // ------------------------------------------------------ Protected Methods
217
218
219     /**
220      * Process the specified command line arguments.
221      *
222      * @param args Command line arguments to process
223      * @return <code>true</code> if we should continue processing
224      */

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                 // NOOP
247             } else if (args[i].equals("configtest")) {
248                 // NOOP
249             } else if (args[i].equals("stop")) {
250                 // NOOP
251             } else {
252                 usage();
253                 return false;
254             }
255         }
256
257         return true;
258     }
259
260
261     /**
262      * Return a File object representing our configuration file.
263      * @return the main configuration file
264      */

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     /**
277      * Create and configure the Digester we will be using for startup.
278      * @return the main digester to parse server.xml
279      */

280     protected Digester createStartDigester() {
281         long t1=System.currentTimeMillis();
282         // Initialize the digester
283         Digester digester = new Digester();
284         digester.setValidating(false);
285         digester.setRulesValidation(true);
286         Map<Class<?>, List<String>> fakeAttributes = new HashMap<>();
287         // Ignore className on all elements
288         List<String> objectAttrs = new ArrayList<>();
289         objectAttrs.add("className");
290         fakeAttributes.put(Object.class, objectAttrs);
291         // Ignore attribute added by Eclipse for its internal tracking
292         List<String> contextAttrs = new ArrayList<>();
293         contextAttrs.add("source");
294         fakeAttributes.put(StandardContext.class, contextAttrs);
295         // Ignore Connector attribute used internally but set on Server
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         // Configure the actions we will be using
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// MUST be specified in the element
335                                  "className");
336         digester.addSetProperties("Server/Service/Listener");
337         digester.addSetNext("Server/Service/Listener",
338                             "addLifecycleListener",
339                             "org.apache.catalina.LifecycleListener");
340
341         //Executor
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// MUST be specified in the element
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// MUST be specified in the element
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         // Add RuleSets for nested elements
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         // When the 'engine' is found, set the parentClassLoader.
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     /**
429      * Cluster support is optional. The JARs may have been removed.
430      */

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     /**
451      * Create and configure the Digester we will be using for shutdown.
452      * @return the digester to process the stop operation
453      */

454     protected Digester createStopDigester() {
455
456         // Initialize the digester
457         Digester digester = new Digester();
458         digester.setUseContextClassLoader(true);
459
460         // Configure the rules we need for shutting down
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             // Create and execute our Digester
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             // Server object already present. Must be running as a service
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         // Stop the existing server
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     /**
538      * Start a new server instance.
539      */

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         // Before digester - it may be needed
552         initNaming();
553
554         // Set configuration source
555         ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), getConfigFile()));
556         File file = configFile();
557
558         // Create and execute our Digester
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         // Stream redirection
580         initStreams();
581
582         // Start the new server
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     /*
601      * Load using arguments
602      */

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     /**
616      * Start a new server instance.
617      */

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         // Start the new server
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         // Register shutdown hook
650         if (useShutdownHook) {
651             if (shutdownHook == null) {
652                 shutdownHook = new CatalinaShutdownHook();
653             }
654             Runtime.getRuntime().addShutdownHook(shutdownHook);
655
656             // If JULI is being used, disable JULI's shutdown hook since
657             // shutdown hooks run in parallel and log messages may be lost
658             // if JULI's hook completes before the CatalinaShutdownHook()
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     /**
674      * Stop an existing server instance.
675      */

676     public void stop() {
677
678         try {
679             // Remove the ShutdownHook first so that server.stop()
680             // doesn't get invoked twice
681             if (useShutdownHook) {
682                 Runtime.getRuntime().removeShutdownHook(shutdownHook);
683
684                 // If JULI is being used, re-enable JULI's shutdown to ensure
685                 // log messages are not lost
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             // This will fail on JDK 1.2. Ignoring, as Tomcat can run
695             // fine without the shutdown hook.
696         }
697
698         // Shut down the server
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                 // Nothing to do. stop() was already called
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     /**
717      * Await and shutdown.
718      */

719     public void await() {
720
721         getServer().await();
722
723     }
724
725
726     /**
727      * Print usage information for this application.
728      */

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         // Replace System.out and System.err with a custom PrintStream
746         System.setOut(new SystemLogHandler(System.out));
747         System.setErr(new SystemLogHandler(System.err));
748     }
749
750
751     protected void initNaming() {
752         // Setting additional variables
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     /**
782      * Set the security package access/protection.
783      */

784     protected void setSecurityProtection(){
785         SecurityConfig securityConfig = SecurityConfig.newInstance();
786         securityConfig.setPackageDefinition();
787         securityConfig.setPackageAccess();
788     }
789
790
791     // --------------------------------------- CatalinaShutdownHook Inner Class
792
793     // XXX Should be moved to embedded !
794     /**
795      * Shutdown hook which will perform a clean shutdown of Catalina if needed.
796      */

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                 // If JULI is used, shut JULI down *after* the server shuts down
810                 // so log messages aren't lost
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 // ------------------------------------------------------------ Private Classes
826
827
828 /**
829  * Rule that sets the parent class loader for the top object on the stack,
830  * which must be a <code>Container</code>.
831  */

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