/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.core;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Deque;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanNotificationInfo;
import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.naming.NamingException;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.FilterRegistration;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.Servlet;
import jakarta.servlet.ServletContainerInitializer;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletContextAttributeListener;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRegistration;
import jakarta.servlet.ServletRegistration.Dynamic;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletRequestAttributeListener;
import jakarta.servlet.ServletRequestEvent;
import jakarta.servlet.ServletRequestListener;
import jakarta.servlet.ServletSecurityElement;
import jakarta.servlet.SessionCookieConfig;
import jakarta.servlet.SessionTrackingMode;
import jakarta.servlet.descriptor.JspConfigDescriptor;
import jakarta.servlet.http.HttpSessionAttributeListener;
import jakarta.servlet.http.HttpSessionIdListener;
import jakarta.servlet.http.HttpSessionListener;
import org.apache.catalina.Authenticator;
import org.apache.catalina.Container;
import org.apache.catalina.ContainerListener;
import org.apache.catalina.Context;
import org.apache.catalina.CredentialHandler;
import org.apache.catalina.Globals;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.Loader;
import org.apache.catalina.Manager;
import org.apache.catalina.Pipeline;
import org.apache.catalina.Realm;
import org.apache.catalina.ThreadBindingListener;
import org.apache.catalina.Valve;
import org.apache.catalina.WebResource;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.Wrapper;
import org.apache.catalina.deploy.NamingResourcesImpl;
import org.apache.catalina.loader.WebappClassLoaderBase;
import org.apache.catalina.loader.WebappLoader;
import org.apache.catalina.session.StandardManager;
import org.apache.catalina.util.CharsetMapper;
import org.apache.catalina.util.ContextName;
import org.apache.catalina.util.ErrorPageSupport;
import org.apache.catalina.util.URLEncoder;
import org.apache.catalina.webresources.StandardRoot;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.naming.ContextBindings;
import org.apache.tomcat.InstanceManager;
import org.apache.tomcat.InstanceManagerBindings;
import org.apache.tomcat.JarScanner;
import org.apache.tomcat.util.ExceptionUtils;
import org.apache.tomcat.util.buf.StringUtils;
import org.apache.tomcat.util.compat.JreCompat;
import org.apache.tomcat.util.descriptor.XmlIdentifiers;
import org.apache.tomcat.util.descriptor.web.ApplicationParameter;
import org.apache.tomcat.util.descriptor.web.ErrorPage;
import org.apache.tomcat.util.descriptor.web.FilterDef;
import org.apache.tomcat.util.descriptor.web.FilterMap;
import org.apache.tomcat.util.descriptor.web.Injectable;
import org.apache.tomcat.util.descriptor.web.InjectionTarget;
import org.apache.tomcat.util.descriptor.web.LoginConfig;
import org.apache.tomcat.util.descriptor.web.MessageDestination;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.apache.tomcat.util.http.CookieProcessor;
import org.apache.tomcat.util.http.Rfc6265CookieProcessor;
import org.apache.tomcat.util.scan.StandardJarScanner;
import org.apache.tomcat.util.security.PrivilegedGetTccl;
import org.apache.tomcat.util.security.PrivilegedSetTccl;
import org.apache.tomcat.util.threads.ScheduledThreadPoolExecutor;
/**
* Standard implementation of the <b>Context</b> interface. Each child container must be a Wrapper implementation to
* process the requests directed to a particular servlet.
*
* @author Craig R. McClanahan
* @author Remy Maucherat
*/
public class StandardContext
extends ContainerBase
implements Context, NotificationEmit
ter {
private static final Log log = LogFactory.getLog(StandardContext.class);
// ----------------------------------------------------------- Constructors
/**
* Create a new StandardContext component with the default basic Valve.
*/
public StandardContext() {
super();
pipeline.setBasic(new StandardContextValve());
broadcaster = new NotificationBroadcasterSupport();
// Set defaults
if (!Globals.STRICT_SERVLET_COMPLIANCE) {
// Strict servlet compliance requires all extension mapped servlets
// to be checked against welcome files
resourceOnlyServlets.add("jsp");
}
}
// ----------------------------------------------------- Instance Variables
/**
* Allow multipart/form-data requests to be parsed even when the target servlet doesn't specify @MultipartConfig or
* have a <multipart-config> element.
*/
protected boolean allowCasualMultipartParsing = false;
/**
* Control whether remaining request data will be read (swallowed) even if the request violates a data size
* constraint.
*/
private boolean swallowAbortedUploads = true;
/**
* The alternate deployment descriptor name.
*/
private String altDDName = null;
/**
* Lifecycle provider.
*/
private InstanceManager instanceManager = null;
/**
* The antiResourceLocking flag for this Context.
*/
private boolean antiResourceLocking = false;
/**
* The list of unique application listener class names configured for this application, in the order they were
* encountered in the resulting merged web.xml file.
*/
private CopyOnWriteArrayList<String> applicationListeners = new CopyOnWriteArrayList<>();
/**
* The set of application listeners that are required to have limited access to ServletContext methods. See Servlet
* 3.1 section 4.4.
*/
private final Set<Object> noPluggabilityListeners = new HashSet<>();
/**
* The list of instantiated application event listener objects. Note that SCIs and other code may use the
* pluggability APIs to add listener instances directly to this list before the application starts.
*/
private List<Object> applicationEventListenersList = new CopyOnWriteArrayList<>();
/**
* The set of instantiated application lifecycle listener objects. Note that SCIs and other code may use the
* pluggability APIs to add listener instances directly to this list before the application starts.
*/
private Object applicationLifecycleListenersObjects[] = new Object[0];
/**
* The ordered set of ServletContainerInitializers for this web application.
*/
private Map<ServletContainerInitializer,Set<Class<?>>> initializers = new LinkedHashMap<>();
/**
* The set of application parameters defined for this application.
*/
private ApplicationParameter applicationParameters[] = new ApplicationParameter[0];
private final Object applicationParametersLock = new Object();
/**
* The broadcaster that sends j2ee notifications.
*/
private NotificationBroadcasterSupport broadcaster = null;
/**
* The Locale to character set mapper for this application.
*/
private CharsetMapper charsetMapper = null;
/**
* The Java class name of the CharsetMapper class to be created.
*/
private String charsetMapperClass = "org.apache.catalina.util.CharsetMapper";
/**
* The URL of the XML descriptor for this context.
*/
private URL configFile = null;
/**
* The "correctly configured" flag for this Context.
*/
private boolean configured = false;
/**
* The security constraints for this web application.
*/
private volatile SecurityConstraint constraints[] = new SecurityConstraint[0];
private final Object constraintsLock = new Object();
/**
* The ServletContext implementation associated with this Context.
*/
protected ApplicationContext context = null;
/**
* The wrapped version of the associated ServletContext that is presented to listeners that are required to have
* limited access to ServletContext methods. See Servlet 3.1 section 4.4.
*/
private NoPluggabilityServletContext noPluggabilityServletContext = null;
/**
* Should we attempt to use cookies for session id communication?
*/
private boolean cookies = true;
/**
* Should we allow the <code>ServletContext.getContext()</code> method to access the context of other web
* applications in this server?
*/
private boolean crossContext = false;
/**
* Encoded path.
*/
private String encodedPath = null;
/**
* Unencoded path for this web application.
*/
private String path = null;
/**
* The "follow standard delegation model" flag that will be used to configure our ClassLoader. Graal cannot actually
* load a class from the webapp classloader, so delegate by default.
*/
private boolean delegate = JreCompat.isGraalAvailable();
private boolean denyUncoveredHttpMethods;
/**
* The display name of this web application.
*/
private String displayName = null;
/**
* Override the default context xml location.
*/
private String defaultContextXml;
/**
* Override the default web xml location.
*/
private String defaultWebXml;
/**
* The distributable flag for this web application.
*/
private boolean distributable = false;
/**
* The document root for this web application.
*/
private String docBase = null;
private final ErrorPageSupport errorPageSupport = new ErrorPageSupport();
/**
* The set of filter configurations (and associated filter instances) we have initialized, keyed by filter name.
*/
private Map<String,ApplicationFilterConfig> filterConfigs = new HashMap<>(); // Guarded by filterDefs
/**
* The set of filter definitions for this application, keyed by filter name.
*/
private Map<String,FilterDef> filterDefs = new HashMap<>();
/**
* The set of filter mappings for this application, in the order they were defined in the deployment descriptor with
* additional mappings added via the {@link ServletContext} possibly both before and after those defined in the
* deployment descriptor.
*/
private final ContextFilterMaps filterMaps = new ContextFilterMaps();
/**
* Ignore annotations.
*/
private boolean ignoreAnnotations = false;
/**
* The Loader implementation with which this Container is associated.
*/
private Loader loader = null;
private final ReadWriteLock loaderLock = new ReentrantReadWriteLock();
/**
* The login configuration descriptor for this web application.
*/
private LoginConfig loginConfig = null;
/**
* The Manager implementation with which this Container is associated.
*/
protected Manager manager = null;
private final ReadWriteLock managerLock = new ReentrantReadWriteLock();
/**
* The naming context listener for this web application.
*/
private NamingContextListener namingContextListener = null;
/**
* The naming resources for this web application.
*/
private NamingResourcesImpl namingResources = null;
/**
* The message destinations for this web application.
*/
private HashMap<String,MessageDestination> messageDestinations = new HashMap<>();
/**
* The MIME mappings for this web application, keyed by extension.
*/
private Map<String,String> mimeMappings = new HashMap<>();
/**
* The context initialization parameters for this web application, keyed by name.
*/
private final Map<String,String> parameters = new ConcurrentHashMap<>();
/**
* The request processing pause flag (while reloading occurs)
*/
private volatile boolean paused = false;
/**
* The public identifier of the DTD for the web application deployment descriptor version we are currently parsing.
* This is used to support relaxed validation rules when processing version 2.2 web.xml files.
*/
private String publicId = null;
/**
* The reloadable flag for this web application.
*/
private boolean reloadable = false;
/**
* Unpack WAR property.
*/
private boolean unpackWAR = true;
/**
* Context level override for default {@link StandardHost#isCopyXML()}.
*/
private boolean copyXML = false;
/**
* The default context override flag for this web application.
*/
private boolean override = false;
/**
* The original document root for this web application.
*/
private String originalDocBase = null;
/**
* The privileged flag for this web application.
*/
private boolean privileged = false;
/**
* Should the next call to <code>addWelcomeFile()</code> cause replacement of any existing welcome files? This will
* be set before processing the web application's deployment descriptor, so that application specified choices
* <strong>replace</strong>, rather than append to, those defined in the global descriptor.
*/
private boolean replaceWelcomeFiles = false;
/**
* The security role mappings for this application, keyed by role name (as used within the application).
*/
private Map<String,String> roleMappings = new HashMap<>();
/**
* The security roles for this application, keyed by role name.
*/
private String securityRoles[] = new String[0];
private final Object securityRolesLock = new Object();
/**
* The servlet mappings for this web application, keyed by matching pattern.
*/
private Map<String,String> servletMappings = new HashMap<>();
private final Object servletMappingsLock = new Object();
/**
* The session timeout (in minutes) for this web application.
*/
private int sessionTimeout = 30;
/**
* The notification sequence number.
*/
private AtomicLong sequenceNumber = new AtomicLong(0);
/**
* Set flag to true to cause the system.out and system.err to be redirected to the logger when executing a servlet.
*/
private boolean swallowOutput = false;
/**
* Amount of ms that the container will wait for servlets to unload.
*/
private long unloadDelay = 2000;
/**
* The watched resources for this application.
*/
private String watchedResources[] = new String[0];
private final Object watchedResourcesLock = new Object();
/**
* The welcome files for this application.
*/
private String welcomeFiles[] = new String[0];
private final Object welcomeFilesLock = new Object();
/**
* The set of classnames of LifecycleListeners that will be added to each newly created Wrapper by
* <code>createWrapper()</code>.
*/
private String wrapperLifecycles[] = new String[0];
private final Object wrapperLifecyclesLock = new Object();
/**
* The set of classnames of ContainerListeners that will be added to each newly created Wrapper by
* <code>createWrapper()</code>.
*/
private String wrapperListeners[] = new String[0];
private final Object wrapperListenersLock = new Object();
/**
* The pathname to the work directory for this context (relative to the server's home if not absolute).
*/
private String workDir = null;
/**
* Java class name of the Wrapper class implementation we use.
*/
private String wrapperClassName = StandardWrapper.class.getName();
private Class<?> wrapperClass = null;
/**
* JNDI use flag.
*/
private boolean useNaming = true;
/**
* Name of the associated naming context.
*/
private String namingContextName = null;
private WebResourceRoot resources;
private final ReadWriteLock resourcesLock = new ReentrantReadWriteLock();
private long startupTime;
private long startTime;
private long tldScanTime;
/**
* Name of the engine. If null, the domain is used.
*/
private String j2EEApplication = "none";
private String j2EEServer = "none";
/**
* Attribute value used to turn on/off XML validation for web.xml and web-fragment.xml files.
*/
private boolean webXmlValidation = Globals.STRICT_SERVLET_COMPLIANCE;
/**
* Attribute value used to turn on/off XML namespace validation
*/
private boolean webXmlNamespaceAware = Globals.STRICT_SERVLET_COMPLIANCE;
/**
* Attribute used to turn on/off the use of external entities.
*/
private boolean xmlBlockExternal = true;
/**
* Attribute value used to turn on/off XML validation
*/
private boolean tldValidation = Globals.STRICT_SERVLET_COMPLIANCE;
/**
* The name to use for session cookies. <code>null</code> indicates that the name is controlled by the application.
*/
private String sessionCookieName;
/**
* The flag that indicates that session cookies should use HttpOnly
*/
private boolean useHttpOnly = true;
/**
* The domain to use for session cookies. <code>null</code> indicates that the domain is controlled by the
* application.
*/
private String sessionCookieDomain;
/**
* The path to use for session cookies. <code>null</code> indicates that the path is controlled by the application.
*/
private String sessionCookiePath;
/**
* Is a / added to the end of the session cookie path to ensure browsers, particularly IE, don't send a session
* cookie for context /foo with requests intended for context /foobar.
*/
private boolean sessionCookiePathUsesTrailingSlash = false;
/**
* The Jar scanner to use to search for Jars that might contain configuration information such as TLDs or
* web-fragment.xml files.
*/
private JarScanner jarScanner = null;
/**
* Enables the RMI Target memory leak detection to be controlled. This is necessary since the detection can only
* work if some of the modularity checks are disabled.
*/
private boolean clearReferencesRmiTargets = true;
/**
* Should Tomcat attempt to terminate threads that have been started by the web application? Stopping threads is
* performed via the deprecated (for good reason) <code>Thread.stop()</code> method and is likely to result in
* instability. As such, enabling this should be viewed as an option of last resort in a development environment and
* is not recommended in a production environment. If not specified, the default value of <code>false</code> will be
* used.
*/
private boolean clearReferencesStopThreads = false;
/**
* Should Tomcat attempt to terminate any {@link java.util.TimerThread}s that have been started by the web
* application? If not specified, the default value of <code>false</code> will be used.
*/
private boolean clearReferencesStopTimerThreads = false;
/**
* If an HttpClient keep-alive timer thread has been started by this web application and is still running, should
* Tomcat change the context class loader from the current {@link ClassLoader} to {@link ClassLoader#getParent()} to
* prevent a memory leak? Note that the keep-alive timer thread will stop on its own once the keep-alives all expire
* however, on a busy system that might not happen for some time.
*/
private boolean clearReferencesHttpClientKeepAliveThread = true;
/**
* Should Tomcat renew the threads of the thread pool when the application is stopped to avoid memory leaks because
* of uncleaned ThreadLocal variables. This also requires that the threadRenewalDelay property of the
* StandardThreadExecutor or ThreadPoolExecutor be set to a positive value.
*/
private boolean renewThreadsWhenStoppingContext = true;
/**
* Should Tomcat attempt to clear references to classes loaded by the web application class loader from the
* ObjectStreamClass caches?
*/
private boolean clearReferencesObjectStreamClassCaches = true;
/**
* Should Tomcat attempt to clear references to classes loaded by this class loader from ThreadLocals?
*/
private boolean clearReferencesThreadLocals = true;
/**
* Should Tomcat skip the memory leak checks when the web application is stopped as part of the process of shutting
* down the JVM?
*/
private boolean skipMemoryLeakChecksOnJvmShutdown = false;
/**
* Should the effective web.xml be logged when the context starts?
*/
private boolean logEffectiveWebXml = false;
private int effectiveMajorVersion = 3;
private int effectiveMinorVersion = 0;
private JspConfigDescriptor jspConfigDescriptor = null;
private Set<String> resourceOnlyServlets = new HashSet<>();
private String webappVersion = "";
private boolean addWebinfClassesResources = false;
private boolean fireRequestListenersOnForwards = false;
/**
* Servlets created via {@link ApplicationContext#createServlet(Class)} for tracking purposes.
*/
private Set<Servlet> createdServlets = new HashSet<>();
private boolean preemptiveAuthentication = false;
private boolean sendRedirectBody = false;
private boolean jndiExceptionOnFailedWrite = true;
private Map<String,String> postConstructMethods = new HashMap<>();
private Map<String,String> preDestroyMethods = new HashMap<>();
private String containerSciFilter;
private Boolean failCtxIfServletStartFails;
protected static final ThreadBindingListener DEFAULT_NAMING_LISTENER = (new ThreadBindingListener() {
@Override
public void bind() {
}
@Override
public void unbind() {
}
});
protected ThreadBindingListener threadBindingListener = DEFAULT_NAMING_LISTENER;
private final Object namingToken = new Object();
private CookieProcessor cookieProcessor;
private boolean validateClientProvidedNewSessionId = true;
private boolean mapperContextRootRedirectEnabled = true;
private boolean mapperDirectoryRedirectEnabled = false;
private boolean useRelativeRedirects = !Globals.STRICT_SERVLET_COMPLIANCE;
private boolean dispatchersUseEncodedPaths = true;
private String requestEncoding = null;
private String responseEncoding = null;
private boolean allowMultipleLeadingForwardSlashInPath = false;
private final AtomicLong inProgressAsyncCount = new AtomicLong(0);
private boolean createUploadTargets = false;
private boolean alwaysAccessSession = Globals.STRICT_SERVLET_COMPLIANCE;
private boolean contextGetResourceRequiresSlash = Globals.STRICT_SERVLET_COMPLIANCE;
private boolean dispatcherWrapsSameObject = Globals.STRICT_SERVLET_COMPLIANCE;
private boolean parallelAnnotationScanning = false;
private boolean useBloomFilterForArchives = false;
// ----------------------------------------------------- Context Properties
@Override
public void setCreateUploadTargets(boolean createUploadTargets) {
this.createUploadTargets = createUploadTargets;
}
@Override
public boolean getCreateUploadTargets() {
return createUploadTargets;
}
@Override
public void incrementInProgressAsyncCount() {
inProgressAsyncCount.incrementAndGet();
}
@Override
public void decrementInProgressAsyncCount() {
inProgressAsyncCount.decrementAndGet();
}
public long getInProgressAsyncCount() {
return inProgressAsyncCount.get();
}
@Override
public void setAllowMultipleLeadingForwardSlashInPath(boolean allowMultipleLeadingForwardSlashInPath) {
this.allowMultipleLeadingForwardSlashInPath = allowMultipleLeadingForwardSlashInPath;
}
@Override
public boolean getAllowMultipleLeadingForwardSlashInPath() {
return allowMultipleLeadingForwardSlashInPath;
}
@Override
public boolean getAlwaysAccessSession() {
return alwaysAccessSession;
}
@Override
public void setAlwaysAccessSession(boolean alwaysAccessSession) {
this.alwaysAccessSession = alwaysAccessSession;
}
@Override
public boolean getContextGetResourceRequiresSlash() {
return contextGetResourceRequiresSlash;
}
@Override
public void setContextGetResourceRequiresSlash(boolean contextGetResourceRequiresSlash) {
this.contextGetResourceRequiresSlash = contextGetResourceRequiresSlash;
}
@Override
public boolean getDispatcherWrapsSameObject() {
return dispatcherWrapsSameObject;
}
@Override
public void setDispatcherWrapsSameObject(boolean dispatcherWrapsSameObject) {
this.dispatcherWrapsSameObject = dispatcherWrapsSameObject;
}
@Override
public String getRequestCharacterEncoding() {
return requestEncoding;
}
@Override
public void setRequestCharacterEncoding(String requestEncoding) {
this.requestEncoding = requestEncoding;
}
@Override
public String getResponseCharacterEncoding() {
return responseEncoding;
}
@Override
public void setResponseCharacterEncoding(String responseEncoding) {
/*
* This ensures that the context response encoding is represented by a unique String object. This enables the
* Default Servlet to differentiate between a Response using this default encoding and one that has been
* explicitly configured.
*/
if (responseEncoding == null) {
this.responseEncoding = null;
} else {
this.responseEncoding = new String(responseEncoding);
}
}
@Override
public void setDispatchersUseEncodedPaths(boolean dispatchersUseEncodedPaths) {
this.dispatchersUseEncodedPaths = dispatchersUseEncodedPaths;
}
/**
* {@inheritDoc}
* <p>
* The default value for this implementation is {@code true}.
*/
@Override
public boolean getDispatchersUseEncodedPaths() {
return dispatchersUseEncodedPaths;
}
@Override
public void setUseRelativeRedirects(boolean useRelativeRedirects) {
this.useRelativeRedirects = useRelativeRedirects;
}
/**
* {@inheritDoc}
* <p>
* The default value for this implementation is {@code true}.
*/
@Override
public boolean getUseRelativeRedirects() {
return useRelativeRedirects;
}
@Override
public void setMapperContextRootRedirectEnabled(boolean mapperContextRootRedirectEnabled) {
this.mapperContextRootRedirectEnabled = mapperContextRootRedirectEnabled;
}
/**
* {@inheritDoc}
* <p>
* The default value for this implementation is {@code false}.
*/
@Override
public boolean getMapperContextRootRedirectEnabled() {
return mapperContextRootRedirectEnabled;
}
@Override
public void setMapperDirectoryRedirectEnabled(boolean mapperDirectoryRedirectEnabled) {
this.mapperDirectoryRedirectEnabled = mapperDirectoryRedirectEnabled;
}
/**
* {@inheritDoc}
* <p>
* The default value for this implementation is {@code false}.
*/
@Override
public boolean getMapperDirectoryRedirectEnabled() {
return mapperDirectoryRedirectEnabled;
}
@Override
public void setValidateClientProvidedNewSessionId(boolean validateClientProvidedNewSessionId) {
this.validateClientProvidedNewSessionId = validateClientProvidedNewSessionId;
}
/**
* {@inheritDoc}
* <p>
* The default value for this implementation is {@code true}.
*/
@Override
public boolean getValidateClientProvidedNewSessionId() {
return validateClientProvidedNewSessionId;
}
@Override
public void setCookieProcessor(CookieProcessor cookieProcessor) {
if (cookieProcessor == null) {
throw new IllegalArgumentException(sm.getString("standardContext.cookieProcessor.null"));
}
this.cookieProcessor = cookieProcessor;
}
@Override
public CookieProcessor getCookieProcessor() {
return cookieProcessor;
}
@Override
public Object getNamingToken() {
return namingToken;
}
@Override
public void setContainerSciFilter(String containerSciFilter) {
this.containerSciFilter = containerSciFilter;
}
@Override
public String getContainerSciFilter() {
return containerSciFilter;
}
@Override
public boolean getSendRedirectBody() {
return sendRedirectBody;
}
@Override
public void setSendRedirectBody(boolean sendRedirectBody) {
this.sendRedirectBody = sendRedirectBody;
}
@Override
public boolean getPreemptiveAuthentication() {
return preemptiveAuthentication;
}
@Override
public void setPreemptiveAuthentication(boolean preemptiveAuthentication) {
this.preemptiveAuthentication = preemptiveAuthentication;
}
@Override
public void setFireRequestListenersOnForwards(boolean enable) {
fireRequestListenersOnForwards = enable;
}
@Override
public boolean getFireRequestListenersOnForwards() {
return fireRequestListenersOnForwards;
}
@Override
public void setAddWebinfClassesResources(boolean addWebinfClassesResources) {
this.addWebinfClassesResources = addWebinfClassesResources;
}
@Override
public boolean getAddWebinfClassesResources() {
return addWebinfClassesResources;
}
@Override
public void setWebappVersion(String webappVersion) {
if (null == webappVersion) {
this.webappVersion = "";
} else {
this.webappVersion = webappVersion;
}
}
@Override
public String getWebappVersion() {
return webappVersion;
}
@Override
public String getBaseName() {
return new ContextName(path, webappVersion).getBaseName();
}
@Override
public String getResourceOnlyServlets() {
return StringUtils.join(resourceOnlyServlets);
}
@Override
public void setResourceOnlyServlets(String resourceOnlyServlets) {
this.resourceOnlyServlets.clear();
if (resourceOnlyServlets == null) {
return;
}
for (String servletName : resourceOnlyServlets.split(",")) {
servletName = servletName.trim();
if (servletName.length() > 0) {
this.resourceOnlyServlets.add(servletName);
}
}
}
@Override
public boolean isResourceOnlyServlet(String servletName) {
return resourceOnlyServlets.contains(servletName);
}
@Override
public int getEffectiveMajorVersion() {
return effectiveMajorVersion;
}
@Override
public void setEffectiveMajorVersion(int effectiveMajorVersion) {
this.effectiveMajorVersion = effectiveMajorVersion;
}
@Override
public int getEffectiveMinorVersion() {
return effectiveMinorVersion;
}
@Override
public void setEffectiveMinorVersion(int effectiveMinorVersion) {
this.effectiveMinorVersion = effectiveMinorVersion;
}
@Override
public void setLogEffectiveWebXml(boolean logEffectiveWebXml) {
this.logEffectiveWebXml = logEffectiveWebXml;
}
@Override
public boolean getLogEffectiveWebXml() {
return logEffectiveWebXml;
}
@Override
public Authenticator getAuthenticator() {
Pipeline pipeline = getPipeline();
if (pipeline != null) {
Valve basic = pipeline.getBasic();
if (basic instanceof Authenticator) {
return (Authenticator) basic;
}
for (Valve valve : pipeline.getValves()) {
if (valve instanceof Authenticator) {
return (Authenticator) valve;
}
}
}
return null;
}
@Override
public JarScanner getJarScanner() {
if (jarScanner == null) {
jarScanner = new StandardJarScanner();
}
return jarScanner;
}
@Override
public void setJarScanner(JarScanner jarScanner) {
this.jarScanner = jarScanner;
}
@Override
public InstanceManager getInstanceManager() {
return instanceManager;
}
@Override
public void setInstanceManager(InstanceManager instanceManager) {
this.instanceManager = instanceManager;
}
@Override
public String getEncodedPath() {
return encodedPath;
}
/**
* Set to <code>true</code> to allow requests mapped to servlets that do not explicitly declare @MultipartConfig or
* have <multipart-config> specified in web.xml to parse multipart/form-data requests.
*
* @param allowCasualMultipartParsing <code>true</code> to allow such casual parsing, <code>false</code> otherwise.
*/
@Override
public void setAllowCasualMultipartParsing(boolean allowCasualMultipartParsing) {
this.allowCasualMultipartParsing = allowCasualMultipartParsing;
}
/**
* Returns <code>true</code> if requests mapped to servlets without "multipart config" to parse multipart/form-data
* requests anyway.
*
* @return <code>true</code> if requests mapped to servlets without "multipart config" to parse multipart/form-data
* requests, <code>false</code> otherwise.
*/
@Override
public boolean getAllowCasualMultipartParsing() {
return this.allowCasualMultipartParsing;
}
/**
* Set to <code>false</code> to disable request data swallowing after an upload was aborted due to size constraints.
*
* @param swallowAbortedUploads <code>false</code> to disable swallowing, <code>true</code> otherwise (default).
*/
@Override
public void setSwallowAbortedUploads(boolean swallowAbortedUploads) {
this.swallowAbortedUploads = swallowAbortedUploads;
}
/**
* Returns <code>true</code> if remaining request data will be read (swallowed) even the request violates a data
* size constraint.
*
* @return <code>true</code> if data will be swallowed (default), <code>false</code> otherwise.
*/
@Override
public boolean getSwallowAbortedUploads() {
return this.swallowAbortedUploads;
}
/**
* Add a ServletContainerInitializer instance to this web application.
*
* @param sci The instance to add
* @param classes The classes in which the initializer expressed an interest
*/
@Override
public void addServletContainerInitializer(ServletContainerInitializer sci, Set<Class<?>> classes) {
initializers.put(sci, classes);
}
/**
* Return the "follow standard delegation model" flag used to configure our ClassLoader.
*
* @return <code>true</code> if classloading delegates to the parent classloader first
*/
public boolean getDelegate() {
return this.delegate;
}
/**
* Set the "follow standard delegation model" flag used to configure our ClassLoader.
*
* @param delegate The new flag
*/
public void setDelegate(boolean delegate) {
boolean oldDelegate = this.delegate;
this.delegate = delegate;
support.firePropertyChange("delegate", oldDelegate, this.delegate);
}
/**
* @return true if the internal naming support is used.
*/
public boolean isUseNaming() {
return useNaming;
}
/**
* Enables or disables naming.
*
* @param useNaming <code>true</code> to enable the naming environment
*/
public void setUseNaming(boolean useNaming) {
this.useNaming = useNaming;
}
@Override
public Object[] getApplicationEventListeners() {
return applicationEventListenersList.toArray();
}
/**
* {@inheritDoc} Note that this implementation is not thread safe. If two threads call this method concurrently, the
* result may be either set of listeners or a the union of both.
*/
@Override
public void setApplicationEventListeners(Object listeners[]) {
applicationEventListenersList.clear();
if (listeners != null && listeners.length > 0) {
applicationEventListenersList.addAll(Arrays.asList(listeners));
}
}
/**
* Add a listener to the end of the list of initialized application event listeners.
*
* @param listener The listener to add
*/
public void addApplicationEventListener(Object listener) {
applicationEventListenersList.add(listener);
}
@Override
public Object[] getApplicationLifecycleListeners() {
return applicationLifecycleListenersObjects;
}
/**
* Store the set of initialized application lifecycle listener objects, in the order they were specified in the web
* application deployment descriptor, for this application.
*
* @param listeners The set of instantiated listener objects.
*/
@Override
public void setApplicationLifecycleListeners(Object listeners[]) {
applicationLifecycleListenersObjects = listeners;
}
/**
* Add a listener to the end of the list of initialized application lifecycle listeners.
*
* @param listener The listener to add
*/
public void addApplicationLifecycleListener(Object listener) {
int len = applicationLifecycleListenersObjects.length;
Object[] newListeners = Arrays.copyOf(applicationLifecycleListenersObjects, len + 1);
newListeners[len] = listener;
applicationLifecycleListenersObjects = newListeners;
}
/**
* @return the antiResourceLocking flag for this Context.
*/
public boolean getAntiResourceLocking() {
return this.antiResourceLocking;
}
/**
* Set the antiResourceLocking feature for this Context.
*
* @param antiResourceLocking The new flag value
*/
public void setAntiResourceLocking(boolean antiResourceLocking) {
boolean oldAntiResourceLocking = this.antiResourceLocking;
this.antiResourceLocking = antiResourceLocking;
support.firePropertyChange("antiResourceLocking", oldAntiResourceLocking, this.antiResourceLocking);
}
@Override
@Deprecated
public boolean getUseBloomFilterForArchives() {
return this.useBloomFilterForArchives;
}
@Override
@Deprecated
public void setUseBloomFilterForArchives(boolean useBloomFilterForArchives) {
boolean oldUseBloomFilterForArchives = this.useBloomFilterForArchives;
this.useBloomFilterForArchives = useBloomFilterForArchives;
support.firePropertyChange("useBloomFilterForArchives", oldUseBloomFilterForArchives,
this.useBloomFilterForArchives);
}
@Override
public void setParallelAnnotationScanning(boolean parallelAnnotationScanning) {
boolean oldParallelAnnotationScanning = this.parallelAnnotationScanning;
this.parallelAnnotationScanning = parallelAnnotationScanning;
support.firePropertyChange("parallelAnnotationScanning", oldParallelAnnotationScanning,
this.parallelAnnotationScanning);
}
@Override
public boolean getParallelAnnotationScanning() {
return this.parallelAnnotationScanning;
}
/**
* @return the Locale to character set mapper for this Context.
*/
public CharsetMapper getCharsetMapper() {
// Create a mapper the first time it is requested
if (this.charsetMapper == null) {
try {
Class<?> clazz = Class.forName(charsetMapperClass);
this.charsetMapper = (CharsetMapper) clazz.getConstructor().newInstance();
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
this.charsetMapper = new CharsetMapper();
}
}
return this.charsetMapper;
}
/**
* Set the Locale to character set mapper for this Context.
*
* @param mapper The new mapper
*/
public void setCharsetMapper(CharsetMapper mapper) {
CharsetMapper oldCharsetMapper = this.charsetMapper;
this.charsetMapper = mapper;
if (mapper != null) {
this.charsetMapperClass = mapper.getClass().getName();
}
support.firePropertyChange("charsetMapper", oldCharsetMapper, this.charsetMapper);
}
@Override
public String getCharset(Locale locale) {
return getCharsetMapper().getCharset(locale);
}
@Override
public URL getConfigFile() {
return this.configFile;
}
@Override
public void setConfigFile(URL configFile) {
this.configFile = configFile;
}
@Override
public boolean getConfigured() {
return this.configured;
}
/**
* Set the "correctly configured" flag for this Context. This can be set to false by startup listeners that detect a
* fatal configuration error to avoid the application from being made available.
*
* @param configured The new correctly configured flag
*/
@Override
public void setConfigured(boolean configured) {
boolean oldConfigured = this.configured;
this.configured = configured;
support.firePropertyChange("configured", oldConfigured, this.configured);
}
@Override
public boolean getCookies() {
return this.cookies;
}
/**
* Set the "use cookies for session ids" flag.
*
* @param cookies The new flag
*/
@Override
public void setCookies(boolean cookies) {
boolean oldCookies = this.cookies;
this.cookies = cookies;
support.firePropertyChange("cookies", oldCookies, this.cookies);
}
/**
* Gets the name to use for session cookies. Overrides any setting that may be specified by the application.
*
* @return The value of the default session cookie name or null if not specified
*/
@Override
public String getSessionCookieName() {
return sessionCookieName;
}
/**
* Sets the name to use for session cookies. Overrides any setting that may be specified by the application.
*
* @param sessionCookieName The name to use
*/
@Override
public void setSessionCookieName(String sessionCookieName) {
String oldSessionCookieName = this.sessionCookieName;
this.sessionCookieName = sessionCookieName;
support.firePropertyChange("sessionCookieName", oldSessionCookieName, sessionCookieName);
}
/**
* Gets the value of the use HttpOnly cookies for session cookies flag.
*
* @return <code>true</code> if the HttpOnly flag should be set on session cookies
*/
@Override
public boolean getUseHttpOnly() {
return useHttpOnly;
}
/**
* Sets the use HttpOnly cookies for session cookies flag.
*
* @param useHttpOnly Set to <code>true</code> to use HttpOnly cookies for session cookies
*/
@Override
public void setUseHttpOnly(boolean useHttpOnly) {
boolean oldUseHttpOnly = this.useHttpOnly;
this.useHttpOnly = useHttpOnly;
support.firePropertyChange("useHttpOnly", oldUseHttpOnly, this.useHttpOnly);
}
/**
* Gets the domain to use for session cookies. Overrides any setting that may be specified by the application.
*
* @return The value of the default session cookie domain or null if not specified
*/
@Override
public String getSessionCookieDomain() {
return sessionCookieDomain;
}
/**
* Sets the domain to use for session cookies. Overrides any setting that may be specified by the application.
*
* @param sessionCookieDomain The domain to use
*/
@Override
public void setSessionCookieDomain(String sessionCookieDomain) {
String oldSessionCookieDomain = this.sessionCookieDomain;
this.sessionCookieDomain = sessionCookieDomain;
support.firePropertyChange("sessionCookieDomain", oldSessionCookieDomain, sessionCookieDomain);
}
/**
* Gets the path to use for session cookies. Overrides any setting that may be specified by the application.
*
* @return The value of the default session cookie path or null if not specified
*/
@Override
public String getSessionCookiePath() {
return sessionCookiePath;
}
/**
* Sets the path to use for session cookies. Overrides any setting that may be specified by the application.
*
* @param sessionCookiePath The path to use
*/
@Override
public void setSessionCookiePath(String sessionCookiePath) {
String oldSessionCookiePath = this.sessionCookiePath;
this.sessionCookiePath = sessionCookiePath;
support.firePropertyChange("sessionCookiePath", oldSessionCookiePath, sessionCookiePath);
}
@Override
public boolean getSessionCookiePathUsesTrailingSlash() {
return sessionCookiePathUsesTrailingSlash;
}
@Override
public void setSessionCookiePathUsesTrailingSlash(boolean sessionCookiePathUsesTrailingSlash) {
this.sessionCookiePathUsesTrailingSlash = sessionCookiePathUsesTrailingSlash;
}
@Override
public boolean getCrossContext() {
return this.crossContext;
}
/**
* Set the "allow crossing servlet contexts" flag.
*
* @param crossContext The new cross contexts flag
*/
@Override
public void setCrossContext(boolean crossContext) {
boolean oldCrossContext = this.crossContext;
this.crossContext = crossContext;
support.firePropertyChange("crossContext", oldCrossContext, this.crossContext);
}
public String getDefaultContextXml() {
return defaultContextXml;
}
/**
* Set the location of the default context xml that will be used. If not absolute, it'll be made relative to the
* engine's base dir ( which defaults to catalina.base system property ).
*
* @param defaultContextXml The default web xml
*/
public void setDefaultContextXml(String defaultContextXml) {
this.defaultContextXml = defaultContextXml;
}
public String getDefaultWebXml() {
return defaultWebXml;
}
/**
* Set the location of the default web xml that will be used. If not absolute, it'll be made relative to the
* engine's base dir ( which defaults to catalina.base system property ).
*
* @param defaultWebXml The default web xml
*/
public void setDefaultWebXml(String defaultWebXml) {
this.defaultWebXml = defaultWebXml;
}
/**
* Gets the time (in milliseconds) it took to start this context.
*
* @return Time (in milliseconds) it took to start this context.
*/
public long getStartupTime() {
return startupTime;
}
public void setStartupTime(long startupTime) {
this.startupTime = startupTime;
}
public long getTldScanTime() {
return tldScanTime;
}
public void setTldScanTime(long tldScanTime) {
this.tldScanTime = tldScanTime;
}
@Override
public boolean getDenyUncoveredHttpMethods() {
return denyUncoveredHttpMethods;
}
@Override
public void setDenyUncoveredHttpMethods(boolean denyUncoveredHttpMethods) {
this.denyUncoveredHttpMethods = denyUncoveredHttpMethods;
}
/**
* @return the display name of this web application.
*/
@Override
public String getDisplayName() {
return this.displayName;
}
/**
* @return the alternate Deployment Descriptor name.
*/
@Override
public String getAltDDName() {
return altDDName;
}
/**
* Set an alternate Deployment Descriptor name.
*
* @param altDDName The new name
*/
@Override
public void setAltDDName(String altDDName) {
this.altDDName = altDDName;
if (context != null) {
context.setAttribute(Globals.ALT_DD_ATTR, altDDName);
}
}
/**
* Set the display name of this web application.
*
* @param displayName The new display name
*/
@Override
public void setDisplayName(String displayName) {
String oldDisplayName = this.displayName;
this.displayName = displayName;
support.firePropertyChange("displayName", oldDisplayName, this.displayName);
}
/**
* @return the distributable flag for this web application.
*/
@Override
public boolean getDistributable() {
return this.distributable;
}
/**
* Set the distributable flag for this web application.
*
* @param distributable The new distributable flag
*/
@Override
public void setDistributable(boolean distributable) {
boolean oldDistributable = this.distributable;
this.distributable = distributable;
support.firePropertyChange("distributable", oldDistributable, this.distributable);
}
@Override
public String getDocBase() {
return this.docBase;
}
@Override
public void setDocBase(String docBase) {
this.docBase = docBase;
}
public String getJ2EEApplication() {
return j2EEApplication;
}
public void setJ2EEApplication(String j2EEApplication) {
this.j2EEApplication = j2EEApplication;
}
public String getJ2EEServer() {
return j2EEServer;
}
public void setJ2EEServer(String j2EEServer) {
this.j2EEServer = j2EEServer;
}
@Override
public Loader getLoader() {
Lock readLock = loaderLock.readLock();
readLock.lock();
try {
return loader;
} finally {
readLock.unlock();
}
}
@Override
public void setLoader(Loader loader) {
Lock writeLock = loaderLock.writeLock();
writeLock.lock();
Loader oldLoader = null;
try {
// Change components if necessary
oldLoader = this.loader;
if (oldLoader == loader) {
return;
}
this.loader = loader;
// Stop the old component if necessary
if (getState().isAvailable() && (oldLoader != null) && (oldLoader instanceof Lifecycle)) {
try {
((Lifecycle) oldLoader).stop();
} catch (LifecycleException e) {
log.error(sm.getString("standardContext.setLoader.stop"), e);
}
}
// Start the new component if necessary
if (loader != null) {
loader.setContext(this);
}
if (getState().isAvailable() && (loader != null) && (loader instanceof Lifecycle)) {
try {
((Lifecycle) loader).start();
} catch (LifecycleException e) {
log.error(sm.getString("standardContext.setLoader.start"), e);
}
}
} finally {
writeLock.unlock();
}
// Report this property change to interested listeners
support.firePropertyChange("loader", oldLoader, loader);
}
@Override
public Manager getManager() {
Lock readLock = managerLock.readLock();
readLock.lock();
try {
return manager;
} finally {
readLock.unlock();
}
}
@Override
public void setManager(Manager manager) {
Lock writeLock = managerLock.writeLock();
writeLock.lock();
Manager oldManager = null;
try {
// Change components if necessary
oldManager = this.manager;
if (oldManager == manager) {
return;
}
this.manager = manager;
// Stop the old component if necessary
if (oldManager instanceof Lifecycle) {
try {
((Lifecycle) oldManager).stop();
((Lifecycle) oldManager).destroy();
} catch (LifecycleException e) {
log.error(sm.getString("standardContext.setManager.stop"), e);
}
}
// Start the new component if necessary
if (manager != null) {
manager.setContext(this);
}
if (getState().isAvailable() && manager instanceof Lifecycle) {
try {
((Lifecycle) manager).start();
} catch (LifecycleException e) {
log.error(sm.getString("standardContext.setManager.start"), e);
}
}
} finally {
writeLock.unlock();
}
// Report this property change to interested listeners
support.firePropertyChange("manager", oldManager, manager);
}
/**
* @return the boolean on the annotations parsing.
*/
@Override
public boolean getIgnoreAnnotations() {
return this.ignoreAnnotations;
}
/**
* Set the boolean on the annotations parsing for this web application.
*
* @param ignoreAnnotations The boolean on the annotations parsing
*/
@Override
public void setIgnoreAnnotations(boolean ignoreAnnotations) {
boolean oldIgnoreAnnotations = this.ignoreAnnotations;
this.ignoreAnnotations = ignoreAnnotations;
support.firePropertyChange("ignoreAnnotations", oldIgnoreAnnotations, this.ignoreAnnotations);
}
/**
* @return the login configuration descriptor for this web application.
*/
@Override
public LoginConfig getLoginConfig() {
return this.loginConfig;
}
/**
* Set the login configuration descriptor for this web application.
*
* @param config The new login configuration
*/
@Override
public void setLoginConfig(LoginConfig config) {
// Validate the incoming property value
if (config == null) {
throw new IllegalArgumentException(sm.getString("standardContext.loginConfig.required"));
}
String loginPage = config.getLoginPage();
if ((loginPage != null) && !loginPage.startsWith("/")) {
if (isServlet22()) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("standardContext.loginConfig.loginWarning", loginPage));
}
config.setLoginPage("/" + loginPage);
} else {
throw new IllegalArgumentException(sm.getString("standardContext.loginConfig.loginPage", loginPage));
}
}
String errorPage = config.getErrorPage();
if ((errorPage != null) && !errorPage.startsWith("/")) {
if (isServlet22()) {
if (log.isDebugEnabled()) {
log.debug(sm.getString("standardContext.loginConfig.errorWarning", errorPage));
}
config.setErrorPage("/" + errorPage);
} else {
throw new IllegalArgumentException(sm.getString("standardContext.loginConfig.errorPage", errorPage));
}
}
// Process the property setting change
LoginConfig oldLoginConfig = this.loginConfig;
this.loginConfig = config;
support.firePropertyChange("loginConfig", oldLoginConfig, this.loginConfig);
}
/**
* @return the naming resources associated with this web application.
*/
@Override
public NamingResourcesImpl getNamingResources() {
if (namingResources == null) {
setNamingResources(new NamingResourcesImpl());
}
return namingResources;
}
/**
* Set the naming resources for this web application.
*
* @param namingResources The new naming resources
*/
@Override
public void setNamingResources(NamingResourcesImpl namingResources) {
// Process the property setting change
NamingResourcesImpl oldNamingResources = this.namingResources;
this.namingResources = namingResources;
if (namingResources != null) {
namingResources.setContainer(this);
}
support.firePropertyChange("namingResources", oldNamingResources, this.namingResources);
if (getState() == LifecycleState.NEW || getState() == LifecycleState.INITIALIZING ||
getState() == LifecycleState.INITIALIZED) {
// NEW will occur if Context is defined in server.xml
// At this point getObjectKeyPropertiesNameOnly() will trigger an
// NPE.
// INITIALIZED will occur if the Context is defined in a context.xml
// file
// If started now, a second start will be attempted when the context
// starts
// In both cases, return and let context init the namingResources
// when it starts
return;
}
if (oldNamingResources != null) {
try {
oldNamingResources.stop();
oldNamingResources.destroy();
} catch (LifecycleException e) {
log.error(sm.getString("standardContext.namingResource.destroy.fail"), e);
}
}
if (namingResources != null) {
try {
namingResources.init();
namingResources.start();
} catch (LifecycleException e) {
log.error(sm.getString("standardContext.namingResource.init.fail"), e);
}
}
}
/**
* @return the context path for this Context.
*/
@Override
public String getPath() {
return path;
}
/**
* Set the context path for this Context.
*
* @param path The new context path
*/
@Override
public void setPath(String path) {
boolean invalid = false;
if (path == null || path.equals("/")) {
invalid = true;
this.path = "";
} else if (path.isEmpty() || path.startsWith("/")) {
this.path = path;
} else {
invalid = true;
this.path = "/" + path;
}
if (this.path.endsWith("/")) {
invalid = true;
this.path = this.path.substring(0, this.path.length() - 1);
}
if (invalid) {
log.warn(sm.getString("standardContext.pathInvalid", path, this.path));
}
encodedPath = URLEncoder.DEFAULT.encode(this.path, StandardCharsets.UTF_8);
if (getName() == null) {
setName(this.path);
}
}
/**
* @return the public identifier of the deployment descriptor DTD that is currently being parsed.
*/
@Override
public String getPublicId() {
return this.publicId;
}
/**
* Set the public identifier of the deployment descriptor DTD that is currently being parsed.
*
* @param publicId The public identifier
*/
@Override
public void setPublicId(String publicId) {
if (log.isDebugEnabled()) {
log.debug("Setting deployment descriptor public ID to '" + publicId + "'");
}
String oldPublicId = this.publicId;
this.publicId = publicId;
support.firePropertyChange("publicId", oldPublicId, publicId);
}
/**
* @return the reloadable flag for this web application.
*/
@Override
public boolean getReloadable() {
return this.reloadable;
}
/**
* @return the default context override flag for this web application.
*/
@Override
public boolean getOverride() {
return this.override;
}
/**
* @return the original document root for this Context. This can be an absolute pathname, a relative pathname, or a
* URL. Is only set as deployment has change docRoot!
*/
public String getOriginalDocBase() {
return this.originalDocBase;
}
/**
* Set the original document root for this Context. This can be an absolute pathname, a relative pathname, or a URL.
*
* @param docBase The original document root
*/
public void setOriginalDocBase(String docBase) {
this.originalDocBase = docBase;
}
/**
* @return the parent class loader (if any) for this web application. This call is meaningful only
* <strong>after</strong> a Loader has been configured.
*/
@Override
public ClassLoader getParentClassLoader() {
if (parentClassLoader != null) {
return parentClassLoader;
}
if (getPrivileged()) {
return this.getClass().getClassLoader();
} else if (parent != null) {
return parent.getParentClassLoader();
}
return ClassLoader.getSystemClassLoader();
}
/**
* @return the privileged flag for this web application.
*/
@Override
public boolean getPrivileged() {
return this.privileged;
}
/**
* Set the privileged flag for this web application.
*
* @param privileged The new privileged flag
*/
@Override
public void setPrivileged(boolean privileged) {
boolean oldPrivileged = this.privileged;
this.privileged = privileged;
support.firePropertyChange("privileged", oldPrivileged, this.privileged);
}
/**
* Set the reloadable flag for this web application.
*
* @param reloadable The new reloadable flag
*/
@Override
public void setReloadable(boolean reloadable) {
boolean oldReloadable = this.reloadable;
this.reloadable = reloadable;
support.firePropertyChange("reloadable", oldReloadable, this.reloadable);
}
/**
* Set the default context override flag for this web application.
*
* @param override The new override flag
*/
@Override
public void setOverride(boolean override) {
boolean oldOverride = this.override;
this.override = override;
support.firePropertyChange("override", oldOverride, this.override);
}
/**
* Set the "replace welcome files" property.
*
* @param replaceWelcomeFiles The new property value
*/
public void setReplaceWelcomeFiles(boolean replaceWelcomeFiles) {
boolean oldReplaceWelcomeFiles = this.replaceWelcomeFiles;
this.replaceWelcomeFiles = replaceWelcomeFiles;
support.firePropertyChange("replaceWelcomeFiles", oldReplaceWelcomeFiles, this.replaceWelcomeFiles);
}
--> --------------------
--> maximum size reached
--> --------------------