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.core;
18
19 import java.io.File;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.net.MalformedURLException;
23 import java.net.URL;
24 import java.nio.charset.StandardCharsets;
25 import java.security.AccessController;
26 import java.security.PrivilegedAction;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.Enumeration;
31 import java.util.EventListener;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.LinkedHashMap;
35 import java.util.List;
36 import java.util.Locale;
37 import java.util.Map;
38 import java.util.Map.Entry;
39 import java.util.Set;
40 import java.util.Stack;
41 import java.util.TreeMap;
42 import java.util.concurrent.ConcurrentHashMap;
43 import java.util.concurrent.CopyOnWriteArrayList;
44 import java.util.concurrent.atomic.AtomicLong;
45 import java.util.concurrent.locks.Lock;
46 import java.util.concurrent.locks.ReadWriteLock;
47 import java.util.concurrent.locks.ReentrantReadWriteLock;
48
49 import javax.management.ListenerNotFoundException;
50 import javax.management.MBeanNotificationInfo;
51 import javax.management.Notification;
52 import javax.management.NotificationBroadcasterSupport;
53 import javax.management.NotificationEmitter;
54 import javax.management.NotificationFilter;
55 import javax.management.NotificationListener;
56 import javax.naming.NamingException;
57 import javax.servlet.Filter;
58 import javax.servlet.FilterConfig;
59 import javax.servlet.FilterRegistration;
60 import javax.servlet.RequestDispatcher;
61 import javax.servlet.Servlet;
62 import javax.servlet.ServletContainerInitializer;
63 import javax.servlet.ServletContext;
64 import javax.servlet.ServletContextAttributeListener;
65 import javax.servlet.ServletContextEvent;
66 import javax.servlet.ServletContextListener;
67 import javax.servlet.ServletException;
68 import javax.servlet.ServletRegistration;
69 import javax.servlet.ServletRegistration.Dynamic;
70 import javax.servlet.ServletRequest;
71 import javax.servlet.ServletRequestAttributeListener;
72 import javax.servlet.ServletRequestEvent;
73 import javax.servlet.ServletRequestListener;
74 import javax.servlet.ServletSecurityElement;
75 import javax.servlet.SessionCookieConfig;
76 import javax.servlet.SessionTrackingMode;
77 import javax.servlet.descriptor.JspConfigDescriptor;
78 import javax.servlet.http.HttpSessionAttributeListener;
79 import javax.servlet.http.HttpSessionIdListener;
80 import javax.servlet.http.HttpSessionListener;
81
82 import org.apache.catalina.Authenticator;
83 import org.apache.catalina.Container;
84 import org.apache.catalina.ContainerListener;
85 import org.apache.catalina.Context;
86 import org.apache.catalina.CredentialHandler;
87 import org.apache.catalina.Globals;
88 import org.apache.catalina.Lifecycle;
89 import org.apache.catalina.LifecycleException;
90 import org.apache.catalina.LifecycleListener;
91 import org.apache.catalina.LifecycleState;
92 import org.apache.catalina.Loader;
93 import org.apache.catalina.Manager;
94 import org.apache.catalina.Pipeline;
95 import org.apache.catalina.Realm;
96 import org.apache.catalina.ThreadBindingListener;
97 import org.apache.catalina.Valve;
98 import org.apache.catalina.WebResource;
99 import org.apache.catalina.WebResourceRoot;
100 import org.apache.catalina.Wrapper;
101 import org.apache.catalina.deploy.NamingResourcesImpl;
102 import org.apache.catalina.loader.WebappLoader;
103 import org.apache.catalina.session.StandardManager;
104 import org.apache.catalina.util.CharsetMapper;
105 import org.apache.catalina.util.ContextName;
106 import org.apache.catalina.util.ErrorPageSupport;
107 import org.apache.catalina.util.ExtensionValidator;
108 import org.apache.catalina.util.URLEncoder;
109 import org.apache.catalina.webresources.StandardRoot;
110 import org.apache.juli.logging.Log;
111 import org.apache.juli.logging.LogFactory;
112 import org.apache.naming.ContextBindings;
113 import org.apache.tomcat.InstanceManager;
114 import org.apache.tomcat.InstanceManagerBindings;
115 import org.apache.tomcat.JarScanner;
116 import org.apache.tomcat.util.ExceptionUtils;
117 import org.apache.tomcat.util.IntrospectionUtils;
118 import org.apache.tomcat.util.buf.StringUtils;
119 import org.apache.tomcat.util.compat.JreCompat;
120 import org.apache.tomcat.util.descriptor.XmlIdentifiers;
121 import org.apache.tomcat.util.descriptor.web.ApplicationParameter;
122 import org.apache.tomcat.util.descriptor.web.ErrorPage;
123 import org.apache.tomcat.util.descriptor.web.FilterDef;
124 import org.apache.tomcat.util.descriptor.web.FilterMap;
125 import org.apache.tomcat.util.descriptor.web.Injectable;
126 import org.apache.tomcat.util.descriptor.web.InjectionTarget;
127 import org.apache.tomcat.util.descriptor.web.LoginConfig;
128 import org.apache.tomcat.util.descriptor.web.MessageDestination;
129 import org.apache.tomcat.util.descriptor.web.MessageDestinationRef;
130 import org.apache.tomcat.util.descriptor.web.SecurityCollection;
131 import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
132 import org.apache.tomcat.util.http.CookieProcessor;
133 import org.apache.tomcat.util.http.Rfc6265CookieProcessor;
134 import org.apache.tomcat.util.scan.StandardJarScanner;
135 import org.apache.tomcat.util.security.PrivilegedGetTccl;
136 import org.apache.tomcat.util.security.PrivilegedSetTccl;
137
138 /**
139  * Standard implementation of the <b>Context</b> interface.  Each
140  * child container must be a Wrapper implementation to process the
141  * requests directed to a particular servlet.
142  *
143  * @author Craig R. McClanahan
144  * @author Remy Maucherat
145  */

146 public class StandardContext extends ContainerBase
147         implements Context, NotificationEmitter {
148
149     private static final Log log = LogFactory.getLog(StandardContext.class);
150
151
152     // ----------------------------------------------------------- Constructors
153
154
155     /**
156      * Create a new StandardContext component with the default basic Valve.
157      */

158     public StandardContext() {
159
160         super();
161         pipeline.setBasic(new StandardContextValve());
162         broadcaster = new NotificationBroadcasterSupport();
163         // Set defaults
164         if (!Globals.STRICT_SERVLET_COMPLIANCE) {
165             // Strict servlet compliance requires all extension mapped servlets
166             // to be checked against welcome files
167             resourceOnlyServlets.add("jsp");
168         }
169     }
170
171
172     // ----------------------------------------------------- Instance Variables
173
174     /**
175      * Allow multipart/form-data requests to be parsed even when the
176      * target servlet doesn't specify @MultipartConfig or have a
177      * &lt;multipart-config&gt; element.
178      */

179     protected boolean allowCasualMultipartParsing = false;
180
181     /**
182      * Control whether remaining request data will be read
183      * (swallowed) even if the request violates a data size constraint.
184      */

185     private boolean swallowAbortedUploads = true;
186
187     /**
188      * The alternate deployment descriptor name.
189      */

190     private String altDDName = null;
191
192
193     /**
194      * Lifecycle provider.
195      */

196     private InstanceManager instanceManager = null;
197
198
199     /**
200      * The antiResourceLocking flag for this Context.
201      */

202     private boolean antiResourceLocking = false;
203
204
205     /**
206      * The set of application listener class names configured for this
207      * application, in the order they were encountered in the resulting merged
208      * web.xml file.
209      */

210     private String applicationListeners[] = new String[0];
211
212     private final Object applicationListenersLock = new Object();
213
214     /**
215      * The set of application listeners that are required to have limited access
216      * to ServletContext methods. See Servlet 3.1 section 4.4.
217      */

218     private final Set<Object> noPluggabilityListeners = new HashSet<>();
219
220     /**
221      * The list of instantiated application event listener objects. Note that
222      * SCIs and other code may use the pluggability APIs to add listener
223      * instances directly to this list before the application starts.
224      */

225     private List<Object> applicationEventListenersList = new CopyOnWriteArrayList<>();
226
227
228     /**
229      * The set of instantiated application lifecycle listener objects. Note that
230      * SCIs and other code may use the pluggability APIs to add listener
231      * instances directly to this list before the application starts.
232      */

233     private Object applicationLifecycleListenersObjects[] =
234         new Object[0];
235
236
237     /**
238      * The ordered set of ServletContainerInitializers for this web application.
239      */

240     private Map<ServletContainerInitializer,Set<Class<?>>> initializers =
241         new LinkedHashMap<>();
242
243
244     /**
245      * The set of application parameters defined for this application.
246      */

247     private ApplicationParameter applicationParameters[] =
248         new ApplicationParameter[0];
249
250     private final Object applicationParametersLock = new Object();
251
252
253     /**
254      * The broadcaster that sends j2ee notifications.
255      */

256     private NotificationBroadcasterSupport broadcaster = null;
257
258     /**
259      * The Locale to character set mapper for this application.
260      */

261     private CharsetMapper charsetMapper = null;
262
263
264     /**
265      * The Java class name of the CharsetMapper class to be created.
266      */

267     private String charsetMapperClass =
268       "org.apache.catalina.util.CharsetMapper";
269
270
271     /**
272      * The URL of the XML descriptor for this context.
273      */

274     private URL configFile = null;
275
276
277     /**
278      * The "correctly configured" flag for this Context.
279      */

280     private boolean configured = false;
281
282
283     /**
284      * The security constraints for this web application.
285      */

286     private volatile SecurityConstraint constraints[] =
287             new SecurityConstraint[0];
288
289     private final Object constraintsLock = new Object();
290
291
292     /**
293      * The ServletContext implementation associated with this Context.
294      */

295     protected ApplicationContext context = null;
296
297     /**
298      * The wrapped version of the associated ServletContext that is presented
299      * to listeners that are required to have limited access to ServletContext
300      * methods. See Servlet 3.1 section 4.4.
301      */

302     private NoPluggabilityServletContext noPluggabilityServletContext = null;
303
304
305     /**
306      * Should we attempt to use cookies for session id communication?
307      */

308     private boolean cookies = true;
309
310
311     /**
312      * Should we allow the <code>ServletContext.getContext()</code> method
313      * to access the context of other web applications in this server?
314      */

315     private boolean crossContext = false;
316
317
318     /**
319      * Encoded path.
320      */

321     private String encodedPath = null;
322
323
324     /**
325      * Unencoded path for this web application.
326      */

327     private String path = null;
328
329
330     /**
331      * The "follow standard delegation model" flag that will be used to
332      * configure our ClassLoader.
333      * Graal cannot actually load a class from the webapp classloader,
334      * so delegate by default.
335      */

336     private boolean delegate = JreCompat.isGraalAvailable();
337
338
339     private boolean denyUncoveredHttpMethods;
340
341
342     /**
343      * The display name of this web application.
344      */

345     private String displayName = null;
346
347
348     /**
349      * Override the default context xml location.
350      */

351     private String defaultContextXml;
352
353
354     /**
355      * Override the default web xml location.
356      */

357     private String defaultWebXml;
358
359
360     /**
361      * The distributable flag for this web application.
362      */

363     private boolean distributable = false;
364
365
366     /**
367      * The document root for this web application.
368      */

369     private String docBase = null;
370
371
372     private final ErrorPageSupport errorPageSupport = new ErrorPageSupport();
373
374     /**
375      * The set of filter configurations (and associated filter instances) we
376      * have initialized, keyed by filter name.
377      */

378     private Map<String, ApplicationFilterConfig> filterConfigs = new HashMap<>();
379
380
381     /**
382      * The set of filter definitions for this application, keyed by
383      * filter name.
384      */

385     private Map<String, FilterDef> filterDefs = new HashMap<>();
386
387
388     /**
389      * The set of filter mappings for this application, in the order
390      * they were defined in the deployment descriptor with additional mappings
391      * added via the {@link ServletContext} possibly both before and after those
392      * defined in the deployment descriptor.
393      */

394     private final ContextFilterMaps filterMaps = new ContextFilterMaps();
395
396     /**
397      * Ignore annotations.
398      */

399     private boolean ignoreAnnotations = false;
400
401
402     /**
403      * The Loader implementation with which this Container is associated.
404      */

405     private Loader loader = null;
406     private final ReadWriteLock loaderLock = new ReentrantReadWriteLock();
407
408
409     /**
410      * The login configuration descriptor for this web application.
411      */

412     private LoginConfig loginConfig = null;
413
414
415     /**
416      * The Manager implementation with which this Container is associated.
417      */

418     protected Manager manager = null;
419     private final ReadWriteLock managerLock = new ReentrantReadWriteLock();
420
421
422     /**
423      * The naming context listener for this web application.
424      */

425     private NamingContextListener namingContextListener = null;
426
427
428     /**
429      * The naming resources for this web application.
430      */

431     private NamingResourcesImpl namingResources = null;
432
433     /**
434      * The message destinations for this web application.
435      */

436     private HashMap<String, MessageDestination> messageDestinations =
437         new HashMap<>();
438
439
440     /**
441      * The MIME mappings for this web application, keyed by extension.
442      */

443     private Map<String, String> mimeMappings = new HashMap<>();
444
445
446     /**
447      * The context initialization parameters for this web application,
448      * keyed by name.
449      */

450     private final Map<String, String> parameters = new ConcurrentHashMap<>();
451
452
453     /**
454      * The request processing pause flag (while reloading occurs)
455      */

456     private volatile boolean paused = false;
457
458
459     /**
460      * The public identifier of the DTD for the web application deployment
461      * descriptor version we are currently parsing.  This is used to support
462      * relaxed validation rules when processing version 2.2 web.xml files.
463      */

464     private String publicId = null;
465
466
467     /**
468      * The reloadable flag for this web application.
469      */

470     private boolean reloadable = false;
471
472
473     /**
474      * Unpack WAR property.
475      */

476     private boolean unpackWAR = true;
477
478
479     /**
480      * Context level override for default {@link StandardHost#isCopyXML()}.
481      */

482     private boolean copyXML = false;
483
484
485     /**
486      * The default context override flag for this web application.
487      */

488     private boolean override = false;
489
490
491     /**
492      * The original document root for this web application.
493      */

494     private String originalDocBase = null;
495
496
497     /**
498      * The privileged flag for this web application.
499      */

500     private boolean privileged = false;
501
502
503     /**
504      * Should the next call to <code>addWelcomeFile()</code> cause replacement
505      * of any existing welcome files?  This will be set before processing the
506      * web application's deployment descriptor, so that application specified
507      * choices <strong>replace</strong>, rather than append to, those defined
508      * in the global descriptor.
509      */

510     private boolean replaceWelcomeFiles = false;
511
512
513     /**
514      * The security role mappings for this application, keyed by role
515      * name (as used within the application).
516      */

517     private Map<String, String> roleMappings = new HashMap<>();
518
519
520     /**
521      * The security roles for this application, keyed by role name.
522      */

523     private String securityRoles[] = new String[0];
524
525     private final Object securityRolesLock = new Object();
526
527
528     /**
529      * The servlet mappings for this web application, keyed by
530      * matching pattern.
531      */

532     private Map<String, String> servletMappings = new HashMap<>();
533
534     private final Object servletMappingsLock = new Object();
535
536
537     /**
538      * The session timeout (in minutes) for this web application.
539      */

540     private int sessionTimeout = 30;
541
542     /**
543      * The notification sequence number.
544      */

545     private AtomicLong sequenceNumber = new AtomicLong(0);
546
547
548     /**
549      * Set flag to true to cause the system.out and system.err to be redirected
550      * to the logger when executing a servlet.
551      */

552     private boolean swallowOutput = false;
553
554
555     /**
556      * Amount of ms that the container will wait for servlets to unload.
557      */

558     private long unloadDelay = 2000;
559
560
561     /**
562      * The watched resources for this application.
563      */

564     private String watchedResources[] = new String[0];
565
566     private final Object watchedResourcesLock = new Object();
567
568
569     /**
570      * The welcome files for this application.
571      */

572     private String welcomeFiles[] = new String[0];
573
574     private final Object welcomeFilesLock = new Object();
575
576
577     /**
578      * The set of classnames of LifecycleListeners that will be added
579      * to each newly created Wrapper by <code>createWrapper()</code>.
580      */

581     private String wrapperLifecycles[] = new String[0];
582
583     private final Object wrapperLifecyclesLock = new Object();
584
585     /**
586      * The set of classnames of ContainerListeners that will be added
587      * to each newly created Wrapper by <code>createWrapper()</code>.
588      */

589     private String wrapperListeners[] = new String[0];
590
591     private final Object wrapperListenersLock = new Object();
592
593     /**
594      * The pathname to the work directory for this context (relative to
595      * the server's home if not absolute).
596      */

597     private String workDir = null;
598
599
600     /**
601      * Java class name of the Wrapper class implementation we use.
602      */

603     private String wrapperClassName = StandardWrapper.class.getName();
604     private Class<?> wrapperClass = null;
605
606
607     /**
608      * JNDI use flag.
609      */

610     private boolean useNaming = true;
611
612
613     /**
614      * Name of the associated naming context.
615      */

616     private String namingContextName = null;
617
618
619     private WebResourceRoot resources;
620     private final ReadWriteLock resourcesLock = new ReentrantReadWriteLock();
621
622     private long startupTime;
623     private long startTime;
624     private long tldScanTime;
625
626     /**
627      * Name of the engine. If null, the domain is used.
628      */

629     private String j2EEApplication="none";
630     private String j2EEServer="none";
631
632
633     /**
634      * Attribute value used to turn on/off XML validation for web.xml and
635      * web-fragment.xml files.
636      */

637     private boolean webXmlValidation = Globals.STRICT_SERVLET_COMPLIANCE;
638
639
640     /**
641      * Attribute value used to turn on/off XML namespace validation
642      */

643     private boolean webXmlNamespaceAware = Globals.STRICT_SERVLET_COMPLIANCE;
644
645
646     /**
647      * Attribute used to turn on/off the use of external entities.
648      */

649     private boolean xmlBlockExternal = true;
650
651
652     /**
653      * Attribute value used to turn on/off XML validation
654      */

655     private boolean tldValidation = Globals.STRICT_SERVLET_COMPLIANCE;
656
657
658     /**
659      * The name to use for session cookies. <code>null</code> indicates that
660      * the name is controlled by the application.
661      */

662     private String sessionCookieName;
663
664
665     /**
666      * The flag that indicates that session cookies should use HttpOnly
667      */

668     private boolean useHttpOnly = true;
669
670
671     /**
672      * The domain to use for session cookies. <code>null</code> indicates that
673      * the domain is controlled by the application.
674      */

675     private String sessionCookieDomain;
676
677
678     /**
679      * The path to use for session cookies. <code>null</code> indicates that
680      * the path is controlled by the application.
681      */

682     private String sessionCookiePath;
683
684
685     /**
686      * Is a / added to the end of the session cookie path to ensure browsers,
687      * particularly IE, don't send a session cookie for context /foo with
688      * requests intended for context /foobar.
689      */

690     private boolean sessionCookiePathUsesTrailingSlash = false;
691
692
693     /**
694      * The Jar scanner to use to search for Jars that might contain
695      * configuration information such as TLDs or web-fragment.xml files.
696      */

697     private JarScanner jarScanner = null;
698
699     /**
700      * Enables the RMI Target memory leak detection to be controlled. This is
701      * necessary since the detection can only work on Java 9 if some of the
702      * modularity checks are disabled.
703      */

704     private boolean clearReferencesRmiTargets = true;
705
706     /**
707      * Should Tomcat attempt to terminate threads that have been started by the
708      * web application? Stopping threads is performed via the deprecated (for
709      * good reason) <code>Thread.stop()</code> method and is likely to result in
710      * instability. As such, enabling this should be viewed as an option of last
711      * resort in a development environment and is not recommended in a
712      * production environment. If not specified, the default value of
713      * <code>false</code> will be used.
714      */

715     private boolean clearReferencesStopThreads = false;
716
717     /**
718      * Should Tomcat attempt to terminate any {@link java.util.TimerThread}s
719      * that have been started by the web application? If not specified, the
720      * default value of <code>false</code> will be used.
721      */

722     private boolean clearReferencesStopTimerThreads = false;
723
724     /**
725      * If an HttpClient keep-alive timer thread has been started by this web
726      * application and is still running, should Tomcat change the context class
727      * loader from the current {@link ClassLoader} to
728      * {@link ClassLoader#getParent()} to prevent a memory leak? Note that the
729      * keep-alive timer thread will stop on its own once the keep-alives all
730      * expire however, on a busy system that might not happen for some time.
731      */

732     private boolean clearReferencesHttpClientKeepAliveThread = true;
733
734     /**
735      * Should Tomcat renew the threads of the thread pool when the application
736      * is stopped to avoid memory leaks because of uncleaned ThreadLocal
737      * variables. This also requires that the threadRenewalDelay property of the
738      * StandardThreadExecutor or ThreadPoolExecutor be set to a positive value.
739      */

740     private boolean renewThreadsWhenStoppingContext = true;
741
742     /**
743      * Should Tomcat attempt to clear references to classes loaded by the web
744      * application class loader from the ObjectStreamClass caches?
745      */

746     private boolean clearReferencesObjectStreamClassCaches = true;
747
748     /**
749      * Should Tomcat attempt to clear references to classes loaded by this class
750      * loader from ThreadLocals?
751      */

752     private boolean clearReferencesThreadLocals = true;
753
754     /**
755      * Should Tomcat skip the memory leak checks when the web application is
756      * stopped as part of the process of shutting down the JVM?
757      */

758     private boolean skipMemoryLeakChecksOnJvmShutdown = false;
759
760     /**
761      * Should the effective web.xml be logged when the context starts?
762      */

763     private boolean logEffectiveWebXml = false;
764
765     private int effectiveMajorVersion = 3;
766
767     private int effectiveMinorVersion = 0;
768
769     private JspConfigDescriptor jspConfigDescriptor = null;
770
771     private Set<String> resourceOnlyServlets = new HashSet<>();
772
773     private String webappVersion = "";
774
775     private boolean addWebinfClassesResources = false;
776
777     private boolean fireRequestListenersOnForwards = false;
778
779     /**
780      * Servlets created via {@link ApplicationContext#createServlet(Class)} for
781      * tracking purposes.
782      */

783     private Set<Servlet> createdServlets = new HashSet<>();
784
785     private boolean preemptiveAuthentication = false;
786
787     private boolean sendRedirectBody = false;
788
789     private boolean jndiExceptionOnFailedWrite = true;
790
791     private Map<String, String> postConstructMethods = new HashMap<>();
792     private Map<String, String> preDestroyMethods = new HashMap<>();
793
794     private String containerSciFilter;
795
796     private Boolean failCtxIfServletStartFails;
797
798     protected static final ThreadBindingListener DEFAULT_NAMING_LISTENER = (new ThreadBindingListener() {
799         @Override
800         public void bind() {}
801         @Override
802         public void unbind() {}
803     });
804     protected ThreadBindingListener threadBindingListener = DEFAULT_NAMING_LISTENER;
805
806     private final Object namingToken = new Object();
807
808     private CookieProcessor cookieProcessor;
809
810     private boolean validateClientProvidedNewSessionId = true;
811
812     private boolean mapperContextRootRedirectEnabled = true;
813
814     private boolean mapperDirectoryRedirectEnabled = false;
815
816     private boolean useRelativeRedirects = !Globals.STRICT_SERVLET_COMPLIANCE;
817
818     private boolean dispatchersUseEncodedPaths = true;
819
820     private String requestEncoding = null;
821
822     private String responseEncoding = null;
823
824     private boolean allowMultipleLeadingForwardSlashInPath = false;
825
826     private final AtomicLong inProgressAsyncCount = new AtomicLong(0);
827
828     private boolean createUploadTargets = false;
829
830
831     // ----------------------------------------------------- Context Properties
832
833     @Override
834     public void setCreateUploadTargets(boolean createUploadTargets) {
835         this.createUploadTargets = createUploadTargets;
836     }
837
838
839     @Override
840     public boolean getCreateUploadTargets() {
841         return createUploadTargets;
842     }
843
844
845     @Override
846     public void incrementInProgressAsyncCount() {
847         inProgressAsyncCount.incrementAndGet();
848     }
849
850
851     @Override
852     public void decrementInProgressAsyncCount() {
853         inProgressAsyncCount.decrementAndGet();
854     }
855
856
857     public long getInProgressAsyncCount() {
858         return inProgressAsyncCount.get();
859     }
860
861
862     @Override
863     public void setAllowMultipleLeadingForwardSlashInPath(
864             boolean allowMultipleLeadingForwardSlashInPath) {
865         this.allowMultipleLeadingForwardSlashInPath = allowMultipleLeadingForwardSlashInPath;
866     }
867
868
869     @Override
870     public boolean getAllowMultipleLeadingForwardSlashInPath() {
871         return allowMultipleLeadingForwardSlashInPath;
872     }
873
874
875     @Override
876     public String getRequestCharacterEncoding() {
877         return requestEncoding;
878     }
879
880
881     @Override
882     public void setRequestCharacterEncoding(String requestEncoding) {
883         this.requestEncoding = requestEncoding;
884     }
885
886
887     @Override
888     public String getResponseCharacterEncoding() {
889         return responseEncoding;
890     }
891
892
893     @Override
894     public void setResponseCharacterEncoding(String responseEncoding) {
895         /*
896          * This ensures that the context response encoding is represented by a
897          * unique String object. This enables the Default Servlet to
898          * differentiate between a Response using this default encoding and one
899          * that has been explicitly configured.
900          */

901         if (responseEncoding == null) {
902             this.responseEncoding = null;
903         } else {
904             this.responseEncoding = new String(responseEncoding);
905         }
906     }
907
908
909     @Override
910     public void setDispatchersUseEncodedPaths(boolean dispatchersUseEncodedPaths) {
911         this.dispatchersUseEncodedPaths = dispatchersUseEncodedPaths;
912     }
913
914
915     /**
916      * {@inheritDoc}
917      * <p>
918      * The default value for this implementation is {@code true}.
919      */

920     @Override
921     public boolean getDispatchersUseEncodedPaths() {
922         return dispatchersUseEncodedPaths;
923     }
924
925
926     @Override
927     public void setUseRelativeRedirects(boolean useRelativeRedirects) {
928         this.useRelativeRedirects = useRelativeRedirects;
929     }
930
931
932     /**
933      * {@inheritDoc}
934      * <p>
935      * The default value for this implementation is {@code true}.
936      */

937     @Override
938     public boolean getUseRelativeRedirects() {
939         return useRelativeRedirects;
940     }
941
942
943     @Override
944     public void setMapperContextRootRedirectEnabled(boolean mapperContextRootRedirectEnabled) {
945         this.mapperContextRootRedirectEnabled = mapperContextRootRedirectEnabled;
946     }
947
948
949     /**
950      * {@inheritDoc}
951      * <p>
952      * The default value for this implementation is {@code false}.
953      */

954     @Override
955     public boolean getMapperContextRootRedirectEnabled() {
956         return mapperContextRootRedirectEnabled;
957     }
958
959
960     @Override
961     public void setMapperDirectoryRedirectEnabled(boolean mapperDirectoryRedirectEnabled) {
962         this.mapperDirectoryRedirectEnabled = mapperDirectoryRedirectEnabled;
963     }
964
965
966     /**
967      * {@inheritDoc}
968      * <p>
969      * The default value for this implementation is {@code false}.
970      */

971     @Override
972     public boolean getMapperDirectoryRedirectEnabled() {
973         return mapperDirectoryRedirectEnabled;
974     }
975
976
977     @Override
978     public void setValidateClientProvidedNewSessionId(boolean validateClientProvidedNewSessionId) {
979         this.validateClientProvidedNewSessionId = validateClientProvidedNewSessionId;
980     }
981
982
983     /**
984      * {@inheritDoc}
985      * <p>
986      * The default value for this implementation is {@code true}.
987      */

988     @Override
989     public boolean getValidateClientProvidedNewSessionId() {
990         return validateClientProvidedNewSessionId;
991     }
992
993
994     @Override
995     public void setCookieProcessor(CookieProcessor cookieProcessor) {
996         if (cookieProcessor == null) {
997             throw new IllegalArgumentException(
998                     sm.getString("standardContext.cookieProcessor.null"));
999         }
1000         this.cookieProcessor = cookieProcessor;
1001     }
1002
1003
1004     @Override
1005     public CookieProcessor getCookieProcessor() {
1006         return cookieProcessor;
1007     }
1008
1009
1010     @Override
1011     public Object getNamingToken() {
1012         return namingToken;
1013     }
1014
1015
1016     @Override
1017     public void setContainerSciFilter(String containerSciFilter) {
1018         this.containerSciFilter = containerSciFilter;
1019     }
1020
1021
1022     @Override
1023     public String getContainerSciFilter() {
1024         return containerSciFilter;
1025     }
1026
1027
1028     @Override
1029     public boolean getSendRedirectBody() {
1030         return sendRedirectBody;
1031     }
1032
1033
1034     @Override
1035     public void setSendRedirectBody(boolean sendRedirectBody) {
1036         this.sendRedirectBody = sendRedirectBody;
1037     }
1038
1039
1040     @Override
1041     public boolean getPreemptiveAuthentication() {
1042         return preemptiveAuthentication;
1043     }
1044
1045
1046     @Override
1047     public void setPreemptiveAuthentication(boolean preemptiveAuthentication) {
1048         this.preemptiveAuthentication = preemptiveAuthentication;
1049     }
1050
1051
1052     @Override
1053     public void setFireRequestListenersOnForwards(boolean enable) {
1054         fireRequestListenersOnForwards = enable;
1055     }
1056
1057
1058     @Override
1059     public boolean getFireRequestListenersOnForwards() {
1060         return fireRequestListenersOnForwards;
1061     }
1062
1063
1064     @Override
1065     public void setAddWebinfClassesResources(
1066             boolean addWebinfClassesResources) {
1067         this.addWebinfClassesResources = addWebinfClassesResources;
1068     }
1069
1070
1071     @Override
1072     public boolean getAddWebinfClassesResources() {
1073         return addWebinfClassesResources;
1074     }
1075
1076
1077     @Override
1078     public void setWebappVersion(String webappVersion) {
1079         if (null == webappVersion) {
1080             this.webappVersion = "";
1081         } else {
1082             this.webappVersion = webappVersion;
1083         }
1084     }
1085
1086
1087     @Override
1088     public String getWebappVersion() {
1089         return webappVersion;
1090     }
1091
1092
1093     @Override
1094     public String getBaseName() {
1095         return new ContextName(path, webappVersion).getBaseName();
1096     }
1097
1098
1099     @Override
1100     public String getResourceOnlyServlets() {
1101         return StringUtils.join(resourceOnlyServlets);
1102     }
1103
1104
1105     @Override
1106     public void setResourceOnlyServlets(String resourceOnlyServlets) {
1107         this.resourceOnlyServlets.clear();
1108         if (resourceOnlyServlets == null) {
1109             return;
1110         }
1111         for (String servletName : resourceOnlyServlets.split(",")) {
1112             servletName = servletName.trim();
1113             if (servletName.length()>0) {
1114                 this.resourceOnlyServlets.add(servletName);
1115             }
1116         }
1117     }
1118
1119
1120     @Override
1121     public boolean isResourceOnlyServlet(String servletName) {
1122         return resourceOnlyServlets.contains(servletName);
1123     }
1124
1125
1126     @Override
1127     public int getEffectiveMajorVersion() {
1128         return effectiveMajorVersion;
1129     }
1130
1131     @Override
1132     public void setEffectiveMajorVersion(int effectiveMajorVersion) {
1133         this.effectiveMajorVersion = effectiveMajorVersion;
1134     }
1135
1136     @Override
1137     public int getEffectiveMinorVersion() {
1138         return effectiveMinorVersion;
1139     }
1140
1141     @Override
1142     public void setEffectiveMinorVersion(int effectiveMinorVersion) {
1143         this.effectiveMinorVersion = effectiveMinorVersion;
1144     }
1145
1146     @Override
1147     public void setLogEffectiveWebXml(boolean logEffectiveWebXml) {
1148         this.logEffectiveWebXml = logEffectiveWebXml;
1149     }
1150
1151     @Override
1152     public boolean getLogEffectiveWebXml() {
1153         return logEffectiveWebXml;
1154     }
1155
1156     @Override
1157     public Authenticator getAuthenticator() {
1158         Pipeline pipeline = getPipeline();
1159         if (pipeline != null) {
1160             Valve basic = pipeline.getBasic();
1161             if (basic instanceof Authenticator)
1162                 return (Authenticator) basic;
1163             for (Valve valve : pipeline.getValves()) {
1164                 if (valve instanceof Authenticator) {
1165                     return (Authenticator) valve;
1166                 }
1167             }
1168         }
1169         return null;
1170     }
1171
1172     @Override
1173     public JarScanner getJarScanner() {
1174         if (jarScanner == null) {
1175             jarScanner = new StandardJarScanner();
1176         }
1177         return jarScanner;
1178     }
1179
1180
1181     @Override
1182     public void setJarScanner(JarScanner jarScanner) {
1183         this.jarScanner = jarScanner;
1184     }
1185
1186
1187     @Override
1188     public InstanceManager getInstanceManager() {
1189        return instanceManager;
1190     }
1191
1192
1193     @Override
1194     public void setInstanceManager(InstanceManager instanceManager) {
1195        this.instanceManager = instanceManager;
1196     }
1197
1198
1199     @Override
1200     public String getEncodedPath() {
1201         return encodedPath;
1202     }
1203
1204
1205     /**
1206      * Set to <code>true</code> to allow requests mapped to servlets that
1207      * do not explicitly declare @MultipartConfig or have
1208      * &lt;multipart-config&gt; specified in web.xml to parse
1209      * multipart/form-data requests.
1210      *
1211      * @param allowCasualMultipartParsing <code>true</code> to allow such
1212      *        casual parsing, <code>false</code> otherwise.
1213      */

1214     @Override
1215     public void setAllowCasualMultipartParsing(
1216             boolean allowCasualMultipartParsing) {
1217         this.allowCasualMultipartParsing = allowCasualMultipartParsing;
1218     }
1219
1220     /**
1221      * Returns <code>true</code> if requests mapped to servlets without
1222      * "multipart config" to parse multipart/form-data requests anyway.
1223      *
1224      * @return <code>true</code> if requests mapped to servlets without
1225      *    "multipart config" to parse multipart/form-data requests,
1226      *    <code>false</code> otherwise.
1227      */

1228     @Override
1229     public boolean getAllowCasualMultipartParsing() {
1230         return this.allowCasualMultipartParsing;
1231     }
1232
1233     /**
1234      * Set to <code>false</code> to disable request data swallowing
1235      * after an upload was aborted due to size constraints.
1236      *
1237      * @param swallowAbortedUploads <code>false</code> to disable
1238      *        swallowing, <code>true</code> otherwise (default).
1239      */

1240     @Override
1241     public void setSwallowAbortedUploads(boolean swallowAbortedUploads) {
1242         this.swallowAbortedUploads = swallowAbortedUploads;
1243     }
1244
1245     /**
1246      * Returns <code>true</code> if remaining request data will be read
1247      * (swallowed) even the request violates a data size constraint.
1248      *
1249      * @return <code>true</code> if data will be swallowed (default),
1250      *    <code>false</code> otherwise.
1251      */

1252     @Override
1253     public boolean getSwallowAbortedUploads() {
1254         return this.swallowAbortedUploads;
1255     }
1256
1257     /**
1258      * Add a ServletContainerInitializer instance to this web application.
1259      *
1260      * @param sci       The instance to add
1261      * @param classes   The classes in which the initializer expressed an
1262      *                  interest
1263      */

1264     @Override
1265     public void addServletContainerInitializer(
1266             ServletContainerInitializer sci, Set<Class<?>> classes) {
1267         initializers.put(sci, classes);
1268     }
1269
1270
1271     /**
1272      * Return the "follow standard delegation model" flag used to configure
1273      * our ClassLoader.
1274      *
1275      * @return <code>true</code> if classloading delegates to the parent classloader first
1276      */

1277     public boolean getDelegate() {
1278         return this.delegate;
1279     }
1280
1281
1282     /**
1283      * Set the "follow standard delegation model" flag used to configure
1284      * our ClassLoader.
1285      *
1286      * @param delegate The new flag
1287      */

1288     public void setDelegate(boolean delegate) {
1289
1290         boolean oldDelegate = this.delegate;
1291         this.delegate = delegate;
1292         support.firePropertyChange("delegate", oldDelegate,
1293                                    this.delegate);
1294
1295     }
1296
1297
1298     /**
1299      * @return true if the internal naming support is used.
1300      */

1301     public boolean isUseNaming() {
1302         return useNaming;
1303     }
1304
1305
1306     /**
1307      * Enables or disables naming.
1308      *
1309      * @param useNaming <code>true</code> to enable the naming environment
1310      */

1311     public void setUseNaming(boolean useNaming) {
1312         this.useNaming = useNaming;
1313     }
1314
1315
1316     @Override
1317     public Object[] getApplicationEventListeners() {
1318         return applicationEventListenersList.toArray();
1319     }
1320
1321
1322     /**
1323      * {@inheritDoc}
1324      *
1325      * Note that this implementation is not thread safe. If two threads call
1326      * this method concurrently, the result may be either set of listeners or a
1327      * the union of both.
1328      */

1329     @Override
1330     public void setApplicationEventListeners(Object listeners[]) {
1331         applicationEventListenersList.clear();
1332         if (listeners != null && listeners.length > 0) {
1333             applicationEventListenersList.addAll(Arrays.asList(listeners));
1334         }
1335     }
1336
1337
1338     /**
1339      * Add a listener to the end of the list of initialized application event
1340      * listeners.
1341      *
1342      * @param listener The listener to add
1343      */

1344     public void addApplicationEventListener(Object listener) {
1345         applicationEventListenersList.add(listener);
1346     }
1347
1348
1349     @Override
1350     public Object[] getApplicationLifecycleListeners() {
1351         return applicationLifecycleListenersObjects;
1352     }
1353
1354
1355     /**
1356      * Store the set of initialized application lifecycle listener objects,
1357      * in the order they were specified in the web application deployment
1358      * descriptor, for this application.
1359      *
1360      * @param listeners The set of instantiated listener objects.
1361      */

1362     @Override
1363     public void setApplicationLifecycleListeners(Object listeners[]) {
1364         applicationLifecycleListenersObjects = listeners;
1365     }
1366
1367
1368     /**
1369      * Add a listener to the end of the list of initialized application
1370      * lifecycle listeners.
1371      *
1372      * @param listener The listener to add
1373      */

1374     public void addApplicationLifecycleListener(Object listener) {
1375         int len = applicationLifecycleListenersObjects.length;
1376         Object[] newListeners = Arrays.copyOf(
1377                 applicationLifecycleListenersObjects, len + 1);
1378         newListeners[len] = listener;
1379         applicationLifecycleListenersObjects = newListeners;
1380     }
1381
1382
1383     /**
1384      * @return the antiResourceLocking flag for this Context.
1385      */

1386     public boolean getAntiResourceLocking() {
1387         return this.antiResourceLocking;
1388     }
1389
1390
1391     /**
1392      * Set the antiResourceLocking feature for this Context.
1393      *
1394      * @param antiResourceLocking The new flag value
1395      */

1396     public void setAntiResourceLocking(boolean antiResourceLocking) {
1397
1398         boolean oldAntiResourceLocking = this.antiResourceLocking;
1399         this.antiResourceLocking = antiResourceLocking;
1400         support.firePropertyChange("antiResourceLocking",
1401                                    oldAntiResourceLocking,
1402                                    this.antiResourceLocking);
1403
1404     }
1405
1406
1407     /**
1408      * @return the Locale to character set mapper for this Context.
1409      */

1410     public CharsetMapper getCharsetMapper() {
1411
1412         // Create a mapper the first time it is requested
1413         if (this.charsetMapper == null) {
1414             try {
1415                 Class<?> clazz = Class.forName(charsetMapperClass);
1416                 this.charsetMapper = (CharsetMapper) clazz.getConstructor().newInstance();
1417             } catch (Throwable t) {
1418                 ExceptionUtils.handleThrowable(t);
1419                 this.charsetMapper = new CharsetMapper();
1420             }
1421         }
1422
1423         return this.charsetMapper;
1424
1425     }
1426
1427
1428     /**
1429      * Set the Locale to character set mapper for this Context.
1430      *
1431      * @param mapper The new mapper
1432      */

1433     public void setCharsetMapper(CharsetMapper mapper) {
1434
1435         CharsetMapper oldCharsetMapper = this.charsetMapper;
1436         this.charsetMapper = mapper;
1437         if( mapper != null )
1438             this.charsetMapperClass= mapper.getClass().getName();
1439         support.firePropertyChange("charsetMapper", oldCharsetMapper,
1440                                    this.charsetMapper);
1441
1442     }
1443
1444
1445     @Override
1446     public String getCharset(Locale locale) {
1447         return getCharsetMapper().getCharset(locale);
1448     }
1449
1450
1451     @Override
1452     public URL getConfigFile() {
1453         return this.configFile;
1454     }
1455
1456
1457     @Override
1458     public void setConfigFile(URL configFile) {
1459         this.configFile = configFile;
1460     }
1461
1462
1463     @Override
1464     public boolean getConfigured() {
1465         return this.configured;
1466     }
1467
1468
1469     /**
1470      * Set the "correctly configured" flag for this Context.  This can be
1471      * set to false by startup listeners that detect a fatal configuration
1472      * error to avoid the application from being made available.
1473      *
1474      * @param configured The new correctly configured flag
1475      */

1476     @Override
1477     public void setConfigured(boolean configured) {
1478
1479         boolean oldConfigured = this.configured;
1480         this.configured = configured;
1481         support.firePropertyChange("configured",
1482                                    oldConfigured,
1483                                    this.configured);
1484
1485     }
1486
1487
1488     @Override
1489     public boolean getCookies() {
1490         return this.cookies;
1491     }
1492
1493
1494     /**
1495      * Set the "use cookies for session ids" flag.
1496      *
1497      * @param cookies The new flag
1498      */

1499     @Override
1500     public void setCookies(boolean cookies) {
1501
1502         boolean oldCookies = this.cookies;
1503         this.cookies = cookies;
1504         support.firePropertyChange("cookies",
1505                                    oldCookies,
1506                                    this.cookies);
1507
1508     }
1509
1510
1511     /**
1512      * Gets the name to use for session cookies. Overrides any setting that
1513      * may be specified by the application.
1514      *
1515      * @return  The value of the default session cookie name or null if not
1516      *          specified
1517      */

1518     @Override
1519     public String getSessionCookieName() {
1520         return sessionCookieName;
1521     }
1522
1523
1524     /**
1525      * Sets the name to use for session cookies. Overrides any setting that
1526      * may be specified by the application.
1527      *
1528      * @param sessionCookieName   The name to use
1529      */

1530     @Override
1531     public void setSessionCookieName(String sessionCookieName) {
1532         String oldSessionCookieName = this.sessionCookieName;
1533         this.sessionCookieName = sessionCookieName;
1534         support.firePropertyChange("sessionCookieName",
1535                 oldSessionCookieName, sessionCookieName);
1536     }
1537
1538
1539     /**
1540      * Gets the value of the use HttpOnly cookies for session cookies flag.
1541      *
1542      * @return <code>true</code> if the HttpOnly flag should be set on session
1543      *         cookies
1544      */

1545     @Override
1546     public boolean getUseHttpOnly() {
1547         return useHttpOnly;
1548     }
1549
1550
1551     /**
1552      * Sets the use HttpOnly cookies for session cookies flag.
1553      *
1554      * @param useHttpOnly   Set to <code>true</code> to use HttpOnly cookies
1555      *                          for session cookies
1556      */

1557     @Override
1558     public void setUseHttpOnly(boolean useHttpOnly) {
1559         boolean oldUseHttpOnly = this.useHttpOnly;
1560         this.useHttpOnly = useHttpOnly;
1561         support.firePropertyChange("useHttpOnly",
1562                 oldUseHttpOnly,
1563                 this.useHttpOnly);
1564     }
1565
1566
1567     /**
1568      * Gets the domain to use for session cookies. Overrides any setting that
1569      * may be specified by the application.
1570      *
1571      * @return  The value of the default session cookie domain or null if not
1572      *          specified
1573      */

1574     @Override
1575     public String getSessionCookieDomain() {
1576         return sessionCookieDomain;
1577     }
1578
1579
1580     /**
1581      * Sets the domain to use for session cookies. Overrides any setting that
1582      * may be specified by the application.
1583      *
1584      * @param sessionCookieDomain   The domain to use
1585      */

1586     @Override
1587     public void setSessionCookieDomain(String sessionCookieDomain) {
1588         String oldSessionCookieDomain = this.sessionCookieDomain;
1589         this.sessionCookieDomain = sessionCookieDomain;
1590         support.firePropertyChange("sessionCookieDomain",
1591                 oldSessionCookieDomain, sessionCookieDomain);
1592     }
1593
1594
1595     /**
1596      * Gets the path to use for session cookies. Overrides any setting that
1597      * may be specified by the application.
1598      *
1599      * @return  The value of the default session cookie path or null if not
1600      *          specified
1601      */

1602     @Override
1603     public String getSessionCookiePath() {
1604         return sessionCookiePath;
1605     }
1606
1607
1608     /**
1609      * Sets the path to use for session cookies. Overrides any setting that
1610      * may be specified by the application.
1611      *
1612      * @param sessionCookiePath   The path to use
1613      */

1614     @Override
1615     public void setSessionCookiePath(String sessionCookiePath) {
1616         String oldSessionCookiePath = this.sessionCookiePath;
1617         this.sessionCookiePath = sessionCookiePath;
1618         support.firePropertyChange("sessionCookiePath",
1619                 oldSessionCookiePath, sessionCookiePath);
1620     }
1621
1622
1623     @Override
1624     public boolean getSessionCookiePathUsesTrailingSlash() {
1625         return sessionCookiePathUsesTrailingSlash;
1626     }
1627
1628
1629     @Override
1630     public void setSessionCookiePathUsesTrailingSlash(
1631             boolean sessionCookiePathUsesTrailingSlash) {
1632         this.sessionCookiePathUsesTrailingSlash =
1633             sessionCookiePathUsesTrailingSlash;
1634     }
1635
1636
1637     @Override
1638     public boolean getCrossContext() {
1639         return this.crossContext;
1640     }
1641
1642
1643     /**
1644      * Set the "allow crossing servlet contexts" flag.
1645      *
1646      * @param crossContext The new cross contexts flag
1647      */

1648     @Override
1649     public void setCrossContext(boolean crossContext) {
1650
1651         boolean oldCrossContext = this.crossContext;
1652         this.crossContext = crossContext;
1653         support.firePropertyChange("crossContext",
1654                                    oldCrossContext,
1655                                    this.crossContext);
1656
1657     }
1658
1659     public String getDefaultContextXml() {
1660         return defaultContextXml;
1661     }
1662
1663     /**
1664      * Set the location of the default context xml that will be used.
1665      * If not absolute, it'll be made relative to the engine's base dir
1666      * ( which defaults to catalina.base system property ).
1667      *
1668      * @param defaultContextXml The default web xml
1669      */

1670     public void setDefaultContextXml(String defaultContextXml) {
1671         this.defaultContextXml = defaultContextXml;
1672     }
1673
1674     public String getDefaultWebXml() {
1675         return defaultWebXml;
1676     }
1677
1678     /**
1679      * Set the location of the default web xml that will be used.
1680      * If not absolute, it'll be made relative to the engine's base dir
1681      * ( which defaults to catalina.base system property ).
1682      *
1683      * @param defaultWebXml The default web xml
1684      */

1685     public void setDefaultWebXml(String defaultWebXml) {
1686         this.defaultWebXml = defaultWebXml;
1687     }
1688
1689     /**
1690      * Gets the time (in milliseconds) it took to start this context.
1691      *
1692      * @return Time (in milliseconds) it took to start this context.
1693      */

1694     public long getStartupTime() {
1695         return startupTime;
1696     }
1697
1698     public void setStartupTime(long startupTime) {
1699         this.startupTime = startupTime;
1700     }
1701
1702     public long getTldScanTime() {
1703         return tldScanTime;
1704     }
1705
1706     public void setTldScanTime(long tldScanTime) {
1707         this.tldScanTime = tldScanTime;
1708     }
1709
1710
1711     @Override
1712     public boolean getDenyUncoveredHttpMethods() {
1713         return denyUncoveredHttpMethods;
1714     }
1715
1716
1717     @Override
1718     public void setDenyUncoveredHttpMethods(boolean denyUncoveredHttpMethods) {
1719         this.denyUncoveredHttpMethods = denyUncoveredHttpMethods;
1720     }
1721
1722
1723     /**
1724      * @return the display name of this web application.
1725      */

1726     @Override
1727     public String getDisplayName() {
1728         return this.displayName;
1729     }
1730
1731
1732     /**
1733      * @return the alternate Deployment Descriptor name.
1734      */

1735     @Override
1736     public String getAltDDName(){
1737         return altDDName;
1738     }
1739
1740
1741     /**
1742      * Set an alternate Deployment Descriptor name.
1743      *
1744      * @param altDDName The new name
1745      */

1746     @Override
1747     public void setAltDDName(String altDDName) {
1748         this.altDDName = altDDName;
1749         if (context != null) {
1750             context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
1751         }
1752     }
1753
1754
1755     /**
1756      * Set the display name of this web application.
1757      *
1758      * @param displayName The new display name
1759      */

1760     @Override
1761     public void setDisplayName(String displayName) {
1762
1763         String oldDisplayName = this.displayName;
1764         this.displayName = displayName;
1765         support.firePropertyChange("displayName", oldDisplayName,
1766                                    this.displayName);
1767     }
1768
1769
1770     /**
1771      * @return the distributable flag for this web application.
1772      */

1773     @Override
1774     public boolean getDistributable() {
1775         return this.distributable;
1776     }
1777
1778     /**
1779      * Set the distributable flag for this web application.
1780      *
1781      * @param distributable The new distributable flag
1782      */

1783     @Override
1784     public void setDistributable(boolean distributable) {
1785         boolean oldDistributable = this.distributable;
1786         this.distributable = distributable;
1787         support.firePropertyChange("distributable",
1788                                    oldDistributable,
1789                                    this.distributable);
1790     }
1791
1792
1793     @Override
1794     public String getDocBase() {
1795         return this.docBase;
1796     }
1797
1798
1799     @Override
1800     public void setDocBase(String docBase) {
1801         this.docBase = docBase;
1802     }
1803
1804
1805     public String getJ2EEApplication() {
1806         return j2EEApplication;
1807     }
1808
1809     public void setJ2EEApplication(String j2EEApplication) {
1810         this.j2EEApplication = j2EEApplication;
1811     }
1812
1813     public String getJ2EEServer() {
1814         return j2EEServer;
1815     }
1816
1817     public void setJ2EEServer(String j2EEServer) {
1818         this.j2EEServer = j2EEServer;
1819     }
1820
1821
1822     @Override
1823     public Loader getLoader() {
1824         Lock readLock = loaderLock.readLock();
1825         readLock.lock();
1826         try {
1827             return loader;
1828         } finally {
1829             readLock.unlock();
1830         }
1831     }
1832
1833     @Override
1834     public void setLoader(Loader loader) {
1835
1836         Lock writeLock = loaderLock.writeLock();
1837         writeLock.lock();
1838         Loader oldLoader = null;
1839         try {
1840             // Change components if necessary
1841             oldLoader = this.loader;
1842             if (oldLoader == loader)
1843                 return;
1844             this.loader = loader;
1845
1846             // Stop the old component if necessary
1847             if (getState().isAvailable() && (oldLoader != null) &&
1848                 (oldLoader instanceof Lifecycle)) {
1849                 try {
1850                     ((Lifecycle) oldLoader).stop();
1851                 } catch (LifecycleException e) {
1852                     log.error(sm.getString("standardContext.setLoader.stop"), e);
1853                 }
1854             }
1855
1856             // Start the new component if necessary
1857             if (loader != null)
1858                 loader.setContext(this);
1859             if (getState().isAvailable() && (loader != null) &&
1860                 (loader instanceof Lifecycle)) {
1861                 try {
1862                     ((Lifecycle) loader).start();
1863                 } catch (LifecycleException e) {
1864                     log.error(sm.getString("standardContext.setLoader.start"), e);
1865                 }
1866             }
1867         } finally {
1868             writeLock.unlock();
1869         }
1870
1871         // Report this property change to interested listeners
1872         support.firePropertyChange("loader", oldLoader, loader);
1873     }
1874
1875
1876     @Override
1877     public Manager getManager() {
1878         Lock readLock = managerLock.readLock();
1879         readLock.lock();
1880         try {
1881             return manager;
1882         } finally {
1883             readLock.unlock();
1884         }
1885     }
1886
1887
1888     @Override
1889     public void setManager(Manager manager) {
1890
1891         Lock writeLock = managerLock.writeLock();
1892         writeLock.lock();
1893         Manager oldManager = null;
1894         try {
1895             // Change components if necessary
1896             oldManager = this.manager;
1897             if (oldManager == manager)
1898                 return;
1899             this.manager = manager;
1900
1901             // Stop the old component if necessary
1902             if (oldManager instanceof Lifecycle) {
1903                 try {
1904                     ((Lifecycle) oldManager).stop();
1905                     ((Lifecycle) oldManager).destroy();
1906                 } catch (LifecycleException e) {
1907                     log.error(sm.getString("standardContext.setManager.stop"), e);
1908                 }
1909             }
1910
1911             // Start the new component if necessary
1912             if (manager != null) {
1913                 manager.setContext(this);
1914             }
1915             if (getState().isAvailable() && manager instanceof Lifecycle) {
1916                 try {
1917                     ((Lifecycle) manager).start();
1918                 } catch (LifecycleException e) {
1919                     log.error(sm.getString("standardContext.setManager.start"), e);
1920                 }
1921             }
1922         } finally {
1923             writeLock.unlock();
1924         }
1925
1926         // Report this property change to interested listeners
1927         support.firePropertyChange("manager", oldManager, manager);
1928     }
1929
1930
1931     /**
1932      * @return the boolean on the annotations parsing.
1933      */

1934     @Override
1935     public boolean getIgnoreAnnotations() {
1936         return this.ignoreAnnotations;
1937     }
1938
1939
1940     /**
1941      * Set the boolean on the annotations parsing for this web
1942      * application.
1943      *
1944      * @param ignoreAnnotations The boolean on the annotations parsing
1945      */

1946     @Override
1947     public void setIgnoreAnnotations(boolean ignoreAnnotations) {
1948         boolean oldIgnoreAnnotations = this.ignoreAnnotations;
1949         this.ignoreAnnotations = ignoreAnnotations;
1950         support.firePropertyChange("ignoreAnnotations", oldIgnoreAnnotations,
1951                 this.ignoreAnnotations);
1952     }
1953
1954
1955     /**
1956      * @return the login configuration descriptor for this web application.
1957      */

1958     @Override
1959     public LoginConfig getLoginConfig() {
1960         return this.loginConfig;
1961     }
1962
1963
1964     /**
1965      * Set the login configuration descriptor for this web application.
1966      *
1967      * @param config The new login configuration
1968      */

1969     @Override
1970     public void setLoginConfig(LoginConfig config) {
1971
1972         // Validate the incoming property value
1973         if (config == null)
1974             throw new IllegalArgumentException
1975                 (sm.getString("standardContext.loginConfig.required"));
1976         String loginPage = config.getLoginPage();
1977         if ((loginPage != null) && !loginPage.startsWith("/")) {
1978             if (isServlet22()) {
1979                 if(log.isDebugEnabled())
1980                     log.debug(sm.getString("standardContext.loginConfig.loginWarning",
1981                                  loginPage));
1982                 config.setLoginPage("/" + loginPage);
1983             } else {
1984                 throw new IllegalArgumentException
1985                     (sm.getString("standardContext.loginConfig.loginPage",
1986                                   loginPage));
1987             }
1988         }
1989         String errorPage = config.getErrorPage();
1990         if ((errorPage != null) && !errorPage.startsWith("/")) {
1991             if (isServlet22()) {
1992                 if(log.isDebugEnabled())
1993                     log.debug(sm.getString("standardContext.loginConfig.errorWarning",
1994                                  errorPage));
1995                 config.setErrorPage("/" + errorPage);
1996             } else {
1997                 throw new IllegalArgumentException
1998                     (sm.getString("standardContext.loginConfig.errorPage",
1999                                   errorPage));
2000             }
2001         }
2002
2003         // Process the property setting change
2004         LoginConfig oldLoginConfig = this.loginConfig;
2005         this.loginConfig = config;
2006         support.firePropertyChange("loginConfig",
2007                                    oldLoginConfig, this.loginConfig);
2008
2009     }
2010
2011
2012     /**
2013      * @return the naming resources associated with this web application.
2014      */

2015     @Override
2016     public NamingResourcesImpl getNamingResources() {
2017         if (namingResources == null) {
2018             setNamingResources(new NamingResourcesImpl());
2019         }
2020         return namingResources;
2021     }
2022
2023
2024     /**
2025      * Set the naming resources for this web application.
2026      *
2027      * @param namingResources The new naming resources
2028      */

2029     @Override
2030     public void setNamingResources(NamingResourcesImpl namingResources) {
2031
2032         // Process the property setting change
2033         NamingResourcesImpl oldNamingResources = this.namingResources;
2034         this.namingResources = namingResources;
2035         if (namingResources != null) {
2036             namingResources.setContainer(this);
2037         }
2038         support.firePropertyChange("namingResources",
2039                                    oldNamingResources, this.namingResources);
2040
2041         if (getState() == LifecycleState.NEW ||
2042                 getState() == LifecycleState.INITIALIZING ||
2043                 getState() == LifecycleState.INITIALIZED) {
2044             // NEW will occur if Context is defined in server.xml
2045             // At this point getObjectKeyPropertiesNameOnly() will trigger an
2046             // NPE.
2047             // INITIALIZED will occur if the Context is defined in a context.xml
2048             // file
2049             // If started now, a second start will be attempted when the context
2050             // starts
2051
2052             // In both cases, return and let context init the namingResources
2053             // when it starts
2054             return;
2055         }
2056
2057         if (oldNamingResources != null) {
2058             try {
2059                 oldNamingResources.stop();
2060                 oldNamingResources.destroy();
2061             } catch (LifecycleException e) {
2062                 log.error(sm.getString("standardContext.namingResource.destroy.fail"), e);
2063             }
2064         }
2065         if (namingResources != null) {
2066             try {
2067                 namingResources.init();
2068                 namingResources.start();
2069             } catch (LifecycleException e) {
2070                 log.error(sm.getString("standardContext.namingResource.init.fail"), e);
2071             }
2072         }
2073     }
2074
2075
2076     /**
2077      * @return the context path for this Context.
2078      */

2079     @Override
2080     public String getPath() {
2081         return path;
2082     }
2083
2084
2085     /**
2086      * Set the context path for this Context.
2087      *
2088      * @param path The new context path
2089      */

2090     @Override
2091     public void setPath(String path) {
2092         boolean invalid = false;
2093         if (path == null || path.equals("/")) {
2094             invalid = true;
2095             this.path = "";
2096         } else if ("".equals(path) || path.startsWith("/")) {
2097             this.path = path;
2098         } else {
2099             invalid = true;
2100             this.path = "/" + path;
2101         }
2102         if (this.path.endsWith("/")) {
2103             invalid = true;
2104             this.path = this.path.substring(0, this.path.length() - 1);
2105         }
2106         if (invalid) {
2107             log.warn(sm.getString(
2108                     "standardContext.pathInvalid", path, this.path));
2109         }
2110         encodedPath = URLEncoder.DEFAULT.encode(this.path, StandardCharsets.UTF_8);
2111         if (getName() == null) {
2112             setName(this.path);
2113         }
2114     }
2115
2116
2117     /**
2118      * @return the public identifier of the deployment descriptor DTD that is
2119      * currently being parsed.
2120      */

2121     @Override
2122     public String getPublicId() {
2123         return this.publicId;
2124     }
2125
2126
2127     /**
2128      * Set the public identifier of the deployment descriptor DTD that is
2129      * currently being parsed.
2130      *
2131      * @param publicId The public identifier
2132      */

2133     @Override
2134     public void setPublicId(String publicId) {
2135
2136         if (log.isDebugEnabled())
2137             log.debug("Setting deployment descriptor public ID to '" +
2138                 publicId + "'");
2139
2140         String oldPublicId = this.publicId;
2141         this.publicId = publicId;
2142         support.firePropertyChange("publicId", oldPublicId, publicId);
2143
2144     }
2145
2146
2147     /**
2148      * @return the reloadable flag for this web application.
2149      */

2150     @Override
2151     public boolean getReloadable() {
2152         return this.reloadable;
2153     }
2154
2155
2156     /**
2157      * @return the default context override flag for this web application.
2158      */

2159     @Override
2160     public boolean getOverride() {
2161         return this.override;
2162     }
2163
2164
2165     /**
2166      * @return the original document root for this Context.  This can be an absolute
2167      * pathname, a relative pathname, or a URL.
2168      * Is only set as deployment has change docRoot!
2169      */

2170     public String getOriginalDocBase() {
2171         return this.originalDocBase;
2172     }
2173
2174     /**
2175      * Set the original document root for this Context.  This can be an absolute
2176      * pathname, a relative pathname, or a URL.
2177      *
2178      * @param docBase The original document root
2179      */

2180     public void setOriginalDocBase(String docBase) {
2181
2182         this.originalDocBase = docBase;
2183     }
2184
2185
2186     /**
2187      * @return the parent class loader (if any) for this web application.
2188      * This call is meaningful only <strong>after</strong> a Loader has
2189      * been configured.
2190      */

2191     @Override
2192     public ClassLoader getParentClassLoader() {
2193         if (parentClassLoader != null)
2194             return parentClassLoader;
2195         if (getPrivileged()) {
2196             return this.getClass().getClassLoader();
2197         } else if (parent != null) {
2198             return parent.getParentClassLoader();
2199         }
2200         return ClassLoader.getSystemClassLoader();
2201     }
2202
2203
2204     /**
2205      * @return the privileged flag for this web application.
2206      */

2207     @Override
2208     public boolean getPrivileged() {
2209         return this.privileged;
2210     }
2211
2212
2213     /**
2214      * Set the privileged flag for this web application.
2215      *
2216      * @param privileged The new privileged flag
2217      */

2218     @Override
2219     public void setPrivileged(boolean privileged) {
2220
2221         boolean oldPrivileged = this.privileged;
2222         this.privileged = privileged;
2223         support.firePropertyChange("privileged",
2224                                    oldPrivileged,
2225                                    this.privileged);
2226
2227     }
2228
2229
2230     /**
2231      * Set the reloadable flag for this web application.
2232      *
2233      * @param reloadable The new reloadable flag
2234      */

2235     @Override
2236     public void setReloadable(boolean reloadable) {
2237
2238         boolean oldReloadable = this.reloadable;
2239         this.reloadable = reloadable;
2240         support.firePropertyChange("reloadable",
2241                                    oldReloadable,
2242                                    this.reloadable);
2243
2244     }
2245
2246
2247     /**
2248      * Set the default context override flag for this web application.
2249      *
2250      * @param override The new override flag
2251      */

2252     @Override
2253     public void setOverride(boolean override) {
2254
2255         boolean oldOverride = this.override;
2256         this.override = override;
2257         support.firePropertyChange("override",
2258                                    oldOverride,
2259                                    this.override);
2260
2261     }
2262
2263
2264     /**
2265      * Set the "replace welcome files" property.
2266      *
2267      * @param replaceWelcomeFiles The new property value
2268      */

2269     public void setReplaceWelcomeFiles(boolean replaceWelcomeFiles) {
2270
2271         boolean oldReplaceWelcomeFiles = this.replaceWelcomeFiles;
2272         this.replaceWelcomeFiles = replaceWelcomeFiles;
2273         support.firePropertyChange("replaceWelcomeFiles",
2274                                    oldReplaceWelcomeFiles,
2275                                    this.replaceWelcomeFiles);
2276
2277     }
2278
2279
2280     /**
2281      * @return the servlet context for which this Context is a facade.
2282      */

2283     @Override
2284     public ServletContext getServletContext() {
2285         if (context == null) {
2286             context = new ApplicationContext(this);
2287             if (altDDName != null)
2288                 context.setAttribute(Globals.ALT_DD_ATTR,altDDName);
2289         }
2290         return context.getFacade();
2291     }
2292
2293
2294     /**
2295      * @return the default session timeout (in minutes) for this
2296      * web application.
2297      */

2298     @Override
2299     public int getSessionTimeout() {
2300         return this.sessionTimeout;
2301     }
2302
2303
2304     /**
2305      * Set the default session timeout (in minutes) for this
2306      * web application.
2307      *
2308      * @param timeout The new default session timeout
2309      */

2310     @Override
2311     public void setSessionTimeout(int timeout) {
2312
2313         int oldSessionTimeout = this.sessionTimeout;
2314         /*
2315          * SRV.13.4 ("Deployment Descriptor"):
2316          * If the timeout is 0 or less, the container ensures the default
2317          * behaviour of sessions is never to time out.
2318          */

2319         this.sessionTimeout = (timeout == 0) ? -1 : timeout;
2320         support.firePropertyChange("sessionTimeout",
2321                                    oldSessionTimeout,
2322                                    this.sessionTimeout);
2323
2324     }
2325
2326
2327     /**
2328      * @return the value of the swallowOutput flag.
2329      */

2330     @Override
2331     public boolean getSwallowOutput() {
2332         return this.swallowOutput;
2333     }
2334
2335
2336     /**
2337      * Set the value of the swallowOutput flag. If set to true, the system.out
2338      * and system.err will be redirected to the logger during a servlet
2339      * execution.
2340      *
2341      * @param swallowOutput The new value
2342      */

2343     @Override
2344     public void setSwallowOutput(boolean swallowOutput) {
2345
2346         boolean oldSwallowOutput = this.swallowOutput;
2347         this.swallowOutput = swallowOutput;
2348         support.firePropertyChange("swallowOutput",
2349                                    oldSwallowOutput,
2350                                    this.swallowOutput);
2351
2352     }
2353
2354
2355     /**
2356      * @return the value of the unloadDelay flag.
2357      */

2358     public long getUnloadDelay() {
2359         return this.unloadDelay;
2360     }
2361
2362
2363     /**
2364      * Set the value of the unloadDelay flag, which represents the amount
2365      * of ms that the container will wait when unloading servlets.
2366      * Setting this to a small value may cause more requests to fail
2367      * to complete when stopping a web application.
2368      *
2369      * @param unloadDelay The new value
2370      */

2371     public void setUnloadDelay(long unloadDelay) {
2372
2373         long oldUnloadDelay = this.unloadDelay;
2374         this.unloadDelay = unloadDelay;
2375         support.firePropertyChange("unloadDelay",
2376                                    Long.valueOf(oldUnloadDelay),
2377                                    Long.valueOf(this.unloadDelay));
2378
2379     }
2380
2381
2382     /**
2383      * @return unpack WAR flag.
2384      */

2385     public boolean getUnpackWAR() {
2386         return unpackWAR;
2387     }
2388
2389
2390     /**
2391      * Unpack WAR flag mutator.
2392      *
2393      * @param unpackWAR <code>true</code> to unpack WARs on deployment
2394      */

2395     public void setUnpackWAR(boolean unpackWAR) {
2396         this.unpackWAR = unpackWAR;
2397     }
2398
2399
2400     /**
2401      * Flag which indicates if bundled context.xml files should be copied to the
2402      * config folder. The doesn't occur by default.
2403      *
2404      * @return <code>true</code> if the <code>META-INF/context.xml</code> file included
2405      *     in a WAR will be copied to the host configuration base folder on deployment
2406      */

2407     public boolean getCopyXML() {
2408         return copyXML;
2409     }
2410
2411
2412     /**
2413      * Allows copying a bundled context.xml file to the host configuration base
2414      * folder on deployment.
2415      *
2416      * @param copyXML the new flag value
2417      */

2418     public void setCopyXML(boolean copyXML) {
2419         this.copyXML = copyXML;
2420     }
2421
2422
2423     /**
2424      * @return the Java class name of the Wrapper implementation used
2425      * for servlets registered in this Context.
2426      */

2427     @Override
2428     public String getWrapperClass() {
2429         return this.wrapperClassName;
2430     }
2431
2432
2433     /**
2434      * Set the Java class name of the Wrapper implementation used
2435      * for servlets registered in this Context.
2436      *
2437      * @param wrapperClassName The new wrapper class name
2438      *
2439      * @throws IllegalArgumentException if the specified wrapper class
2440      * cannot be found or is not a subclass of StandardWrapper
2441      */

2442     @Override
2443     public void setWrapperClass(String wrapperClassName) {
2444
2445         this.wrapperClassName = wrapperClassName;
2446
2447         try {
2448             wrapperClass = Class.forName(wrapperClassName);
2449             if (!StandardWrapper.class.isAssignableFrom(wrapperClass)) {
2450                 throw new IllegalArgumentException(
2451                     sm.getString("standardContext.invalidWrapperClass",
2452                                  wrapperClassName));
2453             }
2454         } catch (ClassNotFoundException cnfe) {
2455             throw new IllegalArgumentException(cnfe.getMessage());
2456         }
2457     }
2458
2459
2460     @Override
2461     public WebResourceRoot getResources() {
2462         Lock readLock = resourcesLock.readLock();
2463         readLock.lock();
2464         try {
2465             return resources;
2466         } finally {
2467             readLock.unlock();
2468         }
2469     }
2470
2471
2472     @Override
2473     public void setResources(WebResourceRoot resources) {
2474
2475         Lock writeLock = resourcesLock.writeLock();
2476         writeLock.lock();
2477         WebResourceRoot oldResources = null;
2478         try {
2479             if (getState().isAvailable()) {
2480                 throw new IllegalStateException
2481                     (sm.getString("standardContext.resourcesStart"));
2482             }
2483
2484             oldResources = this.resources;
2485             if (oldResources == resources)
2486                 return;
2487
2488             this.resources = resources;
2489             if (oldResources != null) {
2490                 oldResources.setContext(null);
2491             }
2492             if (resources != null) {
2493                 resources.setContext(this);
2494             }
2495
2496             support.firePropertyChange("resources", oldResources,
2497                     resources);
2498         } finally {
2499             writeLock.unlock();
2500         }
2501     }
2502
2503
2504     @Override
2505     public JspConfigDescriptor getJspConfigDescriptor() {
2506         return jspConfigDescriptor;
2507     }
2508
2509     @Override
2510     public void setJspConfigDescriptor(JspConfigDescriptor descriptor) {
2511         this.jspConfigDescriptor = descriptor;
2512     }
2513
2514     @Override
2515     public ThreadBindingListener getThreadBindingListener() {
2516         return threadBindingListener;
2517     }
2518
2519     @Override
2520     public void setThreadBindingListener(ThreadBindingListener threadBindingListener) {
2521         this.threadBindingListener = threadBindingListener;
2522     }
2523
2524
2525     // ------------------------------------------------------ Public Properties
2526
2527     /**
2528      * @return whether or not an attempt to modify the JNDI context will trigger
2529      * an exception or if the request will be ignored.
2530      */

2531     public boolean getJndiExceptionOnFailedWrite() {
2532         return jndiExceptionOnFailedWrite;
2533     }
2534
2535
2536     /**
2537      * Controls whether or not an attempt to modify the JNDI context will
2538      * trigger an exception or if the request will be ignored.
2539      *
2540      * @param jndiExceptionOnFailedWrite <code>false</code> to avoid an exception
2541      */

2542     public void setJndiExceptionOnFailedWrite(
2543             boolean jndiExceptionOnFailedWrite) {
2544         this.jndiExceptionOnFailedWrite = jndiExceptionOnFailedWrite;
2545     }
2546
2547
2548     /**
2549      * @return the Locale to character set mapper class for this Context.
2550      */

2551     public String getCharsetMapperClass() {
2552         return this.charsetMapperClass;
2553     }
2554
2555
2556     /**
2557      * Set the Locale to character set mapper class for this Context.
2558      *
2559      * @param mapper The new mapper class
2560      */

2561     public void setCharsetMapperClass(String mapper) {
2562
2563         String oldCharsetMapperClass = this.charsetMapperClass;
2564         this.charsetMapperClass = mapper;
2565         support.firePropertyChange("charsetMapperClass",
2566                                    oldCharsetMapperClass,
2567                                    this.charsetMapperClass);
2568
2569     }
2570
2571
2572     /** Get the absolute path to the work dir.
2573      *  To avoid duplication.
2574      *
2575      * @return The work path
2576      */

2577     public String getWorkPath() {
2578         if (getWorkDir() == null) {
2579             return null;
2580         }
2581         File workDir = new File(getWorkDir());
2582         if (!workDir.isAbsolute()) {
2583             try {
2584                 workDir = new File(getCatalinaBase().getCanonicalFile(),
2585                         getWorkDir());
2586             } catch (IOException e) {
2587                 log.warn(sm.getString("standardContext.workPath", getName()),
2588                         e);
2589             }
2590         }
2591         return workDir.getAbsolutePath();
2592     }
2593
2594     /**
2595      * @return the work directory for this Context.
2596      */

2597     public String getWorkDir() {
2598         return this.workDir;
2599     }
2600
2601
2602     /**
2603      * Set the work directory for this Context.
2604      *
2605      * @param workDir The new work directory
2606      */

2607     public void setWorkDir(String workDir) {
2608
2609         this.workDir = workDir;
2610
2611         if (getState().isAvailable()) {
2612             postWorkDirectory();
2613         }
2614     }
2615
2616
2617     public boolean getClearReferencesRmiTargets() {
2618         return this.clearReferencesRmiTargets;
2619     }
2620
2621
2622     public void setClearReferencesRmiTargets(boolean clearReferencesRmiTargets) {
2623         boolean oldClearReferencesRmiTargets = this.clearReferencesRmiTargets;
2624         this.clearReferencesRmiTargets = clearReferencesRmiTargets;
2625         support.firePropertyChange("clearReferencesRmiTargets",
2626                 oldClearReferencesRmiTargets, this.clearReferencesRmiTargets);
2627     }
2628
2629
2630     /**
2631      * @return the clearReferencesStopThreads flag for this Context.
2632      */

2633     public boolean getClearReferencesStopThreads() {
2634         return this.clearReferencesStopThreads;
2635     }
2636
2637
2638     /**
2639      * Set the clearReferencesStopThreads feature for this Context.
2640      *
2641      * @param clearReferencesStopThreads The new flag value
2642      */

2643     public void setClearReferencesStopThreads(
2644             boolean clearReferencesStopThreads) {
2645
2646         boolean oldClearReferencesStopThreads = this.clearReferencesStopThreads;
2647         this.clearReferencesStopThreads = clearReferencesStopThreads;
2648         support.firePropertyChange("clearReferencesStopThreads",
2649                                    oldClearReferencesStopThreads,
2650                                    this.clearReferencesStopThreads);
2651
2652     }
2653
2654
2655     /**
2656      * @return the clearReferencesStopTimerThreads flag for this Context.
2657      */

2658     public boolean getClearReferencesStopTimerThreads() {
2659         return this.clearReferencesStopTimerThreads;
2660     }
2661
2662
2663     /**
2664      * Set the clearReferencesStopTimerThreads feature for this Context.
2665      *
2666      * @param clearReferencesStopTimerThreads The new flag value
2667      */

2668     public void setClearReferencesStopTimerThreads(
2669             boolean clearReferencesStopTimerThreads) {
2670
2671         boolean oldClearReferencesStopTimerThreads =
2672             this.clearReferencesStopTimerThreads;
2673         this.clearReferencesStopTimerThreads = clearReferencesStopTimerThreads;
2674         support.firePropertyChange("clearReferencesStopTimerThreads",
2675                                    oldClearReferencesStopTimerThreads,
2676                                    this.clearReferencesStopTimerThreads);
2677     }
2678
2679
2680     /**
2681      * @return the clearReferencesHttpClientKeepAliveThread flag for this
2682      * Context.
2683      */

2684     public boolean getClearReferencesHttpClientKeepAliveThread() {
2685         return this.clearReferencesHttpClientKeepAliveThread;
2686     }
2687
2688
2689     /**
2690      * Set the clearReferencesHttpClientKeepAliveThread feature for this
2691      * Context.
2692      *
2693      * @param clearReferencesHttpClientKeepAliveThread The new flag value
2694      */

2695     public void setClearReferencesHttpClientKeepAliveThread(
2696             boolean clearReferencesHttpClientKeepAliveThread) {
2697         this.clearReferencesHttpClientKeepAliveThread =
2698             clearReferencesHttpClientKeepAliveThread;
2699     }
2700
2701
2702     public boolean getRenewThreadsWhenStoppingContext() {
2703         return this.renewThreadsWhenStoppingContext;
2704     }
2705
2706     public void setRenewThreadsWhenStoppingContext(
2707             boolean renewThreadsWhenStoppingContext) {
2708         boolean oldRenewThreadsWhenStoppingContext =
2709                 this.renewThreadsWhenStoppingContext;
2710         this.renewThreadsWhenStoppingContext = renewThreadsWhenStoppingContext;
2711         support.firePropertyChange("renewThreadsWhenStoppingContext",
2712                 oldRenewThreadsWhenStoppingContext,
2713                 this.renewThreadsWhenStoppingContext);
2714     }
2715
2716
2717     public boolean getClearReferencesObjectStreamClassCaches() {
2718         return clearReferencesObjectStreamClassCaches;
2719     }
2720
2721
2722     public void setClearReferencesObjectStreamClassCaches(
2723             boolean clearReferencesObjectStreamClassCaches) {
2724         boolean oldClearReferencesObjectStreamClassCaches =
2725                 this.clearReferencesObjectStreamClassCaches;
2726         this.clearReferencesObjectStreamClassCaches = clearReferencesObjectStreamClassCaches;
2727         support.firePropertyChange("clearReferencesObjectStreamClassCaches",
2728                 oldClearReferencesObjectStreamClassCaches,
2729                 this.clearReferencesObjectStreamClassCaches);
2730     }
2731
2732
2733     public boolean getClearReferencesThreadLocals() {
2734         return clearReferencesThreadLocals;
2735     }
2736
2737
2738     public void setClearReferencesThreadLocals(boolean clearReferencesThreadLocals) {
2739         boolean oldClearReferencesThreadLocals = this.clearReferencesThreadLocals;
2740         this.clearReferencesThreadLocals = clearReferencesThreadLocals;
2741         support.firePropertyChange("clearReferencesThreadLocals",
2742                 oldClearReferencesThreadLocals,
2743                 this.clearReferencesThreadLocals);
2744     }
2745
2746
2747     public boolean getSkipMemoryLeakChecksOnJvmShutdown() {
2748         return skipMemoryLeakChecksOnJvmShutdown;
2749     }
2750
2751
2752     public void setSkipMemoryLeakChecksOnJvmShutdown(boolean skipMemoryLeakChecksOnJvmShutdown) {
2753         this.skipMemoryLeakChecksOnJvmShutdown = skipMemoryLeakChecksOnJvmShutdown;
2754     }
2755
2756
2757     public Boolean getFailCtxIfServletStartFails() {
2758         return failCtxIfServletStartFails;
2759     }
2760
2761     public void setFailCtxIfServletStartFails(
2762             Boolean failCtxIfServletStartFails) {
2763         Boolean oldFailCtxIfServletStartFails = this.failCtxIfServletStartFails;
2764         this.failCtxIfServletStartFails = failCtxIfServletStartFails;
2765         support.firePropertyChange("failCtxIfServletStartFails",
2766                 oldFailCtxIfServletStartFails,
2767                 failCtxIfServletStartFails);
2768     }
2769
2770     protected boolean getComputedFailCtxIfServletStartFails() {
2771         if(failCtxIfServletStartFails != null) {
2772             return failCtxIfServletStartFails.booleanValue();
2773         }
2774         //else look at Host config
2775         if(getParent() instanceof StandardHost) {
2776             return ((StandardHost)getParent()).isFailCtxIfServletStartFails();
2777         }
2778         //else
2779         return false;
2780     }
2781
2782     // -------------------------------------------------------- Context Methods
2783
2784     /**
2785      * Add a new Listener class name to the set of Listeners
2786      * configured for this application.
2787      *
2788      * @param listener Java class name of a listener class
2789      */

2790     @Override
2791     public void addApplicationListener(String listener) {
2792
2793         synchronized (applicationListenersLock) {
2794             String results[] = new String[applicationListeners.length + 1];
2795             for (int i = 0; i < applicationListeners.length; i++) {
2796                 if (listener.equals(applicationListeners[i])) {
2797                     log.info(sm.getString("standardContext.duplicateListener",listener));
2798                     return;
2799                 }
2800                 results[i] = applicationListeners[i];
2801             }
2802             results[applicationListeners.length] = listener;
2803             applicationListeners = results;
2804         }
2805         fireContainerEvent("addApplicationListener", listener);
2806
2807         // FIXME - add instance if already started?
2808     }
2809
2810
2811     /**
2812      * Add a new application parameter for this application.
2813      *
2814      * @param parameter The new application parameter
2815      */

2816     @Override
2817     public void addApplicationParameter(ApplicationParameter parameter) {
2818
2819         synchronized (applicationParametersLock) {
2820             String newName = parameter.getName();
2821             for (ApplicationParameter p : applicationParameters) {
2822                 if (newName.equals(p.getName()) && !p.getOverride())
2823                     return;
2824             }
2825             ApplicationParameter results[] = Arrays.copyOf(
2826                     applicationParameters, applicationParameters.length + 1);
2827             results[applicationParameters.length] = parameter;
2828             applicationParameters = results;
2829         }
2830         fireContainerEvent("addApplicationParameter", parameter);
2831
2832     }
2833
2834
2835     /**
2836      * Add a child Container, only if the proposed child is an implementation
2837      * of Wrapper.
2838      *
2839      * @param child Child container to be added
2840      *
2841      * @exception IllegalArgumentException if the proposed container is
2842      *  not an implementation of Wrapper
2843      */

2844     @Override
2845     public void addChild(Container child) {
2846
2847         // Global JspServlet
2848         Wrapper oldJspServlet = null;
2849
2850         if (!(child instanceof Wrapper)) {
2851             throw new IllegalArgumentException
2852                 (sm.getString("standardContext.notWrapper"));
2853         }
2854
2855         boolean isJspServlet = "jsp".equals(child.getName());
2856
2857         // Allow webapp to override JspServlet inherited from global web.xml.
2858         if (isJspServlet) {
2859             oldJspServlet = (Wrapper) findChild("jsp");
2860             if (oldJspServlet != null) {
2861                 removeChild(oldJspServlet);
2862             }
2863         }
2864
2865         super.addChild(child);
2866
2867         if (isJspServlet && oldJspServlet != null) {
2868             /*
2869              * The webapp-specific JspServlet inherits all the mappings
2870              * specified in the global web.xml, and may add additional ones.
2871              */

2872             String[] jspMappings = oldJspServlet.findMappings();
2873             for (int i=0; jspMappings!=null && i<jspMappings.length; i++) {
2874                 addServletMappingDecoded(jspMappings[i], child.getName());
2875             }
2876         }
2877     }
2878
2879
2880     /**
2881      * Add a security constraint to the set for this web application.
2882      *
2883      * @param constraint the new security constraint
2884      */

2885     @Override
2886     public void addConstraint(SecurityConstraint constraint) {
2887
2888         // Validate the proposed constraint
2889         SecurityCollection collections[] = constraint.findCollections();
2890         for (int i = 0; i < collections.length; i++) {
2891             String patterns[] = collections[i].findPatterns();
2892             for (int j = 0; j < patterns.length; j++) {
2893                 patterns[j] = adjustURLPattern(patterns[j]);
2894                 if (!validateURLPattern(patterns[j]))
2895                     throw new IllegalArgumentException
2896                         (sm.getString
2897                          ("standardContext.securityConstraint.pattern",
2898                           patterns[j]));
2899             }
2900             if (collections[i].findMethods().length > 0 &&
2901                     collections[i].findOmittedMethods().length > 0) {
2902                 throw new IllegalArgumentException(sm.getString(
2903                         "standardContext.securityConstraint.mixHttpMethod"));
2904             }
2905         }
2906
2907         // Add this constraint to the set for our web application
2908         synchronized (constraintsLock) {
2909             SecurityConstraint[] results = Arrays.copyOf(constraints, constraints.length + 1);
2910             results[constraints.length] = constraint;
2911             constraints = results;
2912         }
2913
2914     }
2915
2916
2917
2918     /**
2919      * Add an error page for the specified error or Java exception.
2920      *
2921      * @param errorPage The error page definition to be added
2922      */

2923     @Override
2924     public void addErrorPage(ErrorPage errorPage) {
2925         // Validate the input parameters
2926         if (errorPage == null)
2927             throw new IllegalArgumentException
2928                 (sm.getString("standardContext.errorPage.required"));
2929         String location = errorPage.getLocation();
2930         if ((location != null) && !location.startsWith("/")) {
2931             if (isServlet22()) {
2932                 if(log.isDebugEnabled())
2933                     log.debug(sm.getString("standardContext.errorPage.warning",
2934                                  location));
2935                 errorPage.setLocation("/" + location);
2936             } else {
2937                 throw new IllegalArgumentException
2938                     (sm.getString("standardContext.errorPage.error",
2939                                   location));
2940             }
2941         }
2942
2943         errorPageSupport.add(errorPage);
2944         fireContainerEvent("addErrorPage", errorPage);
2945     }
2946
2947
2948     /**
2949      * Add a filter definition to this Context.
2950      *
2951      * @param filterDef The filter definition to be added
2952      */

2953     @Override
2954     public void addFilterDef(FilterDef filterDef) {
2955
2956         synchronized (filterDefs) {
2957             filterDefs.put(filterDef.getFilterName(), filterDef);
2958         }
2959         fireContainerEvent("addFilterDef", filterDef);
2960
2961     }
2962
2963
2964     /**
2965      * Add a filter mapping to this Context at the end of the current set
2966      * of filter mappings.
2967      *
2968      * @param filterMap The filter mapping to be added
2969      *
2970      * @exception IllegalArgumentException if the specified filter name
2971      *  does not match an existing filter definition, or the filter mapping
2972      *  is malformed
2973      */

2974     @Override
2975     public void addFilterMap(FilterMap filterMap) {
2976         validateFilterMap(filterMap);
2977         // Add this filter mapping to our registered set
2978         filterMaps.add(filterMap);
2979         fireContainerEvent("addFilterMap", filterMap);
2980     }
2981
2982
2983     /**
2984      * Add a filter mapping to this Context before the mappings defined in the
2985      * deployment descriptor but after any other mappings added via this method.
2986      *
2987      * @param filterMap The filter mapping to be added
2988      *
2989      * @exception IllegalArgumentException if the specified filter name
2990      *  does not match an existing filter definition, or the filter mapping
2991      *  is malformed
2992      */

2993     @Override
2994     public void addFilterMapBefore(FilterMap filterMap) {
2995         validateFilterMap(filterMap);
2996         // Add this filter mapping to our registered set
2997         filterMaps.addBefore(filterMap);
2998         fireContainerEvent("addFilterMap", filterMap);
2999     }
3000
3001
3002     /**
3003      * Validate the supplied FilterMap.
3004      *
3005      * @param filterMap the filter mapping
3006      */

3007     private void validateFilterMap(FilterMap filterMap) {
3008         // Validate the proposed filter mapping
3009         String filterName = filterMap.getFilterName();
3010         String[] servletNames = filterMap.getServletNames();
3011         String[] urlPatterns = filterMap.getURLPatterns();
3012         if (findFilterDef(filterName) == null)
3013             throw new IllegalArgumentException
3014                 (sm.getString("standardContext.filterMap.name", filterName));
3015
3016         if (!filterMap.getMatchAllServletNames() &&
3017             !filterMap.getMatchAllUrlPatterns() &&
3018             (servletNames.length == 0) && (urlPatterns.length == 0))
3019             throw new IllegalArgumentException
3020                 (sm.getString("standardContext.filterMap.either"));
3021         // FIXME: Older spec revisions may still check this
3022         /*
3023         if ((servletNames.length != 0) && (urlPatterns.length != 0))
3024             throw new IllegalArgumentException
3025                 (sm.getString("standardContext.filterMap.either"));
3026         */

3027         for (int i = 0; i < urlPatterns.length; i++) {
3028             if (!validateURLPattern(urlPatterns[i])) {
3029                 throw new IllegalArgumentException
3030                     (sm.getString("standardContext.filterMap.pattern",
3031                             urlPatterns[i]));
3032             }
3033         }
3034     }
3035
3036
3037     /**
3038      * Add a Locale Encoding Mapping (see Sec 5.4 of Servlet spec 2.4)
3039      *
3040      * @param locale locale to map an encoding for
3041      * @param encoding encoding to be used for a give locale
3042      */

3043     @Override
3044     public void addLocaleEncodingMappingParameter(String locale, String encoding){
3045         getCharsetMapper().addCharsetMappingFromDeploymentDescriptor(locale, encoding);
3046     }
3047
3048
3049     /**
3050      * Add a message destination for this web application.
3051      *
3052      * @param md New message destination
3053      */

3054     public void addMessageDestination(MessageDestination md) {
3055
3056         synchronized (messageDestinations) {
3057             messageDestinations.put(md.getName(), md);
3058         }
3059         fireContainerEvent("addMessageDestination", md.getName());
3060
3061     }
3062
3063
3064     /**
3065      * Add a message destination reference for this web application.
3066      *
3067      * @param mdr New message destination reference
3068      *
3069      * @deprecated This will be removed in Tomcat 10.
3070      *             Use {@link #getNamingResources()} instead
3071      */

3072     @Deprecated
3073     public void addMessageDestinationRef(MessageDestinationRef mdr) {
3074         getNamingResources().addMessageDestinationRef(mdr);
3075     }
3076
3077
3078     /**
3079      * Add a new MIME mapping, replacing any existing mapping for
3080      * the specified extension.
3081      *
3082      * @param extension Filename extension being mapped
3083      * @param mimeType Corresponding MIME type
3084      */

3085     @Override
3086     public void addMimeMapping(String extension, String mimeType) {
3087
3088         synchronized (mimeMappings) {
3089             mimeMappings.put(extension.toLowerCase(Locale.ENGLISH), mimeType);
3090         }
3091         fireContainerEvent("addMimeMapping", extension);
3092
3093     }
3094
3095
3096     /**
3097      * Add a new context initialization parameter.
3098      *
3099      * @param name Name of the new parameter
3100      * @param value Value of the new  parameter
3101      *
3102      * @exception IllegalArgumentException if the name or value is missing,
3103      *  or if this context initialization parameter has already been
3104      *  registered
3105      */

3106     @Override
3107     public void addParameter(String name, String value) {
3108         // Validate the proposed context initialization parameter
3109         if ((name == null) || (value == null)) {
3110             throw new IllegalArgumentException
3111                 (sm.getString("standardContext.parameter.required"));
3112         }
3113
3114         // Add this parameter to our defined set if not already present
3115         String oldValue = parameters.putIfAbsent(name, value);
3116
3117         if (oldValue != null) {
3118             throw new IllegalArgumentException(
3119                     sm.getString("standardContext.parameter.duplicate", name));
3120         }
3121
3122         fireContainerEvent("addParameter", name);
3123     }
3124
3125
3126     /**
3127      * Add a security role reference for this web application.
3128      *
3129      * @param role Security role used in the application
3130      * @param link Actual security role to check for
3131      */

3132     @Override
3133     public void addRoleMapping(String role, String link) {
3134
3135         synchronized (roleMappings) {
3136             roleMappings.put(role, link);
3137         }
3138         fireContainerEvent("addRoleMapping", role);
3139
3140     }
3141
3142
3143     /**
3144      * Add a new security role for this web application.
3145      *
3146      * @param role New security role
3147      */

3148     @Override
3149     public void addSecurityRole(String role) {
3150
3151         synchronized (securityRolesLock) {
3152             String[] results = Arrays.copyOf(securityRoles, securityRoles.length + 1);
3153             results[securityRoles.length] = role;
3154             securityRoles = results;
3155         }
3156         fireContainerEvent("addSecurityRole", role);
3157
3158     }
3159
3160
3161     /**
3162      * Add a new servlet mapping, replacing any existing mapping for
3163      * the specified pattern.
3164      *
3165      * @param pattern URL pattern to be mapped
3166      * @param name Name of the corresponding servlet to execute
3167      * @param jspWildCard true if name identifies the JspServlet
3168      * and pattern contains a wildcard; false otherwise
3169      *
3170      * @exception IllegalArgumentException if the specified servlet name
3171      *  is not known to this Context
3172      */

3173     @Override
3174     public void addServletMappingDecoded(String pattern, String name,
3175                                   boolean jspWildCard) {
3176         // Validate the proposed mapping
3177         if (findChild(name) == null)
3178             throw new IllegalArgumentException
3179                 (sm.getString("standardContext.servletMap.name", name));
3180         String adjustedPattern = adjustURLPattern(pattern);
3181         if (!validateURLPattern(adjustedPattern))
3182             throw new IllegalArgumentException
3183                 (sm.getString("standardContext.servletMap.pattern", adjustedPattern));
3184
3185         // Add this mapping to our registered set
3186         synchronized (servletMappingsLock) {
3187             String name2 = servletMappings.get(adjustedPattern);
3188             if (name2 != null) {
3189                 // Don't allow more than one servlet on the same pattern
3190                 Wrapper wrapper = (Wrapper) findChild(name2);
3191                 wrapper.removeMapping(adjustedPattern);
3192             }
3193             servletMappings.put(adjustedPattern, name);
3194         }
3195         Wrapper wrapper = (Wrapper) findChild(name);
3196         wrapper.addMapping(adjustedPattern);
3197
3198         fireContainerEvent("addServletMapping", adjustedPattern);
3199     }
3200
3201
3202     /**
3203      * Add a new watched resource to the set recognized by this Context.
3204      *
3205      * @param name New watched resource file name
3206      */

3207     @Override
3208     public void addWatchedResource(String name) {
3209
3210         synchronized (watchedResourcesLock) {
3211             String[] results = Arrays.copyOf(watchedResources, watchedResources.length + 1);
3212             results[watchedResources.length] = name;
3213             watchedResources = results;
3214         }
3215         fireContainerEvent("addWatchedResource", name);
3216     }
3217
3218
3219     /**
3220      * Add a new welcome file to the set recognized by this Context.
3221      *
3222      * @param name New welcome file name
3223      */

3224     @Override
3225     public void addWelcomeFile(String name) {
3226
3227         synchronized (welcomeFilesLock) {
3228             // Welcome files from the application deployment descriptor
3229             // completely replace those from the default conf/web.xml file
3230             if (replaceWelcomeFiles) {
3231                 fireContainerEvent(CLEAR_WELCOME_FILES_EVENT, null);
3232                 welcomeFiles = new String[0];
3233                 setReplaceWelcomeFiles(false);
3234             }
3235             String[] results = Arrays.copyOf(welcomeFiles, welcomeFiles.length + 1);
3236             results[welcomeFiles.length] = name;
3237             welcomeFiles = results;
3238         }
3239         if(this.getState().equals(LifecycleState.STARTED))
3240             fireContainerEvent(ADD_WELCOME_FILE_EVENT, name);
3241     }
3242
3243
3244     /**
3245      * Add the classname of a LifecycleListener to be added to each
3246      * Wrapper appended to this Context.
3247      *
3248      * @param listener Java class name of a LifecycleListener class
3249      */

3250     @Override
3251     public void addWrapperLifecycle(String listener) {
3252
3253         synchronized (wrapperLifecyclesLock) {
3254             String[] results = Arrays.copyOf(wrapperLifecycles, wrapperLifecycles.length + 1);
3255             results[wrapperLifecycles.length] = listener;
3256             wrapperLifecycles = results;
3257         }
3258         fireContainerEvent("addWrapperLifecycle", listener);
3259
3260     }
3261
3262
3263     /**
3264      * Add the classname of a ContainerListener to be added to each
3265      * Wrapper appended to this Context.
3266      *
3267      * @param listener Java class name of a ContainerListener class
3268      */

3269     @Override
3270     public void addWrapperListener(String listener) {
3271
3272         synchronized (wrapperListenersLock) {
3273             String[] results = Arrays.copyOf(wrapperListeners, wrapperListeners.length + 1);
3274             results[wrapperListeners.length] = listener;
3275             wrapperListeners = results;
3276         }
3277         fireContainerEvent("addWrapperListener", listener);
3278
3279     }
3280
3281
3282     /**
3283      * Factory method to create and return a new Wrapper instance, of
3284      * the Java implementation class appropriate for this Context
3285      * implementation.  The constructor of the instantiated Wrapper
3286      * will have been called, but no properties will have been set.
3287      */

3288     @Override
3289     public Wrapper createWrapper() {
3290
3291         Wrapper wrapper = null;
3292         if (wrapperClass != null) {
3293             try {
3294                 wrapper = (Wrapper) wrapperClass.getConstructor().newInstance();
3295             } catch (Throwable t) {
3296                 ExceptionUtils.handleThrowable(t);
3297                 log.error(sm.getString("standardContext.createWrapper.error"), t);
3298                 return null;
3299             }
3300         } else {
3301             wrapper = new StandardWrapper();
3302         }
3303
3304         synchronized (wrapperLifecyclesLock) {
3305             for (int i = 0; i < wrapperLifecycles.length; i++) {
3306                 try {
3307                     Class<?> clazz = Class.forName(wrapperLifecycles[i]);
3308                     LifecycleListener listener =
3309                         (LifecycleListener) clazz.getConstructor().newInstance();
3310                     wrapper.addLifecycleListener(listener);
3311                 } catch (Throwable t) {
3312                     ExceptionUtils.handleThrowable(t);
3313                     log.error(sm.getString("standardContext.createWrapper.listenerError"), t);
3314                     return null;
3315                 }
3316             }
3317         }
3318
3319         synchronized (wrapperListenersLock) {
3320             for (int i = 0; i < wrapperListeners.length; i++) {
3321                 try {
3322                     Class<?> clazz = Class.forName(wrapperListeners[i]);
3323                     ContainerListener listener =
3324                             (ContainerListener) clazz.getConstructor().newInstance();
3325                     wrapper.addContainerListener(listener);
3326                 } catch (Throwable t) {
3327                     ExceptionUtils.handleThrowable(t);
3328                     log.error(sm.getString("standardContext.createWrapper.containerListenerError"), t);
3329                     return null;
3330                 }
3331             }
3332         }
3333
3334         return wrapper;
3335     }
3336
3337
3338     /**
3339      * Return the set of application listener class names configured
3340      * for this application.
3341      */

3342     @Override
3343     public String[] findApplicationListeners() {
3344         return applicationListeners;
3345     }
3346
3347
3348     /**
3349      * Return the set of application parameters for this application.
3350      */

3351     @Override
3352     public ApplicationParameter[] findApplicationParameters() {
3353
3354         synchronized (applicationParametersLock) {
3355             return applicationParameters;
3356         }
3357
3358     }
3359
3360
3361     /**
3362      * Return the security constraints for this web application.
3363      * If there are none, a zero-length array is returned.
3364      */

3365     @Override
3366     public SecurityConstraint[] findConstraints() {
3367         return constraints;
3368     }
3369
3370
3371     /**
3372      * Return the error page entry for the specified HTTP error code,
3373      * if any; otherwise return <code>null</code>.
3374      *
3375      * @param errorCode Error code to look up
3376      */

3377     @Override
3378     public ErrorPage findErrorPage(int errorCode) {
3379         return errorPageSupport.find(errorCode);
3380     }
3381
3382
3383     @Override
3384     @Deprecated
3385     public ErrorPage findErrorPage(String exceptionType) {
3386         return errorPageSupport.find(exceptionType);
3387     }
3388
3389
3390     @Override
3391     public ErrorPage findErrorPage(Throwable exceptionType) {
3392         return errorPageSupport.find(exceptionType);
3393     }
3394
3395
3396     /**
3397      * Return the set of defined error pages for all specified error codes
3398      * and exception types.
3399      */

3400     @Override
3401     public ErrorPage[] findErrorPages() {
3402         return errorPageSupport.findAll();
3403     }
3404
3405
3406     /**
3407      * Return the filter definition for the specified filter name, if any;
3408      * otherwise return <code>null</code>.
3409      *
3410      * @param filterName Filter name to look up
3411      */

3412     @Override
3413     public FilterDef findFilterDef(String filterName) {
3414         synchronized (filterDefs) {
3415             return filterDefs.get(filterName);
3416         }
3417     }
3418
3419
3420     /**
3421      * @return the set of defined filters for this Context.
3422      */

3423     @Override
3424     public FilterDef[] findFilterDefs() {
3425         synchronized (filterDefs) {
3426             FilterDef results[] = new FilterDef[filterDefs.size()];
3427             return filterDefs.values().toArray(results);
3428         }
3429     }
3430
3431
3432     /**
3433      * @return the set of filter mappings for this Context.
3434      */

3435     @Override
3436     public FilterMap[] findFilterMaps() {
3437         return filterMaps.asArray();
3438     }
3439
3440
3441     /**
3442      * @return the message destination with the specified name, if any;
3443      * otherwise, return <code>null</code>.
3444      *
3445      * @param name Name of the desired message destination
3446      */

3447     public MessageDestination findMessageDestination(String name) {
3448         synchronized (messageDestinations) {
3449             return messageDestinations.get(name);
3450         }
3451     }
3452
3453
3454     /**
3455      * @return the set of defined message destinations for this web
3456      * application.  If none have been defined, a zero-length array
3457      * is returned.
3458      */

3459     public MessageDestination[] findMessageDestinations() {
3460         synchronized (messageDestinations) {
3461             MessageDestination results[] =
3462                 new MessageDestination[messageDestinations.size()];
3463             return messageDestinations.values().toArray(results);
3464         }
3465     }
3466
3467
3468     /**
3469      * @param name Name of the desired message destination ref
3470      *
3471      * @return the message destination ref with the specified name, if any;
3472      * otherwise, return <code>null</code>.
3473      *
3474      * @deprecated This will be removed in Tomcat 10.
3475      *             Use {@link #getNamingResources()} instead
3476      */

3477     @Deprecated
3478     public MessageDestinationRef findMessageDestinationRef(String name) {
3479         return getNamingResources().findMessageDestinationRef(name);
3480     }
3481
3482
3483     /**
3484      * @return the set of defined message destination refs for this web
3485      * application.  If none have been defined, a zero-length array
3486      * is returned.
3487      *
3488      * @deprecated This will be removed in Tomcat 10.
3489      *             Use {@link #getNamingResources()} instead
3490      */

3491     @Deprecated
3492     public MessageDestinationRef[] findMessageDestinationRefs() {
3493         return getNamingResources().findMessageDestinationRefs();
3494     }
3495
3496
3497     /**
3498      * @return the MIME type to which the specified extension is mapped,
3499      * if any; otherwise return <code>null</code>.
3500      *
3501      * @param extension Extension to map to a MIME type
3502      */

3503     @Override
3504     public String findMimeMapping(String extension) {
3505         return mimeMappings.get(extension.toLowerCase(Locale.ENGLISH));
3506     }
3507
3508
3509     /**
3510      * @return the extensions for which MIME mappings are defined.  If there
3511      * are none, a zero-length array is returned.
3512      */

3513     @Override
3514     public String[] findMimeMappings() {
3515         synchronized (mimeMappings) {
3516             String results[] = new String[mimeMappings.size()];
3517             return mimeMappings.keySet().toArray(results);
3518         }
3519     }
3520
3521
3522     /**
3523      * @return the value for the specified context initialization
3524      * parameter name, if any; otherwise return <code>null</code>.
3525      *
3526      * @param name Name of the parameter to return
3527      */

3528     @Override
3529     public String findParameter(String name) {
3530         return parameters.get(name);
3531     }
3532
3533
3534     /**
3535      * @return the names of all defined context initialization parameters
3536      * for this Context.  If no parameters are defined, a zero-length
3537      * array is returned.
3538      */

3539     @Override
3540     public String[] findParameters() {
3541         List<String> parameterNames = new ArrayList<>(parameters.size());
3542         parameterNames.addAll(parameters.keySet());
3543         return parameterNames.toArray(new String[parameterNames.size()]);
3544     }
3545
3546
3547     /**
3548      * For the given security role (as used by an application), return the
3549      * corresponding role name (as defined by the underlying Realm) if there
3550      * is one.  Otherwise, return the specified role unchanged.
3551      *
3552      * @param role Security role to map
3553      * @return the role name
3554      */

3555     @Override
3556     public String findRoleMapping(String role) {
3557         String realRole = null;
3558         synchronized (roleMappings) {
3559             realRole = roleMappings.get(role);
3560         }
3561         if (realRole != null)
3562             return realRole;
3563         else
3564             return role;
3565     }
3566
3567
3568     /**
3569      * @return <code>true</code> if the specified security role is defined
3570      * for this application; otherwise return <code>false</code>.
3571      *
3572      * @param role Security role to verify
3573      */

3574     @Override
3575     public boolean findSecurityRole(String role) {
3576
3577         synchronized (securityRolesLock) {
3578             for (int i = 0; i < securityRoles.length; i++) {
3579                 if (role.equals(securityRoles[i]))
3580                     return true;
3581             }
3582         }
3583         return false;
3584
3585     }
3586
3587
3588     /**
3589      * @return the security roles defined for this application.  If none
3590      * have been defined, a zero-length array is returned.
3591      */

3592     @Override
3593     public String[] findSecurityRoles() {
3594         synchronized (securityRolesLock) {
3595             return securityRoles;
3596         }
3597     }
3598
3599
3600     /**
3601      * @return the servlet name mapped by the specified pattern (if any);
3602      * otherwise return <code>null</code>.
3603      *
3604      * @param pattern Pattern for which a mapping is requested
3605      */

3606     @Override
3607     public String findServletMapping(String pattern) {
3608         synchronized (servletMappingsLock) {
3609             return servletMappings.get(pattern);
3610         }
3611     }
3612
3613
3614     /**
3615      * @return the patterns of all defined servlet mappings for this
3616      * Context.  If no mappings are defined, a zero-length array is returned.
3617      */

3618     @Override
3619     public String[] findServletMappings() {
3620         synchronized (servletMappingsLock) {
3621             String results[] = new String[servletMappings.size()];
3622             return servletMappings.keySet().toArray(results);
3623         }
3624     }
3625
3626
3627     @Override
3628     @Deprecated
3629     public String findStatusPage(int status) {
3630
3631         ErrorPage errorPage = findErrorPage(status);
3632         if (errorPage != null) {
3633             return errorPage.getLocation();
3634         }
3635         return null;
3636     }
3637
3638
3639     @Override
3640     @Deprecated
3641     public int[] findStatusPages() {
3642         ErrorPage[] errorPages = findErrorPages();
3643         int size = errorPages.length;
3644         int temp[] = new int[size];
3645         int count = 0;
3646         for (int i = 0; i < size; i++) {
3647             if (errorPages[i].getExceptionType() == null) {
3648                 temp[count++] = errorPages[i].getErrorCode();
3649             }
3650         }
3651         int result[] = new int[count];
3652         System.arraycopy(temp, 0, result, 0, count);
3653         return result;
3654     }
3655
3656
3657     /**
3658      * @return <code>true</code> if the specified welcome file is defined
3659      * for this Context; otherwise return <code>false</code>.
3660      *
3661      * @param name Welcome file to verify
3662      */

3663     @Override
3664     public boolean findWelcomeFile(String name) {
3665
3666         synchronized (welcomeFilesLock) {
3667             for (int i = 0; i < welcomeFiles.length; i++) {
3668                 if (name.equals(welcomeFiles[i]))
3669                     return true;
3670             }
3671         }
3672         return false;
3673
3674     }
3675
3676
3677     /**
3678      * @return the set of watched resources for this Context. If none are
3679      * defined, a zero length array will be returned.
3680      */

3681     @Override
3682     public String[] findWatchedResources() {
3683         synchronized (watchedResourcesLock) {
3684             return watchedResources;
3685         }
3686     }
3687
3688
3689     /**
3690      * @return the set of welcome files defined for this Context.  If none are
3691      * defined, a zero-length array is returned.
3692      */

3693     @Override
3694     public String[] findWelcomeFiles() {
3695         synchronized (welcomeFilesLock) {
3696             return welcomeFiles;
3697         }
3698     }
3699
3700
3701     /**
3702      * @return the set of LifecycleListener classes that will be added to
3703      * newly created Wrappers automatically.
3704      */

3705     @Override
3706     public String[] findWrapperLifecycles() {
3707         synchronized (wrapperLifecyclesLock) {
3708             return wrapperLifecycles;
3709         }
3710     }
3711
3712
3713     /**
3714      * @return the set of ContainerListener classes that will be added to
3715      * newly created Wrappers automatically.
3716      */

3717     @Override
3718     public String[] findWrapperListeners() {
3719         synchronized (wrapperListenersLock) {
3720             return wrapperListeners;
3721         }
3722     }
3723
3724
3725     /**
3726      * Reload this web application, if reloading is supported.
3727      * <p>
3728      * <b>IMPLEMENTATION NOTE</b>:  This method is designed to deal with
3729      * reloads required by changes to classes in the underlying repositories
3730      * of our class loader and changes to the web.xml file. It does not handle
3731      * changes to any context.xml file. If the context.xml has changed, you
3732      * should stop this Context and create (and start) a new Context instance
3733      * instead. Note that there is additional code in
3734      * <code>CoyoteAdapter#postParseRequest()</code> to handle mapping requests
3735      * to paused Contexts.
3736      *
3737      * @exception IllegalStateException if the <code>reloadable</code>
3738      *  property is set to <code>false</code>.
3739      */

3740     @Override
3741     public synchronized void reload() {
3742
3743         // Validate our current component state
3744         if (!getState().isAvailable())
3745             throw new IllegalStateException
3746                 (sm.getString("standardContext.notStarted", getName()));
3747
3748         if(log.isInfoEnabled())
3749             log.info(sm.getString("standardContext.reloadingStarted",
3750                     getName()));
3751
3752         // Stop accepting requests temporarily.
3753         setPaused(true);
3754
3755         try {
3756             stop();
3757         } catch (LifecycleException e) {
3758             log.error(
3759                 sm.getString("standardContext.stoppingContext", getName()), e);
3760         }
3761
3762         try {
3763             start();
3764         } catch (LifecycleException e) {
3765             log.error(
3766                 sm.getString("standardContext.startingContext", getName()), e);
3767         }
3768
3769         setPaused(false);
3770
3771         if(log.isInfoEnabled())
3772             log.info(sm.getString("standardContext.reloadingCompleted",
3773                     getName()));
3774
3775     }
3776
3777
3778     /**
3779      * Remove the specified application listener class from the set of
3780      * listeners for this application.
3781      *
3782      * @param listener Java class name of the listener to be removed
3783      */

3784     @Override
3785     public void removeApplicationListener(String listener) {
3786
3787         synchronized (applicationListenersLock) {
3788
3789             // Make sure this listener is currently present
3790             int n = -1;
3791             for (int i = 0; i < applicationListeners.length; i++) {
3792                 if (applicationListeners[i].equals(listener)) {
3793                     n = i;
3794                     break;
3795                 }
3796             }
3797             if (n < 0)
3798                 return;
3799
3800             // Remove the specified listener
3801             int j = 0;
3802             String results[] = new String[applicationListeners.length - 1];
3803             for (int i = 0; i < applicationListeners.length; i++) {
3804                 if (i != n)
3805                     results[j++] = applicationListeners[i];
3806             }
3807             applicationListeners = results;
3808
3809         }
3810
3811         // Inform interested listeners
3812         fireContainerEvent("removeApplicationListener", listener);
3813
3814         // FIXME - behavior if already started?
3815     }
3816
3817
3818     /**
3819      * Remove the application parameter with the specified name from
3820      * the set for this application.
3821      *
3822      * @param name Name of the application parameter to remove
3823      */

3824     @Override
3825     public void removeApplicationParameter(String name) {
3826
3827         synchronized (applicationParametersLock) {
3828
3829             // Make sure this parameter is currently present
3830             int n = -1;
3831             for (int i = 0; i < applicationParameters.length; i++) {
3832                 if (name.equals(applicationParameters[i].getName())) {
3833                     n = i;
3834                     break;
3835                 }
3836             }
3837             if (n < 0)
3838                 return;
3839
3840             // Remove the specified parameter
3841             int j = 0;
3842             ApplicationParameter results[] =
3843                 new ApplicationParameter[applicationParameters.length - 1];
3844             for (int i = 0; i < applicationParameters.length; i++) {
3845                 if (i != n)
3846                     results[j++] = applicationParameters[i];
3847             }
3848             applicationParameters = results;
3849
3850         }
3851
3852         // Inform interested listeners
3853         fireContainerEvent("removeApplicationParameter", name);
3854
3855     }
3856
3857
3858     /**
3859      * Add a child Container, only if the proposed child is an implementation
3860      * of Wrapper.
3861      *
3862      * @param child Child container to be added
3863      *
3864      * @exception IllegalArgumentException if the proposed container is
3865      *  not an implementation of Wrapper
3866      */

3867     @Override
3868     public void removeChild(Container child) {
3869
3870         if (!(child instanceof Wrapper)) {
3871             throw new IllegalArgumentException
3872                 (sm.getString("standardContext.notWrapper"));
3873         }
3874
3875         super.removeChild(child);
3876
3877     }
3878
3879
3880     /**
3881      * Remove the specified security constraint from this web application.
3882      *
3883      * @param constraint Constraint to be removed
3884      */

3885     @Override
3886     public void removeConstraint(SecurityConstraint constraint) {
3887
3888         synchronized (constraintsLock) {
3889
3890             // Make sure this constraint is currently present
3891             int n = -1;
3892             for (int i = 0; i < constraints.length; i++) {
3893                 if (constraints[i].equals(constraint)) {
3894                     n = i;
3895                     break;
3896                 }
3897             }
3898             if (n < 0)
3899                 return;
3900
3901             // Remove the specified constraint
3902             int j = 0;
3903             SecurityConstraint results[] =
3904                 new SecurityConstraint[constraints.length - 1];
3905             for (int i = 0; i < constraints.length; i++) {
3906                 if (i != n)
3907                     results[j++] = constraints[i];
3908             }
3909             constraints = results;
3910
3911         }
3912
3913         // Inform interested listeners
3914         fireContainerEvent("removeConstraint", constraint);
3915
3916     }
3917
3918
3919     /**
3920      * Remove the error page for the specified error code or
3921      * Java language exception, if it exists; otherwise, no action is taken.
3922      *
3923      * @param errorPage The error page definition to be removed
3924      */

3925     @Override
3926     public void removeErrorPage(ErrorPage errorPage) {
3927         errorPageSupport.remove(errorPage);
3928         fireContainerEvent("removeErrorPage", errorPage);
3929     }
3930
3931
3932     /**
3933      * Remove the specified filter definition from this Context, if it exists;
3934      * otherwise, no action is taken.
3935      *
3936      * @param filterDef Filter definition to be removed
3937      */

3938     @Override
3939     public void removeFilterDef(FilterDef filterDef) {
3940
3941         synchronized (filterDefs) {
3942             filterDefs.remove(filterDef.getFilterName());
3943         }
3944         fireContainerEvent("removeFilterDef", filterDef);
3945
3946     }
3947
3948
3949     /**
3950      * Remove a filter mapping from this Context.
3951      *
3952      * @param filterMap The filter mapping to be removed
3953      */

3954     @Override
3955     public void removeFilterMap(FilterMap filterMap) {
3956         filterMaps.remove(filterMap);
3957         // Inform interested listeners
3958         fireContainerEvent("removeFilterMap", filterMap);
3959     }
3960
3961
3962     /**
3963      * Remove any message destination with the specified name.
3964      *
3965      * @param name Name of the message destination to remove
3966      */

3967     public void removeMessageDestination(String name) {
3968
3969         synchronized (messageDestinations) {
3970             messageDestinations.remove(name);
3971         }
3972         fireContainerEvent("removeMessageDestination", name);
3973
3974     }
3975
3976
3977     /**
3978      * Remove any message destination ref with the specified name.
3979      *
3980      * @param name Name of the message destination ref to remove
3981      *
3982      * @deprecated This will be removed in Tomcat 10.
3983      *             Use {@link #getNamingResources()} instead
3984      */

3985     @Deprecated
3986     public void removeMessageDestinationRef(String name) {
3987         getNamingResources().removeMessageDestinationRef(name);
3988     }
3989
3990
3991     /**
3992      * Remove the MIME mapping for the specified extension, if it exists;
3993      * otherwise, no action is taken.
3994      *
3995      * @param extension Extension to remove the mapping for
3996      */

3997     @Override
3998     public void removeMimeMapping(String extension) {
3999
4000         synchronized (mimeMappings) {
4001             mimeMappings.remove(extension);
4002         }
4003         fireContainerEvent("removeMimeMapping", extension);
4004
4005     }
4006
4007
4008     /**
4009      * Remove the context initialization parameter with the specified
4010      * name, if it exists; otherwise, no action is taken.
4011      *
4012      * @param name Name of the parameter to remove
4013      */

4014     @Override
4015     public void removeParameter(String name) {
4016         parameters.remove(name);
4017         fireContainerEvent("removeParameter", name);
4018     }
4019
4020
4021     /**
4022      * Remove any security role reference for the specified name
4023      *
4024      * @param role Security role (as used in the application) to remove
4025      */

4026     @Override
4027     public void removeRoleMapping(String role) {
4028
4029         synchronized (roleMappings) {
4030             roleMappings.remove(role);
4031         }
4032         fireContainerEvent("removeRoleMapping", role);
4033
4034     }
4035
4036
4037     /**
4038      * Remove any security role with the specified name.
4039      *
4040      * @param role Security role to remove
4041      */

4042     @Override
4043     public void removeSecurityRole(String role) {
4044
4045         synchronized (securityRolesLock) {
4046
4047             // Make sure this security role is currently present
4048             int n = -1;
4049             for (int i = 0; i < securityRoles.length; i++) {
4050                 if (role.equals(securityRoles[i])) {
4051                     n = i;
4052                     break;
4053                 }
4054             }
4055             if (n < 0)
4056                 return;
4057
4058             // Remove the specified security role
4059             int j = 0;
4060             String results[] = new String[securityRoles.length - 1];
4061             for (int i = 0; i < securityRoles.length; i++) {
4062                 if (i != n)
4063                     results[j++] = securityRoles[i];
4064             }
4065             securityRoles = results;
4066
4067         }
4068
4069         // Inform interested listeners
4070         fireContainerEvent("removeSecurityRole", role);
4071
4072     }
4073
4074
4075     /**
4076      * Remove any servlet mapping for the specified pattern, if it exists;
4077      * otherwise, no action is taken.
4078      *
4079      * @param pattern URL pattern of the mapping to remove
4080      */

4081     @Override
4082     public void removeServletMapping(String pattern) {
4083
4084         String name = null;
4085         synchronized (servletMappingsLock) {
4086             name = servletMappings.remove(pattern);
4087         }
4088         Wrapper wrapper = (Wrapper) findChild(name);
4089         if( wrapper != null ) {
4090             wrapper.removeMapping(pattern);
4091         }
4092         fireContainerEvent("removeServletMapping", pattern);
4093     }
4094
4095
4096     /**
4097      * Remove the specified watched resource name from the list associated
4098      * with this Context.
4099      *
4100      * @param name Name of the watched resource to be removed
4101      */

4102     @Override
4103     public void removeWatchedResource(String name) {
4104
4105         synchronized (watchedResourcesLock) {
4106
4107             // Make sure this watched resource is currently present
4108             int n = -1;
4109             for (int i = 0; i < watchedResources.length; i++) {
4110                 if (watchedResources[i].equals(name)) {
4111                     n = i;
4112                     break;
4113                 }
4114             }
4115             if (n < 0)
4116                 return;
4117
4118             // Remove the specified watched resource
4119             int j = 0;
4120             String results[] = new String[watchedResources.length - 1];
4121             for (int i = 0; i < watchedResources.length; i++) {
4122                 if (i != n)
4123                     results[j++] = watchedResources[i];
4124             }
4125             watchedResources = results;
4126
4127         }
4128
4129         fireContainerEvent("removeWatchedResource", name);
4130
4131     }
4132
4133
4134     /**
4135      * Remove the specified welcome file name from the list recognized
4136      * by this Context.
4137      *
4138      * @param name Name of the welcome file to be removed
4139      */

4140     @Override
4141     public void removeWelcomeFile(String name) {
4142
4143         synchronized (welcomeFilesLock) {
4144
4145             // Make sure this welcome file is currently present
4146             int n = -1;
4147             for (int i = 0; i < welcomeFiles.length; i++) {
4148                 if (welcomeFiles[i].equals(name)) {
4149                     n = i;
4150                     break;
4151                 }
4152             }
4153             if (n < 0)
4154                 return;
4155
4156             // Remove the specified welcome file
4157             int j = 0;
4158             String results[] = new String[welcomeFiles.length - 1];
4159             for (int i = 0; i < welcomeFiles.length; i++) {
4160                 if (i != n)
4161                     results[j++] = welcomeFiles[i];
4162             }
4163             welcomeFiles = results;
4164
4165         }
4166
4167         // Inform interested listeners
4168         if(this.getState().equals(LifecycleState.STARTED))
4169             fireContainerEvent(REMOVE_WELCOME_FILE_EVENT, name);
4170
4171     }
4172
4173
4174     /**
4175      * Remove a class name from the set of LifecycleListener classes that
4176      * will be added to newly created Wrappers.
4177      *
4178      * @param listener Class name of a LifecycleListener class to be removed
4179      */

4180     @Override
4181     public void removeWrapperLifecycle(String listener) {
4182
4183
4184         synchronized (wrapperLifecyclesLock) {
4185
4186             // Make sure this lifecycle listener is currently present
4187             int n = -1;
4188             for (int i = 0; i < wrapperLifecycles.length; i++) {
4189                 if (wrapperLifecycles[i].equals(listener)) {
4190                     n = i;
4191                     break;
4192                 }
4193             }
4194             if (n < 0)
4195                 return;
4196
4197             // Remove the specified lifecycle listener
4198             int j = 0;
4199             String results[] = new String[wrapperLifecycles.length - 1];
4200             for (int i = 0; i < wrapperLifecycles.length; i++) {
4201                 if (i != n)
4202                     results[j++] = wrapperLifecycles[i];
4203             }
4204             wrapperLifecycles = results;
4205
4206         }
4207
4208         // Inform interested listeners
4209         fireContainerEvent("removeWrapperLifecycle", listener);
4210
4211     }
4212
4213
4214     /**
4215      * Remove a class name from the set of ContainerListener classes that
4216      * will be added to newly created Wrappers.
4217      *
4218      * @param listener Class name of a ContainerListener class to be removed
4219      */

4220     @Override
4221     public void removeWrapperListener(String listener) {
4222
4223
4224         synchronized (wrapperListenersLock) {
4225
4226             // Make sure this listener is currently present
4227             int n = -1;
4228             for (int i = 0; i < wrapperListeners.length; i++) {
4229                 if (wrapperListeners[i].equals(listener)) {
4230                     n = i;
4231                     break;
4232                 }
4233             }
4234             if (n < 0)
4235                 return;
4236
4237             // Remove the specified listener
4238             int j = 0;
4239             String results[] = new String[wrapperListeners.length - 1];
4240             for (int i = 0; i < wrapperListeners.length; i++) {
4241                 if (i != n)
4242                     results[j++] = wrapperListeners[i];
4243             }
4244             wrapperListeners = results;
4245
4246         }
4247
4248         // Inform interested listeners
4249         fireContainerEvent("removeWrapperListener", listener);
4250
4251     }
4252
4253
4254     /**
4255      * Gets the cumulative processing times of all servlets in this
4256      * StandardContext.
4257      *
4258      * @return Cumulative processing times of all servlets in this
4259      * StandardContext
4260      */

4261     public long getProcessingTime() {
4262
4263         long result = 0;
4264
4265         Container[] children = findChildren();
4266         if (children != null) {
4267             forint i=0; i< children.length; i++ ) {
4268                 result += ((StandardWrapper)children[i]).getProcessingTime();
4269             }
4270         }
4271
4272         return result;
4273     }
4274
4275     /**
4276      * Gets the maximum processing time of all servlets in this
4277      * StandardContext.
4278      *
4279      * @return Maximum processing time of all servlets in this
4280      * StandardContext
4281      */

4282     public long getMaxTime() {
4283
4284         long result = 0;
4285         long time;
4286
4287         Container[] children = findChildren();
4288         if (children != null) {
4289             forint i=0; i< children.length; i++ ) {
4290                 time = ((StandardWrapper)children[i]).getMaxTime();
4291                 if (time > result)
4292                     result = time;
4293             }
4294         }
4295
4296         return result;
4297     }
4298
4299     /**
4300      * Gets the minimum processing time of all servlets in this
4301      * StandardContext.
4302      *
4303      * @return Minimum processing time of all servlets in this
4304      * StandardContext
4305      */

4306     public long getMinTime() {
4307
4308         long result = -1;
4309         long time;
4310
4311         Container[] children = findChildren();
4312         if (children != null) {
4313             forint i=0; i< children.length; i++ ) {
4314                 time = ((StandardWrapper)children[i]).getMinTime();
4315                 if (result < 0 || time < result)
4316                     result = time;
4317             }
4318         }
4319
4320         return result;
4321     }
4322
4323     /**
4324      * Gets the cumulative request count of all servlets in this
4325      * StandardContext.
4326      *
4327      * @return Cumulative request count of all servlets in this
4328      * StandardContext
4329      */

4330     public int getRequestCount() {
4331
4332         int result = 0;
4333
4334         Container[] children = findChildren();
4335         if (children != null) {
4336             forint i=0; i< children.length; i++ ) {
4337                 result += ((StandardWrapper)children[i]).getRequestCount();
4338             }
4339         }
4340
4341         return result;
4342     }
4343
4344     /**
4345      * Gets the cumulative error count of all servlets in this
4346      * StandardContext.
4347      *
4348      * @return Cumulative error count of all servlets in this
4349      * StandardContext
4350      */

4351     public int getErrorCount() {
4352
4353         int result = 0;
4354
4355         Container[] children = findChildren();
4356         if (children != null) {
4357             forint i=0; i< children.length; i++ ) {
4358                 result += ((StandardWrapper)children[i]).getErrorCount();
4359             }
4360         }
4361
4362         return result;
4363     }
4364
4365
4366     /**
4367      * Return the real path for a given virtual path, if possible; otherwise
4368      * return <code>null</code>.
4369      *
4370      * @param path The path to the desired resource
4371      */

4372     @Override
4373     public String getRealPath(String path) {
4374         // The WebResources API expects all paths to start with /. This is a
4375         // special case for consistency with earlier Tomcat versions.
4376         if ("".equals(path)) {
4377             path = "/";
4378         }
4379         if (resources != null) {
4380             try {
4381                 WebResource resource = resources.getResource(path);
4382                 String canonicalPath = resource.getCanonicalPath();
4383                 if (canonicalPath == null) {
4384                     return null;
4385                 } else if ((resource.isDirectory() && !canonicalPath.endsWith(File.separator) ||
4386                         !resource.exists()) && path.endsWith("/")) {
4387                     return canonicalPath + File.separatorChar;
4388                 } else {
4389                     return canonicalPath;
4390                 }
4391             } catch (IllegalArgumentException iae) {
4392                 // ServletContext.getRealPath() does not allow this to be thrown
4393             }
4394         }
4395         return null;
4396     }
4397
4398
4399     /**
4400      * Hook to track which Servlets were created via
4401      * {@link ServletContext#createServlet(Class)}.
4402      *
4403      * @param servlet the created Servlet
4404      */

4405     public void dynamicServletCreated(Servlet servlet) {
4406         createdServlets.add(servlet);
4407     }
4408
4409
4410     public boolean wasCreatedDynamicServlet(Servlet servlet) {
4411         return createdServlets.contains(servlet);
4412     }
4413
4414
4415     /**
4416      * A helper class to manage the filter mappings in a Context.
4417      */

4418     private static final class ContextFilterMaps {
4419         private final Object lock = new Object();
4420
4421         /**
4422          * The set of filter mappings for this application, in the order they
4423          * were defined in the deployment descriptor with additional mappings
4424          * added via the {@link ServletContext} possibly both before and after
4425          * those defined in the deployment descriptor.
4426          */

4427         private FilterMap[] array = new FilterMap[0];
4428
4429         /**
4430          * Filter mappings added via {@link ServletContext} may have to be
4431          * inserted before the mappings in the deployment descriptor but must be
4432          * inserted in the order the {@link ServletContext} methods are called.
4433          * This isn't an issue for the mappings added after the deployment
4434          * descriptor - they are just added to the end - but correctly the
4435          * adding mappings before the deployment descriptor mappings requires
4436          * knowing where the last 'before' mapping was added.
4437          */

4438         private int insertPoint = 0;
4439
4440         /**
4441          * @return The set of filter mappings
4442          */

4443         public FilterMap[] asArray() {
4444             synchronized (lock) {
4445                 return array;
4446             }
4447         }
4448
4449         /**
4450          * Add a filter mapping at the end of the current set of filter
4451          * mappings.
4452          *
4453          * @param filterMap
4454          *            The filter mapping to be added
4455          */

4456         public void add(FilterMap filterMap) {
4457             synchronized (lock) {
4458                 FilterMap results[] = Arrays.copyOf(array, array.length + 1);
4459                 results[array.length] = filterMap;
4460                 array = results;
4461             }
4462         }
4463
4464         /**
4465          * Add a filter mapping before the mappings defined in the deployment
4466          * descriptor but after any other mappings added via this method.
4467          *
4468          * @param filterMap
4469          *            The filter mapping to be added
4470          */

4471         public void addBefore(FilterMap filterMap) {
4472             synchronized (lock) {
4473                 FilterMap results[] = new FilterMap[array.length + 1];
4474                 System.arraycopy(array, 0, results, 0, insertPoint);
4475                 System.arraycopy(array, insertPoint, results, insertPoint + 1,
4476                         array.length - insertPoint);
4477                 results[insertPoint] = filterMap;
4478                 array = results;
4479                 insertPoint++;
4480             }
4481         }
4482
4483         /**
4484          * Remove a filter mapping.
4485          *
4486          * @param filterMap The filter mapping to be removed
4487          */

4488         public void remove(FilterMap filterMap) {
4489             synchronized (lock) {
4490                 // Make sure this filter mapping is currently present
4491                 int n = -1;
4492                 for (int i = 0; i < array.length; i++) {
4493                     if (array[i] == filterMap) {
4494                         n = i;
4495                         break;
4496                     }
4497                 }
4498                 if (n < 0)
4499                     return;
4500
4501                 // Remove the specified filter mapping
4502                 FilterMap results[] = new FilterMap[array.length - 1];
4503                 System.arraycopy(array, 0, results, 0, n);
4504                 System.arraycopy(array, n + 1, results, n, (array.length - 1)
4505                         - n);
4506                 array = results;
4507                 if (n < insertPoint) {
4508                     insertPoint--;
4509                 }
4510             }
4511         }
4512     }
4513
4514     // --------------------------------------------------------- Public Methods
4515
4516
4517     /**
4518      * Configure and initialize the set of filters for this Context.
4519      * @return <code>true</code> if all filter initialization completed
4520      * successfully, or <code>false</code> otherwise.
4521      */

4522     public boolean filterStart() {
4523
4524         if (getLogger().isDebugEnabled()) {
4525             getLogger().debug("Starting filters");
4526         }
4527         // Instantiate and record a FilterConfig for each defined filter
4528         boolean ok = true;
4529         synchronized (filterConfigs) {
4530             filterConfigs.clear();
4531             for (Entry<String,FilterDef> entry : filterDefs.entrySet()) {
4532                 String name = entry.getKey();
4533                 if (getLogger().isDebugEnabled()) {
4534                     getLogger().debug(" Starting filter '" + name + "'");
4535                 }
4536                 try {
4537                     ApplicationFilterConfig filterConfig =
4538                             new ApplicationFilterConfig(this, entry.getValue());
4539                     filterConfigs.put(name, filterConfig);
4540                 } catch (Throwable t) {
4541                     t = ExceptionUtils.unwrapInvocationTargetException(t);
4542                     ExceptionUtils.handleThrowable(t);
4543                     getLogger().error(sm.getString(
4544                             "standardContext.filterStart", name), t);
4545                     ok = false;
4546                 }
4547             }
4548         }
4549
4550         return ok;
4551     }
4552
4553
4554     /**
4555      * Finalize and release the set of filters for this Context.
4556      * @return <code>true</code> if all filter finalization completed
4557      * successfully, or <code>false</code> otherwise.
4558      */

4559     public boolean filterStop() {
4560
4561         if (getLogger().isDebugEnabled())
4562             getLogger().debug("Stopping filters");
4563
4564         // Release all Filter and FilterConfig instances
4565         synchronized (filterConfigs) {
4566             for (Entry<String, ApplicationFilterConfig> entry : filterConfigs.entrySet()) {
4567                 if (getLogger().isDebugEnabled())
4568                     getLogger().debug(" Stopping filter '" + entry.getKey() + "'");
4569                 ApplicationFilterConfig filterConfig = entry.getValue();
4570                 filterConfig.release();
4571             }
4572             filterConfigs.clear();
4573         }
4574         return true;
4575
4576     }
4577
4578
4579     /**
4580      * Find and return the initialized <code>FilterConfig</code> for the
4581      * specified filter name, if any; otherwise return <code>null</code>.
4582      *
4583      * @param name Name of the desired filter
4584      * @return the filter config object
4585      */

4586     public FilterConfig findFilterConfig(String name) {
4587         return filterConfigs.get(name);
4588     }
4589
4590
4591     /**
4592      * Configure the set of instantiated application event listeners
4593      * for this Context.
4594      * @return <code>true</code> if all listeners wre
4595      * initialized successfully, or <code>false</code> otherwise.
4596      */

4597     public boolean listenerStart() {
4598
4599         if (log.isDebugEnabled())
4600             log.debug("Configuring application event listeners");
4601
4602         // Instantiate the required listeners
4603         String listeners[] = findApplicationListeners();
4604         Object results[] = new Object[listeners.length];
4605         boolean ok = true;
4606         for (int i = 0; i < results.length; i++) {
4607             if (getLogger().isDebugEnabled())
4608                 getLogger().debug(" Configuring event listener class '" +
4609                     listeners[i] + "'");
4610             try {
4611                 String listener = listeners[i];
4612                 results[i] = getInstanceManager().newInstance(listener);
4613             } catch (Throwable t) {
4614                 t = ExceptionUtils.unwrapInvocationTargetException(t);
4615                 ExceptionUtils.handleThrowable(t);
4616                 getLogger().error(sm.getString(
4617                         "standardContext.applicationListener", listeners[i]), t);
4618                 ok = false;
4619             }
4620         }
4621         if (!ok) {
4622             getLogger().error(sm.getString("standardContext.applicationSkipped"));
4623             return false;
4624         }
4625
4626         // Sort listeners in two arrays
4627         List<Object> eventListeners = new ArrayList<>();
4628         List<Object> lifecycleListeners = new ArrayList<>();
4629         for (int i = 0; i < results.length; i++) {
4630             if ((results[i] instanceof ServletContextAttributeListener)
4631                 || (results[i] instanceof ServletRequestAttributeListener)
4632                 || (results[i] instanceof ServletRequestListener)
4633                 || (results[i] instanceof HttpSessionIdListener)
4634                 || (results[i] instanceof HttpSessionAttributeListener)) {
4635                 eventListeners.add(results[i]);
4636             }
4637             if ((results[i] instanceof ServletContextListener)
4638                 || (results[i] instanceof HttpSessionListener)) {
4639                 lifecycleListeners.add(results[i]);
4640             }
4641         }
4642
4643         // Listener instances may have been added directly to this Context by
4644         // ServletContextInitializers and other code via the pluggability APIs.
4645         // Put them these listeners after the ones defined in web.xml and/or
4646         // annotations then overwrite the list of instances with the new, full
4647         // list.
4648         for (Object eventListener: getApplicationEventListeners()) {
4649             eventListeners.add(eventListener);
4650         }
4651         setApplicationEventListeners(eventListeners.toArray());
4652         for (Object lifecycleListener: getApplicationLifecycleListeners()) {
4653             lifecycleListeners.add(lifecycleListener);
4654             if (lifecycleListener instanceof ServletContextListener) {
4655                 noPluggabilityListeners.add(lifecycleListener);
4656             }
4657         }
4658         setApplicationLifecycleListeners(lifecycleListeners.toArray());
4659
4660         // Send application start events
4661
4662         if (getLogger().isDebugEnabled())
4663             getLogger().debug("Sending application start events");
4664
4665         // Ensure context is not null
4666         getServletContext();
4667         context.setNewServletContextListenerAllowed(false);
4668
4669         Object instances[] = getApplicationLifecycleListeners();
4670         if (instances == null || instances.length == 0) {
4671             return ok;
4672         }
4673
4674         ServletContextEvent event = new ServletContextEvent(getServletContext());
4675         ServletContextEvent tldEvent = null;
4676         if (noPluggabilityListeners.size() > 0) {
4677             noPluggabilityServletContext = new NoPluggabilityServletContext(getServletContext());
4678             tldEvent = new ServletContextEvent(noPluggabilityServletContext);
4679         }
4680         for (int i = 0; i < instances.length; i++) {
4681             if (!(instances[i] instanceof ServletContextListener))
4682                 continue;
4683             ServletContextListener listener =
4684                 (ServletContextListener) instances[i];
4685             try {
4686                 fireContainerEvent("beforeContextInitialized", listener);
4687                 if (noPluggabilityListeners.contains(listener)) {
4688                     listener.contextInitialized(tldEvent);
4689                 } else {
4690                     listener.contextInitialized(event);
4691                 }
4692                 fireContainerEvent("afterContextInitialized", listener);
4693             } catch (Throwable t) {
4694                 ExceptionUtils.handleThrowable(t);
4695                 fireContainerEvent("afterContextInitialized", listener);
4696                 getLogger().error
4697                     (sm.getString("standardContext.listenerStart",
4698                                   instances[i].getClass().getName()), t);
4699                 ok = false;
4700             }
4701         }
4702         return ok;
4703
4704     }
4705
4706
4707     /**
4708      * Send an application stop event to all interested listeners.
4709      * @return <code>true</code> if all events were sent successfully,
4710      * or <code>false</code> otherwise.
4711      */

4712     public boolean listenerStop() {
4713
4714         if (log.isDebugEnabled())
4715             log.debug("Sending application stop events");
4716
4717         boolean ok = true;
4718         Object listeners[] = getApplicationLifecycleListeners();
4719         if (listeners != null && listeners.length > 0) {
4720             ServletContextEvent event = new ServletContextEvent(getServletContext());
4721             ServletContextEvent tldEvent = null;
4722             if (noPluggabilityServletContext != null) {
4723                 tldEvent = new ServletContextEvent(noPluggabilityServletContext);
4724             }
4725             for (int i = 0; i < listeners.length; i++) {
4726                 int j = (listeners.length - 1) - i;
4727                 if (listeners[j] == null)
4728                     continue;
4729                 if (listeners[j] instanceof ServletContextListener) {
4730                     ServletContextListener listener =
4731                         (ServletContextListener) listeners[j];
4732                     try {
4733                         fireContainerEvent("beforeContextDestroyed", listener);
4734                         if (noPluggabilityListeners.contains(listener)) {
4735                             listener.contextDestroyed(tldEvent);
4736                         } else {
4737                             listener.contextDestroyed(event);
4738                         }
4739                         fireContainerEvent("afterContextDestroyed", listener);
4740                     } catch (Throwable t) {
4741                         ExceptionUtils.handleThrowable(t);
4742                         fireContainerEvent("afterContextDestroyed", listener);
4743                         getLogger().error
4744                             (sm.getString("standardContext.listenerStop",
4745                                 listeners[j].getClass().getName()), t);
4746                         ok = false;
4747                     }
4748                 }
4749                 try {
4750                     if (getInstanceManager() != null) {
4751                         getInstanceManager().destroyInstance(listeners[j]);
4752                     }
4753                 } catch (Throwable t) {
4754                     t = ExceptionUtils.unwrapInvocationTargetException(t);
4755                     ExceptionUtils.handleThrowable(t);
4756                     getLogger().error
4757                        (sm.getString("standardContext.listenerStop",
4758                             listeners[j].getClass().getName()), t);
4759                     ok = false;
4760                 }
4761             }
4762         }
4763
4764         // Annotation processing
4765         listeners = getApplicationEventListeners();
4766         if (listeners != null) {
4767             for (int i = 0; i < listeners.length; i++) {
4768                 int j = (listeners.length - 1) - i;
4769                 if (listeners[j] == null)
4770                     continue;
4771                 try {
4772                     if (getInstanceManager() != null) {
4773                         getInstanceManager().destroyInstance(listeners[j]);
4774                     }
4775                 } catch (Throwable t) {
4776                     t = ExceptionUtils.unwrapInvocationTargetException(t);
4777                     ExceptionUtils.handleThrowable(t);
4778                     getLogger().error
4779                         (sm.getString("standardContext.listenerStop",
4780                             listeners[j].getClass().getName()), t);
4781                     ok = false;
4782                 }
4783             }
4784         }
4785
4786         setApplicationEventListeners(null);
4787         setApplicationLifecycleListeners(null);
4788
4789         noPluggabilityServletContext = null;
4790         noPluggabilityListeners.clear();
4791
4792         return ok;
4793     }
4794
4795
4796     /**
4797      * Allocate resources, including proxy.
4798      * @throws LifecycleException if a start error occurs
4799      */

4800     public void resourcesStart() throws LifecycleException {
4801
4802         // Check current status in case resources were added that had already
4803         // been started
4804         if (!resources.getState().isAvailable()) {
4805             resources.start();
4806         }
4807
4808         if (effectiveMajorVersion >=3 && addWebinfClassesResources) {
4809             WebResource webinfClassesResource = resources.getResource(
4810                     "/WEB-INF/classes/META-INF/resources");
4811             if (webinfClassesResource.isDirectory()) {
4812                 getResources().createWebResourceSet(
4813                         WebResourceRoot.ResourceSetType.RESOURCE_JAR, "/",
4814                         webinfClassesResource.getURL(), "/");
4815             }
4816         }
4817     }
4818
4819
4820     /**
4821      * Deallocate resources and destroy proxy.
4822      * @return <code>true</code> if no error occurred
4823      */

4824     public boolean resourcesStop() {
4825
4826         boolean ok = true;
4827
4828         Lock writeLock = resourcesLock.writeLock();
4829         writeLock.lock();
4830         try {
4831             if (resources != null) {
4832                 resources.stop();
4833             }
4834         } catch (Throwable t) {
4835             ExceptionUtils.handleThrowable(t);
4836             log.error(sm.getString("standardContext.resourcesStop"), t);
4837             ok = false;
4838         } finally {
4839             writeLock.unlock();
4840         }
4841
4842         return ok;
4843     }
4844
4845
4846     /**
4847      * Load and initialize all servlets marked "load on startup" in the
4848      * web application deployment descriptor.
4849      *
4850      * @param children Array of wrappers for all currently defined
4851      *  servlets (including those not declared load on startup)
4852      * @return <code>true</code> if load on startup was considered successful
4853      */

4854     public boolean loadOnStartup(Container children[]) {
4855
4856         // Collect "load on startup" servlets that need to be initialized
4857         TreeMap<Integer, ArrayList<Wrapper>> map = new TreeMap<>();
4858         for (int i = 0; i < children.length; i++) {
4859             Wrapper wrapper = (Wrapper) children[i];
4860             int loadOnStartup = wrapper.getLoadOnStartup();
4861             if (loadOnStartup < 0)
4862                 continue;
4863             Integer key = Integer.valueOf(loadOnStartup);
4864             ArrayList<Wrapper> list = map.get(key);
4865             if (list == null) {
4866                 list = new ArrayList<>();
4867                 map.put(key, list);
4868             }
4869             list.add(wrapper);
4870         }
4871
4872         // Load the collected "load on startup" servlets
4873         for (ArrayList<Wrapper> list : map.values()) {
4874             for (Wrapper wrapper : list) {
4875                 try {
4876                     wrapper.load();
4877                 } catch (ServletException e) {
4878                     getLogger().error(sm.getString("standardContext.loadOnStartup.loadException",
4879                           getName(), wrapper.getName()), StandardWrapper.getRootCause(e));
4880                     // NOTE: load errors (including a servlet that throws
4881                     // UnavailableException from the init() method) are NOT
4882                     // fatal to application startup
4883                     // unless failCtxIfServletStartFails="true" is specified
4884                     if(getComputedFailCtxIfServletStartFails()) {
4885                         return false;
4886                     }
4887                 }
4888             }
4889         }
4890         return true;
4891
4892     }
4893
4894
4895     /**
4896      * Start this component and implement the requirements
4897      * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
4898      *
4899      * @exception LifecycleException if this component detects a fatal error
4900      *  that prevents this component from being used
4901      */

4902     @Override
4903     protected synchronized void startInternal() throws LifecycleException {
4904
4905         if(log.isDebugEnabled())
4906             log.debug("Starting " + getBaseName());
4907
4908         // Send j2ee.state.starting notification
4909         if (this.getObjectName() != null) {
4910             Notification notification = new Notification("j2ee.state.starting",
4911                     this.getObjectName(), sequenceNumber.getAndIncrement());
4912             broadcaster.sendNotification(notification);
4913         }
4914
4915         setConfigured(false);
4916         boolean ok = true;
4917
4918         // Currently this is effectively a NO-OP but needs to be called to
4919         // ensure the NamingResources follows the correct lifecycle
4920         if (namingResources != null) {
4921             namingResources.start();
4922         }
4923
4924         // Post work directory
4925         postWorkDirectory();
4926
4927         // Add missing components as necessary
4928         if (getResources() == null) {   // (1) Required by Loader
4929             if (log.isDebugEnabled())
4930                 log.debug("Configuring default Resources");
4931
4932             try {
4933                 setResources(new StandardRoot(this));
4934             } catch (IllegalArgumentException e) {
4935                 log.error(sm.getString("standardContext.resourcesInit"), e);
4936                 ok = false;
4937             }
4938         }
4939         if (ok) {
4940             resourcesStart();
4941         }
4942
4943         if (getLoader() == null) {
4944             WebappLoader webappLoader = new WebappLoader();
4945             webappLoader.setDelegate(getDelegate());
4946             setLoader(webappLoader);
4947         }
4948
4949         // An explicit cookie processor hasn't been specified; use the default
4950         if (cookieProcessor == null) {
4951             cookieProcessor = new Rfc6265CookieProcessor();
4952         }
4953
4954         // Initialize character set mapper
4955         getCharsetMapper();
4956
4957         // Validate required extensions
4958         boolean dependencyCheck = true;
4959         try {
4960             dependencyCheck = ExtensionValidator.validateApplication
4961                 (getResources(), this);
4962         } catch (IOException ioe) {
4963             log.error(sm.getString("standardContext.extensionValidationError"), ioe);
4964             dependencyCheck = false;
4965         }
4966
4967         if (!dependencyCheck) {
4968             // do not make application available if dependency check fails
4969             ok = false;
4970         }
4971
4972         // Reading the "catalina.useNaming" environment variable
4973         String useNamingProperty = System.getProperty("catalina.useNaming");
4974         if ((useNamingProperty != null)
4975             && (useNamingProperty.equals("false"))) {
4976             useNaming = false;
4977         }
4978
4979         if (ok && isUseNaming()) {
4980             if (getNamingContextListener() == null) {
4981                 NamingContextListener ncl = new NamingContextListener();
4982                 ncl.setName(getNamingContextName());
4983                 ncl.setExceptionOnFailedWrite(getJndiExceptionOnFailedWrite());
4984                 addLifecycleListener(ncl);
4985                 setNamingContextListener(ncl);
4986             }
4987         }
4988
4989         // Standard container startup
4990         if (log.isDebugEnabled())
4991             log.debug("Processing standard container startup");
4992
4993
4994         // Binding thread
4995         ClassLoader oldCCL = bindThread();
4996
4997         try {
4998             if (ok) {
4999                 // Start our subordinate components, if any
5000                 Loader loader = getLoader();
5001                 if (loader instanceof Lifecycle) {
5002                     ((Lifecycle) loader).start();
5003                 }
5004
5005                 // since the loader just started, the webapp classloader is now
5006                 // created.
5007                 setClassLoaderProperty("clearReferencesRmiTargets",
5008                         getClearReferencesRmiTargets());
5009                 setClassLoaderProperty("clearReferencesStopThreads",
5010                         getClearReferencesStopThreads());
5011                 setClassLoaderProperty("clearReferencesStopTimerThreads",
5012                         getClearReferencesStopTimerThreads());
5013                 setClassLoaderProperty("clearReferencesHttpClientKeepAliveThread",
5014                         getClearReferencesHttpClientKeepAliveThread());
5015                 setClassLoaderProperty("clearReferencesObjectStreamClassCaches",
5016                         getClearReferencesObjectStreamClassCaches());
5017                 setClassLoaderProperty("clearReferencesObjectStreamClassCaches",
5018                         getClearReferencesObjectStreamClassCaches());
5019                 setClassLoaderProperty("clearReferencesThreadLocals",
5020                         getClearReferencesThreadLocals());
5021
5022                 // By calling unbindThread and bindThread in a row, we setup the
5023                 // current Thread CCL to be the webapp classloader
5024                 unbindThread(oldCCL);
5025                 oldCCL = bindThread();
5026
5027                 // Initialize logger again. Other components might have used it
5028                 // too early, so it should be reset.
5029                 logger = null;
5030                 getLogger();
5031
5032                 Realm realm = getRealmInternal();
5033                 if(null != realm) {
5034                     if (realm instanceof Lifecycle) {
5035                         ((Lifecycle) realm).start();
5036                     }
5037
5038                     // Place the CredentialHandler into the ServletContext so
5039                     // applications can have access to it. Wrap it in a "safe"
5040                     // handler so application's can't modify it.
5041                     CredentialHandler safeHandler = new CredentialHandler() {
5042                         @Override
5043                         public boolean matches(String inputCredentials, String storedCredentials) {
5044                             return getRealmInternal().getCredentialHandler().matches(inputCredentials, storedCredentials);
5045                         }
5046
5047                         @Override
5048                         public String mutate(String inputCredentials) {
5049                             return getRealmInternal().getCredentialHandler().mutate(inputCredentials);
5050                         }
5051                     };
5052                     context.setAttribute(Globals.CREDENTIAL_HANDLER, safeHandler);
5053                 }
5054
5055                 // Notify our interested LifecycleListeners
5056                 fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null);
5057
5058                 // Start our child containers, if not already started
5059                 for (Container child : findChildren()) {
5060                     if (!child.getState().isAvailable()) {
5061                         child.start();
5062                     }
5063                 }
5064
5065                 // Start the Valves in our pipeline (including the basic),
5066                 // if any
5067                 if (pipeline instanceof Lifecycle) {
5068                     ((Lifecycle) pipeline).start();
5069                 }
5070
5071                 // Acquire clustered manager
5072                 Manager contextManager = null;
5073                 Manager manager = getManager();
5074                 if (manager == null) {
5075                     if (log.isDebugEnabled()) {
5076                         log.debug(sm.getString("standardContext.cluster.noManager",
5077                                 Boolean.valueOf((getCluster() != null)),
5078                                 Boolean.valueOf(distributable)));
5079                     }
5080                     if ((getCluster() != null) && distributable) {
5081                         try {
5082                             contextManager = getCluster().createManager(getName());
5083                         } catch (Exception ex) {
5084                             log.error(sm.getString("standardContext.cluster.managerError"), ex);
5085                             ok = false;
5086                         }
5087                     } else {
5088                         contextManager = new StandardManager();
5089                     }
5090                 }
5091
5092                 // Configure default manager if none was specified
5093                 if (contextManager != null) {
5094                     if (log.isDebugEnabled()) {
5095                         log.debug(sm.getString("standardContext.manager",
5096                                 contextManager.getClass().getName()));
5097                     }
5098                     setManager(contextManager);
5099                 }
5100
5101                 if (manager!=null && (getCluster() != null) && distributable) {
5102                     //let the cluster know that there is a context that is distributable
5103                     //and that it has its own manager
5104                     getCluster().registerManager(manager);
5105                 }
5106             }
5107
5108             if (!getConfigured()) {
5109                 log.error(sm.getString("standardContext.configurationFail"));
5110                 ok = false;
5111             }
5112
5113             // We put the resources into the servlet context
5114             if (ok) {
5115                 getServletContext().setAttribute
5116                     (Globals.RESOURCES_ATTR, getResources());
5117
5118                 if (getInstanceManager() == null) {
5119                     setInstanceManager(createInstanceManager());
5120                 }
5121                 getServletContext().setAttribute(
5122                         InstanceManager.class.getName(), getInstanceManager());
5123                 InstanceManagerBindings.bind(getLoader().getClassLoader(), getInstanceManager());
5124
5125                 // Create context attributes that will be required
5126                 getServletContext().setAttribute(
5127                         JarScanner.class.getName(), getJarScanner());
5128
5129                 // Make the version info available
5130                 getServletContext().setAttribute(Globals.WEBAPP_VERSION, getWebappVersion());
5131             }
5132
5133             // Set up the context init params
5134             mergeParameters();
5135
5136             // Call ServletContainerInitializers
5137             for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry :
5138                 initializers.entrySet()) {
5139                 try {
5140                     entry.getKey().onStartup(entry.getValue(),
5141                             getServletContext());
5142                 } catch (ServletException e) {
5143                     log.error(sm.getString("standardContext.sciFail"), e);
5144                     ok = false;
5145                     break;
5146                 }
5147             }
5148
5149             // Configure and call application event listeners
5150             if (ok) {
5151                 if (!listenerStart()) {
5152                     log.error(sm.getString("standardContext.listenerFail"));
5153                     ok = false;
5154                 }
5155             }
5156
5157             // Check constraints for uncovered HTTP methods
5158             // Needs to be after SCIs and listeners as they may programmatically
5159             // change constraints
5160             if (ok) {
5161                 checkConstraintsForUncoveredMethods(findConstraints());
5162             }
5163
5164             try {
5165                 // Start manager
5166                 Manager manager = getManager();
5167                 if (manager instanceof Lifecycle) {
5168                     ((Lifecycle) manager).start();
5169                 }
5170             } catch(Exception e) {
5171                 log.error(sm.getString("standardContext.managerFail"), e);
5172                 ok = false;
5173             }
5174
5175             // Configure and call application filters
5176             if (ok) {
5177                 if (!filterStart()) {
5178                     log.error(sm.getString("standardContext.filterFail"));
5179                     ok = false;
5180                 }
5181             }
5182
5183             // Load and initialize all "load on startup" servlets
5184             if (ok) {
5185                 if (!loadOnStartup(findChildren())){
5186                     log.error(sm.getString("standardContext.servletFail"));
5187                     ok = false;
5188                 }
5189             }
5190
5191             // Start ContainerBackgroundProcessor thread
5192             super.threadStart();
5193         } finally {
5194             // Unbinding thread
5195             unbindThread(oldCCL);
5196         }
5197
5198         // Set available status depending upon startup success
5199         if (ok) {
5200             if (log.isDebugEnabled())
5201                 log.debug("Starting completed");
5202         } else {
5203             log.error(sm.getString("standardContext.startFailed", getName()));
5204         }
5205
5206         startTime=System.currentTimeMillis();
5207
5208         // Send j2ee.state.running notification
5209         if (ok && (this.getObjectName() != null)) {
5210             Notification notification =
5211                 new Notification("j2ee.state.running"this.getObjectName(),
5212                                  sequenceNumber.getAndIncrement());
5213             broadcaster.sendNotification(notification);
5214         }
5215
5216         // The WebResources implementation caches references to JAR files. On
5217         // some platforms these references may lock the JAR files. Since web
5218         // application start is likely to have read from lots of JARs, trigger
5219         // a clean-up now.
5220         getResources().gc();
5221
5222         // Reinitializing if something went wrong
5223         if (!ok) {
5224             setState(LifecycleState.FAILED);
5225         } else {
5226             setState(LifecycleState.STARTING);
5227         }
5228     }
5229
5230
5231     private void checkConstraintsForUncoveredMethods(
5232             SecurityConstraint[] constraints) {
5233         SecurityConstraint[] newConstraints =
5234                 SecurityConstraint.findUncoveredHttpMethods(constraints,
5235                         getDenyUncoveredHttpMethods(), getLogger());
5236         for (SecurityConstraint constraint : newConstraints) {
5237             addConstraint(constraint);
5238         }
5239     }
5240
5241
5242     private void setClassLoaderProperty(String name, boolean value) {
5243         ClassLoader cl = getLoader().getClassLoader();
5244         if (!IntrospectionUtils.setProperty(cl, name, Boolean.toString(value))) {
5245             // Failed to set
5246             log.info(sm.getString(
5247                     "standardContext.webappClassLoader.missingProperty",
5248                     name, Boolean.toString(value)));
5249         }
5250     }
5251
5252     @Override
5253     public InstanceManager createInstanceManager() {
5254         javax.naming.Context context = null;
5255         if (isUseNaming() && getNamingContextListener() != null) {
5256             context = getNamingContextListener().getEnvContext();
5257         }
5258         Map<String, Map<String, String>> injectionMap = buildInjectionMap(
5259                 getIgnoreAnnotations() ? new NamingResourcesImpl(): getNamingResources());
5260        return new DefaultInstanceManager(context, injectionMap,
5261                thisthis.getClass().getClassLoader());
5262     }
5263
5264     private Map<String, Map<String, String>> buildInjectionMap(NamingResourcesImpl namingResources) {
5265         Map<String, Map<String, String>> injectionMap = new HashMap<>();
5266         for (Injectable resource: namingResources.findLocalEjbs()) {
5267             addInjectionTarget(resource, injectionMap);
5268         }
5269         for (Injectable resource: namingResources.findEjbs()) {
5270             addInjectionTarget(resource, injectionMap);
5271         }
5272         for (Injectable resource: namingResources.findEnvironments()) {
5273             addInjectionTarget(resource, injectionMap);
5274         }
5275         for (Injectable resource: namingResources.findMessageDestinationRefs()) {
5276             addInjectionTarget(resource, injectionMap);
5277         }
5278         for (Injectable resource: namingResources.findResourceEnvRefs()) {
5279             addInjectionTarget(resource, injectionMap);
5280         }
5281         for (Injectable resource: namingResources.findResources()) {
5282             addInjectionTarget(resource, injectionMap);
5283         }
5284         for (Injectable resource: namingResources.findServices()) {
5285             addInjectionTarget(resource, injectionMap);
5286         }
5287         return injectionMap;
5288     }
5289
5290     private void addInjectionTarget(Injectable resource, Map<String, Map<String, String>> injectionMap) {
5291         List<InjectionTarget> injectionTargets = resource.getInjectionTargets();
5292         if (injectionTargets != null && injectionTargets.size() > 0) {
5293             String jndiName = resource.getName();
5294             for (InjectionTarget injectionTarget: injectionTargets) {
5295                 String clazz = injectionTarget.getTargetClass();
5296                 Map<String, String> injections = injectionMap.get(clazz);
5297                 if (injections == null) {
5298                     injections = new HashMap<>();
5299                     injectionMap.put(clazz, injections);
5300                 }
5301                 injections.put(injectionTarget.getTargetName(), jndiName);
5302             }
5303         }
5304     }
5305
5306
5307
5308     /**
5309      * Merge the context initialization parameters specified in the application
5310      * deployment descriptor with the application parameters described in the
5311      * server configuration, respecting the <code>override</code> property of
5312      * the application parameters appropriately.
5313      */

5314     private void mergeParameters() {
5315         Map<String,String> mergedParams = new HashMap<>();
5316
5317         String names[] = findParameters();
5318         for (int i = 0; i < names.length; i++) {
5319             mergedParams.put(names[i], findParameter(names[i]));
5320         }
5321
5322         ApplicationParameter params[] = findApplicationParameters();
5323         for (int i = 0; i < params.length; i++) {
5324             if (params[i].getOverride()) {
5325                 if (mergedParams.get(params[i].getName()) == null) {
5326                     mergedParams.put(params[i].getName(),
5327                             params[i].getValue());
5328                 }
5329             } else {
5330                 mergedParams.put(params[i].getName(), params[i].getValue());
5331             }
5332         }
5333
5334         ServletContext sc = getServletContext();
5335         for (Map.Entry<String,String> entry : mergedParams.entrySet()) {
5336             sc.setInitParameter(entry.getKey(), entry.getValue());
5337         }
5338
5339     }
5340
5341
5342     /**
5343      * Stop this component and implement the requirements
5344      * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}.
5345      *
5346      * @exception LifecycleException if this component detects a fatal error
5347      *  that prevents this component from being used
5348      */

5349     @Override
5350     protected synchronized void stopInternal() throws LifecycleException {
5351
5352         // Send j2ee.state.stopping notification
5353         if (this.getObjectName() != null) {
5354             Notification notification =
5355                 new Notification("j2ee.state.stopping"this.getObjectName(),
5356                                  sequenceNumber.getAndIncrement());
5357             broadcaster.sendNotification(notification);
5358         }
5359
5360         // Context has been removed from Mapper at this point (so no new
5361         // requests will be mapped) but is still available.
5362
5363         // Give the in progress async requests a chance to complete
5364         long limit = System.currentTimeMillis() + unloadDelay;
5365         while (inProgressAsyncCount.get() > 0 && System.currentTimeMillis() < limit) {
5366             try {
5367                 Thread.sleep(50);
5368             } catch (InterruptedException e) {
5369                 log.info(sm.getString("standardContext.stop.asyncWaitInterrupted"), e);
5370                 break;
5371             }
5372         }
5373
5374         // Once the state is set to STOPPING, the Context will report itself as
5375         // not available and any in progress async requests will timeout
5376         setState(LifecycleState.STOPPING);
5377
5378         // Binding thread
5379         ClassLoader oldCCL = bindThread();
5380
5381         try {
5382             // Stop our child containers, if any
5383             final Container[] children = findChildren();
5384
5385             // Stop ContainerBackgroundProcessor thread
5386             threadStop();
5387
5388             for (int i = 0; i < children.length; i++) {
5389                 children[i].stop();
5390             }
5391
5392             // Stop our filters
5393             filterStop();
5394
5395             Manager manager = getManager();
5396             if (manager instanceof Lifecycle && ((Lifecycle) manager).getState().isAvailable()) {
5397                 ((Lifecycle) manager).stop();
5398             }
5399
5400             // Stop our application listeners
5401             listenerStop();
5402
5403             // Finalize our character set mapper
5404             setCharsetMapper(null);
5405
5406             // Normal container shutdown processing
5407             if (log.isDebugEnabled())
5408                 log.debug("Processing standard container shutdown");
5409
5410             // JNDI resources are unbound in CONFIGURE_STOP_EVENT so stop
5411             // naming resources before they are unbound since NamingResources
5412             // does a JNDI lookup to retrieve the resource. This needs to be
5413             // after the application has finished with the resource
5414             if (namingResources != null) {
5415                 namingResources.stop();
5416             }
5417
5418             fireLifecycleEvent(Lifecycle.CONFIGURE_STOP_EVENT, null);
5419
5420             // Stop the Valves in our pipeline (including the basic), if any
5421             if (pipeline instanceof Lifecycle &&
5422                     ((Lifecycle) pipeline).getState().isAvailable()) {
5423                 ((Lifecycle) pipeline).stop();
5424             }
5425
5426             // Clear all application-originated servlet context attributes
5427             if (context != null)
5428                 context.clearAttributes();
5429
5430             Realm realm = getRealmInternal();
5431             if (realm instanceof Lifecycle) {
5432                 ((Lifecycle) realm).stop();
5433             }
5434             Loader loader = getLoader();
5435             if (loader instanceof Lifecycle) {
5436                 ClassLoader classLoader = loader.getClassLoader();
5437                 ((Lifecycle) loader).stop();
5438                 if (classLoader != null) {
5439                     InstanceManagerBindings.unbind(classLoader);
5440                 }
5441             }
5442
5443             // Stop resources
5444             resourcesStop();
5445
5446         } finally {
5447
5448             // Unbinding thread
5449             unbindThread(oldCCL);
5450
5451         }
5452
5453         // Send j2ee.state.stopped notification
5454         if (this.getObjectName() != null) {
5455             Notification notification =
5456                 new Notification("j2ee.state.stopped"this.getObjectName(),
5457                                 sequenceNumber.getAndIncrement());
5458             broadcaster.sendNotification(notification);
5459         }
5460
5461         // Reset application context
5462         context = null;
5463
5464         // This object will no longer be visible or used.
5465         try {
5466             resetContext();
5467         } catch( Exception ex ) {
5468             log.error( "Error resetting context " + this + " " + ex, ex );
5469         }
5470
5471         //reset the instance manager
5472         setInstanceManager(null);
5473
5474         if (log.isDebugEnabled())
5475             log.debug("Stopping complete");
5476
5477     }
5478
5479     /** Destroy needs to clean up the context completely.
5480      *
5481      * The problem is that undoing all the config in start() and restoring
5482      * a 'fresh' state is impossible. After stop()/destroy()/init()/start()
5483      * we should have the same state as if a fresh start was done - i.e
5484      * read modified web.xml, etc. This can only be done by completely
5485      * removing the context object and remapping a new one, or by cleaning
5486      * up everything.
5487      *
5488      * XXX Should this be done in stop() ?
5489      *
5490      */

5491     @Override
5492     protected void destroyInternal() throws LifecycleException {
5493
5494         // If in state NEW when destroy is called, the object name will never
5495         // have been set so the notification can't be created
5496         if (getObjectName() != null) {
5497             // Send j2ee.object.deleted notification
5498             Notification notification =
5499                 new Notification("j2ee.object.deleted"this.getObjectName(),
5500                                  sequenceNumber.getAndIncrement());
5501             broadcaster.sendNotification(notification);
5502         }
5503
5504         if (namingResources != null) {
5505             namingResources.destroy();
5506         }
5507
5508         Loader loader = getLoader();
5509         if (loader instanceof Lifecycle) {
5510             ((Lifecycle) loader).destroy();
5511         }
5512
5513         Manager manager = getManager();
5514         if (manager instanceof Lifecycle) {
5515             ((Lifecycle) manager).destroy();
5516         }
5517
5518         if (resources != null) {
5519             resources.destroy();
5520         }
5521
5522         super.destroyInternal();
5523     }
5524
5525
5526     @Override
5527     public void backgroundProcess() {
5528
5529         if (!getState().isAvailable())
5530             return;
5531
5532         Loader loader = getLoader();
5533         if (loader != null) {
5534             try {
5535                 loader.backgroundProcess();
5536             } catch (Exception e) {
5537                 log.warn(sm.getString(
5538                         "standardContext.backgroundProcess.loader", loader), e);
5539             }
5540         }
5541         Manager manager = getManager();
5542         if (manager != null) {
5543             try {
5544                 manager.backgroundProcess();
5545             } catch (Exception e) {
5546                 log.warn(sm.getString(
5547                         "standardContext.backgroundProcess.manager", manager),
5548                         e);
5549             }
5550         }
5551         WebResourceRoot resources = getResources();
5552         if (resources != null) {
5553             try {
5554                 resources.backgroundProcess();
5555             } catch (Exception e) {
5556                 log.warn(sm.getString(
5557                         "standardContext.backgroundProcess.resources",
5558                         resources), e);
5559             }
5560         }
5561         InstanceManager instanceManager = getInstanceManager();
5562         if (instanceManager != null) {
5563             try {
5564                 instanceManager.backgroundProcess();
5565             } catch (Exception e) {
5566                 log.warn(sm.getString(
5567                         "standardContext.backgroundProcess.instanceManager",
5568                         resources), e);
5569             }
5570         }
5571         super.backgroundProcess();
5572     }
5573
5574
5575     private void resetContext() throws Exception {
5576         // Restore the original state ( pre reading web.xml in start )
5577         // If you extend this - override this method and make sure to clean up
5578
5579         // Don't reset anything that is read from a <Context.../> element since
5580         // <Context .../> elements are read at initialisation will not be read
5581         // again for this object
5582         for (Container child : findChildren()) {
5583             removeChild(child);
5584         }
5585         startupTime = 0;
5586         startTime = 0;
5587         tldScanTime = 0;
5588
5589         // Bugzilla 32867
5590         distributable = false;
5591
5592         applicationListeners = new String[0];
5593         applicationEventListenersList.clear();
5594         applicationLifecycleListenersObjects = new Object[0];
5595         jspConfigDescriptor = null;
5596
5597         initializers.clear();
5598
5599         createdServlets.clear();
5600
5601         postConstructMethods.clear();
5602         preDestroyMethods.clear();
5603
5604         if(log.isDebugEnabled())
5605             log.debug("resetContext " + getObjectName());
5606     }
5607
5608
5609     // ------------------------------------------------------ Protected Methods
5610
5611     /**
5612      * Adjust the URL pattern to begin with a leading slash, if appropriate
5613      * (i.e. we are running a servlet 2.2 application).  Otherwise, return
5614      * the specified URL pattern unchanged.
5615      *
5616      * @param urlPattern The URL pattern to be adjusted (if needed)
5617      *  and returned
5618      * @return the URL pattern with a leading slash if needed
5619      */

5620     protected String adjustURLPattern(String urlPattern) {
5621
5622         if (urlPattern == null)
5623             return urlPattern;
5624         if (urlPattern.startsWith("/") || urlPattern.startsWith("*."))
5625             return urlPattern;
5626         if (!isServlet22())
5627             return urlPattern;
5628         if(log.isDebugEnabled())
5629             log.debug(sm.getString("standardContext.urlPattern.patternWarning",
5630                          urlPattern));
5631         return "/" + urlPattern;
5632
5633     }
5634
5635
5636     /**
5637      * Are we processing a version 2.2 deployment descriptor?
5638      *
5639      * @return <code>true</code> if running a legacy Servlet 2.2 application
5640      */

5641     @Override
5642     public boolean isServlet22() {
5643         return XmlIdentifiers.WEB_22_PUBLIC.equals(publicId);
5644     }
5645
5646
5647     @Override
5648     public Set<String> addServletSecurity(
5649             ServletRegistration.Dynamic registration,
5650             ServletSecurityElement servletSecurityElement) {
5651
5652         Set<String> conflicts = new HashSet<>();
5653
5654         Collection<String> urlPatterns = registration.getMappings();
5655         for (String urlPattern : urlPatterns) {
5656             boolean foundConflict = false;
5657
5658             SecurityConstraint[] securityConstraints =
5659                 findConstraints();
5660             for (SecurityConstraint securityConstraint : securityConstraints) {
5661
5662                 SecurityCollection[] collections =
5663                     securityConstraint.findCollections();
5664                 for (SecurityCollection collection : collections) {
5665                     if (collection.findPattern(urlPattern)) {
5666                         // First pattern found will indicate if there is a
5667                         // conflict since for any given pattern all matching
5668                         // constraints will be from either the descriptor or
5669                         // not. It is not permitted to have a mixture
5670                         if (collection.isFromDescriptor()) {
5671                             // Skip this pattern
5672                             foundConflict = true;
5673                             conflicts.add(urlPattern);
5674                             break;
5675                         } else {
5676                             // Need to overwrite constraint for this pattern
5677                             collection.removePattern(urlPattern);
5678                             // If the collection is now empty, remove it
5679                             if (collection.findPatterns().length == 0) {
5680                                 securityConstraint.removeCollection(collection);
5681                             }
5682                         }
5683                     }
5684                 }
5685
5686                 // If the constraint now has no collections - remove it
5687                 if (securityConstraint.findCollections().length == 0) {
5688                     removeConstraint(securityConstraint);
5689                 }
5690
5691                 // No need to check other constraints for the current pattern
5692                 // once a conflict has been found
5693                 if (foundConflict) {
5694                     break;
5695                 }
5696             }
5697
5698             // Note: For programmatically added Servlets this may not be the
5699             //       complete set of security constraints since additional
5700             //       URL patterns can be added after the application has called
5701             //       setSecurity. For all programmatically added servlets, the
5702             //       #dynamicServletAdded() method sets a flag that ensures that
5703             //       the constraints are re-evaluated before the servlet is
5704             //       first used
5705
5706             // If the pattern did not conflict, add the new constraint(s).
5707             if (!foundConflict) {
5708                 SecurityConstraint[] newSecurityConstraints =
5709                         SecurityConstraint.createConstraints(
5710                                 servletSecurityElement,
5711                                 urlPattern);
5712                 for (SecurityConstraint securityConstraint :
5713                         newSecurityConstraints) {
5714                     addConstraint(securityConstraint);
5715                 }
5716             }
5717         }
5718
5719         return conflicts;
5720     }
5721
5722
5723     /**
5724      * Bind current thread, both for CL purposes and for JNDI ENC support
5725      * during : startup, shutdown and reloading of the context.
5726      *
5727      * @return the previous context class loader
5728      */

5729     protected ClassLoader bindThread() {
5730
5731         ClassLoader oldContextClassLoader = bind(falsenull);
5732
5733         if (isUseNaming()) {
5734             try {
5735                 ContextBindings.bindThread(this, getNamingToken());
5736             } catch (NamingException e) {
5737                 // Silent catch, as this is a normal case during the early
5738                 // startup stages
5739             }
5740         }
5741
5742         return oldContextClassLoader;
5743     }
5744
5745
5746     /**
5747      * Unbind thread and restore the specified context classloader.
5748      *
5749      * @param oldContextClassLoader the previous classloader
5750      */

5751     protected void unbindThread(ClassLoader oldContextClassLoader) {
5752
5753         if (isUseNaming()) {
5754             ContextBindings.unbindThread(this, getNamingToken());
5755         }
5756
5757         unbind(false, oldContextClassLoader);
5758     }
5759
5760
5761     @Override
5762     public ClassLoader bind(boolean usePrivilegedAction, ClassLoader originalClassLoader) {
5763         Loader loader = getLoader();
5764         ClassLoader webApplicationClassLoader = null;
5765         if (loader != null) {
5766             webApplicationClassLoader = loader.getClassLoader();
5767         }
5768
5769         if (originalClassLoader == null) {
5770             if (usePrivilegedAction) {
5771                 PrivilegedAction<ClassLoader> pa = new PrivilegedGetTccl();
5772                 originalClassLoader = AccessController.doPrivileged(pa);
5773             } else {
5774                 originalClassLoader = Thread.currentThread().getContextClassLoader();
5775             }
5776         }
5777
5778         if (webApplicationClassLoader == null ||
5779                 webApplicationClassLoader == originalClassLoader) {
5780             // Not possible or not necessary to switch class loaders. Return
5781             // null to indicate this.
5782             return null;
5783         }
5784
5785         ThreadBindingListener threadBindingListener = getThreadBindingListener();
5786
5787         if (usePrivilegedAction) {
5788             PrivilegedAction<Void> pa = new PrivilegedSetTccl(webApplicationClassLoader);
5789             AccessController.doPrivileged(pa);
5790         } else {
5791             Thread.currentThread().setContextClassLoader(webApplicationClassLoader);
5792         }
5793         if (threadBindingListener != null) {
5794             try {
5795                 threadBindingListener.bind();
5796             } catch (Throwable t) {
5797                 ExceptionUtils.handleThrowable(t);
5798                 log.error(sm.getString(
5799                         "standardContext.threadBindingListenerError", getName()), t);
5800             }
5801         }
5802
5803         return originalClassLoader;
5804     }
5805
5806
5807     @Override
5808     public void unbind(boolean usePrivilegedAction, ClassLoader originalClassLoader) {
5809         if (originalClassLoader == null) {
5810             return;
5811         }
5812
5813         if (threadBindingListener != null) {
5814             try {
5815                 threadBindingListener.unbind();
5816             } catch (Throwable t) {
5817                 ExceptionUtils.handleThrowable(t);
5818                 log.error(sm.getString(
5819                         "standardContext.threadBindingListenerError", getName()), t);
5820             }
5821         }
5822
5823         if (usePrivilegedAction) {
5824             PrivilegedAction<Void> pa = new PrivilegedSetTccl(originalClassLoader);
5825             AccessController.doPrivileged(pa);
5826         } else {
5827             Thread.currentThread().setContextClassLoader(originalClassLoader);
5828         }
5829     }
5830
5831
5832     /**
5833      * Get naming context full name.
5834      *
5835      * @return the context name
5836      */

5837     private String getNamingContextName() {
5838         if (namingContextName == null) {
5839             Container parent = getParent();
5840             if (parent == null) {
5841             namingContextName = getName();
5842             } else {
5843             Stack<String> stk = new Stack<>();
5844             StringBuilder buff = new StringBuilder();
5845             while (parent != null) {
5846                 stk.push(parent.getName());
5847                 parent = parent.getParent();
5848             }
5849             while (!stk.empty()) {
5850                 buff.append("/" + stk.pop());
5851             }
5852             buff.append(getName());
5853             namingContextName = buff.toString();
5854             }
5855         }
5856         return namingContextName;
5857     }
5858
5859
5860     /**
5861      * Naming context listener accessor.
5862      *
5863      * @return the naming context listener associated with the webapp
5864      */

5865     public NamingContextListener getNamingContextListener() {
5866         return namingContextListener;
5867     }
5868
5869
5870     /**
5871      * Naming context listener setter.
5872      *
5873      * @param namingContextListener the new naming context listener
5874      */

5875     public void setNamingContextListener(NamingContextListener namingContextListener) {
5876         this.namingContextListener = namingContextListener;
5877     }
5878
5879
5880     /**
5881      * @return the request processing paused flag for this Context.
5882      */

5883     @Override
5884     public boolean getPaused() {
5885         return this.paused;
5886     }
5887
5888
5889     @Override
5890     public boolean fireRequestInitEvent(ServletRequest request) {
5891
5892         Object instances[] = getApplicationEventListeners();
5893
5894         if ((instances != null) && (instances.length > 0)) {
5895
5896             ServletRequestEvent event =
5897                     new ServletRequestEvent(getServletContext(), request);
5898
5899             for (int i = 0; i < instances.length; i++) {
5900                 if (instances[i] == null)
5901                     continue;
5902                 if (!(instances[i] instanceof ServletRequestListener))
5903                     continue;
5904                 ServletRequestListener listener =
5905                     (ServletRequestListener) instances[i];
5906
5907                 try {
5908                     listener.requestInitialized(event);
5909                 } catch (Throwable t) {
5910                     ExceptionUtils.handleThrowable(t);
5911                     getLogger().error(sm.getString(
5912                             "standardContext.requestListener.requestInit",
5913                             instances[i].getClass().getName()), t);
5914                     request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
5915                     return false;
5916                 }
5917             }
5918         }
5919         return true;
5920     }
5921
5922
5923     @Override
5924     public boolean fireRequestDestroyEvent(ServletRequest request) {
5925         Object instances[] = getApplicationEventListeners();
5926
5927         if ((instances != null) && (instances.length > 0)) {
5928
5929             ServletRequestEvent event =
5930                 new ServletRequestEvent(getServletContext(), request);
5931
5932             for (int i = 0; i < instances.length; i++) {
5933                 int j = (instances.length -1) -i;
5934                 if (instances[j] == null)
5935                     continue;
5936                 if (!(instances[j] instanceof ServletRequestListener))
5937                     continue;
5938                 ServletRequestListener listener =
5939                     (ServletRequestListener) instances[j];
5940
5941                 try {
5942                     listener.requestDestroyed(event);
5943                 } catch (Throwable t) {
5944                     ExceptionUtils.handleThrowable(t);
5945                     getLogger().error(sm.getString(
5946                             "standardContext.requestListener.requestInit",
5947                             instances[j].getClass().getName()), t);
5948                     request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
5949                     return false;
5950                 }
5951             }
5952         }
5953         return true;
5954     }
5955
5956
5957     @Override
5958     public void addPostConstructMethod(String clazz, String method) {
5959         if (clazz == null || method == null)
5960             throw new IllegalArgumentException(
5961                     sm.getString("standardContext.postconstruct.required"));
5962         if (postConstructMethods.get(clazz) != null)
5963             throw new IllegalArgumentException(sm.getString(
5964                     "standardContext.postconstruct.duplicate", clazz));
5965
5966         postConstructMethods.put(clazz, method);
5967         fireContainerEvent("addPostConstructMethod", clazz);
5968     }
5969
5970
5971     @Override
5972     public void removePostConstructMethod(String clazz) {
5973         postConstructMethods.remove(clazz);
5974         fireContainerEvent("removePostConstructMethod", clazz);
5975     }
5976
5977
5978     @Override
5979     public void addPreDestroyMethod(String clazz, String method) {
5980         if (clazz == null || method == null)
5981             throw new IllegalArgumentException(
5982                     sm.getString("standardContext.predestroy.required"));
5983         if (preDestroyMethods.get(clazz) != null)
5984             throw new IllegalArgumentException(sm.getString(
5985                     "standardContext.predestroy.duplicate", clazz));
5986
5987         preDestroyMethods.put(clazz, method);
5988         fireContainerEvent("addPreDestroyMethod", clazz);
5989     }
5990
5991
5992     @Override
5993     public void removePreDestroyMethod(String clazz) {
5994         preDestroyMethods.remove(clazz);
5995         fireContainerEvent("removePreDestroyMethod", clazz);
5996     }
5997
5998
5999     @Override
6000     public String findPostConstructMethod(String clazz) {
6001         return postConstructMethods.get(clazz);
6002     }
6003
6004
6005     @Override
6006     public String findPreDestroyMethod(String clazz) {
6007         return preDestroyMethods.get(clazz);
6008     }
6009
6010
6011     @Override
6012     public Map<String, String> findPostConstructMethods() {
6013         return postConstructMethods;
6014     }
6015
6016
6017     @Override
6018     public Map<String, String> findPreDestroyMethods() {
6019         return preDestroyMethods;
6020     }
6021
6022
6023     /**
6024      * Set the appropriate context attribute for our work directory.
6025      */

6026     private void postWorkDirectory() {
6027
6028         // Acquire (or calculate) the work directory path
6029         String workDir = getWorkDir();
6030         if (workDir == null || workDir.length() == 0) {
6031
6032             // Retrieve our parent (normally a host) name
6033             String hostName = null;
6034             String engineName = null;
6035             String hostWorkDir = null;
6036             Container parentHost = getParent();
6037             if (parentHost != null) {
6038                 hostName = parentHost.getName();
6039                 if (parentHost instanceof StandardHost) {
6040                     hostWorkDir = ((StandardHost)parentHost).getWorkDir();
6041                 }
6042                 Container parentEngine = parentHost.getParent();
6043                 if (parentEngine != null) {
6044                    engineName = parentEngine.getName();
6045                 }
6046             }
6047             if ((hostName == null) || (hostName.length() < 1))
6048                 hostName = "_";
6049             if ((engineName == null) || (engineName.length() < 1))
6050                 engineName = "_";
6051
6052             String temp = getBaseName();
6053             if (temp.startsWith("/"))
6054                 temp = temp.substring(1);
6055             temp = temp.replace('/', '_');
6056             temp = temp.replace('\\', '_');
6057             if (temp.length() < 1)
6058                 temp = ContextName.ROOT_NAME;
6059             if (hostWorkDir != null ) {
6060                 workDir = hostWorkDir + File.separator + temp;
6061             } else {
6062                 workDir = "work" + File.separator + engineName +
6063                     File.separator + hostName + File.separator + temp;
6064             }
6065             setWorkDir(workDir);
6066         }
6067
6068         // Create this directory if necessary
6069         File dir = new File(workDir);
6070         if (!dir.isAbsolute()) {
6071             String catalinaHomePath = null;
6072             try {
6073                 catalinaHomePath = getCatalinaBase().getCanonicalPath();
6074                 dir = new File(catalinaHomePath, workDir);
6075             } catch (IOException e) {
6076                 log.warn(sm.getString("standardContext.workCreateException",
6077                         workDir, catalinaHomePath, getName()), e);
6078             }
6079         }
6080         if (!dir.mkdirs() && !dir.isDirectory()) {
6081             log.warn(sm.getString("standardContext.workCreateFail", dir,
6082                     getName()));
6083         }
6084
6085         // Set the appropriate servlet context attribute
6086         if (context == null) {
6087             getServletContext();
6088         }
6089         context.setAttribute(ServletContext.TEMPDIR, dir);
6090         context.setAttributeReadOnly(ServletContext.TEMPDIR);
6091     }
6092
6093
6094     /**
6095      * Set the request processing paused flag for this Context.
6096      *
6097      * @param paused The new request processing paused flag
6098      */

6099     private void setPaused(boolean paused) {
6100
6101         this.paused = paused;
6102
6103     }
6104
6105
6106     /**
6107      * Validate the syntax of a proposed <code>&lt;url-pattern&gt;</code>
6108      * for conformance with specification requirements.
6109      *
6110      * @param urlPattern URL pattern to be validated
6111      * @return <code>true</code> if the URL pattern is conformant
6112      */

6113     private boolean validateURLPattern(String urlPattern) {
6114
6115         if (urlPattern == null)
6116             return false;
6117         if (urlPattern.indexOf('\n') >= 0 || urlPattern.indexOf('\r') >= 0) {
6118             return false;
6119         }
6120         if (urlPattern.equals("")) {
6121             return true;
6122         }
6123         if (urlPattern.startsWith("*.")) {
6124             if (urlPattern.indexOf('/') < 0) {
6125                 checkUnusualURLPattern(urlPattern);
6126                 return true;
6127             } else
6128                 return false;
6129         }
6130         if (urlPattern.startsWith("/") && !urlPattern.contains("*.")) {
6131             checkUnusualURLPattern(urlPattern);
6132             return true;
6133         } else
6134             return false;
6135
6136     }
6137
6138
6139     /**
6140      * Check for unusual but valid <code>&lt;url-pattern&gt;</code>s.
6141      * See Bugzilla 34805, 43079 & 43080
6142      */

6143     private void checkUnusualURLPattern(String urlPattern) {
6144         if (log.isInfoEnabled()) {
6145             // First group checks for '*' or '/foo*' style patterns
6146             // Second group checks for *.foo.bar style patterns
6147             if((urlPattern.endsWith("*") && (urlPattern.length() < 2 ||
6148                         urlPattern.charAt(urlPattern.length()-2) != '/')) ||
6149                     urlPattern.startsWith("*.") && urlPattern.length() > 2 &&
6150                         urlPattern.lastIndexOf('.') > 1) {
6151                 log.info(sm.getString("standardContext.suspiciousUrl", urlPattern, getName()));
6152             }
6153         }
6154     }
6155
6156
6157     // ------------------------------------------------------------- Operations
6158
6159     @Override
6160     protected String getObjectNameKeyProperties() {
6161
6162         StringBuilder keyProperties =
6163             new StringBuilder("j2eeType=WebModule,");
6164         keyProperties.append(getObjectKeyPropertiesNameOnly());
6165         keyProperties.append(",J2EEApplication=");
6166         keyProperties.append(getJ2EEApplication());
6167         keyProperties.append(",J2EEServer=");
6168         keyProperties.append(getJ2EEServer());
6169
6170         return keyProperties.toString();
6171     }
6172
6173     private String getObjectKeyPropertiesNameOnly() {
6174         StringBuilder result = new StringBuilder("name=//");
6175         String hostname = getParent().getName();
6176         if (hostname == null) {
6177             result.append("DEFAULT");
6178         } else {
6179             result.append(hostname);
6180         }
6181
6182         String contextName = getName();
6183         if (!contextName.startsWith("/")) {
6184             result.append('/');
6185         }
6186         result.append(contextName);
6187
6188         return result.toString();
6189     }
6190
6191     @Override
6192     protected void initInternal() throws LifecycleException {
6193         super.initInternal();
6194
6195         // Register the naming resources
6196         if (namingResources != null) {
6197             namingResources.init();
6198         }
6199
6200         // Send j2ee.object.created notification
6201         if (this.getObjectName() != null) {
6202             Notification notification = new Notification("j2ee.object.created",
6203                     this.getObjectName(), sequenceNumber.getAndIncrement());
6204             broadcaster.sendNotification(notification);
6205         }
6206     }
6207
6208
6209     /* Remove a JMX notificationListener
6210      * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
6211      */

6212     @Override
6213     public void removeNotificationListener(NotificationListener listener,
6214             NotificationFilter filter, Object object) throws ListenerNotFoundException {
6215         broadcaster.removeNotificationListener(listener,filter,object);
6216     }
6217
6218     private MBeanNotificationInfo[] notificationInfo;
6219
6220     /* Get JMX Broadcaster Info
6221      * @TODO use StringManager for international support!
6222      * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed!
6223      * @see javax.management.NotificationBroadcaster#getNotificationInfo()
6224      */

6225     @Override
6226     public MBeanNotificationInfo[] getNotificationInfo() {
6227         // FIXME: i18n
6228         if(notificationInfo == null) {
6229             notificationInfo = new MBeanNotificationInfo[]{
6230                     new MBeanNotificationInfo(new String[] {
6231                     "j2ee.object.created"},
6232                     Notification.class.getName(),
6233                     "web application is created"
6234                     ),
6235                     new MBeanNotificationInfo(new String[] {
6236                     "j2ee.state.starting"},
6237                     Notification.class.getName(),
6238                     "change web application is starting"
6239                     ),
6240                     new MBeanNotificationInfo(new String[] {
6241                     "j2ee.state.running"},
6242                     Notification.class.getName(),
6243                     "web application is running"
6244                     ),
6245                     new MBeanNotificationInfo(new String[] {
6246                     "j2ee.state.stopping"},
6247                     Notification.class.getName(),
6248                     "web application start to stopped"
6249                     ),
6250                     new MBeanNotificationInfo(new String[] {
6251                     "j2ee.object.stopped"},
6252                     Notification.class.getName(),
6253                     "web application is stopped"
6254                     ),
6255                     new MBeanNotificationInfo(new String[] {
6256                     "j2ee.object.deleted"},
6257                     Notification.class.getName(),
6258                     "web application is deleted"
6259                     )
6260             };
6261
6262         }
6263
6264         return notificationInfo;
6265     }
6266
6267
6268     /**
6269      * Add a JMX NotificationListener
6270      * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object)
6271      */

6272     @Override
6273     public void addNotificationListener(NotificationListener listener,
6274             NotificationFilter filter, Object object) throws IllegalArgumentException {
6275         broadcaster.addNotificationListener(listener,filter,object);
6276     }
6277
6278
6279     /**
6280      * Remove a JMX-NotificationListener
6281      * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener)
6282      */

6283     @Override
6284     public void removeNotificationListener(NotificationListener listener)
6285     throws ListenerNotFoundException {
6286         broadcaster.removeNotificationListener(listener);
6287     }
6288
6289
6290     // ------------------------------------------------------------- Attributes
6291
6292     /**
6293      * @return the naming resources associated with this web application.
6294      */

6295     public String[] getWelcomeFiles() {
6296
6297         return findWelcomeFiles();
6298
6299     }
6300
6301
6302     @Override
6303     public boolean getXmlNamespaceAware() {
6304         return webXmlNamespaceAware;
6305     }
6306
6307
6308     @Override
6309     public void setXmlNamespaceAware(boolean webXmlNamespaceAware) {
6310         this.webXmlNamespaceAware = webXmlNamespaceAware;
6311     }
6312
6313
6314     @Override
6315     public void setXmlValidation(boolean webXmlValidation) {
6316         this.webXmlValidation = webXmlValidation;
6317     }
6318
6319
6320     @Override
6321     public boolean getXmlValidation() {
6322         return webXmlValidation;
6323     }
6324
6325
6326     @Override
6327     public void setXmlBlockExternal(boolean xmlBlockExternal) {
6328         this.xmlBlockExternal = xmlBlockExternal;
6329     }
6330
6331
6332     @Override
6333     public boolean getXmlBlockExternal() {
6334         return xmlBlockExternal;
6335     }
6336
6337
6338     @Override
6339     public void setTldValidation(boolean tldValidation) {
6340         this.tldValidation = tldValidation;
6341     }
6342
6343
6344     @Override
6345     public boolean getTldValidation() {
6346         return tldValidation;
6347     }
6348
6349
6350     /**
6351      * The J2EE Server ObjectName this module is deployed on.
6352      */

6353     private String server = null;
6354
6355     /**
6356      * The Java virtual machines on which this module is running.
6357      */

6358     private String[] javaVMs = null;
6359
6360     public String getServer() {
6361         return server;
6362     }
6363
6364     public String setServer(String server) {
6365         return this.server=server;
6366     }
6367
6368     public String[] getJavaVMs() {
6369         return javaVMs;
6370     }
6371
6372     public String[] setJavaVMs(String[] javaVMs) {
6373         return this.javaVMs = javaVMs;
6374     }
6375
6376     /**
6377      * Gets the time this context was started.
6378      *
6379      * @return Time (in milliseconds since January 1, 1970, 00:00:00) when this
6380      * context was started
6381      */

6382     public long getStartTime() {
6383         return startTime;
6384     }
6385
6386
6387     private static class NoPluggabilityServletContext
6388             implements ServletContext {
6389
6390         private final ServletContext sc;
6391
6392         public NoPluggabilityServletContext(ServletContext sc) {
6393             this.sc = sc;
6394         }
6395
6396         @Override
6397         public String getContextPath() {
6398             return sc.getContextPath();
6399         }
6400
6401         @Override
6402         public ServletContext getContext(String uripath) {
6403             return sc.getContext(uripath);
6404         }
6405
6406         @Override
6407         public int getMajorVersion() {
6408            return sc.getMajorVersion();
6409         }
6410
6411         @Override
6412         public int getMinorVersion() {
6413             return sc.getMinorVersion();
6414         }
6415
6416         @Override
6417         public int getEffectiveMajorVersion() {
6418             throw new UnsupportedOperationException(
6419                     sm.getString("noPluggabilityServletContext.notAllowed"));
6420         }
6421
6422         @Override
6423         public int getEffectiveMinorVersion() {
6424             throw new UnsupportedOperationException(
6425                     sm.getString("noPluggabilityServletContext.notAllowed"));
6426         }
6427
6428         @Override
6429         public String getMimeType(String file) {
6430             return sc.getMimeType(file);
6431         }
6432
6433         @Override
6434         public Set<String> getResourcePaths(String path) {
6435             return sc.getResourcePaths(path);
6436         }
6437
6438         @Override
6439         public URL getResource(String path) throws MalformedURLException {
6440             return sc.getResource(path);
6441         }
6442
6443         @Override
6444         public InputStream getResourceAsStream(String path) {
6445             return sc.getResourceAsStream(path);
6446         }
6447
6448         @Override
6449         public RequestDispatcher getRequestDispatcher(String path) {
6450             return sc.getRequestDispatcher(path);
6451         }
6452
6453         @Override
6454         public RequestDispatcher getNamedDispatcher(String name) {
6455             return sc.getNamedDispatcher(name);
6456         }
6457
6458         @Override
6459         @Deprecated
6460         public Servlet getServlet(String name) throws ServletException {
6461             return sc.getServlet(name);
6462         }
6463
6464         @Override
6465         @Deprecated
6466         public Enumeration<Servlet> getServlets() {
6467             return sc.getServlets();
6468         }
6469
6470         @Override
6471         @Deprecated
6472         public Enumeration<String> getServletNames() {
6473             return sc.getServletNames();
6474         }
6475
6476         @Override
6477         public void log(String msg) {
6478             sc.log(msg);
6479         }
6480
6481         @Override
6482         @Deprecated
6483         public void log(Exception exception, String msg) {
6484             sc.log(exception, msg);
6485         }
6486
6487         @Override
6488         public void log(String message, Throwable throwable) {
6489             sc.log(message, throwable);
6490         }
6491
6492         @Override
6493         public String getRealPath(String path) {
6494             return sc.getRealPath(path);
6495         }
6496
6497         @Override
6498         public String getServerInfo() {
6499             return sc.getServerInfo();
6500         }
6501
6502         @Override
6503         public String getInitParameter(String name) {
6504             return sc.getInitParameter(name);
6505         }
6506
6507         @Override
6508         public Enumeration<String> getInitParameterNames() {
6509             return sc.getInitParameterNames();
6510         }
6511
6512         @Override
6513         public boolean setInitParameter(String name, String value) {
6514             throw new UnsupportedOperationException(
6515                     sm.getString("noPluggabilityServletContext.notAllowed"));
6516         }
6517
6518         @Override
6519         public Object getAttribute(String name) {
6520             return sc.getAttribute(name);
6521         }
6522
6523         @Override
6524         public Enumeration<String> getAttributeNames() {
6525             return sc.getAttributeNames();
6526         }
6527
6528         @Override
6529         public void setAttribute(String name, Object object) {
6530             sc.setAttribute(name, object);
6531         }
6532
6533         @Override
6534         public void removeAttribute(String name) {
6535             sc.removeAttribute(name);
6536         }
6537
6538         @Override
6539         public String getServletContextName() {
6540             return sc.getServletContextName();
6541         }
6542
6543         @Override
6544         public Dynamic addServlet(String servletName, String className) {
6545             throw new UnsupportedOperationException(
6546                     sm.getString("noPluggabilityServletContext.notAllowed"));
6547         }
6548
6549         @Override
6550         public Dynamic addServlet(String servletName, Servlet servlet) {
6551             throw new UnsupportedOperationException(
6552                     sm.getString("noPluggabilityServletContext.notAllowed"));
6553         }
6554
6555         @Override
6556         public Dynamic addServlet(String servletName,
6557                 Class<? extends Servlet> servletClass) {
6558             throw new UnsupportedOperationException(
6559                     sm.getString("noPluggabilityServletContext.notAllowed"));
6560         }
6561
6562         @Override
6563         public Dynamic addJspFile(String jspName, String jspFile) {
6564             throw new UnsupportedOperationException(
6565                     sm.getString("noPluggabilityServletContext.notAllowed"));
6566         }
6567
6568         @Override
6569         public <T extends Servlet> T createServlet(Class<T> c)
6570                 throws ServletException {
6571             throw new UnsupportedOperationException(
6572                     sm.getString("noPluggabilityServletContext.notAllowed"));
6573         }
6574
6575         @Override
6576         public ServletRegistration getServletRegistration(String servletName) {
6577             throw new UnsupportedOperationException(
6578                     sm.getString("noPluggabilityServletContext.notAllowed"));
6579         }
6580
6581         @Override
6582         public Map<String,? extends ServletRegistration> getServletRegistrations() {
6583             throw new UnsupportedOperationException(
6584                     sm.getString("noPluggabilityServletContext.notAllowed"));
6585         }
6586
6587         @Override
6588         public javax.servlet.FilterRegistration.Dynamic addFilter(
6589                 String filterName, String className) {
6590             throw new UnsupportedOperationException(
6591                     sm.getString("noPluggabilityServletContext.notAllowed"));
6592         }
6593
6594         @Override
6595         public javax.servlet.FilterRegistration.Dynamic addFilter(
6596                 String filterName, Filter filter) {
6597             throw new UnsupportedOperationException(
6598                     sm.getString("noPluggabilityServletContext.notAllowed"));
6599         }
6600
6601         @Override
6602         public javax.servlet.FilterRegistration.Dynamic addFilter(
6603                 String filterName, Class<? extends Filter> filterClass) {
6604             throw new UnsupportedOperationException(
6605                     sm.getString("noPluggabilityServletContext.notAllowed"));
6606         }
6607
6608         @Override
6609         public <T extends Filter> T createFilter(Class<T> c)
6610                 throws ServletException {
6611             throw new UnsupportedOperationException(
6612                     sm.getString("noPluggabilityServletContext.notAllowed"));
6613         }
6614
6615         @Override
6616         public FilterRegistration getFilterRegistration(String filterName) {
6617             throw new UnsupportedOperationException(
6618                     sm.getString("noPluggabilityServletContext.notAllowed"));
6619         }
6620
6621         @Override
6622         public Map<String,? extends FilterRegistration> getFilterRegistrations() {
6623             throw new UnsupportedOperationException(
6624                     sm.getString("noPluggabilityServletContext.notAllowed"));
6625         }
6626
6627         @Override
6628         public SessionCookieConfig getSessionCookieConfig() {
6629             throw new UnsupportedOperationException(
6630                     sm.getString("noPluggabilityServletContext.notAllowed"));
6631         }
6632
6633         @Override
6634         public void setSessionTrackingModes(
6635                 Set<SessionTrackingMode> sessionTrackingModes) {
6636             throw new UnsupportedOperationException(
6637                     sm.getString("noPluggabilityServletContext.notAllowed"));
6638         }
6639
6640         @Override
6641         public Set<SessionTrackingMode> getDefaultSessionTrackingModes() {
6642             throw new UnsupportedOperationException(
6643                     sm.getString("noPluggabilityServletContext.notAllowed"));
6644         }
6645
6646         @Override
6647         public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() {
6648             throw new UnsupportedOperationException(
6649                     sm.getString("noPluggabilityServletContext.notAllowed"));
6650         }
6651
6652         @Override
6653         public void addListener(String className) {
6654             throw new UnsupportedOperationException(
6655                     sm.getString("noPluggabilityServletContext.notAllowed"));
6656         }
6657
6658         @Override
6659         public <T extends EventListener> void addListener(T t) {
6660             throw new UnsupportedOperationException(
6661                     sm.getString("noPluggabilityServletContext.notAllowed"));
6662         }
6663
6664         @Override
6665         public void addListener(Class<? extends EventListener> listenerClass) {
6666             throw new UnsupportedOperationException(
6667                     sm.getString("noPluggabilityServletContext.notAllowed"));
6668         }
6669
6670         @Override
6671         public <T extends EventListener> T createListener(Class<T> c)
6672                 throws ServletException {
6673             throw new UnsupportedOperationException(
6674                     sm.getString("noPluggabilityServletContext.notAllowed"));
6675         }
6676
6677         @Override
6678         public JspConfigDescriptor getJspConfigDescriptor() {
6679             throw new UnsupportedOperationException(
6680                     sm.getString("noPluggabilityServletContext.notAllowed"));
6681         }
6682
6683         @Override
6684         public ClassLoader getClassLoader() {
6685             throw new UnsupportedOperationException(
6686                     sm.getString("noPluggabilityServletContext.notAllowed"));
6687         }
6688
6689         @Override
6690         public void declareRoles(String... roleNames) {
6691             throw new UnsupportedOperationException(
6692                     sm.getString("noPluggabilityServletContext.notAllowed"));
6693         }
6694
6695         @Override
6696         public String getVirtualServerName() {
6697             return sc.getVirtualServerName();
6698         }
6699
6700         @Override
6701         public int getSessionTimeout() {
6702             throw new UnsupportedOperationException(
6703                     sm.getString("noPluggabilityServletContext.notAllowed"));
6704         }
6705
6706         @Override
6707         public void setSessionTimeout(int sessionTimeout) {
6708             throw new UnsupportedOperationException(
6709                     sm.getString("noPluggabilityServletContext.notAllowed"));
6710         }
6711
6712         @Override
6713         public String getRequestCharacterEncoding() {
6714             throw new UnsupportedOperationException(
6715                     sm.getString("noPluggabilityServletContext.notAllowed"));
6716         }
6717
6718         @Override
6719         public void setRequestCharacterEncoding(String encoding) {
6720             throw new UnsupportedOperationException(
6721                     sm.getString("noPluggabilityServletContext.notAllowed"));
6722         }
6723
6724         @Override
6725         public String getResponseCharacterEncoding() {
6726             throw new UnsupportedOperationException(
6727                     sm.getString("noPluggabilityServletContext.notAllowed"));
6728         }
6729
6730         @Override
6731         public void setResponseCharacterEncoding(String encoding) {
6732             throw new UnsupportedOperationException(
6733                     sm.getString("noPluggabilityServletContext.notAllowed"));
6734         }
6735     }
6736 }
6737