| /* |
| * 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.security.AccessController; |
| import java.security.PrivilegedAction; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Enumeration; |
| import java.util.EventListener; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| 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.Stack; |
| 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 javax.servlet.Filter; |
| import javax.servlet.FilterConfig; |
| import javax.servlet.FilterRegistration; |
| import javax.servlet.RequestDispatcher; |
| import javax.servlet.Servlet; |
| import javax.servlet.ServletContainerInitializer; |
| import javax.servlet.ServletContext; |
| import javax.servlet.ServletContextAttributeListener; |
| import javax.servlet.ServletContextEvent; |
| import javax.servlet.ServletContextListener; |
| import javax.servlet.ServletException; |
| import javax.servlet.ServletRegistration; |
| import javax.servlet.ServletRegistration.Dynamic; |
| import javax.servlet.ServletRequest; |
| import javax.servlet.ServletRequestAttributeListener; |
| import javax.servlet.ServletRequestEvent; |
| import javax.servlet.ServletRequestListener; |
| import javax.servlet.ServletSecurityElement; |
| import javax.servlet.SessionCookieConfig; |
| import javax.servlet.SessionTrackingMode; |
| import javax.servlet.descriptor.JspConfigDescriptor; |
| import javax.servlet.http.HttpSessionAttributeListener; |
| import javax.servlet.http.HttpSessionIdListener; |
| import javax.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.WebappLoader; |
| import org.apache.catalina.session.StandardManager; |
| import org.apache.catalina.util.CharsetMapper; |
| import org.apache.catalina.util.ContextName; |
| import org.apache.catalina.util.ExtensionValidator; |
| 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.IntrospectionUtils; |
| import org.apache.tomcat.util.buf.UDecoder; |
| 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.MessageDestinationRef; |
| 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; |
| |
| /** |
| * 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, NotificationEmitter { |
| |
| 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 set of application listener class names configured for this |
| * application, in the order they were encountered in the resulting merged |
| * web.xml file. |
| */ |
| private String applicationListeners[] = new String[0]; |
| |
| private final Object applicationListenersLock = new Object(); |
| |
| /** |
| * 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. |
| */ |
| private boolean delegate = false; |
| |
| |
| 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; |
| |
| |
| /** |
| * The exception pages for this web application, keyed by fully qualified |
| * class name of the Java exception. |
| */ |
| private HashMap<String, ErrorPage> exceptionPages = new HashMap<>(); |
| |
| |
| /** |
| * The set of filter configurations (and associated filter instances) we |
| * have initialized, keyed by filter name. |
| */ |
| private HashMap<String, ApplicationFilterConfig> filterConfigs = |
| new HashMap<>(); |
| |
| |
| /** |
| * The set of filter definitions for this application, keyed by |
| * filter name. |
| */ |
| private HashMap<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 HashMap<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 HashMap<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 HashMap<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); |
| |
| /** |
| * The status code error pages for this web application, keyed by |
| * HTTP status code (as an Integer). Note status code zero is used for the |
| * default error page. |
| */ |
| private HashMap<Integer, ErrorPage> statusPages = new HashMap<>(); |
| |
| |
| /** |
| * 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 on Java 9 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 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; |
| |
| |
| // ----------------------------------------------------- Context Properties |
| |
| @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() { |
| StringBuilder result = new StringBuilder(); |
| boolean first = true; |
| for (String servletName : resourceOnlyServlets) { |
| if (first) { |
| first = false; |
| } else { |
| result.append(','); |
| } |
| result.append(servletName); |
| } |
| return result.toString(); |
| } |
| |
| |
| @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); |
| |
| } |
| |
| |
| /** |
| * @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.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); |
| } |
| |
| |
| /** |
| * @return the document root for this Context. This can be an absolute |
| * pathname, a relative pathname, or a URL. |
| */ |
| @Override |
| public String getDocBase() { |
| |
| return (this.docBase); |
| |
| } |
| |
| |
| /** |
| * Set the document root for this Context. This can be an absolute |
| * pathname, a relative pathname, or a URL. |
| * |
| * @param docBase The new document root |
| */ |
| @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("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("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("StandardContext.setManager: stop-destroy: ", 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("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.warn("standardContext.namingResource.destroy.fail", e); |
| } |
| } |
| if (namingResources != null) { |
| try { |
| namingResources.init(); |
| namingResources.start(); |
| } catch (LifecycleException e) { |
| log.warn("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 ("".equals(path) || 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, "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); |
| |
| } |
| |
| |
| /** |
| * @return the servlet context for which this Context is a facade. |
| */ |
| @Override |
| public ServletContext getServletContext() { |
| |
| if (context == null) { |
| context = new ApplicationContext(this); |
| if (altDDName != null) |
| context.setAttribute(Globals.ALT_DD_ATTR,altDDName); |
| } |
| return (context.getFacade()); |
| |
| } |
| |
| |
| /** |
| * @return the default session timeout (in minutes) for this |
| * web application. |
| */ |
| @Override |
| public int getSessionTimeout() { |
| |
| return (this.sessionTimeout); |
| |
| } |
| |
| |
| /** |
| * Set the default session timeout (in minutes) for this |
| * web application. |
| * |
| * @param timeout The new default session timeout |
| */ |
| @Override |
| public void setSessionTimeout(int timeout) { |
| |
| int oldSessionTimeout = this.sessionTimeout; |
| /* |
| * SRV.13.4 ("Deployment Descriptor"): |
| * If the timeout is 0 or less, the container ensures the default |
| * behaviour of sessions is never to time out. |
| */ |
| this.sessionTimeout = (timeout == 0) ? -1 : timeout; |
| support.firePropertyChange("sessionTimeout", |
| oldSessionTimeout, |
| this.sessionTimeout); |
| |
| } |
| |
| |
| /** |
| * @return the value of the swallowOutput flag. |
| */ |
| @Override |
| public boolean getSwallowOutput() { |
| |
| return (this.swallowOutput); |
| |
| } |
| |
| |
| /** |
| * Set the value of the swallowOutput flag. If set to true, the system.out |
| * and system.err will be redirected to the logger during a servlet |
| * execution. |
| * |
| * @param swallowOutput The new value |
| */ |
| @Override |
| public void setSwallowOutput(boolean swallowOutput) { |
| |
| boolean oldSwallowOutput = this.swallowOutput; |
| this.swallowOutput = swallowOutput; |
| support.firePropertyChange("swallowOutput", |
| oldSwallowOutput, |
| this.swallowOutput); |
| |
| } |
| |
| |
| /** |
| * @return the value of the unloadDelay flag. |
| */ |
| public long getUnloadDelay() { |
| |
| return (this.unloadDelay); |
| |
| } |
| |
| |
| /** |
| * Set the value of the unloadDelay flag, which represents the amount |
| * of ms that the container will wait when unloading servlets. |
| * Setting this to a small value may cause more requests to fail |
| * to complete when stopping a web application. |
| * |
| * @param unloadDelay The new value |
| */ |
| public void setUnloadDelay(long unloadDelay) { |
| |
| long oldUnloadDelay = this.unloadDelay; |
| this.unloadDelay = unloadDelay; |
| support.firePropertyChange("unloadDelay", |
| Long.valueOf(oldUnloadDelay), |
| Long.valueOf(this.unloadDelay)); |
| |
| } |
| |
| |
| /** |
| * @return unpack WAR flag. |
| */ |
| public boolean getUnpackWAR() { |
| |
| return (unpackWAR); |
| |
| } |
| |
| |
| /** |
| * Unpack WAR flag mutator. |
| * |
| * @param unpackWAR <code>true</code> to unpack WARs on deployment |
| */ |
| public void setUnpackWAR(boolean unpackWAR) { |
| |
| this.unpackWAR = unpackWAR; |
| |
| } |
| |
| |
| /** |
| * Flag which indicates if bundled context.xml files should be copied to the |
| * config folder. The doesn't occur by default. |
| * |
| * @return <code>true</code> if the <code>META-INF/context.xml</code> file included |
| * in a WAR will be copied to the host configuration base folder on deployment |
| */ |
| public boolean getCopyXML() { |
| return copyXML; |
| } |
| |
| |
| /** |
| * Allows copying a bundled context.xml file to the host configuration base |
| * folder on deployment. |
| * |
| * @param copyXML the new flag value |
| */ |
| public void setCopyXML(boolean copyXML) { |
| this.copyXML = copyXML; |
| } |
| |
| |
| /** |
| * @return the Java class name of the Wrapper implementation used |
| * for servlets registered in this Context. |
| */ |
| @Override |
| public String getWrapperClass() { |
| |
| return (this.wrapperClassName); |
| |
| } |
| |
| |
| /** |
| * Set the Java class name of the Wrapper implementation used |
| * for servlets registered in this Context. |
| * |
| * @param wrapperClassName The new wrapper class name |
| * |
| * @throws IllegalArgumentException if the specified wrapper class |
| * cannot be found or is not a subclass of StandardWrapper |
| */ |
| @Override |
| public void setWrapperClass(String wrapperClassName) { |
| |
| this.wrapperClassName = wrapperClassName; |
| |
| try { |
| wrapperClass = Class.forName(wrapperClassName); |
| if (!StandardWrapper.class.isAssignableFrom(wrapperClass)) { |
| throw new IllegalArgumentException( |
| sm.getString("standardContext.invalidWrapperClass", |
| wrapperClassName)); |
| } |
| } catch (ClassNotFoundException cnfe) { |
| throw new IllegalArgumentException(cnfe.getMessage()); |
| } |
| } |
| |
| |
| @Override |
| public WebResourceRoot getResources() { |
| Lock readLock = resourcesLock.readLock(); |
| readLock.lock(); |
| try { |
| return resources; |
| } finally { |
| readLock.unlock(); |
| } |
| } |
| |
| |
| @Override |
| public void setResources(WebResourceRoot resources) { |
| |
| Lock writeLock = resourcesLock.writeLock(); |
| writeLock.lock(); |
| WebResourceRoot oldResources = null; |
| try { |
| if (getState().isAvailable()) { |
| throw new IllegalStateException |
| (sm.getString("standardContext.resourcesStart")); |
| } |
| |
| oldResources = this.resources; |
| if (oldResources == resources) |
| return; |
| |
| this.resources = resources; |
| if (oldResources != null) { |
| oldResources.setContext(null); |
| } |
| if (resources != null) { |
| resources.setContext(this); |
| } |
| |
| support.firePropertyChange("resources", oldResources, |
| resources); |
| } finally { |
| writeLock.unlock(); |
| } |
| } |
| |
| |
| @Override |
| public JspConfigDescriptor getJspConfigDescriptor() { |
| return jspConfigDescriptor; |
| } |
| |
| @Override |
| public void setJspConfigDescriptor(JspConfigDescriptor descriptor) { |
| this.jspConfigDescriptor = descriptor; |
| } |
| |
| @Override |
| public ThreadBindingListener getThreadBindingListener() { |
| return threadBindingListener; |
| } |
| |
| @Override |
| public void setThreadBindingListener(ThreadBindingListener threadBindingListener) { |
| this.threadBindingListener = threadBindingListener; |
| } |
| |
| |
| // ------------------------------------------------------ Public Properties |
| |
| /** |
| * @return whether or not an attempt to modify the JNDI context will trigger |
| * an exception or if the request will be ignored. |
| */ |
| public boolean getJndiExceptionOnFailedWrite() { |
| return jndiExceptionOnFailedWrite; |
| } |
| |
| |
| /** |
| * Controls whether or not an attempt to modify the JNDI context will |
| * trigger an exception or if the request will be ignored. |
| * |
| * @param jndiExceptionOnFailedWrite <code>false</code> to avoid an exception |
| */ |
| public void setJndiExceptionOnFailedWrite( |
| boolean jndiExceptionOnFailedWrite) { |
| this.jndiExceptionOnFailedWrite = jndiExceptionOnFailedWrite; |
| } |
| |
| |
| /** |
| * @return the Locale to character set mapper class for this Context. |
| */ |
| public String getCharsetMapperClass() { |
| |
| return (this.charsetMapperClass); |
| |
| } |
| |
| |
| /** |
| * Set the Locale to character set mapper class for this Context. |
| * |
| * @param mapper The new mapper class |
| */ |
| public void setCharsetMapperClass(String mapper) { |
| |
| String oldCharsetMapperClass = this.charsetMapperClass; |
| this.charsetMapperClass = mapper; |
| support.firePropertyChange("charsetMapperClass", |
| oldCharsetMapperClass, |
| this.charsetMapperClass); |
| |
| } |
| |
| |
| /** Get the absolute path to the work dir. |
| * To avoid duplication. |
| * |
| * @return The work path |
| */ |
| public String getWorkPath() { |
| if (getWorkDir() == null) { |
| return null; |
| } |
| File workDir = new File(getWorkDir()); |
| if (!workDir.isAbsolute()) { |
| try { |
| workDir = new File(getCatalinaBase().getCanonicalFile(), |
| getWorkDir()); |
| } catch (IOException e) { |
| log.warn(sm.getString("standardContext.workPath", getName()), |
| e); |
| } |
| } |
| return workDir.getAbsolutePath(); |
| } |
| |
| /** |
| * @return the work directory for this Context. |
| */ |
| public String getWorkDir() { |
| |
| return (this.workDir); |
| |
| } |
| |
| |
| /** |
| * Set the work directory for this Context. |
| * |
| * @param workDir The new work directory |
| */ |
| public void setWorkDir(String workDir) { |
| |
| this.workDir = workDir; |
| |
| if (getState().isAvailable()) { |
| postWorkDirectory(); |
| } |
| } |
| |
| |
| public boolean getClearReferencesRmiTargets() { |
| return this.clearReferencesRmiTargets; |
| } |
| |
| |
| public void setClearReferencesRmiTargets(boolean clearReferencesRmiTargets) { |
| boolean oldClearReferencesRmiTargets = this.clearReferencesRmiTargets; |
| this.clearReferencesRmiTargets = clearReferencesRmiTargets; |
| support.firePropertyChange("clearReferencesRmiTargets", |
| oldClearReferencesRmiTargets, this.clearReferencesRmiTargets); |
| } |
| |
| |
| /** |
| * @return the clearReferencesStopThreads flag for this Context. |
| */ |
| public boolean getClearReferencesStopThreads() { |
| |
| return (this.clearReferencesStopThreads); |
| |
| } |
| |
| |
| /** |
| * Set the clearReferencesStopThreads feature for this Context. |
| * |
| * @param clearReferencesStopThreads The new flag value |
| */ |
| public void setClearReferencesStopThreads( |
| boolean clearReferencesStopThreads) { |
| |
| boolean oldClearReferencesStopThreads = this.clearReferencesStopThreads; |
| this.clearReferencesStopThreads = clearReferencesStopThreads; |
| support.firePropertyChange("clearReferencesStopThreads", |
| oldClearReferencesStopThreads, |
| this.clearReferencesStopThreads); |
| |
| } |
| |
| |
| /** |
| * @return the clearReferencesStopTimerThreads flag for this Context. |
| */ |
| public boolean getClearReferencesStopTimerThreads() { |
| return (this.clearReferencesStopTimerThreads); |
| } |
| |
| |
| /** |
| * Set the clearReferencesStopTimerThreads feature for this Context. |
| * |
| * @param clearReferencesStopTimerThreads The new flag value |
| */ |
| public void setClearReferencesStopTimerThreads( |
| boolean clearReferencesStopTimerThreads) { |
| |
| boolean oldClearReferencesStopTimerThreads = |
| this.clearReferencesStopTimerThreads; |
| this.clearReferencesStopTimerThreads = clearReferencesStopTimerThreads; |
| support.firePropertyChange("clearReferencesStopTimerThreads", |
| oldClearReferencesStopTimerThreads, |
| this.clearReferencesStopTimerThreads); |
| } |
| |
| |
| /** |
| * @return the clearReferencesHttpClientKeepAliveThread flag for this |
| * Context. |
| */ |
| public boolean getClearReferencesHttpClientKeepAliveThread() { |
| return (this.clearReferencesHttpClientKeepAliveThread); |
| } |
| |
| |
| /** |
| * Set the clearReferencesHttpClientKeepAliveThread feature for this |
| * Context. |
| * |
| * @param clearReferencesHttpClientKeepAliveThread The new flag value |
| */ |
| public void setClearReferencesHttpClientKeepAliveThread( |
| boolean clearReferencesHttpClientKeepAliveThread) { |
| this.clearReferencesHttpClientKeepAliveThread = |
| clearReferencesHttpClientKeepAliveThread; |
| } |
| |
| |
| public boolean getRenewThreadsWhenStoppingContext() { |
| return this.renewThreadsWhenStoppingContext; |
| } |
| |
| public void setRenewThreadsWhenStoppingContext( |
| boolean renewThreadsWhenStoppingContext) { |
| boolean oldRenewThreadsWhenStoppingContext = |
| this.renewThreadsWhenStoppingContext; |
| this.renewThreadsWhenStoppingContext = renewThreadsWhenStoppingContext; |
| support.firePropertyChange("renewThreadsWhenStoppingContext", |
| oldRenewThreadsWhenStoppingContext, |
| this.renewThreadsWhenStoppingContext); |
| } |
| |
| public Boolean getFailCtxIfServletStartFails() { |
| return failCtxIfServletStartFails; |
| } |
| |
| public void setFailCtxIfServletStartFails( |
| Boolean failCtxIfServletStartFails) { |
| Boolean oldFailCtxIfServletStartFails = this.failCtxIfServletStartFails; |
| this.failCtxIfServletStartFails = failCtxIfServletStartFails; |
| support.firePropertyChange("failCtxIfServletStartFails", |
| oldFailCtxIfServletStartFails, |
| failCtxIfServletStartFails); |
| } |
| |
| protected boolean getComputedFailCtxIfServletStartFails() { |
| if(failCtxIfServletStartFails != null) { |
| return failCtxIfServletStartFails.booleanValue(); |
| } |
| //else look at Host config |
| if(getParent() instanceof StandardHost) { |
| return ((StandardHost)getParent()).isFailCtxIfServletStartFails(); |
| } |
| //else |
| return false; |
| } |
| |
| // -------------------------------------------------------- Context Methods |
| |
| /** |
| * Add a new Listener class name to the set of Listeners |
| * configured for this application. |
| * |
| * @param listener Java class name of a listener class |
| */ |
| @Override |
| public void addApplicationListener(String listener) { |
| |
| synchronized (applicationListenersLock) { |
| String results[] = new String[applicationListeners.length + 1]; |
| for (int i = 0; i < applicationListeners.length; i++) { |
| if (listener.equals(applicationListeners[i])) { |
| log.info(sm.getString("standardContext.duplicateListener",listener)); |
| return; |
| } |
| results[i] = applicationListeners[i]; |
| } |
| results[applicationListeners.length] = listener; |
| applicationListeners = results; |
| } |
| fireContainerEvent("addApplicationListener", listener); |
| |
| // FIXME - add instance if already started? |
| } |
| |
| |
| /** |
| * Add a new application parameter for this application. |
| * |
| * @param parameter The new application parameter |
| */ |
| @Override |
| public void addApplicationParameter(ApplicationParameter parameter) { |
| |
| synchronized (applicationParametersLock) { |
| String newName = parameter.getName(); |
| for (ApplicationParameter p : applicationParameters) { |
| if (newName.equals(p.getName()) && !p.getOverride()) |
| return; |
| } |
| ApplicationParameter results[] = Arrays.copyOf( |
| applicationParameters, applicationParameters.length + 1); |
| results[applicationParameters.length] = parameter; |
| applicationParameters = results; |
| } |
| fireContainerEvent("addApplicationParameter", parameter); |
| |
| } |
| |
| |
| /** |
| * Add a child Container, only if the proposed child is an implementation |
| * of Wrapper. |
| * |
| * @param child Child container to be added |
| * |
| * @exception IllegalArgumentException if the proposed container is |
| * not an implementation of Wrapper |
| */ |
| @Override |
| public void addChild(Container child) { |
| |
| // Global JspServlet |
| Wrapper oldJspServlet = null; |
| |
| if (!(child instanceof Wrapper)) { |
| throw new IllegalArgumentException |
| (sm.getString("standardContext.notWrapper")); |
| } |
| |
| boolean isJspServlet = "jsp".equals(child.getName()); |
| |
| // Allow webapp to override JspServlet inherited from global web.xml. |
| if (isJspServlet) { |
| oldJspServlet = (Wrapper) findChild("jsp"); |
| if (oldJspServlet != null) { |
| removeChild(oldJspServlet); |
| } |
| } |
| |
| super.addChild(child); |
| |
| if (isJspServlet && oldJspServlet != null) { |
| /* |
| * The webapp-specific JspServlet inherits all the mappings |
| * specified in the global web.xml, and may add additional ones. |
| */ |
| String[] jspMappings = oldJspServlet.findMappings(); |
| for (int i=0; jspMappings!=null && i<jspMappings.length; i++) { |
| addServletMapping(jspMappings[i], child.getName()); |
| } |
| } |
| } |
| |
| |
| /** |
| * Add a security constraint to the set for this web application. |
| * |
| * @param constraint the new security constraint |
| */ |
| @Override |
| public void addConstraint(SecurityConstraint constraint) { |
| |
| // Validate the proposed constraint |
| SecurityCollection collections[] = constraint.findCollections(); |
| for (int i = 0; i < collections.length; i++) { |
| String patterns[] = collections[i].findPatterns(); |
| for (int j = 0; j < patterns.length; j++) { |
| patterns[j] = adjustURLPattern(patterns[j]); |
| if (!validateURLPattern(patterns[j])) |
| throw new IllegalArgumentException |
| (sm.getString |
| ("standardContext.securityConstraint.pattern", |
| patterns[j])); |
| } |
| if (collections[i].findMethods().length > 0 && |
| collections[i].findOmittedMethods().length > 0) { |
| throw new IllegalArgumentException(sm.getString( |
| "standardContext.securityConstraint.mixHttpMethod")); |
| } |
| } |
| |
| // Add this constraint to the set for our web application |
| synchronized (constraintsLock) { |
| SecurityConstraint results[] = |
| new SecurityConstraint[constraints.length + 1]; |
| for (int i = 0; i < constraints.length; i++) |
| results[i] = constraints[i]; |
| results[constraints.length] = constraint; |
| constraints = results; |
| } |
| |
| } |
| |
| |
| |
| /** |
| * Add an error page for the specified error or Java exception. |
| * |
| * @param errorPage The error page definition to be added |
| */ |
| @Override |
| public void addErrorPage(ErrorPage errorPage) { |
| // Validate the input parameters |
| if (errorPage == null) |
| throw new IllegalArgumentException |
| (sm.getString("standardContext.errorPage.required")); |
| String location = errorPage.getLocation(); |
| if ((location != null) && !location.startsWith("/")) { |
| if (isServlet22()) { |
| if(log.isDebugEnabled()) |
| log.debug(sm.getString("standardContext.errorPage.warning", |
| location)); |
| errorPage.setLocation("/" + location); |
| } else { |
| throw new IllegalArgumentException |
| (sm.getString("standardContext.errorPage.error", |
| location)); |
| } |
| } |
| |
| // Add the specified error page to our internal collections |
| String exceptionType = errorPage.getExceptionType(); |
| if (exceptionType != null) { |
| synchronized (exceptionPages) { |
| exceptionPages.put(exceptionType, errorPage); |
| } |
| } else { |
| synchronized (statusPages) { |
| statusPages.put(Integer.valueOf(errorPage.getErrorCode()), |
| errorPage); |
| } |
| } |
| fireContainerEvent("addErrorPage", errorPage); |
| |
| } |
| |
| |
| /** |
| * Add a filter definition to this Context. |
| * |
| * @param filterDef The filter definition to be added |
| */ |
| @Override |
| public void addFilterDef(FilterDef filterDef) { |
| |
| synchronized (filterDefs) { |
| filterDefs.put(filterDef.getFilterName(), filterDef); |
| } |
| fireContainerEvent("addFilterDef", filterDef); |
| |
| } |
| |
| |
| /** |
| * Add a filter mapping to this Context at the end of the current set |
| * of filter mappings. |
| * |
| * @param filterMap The filter mapping to be added |
| * |
| * @exception IllegalArgumentException if the specified filter name |
| * does not match an existing filter definition, or the filter mapping |
| * is malformed |
| */ |
| @Override |
| public void addFilterMap(FilterMap filterMap) { |
| validateFilterMap(filterMap); |
| // Add this filter mapping to our registered set |
| filterMaps.add(filterMap); |
| fireContainerEvent("addFilterMap", filterMap); |
| } |
| |
| |
| /** |
| * Add a filter mapping to this Context before the mappings defined in the |
| * deployment descriptor but after any other mappings added via this method. |
| * |
| * @param filterMap The filter mapping to be added |
| * |
| * @exception IllegalArgumentException if the specified filter name |
| * does not match an existing filter definition, or the filter mapping |
| * is malformed |
| */ |
| @Override |
| public void addFilterMapBefore(FilterMap filterMap) { |
| validateFilterMap(filterMap); |
| // Add this filter mapping to our registered set |
| filterMaps.addBefore(filterMap); |
| fireContainerEvent("addFilterMap", filterMap); |
| } |
| |
| |
| /** |
| * Validate the supplied FilterMap. |
| * |
| * @param filterMap the filter mapping |
| */ |
| private void validateFilterMap(FilterMap filterMap) { |
| // Validate the proposed filter mapping |
| String filterName = filterMap.getFilterName(); |
| String[] servletNames = filterMap.getServletNames(); |
| String[] urlPatterns = filterMap.getURLPatterns(); |
| if (findFilterDef(filterName) == null) |
| throw new IllegalArgumentException |
| (sm.getString("standardContext.filterMap.name", filterName)); |
| |
| if (!filterMap.getMatchAllServletNames() && |
| !filterMap.getMatchAllUrlPatterns() && |
| (servletNames.length == 0) && (urlPatterns.length == 0)) |
| throw new IllegalArgumentException |
| (sm.getString("standardContext.filterMap.either")); |
| // FIXME: Older spec revisions may still check this |
| /* |
| if ((servletNames.length != 0) && (urlPatterns.length != 0)) |
| throw new IllegalArgumentException |
| (sm.getString("standardContext.filterMap.either")); |
| */ |
| for (int i = 0; i < urlPatterns.length; i++) { |
| if (!validateURLPattern(urlPatterns[i])) { |
| throw new IllegalArgumentException |
| (sm.getString("standardContext.filterMap.pattern", |
| urlPatterns[i])); |
| } |
| } |
| } |
| |
| |
| /** |
| * Add a Locale Encoding Mapping (see Sec 5.4 of Servlet spec 2.4) |
| * |
| * @param locale locale to map an encoding for |
| * @param encoding encoding to be used for a give locale |
| */ |
| @Override |
| public void addLocaleEncodingMappingParameter(String locale, String encoding){ |
| getCharsetMapper().addCharsetMappingFromDeploymentDescriptor(locale, encoding); |
| } |
| |
| |
| /** |
| * Add a message destination for this web application. |
| * |
| * @param md New message destination |
| */ |
| public void addMessageDestination(MessageDestination md) { |
| |
| synchronized (messageDestinations) { |
| messageDestinations.put(md.getName(), md); |
| } |
| fireContainerEvent("addMessageDestination", md.getName()); |
| |
| } |
| |
| |
| /** |
| * Add a message destination reference for this web application. |
| * |
| * @param mdr New message destination reference |
| */ |
| public void addMessageDestinationRef |
| (MessageDestinationRef mdr) { |
| |
| namingResources.addMessageDestinationRef(mdr); |
| fireContainerEvent("addMessageDestinationRef", mdr.getName()); |
| |
| } |
| |
| |
| /** |
| * Add a new MIME mapping, replacing any existing mapping for |
| * the specified extension. |
| * |
| * @param extension Filename extension being mapped |
| * @param mimeType Corresponding MIME type |
| */ |
| @Override |
| public void addMimeMapping(String extension, String mimeType) { |
| |
| synchronized (mimeMappings) { |
| mimeMappings.put(extension.toLowerCase(Locale.ENGLISH), mimeType); |
| } |
| fireContainerEvent("addMimeMapping", extension); |
| |
| } |
| |
| |
| /** |
| * Add a new context initialization parameter. |
| * |
| * @param name Name of the new parameter |
| * @param value Value of the new parameter |
| * |
| * @exception IllegalArgumentException if the name or value is missing, |
| * or if this context initialization parameter has already been |
| * registered |
| */ |
| @Override |
| public void addParameter(String name, String value) { |
| // Validate the proposed context initialization parameter |
| if ((name == null) || (value == null)) { |
| throw new IllegalArgumentException |
| (sm.getString("standardContext.parameter.required")); |
| } |
| |
| // Add this parameter to our defined set if not already present |
| String oldValue = parameters.putIfAbsent(name, value); |
| |
| if (oldValue != null) { |
| throw new IllegalArgumentException( |
| sm.getString("standardContext.parameter.duplicate", name)); |
| } |
| |
| fireContainerEvent("addParameter", name); |
| } |
| |
| |
| /** |
| * Add a security role reference for this web application. |
| * |
| * @param role Security role used in the application |
| * @param link Actual security role to check for |
| */ |
| @Override |
| public void addRoleMapping(String role, String link) { |
| |
| synchronized (roleMappings) { |
| roleMappings.put(role, link); |
| } |
| fireContainerEvent("addRoleMapping", role); |
| |
| } |
| |
| |
| /** |
| * Add a new security role for this web application. |
| * |
| * @param role New security role |
| */ |
| @Override |
| public void addSecurityRole(String role) { |
| |
| synchronized (securityRolesLock) { |
| String results[] =new String[securityRoles.length + 1]; |
| for (int i = 0; i < securityRoles.length; i++) |
| results[i] = securityRoles[i]; |
| results[securityRoles.length] = role; |
| securityRoles = results; |
| } |
| fireContainerEvent("addSecurityRole", role); |
| |
| } |
| |
| |
| /** |
| * Add a new servlet mapping, replacing any existing mapping for |
| * the specified pattern. |
| * |
| * @param pattern URL pattern to be mapped |
| * @param name Name of the corresponding servlet to execute |
| * |
| * @exception IllegalArgumentException if the specified servlet name |
| * is not known to this Context |
| */ |
| @Override |
| public void addServletMapping(String pattern, String name) { |
| addServletMapping(pattern, name, false); |
| } |
| |
| |
| /** |
| * Add a new servlet mapping, replacing any existing mapping for |
| * the specified pattern. |
| * |
| * @param pattern URL pattern to be mapped |
| * @param name Name of the corresponding servlet to execute |
| * @param jspWildCard true if name identifies the JspServlet |
| * and pattern contains a wildcard; false otherwise |
| * |
| * @exception IllegalArgumentException if the specified servlet name |
| * is not known to this Context |
| */ |
| @Override |
| public void addServletMapping(String pattern, String name, |
| boolean jspWildCard) { |
| // Validate the proposed mapping |
| if (findChild(name) == null) |
| throw new IllegalArgumentException |
| (sm.getString("standardContext.servletMap.name", name)); |
| String decodedPattern = adjustURLPattern(UDecoder.URLDecode(pattern)); |
| if (!validateURLPattern(decodedPattern)) |
| throw new IllegalArgumentException |
| (sm.getString("standardContext.servletMap.pattern", decodedPattern)); |
| |
| // Add this mapping to our registered set |
| synchronized (servletMappingsLock) { |
| String name2 = servletMappings.get(decodedPattern); |
| if (name2 != null) { |
| // Don't allow more than one servlet on the same pattern |
| Wrapper wrapper = (Wrapper) findChild(name2); |
| wrapper.removeMapping(decodedPattern); |
| } |
| servletMappings.put(decodedPattern, name); |
| } |
| Wrapper wrapper = (Wrapper) findChild(name); |
| wrapper.addMapping(decodedPattern); |
| |
| fireContainerEvent("addServletMapping", decodedPattern); |
| } |
| |
| |
| /** |
| * Add a new watched resource to the set recognized by this Context. |
| * |
| * @param name New watched resource file name |
| */ |
| @Override |
| public void addWatchedResource(String name) { |
| |
| synchronized (watchedResourcesLock) { |
| String results[] = new String[watchedResources.length + 1]; |
| for (int i = 0; i < watchedResources.length; i++) |
| results[i] = watchedResources[i]; |
| results[watchedResources.length] = name; |
| watchedResources = results; |
| } |
| fireContainerEvent("addWatchedResource", name); |
| } |
| |
| |
| /** |
| * Add a new welcome file to the set recognized by this Context. |
| * |
| * @param name New welcome file name |
| */ |
| @Override |
| public void addWelcomeFile(String name) { |
| |
| synchronized (welcomeFilesLock) { |
| // Welcome files from the application deployment descriptor |
| // completely replace those from the default conf/web.xml file |
| if (replaceWelcomeFiles) { |
| fireContainerEvent(CLEAR_WELCOME_FILES_EVENT, null); |
| welcomeFiles = new String[0]; |
| setReplaceWelcomeFiles(false); |
| } |
| String results[] =new String[welcomeFiles.length + 1]; |
| for (int i = 0; i < welcomeFiles.length; i++) |
| results[i] = welcomeFiles[i]; |
| results[welcomeFiles.length] = name; |
| welcomeFiles = results; |
| } |
| if(this.getState().equals(LifecycleState.STARTED)) |
| fireContainerEvent(ADD_WELCOME_FILE_EVENT, name); |
| } |
| |
| |
| /** |
| * Add the classname of a LifecycleListener to be added to each |
| * Wrapper appended to this Context. |
| * |
| * @param listener Java class name of a LifecycleListener class |
| */ |
| @Override |
| public void addWrapperLifecycle(String listener) { |
| |
| synchronized (wrapperLifecyclesLock) { |
| String results[] =new String[wrapperLifecycles.length + 1]; |
| for (int i = 0; i < wrapperLifecycles.length; i++) |
| results[i] = wrapperLifecycles[i]; |
| results[wrapperLifecycles.length] = listener; |
| wrapperLifecycles = results; |
| } |
| fireContainerEvent("addWrapperLifecycle", listener); |
| |
| } |
| |
| |
| /** |
| * Add the classname of a ContainerListener to be added to each |
| * Wrapper appended to this Context. |
| * |
| * @param listener Java class name of a ContainerListener class |
| */ |
| @Override |
| public void addWrapperListener(String listener) { |
| |
| synchronized (wrapperListenersLock) { |
| String results[] =new String[wrapperListeners.length + 1]; |
| for (int i = 0; i < wrapperListeners.length; i++) |
| results[i] = wrapperListeners[i]; |
| results[wrapperListeners.length] = listener; |
| wrapperListeners = results; |
| } |
| fireContainerEvent("addWrapperListener", listener); |
| |
| } |
| |
| |
| /** |
| * Factory method to create and return a new Wrapper instance, of |
| * the Java implementation class appropriate for this Context |
| * implementation. The constructor of the instantiated Wrapper |
| * will have been called, but no properties will have been set. |
| */ |
| @Override |
| public Wrapper createWrapper() { |
| |
| Wrapper wrapper = null; |
| if (wrapperClass != null) { |
| try { |
| wrapper = (Wrapper) wrapperClass.newInstance(); |
| } catch (Throwable t) { |
| ExceptionUtils.handleThrowable(t); |
| log.error("createWrapper", t); |
| return (null); |
| } |
| } else { |
| wrapper = new StandardWrapper(); |
| } |
| |
| synchronized (wrapperLifecyclesLock) { |
| for (int i = 0; i < wrapperLifecycles.length; i++) { |
| try { |
| Class<?> clazz = Class.forName(wrapperLifecycles[i]); |
| LifecycleListener listener = |
| (LifecycleListener) clazz.newInstance(); |
| wrapper.addLifecycleListener(listener); |
| } catch (Throwable t) { |
| ExceptionUtils.handleThrowable(t); |
| log.error("createWrapper", t); |
| return (null); |
| } |
| } |
| } |
| |
| synchronized (wrapperListenersLock) { |
| for (int i = 0; i < wrapperListeners.length; i++) { |
| try { |
| Class<?> clazz = Class.forName(wrapperListeners[i]); |
| ContainerListener listener = |
| (ContainerListener) clazz.newInstance(); |
| wrapper.addContainerListener(listener); |
| } catch (Throwable t) { |
| ExceptionUtils.handleThrowable(t); |
| log.error("createWrapper", t); |
| return (null); |
| } |
| } |
| } |
| |
| return (wrapper); |
| |
| } |
| |
| |
| /** |
| * Return the set of application listener class names configured |
| * for this application. |
| */ |
| @Override |
| public String[] findApplicationListeners() { |
| return applicationListeners; |
| } |
| |
| |
| /** |
| * Return the set of application parameters for this application. |
| */ |
| @Override |
| public ApplicationParameter[] findApplicationParameters() { |
| |
| synchronized (applicationParametersLock) { |
| return (applicationParameters); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the security constraints for this web application. |
| * If there are none, a zero-length array is returned. |
| */ |
| @Override |
| public SecurityConstraint[] findConstraints() { |
| |
| return (constraints); |
| |
| } |
| |
| |
| /** |
| * Return the error page entry for the specified HTTP error code, |
| * if any; otherwise return <code>null</code>. |
| * |
| * @param errorCode Error code to look up |
| */ |
| @Override |
| public ErrorPage findErrorPage(int errorCode) { |
| return statusPages.get(Integer.valueOf(errorCode)); |
| } |
| |
| |
| /** |
| * Return the error page entry for the specified Java exception type, |
| * if any; otherwise return <code>null</code>. |
| * |
| * @param exceptionType Exception type to look up |
| */ |
| @Override |
| public ErrorPage findErrorPage(String exceptionType) { |
| |
| synchronized (exceptionPages) { |
| return (exceptionPages.get(exceptionType)); |
| } |
| |
| } |
| |
| |
| /** |
| * Return the set of defined error pages for all specified error codes |
| * and exception types. |
| */ |
| @Override |
| public ErrorPage[] findErrorPages() { |
| |
| synchronized(exceptionPages) { |
| synchronized(statusPages) { |
| ErrorPage results1[] = new ErrorPage[exceptionPages.size()]; |
| results1 = exceptionPages.values().toArray(results1); |
| ErrorPage results2[] = new ErrorPage[statusPages.size()]; |
| results2 = statusPages.values().toArray(results2); |
| ErrorPage results[] = |
| new ErrorPage[results1.length + results2.length]; |
| for (int i = 0; i < results1.length; i++) |
| results[i] = results1[i]; |
| for (int i = results1.length; i < results.length; i++) |
| results[i] = results2[i - results1.length]; |
| return (results); |
| } |
| } |
| |
| } |
| |
| |
| /** |
| * Return the filter definition for the specified filter name, if any; |
| * otherwise return <code>null</code>. |
| * |
| * @param filterName Filter name to look up |
| */ |
| @Override |
| public FilterDef findFilterDef(String filterName) { |
| |
| synchronized (filterDefs) { |
| return (filterDefs.get(filterName)); |
| } |
| |
| } |
| |
| |
| /** |
| * @return the set of defined filters for this Context. |
| */ |
| @Override |
| public FilterDef[] findFilterDefs() { |
| |
| synchronized (filterDefs) { |
| FilterDef results[] = new FilterDef[filterDefs.size()]; |
| return (filterDefs.values().toArray(results)); |
| } |
| |
| } |
| |
| |
| /** |
| * @return the set of filter mappings for this Context. |
| */ |
| @Override |
| public FilterMap[] findFilterMaps() { |
| return filterMaps.asArray(); |
| } |
| |
| |
| /** |
| * @return the message destination with the specified name, if any; |
| * otherwise, return <code>null</code>. |
| * |
| * @param name Name of the desired message destination |
| */ |
| public MessageDestination findMessageDestination(String name) { |
| |
| synchronized (messageDestinations) { |
| return (messageDestinations.get(name)); |
| } |
| |
| } |
| |
| |
| /** |
| * @return the set of defined message destinations for this web |
| * application. If none have been defined, a zero-length array |
| * is returned. |
| */ |
| public MessageDestination[] findMessageDestinations() { |
| |
| synchronized (messageDestinations) { |
| MessageDestination results[] = |
| new MessageDestination[messageDestinations.size()]; |
| return (messageDestinations.values().toArray(results)); |
| } |
| |
| } |
| |
| |
| /** |
| * @return the message destination ref with the specified name, if any; |
| * otherwise, return <code>null</code>. |
| * |
| * @param name Name of the desired message destination ref |
| */ |
| public MessageDestinationRef findMessageDestinationRef(String name) { |
| |
| return namingResources.findMessageDestinationRef(name); |
| |
| } |
| |
| |
| /** |
| * @return the set of defined message destination refs for this web |
| * application. If none have been defined, a zero-length array |
| * is returned. |
| */ |
| public MessageDestinationRef[] findMessageDestinationRefs() { |
| |
| return namingResources.findMessageDestinationRefs(); |
| |
| } |
| |
| |
| /** |
| * @return the MIME type to which the specified extension is mapped, |
| * if any; otherwise return <code>null</code>. |
| * |
| * @param extension Extension to map to a MIME type |
| */ |
| @Override |
| public String findMimeMapping(String extension) { |
| |
| return (mimeMappings.get(extension.toLowerCase(Locale.ENGLISH))); |
| |
| } |
| |
| |
| /** |
| * @return the extensions for which MIME mappings are defined. If there |
| * are none, a zero-length array is returned. |
| */ |
| @Override |
| public String[] findMimeMappings() { |
| |
| synchronized (mimeMappings) { |
| String results[] = new String[mimeMappings.size()]; |
| return |
| (mimeMappings.keySet().toArray(results)); |
| } |
| |
| } |
| |
| |
| /** |
| * @return the value for the specified context initialization |
| * parameter name, if any; otherwise return <code>null</code>. |
| * |
| * @param name Name of the parameter to return |
| */ |
| @Override |
| public String findParameter(String name) { |
| return parameters.get(name); |
| } |
| |
| |
| /** |
| * @return the names of all defined context initialization parameters |
| * for this Context. If no parameters are defined, a zero-length |
| * array is returned. |
| */ |
| @Override |
| public String[] findParameters() { |
| List<String> parameterNames = new ArrayList<>(parameters.size()); |
| parameterNames.addAll(parameters.keySet()); |
| return parameterNames.toArray(new String[parameterNames.size()]); |
| } |
| |
| |
| /** |
| * For the given security role (as used by an application), return the |
| * corresponding role name (as defined by the underlying Realm) if there |
| * is one. Otherwise, return the specified role unchanged. |
| * |
| * @param role Security role to map |
| * @return the role name |
| */ |
| @Override |
| public String findRoleMapping(String role) { |
| |
| String realRole = null; |
| synchronized (roleMappings) { |
| realRole = roleMappings.get(role); |
| } |
| if (realRole != null) |
| return (realRole); |
| else |
| return (role); |
| |
| } |
| |
| |
| /** |
| * @return <code>true</code> if the specified security role is defined |
| * for this application; otherwise return <code>false</code>. |
| * |
| * @param role Security role to verify |
| */ |
| @Override |
| public boolean findSecurityRole(String role) { |
| |
| synchronized (securityRolesLock) { |
| for (int i = 0; i < securityRoles.length; i++) { |
| if (role.equals(securityRoles[i])) |
| return true; |
| } |
| } |
| return false; |
| |
| } |
| |
| |
| /** |
| * @return the security roles defined for this application. If none |
| * have been defined, a zero-length array is returned. |
| */ |
| @Override |
| public String[] findSecurityRoles() { |
| |
| synchronized (securityRolesLock) { |
| return (securityRoles); |
| } |
| |
| } |
| |
| |
| /** |
| * @return the servlet name mapped by the specified pattern (if any); |
| * otherwise return <code>null</code>. |
| * |
| * @param pattern Pattern for which a mapping is requested |
| */ |
| @Override |
| public String findServletMapping(String pattern) { |
| |
| synchronized (servletMappingsLock) { |
| return (servletMappings.get(pattern)); |
| } |
| |
| } |
| |
| |
| /** |
| * @return the patterns of all defined servlet mappings for this |
| * Context. If no mappings are defined, a zero-length array is returned. |
| */ |
| @Override |
| public String[] findServletMappings() { |
| |
| synchronized (servletMappingsLock) { |
| String results[] = new String[servletMappings.size()]; |
| return |
| (servletMappings.keySet().toArray(results)); |
| } |
| |
| } |
| |
| |
| /** |
| * @return the context-relative URI of the error page for the specified |
| * HTTP status code, if any; otherwise return <code>null</code>. |
| * |
| * @param status HTTP status code to look up |
| */ |
| @Override |
| public String findStatusPage(int status) { |
| |
| ErrorPage errorPage = statusPages.get(Integer.valueOf(status)); |
| if (errorPage!=null) { |
| return errorPage.getLocation(); |
| } |
| return null; |
| |
| } |
| |
| |
| /** |
| * @return the set of HTTP status codes for which error pages have |
| * been specified. If none are specified, a zero-length array |
| * is returned. |
| */ |
| @Override |
| public int[] findStatusPages() { |
| |
| synchronized (statusPages) { |
| int results[] = new int[statusPages.size()]; |
| Iterator<Integer> elements = statusPages.keySet().iterator(); |
| int i = 0; |
| while (elements.hasNext()) |
| results[i++] = elements.next().intValue(); |
| return (results); |
| } |
| |
| } |
| |
| |
| /** |
| * @return <code>true</code> if the specified welcome file is defined |
| * for this Context; otherwise return <code>false</code>. |
| * |
| * @param name Welcome file to verify |
| */ |
| @Override |
| public boolean findWelcomeFile(String name) { |
| |
| synchronized (welcomeFilesLock) { |
| for (int i = 0; i < welcomeFiles.length; i++) { |
| if (name.equals(welcomeFiles[i])) |
| return true; |
| } |
| } |
| return false; |
| |
| } |
| |
| |
| /** |
| * @return the set of watched resources for this Context. If none are |
| * defined, a zero length array will be returned. |
| */ |
| @Override |
| public String[] findWatchedResources() { |
| synchronized (watchedResourcesLock) { |
| return watchedResources; |
| } |
| } |
| |
| |
| /** |
| * @return the set of welcome files defined for this Context. If none are |
| * defined, a zero-length array is returned. |
| */ |
| @Override |
| public String[] findWelcomeFiles() { |
| |
| synchronized (welcomeFilesLock) { |
| return (welcomeFiles); |
| } |
| |
| } |
| |
| |
| /** |
| * @return the set of LifecycleListener classes that will be added to |
| * newly created Wrappers automatically. |
| */ |
| @Override |
| public String[] findWrapperLifecycles() { |
| |
| synchronized (wrapperLifecyclesLock) { |
| return (wrapperLifecycles); |
| } |
| |
| } |
| |
| |
| /** |
| * @return the set of ContainerListener classes that will be added to |
| * newly created Wrappers automatically. |
| */ |
| @Override |
| public String[] findWrapperListeners() { |
| |
| synchronized (wrapperListenersLock) { |
| return (wrapperListeners); |
| } |
| |
| } |
| |
| |
| /** |
| * Reload this web application, if reloading is supported. |
| * <p> |
| * <b>IMPLEMENTATION NOTE</b>: This method is designed to deal with |
| * reloads required by changes to classes in the underlying repositories |
| * of our class loader and changes to the web.xml file. It does not handle |
| * changes to any context.xml file. If the context.xml has changed, you |
| * should stop this Context and create (and start) a new Context instance |
| * instead. Note that there is additional code in |
| * <code>CoyoteAdapter#postParseRequest()</code> to handle mapping requests |
| * to paused Contexts. |
| * |
| * @exception IllegalStateException if the <code>reloadable</code> |
| * property is set to <code>false</code>. |
| */ |
| @Override |
| public synchronized void reload() { |
| |
| // Validate our current component state |
| if (!getState().isAvailable()) |
| throw new IllegalStateException |
| (sm.getString("standardContext.notStarted", getName())); |
| |
| if(log.isInfoEnabled()) |
| log.info(sm.getString("standardContext.reloadingStarted", |
| getName())); |
| |
| // Stop accepting requests temporarily. |
| setPaused(true); |
| |
| try { |
| stop(); |
| } catch (LifecycleException e) { |
| log.error( |
| sm.getString("standardContext.stoppingContext", getName()), e); |
| } |
| |
| try { |
| start(); |
| } catch (LifecycleException e) { |
| log.error( |
| sm.getString("standardContext.startingContext", getName()), e); |
| } |
| |
| setPaused(false); |
| |
| if(log.isInfoEnabled()) |
| log.info(sm.getString("standardContext.reloadingCompleted", |
| getName())); |
| |
| } |
| |
| |
| /** |
| * Remove the specified application listener class from the set of |
| * listeners for this application. |
| * |
| * @param listener Java class name of the listener to be removed |
| */ |
| @Override |
| public void removeApplicationListener(String listener) { |
| |
| synchronized (applicationListenersLock) { |
| |
| // Make sure this listener is currently present |
| int n = -1; |
| for (int i = 0; i < applicationListeners.length; i++) { |
| if (applicationListeners[i].equals(listener)) { |
| n = i; |
| break; |
| } |
| } |
| if (n < 0) |
| return; |
| |
| // Remove the specified listener |
| int j = 0; |
| String results[] = new String[applicationListeners.length - 1]; |
| for (int i = 0; i < applicationListeners.length; i++) { |
| if (i != n) |
| results[j++] = applicationListeners[i]; |
| } |
| applicationListeners = results; |
| |
| } |
| |
| // Inform interested listeners |
| fireContainerEvent("removeApplicationListener", listener); |
| |
| // FIXME - behavior if already started? |
| } |
| |
| |
| /** |
| * Remove the application parameter with the specified name from |
| * the set for this application. |
| * |
| * @param name Name of the application parameter to remove |
| */ |
| @Override |
| public void removeApplicationParameter(String name) { |
| |
| synchronized (applicationParametersLock) { |
| |
| // Make sure this parameter is currently present |
| int n = -1; |
| for (int i = 0; i < applicationParameters.length; i++) { |
| if (name.equals(applicationParameters[i].getName())) { |
| n = i; |
| break; |
| } |
| } |
| if (n < 0) |
| return; |
| |
| // Remove the specified parameter |
| int j = 0; |
| ApplicationParameter results[] = |
| new ApplicationParameter[applicationParameters.length - 1]; |
| for (int i = 0; i < applicationParameters.length; i++) { |
| if (i != n) |
| results[j++] = applicationParameters[i]; |
| } |
| applicationParameters = results; |
| |
| } |
| |
| // Inform interested listeners |
| fireContainerEvent("removeApplicationParameter", name); |
| |
| } |
| |
| |
| /** |
| * Add a child Container, only if the proposed child is an implementation |
| * of Wrapper. |
| * |
| * @param child Child container to be added |
| * |
| * @exception IllegalArgumentException if the proposed container is |
| * not an implementation of Wrapper |
| */ |
| @Override |
| public void removeChild(Container child) { |
| |
| if (!(child instanceof Wrapper)) { |
| throw new IllegalArgumentException |
| (sm.getString("standardContext.notWrapper")); |
| } |
| |
| super.removeChild(child); |
| |
| } |
| |
| |
| /** |
| * Remove the specified security constraint from this web application. |
| * |
| * @param constraint Constraint to be removed |
| */ |
| @Override |
| public void removeConstraint(SecurityConstraint constraint) { |
| |
| synchronized (constraintsLock) { |
| |
| // Make sure this constraint is currently present |
| int n = -1; |
| for (int i = 0; i < constraints.length; i++) { |
| if (constraints[i].equals(constraint)) { |
| n = i; |
| break; |
| } |
| } |
| if (n < 0) |
| return; |
| |
| // Remove the specified constraint |
| int j = 0; |
| SecurityConstraint results[] = |
| new SecurityConstraint[constraints.length - 1]; |
| for (int i = 0; i < constraints.length; i++) { |
| if (i != n) |
| results[j++] = constraints[i]; |
| } |
| constraints = results; |
| |
| } |
| |
| // Inform interested listeners |
| fireContainerEvent("removeConstraint", constraint); |
| |
| } |
| |
| |
| /** |
| * Remove the error page for the specified error code or |
| * Java language exception, if it exists; otherwise, no action is taken. |
| * |
| * @param errorPage The error page definition to be removed |
| */ |
| @Override |
| public void removeErrorPage(ErrorPage errorPage) { |
| |
| String exceptionType = errorPage.getExceptionType(); |
| if (exceptionType != null) { |
| synchronized (exceptionPages) { |
| exceptionPages.remove(exceptionType); |
| } |
| } else { |
| synchronized (statusPages) { |
| statusPages.remove(Integer.valueOf(errorPage.getErrorCode())); |
| } |
| } |
| fireContainerEvent("removeErrorPage", errorPage); |
| |
| } |
| |
| |
| /** |
| * Remove the specified filter definition from this Context, if it exists; |
| * otherwise, no action is taken. |
| * |
| * @param filterDef Filter definition to be removed |
| */ |
| @Override |
| public void removeFilterDef(FilterDef filterDef) { |
| |
| synchronized (filterDefs) { |
| filterDefs.remove(filterDef.getFilterName()); |
| } |
| fireContainerEvent("removeFilterDef", filterDef); |
| |
| } |
| |
| |
| /** |
| * Remove a filter mapping from this Context. |
| * |
| * @param filterMap The filter mapping to be removed |
| */ |
| @Override |
| public void removeFilterMap(FilterMap filterMap) { |
| filterMaps.remove(filterMap); |
| // Inform interested listeners |
| fireContainerEvent("removeFilterMap", filterMap); |
| } |
| |
| |
| /** |
| * Remove any message destination with the specified name. |
| * |
| * @param name Name of the message destination to remove |
| */ |
| public void removeMessageDestination(String name) { |
| |
| synchronized (messageDestinations) { |
| messageDestinations.remove(name); |
| } |
| fireContainerEvent("removeMessageDestination", name); |
| |
| } |
| |
| |
| /** |
| * Remove any message destination ref with the specified name. |
| * |
| * @param name Name of the message destination ref to remove |
| */ |
| public void removeMessageDestinationRef(String name) { |
| |
| namingResources.removeMessageDestinationRef(name); |
| fireContainerEvent("removeMessageDestinationRef", name); |
| |
| } |
| |
| |
| /** |
| * Remove the MIME mapping for the specified extension, if it exists; |
| * otherwise, no action is taken. |
| * |
| * @param extension Extension to remove the mapping for |
| */ |
| @Override |
| public void removeMimeMapping(String extension) { |
| |
| synchronized (mimeMappings) { |
| mimeMappings.remove(extension); |
| } |
| fireContainerEvent("removeMimeMapping", extension); |
| |
| } |
| |
| |
| /** |
| * Remove the context initialization parameter with the specified |
| * name, if it exists; otherwise, no action is taken. |
| * |
| * @param name Name of the parameter to remove |
| */ |
| @Override |
| public void removeParameter(String name) { |
| parameters.remove(name); |
| fireContainerEvent("removeParameter", name); |
| } |
| |
| |
| /** |
| * Remove any security role reference for the specified name |
| * |
| * @param role Security role (as used in the application) to remove |
| */ |
| @Override |
| public void removeRoleMapping(String role) { |
| |
| synchronized (roleMappings) { |
| roleMappings.remove(role); |
| } |
| fireContainerEvent("removeRoleMapping", role); |
| |
| } |
| |
| |
| /** |
| * Remove any security role with the specified name. |
| * |
| * @param role Security role to remove |
| */ |
| @Override |
| public void removeSecurityRole(String role) { |
| |
| synchronized (securityRolesLock) { |
| |
| // Make sure this security role is currently present |
| int n = -1; |
| for (int i = 0; i < securityRoles.length; i++) { |
| if (role.equals(securityRoles[i])) { |
| n = i; |
| break; |
| } |
| } |
| if (n < 0) |
| return; |
| |
| // Remove the specified security role |
| int j = 0; |
| String results[] = new String[securityRoles.length - 1]; |
| for (int i = 0; i < securityRoles.length; i++) { |
| if (i != n) |
| results[j++] = securityRoles[i]; |
| } |
| securityRoles = results; |
| |
| } |
| |
| // Inform interested listeners |
| fireContainerEvent("removeSecurityRole", role); |
| |
| } |
| |
| |
| /** |
| * Remove any servlet mapping for the specified pattern, if it exists; |
| * otherwise, no action is taken. |
| * |
| * @param pattern URL pattern of the mapping to remove |
| */ |
| @Override |
| public void removeServletMapping(String pattern) { |
| |
| String name = null; |
| synchronized (servletMappingsLock) { |
| name = servletMappings.remove(pattern); |
| } |
| Wrapper wrapper = (Wrapper) findChild(name); |
| if( wrapper != null ) { |
| wrapper.removeMapping(pattern); |
| } |
| fireContainerEvent("removeServletMapping", pattern); |
| } |
| |
| |
| /** |
| * Remove the specified watched resource name from the list associated |
| * with this Context. |
| * |
| * @param name Name of the watched resource to be removed |
| */ |
| @Override |
| public void removeWatchedResource(String name) { |
| |
| synchronized (watchedResourcesLock) { |
| |
| // Make sure this watched resource is currently present |
| int n = -1; |
| for (int i = 0; i < watchedResources.length; i++) { |
| if (watchedResources[i].equals(name)) { |
| n = i; |
| break; |
| } |
| } |
| if (n < 0) |
| return; |
| |
| // Remove the specified watched resource |
| int j = 0; |
| String results[] = new String[watchedResources.length - 1]; |
| for (int i = 0; i < watchedResources.length; i++) { |
| if (i != n) |
| results[j++] = watchedResources[i]; |
| } |
| watchedResources = results; |
| |
| } |
| |
| fireContainerEvent("removeWatchedResource", name); |
| |
| } |
| |
| |
| /** |
| * Remove the specified welcome file name from the list recognized |
| * by this Context. |
| * |
| * @param name Name of the welcome file to be removed |
| */ |
| @Override |
| public void removeWelcomeFile(String name) { |
| |
| synchronized (welcomeFilesLock) { |
| |
| // Make sure this welcome file is currently present |
| int n = -1; |
| for (int i = 0; i < welcomeFiles.length; i++) { |
| if (welcomeFiles[i].equals(name)) { |
| n = i; |
| break; |
| } |
| } |
| if (n < 0) |
| return; |
| |
| // Remove the specified welcome file |
| int j = 0; |
| String results[] = new String[welcomeFiles.length - 1]; |
| for (int i = 0; i < welcomeFiles.length; i++) { |
| if (i != n) |
| results[j++] = welcomeFiles[i]; |
| } |
| welcomeFiles = results; |
| |
| } |
| |
| // Inform interested listeners |
| if(this.getState().equals(LifecycleState.STARTED)) |
| fireContainerEvent(REMOVE_WELCOME_FILE_EVENT, name); |
| |
| } |
| |
| |
| /** |
| * Remove a class name from the set of LifecycleListener classes that |
| * will be added to newly created Wrappers. |
| * |
| * @param listener Class name of a LifecycleListener class to be removed |
| */ |
| @Override |
| public void removeWrapperLifecycle(String listener) { |
| |
| |
| synchronized (wrapperLifecyclesLock) { |
| |
| // Make sure this lifecycle listener is currently present |
| int n = -1; |
| for (int i = 0; i < wrapperLifecycles.length; i++) { |
| if (wrapperLifecycles[i].equals(listener)) { |
| n = i; |
| break; |
| } |
| } |
| if (n < 0) |
| return; |
| |
| // Remove the specified lifecycle listener |
| int j = 0; |
| String results[] = new String[wrapperLifecycles.length - 1]; |
| for (int i = 0; i < wrapperLifecycles.length; i++) { |
| if (i != n) |
| results[j++] = wrapperLifecycles[i]; |
| } |
| wrapperLifecycles = results; |
| |
| } |
| |
| // Inform interested listeners |
| fireContainerEvent("removeWrapperLifecycle", listener); |
| |
| } |
| |
| |
| /** |
| * Remove a class name from the set of ContainerListener classes that |
| * will be added to newly created Wrappers. |
| * |
| * @param listener Class name of a ContainerListener class to be removed |
| */ |
| @Override |
| public void removeWrapperListener(String listener) { |
| |
| |
| synchronized (wrapperListenersLock) { |
| |
| // Make sure this listener is currently present |
| int n = -1; |
| for (int i = 0; i < wrapperListeners.length; i++) { |
| if (wrapperListeners[i].equals(listener)) { |
| n = i; |
| break; |
| } |
| } |
| if (n < 0) |
| return; |
| |
| // Remove the specified listener |
| int j = 0; |
| String results[] = new String[wrapperListeners.length - 1]; |
| for (int i = 0; i < wrapperListeners.length; i++) { |
| if (i != n) |
| results[j++] = wrapperListeners[i]; |
| } |
| wrapperListeners = results; |
| |
| } |
| |
| // Inform interested listeners |
| fireContainerEvent("removeWrapperListener", listener); |
| |
| } |
| |
| |
| /** |
| * Gets the cumulative processing times of all servlets in this |
| * StandardContext. |
| * |
| * @return Cumulative processing times of all servlets in this |
| * StandardContext |
| */ |
| public long getProcessingTime() { |
| |
| long result = 0; |
| |
| Container[] children = findChildren(); |
| if (children != null) { |
| for( int i=0; i< children.length; i++ ) { |
| result += ((StandardWrapper)children[i]).getProcessingTime(); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Gets the maximum processing time of all servlets in this |
| * StandardContext. |
| * |
| * @return Maximum processing time of all servlets in this |
| * StandardContext |
| */ |
| public long getMaxTime() { |
| |
| long result = 0; |
| long time; |
| |
| Container[] children = findChildren(); |
| if (children != null) { |
| for( int i=0; i< children.length; i++ ) { |
| time = ((StandardWrapper)children[i]).getMaxTime(); |
| if (time > result) |
| result = time; |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Gets the minimum processing time of all servlets in this |
| * StandardContext. |
| * |
| * @return Minimum processing time of all servlets in this |
| * StandardContext |
| */ |
| public long getMinTime() { |
| |
| long result = -1; |
| long time; |
| |
| Container[] children = findChildren(); |
| if (children != null) { |
| for( int i=0; i< children.length; i++ ) { |
| time = ((StandardWrapper)children[i]).getMinTime(); |
| if (result < 0 || time < result) |
| result = time; |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Gets the cumulative request count of all servlets in this |
| * StandardContext. |
| * |
| * @return Cumulative request count of all servlets in this |
| * StandardContext |
| */ |
| public int getRequestCount() { |
| |
| int result = 0; |
| |
| Container[] children = findChildren(); |
| if (children != null) { |
| for( int i=0; i< children.length; i++ ) { |
| result += ((StandardWrapper)children[i]).getRequestCount(); |
| } |
| } |
| |
| return result; |
| } |
| |
| /** |
| * Gets the cumulative error count of all servlets in this |
| * StandardContext. |
| * |
| * @return Cumulative error count of all servlets in this |
| * StandardContext |
| */ |
| public int getErrorCount() { |
| |
| int result = 0; |
| |
| Container[] children = findChildren(); |
| if (children != null) { |
| for( int i=0; i< children.length; i++ ) { |
| result += ((StandardWrapper)children[i]).getErrorCount(); |
| } |
| } |
| |
| return result; |
| } |
| |
| |
| /** |
| * Return the real path for a given virtual path, if possible; otherwise |
| * return <code>null</code>. |
| * |
| * @param path The path to the desired resource |
| */ |
| @Override |
| public String getRealPath(String path) { |
| // The WebResources API expects all paths to start with /. This is a |
| // special case for consistency with earlier Tomcat versions. |
| if ("".equals(path)) { |
| path = "/"; |
| } |
| if (resources != null) { |
| try { |
| WebResource resource = resources.getResource(path); |
| String canonicalPath = resource.getCanonicalPath(); |
| if (canonicalPath == null) { |
| return null; |
| } else if ((resource.isDirectory() && !canonicalPath.endsWith(File.separator) || |
| !resource.exists()) && path.endsWith("/")) { |
| return canonicalPath + File.separatorChar; |
| } else { |
| return canonicalPath; |
| } |
| } catch (IllegalArgumentException iae) { |
| // ServletContext.getRealPath() does not allow this to be thrown |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Hook to register that we need to scan for security annotations. |
| * @param wrapper The wrapper for the Servlet that was added |
| * @return the associated registration |
| */ |
| public ServletRegistration.Dynamic dynamicServletAdded(Wrapper wrapper) { |
| Servlet s = wrapper.getServlet(); |
| if (s != null && createdServlets.contains(s)) { |
| // Mark the wrapper to indicate annotations need to be scanned |
| wrapper.setServletSecurityAnnotationScanRequired(true); |
| } |
| return new ApplicationServletRegistration(wrapper, this); |
| } |
| |
| /** |
| * Hook to track which registrations need annotation scanning |
| * @param servlet the Servlet to add |
| */ |
| public void dynamicServletCreated(Servlet servlet) { |
| createdServlets.add(servlet); |
| } |
| |
| |
| /** |
| * A helper class to manage the filter mappings in a Context. |
| */ |
| private static final class ContextFilterMaps { |
| private final Object lock = new Object(); |
| |
| /** |
| * 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 FilterMap[] array = new FilterMap[0]; |
| |
| /** |
| * Filter mappings added via {@link ServletContext} may have to be |
| * inserted before the mappings in the deployment descriptor but must be |
| * inserted in the order the {@link ServletContext} methods are called. |
| * This isn't an issue for the mappings added after the deployment |
| * descriptor - they are just added to the end - but correctly the |
| * adding mappings before the deployment descriptor mappings requires |
| * knowing where the last 'before' mapping was added. |
| */ |
| private int insertPoint = 0; |
| |
| /** |
| * @return The set of filter mappings |
| */ |
| public FilterMap[] asArray() { |
| synchronized (lock) { |
| return array; |
| } |
| } |
| |
| /** |
| * Add a filter mapping at the end of the current set of filter |
| * mappings. |
| * |
| * @param filterMap |
| * The filter mapping to be added |
| */ |
| public void add(FilterMap filterMap) { |
| synchronized (lock) { |
| FilterMap results[] = Arrays.copyOf(array, array.length + 1); |
| results[array.length] = filterMap; |
| array = results; |
| } |
| } |
| |
| /** |
| * Add a filter mapping before the mappings defined in the deployment |
| * descriptor but after any other mappings added via this method. |
| * |
| * @param filterMap |
| * The filter mapping to be added |
| */ |
| public void addBefore(FilterMap filterMap) { |
| synchronized (lock) { |
| FilterMap results[] = new FilterMap[array.length + 1]; |
| System.arraycopy(array, 0, results, 0, insertPoint); |
| System.arraycopy(array, insertPoint, results, insertPoint + 1, |
| array.length - insertPoint); |
| results[insertPoint] = filterMap; |
| array = results; |
| insertPoint++; |
| } |
| } |
| |
| /** |
| * Remove a filter mapping. |
| * |
| * @param filterMap The filter mapping to be removed |
| */ |
| public void remove(FilterMap filterMap) { |
| synchronized (lock) { |
| // Make sure this filter mapping is currently present |
| int n = -1; |
| for (int i = 0; i < array.length; i++) { |
| if (array[i] == filterMap) { |
| n = i; |
| break; |
| } |
| } |
| if (n < 0) |
| return; |
| |
| // Remove the specified filter mapping |
| FilterMap results[] = new FilterMap[array.length - 1]; |
| System.arraycopy(array, 0, results, 0, n); |
| System.arraycopy(array, n + 1, results, n, (array.length - 1) |
| - n); |
| array = results; |
| if (n < insertPoint) { |
| insertPoint--; |
| } |
| } |
| } |
| } |
| |
| // --------------------------------------------------------- Public Methods |
| |
| |
| /** |
| * Configure and initialize the set of filters for this Context. |
| * @return <code>true</code> if all filter initialization completed |
| * successfully, or <code>false</code> otherwise. |
| */ |
| public boolean filterStart() { |
| |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug("Starting filters"); |
| } |
| // Instantiate and record a FilterConfig for each defined filter |
| boolean ok = true; |
| synchronized (filterConfigs) { |
| filterConfigs.clear(); |
| for (Entry<String,FilterDef> entry : filterDefs.entrySet()) { |
| String name = entry.getKey(); |
| if (getLogger().isDebugEnabled()) { |
| getLogger().debug(" Starting filter '" + name + "'"); |
| } |
| try { |
| ApplicationFilterConfig filterConfig = |
| new ApplicationFilterConfig(this, entry.getValue()); |
| filterConfigs.put(name, filterConfig); |
| } catch (Throwable t) { |
| t = ExceptionUtils.unwrapInvocationTargetException(t); |
| ExceptionUtils.handleThrowable(t); |
| getLogger().error(sm.getString( |
| "standardContext.filterStart", name), t); |
| ok = false; |
| } |
| } |
| } |
| |
| return ok; |
| } |
| |
| |
| /** |
| * Finalize and release the set of filters for this Context. |
| * @return <code>true</code> if all filter finalization completed |
| * successfully, or <code>false</code> otherwise. |
| */ |
| public boolean filterStop() { |
| |
| if (getLogger().isDebugEnabled()) |
| getLogger().debug("Stopping filters"); |
| |
| // Release all Filter and FilterConfig instances |
| synchronized (filterConfigs) { |
| for (Entry<String, ApplicationFilterConfig> entry : filterConfigs.entrySet()) { |
| if (getLogger().isDebugEnabled()) |
| getLogger().debug(" Stopping filter '" + entry.getKey() + "'"); |
| ApplicationFilterConfig filterConfig = entry.getValue(); |
| filterConfig.release(); |
| } |
| filterConfigs.clear(); |
| } |
| return true; |
| |
| } |
| |
| |
| /** |
| * Find and return the initialized <code>FilterConfig</code> for the |
| * specified filter name, if any; otherwise return <code>null</code>. |
| * |
| * @param name Name of the desired filter |
| * @return the filter config object |
| */ |
| public FilterConfig findFilterConfig(String name) { |
| |
| return (filterConfigs.get(name)); |
| |
| } |
| |
| |
| /** |
| * Configure the set of instantiated application event listeners |
| * for this Context. |
| * @return <code>true</code> if all listeners wre |
| * initialized successfully, or <code>false</code> otherwise. |
| */ |
| public boolean listenerStart() { |
| |
| if (log.isDebugEnabled()) |
| log.debug("Configuring application event listeners"); |
| |
| // Instantiate the required listeners |
| String listeners[] = findApplicationListeners(); |
| Object results[] = new Object[listeners.length]; |
| boolean ok = true; |
| for (int i = 0; i < results.length; i++) { |
| if (getLogger().isDebugEnabled()) |
| getLogger().debug(" Configuring event listener class '" + |
| listeners[i] + "'"); |
| try { |
| String listener = listeners[i]; |
| results[i] = getInstanceManager().newInstance(listener); |
| } catch (Throwable t) { |
| t = ExceptionUtils.unwrapInvocationTargetException(t); |
| ExceptionUtils.handleThrowable(t); |
| getLogger().error(sm.getString( |
| "standardContext.applicationListener", listeners[i]), t); |
| ok = false; |
| } |
| } |
| if (!ok) { |
| getLogger().error(sm.getString("standardContext.applicationSkipped")); |
| return false; |
| } |
| |
| // Sort listeners in two arrays |
| ArrayList<Object> eventListeners = new ArrayList<>(); |
| ArrayList<Object> lifecycleListeners = new ArrayList<>(); |
| for (int i = 0; i < results.length; i++) { |
| if ((results[i] instanceof ServletContextAttributeListener) |
| || (results[i] instanceof ServletRequestAttributeListener) |
| || (results[i] instanceof ServletRequestListener) |
| || (results[i] instanceof HttpSessionIdListener) |
| || (results[i] instanceof HttpSessionAttributeListener)) { |
| eventListeners.add(results[i]); |
| } |
| if ((results[i] instanceof ServletContextListener) |
| || (results[i] instanceof HttpSessionListener)) { |
| lifecycleListeners.add(results[i]); |
| } |
| } |
| |
| // Listener instances may have been added directly to this Context by |
| // ServletContextInitializers and other code via the pluggability APIs. |
| // Put them these listeners after the ones defined in web.xml and/or |
| // annotations then overwrite the list of instances with the new, full |
| // list. |
| for (Object eventListener: getApplicationEventListeners()) { |
| eventListeners.add(eventListener); |
| } |
| setApplicationEventListeners(eventListeners.toArray()); |
| for (Object lifecycleListener: getApplicationLifecycleListeners()) { |
| lifecycleListeners.add(lifecycleListener); |
| if (lifecycleListener instanceof ServletContextListener) { |
| noPluggabilityListeners.add(lifecycleListener); |
| } |
| } |
| setApplicationLifecycleListeners(lifecycleListeners.toArray()); |
| |
| // Send application start events |
| |
| if (getLogger().isDebugEnabled()) |
| getLogger().debug("Sending application start events"); |
| |
| // Ensure context is not null |
| getServletContext(); |
| context.setNewServletContextListenerAllowed(false); |
| |
| Object instances[] = getApplicationLifecycleListeners(); |
| if (instances == null || instances.length == 0) { |
| return ok; |
| } |
| |
| ServletContextEvent event = new ServletContextEvent(getServletContext()); |
| ServletContextEvent tldEvent = null; |
| if (noPluggabilityListeners.size() > 0) { |
| noPluggabilityServletContext = new NoPluggabilityServletContext(getServletContext()); |
| tldEvent = new ServletContextEvent(noPluggabilityServletContext); |
| } |
| for (int i = 0; i < instances.length; i++) { |
| if (!(instances[i] instanceof ServletContextListener)) |
| continue; |
| ServletContextListener listener = |
| (ServletContextListener) instances[i]; |
| try { |
| fireContainerEvent("beforeContextInitialized", listener); |
| if (noPluggabilityListeners.contains(listener)) { |
| listener.contextInitialized(tldEvent); |
| } else { |
| listener.contextInitialized(event); |
| } |
| fireContainerEvent("afterContextInitialized", listener); |
| } catch (Throwable t) { |
| ExceptionUtils.handleThrowable(t); |
| fireContainerEvent("afterContextInitialized", listener); |
| getLogger().error |
| (sm.getString("standardContext.listenerStart", |
| instances[i].getClass().getName()), t); |
| ok = false; |
| } |
| } |
| return (ok); |
| |
| } |
| |
| |
| /** |
| * Send an application stop event to all interested listeners. |
| * @return <code>true</code> if all events were sent successfully, |
| * or <code>false</code> otherwise. |
| */ |
| public boolean listenerStop() { |
| |
| if (log.isDebugEnabled()) |
| log.debug("Sending application stop events"); |
| |
| boolean ok = true; |
| Object listeners[] = getApplicationLifecycleListeners(); |
| if (listeners != null && listeners.length > 0) { |
| ServletContextEvent event = new ServletContextEvent(getServletContext()); |
| ServletContextEvent tldEvent = null; |
| if (noPluggabilityServletContext != null) { |
| tldEvent = new ServletContextEvent(noPluggabilityServletContext); |
| } |
| for (int i = 0; i < listeners.length; i++) { |
| int j = (listeners.length - 1) - i; |
| if (listeners[j] == null) |
| continue; |
| if (listeners[j] instanceof ServletContextListener) { |
| ServletContextListener listener = |
| (ServletContextListener) listeners[j]; |
| try { |
| fireContainerEvent("beforeContextDestroyed", listener); |
| if (noPluggabilityListeners.contains(listener)) { |
| listener.contextDestroyed(tldEvent); |
| } else { |
| listener.contextDestroyed(event); |
| } |
| fireContainerEvent("afterContextDestroyed", listener); |
| } catch (Throwable t) { |
| ExceptionUtils.handleThrowable(t); |
| fireContainerEvent("afterContextDestroyed", listener); |
| getLogger().error |
| (sm.getString("standardContext.listenerStop", |
| listeners[j].getClass().getName()), t); |
| ok = false; |
| } |
| } |
| try { |
| if (getInstanceManager() != null) { |
| getInstanceManager().destroyInstance(listeners[j]); |
| } |
| } catch (Throwable t) { |
| t = ExceptionUtils.unwrapInvocationTargetException(t); |
| ExceptionUtils.handleThrowable(t); |
| getLogger().error |
| (sm.getString("standardContext.listenerStop", |
| listeners[j].getClass().getName()), t); |
| ok = false; |
| } |
| } |
| } |
| |
| // Annotation processing |
| listeners = getApplicationEventListeners(); |
| if (listeners != null) { |
| for (int i = 0; i < listeners.length; i++) { |
| int j = (listeners.length - 1) - i; |
| if (listeners[j] == null) |
| continue; |
| try { |
| if (getInstanceManager() != null) { |
| getInstanceManager().destroyInstance(listeners[j]); |
| } |
| } catch (Throwable t) { |
| t = ExceptionUtils.unwrapInvocationTargetException(t); |
| ExceptionUtils.handleThrowable(t); |
| getLogger().error |
| (sm.getString("standardContext.listenerStop", |
| listeners[j].getClass().getName()), t); |
| ok = false; |
| } |
| } |
| } |
| |
| setApplicationEventListeners(null); |
| setApplicationLifecycleListeners(null); |
| |
| noPluggabilityServletContext = null; |
| noPluggabilityListeners.clear(); |
| |
| return ok; |
| } |
| |
| |
| /** |
| * Allocate resources, including proxy. |
| * @throws LifecycleException if a start error occurs |
| */ |
| public void resourcesStart() throws LifecycleException { |
| |
| // Check current status in case resources were added that had already |
| // been started |
| if (!resources.getState().isAvailable()) { |
| resources.start(); |
| } |
| |
| if (effectiveMajorVersion >=3 && addWebinfClassesResources) { |
| WebResource webinfClassesResource = resources.getResource( |
| "/WEB-INF/classes/META-INF/resources"); |
| if (webinfClassesResource.isDirectory()) { |
| getResources().createWebResourceSet( |
| WebResourceRoot.ResourceSetType.RESOURCE_JAR, "/", |
| webinfClassesResource.getURL(), "/"); |
| } |
| } |
| } |
| |
| |
| /** |
| * Deallocate resources and destroy proxy. |
| * @return <code>true</code> if no error occurred |
| */ |
| public boolean resourcesStop() { |
| |
| boolean ok = true; |
| |
| Lock writeLock = resourcesLock.writeLock(); |
| writeLock.lock(); |
| try { |
| if (resources != null) { |
| resources.stop(); |
| } |
| } catch (Throwable t) { |
| ExceptionUtils.handleThrowable(t); |
| log.error(sm.getString("standardContext.resourcesStop"), t); |
| ok = false; |
| } finally { |
| writeLock.unlock(); |
| } |
| |
| return ok; |
| } |
| |
| |
| /** |
| * Load and initialize all servlets marked "load on startup" in the |
| * web application deployment descriptor. |
| * |
| * @param children Array of wrappers for all currently defined |
| * servlets (including those not declared load on startup) |
| * @return <code>true</code> if load on startup was considered successful |
| */ |
| public boolean loadOnStartup(Container children[]) { |
| |
| // Collect "load on startup" servlets that need to be initialized |
| TreeMap<Integer, ArrayList<Wrapper>> map = new TreeMap<>(); |
| for (int i = 0; i < children.length; i++) { |
| Wrapper wrapper = (Wrapper) children[i]; |
| int loadOnStartup = wrapper.getLoadOnStartup(); |
| if (loadOnStartup < 0) |
| continue; |
| Integer key = Integer.valueOf(loadOnStartup); |
| ArrayList<Wrapper> list = map.get(key); |
| if (list == null) { |
| list = new ArrayList<>(); |
| map.put(key, list); |
| } |
| list.add(wrapper); |
| } |
| |
| // Load the collected "load on startup" servlets |
| for (ArrayList<Wrapper> list : map.values()) { |
| for (Wrapper wrapper : list) { |
| try { |
| wrapper.load(); |
| } catch (ServletException e) { |
| getLogger().error(sm.getString("standardContext.loadOnStartup.loadException", |
| getName(), wrapper.getName()), StandardWrapper.getRootCause(e)); |
| // NOTE: load errors (including a servlet that throws |
| // UnavailableException from the init() method) are NOT |
| // fatal to application startup |
| // unless failCtxIfServletStartFails="true" is specified |
| if(getComputedFailCtxIfServletStartFails()) { |
| return false; |
| } |
| } |
| } |
| } |
| return true; |
| |
| } |
| |
| |
| /** |
| * Start this component and implement the requirements |
| * of {@link org.apache.catalina.util.LifecycleBase#startInternal()}. |
| * |
| * @exception LifecycleException if this component detects a fatal error |
| * that prevents this component from being used |
| */ |
| @Override |
| protected synchronized void startInternal() throws LifecycleException { |
| |
| if(log.isDebugEnabled()) |
| log.debug("Starting " + getBaseName()); |
| |
| // Send j2ee.state.starting notification |
| if (this.getObjectName() != null) { |
| Notification notification = new Notification("j2ee.state.starting", |
| this.getObjectName(), sequenceNumber.getAndIncrement()); |
| broadcaster.sendNotification(notification); |
| } |
| |
| setConfigured(false); |
| boolean ok = true; |
| |
| // Currently this is effectively a NO-OP but needs to be called to |
| // ensure the NamingResources follows the correct lifecycle |
| if (namingResources != null) { |
| namingResources.start(); |
| } |
| |
| // Add missing components as necessary |
| if (getResources() == null) { // (1) Required by Loader |
| if (log.isDebugEnabled()) |
| log.debug("Configuring default Resources"); |
| |
| try { |
| setResources(new StandardRoot(this)); |
| } catch (IllegalArgumentException e) { |
| log.error(sm.getString("standardContext.resourcesInit"), e); |
| ok = false; |
| } |
| } |
| if (ok) { |
| resourcesStart(); |
| } |
| |
| if (getLoader() == null) { |
| WebappLoader webappLoader = new WebappLoader(getParentClassLoader()); |
| webappLoader.setDelegate(getDelegate()); |
| setLoader(webappLoader); |
| } |
| |
| // An explicit cookie processor hasn't been specified; use the default |
| if (cookieProcessor == null) { |
| cookieProcessor = new Rfc6265CookieProcessor(); |
| } |
| |
| // Initialize character set mapper |
| getCharsetMapper(); |
| |
| // Post work directory |
| postWorkDirectory(); |
| |
| // Validate required extensions |
| boolean dependencyCheck = true; |
| try { |
| dependencyCheck = ExtensionValidator.validateApplication |
| (getResources(), this); |
| } catch (IOException ioe) { |
| log.error(sm.getString("standardContext.extensionValidationError"), ioe); |
| dependencyCheck = false; |
| } |
| |
| if (!dependencyCheck) { |
| // do not make application available if depency check fails |
| ok = false; |
| } |
| |
| // Reading the "catalina.useNaming" environment variable |
| String useNamingProperty = System.getProperty("catalina.useNaming"); |
| if ((useNamingProperty != null) |
| && (useNamingProperty.equals("false"))) { |
| useNaming = false; |
| } |
| |
| if (ok && isUseNaming()) { |
| if (getNamingContextListener() == null) { |
| NamingContextListener ncl = new NamingContextListener(); |
| ncl.setName(getNamingContextName()); |
| ncl.setExceptionOnFailedWrite(getJndiExceptionOnFailedWrite()); |
| addLifecycleListener(ncl); |
| setNamingContextListener(ncl); |
| } |
| } |
| |
| // Standard container startup |
| if (log.isDebugEnabled()) |
| log.debug("Processing standard container startup"); |
| |
| |
| // Binding thread |
| ClassLoader oldCCL = bindThread(); |
| |
| try { |
| if (ok) { |
| // Start our subordinate components, if any |
| Loader loader = getLoader(); |
| if (loader instanceof Lifecycle) { |
| ((Lifecycle) loader).start(); |
| } |
| |
| // since the loader just started, the webapp classloader is now |
| // created. |
| setClassLoaderProperty("clearReferencesRmiTargets", |
| getClearReferencesRmiTargets()); |
| setClassLoaderProperty("clearReferencesStopThreads", |
| getClearReferencesStopThreads()); |
| setClassLoaderProperty("clearReferencesStopTimerThreads", |
| getClearReferencesStopTimerThreads()); |
| setClassLoaderProperty("clearReferencesHttpClientKeepAliveThread", |
| getClearReferencesHttpClientKeepAliveThread()); |
| |
| // By calling unbindThread and bindThread in a row, we setup the |
| // current Thread CCL to be the webapp classloader |
| unbindThread(oldCCL); |
| oldCCL = bindThread(); |
| |
| // Initialize logger again. Other components might have used it |
| // too early, so it should be reset. |
| logger = null; |
| getLogger(); |
| |
| Realm realm = getRealmInternal(); |
| if(null != realm) { |
| if (realm instanceof Lifecycle) { |
| ((Lifecycle) realm).start(); |
| } |
| |
| // Place the CredentialHandler into the ServletContext so |
| // applications can have access to it. Wrap it in a "safe" |
| // handler so application's can't modify it. |
| CredentialHandler safeHandler = new CredentialHandler() { |
| @Override |
| public boolean matches(String inputCredentials, String storedCredentials) { |
| return getRealmInternal().getCredentialHandler().matches(inputCredentials, storedCredentials); |
| } |
| |
| @Override |
| public String mutate(String inputCredentials) { |
| return getRealmInternal().getCredentialHandler().mutate(inputCredentials); |
| } |
| }; |
| context.setAttribute(Globals.CREDENTIAL_HANDLER, safeHandler); |
| } |
| |
| // Notify our interested LifecycleListeners |
| fireLifecycleEvent(Lifecycle.CONFIGURE_START_EVENT, null); |
| |
| // Start our child containers, if not already started |
| for (Container child : findChildren()) { |
| if (!child.getState().isAvailable()) { |
| child.start(); |
| } |
| } |
| |
| // Start the Valves in our pipeline (including the basic), |
| // if any |
| if (pipeline instanceof Lifecycle) { |
| ((Lifecycle) pipeline).start(); |
| } |
| |
| // Acquire clustered manager |
| Manager contextManager = null; |
| Manager manager = getManager(); |
| if (manager == null) { |
| if (log.isDebugEnabled()) { |
| log.debug(sm.getString("standardContext.cluster.noManager", |
| Boolean.valueOf((getCluster() != null)), |
| Boolean.valueOf(distributable))); |
| } |
| if ( (getCluster() != null) && distributable) { |
| try { |
| contextManager = getCluster().createManager(getName()); |
| } catch (Exception ex) { |
| log.error("standardContext.clusterFail", ex); |
| ok = false; |
| } |
| } else { |
| contextManager = new StandardManager(); |
| } |
| } |
| |
| // Configure default manager if none was specified |
| if (contextManager != null) { |
| if (log.isDebugEnabled()) { |
| log.debug(sm.getString("standardContext.manager", |
| contextManager.getClass().getName())); |
| } |
| setManager(contextManager); |
| } |
| |
| if (manager!=null && (getCluster() != null) && distributable) { |
| //let the cluster know that there is a context that is distributable |
| //and that it has its own manager |
| getCluster().registerManager(manager); |
| } |
| } |
| |
| if (!getConfigured()) { |
| log.error(sm.getString("standardContext.configurationFail")); |
| ok = false; |
| } |
| |
| // We put the resources into the servlet context |
| if (ok) |
| getServletContext().setAttribute |
| (Globals.RESOURCES_ATTR, getResources()); |
| |
| if (ok ) { |
| if (getInstanceManager() == null) { |
| javax.naming.Context context = null; |
| if (isUseNaming() && getNamingContextListener() != null) { |
| context = getNamingContextListener().getEnvContext(); |
| } |
| Map<String, Map<String, String>> injectionMap = buildInjectionMap( |
| getIgnoreAnnotations() ? new NamingResourcesImpl(): getNamingResources()); |
| setInstanceManager(new DefaultInstanceManager(context, |
| injectionMap, this, this.getClass().getClassLoader())); |
| } |
| getServletContext().setAttribute( |
| InstanceManager.class.getName(), getInstanceManager()); |
| InstanceManagerBindings.bind(getLoader().getClassLoader(), getInstanceManager()); |
| } |
| |
| // Create context attributes that will be required |
| if (ok) { |
| getServletContext().setAttribute( |
| JarScanner.class.getName(), getJarScanner()); |
| } |
| |
| // Set up the context init params |
| mergeParameters(); |
| |
| // Call ServletContainerInitializers |
| for (Map.Entry<ServletContainerInitializer, Set<Class<?>>> entry : |
| initializers.entrySet()) { |
| try { |
| entry.getKey().onStartup(entry.getValue(), |
| getServletContext()); |
| } catch (ServletException e) { |
| log.error(sm.getString("standardContext.sciFail"), e); |
| ok = false; |
| break; |
| } |
| } |
| |
| // Configure and call application event listeners |
| if (ok) { |
| if (!listenerStart()) { |
| log.error(sm.getString("standardContext.listenerFail")); |
| ok = false; |
| } |
| } |
| |
| // Check constraints for uncovered HTTP methods |
| // Needs to be after SCIs and listeners as they may programatically |
| // change constraints |
| if (ok) { |
| checkConstraintsForUncoveredMethods(findConstraints()); |
| } |
| |
| try { |
| // Start manager |
| Manager manager = getManager(); |
| if (manager instanceof Lifecycle) { |
| ((Lifecycle) manager).start(); |
| } |
| } catch(Exception e) { |
| log.error(sm.getString("standardContext.managerFail"), e); |
| ok = false; |
| } |
| |
| // Configure and call application filters |
| if (ok) { |
| if (!filterStart()) { |
| log.error(sm.getString("standardContext.filterFail")); |
| ok = false; |
| } |
| } |
| |
| // Load and initialize all "load on startup" servlets |
| if (ok) { |
| if (!loadOnStartup(findChildren())){ |
| log.error(sm.getString("standardContext.servletFail")); |
| ok = false; |
| } |
| } |
| |
| // Start ContainerBackgroundProcessor thread |
| super.threadStart(); |
| } finally { |
| // Unbinding thread |
| unbindThread(oldCCL); |
| } |
| |
| // Set available status depending upon startup success |
| if (ok) { |
| if (log.isDebugEnabled()) |
| log.debug("Starting completed"); |
| } else { |
| log.error(sm.getString("standardContext.startFailed", getName())); |
| } |
| |
| startTime=System.currentTimeMillis(); |
| |
| // Send j2ee.state.running notification |
| if (ok && (this.getObjectName() != null)) { |
| Notification notification = |
| new Notification("j2ee.state.running", this.getObjectName(), |
| sequenceNumber.getAndIncrement()); |
| broadcaster.sendNotification(notification); |
| } |
| |
| // The WebResources implementation caches references to JAR files. On |
| // some platforms these references may lock the JAR files. Since web |
| // application start is likely to have read from lots of JARs, trigger |
| // a clean-up now. |
| getResources().gc(); |
| |
| // Reinitializing if something went wrong |
| if (!ok) { |
| setState(LifecycleState.FAILED); |
| } else { |
| setState(LifecycleState.STARTING); |
| } |
| } |
| |
| |
| private void checkConstraintsForUncoveredMethods( |
| SecurityConstraint[] constraints) { |
| SecurityConstraint[] newConstraints = |
| SecurityConstraint.findUncoveredHttpMethods(constraints, |
| getDenyUncoveredHttpMethods(), getLogger()); |
| for (SecurityConstraint constraint : newConstraints) { |
| addConstraint(constraint); |
| } |
| } |
| |
| |
| private void setClassLoaderProperty(String name, boolean value) { |
| ClassLoader cl = getLoader().getClassLoader(); |
| if (!IntrospectionUtils.setProperty(cl, name, Boolean.toString(value))) { |
| // Failed to set |
| log.info(sm.getString( |
| "standardContext.webappClassLoader.missingProperty", |
| name, Boolean.toString(value))); |
| } |
| } |
| |
| private Map<String, Map<String, String>> buildInjectionMap(NamingResourcesImpl namingResources) { |
| Map<String, Map<String, String>> injectionMap = new HashMap<>(); |
| for (Injectable resource: namingResources.findLocalEjbs()) { |
| addInjectionTarget(resource, injectionMap); |
| } |
| for (Injectable resource: namingResources.findEjbs()) { |
| addInjectionTarget(resource, injectionMap); |
| } |
| for (Injectable resource: namingResources.findEnvironments()) { |
| addInjectionTarget(resource, injectionMap); |
| } |
| for (Injectable resource: namingResources.findMessageDestinationRefs()) { |
| addInjectionTarget(resource, injectionMap); |
| } |
| for (Injectable resource: namingResources.findResourceEnvRefs()) { |
| addInjectionTarget(resource, injectionMap); |
| } |
| for (Injectable resource: namingResources.findResources()) { |
| addInjectionTarget(resource, injectionMap); |
| } |
| for (Injectable resource: namingResources.findServices()) { |
| addInjectionTarget(resource, injectionMap); |
| } |
| return injectionMap; |
| } |
| |
| private void addInjectionTarget(Injectable resource, Map<String, Map<String, String>> injectionMap) { |
| List<InjectionTarget> injectionTargets = resource.getInjectionTargets(); |
| if (injectionTargets != null && injectionTargets.size() > 0) { |
| String jndiName = resource.getName(); |
| for (InjectionTarget injectionTarget: injectionTargets) { |
| String clazz = injectionTarget.getTargetClass(); |
| Map<String, String> injections = injectionMap.get(clazz); |
| if (injections == null) { |
| injections = new HashMap<>(); |
| injectionMap.put(clazz, injections); |
| } |
| injections.put(injectionTarget.getTargetName(), jndiName); |
| } |
| } |
| } |
| |
| |
| |
| /** |
| * Merge the context initialization parameters specified in the application |
| * deployment descriptor with the application parameters described in the |
| * server configuration, respecting the <code>override</code> property of |
| * the application parameters appropriately. |
| */ |
| private void mergeParameters() { |
| Map<String,String> mergedParams = new HashMap<>(); |
| |
| String names[] = findParameters(); |
| for (int i = 0; i < names.length; i++) { |
| mergedParams.put(names[i], findParameter(names[i])); |
| } |
| |
| ApplicationParameter params[] = findApplicationParameters(); |
| for (int i = 0; i < params.length; i++) { |
| if (params[i].getOverride()) { |
| if (mergedParams.get(params[i].getName()) == null) { |
| mergedParams.put(params[i].getName(), |
| params[i].getValue()); |
| } |
| } else { |
| mergedParams.put(params[i].getName(), params[i].getValue()); |
| } |
| } |
| |
| ServletContext sc = getServletContext(); |
| for (Map.Entry<String,String> entry : mergedParams.entrySet()) { |
| sc.setInitParameter(entry.getKey(), entry.getValue()); |
| } |
| |
| } |
| |
| |
| /** |
| * Stop this component and implement the requirements |
| * of {@link org.apache.catalina.util.LifecycleBase#stopInternal()}. |
| * |
| * @exception LifecycleException if this component detects a fatal error |
| * that prevents this component from being used |
| */ |
| @Override |
| protected synchronized void stopInternal() throws LifecycleException { |
| |
| // Send j2ee.state.stopping notification |
| if (this.getObjectName() != null) { |
| Notification notification = |
| new Notification("j2ee.state.stopping", this.getObjectName(), |
| sequenceNumber.getAndIncrement()); |
| broadcaster.sendNotification(notification); |
| } |
| |
| setState(LifecycleState.STOPPING); |
| |
| // Binding thread |
| ClassLoader oldCCL = bindThread(); |
| |
| try { |
| // Stop our child containers, if any |
| final Container[] children = findChildren(); |
| |
| // Stop ContainerBackgroundProcessor thread |
| threadStop(); |
| |
| for (int i = 0; i < children.length; i++) { |
| children[i].stop(); |
| } |
| |
| // Stop our filters |
| filterStop(); |
| |
| Manager manager = getManager(); |
| if (manager instanceof Lifecycle && ((Lifecycle) manager).getState().isAvailable()) { |
| ((Lifecycle) manager).stop(); |
| } |
| |
| // Stop our application listeners |
| listenerStop(); |
| |
| // Finalize our character set mapper |
| setCharsetMapper(null); |
| |
| // Normal container shutdown processing |
| if (log.isDebugEnabled()) |
| log.debug("Processing standard container shutdown"); |
| |
| // JNDI resources are unbound in CONFIGURE_STOP_EVENT so stop |
| // naming resources before they are unbound since NamingResoucres |
| // does a JNDI lookup to retrieve the resource. This needs to be |
| // after the application has finished with the resource |
| if (namingResources != null) { |
| namingResources.stop(); |
| } |
| |
| fireLifecycleEvent(Lifecycle.CONFIGURE_STOP_EVENT, null); |
| |
| // Stop the Valves in our pipeline (including the basic), if any |
| if (pipeline instanceof Lifecycle && |
| ((Lifecycle) pipeline).getState().isAvailable()) { |
| ((Lifecycle) pipeline).stop(); |
| } |
| |
| // Clear all application-originated servlet context attributes |
| if (context != null) |
| context.clearAttributes(); |
| |
| Realm realm = getRealmInternal(); |
| if (realm instanceof Lifecycle) { |
| ((Lifecycle) realm).stop(); |
| } |
| Loader loader = getLoader(); |
| if (loader instanceof Lifecycle) { |
| ClassLoader classLoader = loader.getClassLoader(); |
| ((Lifecycle) loader).stop(); |
| if (classLoader != null) { |
| InstanceManagerBindings.unbind(classLoader); |
| } |
| } |
| |
| // Stop resources |
| resourcesStop(); |
| |
| } finally { |
| |
| // Unbinding thread |
| unbindThread(oldCCL); |
| |
| } |
| |
| // Send j2ee.state.stopped notification |
| if (this.getObjectName() != null) { |
| Notification notification = |
| new Notification("j2ee.state.stopped", this.getObjectName(), |
| sequenceNumber.getAndIncrement()); |
| broadcaster.sendNotification(notification); |
| } |
| |
| // Reset application context |
| context = null; |
| |
| // This object will no longer be visible or used. |
| try { |
| resetContext(); |
| } catch( Exception ex ) { |
| log.error( "Error reseting context " + this + " " + ex, ex ); |
| } |
| |
| //reset the instance manager |
| setInstanceManager(null); |
| |
| if (log.isDebugEnabled()) |
| log.debug("Stopping complete"); |
| |
| } |
| |
| /** Destroy needs to clean up the context completely. |
| * |
| * The problem is that undoing all the config in start() and restoring |
| * a 'fresh' state is impossible. After stop()/destroy()/init()/start() |
| * we should have the same state as if a fresh start was done - i.e |
| * read modified web.xml, etc. This can only be done by completely |
| * removing the context object and remapping a new one, or by cleaning |
| * up everything. |
| * |
| * XXX Should this be done in stop() ? |
| * |
| */ |
| @Override |
| protected void destroyInternal() throws LifecycleException { |
| |
| // If in state NEW when destroy is called, the object name will never |
| // have been set so the notification can't be created |
| if (getObjectName() != null) { |
| // Send j2ee.object.deleted notification |
| Notification notification = |
| new Notification("j2ee.object.deleted", this.getObjectName(), |
| sequenceNumber.getAndIncrement()); |
| broadcaster.sendNotification(notification); |
| } |
| |
| if (namingResources != null) { |
| namingResources.destroy(); |
| } |
| |
| Loader loader = getLoader(); |
| if (loader instanceof Lifecycle) { |
| ((Lifecycle) loader).destroy(); |
| } |
| |
| Manager manager = getManager(); |
| if (manager instanceof Lifecycle) { |
| ((Lifecycle) manager).destroy(); |
| } |
| |
| if (resources != null) { |
| resources.destroy(); |
| } |
| |
| super.destroyInternal(); |
| } |
| |
| |
| @Override |
| public void backgroundProcess() { |
| |
| if (!getState().isAvailable()) |
| return; |
| |
| Loader loader = getLoader(); |
| if (loader != null) { |
| try { |
| loader.backgroundProcess(); |
| } catch (Exception e) { |
| log.warn(sm.getString( |
| "standardContext.backgroundProcess.loader", loader), e); |
| } |
| } |
| Manager manager = getManager(); |
| if (manager != null) { |
| try { |
| manager.backgroundProcess(); |
| } catch (Exception e) { |
| log.warn(sm.getString( |
| "standardContext.backgroundProcess.manager", manager), |
| e); |
| } |
| } |
| WebResourceRoot resources = getResources(); |
| if (resources != null) { |
| try { |
| resources.backgroundProcess(); |
| } catch (Exception e) { |
| log.warn(sm.getString( |
| "standardContext.backgroundProcess.resources", |
| resources), e); |
| } |
| } |
| super.backgroundProcess(); |
| } |
| |
| |
| private void resetContext() throws Exception { |
| // Restore the original state ( pre reading web.xml in start ) |
| // If you extend this - override this method and make sure to clean up |
| |
| // Don't reset anything that is read from a <Context.../> element since |
| // <Context .../> elements are read at initialisation will not be read |
| // again for this object |
| for (Container child : findChildren()) { |
| removeChild(child); |
| } |
| startupTime = 0; |
| startTime = 0; |
| tldScanTime = 0; |
| |
| // Bugzilla 32867 |
| distributable = false; |
| |
| applicationListeners = new String[0]; |
| applicationEventListenersList.clear(); |
| applicationLifecycleListenersObjects = new Object[0]; |
| jspConfigDescriptor = null; |
| |
| initializers.clear(); |
| |
| createdServlets.clear(); |
| |
| postConstructMethods.clear(); |
| preDestroyMethods.clear(); |
| |
| if(log.isDebugEnabled()) |
| log.debug("resetContext " + getObjectName()); |
| } |
| |
| /** |
| * Return a String representation of this component. |
| */ |
| @Override |
| public String toString() { |
| |
| StringBuilder sb = new StringBuilder(); |
| if (getParent() != null) { |
| sb.append(getParent().toString()); |
| sb.append("."); |
| } |
| sb.append("StandardContext["); |
| sb.append(getName()); |
| sb.append("]"); |
| return (sb.toString()); |
| |
| } |
| |
| |
| // ------------------------------------------------------ Protected Methods |
| |
| |
| /** |
| * Adjust the URL pattern to begin with a leading slash, if appropriate |
| * (i.e. we are running a servlet 2.2 application). Otherwise, return |
| * the specified URL pattern unchanged. |
| * |
| * @param urlPattern The URL pattern to be adjusted (if needed) |
| * and returned |
| * @return the URL pattern with a leading slash if needed |
| */ |
| protected String adjustURLPattern(String urlPattern) { |
| |
| if (urlPattern == null) |
| return (urlPattern); |
| if (urlPattern.startsWith("/") || urlPattern.startsWith("*.")) |
| return (urlPattern); |
| if (!isServlet22()) |
| return (urlPattern); |
| if(log.isDebugEnabled()) |
| log.debug(sm.getString("standardContext.urlPattern.patternWarning", |
| urlPattern)); |
| return ("/" + urlPattern); |
| |
| } |
| |
| |
| /** |
| * Are we processing a version 2.2 deployment descriptor? |
| * |
| * @return <code>true</code> if running a legacy Servlet 2.2 application |
| */ |
| @Override |
| public boolean isServlet22() { |
| return XmlIdentifiers.WEB_22_PUBLIC.equals(publicId); |
| } |
| |
| |
| @Override |
| public Set<String> addServletSecurity( |
| ServletRegistration.Dynamic registration, |
| ServletSecurityElement servletSecurityElement) { |
| |
| Set<String> conflicts = new HashSet<>(); |
| |
| Collection<String> urlPatterns = registration.getMappings(); |
| for (String urlPattern : urlPatterns) { |
| boolean foundConflict = false; |
| |
| SecurityConstraint[] securityConstraints = |
| findConstraints(); |
| for (SecurityConstraint securityConstraint : securityConstraints) { |
| |
| SecurityCollection[] collections = |
| securityConstraint.findCollections(); |
| for (SecurityCollection collection : collections) { |
| if (collection.findPattern(urlPattern)) { |
| // First pattern found will indicate if there is a |
| // conflict since for any given pattern all matching |
| // constraints will be from either the descriptor or |
| // not. It is not permitted to have a mixture |
| if (collection.isFromDescriptor()) { |
| // Skip this pattern |
| foundConflict = true; |
| conflicts.add(urlPattern); |
| break; |
| } else { |
| // Need to overwrite constraint for this pattern |
| collection.removePattern(urlPattern); |
| // If the collection is now empty, remove it |
| if (collection.findPatterns().length == 0) { |
| securityConstraint.removeCollection(collection); |
| } |
| } |
| } |
| } |
| |
| // If the constraint now has no collections - remove it |
| if (securityConstraint.findCollections().length == 0) { |
| removeConstraint(securityConstraint); |
| } |
| |
| // No need to check other constraints for the current pattern |
| // once a conflict has been found |
| if (foundConflict) { |
| break; |
| } |
| } |
| |
| // Note: For progammatically added Servlets this may not be the |
| // complete set of security constraints since additional |
| // URL patterns can be added after the application has called |
| // setSecurity. For all programmatically added servilets, the |
| // #dynamicServletAdded() method sets a flag that ensures that |
| // the constraints are re-evaluated before the servlet is |
| // first used |
| |
| // If the pattern did not conflict, add the new constraint(s). |
| if (!foundConflict) { |
| SecurityConstraint[] newSecurityConstraints = |
| SecurityConstraint.createConstraints( |
| servletSecurityElement, |
| urlPattern); |
| for (SecurityConstraint securityConstraint : |
| newSecurityConstraints) { |
| addConstraint(securityConstraint); |
| } |
| |
| checkConstraintsForUncoveredMethods(newSecurityConstraints); |
| } |
| } |
| |
| return conflicts; |
| } |
| |
| |
| /** |
| * Bind current thread, both for CL purposes and for JNDI ENC support |
| * during : startup, shutdown and reloading of the context. |
| * |
| * @return the previous context class loader |
| */ |
| protected ClassLoader bindThread() { |
| |
| ClassLoader oldContextClassLoader = bind(false, null); |
| |
| if (isUseNaming()) { |
| try { |
| ContextBindings.bindThread(this, getNamingToken()); |
| } catch (NamingException e) { |
| // Silent catch, as this is a normal case during the early |
| // startup stages |
| } |
| } |
| |
| return oldContextClassLoader; |
| } |
| |
| |
| /** |
| * Unbind thread and restore the specified context classloader. |
| * |
| * @param oldContextClassLoader the previous classloader |
| */ |
| protected void unbindThread(ClassLoader oldContextClassLoader) { |
| |
| if (isUseNaming()) { |
| ContextBindings.unbindThread(this, getNamingToken()); |
| } |
| |
| unbind(false, oldContextClassLoader); |
| } |
| |
| |
| @Override |
| public ClassLoader bind(boolean usePrivilegedAction, ClassLoader originalClassLoader) { |
| Loader loader = getLoader(); |
| ClassLoader webApplicationClassLoader = null; |
| if (loader != null) { |
| webApplicationClassLoader = loader.getClassLoader(); |
| } |
| |
| if (originalClassLoader == null) { |
| if (usePrivilegedAction) { |
| PrivilegedAction<ClassLoader> pa = new PrivilegedGetTccl(); |
| originalClassLoader = AccessController.doPrivileged(pa); |
| } else { |
| originalClassLoader = Thread.currentThread().getContextClassLoader(); |
| } |
| } |
| |
| if (webApplicationClassLoader == null || |
| webApplicationClassLoader == originalClassLoader) { |
| // Not possible or not necessary to switch class loaders. Return |
| // null to indicate this. |
| return null; |
| } |
| |
| ThreadBindingListener threadBindingListener = getThreadBindingListener(); |
| |
| if (usePrivilegedAction) { |
| PrivilegedAction<Void> pa = new PrivilegedSetTccl(webApplicationClassLoader); |
| AccessController.doPrivileged(pa); |
| } else { |
| Thread.currentThread().setContextClassLoader(webApplicationClassLoader); |
| } |
| if (threadBindingListener != null) { |
| try { |
| threadBindingListener.bind(); |
| } catch (Throwable t) { |
| ExceptionUtils.handleThrowable(t); |
| log.error(sm.getString( |
| "standardContext.threadBindingListenerError", getName()), t); |
| } |
| } |
| |
| return originalClassLoader; |
| } |
| |
| |
| @Override |
| public void unbind(boolean usePrivilegedAction, ClassLoader originalClassLoader) { |
| if (originalClassLoader == null) { |
| return; |
| } |
| |
| if (threadBindingListener != null) { |
| try { |
| threadBindingListener.unbind(); |
| } catch (Throwable t) { |
| ExceptionUtils.handleThrowable(t); |
| log.error(sm.getString( |
| "standardContext.threadBindingListenerError", getName()), t); |
| } |
| } |
| |
| if (usePrivilegedAction) { |
| PrivilegedAction<Void> pa = new PrivilegedSetTccl(originalClassLoader); |
| AccessController.doPrivileged(pa); |
| } else { |
| Thread.currentThread().setContextClassLoader(originalClassLoader); |
| } |
| } |
| |
| |
| /** |
| * Get naming context full name. |
| * |
| * @return the context name |
| */ |
| private String getNamingContextName() { |
| if (namingContextName == null) { |
| Container parent = getParent(); |
| if (parent == null) { |
| namingContextName = getName(); |
| } else { |
| Stack<String> stk = new Stack<>(); |
| StringBuilder buff = new StringBuilder(); |
| while (parent != null) { |
| stk.push(parent.getName()); |
| parent = parent.getParent(); |
| } |
| while (!stk.empty()) { |
| buff.append("/" + stk.pop()); |
| } |
| buff.append(getName()); |
| namingContextName = buff.toString(); |
| } |
| } |
| return namingContextName; |
| } |
| |
| |
| /** |
| * Naming context listener accessor. |
| * |
| * @return the naming context listener associated with the webapp |
| */ |
| public NamingContextListener getNamingContextListener() { |
| return namingContextListener; |
| } |
| |
| |
| /** |
| * Naming context listener setter. |
| * |
| * @param namingContextListener the new naming context listener |
| */ |
| public void setNamingContextListener(NamingContextListener namingContextListener) { |
| this.namingContextListener = namingContextListener; |
| } |
| |
| |
| /** |
| * @return the request processing paused flag for this Context. |
| */ |
| @Override |
| public boolean getPaused() { |
| |
| return (this.paused); |
| |
| } |
| |
| |
| @Override |
| public boolean fireRequestInitEvent(ServletRequest request) { |
| |
| Object instances[] = getApplicationEventListeners(); |
| |
| if ((instances != null) && (instances.length > 0)) { |
| |
| ServletRequestEvent event = |
| new ServletRequestEvent(getServletContext(), request); |
| |
| for (int i = 0; i < instances.length; i++) { |
| if (instances[i] == null) |
| continue; |
| if (!(instances[i] instanceof ServletRequestListener)) |
| continue; |
| ServletRequestListener listener = |
| (ServletRequestListener) instances[i]; |
| |
| try { |
| listener.requestInitialized(event); |
| } catch (Throwable t) { |
| ExceptionUtils.handleThrowable(t); |
| getLogger().error(sm.getString( |
| "standardContext.requestListener.requestInit", |
| instances[i].getClass().getName()), t); |
| request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t); |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| |
| @Override |
| public boolean fireRequestDestroyEvent(ServletRequest request) { |
| Object instances[] = getApplicationEventListeners(); |
| |
| if ((instances != null) && (instances.length > 0)) { |
| |
| ServletRequestEvent event = |
| new ServletRequestEvent(getServletContext(), request); |
| |
| for (int i = 0; i < instances.length; i++) { |
| int j = (instances.length -1) -i; |
| if (instances[j] == null) |
| continue; |
| if (!(instances[j] instanceof ServletRequestListener)) |
| continue; |
| ServletRequestListener listener = |
| (ServletRequestListener) instances[j]; |
| |
| try { |
| listener.requestDestroyed(event); |
| } catch (Throwable t) { |
| ExceptionUtils.handleThrowable(t); |
| getLogger().error(sm.getString( |
| "standardContext.requestListener.requestInit", |
| instances[j].getClass().getName()), t); |
| request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t); |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| |
| @Override |
| public void addPostConstructMethod(String clazz, String method) { |
| if (clazz == null || method == null) |
| throw new IllegalArgumentException( |
| sm.getString("standardContext.postconstruct.required")); |
| if (postConstructMethods.get(clazz) != null) |
| throw new IllegalArgumentException(sm.getString( |
| "standardContext.postconstruct.duplicate", clazz)); |
| |
| postConstructMethods.put(clazz, method); |
| fireContainerEvent("addPostConstructMethod", clazz); |
| } |
| |
| |
| @Override |
| public void removePostConstructMethod(String clazz) { |
| postConstructMethods.remove(clazz); |
| fireContainerEvent("removePostConstructMethod", clazz); |
| } |
| |
| |
| @Override |
| public void addPreDestroyMethod(String clazz, String method) { |
| if (clazz == null || method == null) |
| throw new IllegalArgumentException( |
| sm.getString("standardContext.predestroy.required")); |
| if (preDestroyMethods.get(clazz) != null) |
| throw new IllegalArgumentException(sm.getString( |
| "standardContext.predestroy.duplicate", clazz)); |
| |
| preDestroyMethods.put(clazz, method); |
| fireContainerEvent("addPreDestroyMethod", clazz); |
| } |
| |
| |
| @Override |
| public void removePreDestroyMethod(String clazz) { |
| preDestroyMethods.remove(clazz); |
| fireContainerEvent("removePreDestroyMethod", clazz); |
| } |
| |
| |
| @Override |
| public String findPostConstructMethod(String clazz) { |
| return postConstructMethods.get(clazz); |
| } |
| |
| |
| @Override |
| public String findPreDestroyMethod(String clazz) { |
| return preDestroyMethods.get(clazz); |
| } |
| |
| |
| @Override |
| public Map<String, String> findPostConstructMethods() { |
| return postConstructMethods; |
| } |
| |
| |
| @Override |
| public Map<String, String> findPreDestroyMethods() { |
| return preDestroyMethods; |
| } |
| |
| |
| /** |
| * Set the appropriate context attribute for our work directory. |
| */ |
| private void postWorkDirectory() { |
| |
| // Acquire (or calculate) the work directory path |
| String workDir = getWorkDir(); |
| if (workDir == null || workDir.length() == 0) { |
| |
| // Retrieve our parent (normally a host) name |
| String hostName = null; |
| String engineName = null; |
| String hostWorkDir = null; |
| Container parentHost = getParent(); |
| if (parentHost != null) { |
| hostName = parentHost.getName(); |
| if (parentHost instanceof StandardHost) { |
| hostWorkDir = ((StandardHost)parentHost).getWorkDir(); |
| } |
| Container parentEngine = parentHost.getParent(); |
| if (parentEngine != null) { |
| engineName = parentEngine.getName(); |
| } |
| } |
| if ((hostName == null) || (hostName.length() < 1)) |
| hostName = "_"; |
| if ((engineName == null) || (engineName.length() < 1)) |
| engineName = "_"; |
| |
| String temp = getBaseName(); |
| if (temp.startsWith("/")) |
| temp = temp.substring(1); |
| temp = temp.replace('/', '_'); |
| temp = temp.replace('\\', '_'); |
| if (temp.length() < 1) |
| temp = ContextName.ROOT_NAME; |
| if (hostWorkDir != null ) { |
| workDir = hostWorkDir + File.separator + temp; |
| } else { |
| workDir = "work" + File.separator + engineName + |
| File.separator + hostName + File.separator + temp; |
| } |
| setWorkDir(workDir); |
| } |
| |
| // Create this directory if necessary |
| File dir = new File(workDir); |
| if (!dir.isAbsolute()) { |
| String catalinaHomePath = null; |
| try { |
| catalinaHomePath = getCatalinaBase().getCanonicalPath(); |
| dir = new File(catalinaHomePath, workDir); |
| } catch (IOException e) { |
| log.warn(sm.getString("standardContext.workCreateException", |
| workDir, catalinaHomePath, getName()), e); |
| } |
| } |
| if (!dir.mkdirs() && !dir.isDirectory()) { |
| log.warn(sm.getString("standardContext.workCreateFail", dir, |
| getName())); |
| } |
| |
| // Set the appropriate servlet context attribute |
| if (context == null) { |
| getServletContext(); |
| } |
| context.setAttribute(ServletContext.TEMPDIR, dir); |
| context.setAttributeReadOnly(ServletContext.TEMPDIR); |
| } |
| |
| |
| /** |
| * Set the request processing paused flag for this Context. |
| * |
| * @param paused The new request processing paused flag |
| */ |
| private void setPaused(boolean paused) { |
| |
| this.paused = paused; |
| |
| } |
| |
| |
| /** |
| * Validate the syntax of a proposed <code><url-pattern></code> |
| * for conformance with specification requirements. |
| * |
| * @param urlPattern URL pattern to be validated |
| * @return <code>true</code> if the URL pattern is conformant |
| */ |
| private boolean validateURLPattern(String urlPattern) { |
| |
| if (urlPattern == null) |
| return false; |
| if (urlPattern.indexOf('\n') >= 0 || urlPattern.indexOf('\r') >= 0) { |
| return false; |
| } |
| if (urlPattern.equals("")) { |
| return true; |
| } |
| if (urlPattern.startsWith("*.")) { |
| if (urlPattern.indexOf('/') < 0) { |
| checkUnusualURLPattern(urlPattern); |
| return true; |
| } else |
| return false; |
| } |
| if ( (urlPattern.startsWith("/")) && |
| (urlPattern.indexOf("*.") < 0)) { |
| checkUnusualURLPattern(urlPattern); |
| return true; |
| } else |
| return false; |
| |
| } |
| |
| |
| /** |
| * Check for unusual but valid <code><url-pattern></code>s. |
| * See Bugzilla 34805, 43079 & 43080 |
| */ |
| private void checkUnusualURLPattern(String urlPattern) { |
| if (log.isInfoEnabled()) { |
| // First group checks for '*' or '/foo*' style patterns |
| // Second group checks for *.foo.bar style patterns |
| if((urlPattern.endsWith("*") && (urlPattern.length() < 2 || |
| urlPattern.charAt(urlPattern.length()-2) != '/')) || |
| urlPattern.startsWith("*.") && urlPattern.length() > 2 && |
| urlPattern.lastIndexOf('.') > 1) { |
| log.info("Suspicious url pattern: \"" + urlPattern + "\"" + |
| " in context [" + getName() + "] - see" + |
| " sections 12.1 and 12.2 of the Servlet specification"); |
| } |
| } |
| } |
| |
| |
| // ------------------------------------------------------------- Operations |
| |
| @Override |
| protected String getObjectNameKeyProperties() { |
| |
| StringBuilder keyProperties = |
| new StringBuilder("j2eeType=WebModule,"); |
| keyProperties.append(getObjectKeyPropertiesNameOnly()); |
| keyProperties.append(",J2EEApplication="); |
| keyProperties.append(getJ2EEApplication()); |
| keyProperties.append(",J2EEServer="); |
| keyProperties.append(getJ2EEServer()); |
| |
| return keyProperties.toString(); |
| } |
| |
| private String getObjectKeyPropertiesNameOnly() { |
| StringBuilder result = new StringBuilder("name=//"); |
| String hostname = getParent().getName(); |
| if (hostname == null) { |
| result.append("DEFAULT"); |
| } else { |
| result.append(hostname); |
| } |
| |
| String contextName = getName(); |
| if (!contextName.startsWith("/")) { |
| result.append('/'); |
| } |
| result.append(contextName); |
| |
| return result.toString(); |
| } |
| |
| @Override |
| protected void initInternal() throws LifecycleException { |
| super.initInternal(); |
| |
| // Register the naming resources |
| if (namingResources != null) { |
| namingResources.init(); |
| } |
| |
| // Send j2ee.object.created notification |
| if (this.getObjectName() != null) { |
| Notification notification = new Notification("j2ee.object.created", |
| this.getObjectName(), sequenceNumber.getAndIncrement()); |
| broadcaster.sendNotification(notification); |
| } |
| } |
| |
| |
| /* Remove a JMX notficationListener |
| * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) |
| */ |
| @Override |
| public void removeNotificationListener(NotificationListener listener, |
| NotificationFilter filter, Object object) throws ListenerNotFoundException { |
| broadcaster.removeNotificationListener(listener,filter,object); |
| } |
| |
| private MBeanNotificationInfo[] notificationInfo; |
| |
| /* Get JMX Broadcaster Info |
| * @TODO use StringManager for international support! |
| * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed! |
| * @see javax.management.NotificationBroadcaster#getNotificationInfo() |
| */ |
| @Override |
| public MBeanNotificationInfo[] getNotificationInfo() { |
| // FIXME: i18n |
| if(notificationInfo == null) { |
| notificationInfo = new MBeanNotificationInfo[]{ |
| new MBeanNotificationInfo(new String[] { |
| "j2ee.object.created"}, |
| Notification.class.getName(), |
| "web application is created" |
| ), |
| new MBeanNotificationInfo(new String[] { |
| "j2ee.state.starting"}, |
| Notification.class.getName(), |
| "change web application is starting" |
| ), |
| new MBeanNotificationInfo(new String[] { |
| "j2ee.state.running"}, |
| Notification.class.getName(), |
| "web application is running" |
| ), |
| new MBeanNotificationInfo(new String[] { |
| "j2ee.state.stopping"}, |
| Notification.class.getName(), |
| "web application start to stopped" |
| ), |
| new MBeanNotificationInfo(new String[] { |
| "j2ee.object.stopped"}, |
| Notification.class.getName(), |
| "web application is stopped" |
| ), |
| new MBeanNotificationInfo(new String[] { |
| "j2ee.object.deleted"}, |
| Notification.class.getName(), |
| "web application is deleted" |
| ) |
| }; |
| |
| } |
| |
| return notificationInfo; |
| } |
| |
| |
| /** |
| * Add a JMX NotificationListener |
| * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) |
| */ |
| @Override |
| public void addNotificationListener(NotificationListener listener, |
| NotificationFilter filter, Object object) throws IllegalArgumentException { |
| broadcaster.addNotificationListener(listener,filter,object); |
| } |
| |
| |
| /** |
| * Remove a JMX-NotificationListener |
| * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener) |
| */ |
| @Override |
| public void removeNotificationListener(NotificationListener listener) |
| throws ListenerNotFoundException { |
| broadcaster.removeNotificationListener(listener); |
| } |
| |
| |
| // ------------------------------------------------------------- Attributes |
| |
| /** |
| * @return the naming resources associated with this web application. |
| */ |
| public String[] getWelcomeFiles() { |
| |
| return findWelcomeFiles(); |
| |
| } |
| |
| |
| @Override |
| public boolean getXmlNamespaceAware() { |
| return webXmlNamespaceAware; |
| } |
| |
| |
| @Override |
| public void setXmlNamespaceAware(boolean webXmlNamespaceAware) { |
| this.webXmlNamespaceAware = webXmlNamespaceAware; |
| } |
| |
| |
| @Override |
| public void setXmlValidation(boolean webXmlValidation) { |
| this.webXmlValidation = webXmlValidation; |
| } |
| |
| |
| @Override |
| public boolean getXmlValidation() { |
| return webXmlValidation; |
| } |
| |
| |
| @Override |
| public void setXmlBlockExternal(boolean xmlBlockExternal) { |
| this.xmlBlockExternal = xmlBlockExternal; |
| } |
| |
| |
| @Override |
| public boolean getXmlBlockExternal() { |
| return xmlBlockExternal; |
| } |
| |
| |
| @Override |
| public void setTldValidation(boolean tldValidation) { |
| this.tldValidation = tldValidation; |
| } |
| |
| |
| @Override |
| public boolean getTldValidation() { |
| return tldValidation; |
| } |
| |
| |
| /** |
| * The J2EE Server ObjectName this module is deployed on. |
| */ |
| private String server = null; |
| |
| /** |
| * The Java virtual machines on which this module is running. |
| */ |
| private String[] javaVMs = null; |
| |
| public String getServer() { |
| return server; |
| } |
| |
| public String setServer(String server) { |
| return this.server=server; |
| } |
| |
| public String[] getJavaVMs() { |
| return javaVMs; |
| } |
| |
| public String[] setJavaVMs(String[] javaVMs) { |
| return this.javaVMs = javaVMs; |
| } |
| |
| /** |
| * Gets the time this context was started. |
| * |
| * @return Time (in milliseconds since January 1, 1970, 00:00:00) when this |
| * context was started |
| */ |
| public long getStartTime() { |
| return startTime; |
| } |
| |
| |
| private static class NoPluggabilityServletContext |
| implements ServletContext { |
| |
| private final ServletContext sc; |
| |
| public NoPluggabilityServletContext(ServletContext sc) { |
| this.sc = sc; |
| } |
| |
| @Override |
| public String getContextPath() { |
| return sc.getContextPath(); |
| } |
| |
| @Override |
| public ServletContext getContext(String uripath) { |
| return sc.getContext(uripath); |
| } |
| |
| @Override |
| public int getMajorVersion() { |
| return sc.getMajorVersion(); |
| } |
| |
| @Override |
| public int getMinorVersion() { |
| return sc.getMinorVersion(); |
| } |
| |
| @Override |
| public int getEffectiveMajorVersion() { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public int getEffectiveMinorVersion() { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public String getMimeType(String file) { |
| return sc.getMimeType(file); |
| } |
| |
| @Override |
| public Set<String> getResourcePaths(String path) { |
| return sc.getResourcePaths(path); |
| } |
| |
| @Override |
| public URL getResource(String path) throws MalformedURLException { |
| return sc.getResource(path); |
| } |
| |
| @Override |
| public InputStream getResourceAsStream(String path) { |
| return sc.getResourceAsStream(path); |
| } |
| |
| @Override |
| public RequestDispatcher getRequestDispatcher(String path) { |
| return sc.getRequestDispatcher(path); |
| } |
| |
| @Override |
| public RequestDispatcher getNamedDispatcher(String name) { |
| return sc.getNamedDispatcher(name); |
| } |
| |
| @Override |
| @Deprecated |
| public Servlet getServlet(String name) throws ServletException { |
| return sc.getServlet(name); |
| } |
| |
| @Override |
| @Deprecated |
| public Enumeration<Servlet> getServlets() { |
| return sc.getServlets(); |
| } |
| |
| @Override |
| @Deprecated |
| public Enumeration<String> getServletNames() { |
| return sc.getServletNames(); |
| } |
| |
| @Override |
| public void log(String msg) { |
| sc.log(msg); |
| } |
| |
| @Override |
| @Deprecated |
| public void log(Exception exception, String msg) { |
| sc.log(exception, msg); |
| } |
| |
| @Override |
| public void log(String message, Throwable throwable) { |
| sc.log(message, throwable); |
| } |
| |
| @Override |
| public String getRealPath(String path) { |
| return sc.getRealPath(path); |
| } |
| |
| @Override |
| public String getServerInfo() { |
| return sc.getServerInfo(); |
| } |
| |
| @Override |
| public String getInitParameter(String name) { |
| return sc.getInitParameter(name); |
| } |
| |
| @Override |
| public Enumeration<String> getInitParameterNames() { |
| return sc.getInitParameterNames(); |
| } |
| |
| @Override |
| public boolean setInitParameter(String name, String value) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public Object getAttribute(String name) { |
| return sc.getAttribute(name); |
| } |
| |
| @Override |
| public Enumeration<String> getAttributeNames() { |
| return sc.getAttributeNames(); |
| } |
| |
| @Override |
| public void setAttribute(String name, Object object) { |
| sc.setAttribute(name, object); |
| } |
| |
| @Override |
| public void removeAttribute(String name) { |
| sc.removeAttribute(name); |
| } |
| |
| @Override |
| public String getServletContextName() { |
| return sc.getServletContextName(); |
| } |
| |
| @Override |
| public Dynamic addServlet(String servletName, String className) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public Dynamic addServlet(String servletName, Servlet servlet) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public Dynamic addServlet(String servletName, |
| Class<? extends Servlet> servletClass) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public <T extends Servlet> T createServlet(Class<T> c) |
| throws ServletException { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public ServletRegistration getServletRegistration(String servletName) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public Map<String,? extends ServletRegistration> getServletRegistrations() { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public javax.servlet.FilterRegistration.Dynamic addFilter( |
| String filterName, String className) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public javax.servlet.FilterRegistration.Dynamic addFilter( |
| String filterName, Filter filter) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public javax.servlet.FilterRegistration.Dynamic addFilter( |
| String filterName, Class<? extends Filter> filterClass) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public <T extends Filter> T createFilter(Class<T> c) |
| throws ServletException { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public FilterRegistration getFilterRegistration(String filterName) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public Map<String,? extends FilterRegistration> getFilterRegistrations() { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public SessionCookieConfig getSessionCookieConfig() { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public void setSessionTrackingModes( |
| Set<SessionTrackingMode> sessionTrackingModes) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public Set<SessionTrackingMode> getDefaultSessionTrackingModes() { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public void addListener(String className) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public <T extends EventListener> void addListener(T t) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public void addListener(Class<? extends EventListener> listenerClass) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public <T extends EventListener> T createListener(Class<T> c) |
| throws ServletException { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public JspConfigDescriptor getJspConfigDescriptor() { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public ClassLoader getClassLoader() { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public void declareRoles(String... roleNames) { |
| throw new UnsupportedOperationException( |
| sm.getString("noPluggabilityServletContext.notAllowed")); |
| } |
| |
| @Override |
| public String getVirtualServerName() { |
| return sc.getVirtualServerName(); |
| } |
| } |
| } |