ASF Bugzilla – Attachment 27772 Details for
Bug 46264
Shutting down tomcat with large number of contexts is slow
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Threaded start, stop and deployment for Contexts
tc8-bug46264-v5.patch (text/plain), 999.07 KB, created by
Mark Thomas
on 2011-10-13 23:19:14 UTC
(
hide
)
Description:
Threaded start, stop and deployment for Contexts
Filename:
MIME Type:
Creator:
Mark Thomas
Created:
2011-10-13 23:19:14 UTC
Size:
999.07 KB
patch
obsolete
>diff --git a/java/org/apache/catalina/Container.java b/java/org/apache/catalina/Container.java >index 73b265e..5ca3c09 100644 >--- a/java/org/apache/catalina/Container.java >+++ b/java/org/apache/catalina/Container.java >@@ -1,479 +1,496 @@ >-/* >- * 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; >- >- >-import java.beans.PropertyChangeListener; >-import java.io.IOException; >- >-import javax.management.ObjectName; >-import javax.naming.directory.DirContext; >-import javax.servlet.ServletException; >- >-import org.apache.catalina.connector.Request; >-import org.apache.catalina.connector.Response; >-import org.apache.juli.logging.Log; >- >- >-/** >- * A <b>Container</b> is an object that can execute requests received from >- * a client, and return responses based on those requests. A Container may >- * optionally support a pipeline of Valves that process the request in an >- * order configured at runtime, by implementing the <b>Pipeline</b> interface >- * as well. >- * <p> >- * Containers will exist at several conceptual levels within Catalina. The >- * following examples represent common cases: >- * <ul> >- * <li><b>Engine</b> - Representation of the entire Catalina servlet engine, >- * most likely containing one or more subcontainers that are either Host >- * or Context implementations, or other custom groups. >- * <li><b>Host</b> - Representation of a virtual host containing a number >- * of Contexts. >- * <li><b>Context</b> - Representation of a single ServletContext, which will >- * typically contain one or more Wrappers for the supported servlets. >- * <li><b>Wrapper</b> - Representation of an individual servlet definition >- * (which may support multiple servlet instances if the servlet itself >- * implements SingleThreadModel). >- * </ul> >- * A given deployment of Catalina need not include Containers at all of the >- * levels described above. For example, an administration application >- * embedded within a network device (such as a router) might only contain >- * a single Context and a few Wrappers, or even a single Wrapper if the >- * application is relatively small. Therefore, Container implementations >- * need to be designed so that they will operate correctly in the absence >- * of parent Containers in a given deployment. >- * <p> >- * A Container may also be associated with a number of support components >- * that provide functionality which might be shared (by attaching it to a >- * parent Container) or individually customized. The following support >- * components are currently recognized: >- * <ul> >- * <li><b>Loader</b> - Class loader to use for integrating new Java classes >- * for this Container into the JVM in which Catalina is running. >- * <li><b>Logger</b> - Implementation of the <code>log()</code> method >- * signatures of the <code>ServletContext</code> interface. >- * <li><b>Manager</b> - Manager for the pool of Sessions associated with >- * this Container. >- * <li><b>Realm</b> - Read-only interface to a security domain, for >- * authenticating user identities and their corresponding roles. >- * <li><b>Resources</b> - JNDI directory context enabling access to static >- * resources, enabling custom linkages to existing server components when >- * Catalina is embedded in a larger server. >- * </ul> >- * >- * @author Craig R. McClanahan >- * @author Remy Maucherat >- * @version $Id$ >- */ >- >-public interface Container extends Lifecycle { >- >- >- // ----------------------------------------------------- Manifest Constants >- >- >- /** >- * The ContainerEvent event type sent when a child container is added >- * by <code>addChild()</code>. >- */ >- public static final String ADD_CHILD_EVENT = "addChild"; >- >- >- /** >- * The ContainerEvent event type sent when a Mapper is added >- * by <code>addMapper()</code>. >- */ >- public static final String ADD_MAPPER_EVENT = "addMapper"; >- >- >- /** >- * The ContainerEvent event type sent when a valve is added >- * by <code>addValve()</code>, if this Container supports pipelines. >- */ >- public static final String ADD_VALVE_EVENT = "addValve"; >- >- >- /** >- * The ContainerEvent event type sent when a child container is removed >- * by <code>removeChild()</code>. >- */ >- public static final String REMOVE_CHILD_EVENT = "removeChild"; >- >- >- /** >- * The ContainerEvent event type sent when a Mapper is removed >- * by <code>removeMapper()</code>. >- */ >- public static final String REMOVE_MAPPER_EVENT = "removeMapper"; >- >- >- /** >- * The ContainerEvent event type sent when a valve is removed >- * by <code>removeValve()</code>, if this Container supports pipelines. >- */ >- public static final String REMOVE_VALVE_EVENT = "removeValve"; >- >- >- // ------------------------------------------------------------- Properties >- >- >- /** >- * Return descriptive information about this Container implementation and >- * the corresponding version number, in the format >- * <code><description>/<version></code>. >- */ >- public String getInfo(); >- >- >- /** >- * Return the Loader with which this Container is associated. If there is >- * no associated Loader, return the Loader associated with our parent >- * Container (if any); otherwise, return <code>null</code>. >- */ >- public Loader getLoader(); >- >- >- /** >- * Set the Loader with which this Container is associated. >- * >- * @param loader The newly associated loader >- */ >- public void setLoader(Loader loader); >- >- >- /** >- * Return the Logger with which this Container is associated. If there is >- * no associated Logger, return the Logger associated with our parent >- * Container (if any); otherwise return <code>null</code>. >- */ >- public Log getLogger(); >- >- >- /** >- * Return the Manager with which this Container is associated. If there is >- * no associated Manager, return the Manager associated with our parent >- * Container (if any); otherwise return <code>null</code>. >- */ >- public Manager getManager(); >- >- >- /** >- * Set the Manager with which this Container is associated. >- * >- * @param manager The newly associated Manager >- */ >- public void setManager(Manager manager); >- >- >- /** >- * Return an object which may be utilized for mapping to this component. >- */ >- public Object getMappingObject(); >- >- >- /** >- * Return the JMX name associated with this container. >- */ >- public ObjectName getObjectName(); >- >- /** >- * Return the Pipeline object that manages the Valves associated with >- * this Container. >- */ >- public Pipeline getPipeline(); >- >- >- /** >- * Return the Cluster with which this Container is associated. If there is >- * no associated Cluster, return the Cluster associated with our parent >- * Container (if any); otherwise return <code>null</code>. >- */ >- public Cluster getCluster(); >- >- >- /** >- * Set the Cluster with which this Container is associated. >- * >- * @param cluster the Cluster with which this Container is associated. >- */ >- public void setCluster(Cluster cluster); >- >- >- /** >- * Get the delay between the invocation of the backgroundProcess method on >- * this container and its children. Child containers will not be invoked >- * if their delay value is not negative (which would mean they are using >- * their own thread). Setting this to a positive value will cause >- * a thread to be spawn. After waiting the specified amount of time, >- * the thread will invoke the executePeriodic method on this container >- * and all its children. >- */ >- public int getBackgroundProcessorDelay(); >- >- >- /** >- * Set the delay between the invocation of the execute method on this >- * container and its children. >- * >- * @param delay The delay in seconds between the invocation of >- * backgroundProcess methods >- */ >- public void setBackgroundProcessorDelay(int delay); >- >- >- /** >- * Return a name string (suitable for use by humans) that describes this >- * Container. Within the set of child containers belonging to a particular >- * parent, Container names must be unique. >- */ >- public String getName(); >- >- >- /** >- * Set a name string (suitable for use by humans) that describes this >- * Container. Within the set of child containers belonging to a particular >- * parent, Container names must be unique. >- * >- * @param name New name of this container >- * >- * @exception IllegalStateException if this Container has already been >- * added to the children of a parent Container (after which the name >- * may not be changed) >- */ >- public void setName(String name); >- >- >- /** >- * Return the Container for which this Container is a child, if there is >- * one. If there is no defined parent, return <code>null</code>. >- */ >- public Container getParent(); >- >- >- /** >- * Set the parent Container to which this Container is being added as a >- * child. This Container may refuse to become attached to the specified >- * Container by throwing an exception. >- * >- * @param container Container to which this Container is being added >- * as a child >- * >- * @exception IllegalArgumentException if this Container refuses to become >- * attached to the specified Container >- */ >- public void setParent(Container container); >- >- >- /** >- * Return the parent class loader for this component. If not set, return >- * {@link #getParent()} {@link #getParentClassLoader()}. If no parent has >- * been set, return the system class loader. >- */ >- public ClassLoader getParentClassLoader(); >- >- >- /** >- * Set the parent class loader for this component. For {@link Context}s >- * this call is meaningful only <strong>before</strong> a Loader has >- * been configured, and the specified value (if non-null) should be >- * passed as an argument to the class loader constructor. >- * >- * @param parent The new parent class loader >- */ >- public void setParentClassLoader(ClassLoader parent); >- >- >- /** >- * Return the Realm with which this Container is associated. If there is >- * no associated Realm, return the Realm associated with our parent >- * Container (if any); otherwise return <code>null</code>. >- */ >- public Realm getRealm(); >- >- >- /** >- * Set the Realm with which this Container is associated. >- * >- * @param realm The newly associated Realm >- */ >- public void setRealm(Realm realm); >- >- >- /** >- * Return the Resources with which this Container is associated. If there >- * is no associated Resources object, return the Resources associated with >- * our parent Container (if any); otherwise return <code>null</code>. >- */ >- public DirContext getResources(); >- >- >- /** >- * Set the Resources object with which this Container is associated. >- * >- * @param resources The newly associated Resources >- */ >- public void setResources(DirContext resources); >- >- >- // --------------------------------------------------------- Public Methods >- >- >- /** >- * Execute a periodic task, such as reloading, etc. This method will be >- * invoked inside the classloading context of this container. Unexpected >- * throwables will be caught and logged. >- */ >- public void backgroundProcess(); >- >- >- /** >- * Add a new child Container to those associated with this Container, >- * if supported. Prior to adding this Container to the set of children, >- * the child's <code>setParent()</code> method must be called, with this >- * Container as an argument. This method may thrown an >- * <code>IllegalArgumentException</code> if this Container chooses not >- * to be attached to the specified Container, in which case it is not added >- * >- * @param child New child Container to be added >- * >- * @exception IllegalArgumentException if this exception is thrown by >- * the <code>setParent()</code> method of the child Container >- * @exception IllegalArgumentException if the new child does not have >- * a name unique from that of existing children of this Container >- * @exception IllegalStateException if this Container does not support >- * child Containers >- */ >- public void addChild(Container child); >- >- >- /** >- * Add a container event listener to this component. >- * >- * @param listener The listener to add >- */ >- public void addContainerListener(ContainerListener listener); >- >- >- /** >- * Add a property change listener to this component. >- * >- * @param listener The listener to add >- */ >- public void addPropertyChangeListener(PropertyChangeListener listener); >- >- >- /** >- * Return the child Container, associated with this Container, with >- * the specified name (if any); otherwise, return <code>null</code> >- * >- * @param name Name of the child Container to be retrieved >- */ >- public Container findChild(String name); >- >- >- /** >- * Return the set of children Containers associated with this Container. >- * If this Container has no children, a zero-length array is returned. >- */ >- public Container[] findChildren(); >- >- >- /** >- * Return the set of container listeners associated with this Container. >- * If this Container has no registered container listeners, a zero-length >- * array is returned. >- */ >- public ContainerListener[] findContainerListeners(); >- >- >- /** >- * Process the specified Request, and generate the corresponding Response, >- * according to the design of this particular Container. >- * >- * @param request Request to be processed >- * @param response Response to be produced >- * >- * @exception IOException if an input/output error occurred while >- * processing >- * @exception ServletException if a ServletException was thrown >- * while processing this request >- */ >- public void invoke(Request request, Response response) >- throws IOException, ServletException; >- >- >- /** >- * Remove an existing child Container from association with this parent >- * Container. >- * >- * @param child Existing child Container to be removed >- */ >- public void removeChild(Container child); >- >- >- /** >- * Remove a container event listener from this component. >- * >- * @param listener The listener to remove >- */ >- public void removeContainerListener(ContainerListener listener); >- >- >- /** >- * Remove a property change listener from this component. >- * >- * @param listener The listener to remove >- */ >- public void removePropertyChangeListener(PropertyChangeListener listener); >- >- >- /** >- * Notify all container event listeners that a particular event has >- * occurred for this Container. The default implementation performs >- * this notification synchronously using the calling thread. >- * >- * @param type Event type >- * @param data Event data >- */ >- public void fireContainerEvent(String type, Object data); >- >- >- /** >- * Log a request/response that was destined for this container but has been >- * handled earlier in the processing chain so that the request/response >- * still appears in the correct access logs. >- * @param request Request (associated with the response) to log >- * @param response Response (associated with the request) to log >- * @param time Time taken to process the request/response in >- * milliseconds (use 0 if not known) >- * @param useDefault Flag that indicates that the request/response should >- * be logged in the engine's default access log >- */ >- public void logAccess(Request request, Response response, long time, >- boolean useDefault); >- >- >- /** >- * Identify the AccessLog to use to log a request/response that was destined >- * for this container but was handled earlier in the processing chain so >- * that the request/response still appears in the correct access logs. >- */ >- public AccessLog getAccessLog(); >-} >+/* >+ * 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; >+ >+ >+import java.beans.PropertyChangeListener; >+import java.io.IOException; >+ >+import javax.management.ObjectName; >+import javax.naming.directory.DirContext; >+import javax.servlet.ServletException; >+ >+import org.apache.catalina.connector.Request; >+import org.apache.catalina.connector.Response; >+import org.apache.juli.logging.Log; >+ >+ >+/** >+ * A <b>Container</b> is an object that can execute requests received from >+ * a client, and return responses based on those requests. A Container may >+ * optionally support a pipeline of Valves that process the request in an >+ * order configured at runtime, by implementing the <b>Pipeline</b> interface >+ * as well. >+ * <p> >+ * Containers will exist at several conceptual levels within Catalina. The >+ * following examples represent common cases: >+ * <ul> >+ * <li><b>Engine</b> - Representation of the entire Catalina servlet engine, >+ * most likely containing one or more subcontainers that are either Host >+ * or Context implementations, or other custom groups. >+ * <li><b>Host</b> - Representation of a virtual host containing a number >+ * of Contexts. >+ * <li><b>Context</b> - Representation of a single ServletContext, which will >+ * typically contain one or more Wrappers for the supported servlets. >+ * <li><b>Wrapper</b> - Representation of an individual servlet definition >+ * (which may support multiple servlet instances if the servlet itself >+ * implements SingleThreadModel). >+ * </ul> >+ * A given deployment of Catalina need not include Containers at all of the >+ * levels described above. For example, an administration application >+ * embedded within a network device (such as a router) might only contain >+ * a single Context and a few Wrappers, or even a single Wrapper if the >+ * application is relatively small. Therefore, Container implementations >+ * need to be designed so that they will operate correctly in the absence >+ * of parent Containers in a given deployment. >+ * <p> >+ * A Container may also be associated with a number of support components >+ * that provide functionality which might be shared (by attaching it to a >+ * parent Container) or individually customized. The following support >+ * components are currently recognized: >+ * <ul> >+ * <li><b>Loader</b> - Class loader to use for integrating new Java classes >+ * for this Container into the JVM in which Catalina is running. >+ * <li><b>Logger</b> - Implementation of the <code>log()</code> method >+ * signatures of the <code>ServletContext</code> interface. >+ * <li><b>Manager</b> - Manager for the pool of Sessions associated with >+ * this Container. >+ * <li><b>Realm</b> - Read-only interface to a security domain, for >+ * authenticating user identities and their corresponding roles. >+ * <li><b>Resources</b> - JNDI directory context enabling access to static >+ * resources, enabling custom linkages to existing server components when >+ * Catalina is embedded in a larger server. >+ * </ul> >+ * >+ * @author Craig R. McClanahan >+ * @author Remy Maucherat >+ * @version $Id$ >+ */ >+ >+public interface Container extends Lifecycle { >+ >+ >+ // ----------------------------------------------------- Manifest Constants >+ >+ >+ /** >+ * The ContainerEvent event type sent when a child container is added >+ * by <code>addChild()</code>. >+ */ >+ public static final String ADD_CHILD_EVENT = "addChild"; >+ >+ >+ /** >+ * The ContainerEvent event type sent when a Mapper is added >+ * by <code>addMapper()</code>. >+ */ >+ public static final String ADD_MAPPER_EVENT = "addMapper"; >+ >+ >+ /** >+ * The ContainerEvent event type sent when a valve is added >+ * by <code>addValve()</code>, if this Container supports pipelines. >+ */ >+ public static final String ADD_VALVE_EVENT = "addValve"; >+ >+ >+ /** >+ * The ContainerEvent event type sent when a child container is removed >+ * by <code>removeChild()</code>. >+ */ >+ public static final String REMOVE_CHILD_EVENT = "removeChild"; >+ >+ >+ /** >+ * The ContainerEvent event type sent when a Mapper is removed >+ * by <code>removeMapper()</code>. >+ */ >+ public static final String REMOVE_MAPPER_EVENT = "removeMapper"; >+ >+ >+ /** >+ * The ContainerEvent event type sent when a valve is removed >+ * by <code>removeValve()</code>, if this Container supports pipelines. >+ */ >+ public static final String REMOVE_VALVE_EVENT = "removeValve"; >+ >+ >+ // ------------------------------------------------------------- Properties >+ >+ >+ /** >+ * Return descriptive information about this Container implementation and >+ * the corresponding version number, in the format >+ * <code><description>/<version></code>. >+ */ >+ public String getInfo(); >+ >+ >+ /** >+ * Return the Loader with which this Container is associated. If there is >+ * no associated Loader, return the Loader associated with our parent >+ * Container (if any); otherwise, return <code>null</code>. >+ */ >+ public Loader getLoader(); >+ >+ >+ /** >+ * Set the Loader with which this Container is associated. >+ * >+ * @param loader The newly associated loader >+ */ >+ public void setLoader(Loader loader); >+ >+ >+ /** >+ * Return the Logger with which this Container is associated. If there is >+ * no associated Logger, return the Logger associated with our parent >+ * Container (if any); otherwise return <code>null</code>. >+ */ >+ public Log getLogger(); >+ >+ >+ /** >+ * Return the Manager with which this Container is associated. If there is >+ * no associated Manager, return the Manager associated with our parent >+ * Container (if any); otherwise return <code>null</code>. >+ */ >+ public Manager getManager(); >+ >+ >+ /** >+ * Set the Manager with which this Container is associated. >+ * >+ * @param manager The newly associated Manager >+ */ >+ public void setManager(Manager manager); >+ >+ >+ /** >+ * Return an object which may be utilized for mapping to this component. >+ */ >+ public Object getMappingObject(); >+ >+ >+ /** >+ * Return the JMX name associated with this container. >+ */ >+ public ObjectName getObjectName(); >+ >+ /** >+ * Return the Pipeline object that manages the Valves associated with >+ * this Container. >+ */ >+ public Pipeline getPipeline(); >+ >+ >+ /** >+ * Return the Cluster with which this Container is associated. If there is >+ * no associated Cluster, return the Cluster associated with our parent >+ * Container (if any); otherwise return <code>null</code>. >+ */ >+ public Cluster getCluster(); >+ >+ >+ /** >+ * Set the Cluster with which this Container is associated. >+ * >+ * @param cluster the Cluster with which this Container is associated. >+ */ >+ public void setCluster(Cluster cluster); >+ >+ >+ /** >+ * Get the delay between the invocation of the backgroundProcess method on >+ * this container and its children. Child containers will not be invoked >+ * if their delay value is not negative (which would mean they are using >+ * their own thread). Setting this to a positive value will cause >+ * a thread to be spawn. After waiting the specified amount of time, >+ * the thread will invoke the executePeriodic method on this container >+ * and all its children. >+ */ >+ public int getBackgroundProcessorDelay(); >+ >+ >+ /** >+ * Set the delay between the invocation of the execute method on this >+ * container and its children. >+ * >+ * @param delay The delay in seconds between the invocation of >+ * backgroundProcess methods >+ */ >+ public void setBackgroundProcessorDelay(int delay); >+ >+ >+ /** >+ * Return a name string (suitable for use by humans) that describes this >+ * Container. Within the set of child containers belonging to a particular >+ * parent, Container names must be unique. >+ */ >+ public String getName(); >+ >+ >+ /** >+ * Set a name string (suitable for use by humans) that describes this >+ * Container. Within the set of child containers belonging to a particular >+ * parent, Container names must be unique. >+ * >+ * @param name New name of this container >+ * >+ * @exception IllegalStateException if this Container has already been >+ * added to the children of a parent Container (after which the name >+ * may not be changed) >+ */ >+ public void setName(String name); >+ >+ >+ /** >+ * Return the Container for which this Container is a child, if there is >+ * one. If there is no defined parent, return <code>null</code>. >+ */ >+ public Container getParent(); >+ >+ >+ /** >+ * Set the parent Container to which this Container is being added as a >+ * child. This Container may refuse to become attached to the specified >+ * Container by throwing an exception. >+ * >+ * @param container Container to which this Container is being added >+ * as a child >+ * >+ * @exception IllegalArgumentException if this Container refuses to become >+ * attached to the specified Container >+ */ >+ public void setParent(Container container); >+ >+ >+ /** >+ * Return the parent class loader for this component. If not set, return >+ * {@link #getParent()} {@link #getParentClassLoader()}. If no parent has >+ * been set, return the system class loader. >+ */ >+ public ClassLoader getParentClassLoader(); >+ >+ >+ /** >+ * Set the parent class loader for this component. For {@link Context}s >+ * this call is meaningful only <strong>before</strong> a Loader has >+ * been configured, and the specified value (if non-null) should be >+ * passed as an argument to the class loader constructor. >+ * >+ * @param parent The new parent class loader >+ */ >+ public void setParentClassLoader(ClassLoader parent); >+ >+ >+ /** >+ * Return the Realm with which this Container is associated. If there is >+ * no associated Realm, return the Realm associated with our parent >+ * Container (if any); otherwise return <code>null</code>. >+ */ >+ public Realm getRealm(); >+ >+ >+ /** >+ * Set the Realm with which this Container is associated. >+ * >+ * @param realm The newly associated Realm >+ */ >+ public void setRealm(Realm realm); >+ >+ >+ /** >+ * Return the Resources with which this Container is associated. If there >+ * is no associated Resources object, return the Resources associated with >+ * our parent Container (if any); otherwise return <code>null</code>. >+ */ >+ public DirContext getResources(); >+ >+ >+ /** >+ * Set the Resources object with which this Container is associated. >+ * >+ * @param resources The newly associated Resources >+ */ >+ public void setResources(DirContext resources); >+ >+ >+ // --------------------------------------------------------- Public Methods >+ >+ >+ /** >+ * Execute a periodic task, such as reloading, etc. This method will be >+ * invoked inside the classloading context of this container. Unexpected >+ * throwables will be caught and logged. >+ */ >+ public void backgroundProcess(); >+ >+ >+ /** >+ * Add a new child Container to those associated with this Container, >+ * if supported. Prior to adding this Container to the set of children, >+ * the child's <code>setParent()</code> method must be called, with this >+ * Container as an argument. This method may thrown an >+ * <code>IllegalArgumentException</code> if this Container chooses not >+ * to be attached to the specified Container, in which case it is not added >+ * >+ * @param child New child Container to be added >+ * >+ * @exception IllegalArgumentException if this exception is thrown by >+ * the <code>setParent()</code> method of the child Container >+ * @exception IllegalArgumentException if the new child does not have >+ * a name unique from that of existing children of this Container >+ * @exception IllegalStateException if this Container does not support >+ * child Containers >+ */ >+ public void addChild(Container child); >+ >+ >+ /** >+ * Add a container event listener to this component. >+ * >+ * @param listener The listener to add >+ */ >+ public void addContainerListener(ContainerListener listener); >+ >+ >+ /** >+ * Add a property change listener to this component. >+ * >+ * @param listener The listener to add >+ */ >+ public void addPropertyChangeListener(PropertyChangeListener listener); >+ >+ >+ /** >+ * Return the child Container, associated with this Container, with >+ * the specified name (if any); otherwise, return <code>null</code> >+ * >+ * @param name Name of the child Container to be retrieved >+ */ >+ public Container findChild(String name); >+ >+ >+ /** >+ * Return the set of children Containers associated with this Container. >+ * If this Container has no children, a zero-length array is returned. >+ */ >+ public Container[] findChildren(); >+ >+ >+ /** >+ * Return the set of container listeners associated with this Container. >+ * If this Container has no registered container listeners, a zero-length >+ * array is returned. >+ */ >+ public ContainerListener[] findContainerListeners(); >+ >+ >+ /** >+ * Process the specified Request, and generate the corresponding Response, >+ * according to the design of this particular Container. >+ * >+ * @param request Request to be processed >+ * @param response Response to be produced >+ * >+ * @exception IOException if an input/output error occurred while >+ * processing >+ * @exception ServletException if a ServletException was thrown >+ * while processing this request >+ */ >+ public void invoke(Request request, Response response) >+ throws IOException, ServletException; >+ >+ >+ /** >+ * Remove an existing child Container from association with this parent >+ * Container. >+ * >+ * @param child Existing child Container to be removed >+ */ >+ public void removeChild(Container child); >+ >+ >+ /** >+ * Remove a container event listener from this component. >+ * >+ * @param listener The listener to remove >+ */ >+ public void removeContainerListener(ContainerListener listener); >+ >+ >+ /** >+ * Remove a property change listener from this component. >+ * >+ * @param listener The listener to remove >+ */ >+ public void removePropertyChangeListener(PropertyChangeListener listener); >+ >+ >+ /** >+ * Notify all container event listeners that a particular event has >+ * occurred for this Container. The default implementation performs >+ * this notification synchronously using the calling thread. >+ * >+ * @param type Event type >+ * @param data Event data >+ */ >+ public void fireContainerEvent(String type, Object data); >+ >+ >+ /** >+ * Log a request/response that was destined for this container but has been >+ * handled earlier in the processing chain so that the request/response >+ * still appears in the correct access logs. >+ * @param request Request (associated with the response) to log >+ * @param response Response (associated with the request) to log >+ * @param time Time taken to process the request/response in >+ * milliseconds (use 0 if not known) >+ * @param useDefault Flag that indicates that the request/response should >+ * be logged in the engine's default access log >+ */ >+ public void logAccess(Request request, Response response, long time, >+ boolean useDefault); >+ >+ >+ /** >+ * Identify the AccessLog to use to log a request/response that was destined >+ * for this container but was handled earlier in the processing chain so >+ * that the request/response still appears in the correct access logs. >+ */ >+ public AccessLog getAccessLog(); >+ >+ >+ /** >+ * Returns the number of threads available for starting and stopping any >+ * children associated with this container. This allows start/stop calls to >+ * children to be processed in parallel. >+ */ >+ public int getStartStopThreads(); >+ >+ >+ /** >+ * Sets the number of threads available for starting and stopping any >+ * children associated with this container. This allows start/stop calls to >+ * children to be processed in parallel. >+ * @param startStopThreads The new number of threads to be used >+ */ >+ public void setStartStopThreads(int startStopThreads); >+} >diff --git a/java/org/apache/catalina/Host.java b/java/org/apache/catalina/Host.java >index 72f5dc2..9d27191 100644 >--- a/java/org/apache/catalina/Host.java >+++ b/java/org/apache/catalina/Host.java >@@ -1,220 +1,228 @@ >-/* >- * 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; >- >-import java.io.File; >-import java.util.regex.Pattern; >- >- >-/** >- * A <b>Host</b> is a Container that represents a virtual host in the >- * Catalina servlet engine. It is useful in the following types of scenarios: >- * <ul> >- * <li>You wish to use Interceptors that see every single request processed >- * by this particular virtual host. >- * <li>You wish to run Catalina in with a standalone HTTP connector, but still >- * want support for multiple virtual hosts. >- * </ul> >- * In general, you would not use a Host when deploying Catalina connected >- * to a web server (such as Apache), because the Connector will have >- * utilized the web server's facilities to determine which Context (or >- * perhaps even which Wrapper) should be utilized to process this request. >- * <p> >- * The parent Container attached to a Host is generally an Engine, but may >- * be some other implementation, or may be omitted if it is not necessary. >- * <p> >- * The child containers attached to a Host are generally implementations >- * of Context (representing an individual servlet context). >- * >- * @author Craig R. McClanahan >- * @version $Id$ >- */ >- >-public interface Host extends Container { >- >- >- // ----------------------------------------------------- Manifest Constants >- >- >- /** >- * The ContainerEvent event type sent when a new alias is added >- * by <code>addAlias()</code>. >- */ >- public static final String ADD_ALIAS_EVENT = "addAlias"; >- >- >- /** >- * The ContainerEvent event type sent when an old alias is removed >- * by <code>removeAlias()</code>. >- */ >- public static final String REMOVE_ALIAS_EVENT = "removeAlias"; >- >- >- // ------------------------------------------------------------- Properties >- >- >- /** >- * Return the XML root for this Host. This can be an absolute >- * pathname, a relative pathname, or a URL. >- * If null, defaults to >- * ${catalina.base}/conf/<engine name>/<host name> directory >- */ >- public String getXmlBase(); >- >- /** >- * Set the Xml root for this Host. This can be an absolute >- * pathname, a relative pathname, or a URL. >- * If null, defaults to >- * ${catalina.base}/conf/<engine name>/<host name> directory >- * @param xmlBase The new XML root >- */ >- public void setXmlBase(String xmlBase); >- >- /** >- * Return the application root for this Host. This can be an absolute >- * pathname, a relative pathname, or a URL. >- */ >- public String getAppBase(); >- >- >- /** >- * Return an absolute {@link File} for the appBase of this Host. The file >- * will be canonical if possible. There is no guarantee that that the >- * appBase exists. >- */ >- public File getAppBaseFile(); >- >- >- /** >- * Set the application root for this Host. This can be an absolute >- * pathname, a relative pathname, or a URL. >- * >- * @param appBase The new application root >- */ >- public void setAppBase(String appBase); >- >- >- /** >- * Return the value of the auto deploy flag. If true, it indicates that >- * this host's child webapps should be discovered and automatically >- * deployed dynamically. >- */ >- public boolean getAutoDeploy(); >- >- >- /** >- * Set the auto deploy flag value for this host. >- * >- * @param autoDeploy The new auto deploy flag >- */ >- public void setAutoDeploy(boolean autoDeploy); >- >- >- /** >- * Return the Java class name of the context configuration class >- * for new web applications. >- */ >- public String getConfigClass(); >- >- >- /** >- * Set the Java class name of the context configuration class >- * for new web applications. >- * >- * @param configClass The new context configuration class >- */ >- public void setConfigClass(String configClass); >- >- >- /** >- * Return the value of the deploy on startup flag. If true, it indicates >- * that this host's child webapps should be discovered and automatically >- * deployed. >- */ >- public boolean getDeployOnStartup(); >- >- >- /** >- * Set the deploy on startup flag value for this host. >- * >- * @param deployOnStartup The new deploy on startup flag >- */ >- public void setDeployOnStartup(boolean deployOnStartup); >- >- >- /** >- * Return the regular expression that defines the files and directories in >- * the host's appBase that will be ignored by the automatic deployment >- * process. >- */ >- public String getDeployIgnore(); >- >- >- /** >- * Return the compiled regular expression that defines the files and >- * directories in the host's appBase that will be ignored by the automatic >- * deployment process. >- */ >- public Pattern getDeployIgnorePattern(); >- >- >- /** >- * Set the regular expression that defines the files and directories in >- * the host's appBase that will be ignored by the automatic deployment >- * process. >- */ >- public void setDeployIgnore(String deployIgnore); >- >- >- // --------------------------------------------------------- Public Methods >- >- >- /** >- * Add an alias name that should be mapped to this same Host. >- * >- * @param alias The alias to be added >- */ >- public void addAlias(String alias); >- >- >- /** >- * Return the set of alias names for this Host. If none are defined, >- * a zero length array is returned. >- */ >- public String[] findAliases(); >- >- >- /** >- * Remove the specified alias name from the aliases for this Host. >- * >- * @param alias Alias name to be removed >- */ >- public void removeAlias(String alias); >- >- /** >- * Returns true if the Host will attempt to create directories for appBase and xmlBase >- * unless they already exist. >- * @return true if the Host will attempt to create directories >- */ >- public boolean getCreateDirs(); >- /** >- * Set to true if the Host should attempt to create directories for xmlBase and appBase upon startup >- * @param createDirs >- */ >- public void setCreateDirs(boolean createDirs); >- >-} >+/* >+ * 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; >+ >+import java.io.File; >+import java.util.concurrent.ExecutorService; >+import java.util.regex.Pattern; >+ >+ >+/** >+ * A <b>Host</b> is a Container that represents a virtual host in the >+ * Catalina servlet engine. It is useful in the following types of scenarios: >+ * <ul> >+ * <li>You wish to use Interceptors that see every single request processed >+ * by this particular virtual host. >+ * <li>You wish to run Catalina in with a standalone HTTP connector, but still >+ * want support for multiple virtual hosts. >+ * </ul> >+ * In general, you would not use a Host when deploying Catalina connected >+ * to a web server (such as Apache), because the Connector will have >+ * utilized the web server's facilities to determine which Context (or >+ * perhaps even which Wrapper) should be utilized to process this request. >+ * <p> >+ * The parent Container attached to a Host is generally an Engine, but may >+ * be some other implementation, or may be omitted if it is not necessary. >+ * <p> >+ * The child containers attached to a Host are generally implementations >+ * of Context (representing an individual servlet context). >+ * >+ * @author Craig R. McClanahan >+ * @version $Id$ >+ */ >+ >+public interface Host extends Container { >+ >+ >+ // ----------------------------------------------------- Manifest Constants >+ >+ >+ /** >+ * The ContainerEvent event type sent when a new alias is added >+ * by <code>addAlias()</code>. >+ */ >+ public static final String ADD_ALIAS_EVENT = "addAlias"; >+ >+ >+ /** >+ * The ContainerEvent event type sent when an old alias is removed >+ * by <code>removeAlias()</code>. >+ */ >+ public static final String REMOVE_ALIAS_EVENT = "removeAlias"; >+ >+ >+ // ------------------------------------------------------------- Properties >+ >+ >+ /** >+ * Return the XML root for this Host. This can be an absolute >+ * pathname, a relative pathname, or a URL. >+ * If null, defaults to >+ * ${catalina.base}/conf/<engine name>/<host name> directory >+ */ >+ public String getXmlBase(); >+ >+ /** >+ * Set the Xml root for this Host. This can be an absolute >+ * pathname, a relative pathname, or a URL. >+ * If null, defaults to >+ * ${catalina.base}/conf/<engine name>/<host name> directory >+ * @param xmlBase The new XML root >+ */ >+ public void setXmlBase(String xmlBase); >+ >+ /** >+ * Return the application root for this Host. This can be an absolute >+ * pathname, a relative pathname, or a URL. >+ */ >+ public String getAppBase(); >+ >+ >+ /** >+ * Return an absolute {@link File} for the appBase of this Host. The file >+ * will be canonical if possible. There is no guarantee that that the >+ * appBase exists. >+ */ >+ public File getAppBaseFile(); >+ >+ >+ /** >+ * Set the application root for this Host. This can be an absolute >+ * pathname, a relative pathname, or a URL. >+ * >+ * @param appBase The new application root >+ */ >+ public void setAppBase(String appBase); >+ >+ >+ /** >+ * Return the value of the auto deploy flag. If true, it indicates that >+ * this host's child webapps should be discovered and automatically >+ * deployed dynamically. >+ */ >+ public boolean getAutoDeploy(); >+ >+ >+ /** >+ * Set the auto deploy flag value for this host. >+ * >+ * @param autoDeploy The new auto deploy flag >+ */ >+ public void setAutoDeploy(boolean autoDeploy); >+ >+ >+ /** >+ * Return the Java class name of the context configuration class >+ * for new web applications. >+ */ >+ public String getConfigClass(); >+ >+ >+ /** >+ * Set the Java class name of the context configuration class >+ * for new web applications. >+ * >+ * @param configClass The new context configuration class >+ */ >+ public void setConfigClass(String configClass); >+ >+ >+ /** >+ * Return the value of the deploy on startup flag. If true, it indicates >+ * that this host's child webapps should be discovered and automatically >+ * deployed. >+ */ >+ public boolean getDeployOnStartup(); >+ >+ >+ /** >+ * Set the deploy on startup flag value for this host. >+ * >+ * @param deployOnStartup The new deploy on startup flag >+ */ >+ public void setDeployOnStartup(boolean deployOnStartup); >+ >+ >+ /** >+ * Return the regular expression that defines the files and directories in >+ * the host's appBase that will be ignored by the automatic deployment >+ * process. >+ */ >+ public String getDeployIgnore(); >+ >+ >+ /** >+ * Return the compiled regular expression that defines the files and >+ * directories in the host's appBase that will be ignored by the automatic >+ * deployment process. >+ */ >+ public Pattern getDeployIgnorePattern(); >+ >+ >+ /** >+ * Set the regular expression that defines the files and directories in >+ * the host's appBase that will be ignored by the automatic deployment >+ * process. >+ */ >+ public void setDeployIgnore(String deployIgnore); >+ >+ >+ /** >+ * Return the executor that is used for starting and stopping contexts. This >+ * is primarily for use by components deploying contexts that want to do >+ * this in a multi-threaded manner. >+ */ >+ public ExecutorService getStartStopExecutor(); >+ >+ >+ // --------------------------------------------------------- Public Methods >+ >+ /** >+ * Add an alias name that should be mapped to this same Host. >+ * >+ * @param alias The alias to be added >+ */ >+ public void addAlias(String alias); >+ >+ >+ /** >+ * Return the set of alias names for this Host. If none are defined, >+ * a zero length array is returned. >+ */ >+ public String[] findAliases(); >+ >+ >+ /** >+ * Remove the specified alias name from the aliases for this Host. >+ * >+ * @param alias Alias name to be removed >+ */ >+ public void removeAlias(String alias); >+ >+ /** >+ * Returns true if the Host will attempt to create directories for appBase and xmlBase >+ * unless they already exist. >+ * @return true if the Host will attempt to create directories >+ */ >+ public boolean getCreateDirs(); >+ /** >+ * Set to true if the Host should attempt to create directories for xmlBase and appBase upon startup >+ * @param createDirs >+ */ >+ public void setCreateDirs(boolean createDirs); >+ >+} >diff --git a/java/org/apache/catalina/core/ContainerBase.java b/java/org/apache/catalina/core/ContainerBase.java >index 4a736a6..0a8edfc 100644 >--- a/java/org/apache/catalina/core/ContainerBase.java >+++ b/java/org/apache/catalina/core/ContainerBase.java >@@ -1,1415 +1,1546 @@ >-/* >- * 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.beans.PropertyChangeListener; >-import java.beans.PropertyChangeSupport; >-import java.io.IOException; >-import java.security.AccessController; >-import java.security.PrivilegedAction; >-import java.util.ArrayList; >-import java.util.HashMap; >-import java.util.Hashtable; >-import java.util.Iterator; >- >-import javax.management.ObjectName; >-import javax.naming.directory.DirContext; >-import javax.servlet.ServletException; >- >-import org.apache.catalina.AccessLog; >-import org.apache.catalina.CatalinaFactory; >-import org.apache.catalina.Cluster; >-import org.apache.catalina.Container; >-import org.apache.catalina.ContainerEvent; >-import org.apache.catalina.ContainerListener; >-import org.apache.catalina.Globals; >-import org.apache.catalina.Lifecycle; >-import org.apache.catalina.LifecycleException; >-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.Valve; >-import org.apache.catalina.connector.Request; >-import org.apache.catalina.connector.Response; >-import org.apache.catalina.mbeans.MBeanUtils; >-import org.apache.catalina.util.LifecycleMBeanBase; >-import org.apache.juli.logging.Log; >-import org.apache.juli.logging.LogFactory; >-import org.apache.naming.resources.ProxyDirContext; >-import org.apache.tomcat.util.ExceptionUtils; >-import org.apache.tomcat.util.res.StringManager; >- >- >-/** >- * Abstract implementation of the <b>Container</b> interface, providing common >- * functionality required by nearly every implementation. Classes extending >- * this base class must implement <code>getInfo()</code>, and may implement >- * a replacement for <code>invoke()</code>. >- * <p> >- * All subclasses of this abstract base class will include support for a >- * Pipeline object that defines the processing to be performed for each request >- * received by the <code>invoke()</code> method of this class, utilizing the >- * "Chain of Responsibility" design pattern. A subclass should encapsulate its >- * own processing functionality as a <code>Valve</code>, and configure this >- * Valve into the pipeline by calling <code>setBasic()</code>. >- * <p> >- * This implementation fires property change events, per the JavaBeans design >- * pattern, for changes in singleton properties. In addition, it fires the >- * following <code>ContainerEvent</code> events to listeners who register >- * themselves with <code>addContainerListener()</code>: >- * <table border=1> >- * <tr> >- * <th>Type</th> >- * <th>Data</th> >- * <th>Description</th> >- * </tr> >- * <tr> >- * <td align=center><code>addChild</code></td> >- * <td align=center><code>Container</code></td> >- * <td>Child container added to this Container.</td> >- * </tr> >- * <tr> >- * <td align=center><code>addValve</code></td> >- * <td align=center><code>Valve</code></td> >- * <td>Valve added to this Container.</td> >- * </tr> >- * <tr> >- * <td align=center><code>removeChild</code></td> >- * <td align=center><code>Container</code></td> >- * <td>Child container removed from this Container.</td> >- * </tr> >- * <tr> >- * <td align=center><code>removeValve</code></td> >- * <td align=center><code>Valve</code></td> >- * <td>Valve removed from this Container.</td> >- * </tr> >- * <tr> >- * <td align=center><code>start</code></td> >- * <td align=center><code>null</code></td> >- * <td>Container was started.</td> >- * </tr> >- * <tr> >- * <td align=center><code>stop</code></td> >- * <td align=center><code>null</code></td> >- * <td>Container was stopped.</td> >- * </tr> >- * </table> >- * Subclasses that fire additional events should document them in the >- * class comments of the implementation class. >- * >- * TODO: Review synchronisation around background processing. See bug 47024. >- * >- * @author Craig R. McClanahan >- */ >-public abstract class ContainerBase extends LifecycleMBeanBase >- implements Container { >- >- private static final org.apache.juli.logging.Log log= >- org.apache.juli.logging.LogFactory.getLog( ContainerBase.class ); >- >- /** >- * Perform addChild with the permissions of this class. >- * addChild can be called with the XML parser on the stack, >- * this allows the XML parser to have fewer privileges than >- * Tomcat. >- */ >- protected class PrivilegedAddChild >- implements PrivilegedAction<Void> { >- >- private Container child; >- >- PrivilegedAddChild(Container child) { >- this.child = child; >- } >- >- @Override >- public Void run() { >- addChildInternal(child); >- return null; >- } >- >- } >- >- >- // ----------------------------------------------------- Instance Variables >- >- >- /** >- * The child Containers belonging to this Container, keyed by name. >- */ >- protected HashMap<String, Container> children = >- new HashMap<String, Container>(); >- >- >- /** >- * The processor delay for this component. >- */ >- protected int backgroundProcessorDelay = -1; >- >- >- /** >- * The container event listeners for this Container. >- */ >- protected ArrayList<ContainerListener> listeners = new ArrayList<ContainerListener>(); >- >- >- /** >- * The Loader implementation with which this Container is associated. >- */ >- protected Loader loader = null; >- >- >- /** >- * The Logger implementation with which this Container is associated. >- */ >- protected Log logger = null; >- >- >- /** >- * Associated logger name. >- */ >- protected String logName = null; >- >- >- /** >- * The Manager implementation with which this Container is associated. >- */ >- protected Manager manager = null; >- >- >- /** >- * The cluster with which this Container is associated. >- */ >- protected Cluster cluster = null; >- >- >- /** >- * The human-readable name of this Container. >- */ >- protected String name = null; >- >- >- /** >- * The parent Container to which this Container is a child. >- */ >- protected Container parent = null; >- >- >- /** >- * The parent class loader to be configured when we install a Loader. >- */ >- protected ClassLoader parentClassLoader = null; >- >- >- /** >- * The Pipeline object with which this Container is associated. >- */ >- protected Pipeline pipeline = >- CatalinaFactory.getFactory().createPipeline(this); >- >- >- /** >- * The Realm with which this Container is associated. >- */ >- protected Realm realm = null; >- >- >- /** >- * The resources DirContext object with which this Container is associated. >- */ >- protected DirContext resources = null; >- >- >- /** >- * The string manager for this package. >- */ >- protected static final StringManager sm = >- StringManager.getManager(Constants.Package); >- >- >- /** >- * Will children be started automatically when they are added. >- */ >- protected boolean startChildren = true; >- >- /** >- * The property change support for this component. >- */ >- protected PropertyChangeSupport support = new PropertyChangeSupport(this); >- >- >- /** >- * The background thread. >- */ >- private Thread thread = null; >- >- >- /** >- * The background thread completion semaphore. >- */ >- private volatile boolean threadDone = false; >- >- >- /** >- * The access log to use for requests normally handled by this container >- * that have been handled earlier in the processing chain. >- */ >- protected volatile AccessLog accessLog = null; >- private volatile boolean accessLogScanComplete = false; >- >- // ------------------------------------------------------------- Properties >- >- >- /** >- * Get the delay between the invocation of the backgroundProcess method on >- * this container and its children. Child containers will not be invoked >- * if their delay value is not negative (which would mean they are using >- * their own thread). Setting this to a positive value will cause >- * a thread to be spawn. After waiting the specified amount of time, >- * the thread will invoke the executePeriodic method on this container >- * and all its children. >- */ >- @Override >- public int getBackgroundProcessorDelay() { >- return backgroundProcessorDelay; >- } >- >- >- /** >- * Set the delay between the invocation of the execute method on this >- * container and its children. >- * >- * @param delay The delay in seconds between the invocation of >- * backgroundProcess methods >- */ >- @Override >- public void setBackgroundProcessorDelay(int delay) { >- backgroundProcessorDelay = delay; >- } >- >- >- /** >- * Return descriptive information about this Container implementation and >- * the corresponding version number, in the format >- * <code><description>/<version></code>. >- */ >- @Override >- public String getInfo() { >- return this.getClass().getName(); >- } >- >- >- /** >- * Return the Loader with which this Container is associated. If there is >- * no associated Loader, return the Loader associated with our parent >- * Container (if any); otherwise, return <code>null</code>. >- */ >- @Override >- public Loader getLoader() { >- >- if (loader != null) >- return (loader); >- if (parent != null) >- return (parent.getLoader()); >- return (null); >- >- } >- >- >- /** >- * Set the Loader with which this Container is associated. >- * >- * @param loader The newly associated loader >- */ >- @Override >- public synchronized void setLoader(Loader loader) { >- >- // Change components if necessary >- Loader 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("ContainerBase.setLoader: stop: ", e); >- } >- } >- >- // Start the new component if necessary >- if (loader != null) >- loader.setContainer(this); >- if (getState().isAvailable() && (loader != null) && >- (loader instanceof Lifecycle)) { >- try { >- ((Lifecycle) loader).start(); >- } catch (LifecycleException e) { >- log.error("ContainerBase.setLoader: start: ", e); >- } >- } >- >- // Report this property change to interested listeners >- support.firePropertyChange("loader", oldLoader, this.loader); >- >- } >- >- >- /** >- * Return the Logger for this Container. >- */ >- @Override >- public Log getLogger() { >- >- if (logger != null) >- return (logger); >- logger = LogFactory.getLog(logName()); >- return (logger); >- >- } >- >- >- /** >- * Return the Manager with which this Container is associated. If there is >- * no associated Manager, return the Manager associated with our parent >- * Container (if any); otherwise return <code>null</code>. >- */ >- @Override >- public Manager getManager() { >- >- if (manager != null) >- return (manager); >- if (parent != null) >- return (parent.getManager()); >- return (null); >- >- } >- >- >- /** >- * Set the Manager with which this Container is associated. >- * >- * @param manager The newly associated Manager >- */ >- @Override >- public synchronized void setManager(Manager manager) { >- >- // Change components if necessary >- Manager oldManager = this.manager; >- if (oldManager == manager) >- return; >- this.manager = manager; >- >- // Stop the old component if necessary >- if (getState().isAvailable() && (oldManager != null) && >- (oldManager instanceof Lifecycle)) { >- try { >- ((Lifecycle) oldManager).stop(); >- } catch (LifecycleException e) { >- log.error("ContainerBase.setManager: stop: ", e); >- } >- } >- >- // Start the new component if necessary >- if (manager != null) >- manager.setContainer(this); >- if (getState().isAvailable() && (manager != null) && >- (manager instanceof Lifecycle)) { >- try { >- ((Lifecycle) manager).start(); >- } catch (LifecycleException e) { >- log.error("ContainerBase.setManager: start: ", e); >- } >- } >- >- // Report this property change to interested listeners >- support.firePropertyChange("manager", oldManager, this.manager); >- >- } >- >- >- /** >- * Return an object which may be utilized for mapping to this component. >- */ >- @Override >- public Object getMappingObject() { >- return this; >- } >- >- >- /** >- * Return the Cluster with which this Container is associated. If there is >- * no associated Cluster, return the Cluster associated with our parent >- * Container (if any); otherwise return <code>null</code>. >- */ >- @Override >- public Cluster getCluster() { >- if (cluster != null) >- return (cluster); >- >- if (parent != null) >- return (parent.getCluster()); >- >- return (null); >- } >- >- >- /** >- * Set the Cluster with which this Container is associated. >- * >- * @param cluster The newly associated Cluster >- */ >- @Override >- public synchronized void setCluster(Cluster cluster) { >- // Change components if necessary >- Cluster oldCluster = this.cluster; >- if (oldCluster == cluster) >- return; >- this.cluster = cluster; >- >- // Stop the old component if necessary >- if (getState().isAvailable() && (oldCluster != null) && >- (oldCluster instanceof Lifecycle)) { >- try { >- ((Lifecycle) oldCluster).stop(); >- } catch (LifecycleException e) { >- log.error("ContainerBase.setCluster: stop: ", e); >- } >- } >- >- // Start the new component if necessary >- if (cluster != null) >- cluster.setContainer(this); >- >- if (getState().isAvailable() && (cluster != null) && >- (cluster instanceof Lifecycle)) { >- try { >- ((Lifecycle) cluster).start(); >- } catch (LifecycleException e) { >- log.error("ContainerBase.setCluster: start: ", e); >- } >- } >- >- // Report this property change to interested listeners >- support.firePropertyChange("cluster", oldCluster, this.cluster); >- } >- >- >- /** >- * Return a name string (suitable for use by humans) that describes this >- * Container. Within the set of child containers belonging to a particular >- * parent, Container names must be unique. >- */ >- @Override >- public String getName() { >- >- return (name); >- >- } >- >- >- /** >- * Set a name string (suitable for use by humans) that describes this >- * Container. Within the set of child containers belonging to a particular >- * parent, Container names must be unique. >- * >- * @param name New name of this container >- * >- * @exception IllegalStateException if this Container has already been >- * added to the children of a parent Container (after which the name >- * may not be changed) >- */ >- @Override >- public void setName(String name) { >- >- String oldName = this.name; >- this.name = name; >- support.firePropertyChange("name", oldName, this.name); >- } >- >- >- /** >- * Return if children of this container will be started automatically when >- * they are added to this container. >- */ >- public boolean getStartChildren() { >- >- return (startChildren); >- >- } >- >- >- /** >- * Set if children of this container will be started automatically when >- * they are added to this container. >- * >- * @param startChildren New value of the startChildren flag >- */ >- public void setStartChildren(boolean startChildren) { >- >- boolean oldStartChildren = this.startChildren; >- this.startChildren = startChildren; >- support.firePropertyChange("startChildren", oldStartChildren, this.startChildren); >- } >- >- >- /** >- * Return the Container for which this Container is a child, if there is >- * one. If there is no defined parent, return <code>null</code>. >- */ >- @Override >- public Container getParent() { >- >- return (parent); >- >- } >- >- >- /** >- * Set the parent Container to which this Container is being added as a >- * child. This Container may refuse to become attached to the specified >- * Container by throwing an exception. >- * >- * @param container Container to which this Container is being added >- * as a child >- * >- * @exception IllegalArgumentException if this Container refuses to become >- * attached to the specified Container >- */ >- @Override >- public void setParent(Container container) { >- >- Container oldParent = this.parent; >- this.parent = container; >- support.firePropertyChange("parent", oldParent, this.parent); >- >- } >- >- >- /** >- * 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 (parent != null) { >- return (parent.getParentClassLoader()); >- } >- return (ClassLoader.getSystemClassLoader()); >- >- } >- >- >- /** >- * Set the parent class loader (if any) for this web application. >- * This call is meaningful only <strong>before</strong> a Loader has >- * been configured, and the specified value (if non-null) should be >- * passed as an argument to the class loader constructor. >- * >- * >- * @param parent The new parent class loader >- */ >- @Override >- public void setParentClassLoader(ClassLoader parent) { >- ClassLoader oldParentClassLoader = this.parentClassLoader; >- this.parentClassLoader = parent; >- support.firePropertyChange("parentClassLoader", oldParentClassLoader, >- this.parentClassLoader); >- >- } >- >- >- /** >- * Return the Pipeline object that manages the Valves associated with >- * this Container. >- */ >- @Override >- public Pipeline getPipeline() { >- >- return (this.pipeline); >- >- } >- >- >- /** >- * Return the Realm with which this Container is associated. If there is >- * no associated Realm, return the Realm associated with our parent >- * Container (if any); otherwise return <code>null</code>. >- */ >- @Override >- public Realm getRealm() { >- >- if (realm != null) >- return (realm); >- if (parent != null) >- return (parent.getRealm()); >- return (null); >- >- } >- >- >- /** >- * Set the Realm with which this Container is associated. >- * >- * @param realm The newly associated Realm >- */ >- @Override >- public synchronized void setRealm(Realm realm) { >- >- // Change components if necessary >- Realm oldRealm = this.realm; >- if (oldRealm == realm) >- return; >- this.realm = realm; >- >- // Stop the old component if necessary >- if (getState().isAvailable() && (oldRealm != null) && >- (oldRealm instanceof Lifecycle)) { >- try { >- ((Lifecycle) oldRealm).stop(); >- } catch (LifecycleException e) { >- log.error("ContainerBase.setRealm: stop: ", e); >- } >- } >- >- // Start the new component if necessary >- if (realm != null) >- realm.setContainer(this); >- if (getState().isAvailable() && (realm != null) && >- (realm instanceof Lifecycle)) { >- try { >- ((Lifecycle) realm).start(); >- } catch (LifecycleException e) { >- log.error("ContainerBase.setRealm: start: ", e); >- } >- } >- >- // Report this property change to interested listeners >- support.firePropertyChange("realm", oldRealm, this.realm); >- >- } >- >- >- /** >- * Return the resources DirContext object with which this Container is >- * associated. If there is no associated resources object, return the >- * resources associated with our parent Container (if any); otherwise >- * return <code>null</code>. >- */ >- @Override >- public DirContext getResources() { >- if (resources != null) >- return (resources); >- if (parent != null) >- return (parent.getResources()); >- return (null); >- >- } >- >- >- /** >- * Set the resources DirContext object with which this Container is >- * associated. >- * >- * @param resources The newly associated DirContext >- */ >- @Override >- public synchronized void setResources(DirContext resources) { >- // Called from StandardContext.setResources() >- // <- StandardContext.start() >- // <- ContainerBase.addChildInternal() >- >- // Change components if necessary >- DirContext oldResources = this.resources; >- if (oldResources == resources) >- return; >- Hashtable<String, String> env = new Hashtable<String, String>(); >- if (getParent() != null) >- env.put(ProxyDirContext.HOST, getParent().getName()); >- env.put(ProxyDirContext.CONTEXT, getName()); >- this.resources = new ProxyDirContext(env, resources); >- // Report this property change to interested listeners >- support.firePropertyChange("resources", oldResources, this.resources); >- >- } >- >- >- // ------------------------------------------------------ Container Methods >- >- >- /** >- * Add a new child Container to those associated with this Container, >- * if supported. Prior to adding this Container to the set of children, >- * the child's <code>setParent()</code> method must be called, with this >- * Container as an argument. This method may thrown an >- * <code>IllegalArgumentException</code> if this Container chooses not >- * to be attached to the specified Container, in which case it is not added >- * >- * @param child New child Container to be added >- * >- * @exception IllegalArgumentException if this exception is thrown by >- * the <code>setParent()</code> method of the child Container >- * @exception IllegalArgumentException if the new child does not have >- * a name unique from that of existing children of this Container >- * @exception IllegalStateException if this Container does not support >- * child Containers >- */ >- @Override >- public void addChild(Container child) { >- if (Globals.IS_SECURITY_ENABLED) { >- PrivilegedAction<Void> dp = >- new PrivilegedAddChild(child); >- AccessController.doPrivileged(dp); >- } else { >- addChildInternal(child); >- } >- } >- >- private void addChildInternal(Container child) { >- >- if( log.isDebugEnabled() ) >- log.debug("Add child " + child + " " + this); >- synchronized(children) { >- if (children.get(child.getName()) != null) >- throw new IllegalArgumentException("addChild: Child name '" + >- child.getName() + >- "' is not unique"); >- child.setParent(this); // May throw IAE >- children.put(child.getName(), child); >- } >- >- // Start child >- // Don't do this inside sync block - start can be a slow process and >- // locking the children object can cause problems elsewhere >- if ((getState().isAvailable() || >- LifecycleState.STARTING_PREP.equals(getState())) && >- startChildren) { >- boolean success = false; >- try { >- child.start(); >- success = true; >- } catch (LifecycleException e) { >- log.error("ContainerBase.addChild: start: ", e); >- throw new IllegalStateException >- ("ContainerBase.addChild: start: " + e); >- } finally { >- if (!success) { >- synchronized (children) { >- children.remove(child.getName()); >- } >- } >- } >- } >- >- fireContainerEvent(ADD_CHILD_EVENT, child); >- } >- >- >- /** >- * Add a container event listener to this component. >- * >- * @param listener The listener to add >- */ >- @Override >- public void addContainerListener(ContainerListener listener) { >- >- synchronized (listeners) { >- listeners.add(listener); >- } >- >- } >- >- >- /** >- * Add a property change listener to this component. >- * >- * @param listener The listener to add >- */ >- @Override >- public void addPropertyChangeListener(PropertyChangeListener listener) { >- >- support.addPropertyChangeListener(listener); >- >- } >- >- >- /** >- * Return the child Container, associated with this Container, with >- * the specified name (if any); otherwise, return <code>null</code> >- * >- * @param name Name of the child Container to be retrieved >- */ >- @Override >- public Container findChild(String name) { >- >- if (name == null) >- return (null); >- synchronized (children) { >- return children.get(name); >- } >- >- } >- >- >- /** >- * Return the set of children Containers associated with this Container. >- * If this Container has no children, a zero-length array is returned. >- */ >- @Override >- public Container[] findChildren() { >- >- synchronized (children) { >- Container results[] = new Container[children.size()]; >- return children.values().toArray(results); >- } >- >- } >- >- >- /** >- * Return the set of container listeners associated with this Container. >- * If this Container has no registered container listeners, a zero-length >- * array is returned. >- */ >- @Override >- public ContainerListener[] findContainerListeners() { >- >- synchronized (listeners) { >- ContainerListener[] results = >- new ContainerListener[listeners.size()]; >- return listeners.toArray(results); >- } >- >- } >- >- >- /** >- * Process the specified Request, to produce the corresponding Response, >- * by invoking the first Valve in our pipeline (if any), or the basic >- * Valve otherwise. >- * >- * @param request Request to be processed >- * @param response Response to be produced >- * >- * @exception IllegalStateException if neither a pipeline or a basic >- * Valve have been configured for this Container >- * @exception IOException if an input/output error occurred while >- * processing >- * @exception ServletException if a ServletException was thrown >- * while processing this request >- */ >- @Override >- public void invoke(Request request, Response response) >- throws IOException, ServletException { >- >- pipeline.getFirst().invoke(request, response); >- >- } >- >- >- /** >- * Remove an existing child Container from association with this parent >- * Container. >- * >- * @param child Existing child Container to be removed >- */ >- @Override >- public void removeChild(Container child) { >- >- if (child == null) { >- return; >- } >- >- synchronized(children) { >- if (children.get(child.getName()) == null) >- return; >- children.remove(child.getName()); >- } >- >- try { >- if (child.getState().isAvailable()) { >- child.stop(); >- } >- } catch (LifecycleException e) { >- log.error("ContainerBase.removeChild: stop: ", e); >- } >- >- fireContainerEvent(REMOVE_CHILD_EVENT, child); >- >- try { >- // child.destroy() may have already been called which would have >- // triggered this call. If that is the case, no need to destroy the >- // child again. >- if (!LifecycleState.DESTROYING.equals(child.getState())) { >- child.destroy(); >- } >- } catch (LifecycleException e) { >- log.error("ContainerBase.removeChild: destroy: ", e); >- } >- >- } >- >- >- /** >- * Remove a container event listener from this component. >- * >- * @param listener The listener to remove >- */ >- @Override >- public void removeContainerListener(ContainerListener listener) { >- >- synchronized (listeners) { >- listeners.remove(listener); >- } >- >- } >- >- >- /** >- * Remove a property change listener from this component. >- * >- * @param listener The listener to remove >- */ >- @Override >- public void removePropertyChangeListener(PropertyChangeListener listener) { >- >- support.removePropertyChangeListener(listener); >- >- } >- >- >- /** >- * 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 { >- >- // Start our subordinate components, if any >- if ((loader != null) && (loader instanceof Lifecycle)) >- ((Lifecycle) loader).start(); >- logger = null; >- getLogger(); >- if ((logger != null) && (logger instanceof Lifecycle)) >- ((Lifecycle) logger).start(); >- if ((manager != null) && (manager instanceof Lifecycle)) >- ((Lifecycle) manager).start(); >- if ((cluster != null) && (cluster instanceof Lifecycle)) >- ((Lifecycle) cluster).start(); >- if ((realm != null) && (realm instanceof Lifecycle)) >- ((Lifecycle) realm).start(); >- if ((resources != null) && (resources instanceof Lifecycle)) >- ((Lifecycle) resources).start(); >- >- // Start our child containers, if any >- Container children[] = findChildren(); >- for (int i = 0; i < children.length; i++) { >- children[i].start(); >- } >- >- // Start the Valves in our pipeline (including the basic), if any >- if (pipeline instanceof Lifecycle) >- ((Lifecycle) pipeline).start(); >- >- >- setState(LifecycleState.STARTING); >- >- // Start our thread >- threadStart(); >- >- } >- >- >- /** >- * 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 { >- >- // Stop our thread >- threadStop(); >- >- setState(LifecycleState.STOPPING); >- >- // Stop the Valves in our pipeline (including the basic), if any >- if (pipeline instanceof Lifecycle && >- ((Lifecycle) pipeline).getState().isAvailable()) { >- ((Lifecycle) pipeline).stop(); >- } >- >- // Stop our child containers, if any >- Container children[] = findChildren(); >- for (int i = 0; i < children.length; i++) { >- children[i].stop(); >- } >- >- // Stop our subordinate components, if any >- if ((resources != null) && (resources instanceof Lifecycle)) { >- ((Lifecycle) resources).stop(); >- } >- if ((realm != null) && (realm instanceof Lifecycle)) { >- ((Lifecycle) realm).stop(); >- } >- if ((cluster != null) && (cluster instanceof Lifecycle)) { >- ((Lifecycle) cluster).stop(); >- } >- if ((manager != null) && (manager instanceof Lifecycle) && >- ((Lifecycle) manager).getState().isAvailable() ) { >- ((Lifecycle) manager).stop(); >- } >- if ((logger != null) && (logger instanceof Lifecycle)) { >- ((Lifecycle) logger).stop(); >- } >- if ((loader != null) && (loader instanceof Lifecycle)) { >- ((Lifecycle) loader).stop(); >- } >- } >- >- @Override >- protected void destroyInternal() throws LifecycleException { >- >- // Stop the Valves in our pipeline (including the basic), if any >- if (pipeline instanceof Lifecycle) { >- ((Lifecycle) pipeline).destroy(); >- } >- >- // Remove children now this container is being destroyed >- for (Container child : findChildren()) { >- removeChild(child); >- } >- >- // Required if the child is destroyed directly. >- if (parent != null) { >- parent.removeChild(this); >- } >- >- super.destroyInternal(); >- } >- >- >- /** >- * Check this container for an access log and if none is found, look to the >- * parent. If there is no parent and still none is found, use the NoOp >- * access log. >- */ >- @Override >- public void logAccess(Request request, Response response, long time, >- boolean useDefault) { >- >- boolean logged = false; >- >- if (getAccessLog() != null) { >- getAccessLog().log(request, response, time); >- logged = true; >- } >- >- if (getParent() != null) { >- // No need to use default logger once request/response has been logged >- // once >- getParent().logAccess(request, response, time, (useDefault && !logged)); >- } >- } >- >- @Override >- public AccessLog getAccessLog() { >- >- if (accessLogScanComplete) { >- return accessLog; >- } >- >- AccessLogAdapter adapter = null; >- Valve valves[] = getPipeline().getValves(); >- for (Valve valve : valves) { >- if (valve instanceof AccessLog) { >- if (adapter == null) { >- adapter = new AccessLogAdapter((AccessLog) valve); >- } else { >- adapter.add((AccessLog) valve); >- } >- } >- } >- if (adapter != null) { >- accessLog = adapter; >- } >- accessLogScanComplete = true; >- return accessLog; >- } >- >- // ------------------------------------------------------- Pipeline Methods >- >- >- /** >- * Convenience method, intended for use by the digester to simplify the >- * process of adding Valves to containers. See >- * {@link Pipeline#addValve(Valve)} for full details. Components other than >- * the digester should use {@link #getPipeline()}.{@link #addValve(Valve)} in case a >- * future implementation provides an alternative method for the digester to >- * use. >- * >- * @param valve Valve to be added >- * >- * @exception IllegalArgumentException if this Container refused to >- * accept the specified Valve >- * @exception IllegalArgumentException if the specified Valve refuses to be >- * associated with this Container >- * @exception IllegalStateException if the specified Valve is already >- * associated with a different Container >- */ >- public synchronized void addValve(Valve valve) { >- >- pipeline.addValve(valve); >- } >- >- >- /** >- * Execute a periodic task, such as reloading, etc. This method will be >- * invoked inside the classloading context of this container. Unexpected >- * throwables will be caught and logged. >- */ >- @Override >- public void backgroundProcess() { >- >- if (!getState().isAvailable()) >- return; >- >- if (cluster != null) { >- try { >- cluster.backgroundProcess(); >- } catch (Exception e) { >- log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e); >- } >- } >- if (loader != null) { >- try { >- loader.backgroundProcess(); >- } catch (Exception e) { >- log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e); >- } >- } >- if (manager != null) { >- try { >- manager.backgroundProcess(); >- } catch (Exception e) { >- log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e); >- } >- } >- if (realm != null) { >- try { >- realm.backgroundProcess(); >- } catch (Exception e) { >- log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e); >- } >- } >- Valve current = pipeline.getFirst(); >- while (current != null) { >- try { >- current.backgroundProcess(); >- } catch (Exception e) { >- log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e); >- } >- current = current.getNext(); >- } >- fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null); >- } >- >- >- // ------------------------------------------------------ Protected Methods >- >- >- /** >- * Notify all container event listeners that a particular event has >- * occurred for this Container. The default implementation performs >- * this notification synchronously using the calling thread. >- * >- * @param type Event type >- * @param data Event data >- */ >- @Override >- public void fireContainerEvent(String type, Object data) { >- >- if (listeners.size() < 1) >- return; >- ContainerEvent event = new ContainerEvent(this, type, data); >- ContainerListener list[] = new ContainerListener[0]; >- synchronized (listeners) { >- list = listeners.toArray(list); >- } >- for (int i = 0; i < list.length; i++) >- list[i].containerEvent(event); >- >- } >- >- >- /** >- * Return the abbreviated name of this container for logging messages >- */ >- protected String logName() { >- >- if (logName != null) { >- return logName; >- } >- String loggerName = null; >- Container current = this; >- while (current != null) { >- String name = current.getName(); >- if ((name == null) || (name.equals(""))) { >- name = "/"; >- } else if (name.startsWith("##")) { >- name = "/" + name; >- } >- loggerName = "[" + name + "]" >- + ((loggerName != null) ? ("." + loggerName) : ""); >- current = current.getParent(); >- } >- logName = ContainerBase.class.getName() + "." + loggerName; >- return logName; >- >- } >- >- >- // -------------------- JMX and Registration -------------------- >- >- @Override >- protected String getDomainInternal() { >- return MBeanUtils.getDomain(this); >- } >- >- public ObjectName[] getChildren() { >- ObjectName result[]=new ObjectName[children.size()]; >- Iterator<Container> it=children.values().iterator(); >- int i=0; >- while( it.hasNext() ) { >- Object next=it.next(); >- if( next instanceof ContainerBase ) { >- result[i++]=((ContainerBase)next).getObjectName(); >- } >- } >- return result; >- } >- >- >- // -------------------- Background Thread -------------------- >- >- /** >- * Start the background thread that will periodically check for >- * session timeouts. >- */ >- protected void threadStart() { >- >- if (thread != null) >- return; >- if (backgroundProcessorDelay <= 0) >- return; >- >- threadDone = false; >- String threadName = "ContainerBackgroundProcessor[" + toString() + "]"; >- thread = new Thread(new ContainerBackgroundProcessor(), threadName); >- thread.setDaemon(true); >- thread.start(); >- >- } >- >- >- /** >- * Stop the background thread that is periodically checking for >- * session timeouts. >- */ >- protected void threadStop() { >- >- if (thread == null) >- return; >- >- threadDone = true; >- thread.interrupt(); >- try { >- thread.join(); >- } catch (InterruptedException e) { >- // Ignore >- } >- >- thread = null; >- >- } >- >- >- // -------------------------------------- ContainerExecuteDelay Inner Class >- >- >- /** >- * Private thread class to invoke the backgroundProcess method >- * of this container and its children after a fixed delay. >- */ >- protected class ContainerBackgroundProcessor implements Runnable { >- >- @Override >- public void run() { >- while (!threadDone) { >- try { >- Thread.sleep(backgroundProcessorDelay * 1000L); >- } catch (InterruptedException e) { >- // Ignore >- } >- if (!threadDone) { >- Container parent = (Container) getMappingObject(); >- ClassLoader cl = >- Thread.currentThread().getContextClassLoader(); >- if (parent.getLoader() != null) { >- cl = parent.getLoader().getClassLoader(); >- } >- processChildren(parent, cl); >- } >- } >- } >- >- protected void processChildren(Container container, ClassLoader cl) { >- try { >- if (container.getLoader() != null) { >- Thread.currentThread().setContextClassLoader >- (container.getLoader().getClassLoader()); >- } >- container.backgroundProcess(); >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- log.error("Exception invoking periodic operation: ", t); >- } finally { >- Thread.currentThread().setContextClassLoader(cl); >- } >- Container[] children = container.findChildren(); >- for (int i = 0; i < children.length; i++) { >- if (children[i].getBackgroundProcessorDelay() <= 0) { >- processChildren(children[i], cl); >- } >- } >- } >- } >-} >+/* >+ * 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.beans.PropertyChangeListener; >+import java.beans.PropertyChangeSupport; >+import java.io.IOException; >+import java.security.AccessController; >+import java.security.PrivilegedAction; >+import java.util.ArrayList; >+import java.util.HashMap; >+import java.util.Hashtable; >+import java.util.Iterator; >+import java.util.List; >+import java.util.concurrent.BlockingQueue; >+import java.util.concurrent.Callable; >+import java.util.concurrent.Future; >+import java.util.concurrent.LinkedBlockingQueue; >+import java.util.concurrent.ThreadPoolExecutor; >+import java.util.concurrent.TimeUnit; >+ >+import javax.management.ObjectName; >+import javax.naming.directory.DirContext; >+import javax.servlet.ServletException; >+ >+import org.apache.catalina.AccessLog; >+import org.apache.catalina.CatalinaFactory; >+import org.apache.catalina.Cluster; >+import org.apache.catalina.Container; >+import org.apache.catalina.ContainerEvent; >+import org.apache.catalina.ContainerListener; >+import org.apache.catalina.Globals; >+import org.apache.catalina.Lifecycle; >+import org.apache.catalina.LifecycleException; >+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.Valve; >+import org.apache.catalina.connector.Request; >+import org.apache.catalina.connector.Response; >+import org.apache.catalina.mbeans.MBeanUtils; >+import org.apache.catalina.util.LifecycleMBeanBase; >+import org.apache.juli.logging.Log; >+import org.apache.juli.logging.LogFactory; >+import org.apache.naming.resources.ProxyDirContext; >+import org.apache.tomcat.util.ExceptionUtils; >+import org.apache.tomcat.util.res.StringManager; >+ >+ >+/** >+ * Abstract implementation of the <b>Container</b> interface, providing common >+ * functionality required by nearly every implementation. Classes extending >+ * this base class must implement <code>getInfo()</code>, and may implement >+ * a replacement for <code>invoke()</code>. >+ * <p> >+ * All subclasses of this abstract base class will include support for a >+ * Pipeline object that defines the processing to be performed for each request >+ * received by the <code>invoke()</code> method of this class, utilizing the >+ * "Chain of Responsibility" design pattern. A subclass should encapsulate its >+ * own processing functionality as a <code>Valve</code>, and configure this >+ * Valve into the pipeline by calling <code>setBasic()</code>. >+ * <p> >+ * This implementation fires property change events, per the JavaBeans design >+ * pattern, for changes in singleton properties. In addition, it fires the >+ * following <code>ContainerEvent</code> events to listeners who register >+ * themselves with <code>addContainerListener()</code>: >+ * <table border=1> >+ * <tr> >+ * <th>Type</th> >+ * <th>Data</th> >+ * <th>Description</th> >+ * </tr> >+ * <tr> >+ * <td align=center><code>addChild</code></td> >+ * <td align=center><code>Container</code></td> >+ * <td>Child container added to this Container.</td> >+ * </tr> >+ * <tr> >+ * <td align=center><code>addValve</code></td> >+ * <td align=center><code>Valve</code></td> >+ * <td>Valve added to this Container.</td> >+ * </tr> >+ * <tr> >+ * <td align=center><code>removeChild</code></td> >+ * <td align=center><code>Container</code></td> >+ * <td>Child container removed from this Container.</td> >+ * </tr> >+ * <tr> >+ * <td align=center><code>removeValve</code></td> >+ * <td align=center><code>Valve</code></td> >+ * <td>Valve removed from this Container.</td> >+ * </tr> >+ * <tr> >+ * <td align=center><code>start</code></td> >+ * <td align=center><code>null</code></td> >+ * <td>Container was started.</td> >+ * </tr> >+ * <tr> >+ * <td align=center><code>stop</code></td> >+ * <td align=center><code>null</code></td> >+ * <td>Container was stopped.</td> >+ * </tr> >+ * </table> >+ * Subclasses that fire additional events should document them in the >+ * class comments of the implementation class. >+ * >+ * TODO: Review synchronisation around background processing. See bug 47024. >+ * >+ * @author Craig R. McClanahan >+ */ >+public abstract class ContainerBase extends LifecycleMBeanBase >+ implements Container { >+ >+ private static final org.apache.juli.logging.Log log= >+ org.apache.juli.logging.LogFactory.getLog( ContainerBase.class ); >+ >+ /** >+ * Perform addChild with the permissions of this class. >+ * addChild can be called with the XML parser on the stack, >+ * this allows the XML parser to have fewer privileges than >+ * Tomcat. >+ */ >+ protected class PrivilegedAddChild >+ implements PrivilegedAction<Void> { >+ >+ private Container child; >+ >+ PrivilegedAddChild(Container child) { >+ this.child = child; >+ } >+ >+ @Override >+ public Void run() { >+ addChildInternal(child); >+ return null; >+ } >+ >+ } >+ >+ >+ // ----------------------------------------------------- Instance Variables >+ >+ >+ /** >+ * The child Containers belonging to this Container, keyed by name. >+ */ >+ protected HashMap<String, Container> children = >+ new HashMap<String, Container>(); >+ >+ >+ /** >+ * The processor delay for this component. >+ */ >+ protected int backgroundProcessorDelay = -1; >+ >+ >+ /** >+ * The container event listeners for this Container. >+ */ >+ protected ArrayList<ContainerListener> listeners = new ArrayList<ContainerListener>(); >+ >+ >+ /** >+ * The Loader implementation with which this Container is associated. >+ */ >+ protected Loader loader = null; >+ >+ >+ /** >+ * The Logger implementation with which this Container is associated. >+ */ >+ protected Log logger = null; >+ >+ >+ /** >+ * Associated logger name. >+ */ >+ protected String logName = null; >+ >+ >+ /** >+ * The Manager implementation with which this Container is associated. >+ */ >+ protected Manager manager = null; >+ >+ >+ /** >+ * The cluster with which this Container is associated. >+ */ >+ protected Cluster cluster = null; >+ >+ >+ /** >+ * The human-readable name of this Container. >+ */ >+ protected String name = null; >+ >+ >+ /** >+ * The parent Container to which this Container is a child. >+ */ >+ protected Container parent = null; >+ >+ >+ /** >+ * The parent class loader to be configured when we install a Loader. >+ */ >+ protected ClassLoader parentClassLoader = null; >+ >+ >+ /** >+ * The Pipeline object with which this Container is associated. >+ */ >+ protected Pipeline pipeline = >+ CatalinaFactory.getFactory().createPipeline(this); >+ >+ >+ /** >+ * The Realm with which this Container is associated. >+ */ >+ protected Realm realm = null; >+ >+ >+ /** >+ * The resources DirContext object with which this Container is associated. >+ */ >+ protected DirContext resources = null; >+ >+ >+ /** >+ * The string manager for this package. >+ */ >+ protected static final StringManager sm = >+ StringManager.getManager(Constants.Package); >+ >+ >+ /** >+ * Will children be started automatically when they are added. >+ */ >+ protected boolean startChildren = true; >+ >+ /** >+ * The property change support for this component. >+ */ >+ protected PropertyChangeSupport support = new PropertyChangeSupport(this); >+ >+ >+ /** >+ * The background thread. >+ */ >+ private Thread thread = null; >+ >+ >+ /** >+ * The background thread completion semaphore. >+ */ >+ private volatile boolean threadDone = false; >+ >+ >+ /** >+ * The access log to use for requests normally handled by this container >+ * that have been handled earlier in the processing chain. >+ */ >+ protected volatile AccessLog accessLog = null; >+ private volatile boolean accessLogScanComplete = false; >+ >+ >+ /** >+ * The number of threads available to process start and stop events for any >+ * children associated with this container. >+ */ >+ private int startStopThreads = 1; >+ protected ThreadPoolExecutor startStopExecutor; >+ >+ // ------------------------------------------------------------- Properties >+ >+ @Override >+ public int getStartStopThreads() { >+ return startStopThreads; >+ } >+ >+ /** >+ * Handles the special values. >+ */ >+ private int getStartStopThreadsInternal() { >+ int result = getStartStopThreads(); >+ >+ // Positive values are unchanged >+ if (result > 0) { >+ return result; >+ } >+ >+ // Zero == Runtime.getRuntime().availableProcessors() >+ // -ve == Runtime.getRuntime().availableProcessors() + value >+ // These two are the same >+ result = Runtime.getRuntime().availableProcessors() + result; >+ if (result < 1) { >+ result = 1; >+ } >+ return result; >+ } >+ >+ @Override >+ public void setStartStopThreads(int startStopThreads) { >+ this.startStopThreads = startStopThreads; >+ >+ // Use local copies to ensure thread safety >+ ThreadPoolExecutor executor = startStopExecutor; >+ if (executor != null) { >+ int newThreads = getStartStopThreadsInternal(); >+ executor.setMaximumPoolSize(newThreads); >+ executor.setCorePoolSize(newThreads); >+ } >+ } >+ >+ >+ /** >+ * Get the delay between the invocation of the backgroundProcess method on >+ * this container and its children. Child containers will not be invoked >+ * if their delay value is not negative (which would mean they are using >+ * their own thread). Setting this to a positive value will cause >+ * a thread to be spawn. After waiting the specified amount of time, >+ * the thread will invoke the executePeriodic method on this container >+ * and all its children. >+ */ >+ @Override >+ public int getBackgroundProcessorDelay() { >+ return backgroundProcessorDelay; >+ } >+ >+ >+ /** >+ * Set the delay between the invocation of the execute method on this >+ * container and its children. >+ * >+ * @param delay The delay in seconds between the invocation of >+ * backgroundProcess methods >+ */ >+ @Override >+ public void setBackgroundProcessorDelay(int delay) { >+ backgroundProcessorDelay = delay; >+ } >+ >+ >+ /** >+ * Return descriptive information about this Container implementation and >+ * the corresponding version number, in the format >+ * <code><description>/<version></code>. >+ */ >+ @Override >+ public String getInfo() { >+ return this.getClass().getName(); >+ } >+ >+ >+ /** >+ * Return the Loader with which this Container is associated. If there is >+ * no associated Loader, return the Loader associated with our parent >+ * Container (if any); otherwise, return <code>null</code>. >+ */ >+ @Override >+ public Loader getLoader() { >+ >+ if (loader != null) >+ return (loader); >+ if (parent != null) >+ return (parent.getLoader()); >+ return (null); >+ >+ } >+ >+ >+ /** >+ * Set the Loader with which this Container is associated. >+ * >+ * @param loader The newly associated loader >+ */ >+ @Override >+ public synchronized void setLoader(Loader loader) { >+ >+ // Change components if necessary >+ Loader 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("ContainerBase.setLoader: stop: ", e); >+ } >+ } >+ >+ // Start the new component if necessary >+ if (loader != null) >+ loader.setContainer(this); >+ if (getState().isAvailable() && (loader != null) && >+ (loader instanceof Lifecycle)) { >+ try { >+ ((Lifecycle) loader).start(); >+ } catch (LifecycleException e) { >+ log.error("ContainerBase.setLoader: start: ", e); >+ } >+ } >+ >+ // Report this property change to interested listeners >+ support.firePropertyChange("loader", oldLoader, this.loader); >+ >+ } >+ >+ >+ /** >+ * Return the Logger for this Container. >+ */ >+ @Override >+ public Log getLogger() { >+ >+ if (logger != null) >+ return (logger); >+ logger = LogFactory.getLog(logName()); >+ return (logger); >+ >+ } >+ >+ >+ /** >+ * Return the Manager with which this Container is associated. If there is >+ * no associated Manager, return the Manager associated with our parent >+ * Container (if any); otherwise return <code>null</code>. >+ */ >+ @Override >+ public Manager getManager() { >+ >+ if (manager != null) >+ return (manager); >+ if (parent != null) >+ return (parent.getManager()); >+ return (null); >+ >+ } >+ >+ >+ /** >+ * Set the Manager with which this Container is associated. >+ * >+ * @param manager The newly associated Manager >+ */ >+ @Override >+ public synchronized void setManager(Manager manager) { >+ >+ // Change components if necessary >+ Manager oldManager = this.manager; >+ if (oldManager == manager) >+ return; >+ this.manager = manager; >+ >+ // Stop the old component if necessary >+ if (getState().isAvailable() && (oldManager != null) && >+ (oldManager instanceof Lifecycle)) { >+ try { >+ ((Lifecycle) oldManager).stop(); >+ } catch (LifecycleException e) { >+ log.error("ContainerBase.setManager: stop: ", e); >+ } >+ } >+ >+ // Start the new component if necessary >+ if (manager != null) >+ manager.setContainer(this); >+ if (getState().isAvailable() && (manager != null) && >+ (manager instanceof Lifecycle)) { >+ try { >+ ((Lifecycle) manager).start(); >+ } catch (LifecycleException e) { >+ log.error("ContainerBase.setManager: start: ", e); >+ } >+ } >+ >+ // Report this property change to interested listeners >+ support.firePropertyChange("manager", oldManager, this.manager); >+ >+ } >+ >+ >+ /** >+ * Return an object which may be utilized for mapping to this component. >+ */ >+ @Override >+ public Object getMappingObject() { >+ return this; >+ } >+ >+ >+ /** >+ * Return the Cluster with which this Container is associated. If there is >+ * no associated Cluster, return the Cluster associated with our parent >+ * Container (if any); otherwise return <code>null</code>. >+ */ >+ @Override >+ public Cluster getCluster() { >+ if (cluster != null) >+ return (cluster); >+ >+ if (parent != null) >+ return (parent.getCluster()); >+ >+ return (null); >+ } >+ >+ >+ /** >+ * Set the Cluster with which this Container is associated. >+ * >+ * @param cluster The newly associated Cluster >+ */ >+ @Override >+ public synchronized void setCluster(Cluster cluster) { >+ // Change components if necessary >+ Cluster oldCluster = this.cluster; >+ if (oldCluster == cluster) >+ return; >+ this.cluster = cluster; >+ >+ // Stop the old component if necessary >+ if (getState().isAvailable() && (oldCluster != null) && >+ (oldCluster instanceof Lifecycle)) { >+ try { >+ ((Lifecycle) oldCluster).stop(); >+ } catch (LifecycleException e) { >+ log.error("ContainerBase.setCluster: stop: ", e); >+ } >+ } >+ >+ // Start the new component if necessary >+ if (cluster != null) >+ cluster.setContainer(this); >+ >+ if (getState().isAvailable() && (cluster != null) && >+ (cluster instanceof Lifecycle)) { >+ try { >+ ((Lifecycle) cluster).start(); >+ } catch (LifecycleException e) { >+ log.error("ContainerBase.setCluster: start: ", e); >+ } >+ } >+ >+ // Report this property change to interested listeners >+ support.firePropertyChange("cluster", oldCluster, this.cluster); >+ } >+ >+ >+ /** >+ * Return a name string (suitable for use by humans) that describes this >+ * Container. Within the set of child containers belonging to a particular >+ * parent, Container names must be unique. >+ */ >+ @Override >+ public String getName() { >+ >+ return (name); >+ >+ } >+ >+ >+ /** >+ * Set a name string (suitable for use by humans) that describes this >+ * Container. Within the set of child containers belonging to a particular >+ * parent, Container names must be unique. >+ * >+ * @param name New name of this container >+ * >+ * @exception IllegalStateException if this Container has already been >+ * added to the children of a parent Container (after which the name >+ * may not be changed) >+ */ >+ @Override >+ public void setName(String name) { >+ >+ String oldName = this.name; >+ this.name = name; >+ support.firePropertyChange("name", oldName, this.name); >+ } >+ >+ >+ /** >+ * Return if children of this container will be started automatically when >+ * they are added to this container. >+ */ >+ public boolean getStartChildren() { >+ >+ return (startChildren); >+ >+ } >+ >+ >+ /** >+ * Set if children of this container will be started automatically when >+ * they are added to this container. >+ * >+ * @param startChildren New value of the startChildren flag >+ */ >+ public void setStartChildren(boolean startChildren) { >+ >+ boolean oldStartChildren = this.startChildren; >+ this.startChildren = startChildren; >+ support.firePropertyChange("startChildren", oldStartChildren, this.startChildren); >+ } >+ >+ >+ /** >+ * Return the Container for which this Container is a child, if there is >+ * one. If there is no defined parent, return <code>null</code>. >+ */ >+ @Override >+ public Container getParent() { >+ >+ return (parent); >+ >+ } >+ >+ >+ /** >+ * Set the parent Container to which this Container is being added as a >+ * child. This Container may refuse to become attached to the specified >+ * Container by throwing an exception. >+ * >+ * @param container Container to which this Container is being added >+ * as a child >+ * >+ * @exception IllegalArgumentException if this Container refuses to become >+ * attached to the specified Container >+ */ >+ @Override >+ public void setParent(Container container) { >+ >+ Container oldParent = this.parent; >+ this.parent = container; >+ support.firePropertyChange("parent", oldParent, this.parent); >+ >+ } >+ >+ >+ /** >+ * 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 (parent != null) { >+ return (parent.getParentClassLoader()); >+ } >+ return (ClassLoader.getSystemClassLoader()); >+ >+ } >+ >+ >+ /** >+ * Set the parent class loader (if any) for this web application. >+ * This call is meaningful only <strong>before</strong> a Loader has >+ * been configured, and the specified value (if non-null) should be >+ * passed as an argument to the class loader constructor. >+ * >+ * >+ * @param parent The new parent class loader >+ */ >+ @Override >+ public void setParentClassLoader(ClassLoader parent) { >+ ClassLoader oldParentClassLoader = this.parentClassLoader; >+ this.parentClassLoader = parent; >+ support.firePropertyChange("parentClassLoader", oldParentClassLoader, >+ this.parentClassLoader); >+ >+ } >+ >+ >+ /** >+ * Return the Pipeline object that manages the Valves associated with >+ * this Container. >+ */ >+ @Override >+ public Pipeline getPipeline() { >+ >+ return (this.pipeline); >+ >+ } >+ >+ >+ /** >+ * Return the Realm with which this Container is associated. If there is >+ * no associated Realm, return the Realm associated with our parent >+ * Container (if any); otherwise return <code>null</code>. >+ */ >+ @Override >+ public Realm getRealm() { >+ >+ if (realm != null) >+ return (realm); >+ if (parent != null) >+ return (parent.getRealm()); >+ return (null); >+ >+ } >+ >+ >+ /** >+ * Set the Realm with which this Container is associated. >+ * >+ * @param realm The newly associated Realm >+ */ >+ @Override >+ public synchronized void setRealm(Realm realm) { >+ >+ // Change components if necessary >+ Realm oldRealm = this.realm; >+ if (oldRealm == realm) >+ return; >+ this.realm = realm; >+ >+ // Stop the old component if necessary >+ if (getState().isAvailable() && (oldRealm != null) && >+ (oldRealm instanceof Lifecycle)) { >+ try { >+ ((Lifecycle) oldRealm).stop(); >+ } catch (LifecycleException e) { >+ log.error("ContainerBase.setRealm: stop: ", e); >+ } >+ } >+ >+ // Start the new component if necessary >+ if (realm != null) >+ realm.setContainer(this); >+ if (getState().isAvailable() && (realm != null) && >+ (realm instanceof Lifecycle)) { >+ try { >+ ((Lifecycle) realm).start(); >+ } catch (LifecycleException e) { >+ log.error("ContainerBase.setRealm: start: ", e); >+ } >+ } >+ >+ // Report this property change to interested listeners >+ support.firePropertyChange("realm", oldRealm, this.realm); >+ >+ } >+ >+ >+ /** >+ * Return the resources DirContext object with which this Container is >+ * associated. If there is no associated resources object, return the >+ * resources associated with our parent Container (if any); otherwise >+ * return <code>null</code>. >+ */ >+ @Override >+ public DirContext getResources() { >+ if (resources != null) >+ return (resources); >+ if (parent != null) >+ return (parent.getResources()); >+ return (null); >+ >+ } >+ >+ >+ /** >+ * Set the resources DirContext object with which this Container is >+ * associated. >+ * >+ * @param resources The newly associated DirContext >+ */ >+ @Override >+ public synchronized void setResources(DirContext resources) { >+ // Called from StandardContext.setResources() >+ // <- StandardContext.start() >+ // <- ContainerBase.addChildInternal() >+ >+ // Change components if necessary >+ DirContext oldResources = this.resources; >+ if (oldResources == resources) >+ return; >+ Hashtable<String, String> env = new Hashtable<String, String>(); >+ if (getParent() != null) >+ env.put(ProxyDirContext.HOST, getParent().getName()); >+ env.put(ProxyDirContext.CONTEXT, getName()); >+ this.resources = new ProxyDirContext(env, resources); >+ // Report this property change to interested listeners >+ support.firePropertyChange("resources", oldResources, this.resources); >+ >+ } >+ >+ >+ // ------------------------------------------------------ Container Methods >+ >+ >+ /** >+ * Add a new child Container to those associated with this Container, >+ * if supported. Prior to adding this Container to the set of children, >+ * the child's <code>setParent()</code> method must be called, with this >+ * Container as an argument. This method may thrown an >+ * <code>IllegalArgumentException</code> if this Container chooses not >+ * to be attached to the specified Container, in which case it is not added >+ * >+ * @param child New child Container to be added >+ * >+ * @exception IllegalArgumentException if this exception is thrown by >+ * the <code>setParent()</code> method of the child Container >+ * @exception IllegalArgumentException if the new child does not have >+ * a name unique from that of existing children of this Container >+ * @exception IllegalStateException if this Container does not support >+ * child Containers >+ */ >+ @Override >+ public void addChild(Container child) { >+ if (Globals.IS_SECURITY_ENABLED) { >+ PrivilegedAction<Void> dp = >+ new PrivilegedAddChild(child); >+ AccessController.doPrivileged(dp); >+ } else { >+ addChildInternal(child); >+ } >+ } >+ >+ private void addChildInternal(Container child) { >+ >+ if( log.isDebugEnabled() ) >+ log.debug("Add child " + child + " " + this); >+ synchronized(children) { >+ if (children.get(child.getName()) != null) >+ throw new IllegalArgumentException("addChild: Child name '" + >+ child.getName() + >+ "' is not unique"); >+ child.setParent(this); // May throw IAE >+ children.put(child.getName(), child); >+ } >+ >+ // Start child >+ // Don't do this inside sync block - start can be a slow process and >+ // locking the children object can cause problems elsewhere >+ if ((getState().isAvailable() || >+ LifecycleState.STARTING_PREP.equals(getState())) && >+ startChildren) { >+ boolean success = false; >+ try { >+ child.start(); >+ success = true; >+ } catch (LifecycleException e) { >+ log.error("ContainerBase.addChild: start: ", e); >+ throw new IllegalStateException >+ ("ContainerBase.addChild: start: " + e); >+ } finally { >+ if (!success) { >+ synchronized (children) { >+ children.remove(child.getName()); >+ } >+ } >+ } >+ } >+ >+ fireContainerEvent(ADD_CHILD_EVENT, child); >+ } >+ >+ >+ /** >+ * Add a container event listener to this component. >+ * >+ * @param listener The listener to add >+ */ >+ @Override >+ public void addContainerListener(ContainerListener listener) { >+ >+ synchronized (listeners) { >+ listeners.add(listener); >+ } >+ >+ } >+ >+ >+ /** >+ * Add a property change listener to this component. >+ * >+ * @param listener The listener to add >+ */ >+ @Override >+ public void addPropertyChangeListener(PropertyChangeListener listener) { >+ >+ support.addPropertyChangeListener(listener); >+ >+ } >+ >+ >+ /** >+ * Return the child Container, associated with this Container, with >+ * the specified name (if any); otherwise, return <code>null</code> >+ * >+ * @param name Name of the child Container to be retrieved >+ */ >+ @Override >+ public Container findChild(String name) { >+ >+ if (name == null) >+ return (null); >+ synchronized (children) { >+ return children.get(name); >+ } >+ >+ } >+ >+ >+ /** >+ * Return the set of children Containers associated with this Container. >+ * If this Container has no children, a zero-length array is returned. >+ */ >+ @Override >+ public Container[] findChildren() { >+ >+ synchronized (children) { >+ Container results[] = new Container[children.size()]; >+ return children.values().toArray(results); >+ } >+ >+ } >+ >+ >+ /** >+ * Return the set of container listeners associated with this Container. >+ * If this Container has no registered container listeners, a zero-length >+ * array is returned. >+ */ >+ @Override >+ public ContainerListener[] findContainerListeners() { >+ >+ synchronized (listeners) { >+ ContainerListener[] results = >+ new ContainerListener[listeners.size()]; >+ return listeners.toArray(results); >+ } >+ >+ } >+ >+ >+ /** >+ * Process the specified Request, to produce the corresponding Response, >+ * by invoking the first Valve in our pipeline (if any), or the basic >+ * Valve otherwise. >+ * >+ * @param request Request to be processed >+ * @param response Response to be produced >+ * >+ * @exception IllegalStateException if neither a pipeline or a basic >+ * Valve have been configured for this Container >+ * @exception IOException if an input/output error occurred while >+ * processing >+ * @exception ServletException if a ServletException was thrown >+ * while processing this request >+ */ >+ @Override >+ public void invoke(Request request, Response response) >+ throws IOException, ServletException { >+ >+ pipeline.getFirst().invoke(request, response); >+ >+ } >+ >+ >+ /** >+ * Remove an existing child Container from association with this parent >+ * Container. >+ * >+ * @param child Existing child Container to be removed >+ */ >+ @Override >+ public void removeChild(Container child) { >+ >+ if (child == null) { >+ return; >+ } >+ >+ synchronized(children) { >+ if (children.get(child.getName()) == null) >+ return; >+ children.remove(child.getName()); >+ } >+ >+ try { >+ if (child.getState().isAvailable()) { >+ child.stop(); >+ } >+ } catch (LifecycleException e) { >+ log.error("ContainerBase.removeChild: stop: ", e); >+ } >+ >+ fireContainerEvent(REMOVE_CHILD_EVENT, child); >+ >+ try { >+ // child.destroy() may have already been called which would have >+ // triggered this call. If that is the case, no need to destroy the >+ // child again. >+ if (!LifecycleState.DESTROYING.equals(child.getState())) { >+ child.destroy(); >+ } >+ } catch (LifecycleException e) { >+ log.error("ContainerBase.removeChild: destroy: ", e); >+ } >+ >+ } >+ >+ >+ /** >+ * Remove a container event listener from this component. >+ * >+ * @param listener The listener to remove >+ */ >+ @Override >+ public void removeContainerListener(ContainerListener listener) { >+ >+ synchronized (listeners) { >+ listeners.remove(listener); >+ } >+ >+ } >+ >+ >+ /** >+ * Remove a property change listener from this component. >+ * >+ * @param listener The listener to remove >+ */ >+ @Override >+ public void removePropertyChangeListener(PropertyChangeListener listener) { >+ >+ support.removePropertyChangeListener(listener); >+ >+ } >+ >+ >+ @Override >+ protected void initInternal() throws LifecycleException { >+ BlockingQueue<Runnable> startStopQueue = >+ new LinkedBlockingQueue<Runnable>(); >+ startStopExecutor = new ThreadPoolExecutor(0, >+ getStartStopThreadsInternal(), 10, TimeUnit.SECONDS, >+ startStopQueue); >+ super.initInternal(); >+ } >+ >+ >+ /** >+ * 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 { >+ >+ // Start our subordinate components, if any >+ if ((loader != null) && (loader instanceof Lifecycle)) >+ ((Lifecycle) loader).start(); >+ logger = null; >+ getLogger(); >+ if ((logger != null) && (logger instanceof Lifecycle)) >+ ((Lifecycle) logger).start(); >+ if ((manager != null) && (manager instanceof Lifecycle)) >+ ((Lifecycle) manager).start(); >+ if ((cluster != null) && (cluster instanceof Lifecycle)) >+ ((Lifecycle) cluster).start(); >+ if ((realm != null) && (realm instanceof Lifecycle)) >+ ((Lifecycle) realm).start(); >+ if ((resources != null) && (resources instanceof Lifecycle)) >+ ((Lifecycle) resources).start(); >+ >+ // Start our child containers, if any >+ Container children[] = findChildren(); >+ List<Future<Void>> results = new ArrayList<Future<Void>>(); >+ for (int i = 0; i < children.length; i++) { >+ results.add(startStopExecutor.submit(new StartChild(children[i]))); >+ } >+ >+ boolean fail = false; >+ for (Future<Void> result : results) { >+ try { >+ result.get(); >+ } catch (Exception e) { >+ log.error(sm.getString("containerBase.threadedStartFailed"), e); >+ fail = true; >+ } >+ >+ } >+ if (fail) { >+ throw new LifecycleException( >+ sm.getString("containerBase.threadedStartFailed")); >+ } >+ >+ // Start the Valves in our pipeline (including the basic), if any >+ if (pipeline instanceof Lifecycle) >+ ((Lifecycle) pipeline).start(); >+ >+ >+ setState(LifecycleState.STARTING); >+ >+ // Start our thread >+ threadStart(); >+ >+ } >+ >+ >+ /** >+ * 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 { >+ >+ // Stop our thread >+ threadStop(); >+ >+ setState(LifecycleState.STOPPING); >+ >+ // Stop the Valves in our pipeline (including the basic), if any >+ if (pipeline instanceof Lifecycle && >+ ((Lifecycle) pipeline).getState().isAvailable()) { >+ ((Lifecycle) pipeline).stop(); >+ } >+ >+ // Stop our child containers, if any >+ Container children[] = findChildren(); >+ List<Future<Void>> results = new ArrayList<Future<Void>>(); >+ for (int i = 0; i < children.length; i++) { >+ results.add(startStopExecutor.submit(new StopChild(children[i]))); >+ } >+ >+ boolean fail = false; >+ for (Future<Void> result : results) { >+ try { >+ result.get(); >+ } catch (Exception e) { >+ log.error(sm.getString("containerBase.threadedStopFailed"), e); >+ fail = true; >+ } >+ } >+ if (fail) { >+ throw new LifecycleException( >+ sm.getString("containerBase.threadedStopFailed")); >+ } >+ >+ // Stop our subordinate components, if any >+ if ((resources != null) && (resources instanceof Lifecycle)) { >+ ((Lifecycle) resources).stop(); >+ } >+ if ((realm != null) && (realm instanceof Lifecycle)) { >+ ((Lifecycle) realm).stop(); >+ } >+ if ((cluster != null) && (cluster instanceof Lifecycle)) { >+ ((Lifecycle) cluster).stop(); >+ } >+ if ((manager != null) && (manager instanceof Lifecycle) && >+ ((Lifecycle) manager).getState().isAvailable() ) { >+ ((Lifecycle) manager).stop(); >+ } >+ if ((logger != null) && (logger instanceof Lifecycle)) { >+ ((Lifecycle) logger).stop(); >+ } >+ if ((loader != null) && (loader instanceof Lifecycle)) { >+ ((Lifecycle) loader).stop(); >+ } >+ } >+ >+ @Override >+ protected void destroyInternal() throws LifecycleException { >+ >+ // Stop the Valves in our pipeline (including the basic), if any >+ if (pipeline instanceof Lifecycle) { >+ ((Lifecycle) pipeline).destroy(); >+ } >+ >+ // Remove children now this container is being destroyed >+ for (Container child : findChildren()) { >+ removeChild(child); >+ } >+ >+ // Required if the child is destroyed directly. >+ if (parent != null) { >+ parent.removeChild(this); >+ } >+ >+ startStopExecutor.shutdownNow(); >+ >+ super.destroyInternal(); >+ } >+ >+ >+ /** >+ * Check this container for an access log and if none is found, look to the >+ * parent. If there is no parent and still none is found, use the NoOp >+ * access log. >+ */ >+ @Override >+ public void logAccess(Request request, Response response, long time, >+ boolean useDefault) { >+ >+ boolean logged = false; >+ >+ if (getAccessLog() != null) { >+ getAccessLog().log(request, response, time); >+ logged = true; >+ } >+ >+ if (getParent() != null) { >+ // No need to use default logger once request/response has been logged >+ // once >+ getParent().logAccess(request, response, time, (useDefault && !logged)); >+ } >+ } >+ >+ @Override >+ public AccessLog getAccessLog() { >+ >+ if (accessLogScanComplete) { >+ return accessLog; >+ } >+ >+ AccessLogAdapter adapter = null; >+ Valve valves[] = getPipeline().getValves(); >+ for (Valve valve : valves) { >+ if (valve instanceof AccessLog) { >+ if (adapter == null) { >+ adapter = new AccessLogAdapter((AccessLog) valve); >+ } else { >+ adapter.add((AccessLog) valve); >+ } >+ } >+ } >+ if (adapter != null) { >+ accessLog = adapter; >+ } >+ accessLogScanComplete = true; >+ return accessLog; >+ } >+ >+ // ------------------------------------------------------- Pipeline Methods >+ >+ >+ /** >+ * Convenience method, intended for use by the digester to simplify the >+ * process of adding Valves to containers. See >+ * {@link Pipeline#addValve(Valve)} for full details. Components other than >+ * the digester should use {@link #getPipeline()}.{@link #addValve(Valve)} in case a >+ * future implementation provides an alternative method for the digester to >+ * use. >+ * >+ * @param valve Valve to be added >+ * >+ * @exception IllegalArgumentException if this Container refused to >+ * accept the specified Valve >+ * @exception IllegalArgumentException if the specified Valve refuses to be >+ * associated with this Container >+ * @exception IllegalStateException if the specified Valve is already >+ * associated with a different Container >+ */ >+ public synchronized void addValve(Valve valve) { >+ >+ pipeline.addValve(valve); >+ } >+ >+ >+ /** >+ * Execute a periodic task, such as reloading, etc. This method will be >+ * invoked inside the classloading context of this container. Unexpected >+ * throwables will be caught and logged. >+ */ >+ @Override >+ public void backgroundProcess() { >+ >+ if (!getState().isAvailable()) >+ return; >+ >+ if (cluster != null) { >+ try { >+ cluster.backgroundProcess(); >+ } catch (Exception e) { >+ log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e); >+ } >+ } >+ if (loader != null) { >+ try { >+ loader.backgroundProcess(); >+ } catch (Exception e) { >+ log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e); >+ } >+ } >+ if (manager != null) { >+ try { >+ manager.backgroundProcess(); >+ } catch (Exception e) { >+ log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e); >+ } >+ } >+ if (realm != null) { >+ try { >+ realm.backgroundProcess(); >+ } catch (Exception e) { >+ log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e); >+ } >+ } >+ Valve current = pipeline.getFirst(); >+ while (current != null) { >+ try { >+ current.backgroundProcess(); >+ } catch (Exception e) { >+ log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e); >+ } >+ current = current.getNext(); >+ } >+ fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null); >+ } >+ >+ >+ // ------------------------------------------------------ Protected Methods >+ >+ >+ /** >+ * Notify all container event listeners that a particular event has >+ * occurred for this Container. The default implementation performs >+ * this notification synchronously using the calling thread. >+ * >+ * @param type Event type >+ * @param data Event data >+ */ >+ @Override >+ public void fireContainerEvent(String type, Object data) { >+ >+ if (listeners.size() < 1) >+ return; >+ ContainerEvent event = new ContainerEvent(this, type, data); >+ ContainerListener list[] = new ContainerListener[0]; >+ synchronized (listeners) { >+ list = listeners.toArray(list); >+ } >+ for (int i = 0; i < list.length; i++) >+ list[i].containerEvent(event); >+ >+ } >+ >+ >+ /** >+ * Return the abbreviated name of this container for logging messages >+ */ >+ protected String logName() { >+ >+ if (logName != null) { >+ return logName; >+ } >+ String loggerName = null; >+ Container current = this; >+ while (current != null) { >+ String name = current.getName(); >+ if ((name == null) || (name.equals(""))) { >+ name = "/"; >+ } else if (name.startsWith("##")) { >+ name = "/" + name; >+ } >+ loggerName = "[" + name + "]" >+ + ((loggerName != null) ? ("." + loggerName) : ""); >+ current = current.getParent(); >+ } >+ logName = ContainerBase.class.getName() + "." + loggerName; >+ return logName; >+ >+ } >+ >+ >+ // -------------------- JMX and Registration -------------------- >+ >+ @Override >+ protected String getDomainInternal() { >+ return MBeanUtils.getDomain(this); >+ } >+ >+ public ObjectName[] getChildren() { >+ ObjectName result[]=new ObjectName[children.size()]; >+ Iterator<Container> it=children.values().iterator(); >+ int i=0; >+ while( it.hasNext() ) { >+ Object next=it.next(); >+ if( next instanceof ContainerBase ) { >+ result[i++]=((ContainerBase)next).getObjectName(); >+ } >+ } >+ return result; >+ } >+ >+ >+ // -------------------- Background Thread -------------------- >+ >+ /** >+ * Start the background thread that will periodically check for >+ * session timeouts. >+ */ >+ protected void threadStart() { >+ >+ if (thread != null) >+ return; >+ if (backgroundProcessorDelay <= 0) >+ return; >+ >+ threadDone = false; >+ String threadName = "ContainerBackgroundProcessor[" + toString() + "]"; >+ thread = new Thread(new ContainerBackgroundProcessor(), threadName); >+ thread.setDaemon(true); >+ thread.start(); >+ >+ } >+ >+ >+ /** >+ * Stop the background thread that is periodically checking for >+ * session timeouts. >+ */ >+ protected void threadStop() { >+ >+ if (thread == null) >+ return; >+ >+ threadDone = true; >+ thread.interrupt(); >+ try { >+ thread.join(); >+ } catch (InterruptedException e) { >+ // Ignore >+ } >+ >+ thread = null; >+ >+ } >+ >+ >+ // -------------------------------------- ContainerExecuteDelay Inner Class >+ >+ >+ /** >+ * Private thread class to invoke the backgroundProcess method >+ * of this container and its children after a fixed delay. >+ */ >+ protected class ContainerBackgroundProcessor implements Runnable { >+ >+ @Override >+ public void run() { >+ while (!threadDone) { >+ try { >+ Thread.sleep(backgroundProcessorDelay * 1000L); >+ } catch (InterruptedException e) { >+ // Ignore >+ } >+ if (!threadDone) { >+ Container parent = (Container) getMappingObject(); >+ ClassLoader cl = >+ Thread.currentThread().getContextClassLoader(); >+ if (parent.getLoader() != null) { >+ cl = parent.getLoader().getClassLoader(); >+ } >+ processChildren(parent, cl); >+ } >+ } >+ } >+ >+ protected void processChildren(Container container, ClassLoader cl) { >+ try { >+ if (container.getLoader() != null) { >+ Thread.currentThread().setContextClassLoader >+ (container.getLoader().getClassLoader()); >+ } >+ container.backgroundProcess(); >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ log.error("Exception invoking periodic operation: ", t); >+ } finally { >+ Thread.currentThread().setContextClassLoader(cl); >+ } >+ Container[] children = container.findChildren(); >+ for (int i = 0; i < children.length; i++) { >+ if (children[i].getBackgroundProcessorDelay() <= 0) { >+ processChildren(children[i], cl); >+ } >+ } >+ } >+ } >+ >+ >+ // ----------------------------- Inner classes used with start/stop Executor >+ >+ private static class StartChild implements Callable<Void> { >+ >+ private Container child; >+ >+ public StartChild(Container child) { >+ this.child = child; >+ } >+ >+ @Override >+ public Void call() throws LifecycleException { >+ child.start(); >+ return null; >+ } >+ } >+ >+ private static class StopChild implements Callable<Void> { >+ >+ private Container child; >+ >+ public StopChild(Container child) { >+ this.child = child; >+ } >+ >+ @Override >+ public Void call() throws LifecycleException { >+ child.stop(); >+ return null; >+ } >+ } >+} >diff --git a/java/org/apache/catalina/core/LocalStrings.properties b/java/org/apache/catalina/core/LocalStrings.properties >index 839005c..f51c19e 100644 >--- a/java/org/apache/catalina/core/LocalStrings.properties >+++ b/java/org/apache/catalina/core/LocalStrings.properties >@@ -1,255 +1,257 @@ >-# 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. >- >-applicationContext.addFilter.ise=Filters can not be added to context {0} as the context has been initialised >-applicationContext.addListener.iae.cnfe=Unable to create an instance of type [{0}] >-applicationContext.addListener.iae.wrongType=The type specified [{0}] is not one of the expected listener types >-applicationContext.addListener.iae.sclNotAllowed=Once the first ServletContextListener has been called, no more ServletContextListeners may be added. >-applicationContext.addListener.ise=Listeners can not be added to context {0} as the context has been initialised >-applicationContext.addRole.ise=Roles can not be added to context {0} as the context has been initialised >-applicationContext.addServlet.ise=Servlets can not be added to context {0} as the context has been initialised >-applicationContext.attributeEvent=Exception thrown by attributes event listener >-applicationContext.mapping.error=Error during mapping >-applicationContext.requestDispatcher.iae=Path {0} does not start with a "/" character >-applicationContext.resourcePaths.iae=Path {0} does not start with a "/" character >-applicationContext.role.iae=An individual role to declare for context [{0}] may not be null nor the empty string >-applicationContext.roles.iae=Array of roles to declare for context [{0}] cannot be null >-applicationContext.setAttribute.namenull=Name cannot be null >-applicationContext.addSessionCookieConfig.ise=Session Cookie configuration cannot be set for context {0} as the context has been initialised >-applicationContext.setSessionTracking.ise=The session tracking modes for context {0} cannot be set whilst the context is running >-applicationContext.setSessionTracking.iae.invalid=The session tracking mode {0} requested for context {1} is not supported by that context >-applicationContext.setSessionTracking.iae.ssl=The session tracking modes requested for context {1} included SSL and at least one other mode. SSL may not be configured with other modes. >-applicationContext.lookup.error=Failed to locate resource [{0}] in context [{1}] >-applicationDispatcher.allocateException=Allocate exception for servlet {0} >-applicationDispatcher.deallocateException=Deallocate exception for servlet {0} >-applicationDispatcher.forward.ise=Cannot forward after response has been committed >-applicationDispatcher.forward.throw=Forwarded resource threw an exception >-applicationDispatcher.include.throw=Included resource threw an exception >-applicationDispatcher.isUnavailable=Servlet {0} is currently unavailable >-applicationDispatcher.serviceException=Servlet.service() for servlet {0} threw exception >-applicationDispatcher.specViolation.request=Original SevletRequest or wrapped original ServletRequest not passed to RequestDispatcher in violation of SRV.8.2 and SRV.14.2.5.1 >-applicationDispatcher.specViolation.response=Original SevletResponse or wrapped original ServletResponse not passed to RequestDispatcher in violation of SRV.8.2 and SRV.14.2.5.1 >-applicationFilterConfig.jmxRegisterFail=JMX registration failed for filter of type [{0}] and name [{1}] >-applicationFilterConfig.jmxUnregister=JMX de-registration complete for filter of type [{0}] and name [{1}] >-applicationFilterConfig.jmxUnregisterFail=JMX de-registration failed for filter of type [{0}] and name [{1}] >-applicationFilterRegistration.nullInitParam=Unable to set initialisation parameter for filter due to null name and/or value. Name [{0}], Value [{1}] >-applicationFilterRegistration.nullInitParams=Unable to set initialisation parameters for filter due to null name and/or value. Name [{0}], Value [{1}] >-applicationRequest.badParent=Cannot locate parent Request implementation >-applicationRequest.badRequest=Request is not a javax.servlet.ServletRequestWrapper >-applicationResponse.badParent=Cannot locate parent Response implementation >-applicationResponse.badResponse=Response is not a javax.servlet.ServletResponseWrapper >-applicationServletRegistration.setServletSecurity.iae=Null constraint specified for servlet [{0}] deployed to context with name [{1}] >-applicationServletRegistration.setServletSecurity.ise=Security constraints can't be added to servlet [{0}] deployed to context with name [{1}] as the context has already been initialised >-aprListener.aprInit=The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: {0} >-aprListener.tcnInvalid=An incompatible version {0} of the APR based Apache Tomcat Native library is installed, while Tomcat requires version {1} >-aprListener.tcnVersion=An older version {0} of the APR based Apache Tomcat Native library is installed, while Tomcat recommends a minimum version of {1} >-aprListener.aprDestroy=Failed shutdown of APR based Apache Tomcat Native library >-aprListener.sslInit=Failed to initialize the SSLEngine. >-aprListener.tcnValid=Loaded APR based Apache Tomcat Native library {0}. >-aprListener.flags=APR capabilities: IPv6 [{0}], sendfile [{1}], accept filters [{2}], random [{3}]. >-asyncContextImpl.requestEnded=The request associated with the AsyncContext has already completed processing. >-containerBase.alreadyStarted=Container {0} has already been started >-containerBase.notConfigured=No basic Valve has been configured >-containerBase.notStarted=Container {0} has not been started >-containerBase.backgroundProcess.cluster=Exception processing cluster {0} background process >-containerBase.backgroundProcess.loader=Exception processing loader {0} background process >-containerBase.backgroundProcess.manager=Exception processing manager {0} background process >-containerBase.backgroundProcess.realm=Exception processing realm {0} background process >-containerBase.backgroundProcess.valve=Exception processing valve {0} background process >-fastEngineMapper.alreadyStarted=FastEngineMapper {0} has already been started >-fastEngineMapper.notStarted=FastEngineMapper {0} has not yet been started >-filterChain.filter=Filter execution threw an exception >-filterChain.servlet=Servlet execution threw an exception >-httpContextMapper.container=This container is not a StandardContext >-httpEngineMapper.container=This container is not a StandardEngine >-httpHostMapper.container=This container is not a StandardHost >-interceptorValve.alreadyStarted=InterceptorValve has already been started >-interceptorValve.notStarted=InterceptorValve has not yet been started >-jreLeakListener.keepAliveFail=Failed to trigger creation of the sun.net.www.http.HttpClient class during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs. >-jreLeakListener.gcDaemonFail=Failed to trigger creation of the GC Daemon thread during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs. >-jreLeakListener.jarUrlConnCacheFail=Failed to disable Jar URL connection caching by default >-jreLeakListener.xmlParseFail=Error whilst attempting to prevent memory leaks during XML parsing >-jreLeakListener.authPolicyFail=Error whilst attempting to prevent memory leak in javax.security.auth.Policy class >-jreLeakListener.ldapPoolManagerFail=Failed to trigger creation of the com.sun.jndi.ldap.LdapPoolManager class during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs. >-jreLeakListener.classToInitializeFail=Failed to load class {0} during Tomcat start to prevent possible memory leaks. >-naming.wsdlFailed=Failed to find wsdl file: {0} >-naming.bindFailed=Failed to bind object: {0} >-naming.jmxRegistrationFailed=Failed to register in JMX: {0} >-naming.unbindFailed=Failed to unbind object: {0} >-naming.invalidEnvEntryType=Environment entry {0} has an invalid type >-naming.invalidEnvEntryValue=Environment entry {0} has an invalid value >-naming.namingContextCreationFailed=Creation of the naming context failed: {0} >-standardContext.invalidWrapperClass={0} is not a subclass of StandardWrapper >-standardContext.alreadyStarted=Context has already been started >-standardContext.applicationListener=Error configuring application listener of class {0} >-standardContext.applicationSkipped=Skipped installing application listeners due to previous error(s) >-standardContext.badRequest=Invalid request path ({0}). >-standardContext.cluster.noManager=No manager found. Checking if cluster manager should be used. Cluster configured: [{0}], Application distributable: [{1}] >-standardContext.crlfinurl=The URL pattern "{0}" contains a CR or LF and so can never be matched. >-standardContext.duplicateListener=The listener "{0}" is already configured for this context. The duplicate definition has been ignored. >-standardContext.errorPage.error=Error page location {0} must start with a ''/'' >-standardContext.errorPage.required=ErrorPage cannot be null >-standardContext.errorPage.warning=WARNING: Error page location {0} must start with a ''/'' in Servlet 2.4 >-standardContext.filterMap.either=Filter mapping must specify either a <url-pattern> or a <servlet-name> >-standardContext.filterMap.name=Filter mapping specifies an unknown filter name {0} >-standardContext.filterMap.pattern=Invalid <url-pattern> {0} in filter mapping >-standardContext.filterStart=Exception starting filter {0} >-standardContext.filterStartFailed=Failed to start application Filters successfully >-standardContext.requestListener.requestInit=Exception sending request initialized lifecycle event to listener instance of class {0} >-standardContext.requestListener.requestDestroy=Exception sending request destroyed lifecycle event to listener instance of class {0} >-standardContext.requestListenerStartFailed=Failed to start request listener valve successfully >-standardContext.requestListenerConfig.added=Added request listener Valve >-standardContext.requestListenerConfig.error=Exception adding request listener Valve: {0} >-standardContext.isUnavailable=This application is not currently available >-standardContext.listenerStart=Exception sending context initialized event to listener instance of class {0} >-standardContext.listenerStartFailed=Failed to start application Listeners successfully >-standardContext.listenerStop=Exception sending context destroyed event to listener instance of class {0} >-standardContext.loginConfig.errorPage=Form error page {0} must start with a ''/' >-standardContext.loginConfig.errorWarning=WARNING: Form error page {0} must start with a ''/'' in Servlet 2.4 >-standardContext.loginConfig.loginPage=Form login page {0} must start with a ''/' >-standardContext.loginConfig.loginWarning=WARNING: Form login page {0} must start with a ''/'' in Servlet 2.4 >-standardContext.loginConfig.required=LoginConfig cannot be null >-standardContext.manager=Configured a manager of class [{0}] >-standardContext.mappingError=MAPPING configuration error for relative URI {0} >-standardContext.namingResource.init.fail=Failed to init new naming resources >-standardContext.namingResource.destroy.fail=Failed to destroy old naming resources >-standardContext.noResourceJar=Resource JARs are not supported. The JAR found at [{0}] will not be used to provide static content for context with name [{1}] >-standardContext.notFound=The requested resource ({0}) is not available. >-standardContext.notReloadable=Reloading is disabled on this Context >-standardContext.notStarted=Context with name [{0}] has not yet been started >-standardContext.notWrapper=Child of a Context must be a Wrapper >-standardContext.parameter.duplicate=Duplicate context initialization parameter {0} >-standardContext.parameter.required=Both parameter name and parameter value are required >-standardContext.pathInvalid=A context path must either be an empty string or start with a ''/''. The path [{0}] does not meet these criteria and has been changed to [{1}] >-standardContext.reloadingCompleted=Reloading Context with name [{0}] is completed >-standardContext.reloadingFailed=Reloading this Context failed due to previous errors >-standardContext.reloadingStarted=Reloading Context with name [{0}] has started >-standardContext.resourcesStart=Error starting static Resources >-standardContext.securityConstraint.mixHttpMethod=It is not permitted to mix <http-method> and <http-method-omission> in the same web resource collection >-standardContext.securityConstraint.pattern=Invalid <url-pattern> {0} in security constraint >-standardContext.servletMap.name=Servlet mapping specifies an unknown servlet name {0} >-standardContext.servletMap.pattern=Invalid <url-pattern> {0} in servlet mapping >-standardContext.startCleanup=Exception during cleanup after start failed >-standardContext.startFailed=Context [{0}] startup failed due to previous errors >-standardContext.startingContext=Exception starting Context with name [{0}] >-standardContext.startingLoader=Exception starting Loader >-standardContext.startingManager=Exception starting Manager >-standardContext.startingWrapper=Exception starting Wrapper for servlet {0} >-standardContext.stoppingContext=Exception stopping Context with name [{0}] >-standardContext.stoppingLoader=Exception stopping Loader >-standardContext.stoppingManager=Exception stopping Manager >-standardContext.stoppingWrapper=Exception stopping Wrapper for servlet {0} >-standardContext.urlDecode=Cannot URL decode request path {0} >-standardContext.urlPattern.patternWarning=WARNING: URL pattern {0} must start with a ''/'' in Servlet 2.4 >-standardContext.urlValidate=Cannot validate URL decoded request path {0} >-standardContext.workPath=Exception obtaining work path for context [{0}] >-standardContext.workCreateException=Failed to determine absolute work directory from directory [{0}] and CATALINA_HOME [{1}] for context [{2}] >-standardContext.workCreateFail=Failed to create work directory [{0}] for context [{1}] >-standardContextValve.acknowledgeException=Failed to acknowledge request with a 100 (Continue) response >-standardEngine.alreadyStarted=Engine has already been started >-standardEngine.jvmRouteFail=Failed to set Engine's jvmRoute attribute from system property >-standardEngine.mappingError=MAPPING configuration error for server name {0} >-standardEngine.noHost=No Host matches server name {0} >-standardEngine.noHostHeader=HTTP/1.1 request with no Host: header >-standardEngine.notHost=Child of an Engine must be a Host >-standardEngine.notParent=Engine cannot have a parent Container >-standardEngine.notStarted=Engine has not yet been started >-standardEngine.unfoundHost=Virtual host {0} not found >-standardEngine.unknownHost=No server host specified in this request >-standardEngine.unregister.mbeans.failed=Error in destroy() for mbean file {0} >-standardHost.accessBase=Cannot access document base directory {0} >-standardHost.alreadyStarted=Host has already been started >-standardHost.appBase=Application base directory {0} does not exist >-standardHost.clientAbort=Remote Client Aborted Request, IOException: {0} >-standardHost.configRequired=URL to configuration file is required >-standardHost.configNotAllowed=Use of configuration file is not allowed >-standardHost.installBase=Only web applications in the Host web application directory can be installed >-standardHost.installing=Installing web application at context path {0} from URL {1} >-standardHost.installingWAR=Installing web application from URL {0} >-standardHost.installingXML=Processing Context configuration file URL {0} >-standardHost.installError=Error deploying application at context path {0} >-standardHost.invalidErrorReportValveClass=Couldn''t load specified error report valve class: {0} >-standardHost.docBase=Document base directory {0} already exists >-standardHost.mappingError=MAPPING configuration error for request URI {0} >-standardHost.noContext=No Context configured to process this request >-standardHost.noHost=No Host configured to process this request >-standardHost.notContext=Child of a Host must be a Context >-standardHost.notStarted=Host has not yet been started >-standardHost.nullName=Host name is required >-standardHost.pathFormat=Invalid context path: {0} >-standardHost.pathMatch=Context path {0} must match the directory or WAR file name: {1} >-standardHost.pathMissing=Context path {0} is not currently in use >-standardHost.pathRequired=Context path is required >-standardHost.pathUsed=Context path {0} is already in use >-standardHost.removing=Removing web application at context path {0} >-standardHost.removeError=Error removing application at context path {0} >-standardHost.start=Starting web application at context path {0} >-standardHost.stop=Stopping web application at context path {0} >-standardHost.unfoundContext=Cannot find context for request URI {0} >-standardHost.warRequired=URL to web application archive is required >-standardHost.warURL=Invalid URL for web application archive: {0} >-standardServer.onameFail=MBean name specified for Server [{0}] is not valid >-standardServer.shutdownViaPort=A valid shutdown command was received via the shutdown port. Stopping the Server instance. >-standardService.connector.initFailed=Failed to initialize connector [{0}] >-standardService.connector.destroyFailed=Failed to destroy connector [{0}] >-standardService.connector.pauseFailed=Failed to pause connector [{0}] >-standardService.connector.startFailed=Failed to start connector [{0}] >-standardService.connector.stopFailed=Failed to stop connector [{0}] >-standardService.initialize.failed=Service initializing at {0} failed >-standardService.onameFail=MBean name specified for Service [{0}] is not valid >-standardService.register.failed=Error registering Service at domain {0} >-standardService.start.name=Starting service {0} >-standardService.stop.name=Stopping service {0} >-standardThreadExecutor.onameFail=MBean name specified for Thread Executor [{0}] is not valid >-standardWrapper.allocate=Error allocating a servlet instance >-standardWrapper.allocateException=Allocate exception for servlet {0} >-standardWrapper.containerServlet=Loading container servlet {0} >-standardWrapper.createFilters=Create filters exception for servlet {0} >-standardWrapper.deallocateException=Deallocate exception for servlet {0} >-standardWrapper.destroyException=Servlet.destroy() for servlet {0} threw exception >-standardWrapper.exception0=Tomcat Exception Report >-standardWrapper.exception1=A Servlet Exception Has Occurred >-standardWrapper.exception2=Exception Report: >-standardWrapper.exception3=Root Cause: >-standardWrapper.initException=Servlet.init() for servlet {0} threw exception >-standardWrapper.instantiate=Error instantiating servlet class {0} >-standardWrapper.isUnavailable=Servlet {0} is currently unavailable >-standardWrapper.jasperLoader=Using Jasper classloader for servlet {0} >-standardWrapper.jspFile.format=JSP file {0} does not start with a ''/'' character >-standardWrapper.loadException=Servlet {0} threw load() exception >-standardWrapper.missingClass=Wrapper cannot find servlet class {0} or a class it depends on >-standardWrapper.missingLoader=Wrapper cannot find Loader for servlet {0} >-standardWrapper.notChild=Wrapper container may not have child containers >-standardWrapper.notClass=No servlet class has been specified for servlet {0} >-standardWrapper.notContext=Parent container of a Wrapper must be a Context >-standardWrapper.notFound=Servlet {0} is not available >-standardWrapper.notServlet=Class {0} is not a Servlet >-standardWrapper.releaseFilters=Release filters exception for servlet {0} >-standardWrapper.serviceException=Servlet.service() for servlet [{0}] in context with path [{1}] threw exception >-standardWrapper.serviceExceptionRoot=Servlet.service() for servlet [{0}] in context with path [{1}] threw exception [{2}] with root cause >-standardWrapper.statusHeader=HTTP Status {0} - {1} >-standardWrapper.statusTitle=Tomcat Error Report >-standardWrapper.unavailable=Marking servlet {0} as unavailable >-standardWrapper.unloadException=Servlet {0} threw unload() exception >-standardWrapper.unloading=Cannot allocate servlet {0} because it is being unloaded >-standardWrapper.waiting=Waiting for {0} instance(s) to be deallocated >-threadLocalLeakPreventionListener.lifecycleEvent.error=Exception processing lifecycle event {0} >-threadLocalLeakPreventionListener.containerEvent.error=Exception processing container event {0} >- >-defaultInstanceManager.restrictedServletsResource=Restricted servlets property file not found >-defaultInstanceManager.privilegedServlet=Servlet of class {0} is privileged and cannot be loaded by this web application >-defaultInstanceManager.restrictedFiltersResource=Restricted filters property file not found >-defaultInstanceManager.privilegedFilter=Filter of class {0} is privileged and cannot be loaded by this web application >-defaultInstanceManager.restrictedListenersResources="Restricted listeners property file not found >+# 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. >+ >+applicationContext.addFilter.ise=Filters can not be added to context {0} as the context has been initialised >+applicationContext.addListener.iae.cnfe=Unable to create an instance of type [{0}] >+applicationContext.addListener.iae.wrongType=The type specified [{0}] is not one of the expected listener types >+applicationContext.addListener.iae.sclNotAllowed=Once the first ServletContextListener has been called, no more ServletContextListeners may be added. >+applicationContext.addListener.ise=Listeners can not be added to context {0} as the context has been initialised >+applicationContext.addRole.ise=Roles can not be added to context {0} as the context has been initialised >+applicationContext.addServlet.ise=Servlets can not be added to context {0} as the context has been initialised >+applicationContext.attributeEvent=Exception thrown by attributes event listener >+applicationContext.mapping.error=Error during mapping >+applicationContext.requestDispatcher.iae=Path {0} does not start with a "/" character >+applicationContext.resourcePaths.iae=Path {0} does not start with a "/" character >+applicationContext.role.iae=An individual role to declare for context [{0}] may not be null nor the empty string >+applicationContext.roles.iae=Array of roles to declare for context [{0}] cannot be null >+applicationContext.setAttribute.namenull=Name cannot be null >+applicationContext.addSessionCookieConfig.ise=Session Cookie configuration cannot be set for context {0} as the context has been initialised >+applicationContext.setSessionTracking.ise=The session tracking modes for context {0} cannot be set whilst the context is running >+applicationContext.setSessionTracking.iae.invalid=The session tracking mode {0} requested for context {1} is not supported by that context >+applicationContext.setSessionTracking.iae.ssl=The session tracking modes requested for context {1} included SSL and at least one other mode. SSL may not be configured with other modes. >+applicationContext.lookup.error=Failed to locate resource [{0}] in context [{1}] >+applicationDispatcher.allocateException=Allocate exception for servlet {0} >+applicationDispatcher.deallocateException=Deallocate exception for servlet {0} >+applicationDispatcher.forward.ise=Cannot forward after response has been committed >+applicationDispatcher.forward.throw=Forwarded resource threw an exception >+applicationDispatcher.include.throw=Included resource threw an exception >+applicationDispatcher.isUnavailable=Servlet {0} is currently unavailable >+applicationDispatcher.serviceException=Servlet.service() for servlet {0} threw exception >+applicationDispatcher.specViolation.request=Original SevletRequest or wrapped original ServletRequest not passed to RequestDispatcher in violation of SRV.8.2 and SRV.14.2.5.1 >+applicationDispatcher.specViolation.response=Original SevletResponse or wrapped original ServletResponse not passed to RequestDispatcher in violation of SRV.8.2 and SRV.14.2.5.1 >+applicationFilterConfig.jmxRegisterFail=JMX registration failed for filter of type [{0}] and name [{1}] >+applicationFilterConfig.jmxUnregister=JMX de-registration complete for filter of type [{0}] and name [{1}] >+applicationFilterConfig.jmxUnregisterFail=JMX de-registration failed for filter of type [{0}] and name [{1}] >+applicationFilterRegistration.nullInitParam=Unable to set initialisation parameter for filter due to null name and/or value. Name [{0}], Value [{1}] >+applicationFilterRegistration.nullInitParams=Unable to set initialisation parameters for filter due to null name and/or value. Name [{0}], Value [{1}] >+applicationRequest.badParent=Cannot locate parent Request implementation >+applicationRequest.badRequest=Request is not a javax.servlet.ServletRequestWrapper >+applicationResponse.badParent=Cannot locate parent Response implementation >+applicationResponse.badResponse=Response is not a javax.servlet.ServletResponseWrapper >+applicationServletRegistration.setServletSecurity.iae=Null constraint specified for servlet [{0}] deployed to context with name [{1}] >+applicationServletRegistration.setServletSecurity.ise=Security constraints can't be added to servlet [{0}] deployed to context with name [{1}] as the context has already been initialised >+aprListener.aprInit=The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: {0} >+aprListener.tcnInvalid=An incompatible version {0} of the APR based Apache Tomcat Native library is installed, while Tomcat requires version {1} >+aprListener.tcnVersion=An older version {0} of the APR based Apache Tomcat Native library is installed, while Tomcat recommends a minimum version of {1} >+aprListener.aprDestroy=Failed shutdown of APR based Apache Tomcat Native library >+aprListener.sslInit=Failed to initialize the SSLEngine. >+aprListener.tcnValid=Loaded APR based Apache Tomcat Native library {0}. >+aprListener.flags=APR capabilities: IPv6 [{0}], sendfile [{1}], accept filters [{2}], random [{3}]. >+asyncContextImpl.requestEnded=The request associated with the AsyncContext has already completed processing. >+containerBase.alreadyStarted=Container {0} has already been started >+containerBase.notConfigured=No basic Valve has been configured >+containerBase.notStarted=Container {0} has not been started >+containerBase.threadedStartFailed=A child container failed during start >+containerBase.threadedStopFailed=A child container failed during stop >+containerBase.backgroundProcess.cluster=Exception processing cluster {0} background process >+containerBase.backgroundProcess.loader=Exception processing loader {0} background process >+containerBase.backgroundProcess.manager=Exception processing manager {0} background process >+containerBase.backgroundProcess.realm=Exception processing realm {0} background process >+containerBase.backgroundProcess.valve=Exception processing valve {0} background process >+fastEngineMapper.alreadyStarted=FastEngineMapper {0} has already been started >+fastEngineMapper.notStarted=FastEngineMapper {0} has not yet been started >+filterChain.filter=Filter execution threw an exception >+filterChain.servlet=Servlet execution threw an exception >+httpContextMapper.container=This container is not a StandardContext >+httpEngineMapper.container=This container is not a StandardEngine >+httpHostMapper.container=This container is not a StandardHost >+interceptorValve.alreadyStarted=InterceptorValve has already been started >+interceptorValve.notStarted=InterceptorValve has not yet been started >+jreLeakListener.keepAliveFail=Failed to trigger creation of the sun.net.www.http.HttpClient class during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs. >+jreLeakListener.gcDaemonFail=Failed to trigger creation of the GC Daemon thread during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs. >+jreLeakListener.jarUrlConnCacheFail=Failed to disable Jar URL connection caching by default >+jreLeakListener.xmlParseFail=Error whilst attempting to prevent memory leaks during XML parsing >+jreLeakListener.authPolicyFail=Error whilst attempting to prevent memory leak in javax.security.auth.Policy class >+jreLeakListener.ldapPoolManagerFail=Failed to trigger creation of the com.sun.jndi.ldap.LdapPoolManager class during Tomcat start to prevent possible memory leaks. This is expected on non-Sun JVMs. >+jreLeakListener.classToInitializeFail=Failed to load class {0} during Tomcat start to prevent possible memory leaks. >+naming.wsdlFailed=Failed to find wsdl file: {0} >+naming.bindFailed=Failed to bind object: {0} >+naming.jmxRegistrationFailed=Failed to register in JMX: {0} >+naming.unbindFailed=Failed to unbind object: {0} >+naming.invalidEnvEntryType=Environment entry {0} has an invalid type >+naming.invalidEnvEntryValue=Environment entry {0} has an invalid value >+naming.namingContextCreationFailed=Creation of the naming context failed: {0} >+standardContext.invalidWrapperClass={0} is not a subclass of StandardWrapper >+standardContext.alreadyStarted=Context has already been started >+standardContext.applicationListener=Error configuring application listener of class {0} >+standardContext.applicationSkipped=Skipped installing application listeners due to previous error(s) >+standardContext.badRequest=Invalid request path ({0}). >+standardContext.cluster.noManager=No manager found. Checking if cluster manager should be used. Cluster configured: [{0}], Application distributable: [{1}] >+standardContext.crlfinurl=The URL pattern "{0}" contains a CR or LF and so can never be matched. >+standardContext.duplicateListener=The listener "{0}" is already configured for this context. The duplicate definition has been ignored. >+standardContext.errorPage.error=Error page location {0} must start with a ''/'' >+standardContext.errorPage.required=ErrorPage cannot be null >+standardContext.errorPage.warning=WARNING: Error page location {0} must start with a ''/'' in Servlet 2.4 >+standardContext.filterMap.either=Filter mapping must specify either a <url-pattern> or a <servlet-name> >+standardContext.filterMap.name=Filter mapping specifies an unknown filter name {0} >+standardContext.filterMap.pattern=Invalid <url-pattern> {0} in filter mapping >+standardContext.filterStart=Exception starting filter {0} >+standardContext.filterStartFailed=Failed to start application Filters successfully >+standardContext.requestListener.requestInit=Exception sending request initialized lifecycle event to listener instance of class {0} >+standardContext.requestListener.requestDestroy=Exception sending request destroyed lifecycle event to listener instance of class {0} >+standardContext.requestListenerStartFailed=Failed to start request listener valve successfully >+standardContext.requestListenerConfig.added=Added request listener Valve >+standardContext.requestListenerConfig.error=Exception adding request listener Valve: {0} >+standardContext.isUnavailable=This application is not currently available >+standardContext.listenerStart=Exception sending context initialized event to listener instance of class {0} >+standardContext.listenerStartFailed=Failed to start application Listeners successfully >+standardContext.listenerStop=Exception sending context destroyed event to listener instance of class {0} >+standardContext.loginConfig.errorPage=Form error page {0} must start with a ''/' >+standardContext.loginConfig.errorWarning=WARNING: Form error page {0} must start with a ''/'' in Servlet 2.4 >+standardContext.loginConfig.loginPage=Form login page {0} must start with a ''/' >+standardContext.loginConfig.loginWarning=WARNING: Form login page {0} must start with a ''/'' in Servlet 2.4 >+standardContext.loginConfig.required=LoginConfig cannot be null >+standardContext.manager=Configured a manager of class [{0}] >+standardContext.mappingError=MAPPING configuration error for relative URI {0} >+standardContext.namingResource.init.fail=Failed to init new naming resources >+standardContext.namingResource.destroy.fail=Failed to destroy old naming resources >+standardContext.noResourceJar=Resource JARs are not supported. The JAR found at [{0}] will not be used to provide static content for context with name [{1}] >+standardContext.notFound=The requested resource ({0}) is not available. >+standardContext.notReloadable=Reloading is disabled on this Context >+standardContext.notStarted=Context with name [{0}] has not yet been started >+standardContext.notWrapper=Child of a Context must be a Wrapper >+standardContext.parameter.duplicate=Duplicate context initialization parameter {0} >+standardContext.parameter.required=Both parameter name and parameter value are required >+standardContext.pathInvalid=A context path must either be an empty string or start with a ''/''. The path [{0}] does not meet these criteria and has been changed to [{1}] >+standardContext.reloadingCompleted=Reloading Context with name [{0}] is completed >+standardContext.reloadingFailed=Reloading this Context failed due to previous errors >+standardContext.reloadingStarted=Reloading Context with name [{0}] has started >+standardContext.resourcesStart=Error starting static Resources >+standardContext.securityConstraint.mixHttpMethod=It is not permitted to mix <http-method> and <http-method-omission> in the same web resource collection >+standardContext.securityConstraint.pattern=Invalid <url-pattern> {0} in security constraint >+standardContext.servletMap.name=Servlet mapping specifies an unknown servlet name {0} >+standardContext.servletMap.pattern=Invalid <url-pattern> {0} in servlet mapping >+standardContext.startCleanup=Exception during cleanup after start failed >+standardContext.startFailed=Context [{0}] startup failed due to previous errors >+standardContext.startingContext=Exception starting Context with name [{0}] >+standardContext.startingLoader=Exception starting Loader >+standardContext.startingManager=Exception starting Manager >+standardContext.startingWrapper=Exception starting Wrapper for servlet {0} >+standardContext.stoppingContext=Exception stopping Context with name [{0}] >+standardContext.stoppingLoader=Exception stopping Loader >+standardContext.stoppingManager=Exception stopping Manager >+standardContext.stoppingWrapper=Exception stopping Wrapper for servlet {0} >+standardContext.urlDecode=Cannot URL decode request path {0} >+standardContext.urlPattern.patternWarning=WARNING: URL pattern {0} must start with a ''/'' in Servlet 2.4 >+standardContext.urlValidate=Cannot validate URL decoded request path {0} >+standardContext.workPath=Exception obtaining work path for context [{0}] >+standardContext.workCreateException=Failed to determine absolute work directory from directory [{0}] and CATALINA_HOME [{1}] for context [{2}] >+standardContext.workCreateFail=Failed to create work directory [{0}] for context [{1}] >+standardContextValve.acknowledgeException=Failed to acknowledge request with a 100 (Continue) response >+standardEngine.alreadyStarted=Engine has already been started >+standardEngine.jvmRouteFail=Failed to set Engine's jvmRoute attribute from system property >+standardEngine.mappingError=MAPPING configuration error for server name {0} >+standardEngine.noHost=No Host matches server name {0} >+standardEngine.noHostHeader=HTTP/1.1 request with no Host: header >+standardEngine.notHost=Child of an Engine must be a Host >+standardEngine.notParent=Engine cannot have a parent Container >+standardEngine.notStarted=Engine has not yet been started >+standardEngine.unfoundHost=Virtual host {0} not found >+standardEngine.unknownHost=No server host specified in this request >+standardEngine.unregister.mbeans.failed=Error in destroy() for mbean file {0} >+standardHost.accessBase=Cannot access document base directory {0} >+standardHost.alreadyStarted=Host has already been started >+standardHost.appBase=Application base directory {0} does not exist >+standardHost.clientAbort=Remote Client Aborted Request, IOException: {0} >+standardHost.configRequired=URL to configuration file is required >+standardHost.configNotAllowed=Use of configuration file is not allowed >+standardHost.installBase=Only web applications in the Host web application directory can be installed >+standardHost.installing=Installing web application at context path {0} from URL {1} >+standardHost.installingWAR=Installing web application from URL {0} >+standardHost.installingXML=Processing Context configuration file URL {0} >+standardHost.installError=Error deploying application at context path {0} >+standardHost.invalidErrorReportValveClass=Couldn''t load specified error report valve class: {0} >+standardHost.docBase=Document base directory {0} already exists >+standardHost.mappingError=MAPPING configuration error for request URI {0} >+standardHost.noContext=No Context configured to process this request >+standardHost.noHost=No Host configured to process this request >+standardHost.notContext=Child of a Host must be a Context >+standardHost.notStarted=Host has not yet been started >+standardHost.nullName=Host name is required >+standardHost.pathFormat=Invalid context path: {0} >+standardHost.pathMatch=Context path {0} must match the directory or WAR file name: {1} >+standardHost.pathMissing=Context path {0} is not currently in use >+standardHost.pathRequired=Context path is required >+standardHost.pathUsed=Context path {0} is already in use >+standardHost.removing=Removing web application at context path {0} >+standardHost.removeError=Error removing application at context path {0} >+standardHost.start=Starting web application at context path {0} >+standardHost.stop=Stopping web application at context path {0} >+standardHost.unfoundContext=Cannot find context for request URI {0} >+standardHost.warRequired=URL to web application archive is required >+standardHost.warURL=Invalid URL for web application archive: {0} >+standardServer.onameFail=MBean name specified for Server [{0}] is not valid >+standardServer.shutdownViaPort=A valid shutdown command was received via the shutdown port. Stopping the Server instance. >+standardService.connector.initFailed=Failed to initialize connector [{0}] >+standardService.connector.destroyFailed=Failed to destroy connector [{0}] >+standardService.connector.pauseFailed=Failed to pause connector [{0}] >+standardService.connector.startFailed=Failed to start connector [{0}] >+standardService.connector.stopFailed=Failed to stop connector [{0}] >+standardService.initialize.failed=Service initializing at {0} failed >+standardService.onameFail=MBean name specified for Service [{0}] is not valid >+standardService.register.failed=Error registering Service at domain {0} >+standardService.start.name=Starting service {0} >+standardService.stop.name=Stopping service {0} >+standardThreadExecutor.onameFail=MBean name specified for Thread Executor [{0}] is not valid >+standardWrapper.allocate=Error allocating a servlet instance >+standardWrapper.allocateException=Allocate exception for servlet {0} >+standardWrapper.containerServlet=Loading container servlet {0} >+standardWrapper.createFilters=Create filters exception for servlet {0} >+standardWrapper.deallocateException=Deallocate exception for servlet {0} >+standardWrapper.destroyException=Servlet.destroy() for servlet {0} threw exception >+standardWrapper.exception0=Tomcat Exception Report >+standardWrapper.exception1=A Servlet Exception Has Occurred >+standardWrapper.exception2=Exception Report: >+standardWrapper.exception3=Root Cause: >+standardWrapper.initException=Servlet.init() for servlet {0} threw exception >+standardWrapper.instantiate=Error instantiating servlet class {0} >+standardWrapper.isUnavailable=Servlet {0} is currently unavailable >+standardWrapper.jasperLoader=Using Jasper classloader for servlet {0} >+standardWrapper.jspFile.format=JSP file {0} does not start with a ''/'' character >+standardWrapper.loadException=Servlet {0} threw load() exception >+standardWrapper.missingClass=Wrapper cannot find servlet class {0} or a class it depends on >+standardWrapper.missingLoader=Wrapper cannot find Loader for servlet {0} >+standardWrapper.notChild=Wrapper container may not have child containers >+standardWrapper.notClass=No servlet class has been specified for servlet {0} >+standardWrapper.notContext=Parent container of a Wrapper must be a Context >+standardWrapper.notFound=Servlet {0} is not available >+standardWrapper.notServlet=Class {0} is not a Servlet >+standardWrapper.releaseFilters=Release filters exception for servlet {0} >+standardWrapper.serviceException=Servlet.service() for servlet [{0}] in context with path [{1}] threw exception >+standardWrapper.serviceExceptionRoot=Servlet.service() for servlet [{0}] in context with path [{1}] threw exception [{2}] with root cause >+standardWrapper.statusHeader=HTTP Status {0} - {1} >+standardWrapper.statusTitle=Tomcat Error Report >+standardWrapper.unavailable=Marking servlet {0} as unavailable >+standardWrapper.unloadException=Servlet {0} threw unload() exception >+standardWrapper.unloading=Cannot allocate servlet {0} because it is being unloaded >+standardWrapper.waiting=Waiting for {0} instance(s) to be deallocated >+threadLocalLeakPreventionListener.lifecycleEvent.error=Exception processing lifecycle event {0} >+threadLocalLeakPreventionListener.containerEvent.error=Exception processing container event {0} >+ >+defaultInstanceManager.restrictedServletsResource=Restricted servlets property file not found >+defaultInstanceManager.privilegedServlet=Servlet of class {0} is privileged and cannot be loaded by this web application >+defaultInstanceManager.restrictedFiltersResource=Restricted filters property file not found >+defaultInstanceManager.privilegedFilter=Filter of class {0} is privileged and cannot be loaded by this web application >+defaultInstanceManager.restrictedListenersResources="Restricted listeners property file not found >diff --git a/java/org/apache/catalina/core/StandardContext.java b/java/org/apache/catalina/core/StandardContext.java >index a408da0..8e7b971 100644 >--- a/java/org/apache/catalina/core/StandardContext.java >+++ b/java/org/apache/catalina/core/StandardContext.java >@@ -1,6544 +1,6462 @@ >-/* >- * 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.BufferedReader; >-import java.io.File; >-import java.io.IOException; >-import java.io.InputStream; >-import java.io.InputStreamReader; >-import java.net.URL; >-import java.util.ArrayList; >-import java.util.Arrays; >-import java.util.Collection; >-import java.util.HashMap; >-import java.util.HashSet; >-import java.util.Hashtable; >-import java.util.Iterator; >-import java.util.LinkedHashMap; >-import java.util.List; >-import java.util.Map; >-import java.util.Set; >-import java.util.Stack; >-import java.util.TreeMap; >-import java.util.concurrent.Callable; >-import java.util.concurrent.atomic.AtomicLong; >- >-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.management.ObjectName; >-import javax.naming.NamingException; >-import javax.naming.directory.DirContext; >-import javax.servlet.FilterConfig; >-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.ServletRequest; >-import javax.servlet.ServletRequestAttributeListener; >-import javax.servlet.ServletRequestEvent; >-import javax.servlet.ServletRequestListener; >-import javax.servlet.ServletSecurityElement; >-import javax.servlet.descriptor.JspConfigDescriptor; >-import javax.servlet.http.HttpSessionAttributeListener; >-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.Globals; >-import org.apache.catalina.Host; >-import org.apache.catalina.InstanceListener; >-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.Valve; >-import org.apache.catalina.Wrapper; >-import org.apache.catalina.deploy.ApplicationParameter; >-import org.apache.catalina.deploy.ErrorPage; >-import org.apache.catalina.deploy.FilterDef; >-import org.apache.catalina.deploy.FilterMap; >-import org.apache.catalina.deploy.Injectable; >-import org.apache.catalina.deploy.InjectionTarget; >-import org.apache.catalina.deploy.LoginConfig; >-import org.apache.catalina.deploy.MessageDestination; >-import org.apache.catalina.deploy.MessageDestinationRef; >-import org.apache.catalina.deploy.NamingResources; >-import org.apache.catalina.deploy.SecurityCollection; >-import org.apache.catalina.deploy.SecurityConstraint; >-import org.apache.catalina.loader.WebappLoader; >-import org.apache.catalina.session.StandardManager; >-import org.apache.catalina.startup.TldConfig; >-import org.apache.catalina.util.CharsetMapper; >-import org.apache.catalina.util.ContextName; >-import org.apache.catalina.util.ExtensionValidator; >-import org.apache.catalina.util.RequestUtil; >-import org.apache.catalina.util.URLEncoder; >-import org.apache.juli.logging.Log; >-import org.apache.juli.logging.LogFactory; >-import org.apache.naming.ContextBindings; >-import org.apache.naming.resources.BaseDirContext; >-import org.apache.naming.resources.DirContextURLStreamHandler; >-import org.apache.naming.resources.FileDirContext; >-import org.apache.naming.resources.ProxyDirContext; >-import org.apache.naming.resources.WARDirContext; >-import org.apache.tomcat.InstanceManager; >-import org.apache.tomcat.JarScanner; >-import org.apache.tomcat.util.ExceptionUtils; >-import org.apache.tomcat.util.modeler.Registry; >-import org.apache.tomcat.util.scan.StandardJarScanner; >-import org.apache.tomcat.util.threads.DedicatedThreadExecutor; >- >-/** >- * 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 >- * @version $Id$ >- */ >- >-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"); >- } >- } >- >- >- // ----------------------------------------------------- Class Variables >- >- >- /** >- * The descriptive information string for this implementation. >- */ >- private static final String info = >- "org.apache.catalina.core.StandardContext/1.0"; >- >- >- /** >- * Array containing the safe characters set. >- */ >- protected static URLEncoder urlEncoder; >- >- >- /** >- * GMT timezone - all HTTP dates are on GMT >- */ >- static { >- urlEncoder = new URLEncoder(); >- urlEncoder.addSafeCharacter('~'); >- urlEncoder.addSafeCharacter('-'); >- urlEncoder.addSafeCharacter('_'); >- urlEncoder.addSafeCharacter('.'); >- urlEncoder.addSafeCharacter('*'); >- urlEncoder.addSafeCharacter('/'); >- } >- >- >- // ----------------------------------------------------- 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; >- >- >- /** >- * Associated host name. >- */ >- private String hostName; >- >- >- /** >- * The antiJARLocking flag for this Context. >- */ >- private boolean antiJARLocking = false; >- >- >- /** >- * 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 web.xml file. >- */ >- private String applicationListeners[] = new String[0]; >- >- private final Object applicationListenersLock = new Object(); >- >- >- /** >- * The set of instantiated application event listener objects</code>. >- */ >- private Object applicationEventListenersObjects[] = >- new Object[0]; >- >- >- /** >- * The set of instantiated application lifecycle listener objects</code>. >- */ >- private Object applicationLifecycleListenersObjects[] = >- new Object[0]; >- >- >- /** >- * The ordered set of ServletContainerInitializers for this web application. >- */ >- private Map<ServletContainerInitializer,Set<Class<?>>> initializers = >- new LinkedHashMap<ServletContainerInitializer,Set<Class<?>>>(); >- >- >- /** >- * 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; >- >- >- /** >- * Compiler classpath to use. >- */ >- private String compilerClasspath = 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; >- >- >- /** >- * 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<String, ErrorPage>(); >- >- >- /** >- * The set of filter configurations (and associated filter instances) we >- * have initialized, keyed by filter name. >- */ >- private HashMap<String, ApplicationFilterConfig> filterConfigs = >- new HashMap<String, ApplicationFilterConfig>(); >- >- >- /** >- * The set of filter definitions for this application, keyed by >- * filter name. >- */ >- private HashMap<String, FilterDef> filterDefs = >- new HashMap<String, FilterDef>(); >- >- >- /** >- * 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 set of classnames of InstanceListeners that will be added >- * to each newly created Wrapper by <code>createWrapper()</code>. >- */ >- private String instanceListeners[] = new String[0]; >- >- private final Object instanceListenersLock = new Object(); >- >- >- /** >- * The login configuration descriptor for this web application. >- */ >- private LoginConfig loginConfig = null; >- >- >- /** >- * The mapper associated with this context. >- */ >- private org.apache.tomcat.util.http.mapper.Mapper mapper = >- new org.apache.tomcat.util.http.mapper.Mapper(); >- >- >- /** >- * The naming context listener for this web application. >- */ >- private NamingContextListener namingContextListener = null; >- >- >- /** >- * The naming resources for this web application. >- */ >- private NamingResources namingResources = null; >- >- /** >- * The message destinations for this web application. >- */ >- private HashMap<String, MessageDestination> messageDestinations = >- new HashMap<String, MessageDestination>(); >- >- >- /** >- * The MIME mappings for this web application, keyed by extension. >- */ >- private HashMap<String, String> mimeMappings = >- new HashMap<String, String>(); >- >- >- /** >- * Special case: error page for status 200. >- */ >- private ErrorPage okErrorPage = null; >- >- >- /** >- * The context initialization parameters for this web application, >- * keyed by name. >- */ >- private HashMap<String, String> parameters = new HashMap<String, String>(); >- >- >- /** >- * The request processing pause flag (while reloading occurs) >- */ >- private 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; >- >- >- /** >- * 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<String, String>(); >- >- >- /** >- * 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<String, String>(); >- >- 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). >- */ >- private HashMap<Integer, ErrorPage> statusPages = >- new HashMap<Integer, ErrorPage>(); >- >- >- /** >- * 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; >- >- >- /** >- * Filesystem based flag. >- */ >- private boolean filesystemBased = false; >- >- >- /** >- * Name of the associated naming context. >- */ >- private String namingContextName = null; >- >- >- /** >- * Caching allowed flag. >- */ >- private boolean cachingAllowed = true; >- >- >- /** >- * Allow linking. >- */ >- protected boolean allowLinking = false; >- >- >- /** >- * Cache max size in KB. >- */ >- protected int cacheMaxSize = 10240; // 10 MB >- >- >- /** >- * Cache object max size in KB. >- */ >- protected int cacheObjectMaxSize = 512; // 512K >- >- >- /** >- * Cache TTL in ms. >- */ >- protected int cacheTTL = 5000; >- >- >- /** >- * List of resource aliases. >- */ >- private String aliases = null; >- >- >- /** >- * Non proxied resources. >- */ >- private DirContext webappResources = null; >- >- 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 >- */ >- 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 value used to turn on/off TLD processing >- */ >- private boolean processTlds = true; >- >- /** >- * Attribute value used to turn on/off XML validation >- */ >- private boolean tldValidation = Globals.STRICT_SERVLET_COMPLIANCE; >- >- >- /** >- * Attribute value used to turn on/off TLD XML namespace validation >- */ >- private boolean tldNamespaceAware = Globals.STRICT_SERVLET_COMPLIANCE; >- >- >- /** >- * Should we save the configuration. >- */ >- private boolean saveConfig = true; >- >- >- /** >- * 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 = true; >- >- >- /** >- * 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; >- >- /** >- * Should Tomcat attempt to null out any static or final fields from loaded >- * classes when a web application is stopped as a work around for apparent >- * garbage collection bugs and application coding errors? There have been >- * some issues reported with log4j when this option is true. Applications >- * without memory leaks using recent JVMs should operate correctly with this >- * option set to <code>false</code>. If not specified, the default value of >- * <code>false</code> will be used. >- */ >- private boolean clearReferencesStatic = false; >- >- /** >- * 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 WebappClassLoader} to >- * {@link WebappClassLoader#parent} 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 of 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 = >- new ApplicationJspConfigDescriptor(); >- >- private Set<String> resourceOnlyServlets = new HashSet<String>(); >- >- 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<Servlet>(); >- >- private boolean preemptiveAuthentication = false; >- >- private boolean sendRedirectBody = false; >- >- >- // ----------------------------------------------------- Context Properties >- >- @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; >- } >- >- >- public void setAddWebinfClassesResources( >- boolean addWebinfClassesResources) { >- this.addWebinfClassesResources = addWebinfClassesResources; >- } >- >- >- 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) { >- 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() { >- if (this instanceof Authenticator) >- return (Authenticator) this; >- >- Pipeline pipeline = getPipeline(); >- if (pipeline != null) { >- Valve basic = pipeline.getBasic(); >- if ((basic != null) && (basic instanceof Authenticator)) >- return (Authenticator) basic; >- Valve valves[] = pipeline.getValves(); >- for (int i = 0; i < valves.length; i++) { >- if (valves[i] instanceof Authenticator) >- return (Authenticator) valves[i]; >- } >- } >- return null; >- } >- >- @Override >- public JarScanner getJarScanner() { >- if (jarScanner == null) { >- jarScanner = new StandardJarScanner(); >- } >- return jarScanner; >- } >- >- >- @Override >- public void setJarScanner(JarScanner jarScanner) { >- this.jarScanner = jarScanner; >- } >- >- >- public InstanceManager getInstanceManager() { >- return instanceManager; >- } >- >- >- public void setInstanceManager(InstanceManager instanceManager) { >- this.instanceManager = instanceManager; >- } >- >- >- @Override >- public String getEncodedPath() { >- return encodedPath; >- } >- >- >- /** >- * Is caching allowed ? >- */ >- public boolean isCachingAllowed() { >- return cachingAllowed; >- } >- >- >- /** >- * Set caching allowed flag. >- */ >- public void setCachingAllowed(boolean cachingAllowed) { >- this.cachingAllowed = cachingAllowed; >- } >- >- >- /** >- * Set allow linking. >- */ >- public void setAllowLinking(boolean allowLinking) { >- this.allowLinking = allowLinking; >- } >- >- >- /** >- * Is linking allowed. >- */ >- public boolean isAllowLinking() { >- return allowLinking; >- } >- >- /** >- * 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; >- } >- >- /** >- * Set cache TTL. >- */ >- public void setCacheTTL(int cacheTTL) { >- this.cacheTTL = cacheTTL; >- } >- >- >- /** >- * Get cache TTL. >- */ >- public int getCacheTTL() { >- return cacheTTL; >- } >- >- >- /** >- * Return the maximum size of the cache in KB. >- */ >- public int getCacheMaxSize() { >- return cacheMaxSize; >- } >- >- >- /** >- * Set the maximum size of the cache in KB. >- */ >- public void setCacheMaxSize(int cacheMaxSize) { >- this.cacheMaxSize = cacheMaxSize; >- } >- >- >- /** >- * Return the maximum size of objects to be cached in KB. >- */ >- public int getCacheObjectMaxSize() { >- return cacheObjectMaxSize; >- } >- >- >- /** >- * Set the maximum size of objects to be placed the cache in KB. >- */ >- public void setCacheObjectMaxSize(int cacheObjectMaxSize) { >- this.cacheObjectMaxSize = cacheObjectMaxSize; >- } >- >- >- /** >- * Return the list of resource aliases. >- */ >- public String getAliases() { >- return this.aliases; >- } >- >- >- /** >- * Add a URL for a JAR that contains static resources in a >- * META-INF/resources directory that should be included in the static >- * resources for this context. >- */ >- @Override >- public void addResourceJarUrl(URL url) { >- if (webappResources instanceof BaseDirContext) { >- ((BaseDirContext) webappResources).addResourcesJar(url); >- } else { >- log.error(sm.getString("standardContext.noResourceJar", url, >- getName())); >- } >- } >- >- >- /** >- * Set the current alias configuration. The list of aliases should be of the >- * form "/aliasPath1=docBase1,/aliasPath2=docBase2" where aliasPathN must >- * include a leading '/' and docBaseN must be an absolute path to either a >- * .war file or a directory. >- */ >- public void setAliases(String aliases) { >- this.aliases = aliases; >- } >- >- >- /** >- * 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. >- */ >- 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); >- >- } >- >- >- /** >- * Returns true if the internal naming support is used. >- */ >- public boolean isUseNaming() { >- >- return (useNaming); >- >- } >- >- >- /** >- * Enables or disables naming. >- */ >- public void setUseNaming(boolean useNaming) { >- this.useNaming = useNaming; >- } >- >- >- /** >- * Returns true if the resources associated with this context are >- * filesystem based. >- */ >- public boolean isFilesystemBased() { >- >- return (filesystemBased); >- >- } >- >- >- /** >- * Return the set of initialized application event listener objects, >- * in the order they were specified in the web application deployment >- * descriptor, for this application. >- * >- * @exception IllegalStateException if this method is called before >- * this application has started, or after it has been stopped >- */ >- @Override >- public Object[] getApplicationEventListeners() { >- return (applicationEventListenersObjects); >- } >- >- >- /** >- * Store the set of initialized application event 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 setApplicationEventListeners(Object listeners[]) { >- applicationEventListenersObjects = listeners; >- } >- >- >- /** >- * Add a listener to the end of the list of initialized application event >- * listeners. >- */ >- public void addApplicationEventListener(Object listener) { >- int len = applicationEventListenersObjects.length; >- Object[] newListeners = Arrays.copyOf(applicationEventListenersObjects, >- len + 1); >- newListeners[len] = listener; >- applicationEventListenersObjects = newListeners; >- } >- >- >- /** >- * Return the set of initialized application lifecycle listener objects, >- * in the order they were specified in the web application deployment >- * descriptor, for this application. >- * >- * @exception IllegalStateException if this method is called before >- * this application has started, or after it has been stopped >- */ >- @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. >- */ >- public void addApplicationLifecycleListener(Object listener) { >- int len = applicationLifecycleListenersObjects.length; >- Object[] newListeners = Arrays.copyOf( >- applicationLifecycleListenersObjects, len + 1); >- newListeners[len] = listener; >- applicationLifecycleListenersObjects = newListeners; >- } >- >- >- /** >- * Return the antiJARLocking flag for this Context. >- */ >- public boolean getAntiJARLocking() { >- >- return (this.antiJARLocking); >- >- } >- >- >- /** >- * Return the antiResourceLocking flag for this Context. >- */ >- public boolean getAntiResourceLocking() { >- >- return (this.antiResourceLocking); >- >- } >- >- >- /** >- * Set the antiJARLocking feature for this Context. >- * >- * @param antiJARLocking The new flag value >- */ >- public void setAntiJARLocking(boolean antiJARLocking) { >- >- boolean oldAntiJARLocking = this.antiJARLocking; >- this.antiJARLocking = antiJARLocking; >- support.firePropertyChange("antiJARLocking", >- oldAntiJARLocking, >- this.antiJARLocking); >- >- } >- >- >- /** >- * 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 application available flag for this Context. >- */ >- @Override >- public boolean getAvailable() { >- >- // TODO Remove this method entirely >- return getState().isAvailable(); >- >- } >- >- >- /** >- * Return the Locale to character set mapper for this Context. >- */ >- @Override >- 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 >- */ >- @Override >- 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); >- >- } >- >- /** >- * Return the URL of the XML descriptor for this context. >- */ >- @Override >- public URL getConfigFile() { >- >- return (this.configFile); >- >- } >- >- >- /** >- * Set the URL of the XML descriptor for this context. >- * >- * @param configFile The URL of the XML descriptor for this context. >- */ >- @Override >- public void setConfigFile(URL configFile) { >- >- this.configFile = configFile; >- } >- >- >- /** >- * Return the "correctly configured" flag for this Context. >- */ >- @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); >- >- } >- >- >- /** >- * Return the "use cookies for session ids" flag. >- */ >- @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; >- } >- >- >- /** >- * Return the "allow crossing servlet contexts" flag. >- */ >- @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; >- } >- >- /** >- * 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. >- */ >- @Override >- public void setAltDDName(String altDDName) { >- this.altDDName = altDDName; >- if (context != null) { >- context.setAttribute(Globals.ALT_DD_ATTR,altDDName); >- } >- } >- >- >- /** >- * Return the compiler classpath. >- */ >- public String getCompilerClasspath(){ >- return compilerClasspath; >- } >- >- >- /** >- * Set the compiler classpath. >- */ >- public void setCompilerClasspath(String compilerClasspath) { >- this.compilerClasspath = compilerClasspath; >- } >- >- >- /** >- * 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); >- >- // Bugzilla 32866 >- if(getManager() != null) { >- if(log.isDebugEnabled()) { >- log.debug("Propagating distributable=" + distributable >- + " to manager"); >- } >- getManager().setDistributable(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; >- >- } >- >- /** >- * Return descriptive information about this Container implementation and >- * the corresponding version number, in the format >- * <code><description>/<version></code>. >- */ >- @Override >- public String getInfo() { >- >- return (info); >- >- } >- >- 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; >- } >- >- >- /** >- * Set the Loader with which this Context is associated. >- * >- * @param loader The newly associated loader >- */ >- @Override >- public synchronized void setLoader(Loader loader) { >- >- super.setLoader(loader); >- >- } >- >- >- /** >- * 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); >- >- } >- >- >- /** >- * Get the mapper associated with the context. >- */ >- @Override >- public org.apache.tomcat.util.http.mapper.Mapper getMapper() { >- return (mapper); >- } >- >- >- /** >- * Return the naming resources associated with this web application. >- */ >- @Override >- public NamingResources getNamingResources() { >- >- if (namingResources == null) { >- setNamingResources(new NamingResources()); >- } >- return (namingResources); >- >- } >- >- >- /** >- * Set the naming resources for this web application. >- * >- * @param namingResources The new naming resources >- */ >- @Override >- public void setNamingResources(NamingResources namingResources) { >- >- // Process the property setting change >- NamingResources 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) { >- if (path == null || (!path.equals("") && !path.startsWith("/"))) { >- this.path = "/" + path; >- log.warn(sm.getString( >- "standardContext.pathInvalid", path, this.path)); >- } else { >- this.path = path; >- } >- encodedPath = urlEncoder.encode(this.path); >- 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); >- >- } >- >- >- /** >- * Return the "replace welcome files" property. >- */ >- public boolean isReplaceWelcomeFiles() { >- >- return (this.replaceWelcomeFiles); >- >- } >- >- >- /** >- * 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)); >- >- } >- >- >- /** >- * Unpack WAR flag accessor. >- */ >- public boolean getUnpackWAR() { >- >- return (unpackWAR); >- >- } >- >- >- /** >- * Unpack WAR flag mutator. >- */ >- public void setUnpackWAR(boolean unpackWAR) { >- >- this.unpackWAR = unpackWAR; >- >- } >- >- /** >- * 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()); >- } >- } >- >- >- /** >- * Set the resources DirContext object with which this Container is >- * associated. >- * >- * @param resources The newly associated DirContext >- */ >- @Override >- public synchronized void setResources(DirContext resources) { >- >- if (getState().isAvailable()) { >- throw new IllegalStateException >- (sm.getString("standardContext.resources.started")); >- } >- >- DirContext oldResources = this.webappResources; >- if (oldResources == resources) >- return; >- >- if (resources instanceof BaseDirContext) { >- // Caching >- ((BaseDirContext) resources).setCached(isCachingAllowed()); >- ((BaseDirContext) resources).setCacheTTL(getCacheTTL()); >- ((BaseDirContext) resources).setCacheMaxSize(getCacheMaxSize()); >- ((BaseDirContext) resources).setCacheObjectMaxSize( >- getCacheObjectMaxSize()); >- // Alias support >- ((BaseDirContext) resources).setAliases(getAliases()); >- } >- if (resources instanceof FileDirContext) { >- filesystemBased = true; >- ((FileDirContext) resources).setAllowLinking(isAllowLinking()); >- } >- this.webappResources = resources; >- >- // The proxied resources will be refreshed on start >- this.resources = null; >- >- support.firePropertyChange("resources", oldResources, >- this.webappResources); >- >- } >- >- >- @Override >- public JspConfigDescriptor getJspConfigDescriptor() { >- return jspConfigDescriptor; >- } >- >- >- // ------------------------------------------------------ Public Properties >- >- >- /** >- * 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()) { >- File catalinaHome = engineBase(); >- String catalinaHomePath = null; >- try { >- catalinaHomePath = catalinaHome.getCanonicalPath(); >- workDir = new File(catalinaHomePath, >- 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(); >- } >- } >- >- >- /** >- * Save config ? >- */ >- public boolean isSaveConfig() { >- return saveConfig; >- } >- >- >- /** >- * Set save config flag. >- */ >- public void setSaveConfig(boolean saveConfig) { >- this.saveConfig = saveConfig; >- } >- >- >- /** >- * Return the clearReferencesStatic flag for this Context. >- */ >- public boolean getClearReferencesStatic() { >- >- return (this.clearReferencesStatic); >- >- } >- >- >- /** >- * Set the clearReferencesStatic feature for this Context. >- * >- * @param clearReferencesStatic The new flag value >- */ >- public void setClearReferencesStatic(boolean clearReferencesStatic) { >- >- boolean oldClearReferencesStatic = this.clearReferencesStatic; >- this.clearReferencesStatic = clearReferencesStatic; >- support.firePropertyChange("clearReferencesStatic", >- oldClearReferencesStatic, >- this.clearReferencesStatic); >- >- } >- >- >- /** >- * 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); >- } >- >- // -------------------------------------------------------- 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. >- */ >- @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) { >- if (errorPage.getErrorCode() == 200) { >- this.okErrorPage = errorPage; >- } >- 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. >- */ >- 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 the classname of an InstanceListener to be added to each >- * Wrapper appended to this Context. >- * >- * @param listener Java class name of an InstanceListener class >- */ >- @Override >- public void addInstanceListener(String listener) { >- >- synchronized (instanceListenersLock) { >- String results[] =new String[instanceListeners.length + 1]; >- for (int i = 0; i < instanceListeners.length; i++) >- results[i] = instanceListeners[i]; >- results[instanceListeners.length] = listener; >- instanceListeners = results; >- } >- fireContainerEvent("addInstanceListener", listener); >- >- } >- >- /** >- * 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, 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")); >- if (parameters.get(name) != null) >- throw new IllegalArgumentException >- (sm.getString("standardContext.parameter.duplicate", name)); >- >- // Add this parameter to our defined set >- synchronized (parameters) { >- parameters.put(name, value); >- } >- 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(RequestUtil.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); >- mapper.removeWrapper(decodedPattern); >- } >- servletMappings.put(decodedPattern, name); >- } >- Wrapper wrapper = (Wrapper) findChild(name); >- wrapper.addMapping(decodedPattern); >- >- // Update context mapper >- mapper.addWrapper(decodedPattern, wrapper, jspWildCard, >- resourceOnlyServlets.contains(name)); >- >- 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 (instanceListenersLock) { >- for (int i = 0; i < instanceListeners.length; i++) { >- try { >- Class<?> clazz = Class.forName(instanceListeners[i]); >- InstanceListener listener = >- (InstanceListener) clazz.newInstance(); >- wrapper.addInstanceListener(listener); >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- log.error("createWrapper", t); >- return (null); >- } >- } >- } >- >- 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) { >- if (errorCode == 200) { >- return (okErrorPage); >- } else { >- 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 set of InstanceListener classes that will be added to >- * newly created Wrappers automatically. >- */ >- @Override >- public String[] findInstanceListeners() { >- >- synchronized (instanceListenersLock) { >- return (instanceListeners); >- } >- >- } >- >- >- /** >- * FIXME: Fooling introspection ... >- */ >- public Context findMappingObject() { >- return (Context) getMappingObject(); >- } >- >- >- /** >- * 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)); >- >- } >- >- >- /** >- * 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) { >- >- synchronized (parameters) { >- 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() { >- >- synchronized (parameters) { >- String results[] = new String[parameters.size()]; >- return (parameters.keySet().toArray(results)); >- } >- >- } >- >- >- /** >- * 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 >- */ >- @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. It does not handle changes to the web application >- * deployment descriptor. If that has occurred, you should stop this >- * Context and create (and start) a new Context instance instead. >- * >- * @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 welcome file 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 constraint >- 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) { >- if (errorPage.getErrorCode() == 200) { >- this.okErrorPage = null; >- } >- 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 a class name from the set of InstanceListener classes that >- * will be added to newly created Wrappers. >- * >- * @param listener Class name of an InstanceListener class to be removed >- */ >- @Override >- public void removeInstanceListener(String listener) { >- >- synchronized (instanceListenersLock) { >- >- // Make sure this welcome file is currently present >- int n = -1; >- for (int i = 0; i < instanceListeners.length; i++) { >- if (instanceListeners[i].equals(listener)) { >- n = i; >- break; >- } >- } >- if (n < 0) >- return; >- >- // Remove the specified constraint >- int j = 0; >- String results[] = new String[instanceListeners.length - 1]; >- for (int i = 0; i < instanceListeners.length; i++) { >- if (i != n) >- results[j++] = instanceListeners[i]; >- } >- instanceListeners = results; >- >- } >- >- // Inform interested listeners >- fireContainerEvent("removeInstanceListener", listener); >- >- } >- >- >- /** >- * 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) { >- >- synchronized (parameters) { >- 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); >- } >- mapper.removeWrapper(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 constraint >- 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 welcome file 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 constraint >- 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 welcome file 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 constraint >- 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; >- } >- >- >- /** >- * 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) { >- if (webappResources instanceof BaseDirContext) { >- return ((BaseDirContext) webappResources).getRealPath(path); >- } >- return null; >- } >- >- /** >- * hook to register that we need to scan for security annotations. >- * @param wrapper The wrapper for the Servlet that was added >- */ >- 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 >- */ >- 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(); >- Iterator<String> names = filterDefs.keySet().iterator(); >- while (names.hasNext()) { >- String name = names.next(); >- if (getLogger().isDebugEnabled()) >- getLogger().debug(" Starting filter '" + name + "'"); >- ApplicationFilterConfig filterConfig = null; >- try { >- filterConfig = >- new ApplicationFilterConfig(this, filterDefs.get(name)); >- filterConfigs.put(name, filterConfig); >- } catch (Throwable 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) { >- Iterator<String> names = filterConfigs.keySet().iterator(); >- while (names.hasNext()) { >- String name = names.next(); >- if (getLogger().isDebugEnabled()) >- getLogger().debug(" Stopping filter '" + name + "'"); >- ApplicationFilterConfig filterConfig = filterConfigs.get(name); >- 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 >- */ >- 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 { >- results[i] = instanceManager.newInstance(listeners[i]); >- } catch (Throwable 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<Object>(); >- ArrayList<Object> lifecycleListeners = new ArrayList<Object>(); >- for (int i = 0; i < results.length; i++) { >- if ((results[i] instanceof ServletContextAttributeListener) >- || (results[i] instanceof ServletRequestAttributeListener) >- || (results[i] instanceof ServletRequestListener) >- || (results[i] instanceof HttpSessionAttributeListener)) { >- eventListeners.add(results[i]); >- } >- if ((results[i] instanceof ServletContextListener) >- || (results[i] instanceof HttpSessionListener)) { >- lifecycleListeners.add(results[i]); >- } >- } >- >- //Listeners may have been added by ServletContextInitializers. Put them after the ones we know about. >- for (Object eventListener: getApplicationEventListeners()) { >- eventListeners.add(eventListener); >- } >- setApplicationEventListeners(eventListeners.toArray()); >- for (Object lifecycleListener: getApplicationLifecycleListeners()) { >- lifecycleListeners.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) >- return (ok); >- ServletContextEvent event = >- new ServletContextEvent(getServletContext()); >- for (int i = 0; i < instances.length; i++) { >- if (instances[i] == null) >- continue; >- if (!(instances[i] instanceof ServletContextListener)) >- continue; >- ServletContextListener listener = >- (ServletContextListener) instances[i]; >- try { >- fireContainerEvent("beforeContextInitialized", listener); >- 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) { >- ServletContextEvent event = >- new ServletContextEvent(getServletContext()); >- 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); >- 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 { >- getInstanceManager().destroyInstance(listeners[j]); >- } catch (Throwable 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 { >- getInstanceManager().destroyInstance(listeners[j]); >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- getLogger().error >- (sm.getString("standardContext.listenerStop", >- listeners[j].getClass().getName()), t); >- ok = false; >- } >- } >- } >- >- setApplicationEventListeners(null); >- setApplicationLifecycleListeners(null); >- >- return (ok); >- >- } >- >- >- /** >- * Allocate resources, including proxy. >- * Return <code>true</code> if initialization was successfull, >- * or <code>false</code> otherwise. >- */ >- public boolean resourcesStart() { >- >- boolean ok = true; >- >- Hashtable<String, String> env = new Hashtable<String, String>(); >- if (getParent() != null) >- env.put(ProxyDirContext.HOST, getParent().getName()); >- env.put(ProxyDirContext.CONTEXT, getName()); >- >- try { >- ProxyDirContext proxyDirContext = >- new ProxyDirContext(env, webappResources); >- if (webappResources instanceof FileDirContext) { >- filesystemBased = true; >- ((FileDirContext) webappResources).setAllowLinking >- (isAllowLinking()); >- } >- if (webappResources instanceof BaseDirContext) { >- ((BaseDirContext) webappResources).setDocBase(getBasePath()); >- ((BaseDirContext) webappResources).setCached >- (isCachingAllowed()); >- ((BaseDirContext) webappResources).setCacheTTL(getCacheTTL()); >- ((BaseDirContext) webappResources).setCacheMaxSize >- (getCacheMaxSize()); >- ((BaseDirContext) webappResources).allocate(); >- // Alias support >- ((BaseDirContext) webappResources).setAliases(getAliases()); >- >- if (effectiveMajorVersion >=3 && addWebinfClassesResources) { >- try { >- DirContext webInfCtx = >- (DirContext) webappResources.lookup( >- "/WEB-INF/classes"); >- // Do the lookup to make sure it exists >- webInfCtx.lookup("META-INF/resources"); >- ((BaseDirContext) webappResources).addAltDirContext( >- webInfCtx); >- } catch (NamingException e) { >- // Doesn't exist - ignore and carry on >- } >- } >- } >- // Register the cache in JMX >- if (isCachingAllowed()) { >- String contextName = getName(); >- if (!contextName.startsWith("/")) { >- contextName = "/" + contextName; >- } >- ObjectName resourcesName = >- new ObjectName(this.getDomain() + ":type=Cache,host=" >- + getHostname() + ",context=" + contextName); >- Registry.getRegistry(null, null).registerComponent >- (proxyDirContext.getCache(), resourcesName, null); >- } >- this.resources = proxyDirContext; >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- log.error(sm.getString("standardContext.resourcesStart"), t); >- ok = false; >- } >- >- return (ok); >- >- } >- >- >- /** >- * Deallocate resources and destroy proxy. >- */ >- public boolean resourcesStop() { >- >- boolean ok = true; >- >- try { >- if (resources != null) { >- if (resources instanceof Lifecycle) { >- ((Lifecycle) resources).stop(); >- } >- if (webappResources instanceof BaseDirContext) { >- ((BaseDirContext) webappResources).release(); >- } >- // Unregister the cache in JMX >- if (isCachingAllowed()) { >- String contextName = getName(); >- if (!contextName.startsWith("/")) { >- contextName = "/" + contextName; >- } >- ObjectName resourcesName = >- new ObjectName(this.getDomain() >- + ":type=Cache,host=" >- + getHostname() + ",context=" >- + contextName); >- Registry.getRegistry(null, null) >- .unregisterComponent(resourcesName); >- } >- } >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- log.error(sm.getString("standardContext.resourcesStop"), t); >- ok = false; >- } >- >- this.resources = null; >- >- 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) >- */ >- public void loadOnStartup(Container children[]) { >- >- // Collect "load on startup" servlets that need to be initialized >- TreeMap<Integer, ArrayList<Wrapper>> map = >- new TreeMap<Integer, ArrayList<Wrapper>>(); >- 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<Wrapper>(); >- 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("standardWrapper.loadException", >- getName()), StandardWrapper.getRootCause(e)); >- // NOTE: load errors (including a servlet that throws >- // UnavailableException from tht init() method) are NOT >- // fatal to application startup >- } >- } >- } >- >- } >- >- >- /** >- * 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 (webappResources == null) { // (1) Required by Loader >- if (log.isDebugEnabled()) >- log.debug("Configuring default Resources"); >- try { >- if ((getDocBase() != null) && (getDocBase().endsWith(".war")) && >- (!(new File(getBasePath())).isDirectory())) >- setResources(new WARDirContext()); >- else >- setResources(new FileDirContext()); >- } catch (IllegalArgumentException e) { >- log.error("Error initializing resources: " + e.getMessage()); >- ok = false; >- } >- } >- if (ok) { >- if (!resourcesStart()) { >- log.error( "Error in resourceStart()"); >- ok = false; >- } >- } >- >- if (getLoader() == null) { >- WebappLoader webappLoader = new WebappLoader(getParentClassLoader()); >- webappLoader.setDelegate(getDelegate()); >- setLoader(webappLoader); >- } >- >- // 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("Error in dependencyCheck", 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()); >- 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 >- if ((loader != null) && (loader instanceof Lifecycle)) >- ((Lifecycle) loader).start(); >- >- // since the loader just started, the webapp classloader is now >- // created. >- // 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(); >- if ((logger != null) && (logger instanceof Lifecycle)) >- ((Lifecycle) logger).start(); >- >- if ((cluster != null) && (cluster instanceof Lifecycle)) >- ((Lifecycle) cluster).start(); >- if ((realm != null) && (realm instanceof Lifecycle)) >- ((Lifecycle) realm).start(); >- if ((resources != null) && (resources instanceof Lifecycle)) >- ((Lifecycle) resources).start(); >- >- // 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; >- 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); >- } >- } >- >- } finally { >- // Unbinding thread >- unbindThread(oldCCL); >- } >- >- if (!getConfigured()) { >- log.error( "Error getConfigured"); >- ok = false; >- } >- >- // We put the resources into the servlet context >- if (ok) >- getServletContext().setAttribute >- (Globals.RESOURCES_ATTR, getResources()); >- >- // Initialize associated mapper >- mapper.setContext(getPath(), welcomeFiles, resources); >- >- // Binding thread >- oldCCL = bindThread(); >- >- 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 NamingResources(): getNamingResources()); >- setInstanceManager(new DefaultInstanceManager(context, >- injectionMap, this, this.getClass().getClassLoader())); >- getServletContext().setAttribute( >- InstanceManager.class.getName(), getInstanceManager()); >- } >- } >- >- DedicatedThreadExecutor temporaryExecutor = new DedicatedThreadExecutor(); >- try { >- >- // 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) { >- // TODO: Log error >- ok = false; >- break; >- } >- } >- >- // Configure and call application event listeners >- if (ok) { >- // we do it in a dedicated thread for memory leak protection, in >- // case the Listeners registers some ThreadLocals that they >- // forget to cleanup >- Boolean listenerStarted = >- temporaryExecutor.execute(new Callable<Boolean>() { >- @Override >- public Boolean call() throws Exception { >- ClassLoader old = bindThread(); >- try { >- return Boolean.valueOf(listenerStart()); >- } finally { >- unbindThread(old); >- } >- } >- }); >- if (!listenerStarted.booleanValue()) { >- log.error( "Error listenerStart"); >- ok = false; >- } >- } >- >- try { >- // Start manager >- if ((manager != null) && (manager instanceof Lifecycle)) { >- ((Lifecycle) getManager()).start(); >- } >- >- // Start ContainerBackgroundProcessor thread >- super.threadStart(); >- } catch(Exception e) { >- log.error("Error manager.start()", e); >- ok = false; >- } >- >- // Configure and call application filters >- if (ok) { >- // we do it in a dedicated thread for memory leak protection, in >- // case the Filters register some ThreadLocals that they forget >- // to cleanup >- Boolean filterStarted = >- temporaryExecutor.execute(new Callable<Boolean>() { >- @Override >- public Boolean call() throws Exception { >- ClassLoader old = bindThread(); >- try { >- return Boolean.valueOf(filterStart()); >- } finally { >- unbindThread(old); >- } >- } >- }); >- if (!filterStarted.booleanValue()) { >- log.error("Error filterStart"); >- ok = false; >- } >- } >- >- // Load and initialize all "load on startup" servlets >- if (ok) { >- // we do it in a dedicated thread for memory leak protection, in >- // case the Servlets register some ThreadLocals that they forget >- // to cleanup >- temporaryExecutor.execute(new Callable<Void>() { >- @Override >- public Void call() throws Exception { >- ClassLoader old = bindThread(); >- try { >- loadOnStartup(findChildren()); >- return null; >- } finally { >- unbindThread(old); >- } >- } >- }); >- } >- >- } finally { >- // Unbinding thread >- unbindThread(oldCCL); >- temporaryExecutor.shutdown(); >- } >- >- // 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); >- } >- >- // Close all JARs right away to avoid always opening a peak number >- // of files on startup >- if (getLoader() instanceof WebappLoader) { >- ((WebappLoader) getLoader()).closeJARs(true); >- } >- >- // Reinitializing if something went wrong >- if (!ok) { >- setState(LifecycleState.FAILED); >- } else { >- setState(LifecycleState.STARTING); >- } >- } >- >- private Map<String, Map<String, String>> buildInjectionMap(NamingResources namingResources) { >- Map<String, Map<String, String>> injectionMap = new HashMap<String, Map<String, String>>(); >- 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<String, String>(); >- 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,String>(); >- >- 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(); >- // we do it in a dedicated thread for memory leak protection, in >- // case some webapp code registers some ThreadLocals that they >- // forget to cleanup >- // TODO Figure out why DedicatedThreadExecutor hangs randomly in the >- // unit tests if used here >- RunnableWithLifecycleException stop = >- new RunnableWithLifecycleException() { >- @Override >- public void run() { >- ClassLoader old = bindThread(); >- try { >- for (int i = 0; i < children.length; i++) { >- try { >- children[i].stop(); >- } catch (LifecycleException e) { >- le = e; >- return; >- } >- } >- >- // Stop our filters >- filterStop(); >- >- // Stop ContainerBackgroundProcessor thread >- threadStop(); >- >- if (manager != null && manager instanceof Lifecycle && >- ((Lifecycle) manager).getState().isAvailable()) { >- try { >- ((Lifecycle) manager).stop(); >- } catch (LifecycleException e) { >- le = e; >- return; >- } >- } >- >- // Stop our application listeners >- listenerStop(); >- }finally{ >- unbindThread(old); >- } >- } >- }; >- >- Thread t = new Thread(stop); >- t.setName("stop children - " + getObjectName().toString()); >- t.start(); >- try { >- t.join(); >- } catch (InterruptedException e) { >- // Shouldn't happen >- throw new LifecycleException(e); >- } >- if (stop.getLifecycleException() != null) { >- throw stop.getLifecycleException(); >- } >- >- // 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 resoucres 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(); >- >- // Stop resources >- resourcesStop(); >- >- if ((realm != null) && (realm instanceof Lifecycle)) { >- ((Lifecycle) realm).stop(); >- } >- if ((cluster != null) && (cluster instanceof Lifecycle)) { >- ((Lifecycle) cluster).stop(); >- } >- if ((logger != null) && (logger instanceof Lifecycle)) { >- ((Lifecycle) logger).stop(); >- } >- if ((loader != null) && (loader instanceof Lifecycle)) { >- ((Lifecycle) loader).stop(); >- } >- >- } 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 >- instanceManager = 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 ((manager != null) && (manager instanceof Lifecycle)) { >- ((Lifecycle) manager).destroy(); >- } >- if ((realm != null) && (realm instanceof Lifecycle)) { >- ((Lifecycle) realm).destroy(); >- } >- if ((cluster != null) && (cluster instanceof Lifecycle)) { >- ((Lifecycle) cluster).destroy(); >- } >- if ((logger != null) && (logger instanceof Lifecycle)) { >- ((Lifecycle) logger).destroy(); >- } >- if ((loader != null) && (loader instanceof Lifecycle)) { >- ((Lifecycle) loader).destroy(); >- } >- >- // 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(); >- } >- >- synchronized (instanceListenersLock) { >- instanceListeners = new String[0]; >- } >- >- super.destroyInternal(); >- } >- >- 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 >- children = new HashMap<String, Container>(); >- startupTime = 0; >- startTime = 0; >- tldScanTime = 0; >- >- // Bugzilla 32867 >- distributable = false; >- >- applicationListeners = new String[0]; >- applicationEventListenersObjects = new Object[0]; >- applicationLifecycleListenersObjects = new Object[0]; >- jspConfigDescriptor = new ApplicationJspConfigDescriptor(); >- >- initializers.clear(); >- >- createdServlets.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 >- */ >- 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? >- */ >- @Override >- public boolean isServlet22() { >- >- if (this.publicId == null) >- return (false); >- if (this.publicId.equals >- (org.apache.catalina.startup.Constants.WebDtdPublicId_22)) >- return (true); >- else >- return (false); >- >- } >- >- @Override >- public Set<String> addServletSecurity( >- ApplicationServletRegistration registration, >- ServletSecurityElement servletSecurityElement) { >- >- Set<String> conflicts = new HashSet<String>(); >- >- 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); >- } else { >- // Need to overwrite constraint for this pattern >- // so remove every pattern found >- >- // TODO spec 13.4.2 appears to say only the >- // conflicting pattern is overwritten, not the >- // entire security constraint. >- removeConstraint(securityConstraint); >- } >- } >- if (foundConflict) { >- break; >- } >- } >- if (foundConflict) { >- break; >- } >- } >- // TODO spec 13.4.2 appears to say that non-conflicting patterns are >- // still used. >- // TODO you can't calculate the eventual security constraint now, >- // you have to wait until the context is started, since application >- // code can add url patterns after calling setSecurity. >- if (!foundConflict) { >- SecurityConstraint[] newSecurityConstraints = >- SecurityConstraint.createConstraints( >- servletSecurityElement, >- urlPattern); >- for (SecurityConstraint securityConstraint : >- newSecurityConstraints) { >- addConstraint(securityConstraint); >- } >- } >- } >- >- return conflicts; >- >- } >- >- >- /** >- * Return a File object representing the base directory for the >- * entire servlet container (i.e. the Engine container if present). >- */ >- protected File engineBase() { >- String base=System.getProperty(Globals.CATALINA_BASE_PROP); >- if( base == null ) { >- StandardEngine eng=(StandardEngine)this.getParent().getParent(); >- base=eng.getBaseDir(); >- } >- return (new File(base)); >- } >- >- >- /** >- * Bind current thread, both for CL purposes and for JNDI ENC support >- * during : startup, shutdown and realoading of the context. >- * >- * @return the previous context class loader >- */ >- protected ClassLoader bindThread() { >- >- ClassLoader oldContextClassLoader = >- Thread.currentThread().getContextClassLoader(); >- >- if (getResources() == null) >- return oldContextClassLoader; >- >- if (getLoader().getClassLoader() != null) { >- Thread.currentThread().setContextClassLoader >- (getLoader().getClassLoader()); >- } >- >- DirContextURLStreamHandler.bindThread(getResources()); >- >- if (isUseNaming()) { >- try { >- ContextBindings.bindThread(this, this); >- } catch (NamingException e) { >- // Silent catch, as this is a normal case during the early >- // startup stages >- } >- } >- >- return oldContextClassLoader; >- >- } >- >- >- /** >- * Unbind thread. >- */ >- protected void unbindThread(ClassLoader oldContextClassLoader) { >- >- if (isUseNaming()) { >- ContextBindings.unbindThread(this, this); >- } >- >- DirContextURLStreamHandler.unbindThread(); >- >- Thread.currentThread().setContextClassLoader(oldContextClassLoader); >- } >- >- >- >- /** >- * Get base path. >- */ >- protected String getBasePath() { >- String docBase = null; >- Container container = this; >- while (container != null) { >- if (container instanceof Host) >- break; >- container = container.getParent(); >- } >- File file = new File(getDocBase()); >- if (!file.isAbsolute()) { >- if (container == null) { >- docBase = (new File(engineBase(), getDocBase())).getPath(); >- } else { >- // Use the "appBase" property of this container >- file = ((Host) container).getAppBaseFile(); >- docBase = (new File(file, getDocBase())).getPath(); >- } >- } else { >- docBase = file.getPath(); >- } >- return docBase; >- } >- >- >- /** >- * Get naming context full name. >- */ >- private String getNamingContextName() { >- if (namingContextName == null) { >- Container parent = getParent(); >- if (parent == null) { >- namingContextName = getName(); >- } else { >- Stack<String> stk = new Stack<String>(); >- 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. >- */ >- public NamingContextListener getNamingContextListener() { >- return namingContextListener; >- } >- >- >- /** >- * Naming context listener setter. >- */ >- public void setNamingContextListener(NamingContextListener namingContextListener) { >- this.namingContextListener = namingContextListener; >- } >- >- >- /** >- * Return the request processing paused flag for this Context. >- */ >- @Override >- public boolean getPaused() { >- >- return (this.paused); >- >- } >- >- >- public String getHostname() { >- Container parentHost = getParent(); >- if (parentHost != null) { >- hostName = parentHost.getName(); >- } >- if ((hostName == null) || (hostName.length() < 1)) >- hostName = "_"; >- return hostName; >- } >- >- >- @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; >- } >- >- >- /** >- * 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 = getName(); >- if (temp.startsWith("/")) >- temp = temp.substring(1); >- temp = temp.replace('/', '_'); >- temp = temp.replace('\\', '_'); >- if (temp.length() < 1) >- temp = "_"; >- 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()) { >- File catalinaHome = engineBase(); >- String catalinaHomePath = null; >- try { >- catalinaHomePath = catalinaHome.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 >- */ >- private boolean validateURLPattern(String urlPattern) { >- >- if (urlPattern == null) >- return (false); >- if (urlPattern.indexOf('\n') >= 0 || urlPattern.indexOf('\r') >= 0) { >- return (false); >- } >- 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()) { >- if(urlPattern.endsWith("*") && (urlPattern.length() < 2 || >- urlPattern.charAt(urlPattern.length()-2) != '/')) { >- log.info("Suspicious url pattern: \"" + urlPattern + "\"" + >- " in context [" + getName() + "] - see" + >- " section SRV.11.2 of the Servlet specification" ); >- } >- } >- } >- >- >- // ------------------------------------------------------------- Operations >- >- >- /** >- * JSR77 deploymentDescriptor attribute >- * >- * @return string deployment descriptor >- */ >- public String getDeploymentDescriptor() { >- >- InputStream stream = null; >- ServletContext servletContext = getServletContext(); >- if (servletContext != null) { >- stream = servletContext.getResourceAsStream( >- org.apache.catalina.startup.Constants.ApplicationWebXml); >- } >- if (stream == null) { >- return ""; >- } >- StringBuilder sb = new StringBuilder(); >- BufferedReader br = null; >- try { >- br = new BufferedReader(new InputStreamReader(stream)); >- String strRead = ""; >- while (strRead != null) { >- sb.append(strRead); >- strRead = br.readLine(); >- } >- } catch (IOException e) { >- return ""; >- } finally { >- if (br != null) { >- try { >- br.close(); >- } catch (IOException ioe) {/*Ignore*/} >- } >- } >- >- return sb.toString(); >- } >- >- >- /** >- * JSR77 servlets attribute >- * >- * @return list of all servlets ( we know about ) >- */ >- public String[] getServlets() { >- >- String[] result = null; >- >- Container[] children = findChildren(); >- if (children != null) { >- result = new String[children.length]; >- for( int i=0; i< children.length; i++ ) { >- result[i] = children[i].getObjectName().toString(); >- } >- } >- >- return result; >- } >- >- >- @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(); >- >- if (processTlds) { >- this.addLifecycleListener(new TldConfig()); >- } >- >- // 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 javax.naming.directory.DirContext getStaticResources() { >- >- return getResources(); >- >- } >- >- >- /** >- * Return the naming resources associated with this web application. >- * FIXME: Fooling introspection ... >- */ >- public javax.naming.directory.DirContext findStaticResources() { >- >- return getResources(); >- >- } >- >- >- /** >- * Return the naming resources associated with this web application. >- */ >- public String[] getWelcomeFiles() { >- >- return findWelcomeFiles(); >- >- } >- >- /** >- * Set the validation feature of the XML parser used when >- * parsing xml instances. >- * @param webXmlValidation true to enable xml instance validation >- */ >- @Override >- public void setXmlValidation(boolean webXmlValidation){ >- >- this.webXmlValidation = webXmlValidation; >- >- } >- >- /** >- * Get the server.xml <context> attribute's xmlValidation. >- * @return true if validation is enabled. >- * >- */ >- @Override >- public boolean getXmlValidation(){ >- return webXmlValidation; >- } >- >- >- /** >- * Get the server.xml <context> attribute's xmlNamespaceAware. >- * @return true if namespace awarenes is enabled. >- */ >- @Override >- public boolean getXmlNamespaceAware(){ >- return webXmlNamespaceAware; >- } >- >- >- /** >- * Set the namespace aware feature of the XML parser used when >- * parsing xml instances. >- * @param webXmlNamespaceAware true to enable namespace awareness >- */ >- @Override >- public void setXmlNamespaceAware(boolean webXmlNamespaceAware){ >- this.webXmlNamespaceAware= webXmlNamespaceAware; >- } >- >- >- /** >- * Set the validation feature of the XML parser used when >- * parsing tlds files. >- * @param tldValidation true to enable xml instance validation >- */ >- @Override >- public void setTldValidation(boolean tldValidation){ >- >- this.tldValidation = tldValidation; >- >- } >- >- /** >- * Get the server.xml <context> attribute's webXmlValidation. >- * @return true if validation is enabled. >- * >- */ >- @Override >- public boolean getTldValidation(){ >- return tldValidation; >- } >- >- /** >- * Sets the process TLDs attribute. >- * >- * @param newProcessTlds The new value >- */ >- public void setProcessTlds(boolean newProcessTlds) { >- processTlds = newProcessTlds; >- } >- >- /** >- * Returns the processTlds attribute value. >- */ >- public boolean getProcessTlds() { >- return processTlds; >- } >- >- /** >- * Get the server.xml <host> attribute's xmlNamespaceAware. >- * @return true if namespace awarenes is enabled. >- */ >- @Override >- public boolean getTldNamespaceAware(){ >- return tldNamespaceAware; >- } >- >- >- /** >- * Set the namespace aware feature of the XML parser used when >- * parsing xml instances. >- * @param tldNamespaceAware true to enable namespace awareness >- */ >- @Override >- public void setTldNamespaceAware(boolean tldNamespaceAware){ >- this.tldNamespaceAware= tldNamespaceAware; >- } >- >- >- /** >- * Support for "stateManageable" JSR77 >- */ >- public boolean isStateManageable() { >- return true; >- } >- >- public void startRecursive() throws LifecycleException { >- // nothing to start recursive, the servlets will be started by load-on-startup >- start(); >- } >- >- /** >- * 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; >- } >- >- public boolean isEventProvider() { >- return false; >- } >- >- public boolean isStatisticsProvider() { >- return false; >- } >- >- private abstract static class RunnableWithLifecycleException >- implements Runnable { >- >- protected LifecycleException le = null; >- >- public LifecycleException getLifecycleException() { >- return le; >- } >- } >-} >+/* >+ * 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.BufferedReader; >+import java.io.File; >+import java.io.IOException; >+import java.io.InputStream; >+import java.io.InputStreamReader; >+import java.net.URL; >+import java.util.ArrayList; >+import java.util.Arrays; >+import java.util.Collection; >+import java.util.HashMap; >+import java.util.HashSet; >+import java.util.Hashtable; >+import java.util.Iterator; >+import java.util.LinkedHashMap; >+import java.util.List; >+import java.util.Map; >+import java.util.Set; >+import java.util.Stack; >+import java.util.TreeMap; >+import java.util.concurrent.atomic.AtomicLong; >+ >+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.management.ObjectName; >+import javax.naming.NamingException; >+import javax.naming.directory.DirContext; >+import javax.servlet.FilterConfig; >+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.ServletRequest; >+import javax.servlet.ServletRequestAttributeListener; >+import javax.servlet.ServletRequestEvent; >+import javax.servlet.ServletRequestListener; >+import javax.servlet.ServletSecurityElement; >+import javax.servlet.descriptor.JspConfigDescriptor; >+import javax.servlet.http.HttpSessionAttributeListener; >+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.Globals; >+import org.apache.catalina.Host; >+import org.apache.catalina.InstanceListener; >+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.Valve; >+import org.apache.catalina.Wrapper; >+import org.apache.catalina.deploy.ApplicationParameter; >+import org.apache.catalina.deploy.ErrorPage; >+import org.apache.catalina.deploy.FilterDef; >+import org.apache.catalina.deploy.FilterMap; >+import org.apache.catalina.deploy.Injectable; >+import org.apache.catalina.deploy.InjectionTarget; >+import org.apache.catalina.deploy.LoginConfig; >+import org.apache.catalina.deploy.MessageDestination; >+import org.apache.catalina.deploy.MessageDestinationRef; >+import org.apache.catalina.deploy.NamingResources; >+import org.apache.catalina.deploy.SecurityCollection; >+import org.apache.catalina.deploy.SecurityConstraint; >+import org.apache.catalina.loader.WebappLoader; >+import org.apache.catalina.session.StandardManager; >+import org.apache.catalina.startup.TldConfig; >+import org.apache.catalina.util.CharsetMapper; >+import org.apache.catalina.util.ContextName; >+import org.apache.catalina.util.ExtensionValidator; >+import org.apache.catalina.util.RequestUtil; >+import org.apache.catalina.util.URLEncoder; >+import org.apache.juli.logging.Log; >+import org.apache.juli.logging.LogFactory; >+import org.apache.naming.ContextBindings; >+import org.apache.naming.resources.BaseDirContext; >+import org.apache.naming.resources.DirContextURLStreamHandler; >+import org.apache.naming.resources.FileDirContext; >+import org.apache.naming.resources.ProxyDirContext; >+import org.apache.naming.resources.WARDirContext; >+import org.apache.tomcat.InstanceManager; >+import org.apache.tomcat.JarScanner; >+import org.apache.tomcat.util.ExceptionUtils; >+import org.apache.tomcat.util.modeler.Registry; >+import org.apache.tomcat.util.scan.StandardJarScanner; >+ >+/** >+ * 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 >+ * @version $Id$ >+ */ >+ >+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"); >+ } >+ } >+ >+ >+ // ----------------------------------------------------- Class Variables >+ >+ >+ /** >+ * The descriptive information string for this implementation. >+ */ >+ private static final String info = >+ "org.apache.catalina.core.StandardContext/1.0"; >+ >+ >+ /** >+ * Array containing the safe characters set. >+ */ >+ protected static URLEncoder urlEncoder; >+ >+ >+ /** >+ * GMT timezone - all HTTP dates are on GMT >+ */ >+ static { >+ urlEncoder = new URLEncoder(); >+ urlEncoder.addSafeCharacter('~'); >+ urlEncoder.addSafeCharacter('-'); >+ urlEncoder.addSafeCharacter('_'); >+ urlEncoder.addSafeCharacter('.'); >+ urlEncoder.addSafeCharacter('*'); >+ urlEncoder.addSafeCharacter('/'); >+ } >+ >+ >+ // ----------------------------------------------------- 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; >+ >+ >+ /** >+ * Associated host name. >+ */ >+ private String hostName; >+ >+ >+ /** >+ * The antiJARLocking flag for this Context. >+ */ >+ private boolean antiJARLocking = false; >+ >+ >+ /** >+ * 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 web.xml file. >+ */ >+ private String applicationListeners[] = new String[0]; >+ >+ private final Object applicationListenersLock = new Object(); >+ >+ >+ /** >+ * The set of instantiated application event listener objects</code>. >+ */ >+ private Object applicationEventListenersObjects[] = >+ new Object[0]; >+ >+ >+ /** >+ * The set of instantiated application lifecycle listener objects</code>. >+ */ >+ private Object applicationLifecycleListenersObjects[] = >+ new Object[0]; >+ >+ >+ /** >+ * The ordered set of ServletContainerInitializers for this web application. >+ */ >+ private Map<ServletContainerInitializer,Set<Class<?>>> initializers = >+ new LinkedHashMap<ServletContainerInitializer,Set<Class<?>>>(); >+ >+ >+ /** >+ * 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; >+ >+ >+ /** >+ * Compiler classpath to use. >+ */ >+ private String compilerClasspath = 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; >+ >+ >+ /** >+ * 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<String, ErrorPage>(); >+ >+ >+ /** >+ * The set of filter configurations (and associated filter instances) we >+ * have initialized, keyed by filter name. >+ */ >+ private HashMap<String, ApplicationFilterConfig> filterConfigs = >+ new HashMap<String, ApplicationFilterConfig>(); >+ >+ >+ /** >+ * The set of filter definitions for this application, keyed by >+ * filter name. >+ */ >+ private HashMap<String, FilterDef> filterDefs = >+ new HashMap<String, FilterDef>(); >+ >+ >+ /** >+ * 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 set of classnames of InstanceListeners that will be added >+ * to each newly created Wrapper by <code>createWrapper()</code>. >+ */ >+ private String instanceListeners[] = new String[0]; >+ >+ private final Object instanceListenersLock = new Object(); >+ >+ >+ /** >+ * The login configuration descriptor for this web application. >+ */ >+ private LoginConfig loginConfig = null; >+ >+ >+ /** >+ * The mapper associated with this context. >+ */ >+ private org.apache.tomcat.util.http.mapper.Mapper mapper = >+ new org.apache.tomcat.util.http.mapper.Mapper(); >+ >+ >+ /** >+ * The naming context listener for this web application. >+ */ >+ private NamingContextListener namingContextListener = null; >+ >+ >+ /** >+ * The naming resources for this web application. >+ */ >+ private NamingResources namingResources = null; >+ >+ /** >+ * The message destinations for this web application. >+ */ >+ private HashMap<String, MessageDestination> messageDestinations = >+ new HashMap<String, MessageDestination>(); >+ >+ >+ /** >+ * The MIME mappings for this web application, keyed by extension. >+ */ >+ private HashMap<String, String> mimeMappings = >+ new HashMap<String, String>(); >+ >+ >+ /** >+ * Special case: error page for status 200. >+ */ >+ private ErrorPage okErrorPage = null; >+ >+ >+ /** >+ * The context initialization parameters for this web application, >+ * keyed by name. >+ */ >+ private HashMap<String, String> parameters = new HashMap<String, String>(); >+ >+ >+ /** >+ * The request processing pause flag (while reloading occurs) >+ */ >+ private 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; >+ >+ >+ /** >+ * 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<String, String>(); >+ >+ >+ /** >+ * 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<String, String>(); >+ >+ 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). >+ */ >+ private HashMap<Integer, ErrorPage> statusPages = >+ new HashMap<Integer, ErrorPage>(); >+ >+ >+ /** >+ * 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; >+ >+ >+ /** >+ * Filesystem based flag. >+ */ >+ private boolean filesystemBased = false; >+ >+ >+ /** >+ * Name of the associated naming context. >+ */ >+ private String namingContextName = null; >+ >+ >+ /** >+ * Caching allowed flag. >+ */ >+ private boolean cachingAllowed = true; >+ >+ >+ /** >+ * Allow linking. >+ */ >+ protected boolean allowLinking = false; >+ >+ >+ /** >+ * Cache max size in KB. >+ */ >+ protected int cacheMaxSize = 10240; // 10 MB >+ >+ >+ /** >+ * Cache object max size in KB. >+ */ >+ protected int cacheObjectMaxSize = 512; // 512K >+ >+ >+ /** >+ * Cache TTL in ms. >+ */ >+ protected int cacheTTL = 5000; >+ >+ >+ /** >+ * List of resource aliases. >+ */ >+ private String aliases = null; >+ >+ >+ /** >+ * Non proxied resources. >+ */ >+ private DirContext webappResources = null; >+ >+ 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 >+ */ >+ 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 value used to turn on/off TLD processing >+ */ >+ private boolean processTlds = true; >+ >+ /** >+ * Attribute value used to turn on/off XML validation >+ */ >+ private boolean tldValidation = Globals.STRICT_SERVLET_COMPLIANCE; >+ >+ >+ /** >+ * Attribute value used to turn on/off TLD XML namespace validation >+ */ >+ private boolean tldNamespaceAware = Globals.STRICT_SERVLET_COMPLIANCE; >+ >+ >+ /** >+ * Should we save the configuration. >+ */ >+ private boolean saveConfig = true; >+ >+ >+ /** >+ * 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 = true; >+ >+ >+ /** >+ * 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; >+ >+ /** >+ * Should Tomcat attempt to null out any static or final fields from loaded >+ * classes when a web application is stopped as a work around for apparent >+ * garbage collection bugs and application coding errors? There have been >+ * some issues reported with log4j when this option is true. Applications >+ * without memory leaks using recent JVMs should operate correctly with this >+ * option set to <code>false</code>. If not specified, the default value of >+ * <code>false</code> will be used. >+ */ >+ private boolean clearReferencesStatic = false; >+ >+ /** >+ * 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 WebappClassLoader} to >+ * {@link WebappClassLoader#parent} 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 of 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 = >+ new ApplicationJspConfigDescriptor(); >+ >+ private Set<String> resourceOnlyServlets = new HashSet<String>(); >+ >+ 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<Servlet>(); >+ >+ private boolean preemptiveAuthentication = false; >+ >+ private boolean sendRedirectBody = false; >+ >+ >+ // ----------------------------------------------------- Context Properties >+ >+ @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; >+ } >+ >+ >+ public void setAddWebinfClassesResources( >+ boolean addWebinfClassesResources) { >+ this.addWebinfClassesResources = addWebinfClassesResources; >+ } >+ >+ >+ 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) { >+ 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() { >+ if (this instanceof Authenticator) >+ return (Authenticator) this; >+ >+ Pipeline pipeline = getPipeline(); >+ if (pipeline != null) { >+ Valve basic = pipeline.getBasic(); >+ if ((basic != null) && (basic instanceof Authenticator)) >+ return (Authenticator) basic; >+ Valve valves[] = pipeline.getValves(); >+ for (int i = 0; i < valves.length; i++) { >+ if (valves[i] instanceof Authenticator) >+ return (Authenticator) valves[i]; >+ } >+ } >+ return null; >+ } >+ >+ @Override >+ public JarScanner getJarScanner() { >+ if (jarScanner == null) { >+ jarScanner = new StandardJarScanner(); >+ } >+ return jarScanner; >+ } >+ >+ >+ @Override >+ public void setJarScanner(JarScanner jarScanner) { >+ this.jarScanner = jarScanner; >+ } >+ >+ >+ public InstanceManager getInstanceManager() { >+ return instanceManager; >+ } >+ >+ >+ public void setInstanceManager(InstanceManager instanceManager) { >+ this.instanceManager = instanceManager; >+ } >+ >+ >+ @Override >+ public String getEncodedPath() { >+ return encodedPath; >+ } >+ >+ >+ /** >+ * Is caching allowed ? >+ */ >+ public boolean isCachingAllowed() { >+ return cachingAllowed; >+ } >+ >+ >+ /** >+ * Set caching allowed flag. >+ */ >+ public void setCachingAllowed(boolean cachingAllowed) { >+ this.cachingAllowed = cachingAllowed; >+ } >+ >+ >+ /** >+ * Set allow linking. >+ */ >+ public void setAllowLinking(boolean allowLinking) { >+ this.allowLinking = allowLinking; >+ } >+ >+ >+ /** >+ * Is linking allowed. >+ */ >+ public boolean isAllowLinking() { >+ return allowLinking; >+ } >+ >+ /** >+ * 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; >+ } >+ >+ /** >+ * Set cache TTL. >+ */ >+ public void setCacheTTL(int cacheTTL) { >+ this.cacheTTL = cacheTTL; >+ } >+ >+ >+ /** >+ * Get cache TTL. >+ */ >+ public int getCacheTTL() { >+ return cacheTTL; >+ } >+ >+ >+ /** >+ * Return the maximum size of the cache in KB. >+ */ >+ public int getCacheMaxSize() { >+ return cacheMaxSize; >+ } >+ >+ >+ /** >+ * Set the maximum size of the cache in KB. >+ */ >+ public void setCacheMaxSize(int cacheMaxSize) { >+ this.cacheMaxSize = cacheMaxSize; >+ } >+ >+ >+ /** >+ * Return the maximum size of objects to be cached in KB. >+ */ >+ public int getCacheObjectMaxSize() { >+ return cacheObjectMaxSize; >+ } >+ >+ >+ /** >+ * Set the maximum size of objects to be placed the cache in KB. >+ */ >+ public void setCacheObjectMaxSize(int cacheObjectMaxSize) { >+ this.cacheObjectMaxSize = cacheObjectMaxSize; >+ } >+ >+ >+ /** >+ * Return the list of resource aliases. >+ */ >+ public String getAliases() { >+ return this.aliases; >+ } >+ >+ >+ /** >+ * Add a URL for a JAR that contains static resources in a >+ * META-INF/resources directory that should be included in the static >+ * resources for this context. >+ */ >+ @Override >+ public void addResourceJarUrl(URL url) { >+ if (webappResources instanceof BaseDirContext) { >+ ((BaseDirContext) webappResources).addResourcesJar(url); >+ } else { >+ log.error(sm.getString("standardContext.noResourceJar", url, >+ getName())); >+ } >+ } >+ >+ >+ /** >+ * Set the current alias configuration. The list of aliases should be of the >+ * form "/aliasPath1=docBase1,/aliasPath2=docBase2" where aliasPathN must >+ * include a leading '/' and docBaseN must be an absolute path to either a >+ * .war file or a directory. >+ */ >+ public void setAliases(String aliases) { >+ this.aliases = aliases; >+ } >+ >+ >+ /** >+ * 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. >+ */ >+ 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); >+ >+ } >+ >+ >+ /** >+ * Returns true if the internal naming support is used. >+ */ >+ public boolean isUseNaming() { >+ >+ return (useNaming); >+ >+ } >+ >+ >+ /** >+ * Enables or disables naming. >+ */ >+ public void setUseNaming(boolean useNaming) { >+ this.useNaming = useNaming; >+ } >+ >+ >+ /** >+ * Returns true if the resources associated with this context are >+ * filesystem based. >+ */ >+ public boolean isFilesystemBased() { >+ >+ return (filesystemBased); >+ >+ } >+ >+ >+ /** >+ * Return the set of initialized application event listener objects, >+ * in the order they were specified in the web application deployment >+ * descriptor, for this application. >+ * >+ * @exception IllegalStateException if this method is called before >+ * this application has started, or after it has been stopped >+ */ >+ @Override >+ public Object[] getApplicationEventListeners() { >+ return (applicationEventListenersObjects); >+ } >+ >+ >+ /** >+ * Store the set of initialized application event 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 setApplicationEventListeners(Object listeners[]) { >+ applicationEventListenersObjects = listeners; >+ } >+ >+ >+ /** >+ * Add a listener to the end of the list of initialized application event >+ * listeners. >+ */ >+ public void addApplicationEventListener(Object listener) { >+ int len = applicationEventListenersObjects.length; >+ Object[] newListeners = Arrays.copyOf(applicationEventListenersObjects, >+ len + 1); >+ newListeners[len] = listener; >+ applicationEventListenersObjects = newListeners; >+ } >+ >+ >+ /** >+ * Return the set of initialized application lifecycle listener objects, >+ * in the order they were specified in the web application deployment >+ * descriptor, for this application. >+ * >+ * @exception IllegalStateException if this method is called before >+ * this application has started, or after it has been stopped >+ */ >+ @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. >+ */ >+ public void addApplicationLifecycleListener(Object listener) { >+ int len = applicationLifecycleListenersObjects.length; >+ Object[] newListeners = Arrays.copyOf( >+ applicationLifecycleListenersObjects, len + 1); >+ newListeners[len] = listener; >+ applicationLifecycleListenersObjects = newListeners; >+ } >+ >+ >+ /** >+ * Return the antiJARLocking flag for this Context. >+ */ >+ public boolean getAntiJARLocking() { >+ >+ return (this.antiJARLocking); >+ >+ } >+ >+ >+ /** >+ * Return the antiResourceLocking flag for this Context. >+ */ >+ public boolean getAntiResourceLocking() { >+ >+ return (this.antiResourceLocking); >+ >+ } >+ >+ >+ /** >+ * Set the antiJARLocking feature for this Context. >+ * >+ * @param antiJARLocking The new flag value >+ */ >+ public void setAntiJARLocking(boolean antiJARLocking) { >+ >+ boolean oldAntiJARLocking = this.antiJARLocking; >+ this.antiJARLocking = antiJARLocking; >+ support.firePropertyChange("antiJARLocking", >+ oldAntiJARLocking, >+ this.antiJARLocking); >+ >+ } >+ >+ >+ /** >+ * 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 application available flag for this Context. >+ */ >+ @Override >+ public boolean getAvailable() { >+ >+ // TODO Remove this method entirely >+ return getState().isAvailable(); >+ >+ } >+ >+ >+ /** >+ * Return the Locale to character set mapper for this Context. >+ */ >+ @Override >+ 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 >+ */ >+ @Override >+ 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); >+ >+ } >+ >+ /** >+ * Return the URL of the XML descriptor for this context. >+ */ >+ @Override >+ public URL getConfigFile() { >+ >+ return (this.configFile); >+ >+ } >+ >+ >+ /** >+ * Set the URL of the XML descriptor for this context. >+ * >+ * @param configFile The URL of the XML descriptor for this context. >+ */ >+ @Override >+ public void setConfigFile(URL configFile) { >+ >+ this.configFile = configFile; >+ } >+ >+ >+ /** >+ * Return the "correctly configured" flag for this Context. >+ */ >+ @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); >+ >+ } >+ >+ >+ /** >+ * Return the "use cookies for session ids" flag. >+ */ >+ @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; >+ } >+ >+ >+ /** >+ * Return the "allow crossing servlet contexts" flag. >+ */ >+ @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; >+ } >+ >+ /** >+ * 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. >+ */ >+ @Override >+ public void setAltDDName(String altDDName) { >+ this.altDDName = altDDName; >+ if (context != null) { >+ context.setAttribute(Globals.ALT_DD_ATTR,altDDName); >+ } >+ } >+ >+ >+ /** >+ * Return the compiler classpath. >+ */ >+ public String getCompilerClasspath(){ >+ return compilerClasspath; >+ } >+ >+ >+ /** >+ * Set the compiler classpath. >+ */ >+ public void setCompilerClasspath(String compilerClasspath) { >+ this.compilerClasspath = compilerClasspath; >+ } >+ >+ >+ /** >+ * 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); >+ >+ // Bugzilla 32866 >+ if(getManager() != null) { >+ if(log.isDebugEnabled()) { >+ log.debug("Propagating distributable=" + distributable >+ + " to manager"); >+ } >+ getManager().setDistributable(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; >+ >+ } >+ >+ /** >+ * Return descriptive information about this Container implementation and >+ * the corresponding version number, in the format >+ * <code><description>/<version></code>. >+ */ >+ @Override >+ public String getInfo() { >+ >+ return (info); >+ >+ } >+ >+ 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; >+ } >+ >+ >+ /** >+ * Set the Loader with which this Context is associated. >+ * >+ * @param loader The newly associated loader >+ */ >+ @Override >+ public synchronized void setLoader(Loader loader) { >+ >+ super.setLoader(loader); >+ >+ } >+ >+ >+ /** >+ * 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); >+ >+ } >+ >+ >+ /** >+ * Get the mapper associated with the context. >+ */ >+ @Override >+ public org.apache.tomcat.util.http.mapper.Mapper getMapper() { >+ return (mapper); >+ } >+ >+ >+ /** >+ * Return the naming resources associated with this web application. >+ */ >+ @Override >+ public NamingResources getNamingResources() { >+ >+ if (namingResources == null) { >+ setNamingResources(new NamingResources()); >+ } >+ return (namingResources); >+ >+ } >+ >+ >+ /** >+ * Set the naming resources for this web application. >+ * >+ * @param namingResources The new naming resources >+ */ >+ @Override >+ public void setNamingResources(NamingResources namingResources) { >+ >+ // Process the property setting change >+ NamingResources 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) { >+ if (path == null || (!path.equals("") && !path.startsWith("/"))) { >+ this.path = "/" + path; >+ log.warn(sm.getString( >+ "standardContext.pathInvalid", path, this.path)); >+ } else { >+ this.path = path; >+ } >+ encodedPath = urlEncoder.encode(this.path); >+ 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); >+ >+ } >+ >+ >+ /** >+ * Return the "replace welcome files" property. >+ */ >+ public boolean isReplaceWelcomeFiles() { >+ >+ return (this.replaceWelcomeFiles); >+ >+ } >+ >+ >+ /** >+ * 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)); >+ >+ } >+ >+ >+ /** >+ * Unpack WAR flag accessor. >+ */ >+ public boolean getUnpackWAR() { >+ >+ return (unpackWAR); >+ >+ } >+ >+ >+ /** >+ * Unpack WAR flag mutator. >+ */ >+ public void setUnpackWAR(boolean unpackWAR) { >+ >+ this.unpackWAR = unpackWAR; >+ >+ } >+ >+ /** >+ * 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()); >+ } >+ } >+ >+ >+ /** >+ * Set the resources DirContext object with which this Container is >+ * associated. >+ * >+ * @param resources The newly associated DirContext >+ */ >+ @Override >+ public synchronized void setResources(DirContext resources) { >+ >+ if (getState().isAvailable()) { >+ throw new IllegalStateException >+ (sm.getString("standardContext.resources.started")); >+ } >+ >+ DirContext oldResources = this.webappResources; >+ if (oldResources == resources) >+ return; >+ >+ if (resources instanceof BaseDirContext) { >+ // Caching >+ ((BaseDirContext) resources).setCached(isCachingAllowed()); >+ ((BaseDirContext) resources).setCacheTTL(getCacheTTL()); >+ ((BaseDirContext) resources).setCacheMaxSize(getCacheMaxSize()); >+ ((BaseDirContext) resources).setCacheObjectMaxSize( >+ getCacheObjectMaxSize()); >+ // Alias support >+ ((BaseDirContext) resources).setAliases(getAliases()); >+ } >+ if (resources instanceof FileDirContext) { >+ filesystemBased = true; >+ ((FileDirContext) resources).setAllowLinking(isAllowLinking()); >+ } >+ this.webappResources = resources; >+ >+ // The proxied resources will be refreshed on start >+ this.resources = null; >+ >+ support.firePropertyChange("resources", oldResources, >+ this.webappResources); >+ >+ } >+ >+ >+ @Override >+ public JspConfigDescriptor getJspConfigDescriptor() { >+ return jspConfigDescriptor; >+ } >+ >+ >+ // ------------------------------------------------------ Public Properties >+ >+ >+ /** >+ * 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()) { >+ File catalinaHome = engineBase(); >+ String catalinaHomePath = null; >+ try { >+ catalinaHomePath = catalinaHome.getCanonicalPath(); >+ workDir = new File(catalinaHomePath, >+ 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(); >+ } >+ } >+ >+ >+ /** >+ * Save config ? >+ */ >+ public boolean isSaveConfig() { >+ return saveConfig; >+ } >+ >+ >+ /** >+ * Set save config flag. >+ */ >+ public void setSaveConfig(boolean saveConfig) { >+ this.saveConfig = saveConfig; >+ } >+ >+ >+ /** >+ * Return the clearReferencesStatic flag for this Context. >+ */ >+ public boolean getClearReferencesStatic() { >+ >+ return (this.clearReferencesStatic); >+ >+ } >+ >+ >+ /** >+ * Set the clearReferencesStatic feature for this Context. >+ * >+ * @param clearReferencesStatic The new flag value >+ */ >+ public void setClearReferencesStatic(boolean clearReferencesStatic) { >+ >+ boolean oldClearReferencesStatic = this.clearReferencesStatic; >+ this.clearReferencesStatic = clearReferencesStatic; >+ support.firePropertyChange("clearReferencesStatic", >+ oldClearReferencesStatic, >+ this.clearReferencesStatic); >+ >+ } >+ >+ >+ /** >+ * 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); >+ } >+ >+ // -------------------------------------------------------- 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. >+ */ >+ @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) { >+ if (errorPage.getErrorCode() == 200) { >+ this.okErrorPage = errorPage; >+ } >+ 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. >+ */ >+ 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 the classname of an InstanceListener to be added to each >+ * Wrapper appended to this Context. >+ * >+ * @param listener Java class name of an InstanceListener class >+ */ >+ @Override >+ public void addInstanceListener(String listener) { >+ >+ synchronized (instanceListenersLock) { >+ String results[] =new String[instanceListeners.length + 1]; >+ for (int i = 0; i < instanceListeners.length; i++) >+ results[i] = instanceListeners[i]; >+ results[instanceListeners.length] = listener; >+ instanceListeners = results; >+ } >+ fireContainerEvent("addInstanceListener", listener); >+ >+ } >+ >+ /** >+ * 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, 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")); >+ if (parameters.get(name) != null) >+ throw new IllegalArgumentException >+ (sm.getString("standardContext.parameter.duplicate", name)); >+ >+ // Add this parameter to our defined set >+ synchronized (parameters) { >+ parameters.put(name, value); >+ } >+ 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(RequestUtil.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); >+ mapper.removeWrapper(decodedPattern); >+ } >+ servletMappings.put(decodedPattern, name); >+ } >+ Wrapper wrapper = (Wrapper) findChild(name); >+ wrapper.addMapping(decodedPattern); >+ >+ // Update context mapper >+ mapper.addWrapper(decodedPattern, wrapper, jspWildCard, >+ resourceOnlyServlets.contains(name)); >+ >+ 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 (instanceListenersLock) { >+ for (int i = 0; i < instanceListeners.length; i++) { >+ try { >+ Class<?> clazz = Class.forName(instanceListeners[i]); >+ InstanceListener listener = >+ (InstanceListener) clazz.newInstance(); >+ wrapper.addInstanceListener(listener); >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ log.error("createWrapper", t); >+ return (null); >+ } >+ } >+ } >+ >+ 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) { >+ if (errorCode == 200) { >+ return (okErrorPage); >+ } else { >+ 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 set of InstanceListener classes that will be added to >+ * newly created Wrappers automatically. >+ */ >+ @Override >+ public String[] findInstanceListeners() { >+ >+ synchronized (instanceListenersLock) { >+ return (instanceListeners); >+ } >+ >+ } >+ >+ >+ /** >+ * FIXME: Fooling introspection ... >+ */ >+ public Context findMappingObject() { >+ return (Context) getMappingObject(); >+ } >+ >+ >+ /** >+ * 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)); >+ >+ } >+ >+ >+ /** >+ * 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) { >+ >+ synchronized (parameters) { >+ 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() { >+ >+ synchronized (parameters) { >+ String results[] = new String[parameters.size()]; >+ return (parameters.keySet().toArray(results)); >+ } >+ >+ } >+ >+ >+ /** >+ * 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 >+ */ >+ @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. It does not handle changes to the web application >+ * deployment descriptor. If that has occurred, you should stop this >+ * Context and create (and start) a new Context instance instead. >+ * >+ * @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 welcome file 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 constraint >+ 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) { >+ if (errorPage.getErrorCode() == 200) { >+ this.okErrorPage = null; >+ } >+ 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 a class name from the set of InstanceListener classes that >+ * will be added to newly created Wrappers. >+ * >+ * @param listener Class name of an InstanceListener class to be removed >+ */ >+ @Override >+ public void removeInstanceListener(String listener) { >+ >+ synchronized (instanceListenersLock) { >+ >+ // Make sure this welcome file is currently present >+ int n = -1; >+ for (int i = 0; i < instanceListeners.length; i++) { >+ if (instanceListeners[i].equals(listener)) { >+ n = i; >+ break; >+ } >+ } >+ if (n < 0) >+ return; >+ >+ // Remove the specified constraint >+ int j = 0; >+ String results[] = new String[instanceListeners.length - 1]; >+ for (int i = 0; i < instanceListeners.length; i++) { >+ if (i != n) >+ results[j++] = instanceListeners[i]; >+ } >+ instanceListeners = results; >+ >+ } >+ >+ // Inform interested listeners >+ fireContainerEvent("removeInstanceListener", listener); >+ >+ } >+ >+ >+ /** >+ * 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) { >+ >+ synchronized (parameters) { >+ 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); >+ } >+ mapper.removeWrapper(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 constraint >+ 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 welcome file 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 constraint >+ 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 welcome file 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 constraint >+ 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; >+ } >+ >+ >+ /** >+ * 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) { >+ if (webappResources instanceof BaseDirContext) { >+ return ((BaseDirContext) webappResources).getRealPath(path); >+ } >+ return null; >+ } >+ >+ /** >+ * hook to register that we need to scan for security annotations. >+ * @param wrapper The wrapper for the Servlet that was added >+ */ >+ 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 >+ */ >+ 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(); >+ Iterator<String> names = filterDefs.keySet().iterator(); >+ while (names.hasNext()) { >+ String name = names.next(); >+ if (getLogger().isDebugEnabled()) >+ getLogger().debug(" Starting filter '" + name + "'"); >+ ApplicationFilterConfig filterConfig = null; >+ try { >+ filterConfig = >+ new ApplicationFilterConfig(this, filterDefs.get(name)); >+ filterConfigs.put(name, filterConfig); >+ } catch (Throwable 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) { >+ Iterator<String> names = filterConfigs.keySet().iterator(); >+ while (names.hasNext()) { >+ String name = names.next(); >+ if (getLogger().isDebugEnabled()) >+ getLogger().debug(" Stopping filter '" + name + "'"); >+ ApplicationFilterConfig filterConfig = filterConfigs.get(name); >+ 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 >+ */ >+ 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 { >+ results[i] = instanceManager.newInstance(listeners[i]); >+ } catch (Throwable 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<Object>(); >+ ArrayList<Object> lifecycleListeners = new ArrayList<Object>(); >+ for (int i = 0; i < results.length; i++) { >+ if ((results[i] instanceof ServletContextAttributeListener) >+ || (results[i] instanceof ServletRequestAttributeListener) >+ || (results[i] instanceof ServletRequestListener) >+ || (results[i] instanceof HttpSessionAttributeListener)) { >+ eventListeners.add(results[i]); >+ } >+ if ((results[i] instanceof ServletContextListener) >+ || (results[i] instanceof HttpSessionListener)) { >+ lifecycleListeners.add(results[i]); >+ } >+ } >+ >+ //Listeners may have been added by ServletContextInitializers. Put them after the ones we know about. >+ for (Object eventListener: getApplicationEventListeners()) { >+ eventListeners.add(eventListener); >+ } >+ setApplicationEventListeners(eventListeners.toArray()); >+ for (Object lifecycleListener: getApplicationLifecycleListeners()) { >+ lifecycleListeners.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) >+ return (ok); >+ ServletContextEvent event = >+ new ServletContextEvent(getServletContext()); >+ for (int i = 0; i < instances.length; i++) { >+ if (instances[i] == null) >+ continue; >+ if (!(instances[i] instanceof ServletContextListener)) >+ continue; >+ ServletContextListener listener = >+ (ServletContextListener) instances[i]; >+ try { >+ fireContainerEvent("beforeContextInitialized", listener); >+ 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) { >+ ServletContextEvent event = >+ new ServletContextEvent(getServletContext()); >+ 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); >+ 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 { >+ getInstanceManager().destroyInstance(listeners[j]); >+ } catch (Throwable 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 { >+ getInstanceManager().destroyInstance(listeners[j]); >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ getLogger().error >+ (sm.getString("standardContext.listenerStop", >+ listeners[j].getClass().getName()), t); >+ ok = false; >+ } >+ } >+ } >+ >+ setApplicationEventListeners(null); >+ setApplicationLifecycleListeners(null); >+ >+ return (ok); >+ >+ } >+ >+ >+ /** >+ * Allocate resources, including proxy. >+ * Return <code>true</code> if initialization was successfull, >+ * or <code>false</code> otherwise. >+ */ >+ public boolean resourcesStart() { >+ >+ boolean ok = true; >+ >+ Hashtable<String, String> env = new Hashtable<String, String>(); >+ if (getParent() != null) >+ env.put(ProxyDirContext.HOST, getParent().getName()); >+ env.put(ProxyDirContext.CONTEXT, getName()); >+ >+ try { >+ ProxyDirContext proxyDirContext = >+ new ProxyDirContext(env, webappResources); >+ if (webappResources instanceof FileDirContext) { >+ filesystemBased = true; >+ ((FileDirContext) webappResources).setAllowLinking >+ (isAllowLinking()); >+ } >+ if (webappResources instanceof BaseDirContext) { >+ ((BaseDirContext) webappResources).setDocBase(getBasePath()); >+ ((BaseDirContext) webappResources).setCached >+ (isCachingAllowed()); >+ ((BaseDirContext) webappResources).setCacheTTL(getCacheTTL()); >+ ((BaseDirContext) webappResources).setCacheMaxSize >+ (getCacheMaxSize()); >+ ((BaseDirContext) webappResources).allocate(); >+ // Alias support >+ ((BaseDirContext) webappResources).setAliases(getAliases()); >+ >+ if (effectiveMajorVersion >=3 && addWebinfClassesResources) { >+ try { >+ DirContext webInfCtx = >+ (DirContext) webappResources.lookup( >+ "/WEB-INF/classes"); >+ // Do the lookup to make sure it exists >+ webInfCtx.lookup("META-INF/resources"); >+ ((BaseDirContext) webappResources).addAltDirContext( >+ webInfCtx); >+ } catch (NamingException e) { >+ // Doesn't exist - ignore and carry on >+ } >+ } >+ } >+ // Register the cache in JMX >+ if (isCachingAllowed()) { >+ String contextName = getName(); >+ if (!contextName.startsWith("/")) { >+ contextName = "/" + contextName; >+ } >+ ObjectName resourcesName = >+ new ObjectName(this.getDomain() + ":type=Cache,host=" >+ + getHostname() + ",context=" + contextName); >+ Registry.getRegistry(null, null).registerComponent >+ (proxyDirContext.getCache(), resourcesName, null); >+ } >+ this.resources = proxyDirContext; >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ log.error(sm.getString("standardContext.resourcesStart"), t); >+ ok = false; >+ } >+ >+ return (ok); >+ >+ } >+ >+ >+ /** >+ * Deallocate resources and destroy proxy. >+ */ >+ public boolean resourcesStop() { >+ >+ boolean ok = true; >+ >+ try { >+ if (resources != null) { >+ if (resources instanceof Lifecycle) { >+ ((Lifecycle) resources).stop(); >+ } >+ if (webappResources instanceof BaseDirContext) { >+ ((BaseDirContext) webappResources).release(); >+ } >+ // Unregister the cache in JMX >+ if (isCachingAllowed()) { >+ String contextName = getName(); >+ if (!contextName.startsWith("/")) { >+ contextName = "/" + contextName; >+ } >+ ObjectName resourcesName = >+ new ObjectName(this.getDomain() >+ + ":type=Cache,host=" >+ + getHostname() + ",context=" >+ + contextName); >+ Registry.getRegistry(null, null) >+ .unregisterComponent(resourcesName); >+ } >+ } >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ log.error(sm.getString("standardContext.resourcesStop"), t); >+ ok = false; >+ } >+ >+ this.resources = null; >+ >+ 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) >+ */ >+ public void loadOnStartup(Container children[]) { >+ >+ // Collect "load on startup" servlets that need to be initialized >+ TreeMap<Integer, ArrayList<Wrapper>> map = >+ new TreeMap<Integer, ArrayList<Wrapper>>(); >+ 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<Wrapper>(); >+ 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("standardWrapper.loadException", >+ getName()), StandardWrapper.getRootCause(e)); >+ // NOTE: load errors (including a servlet that throws >+ // UnavailableException from tht init() method) are NOT >+ // fatal to application startup >+ } >+ } >+ } >+ >+ } >+ >+ >+ /** >+ * 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 (webappResources == null) { // (1) Required by Loader >+ if (log.isDebugEnabled()) >+ log.debug("Configuring default Resources"); >+ try { >+ if ((getDocBase() != null) && (getDocBase().endsWith(".war")) && >+ (!(new File(getBasePath())).isDirectory())) >+ setResources(new WARDirContext()); >+ else >+ setResources(new FileDirContext()); >+ } catch (IllegalArgumentException e) { >+ log.error("Error initializing resources: " + e.getMessage()); >+ ok = false; >+ } >+ } >+ if (ok) { >+ if (!resourcesStart()) { >+ log.error( "Error in resourceStart()"); >+ ok = false; >+ } >+ } >+ >+ if (getLoader() == null) { >+ WebappLoader webappLoader = new WebappLoader(getParentClassLoader()); >+ webappLoader.setDelegate(getDelegate()); >+ setLoader(webappLoader); >+ } >+ >+ // 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("Error in dependencyCheck", 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()); >+ 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 >+ if ((loader != null) && (loader instanceof Lifecycle)) >+ ((Lifecycle) loader).start(); >+ >+ // since the loader just started, the webapp classloader is now >+ // created. >+ // 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(); >+ if ((logger != null) && (logger instanceof Lifecycle)) >+ ((Lifecycle) logger).start(); >+ >+ if ((cluster != null) && (cluster instanceof Lifecycle)) >+ ((Lifecycle) cluster).start(); >+ if ((realm != null) && (realm instanceof Lifecycle)) >+ ((Lifecycle) realm).start(); >+ if ((resources != null) && (resources instanceof Lifecycle)) >+ ((Lifecycle) resources).start(); >+ >+ // 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; >+ 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); >+ } >+ } >+ >+ } finally { >+ // Unbinding thread >+ unbindThread(oldCCL); >+ } >+ >+ if (!getConfigured()) { >+ log.error( "Error getConfigured"); >+ ok = false; >+ } >+ >+ // We put the resources into the servlet context >+ if (ok) >+ getServletContext().setAttribute >+ (Globals.RESOURCES_ATTR, getResources()); >+ >+ // Initialize associated mapper >+ mapper.setContext(getPath(), welcomeFiles, resources); >+ >+ // Binding thread >+ oldCCL = bindThread(); >+ >+ 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 NamingResources(): getNamingResources()); >+ setInstanceManager(new DefaultInstanceManager(context, >+ injectionMap, this, this.getClass().getClassLoader())); >+ getServletContext().setAttribute( >+ InstanceManager.class.getName(), getInstanceManager()); >+ } >+ } >+ >+ try { >+ // 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) { >+ // TODO: Log error >+ ok = false; >+ break; >+ } >+ } >+ >+ // Configure and call application event listeners >+ if (ok) { >+ if (!listenerStart()) { >+ log.error( "Error listenerStart"); >+ ok = false; >+ } >+ } >+ >+ try { >+ // Start manager >+ if ((manager != null) && (manager instanceof Lifecycle)) { >+ ((Lifecycle) getManager()).start(); >+ } >+ >+ // Start ContainerBackgroundProcessor thread >+ super.threadStart(); >+ } catch(Exception e) { >+ log.error("Error manager.start()", e); >+ ok = false; >+ } >+ >+ // Configure and call application filters >+ if (ok) { >+ if (!filterStart()) { >+ log.error("Error filterStart"); >+ ok = false; >+ } >+ } >+ >+ // Load and initialize all "load on startup" servlets >+ if (ok) { >+ loadOnStartup(findChildren()); >+ } >+ >+ } 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); >+ } >+ >+ // Close all JARs right away to avoid always opening a peak number >+ // of files on startup >+ if (getLoader() instanceof WebappLoader) { >+ ((WebappLoader) getLoader()).closeJARs(true); >+ } >+ >+ // Reinitializing if something went wrong >+ if (!ok) { >+ setState(LifecycleState.FAILED); >+ } else { >+ setState(LifecycleState.STARTING); >+ } >+ } >+ >+ private Map<String, Map<String, String>> buildInjectionMap(NamingResources namingResources) { >+ Map<String, Map<String, String>> injectionMap = new HashMap<String, Map<String, String>>(); >+ 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<String, String>(); >+ 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,String>(); >+ >+ 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(); >+ >+ ClassLoader old = bindThread(); >+ try { >+ for (int i = 0; i < children.length; i++) { >+ children[i].stop(); >+ } >+ >+ // Stop our filters >+ filterStop(); >+ >+ // Stop ContainerBackgroundProcessor thread >+ threadStop(); >+ >+ if (manager != null && manager instanceof Lifecycle && >+ ((Lifecycle) manager).getState().isAvailable()) { >+ ((Lifecycle) manager).stop(); >+ } >+ >+ // Stop our application listeners >+ listenerStop(); >+ } finally{ >+ unbindThread(old); >+ } >+ >+ // 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 resoucres 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(); >+ >+ // Stop resources >+ resourcesStop(); >+ >+ if ((realm != null) && (realm instanceof Lifecycle)) { >+ ((Lifecycle) realm).stop(); >+ } >+ if ((cluster != null) && (cluster instanceof Lifecycle)) { >+ ((Lifecycle) cluster).stop(); >+ } >+ if ((logger != null) && (logger instanceof Lifecycle)) { >+ ((Lifecycle) logger).stop(); >+ } >+ if ((loader != null) && (loader instanceof Lifecycle)) { >+ ((Lifecycle) loader).stop(); >+ } >+ >+ } 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 >+ instanceManager = 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 ((manager != null) && (manager instanceof Lifecycle)) { >+ ((Lifecycle) manager).destroy(); >+ } >+ if ((realm != null) && (realm instanceof Lifecycle)) { >+ ((Lifecycle) realm).destroy(); >+ } >+ if ((cluster != null) && (cluster instanceof Lifecycle)) { >+ ((Lifecycle) cluster).destroy(); >+ } >+ if ((logger != null) && (logger instanceof Lifecycle)) { >+ ((Lifecycle) logger).destroy(); >+ } >+ if ((loader != null) && (loader instanceof Lifecycle)) { >+ ((Lifecycle) loader).destroy(); >+ } >+ >+ // 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(); >+ } >+ >+ synchronized (instanceListenersLock) { >+ instanceListeners = new String[0]; >+ } >+ >+ super.destroyInternal(); >+ } >+ >+ 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 >+ children = new HashMap<String, Container>(); >+ startupTime = 0; >+ startTime = 0; >+ tldScanTime = 0; >+ >+ // Bugzilla 32867 >+ distributable = false; >+ >+ applicationListeners = new String[0]; >+ applicationEventListenersObjects = new Object[0]; >+ applicationLifecycleListenersObjects = new Object[0]; >+ jspConfigDescriptor = new ApplicationJspConfigDescriptor(); >+ >+ initializers.clear(); >+ >+ createdServlets.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 >+ */ >+ 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? >+ */ >+ @Override >+ public boolean isServlet22() { >+ >+ if (this.publicId == null) >+ return (false); >+ if (this.publicId.equals >+ (org.apache.catalina.startup.Constants.WebDtdPublicId_22)) >+ return (true); >+ else >+ return (false); >+ >+ } >+ >+ @Override >+ public Set<String> addServletSecurity( >+ ApplicationServletRegistration registration, >+ ServletSecurityElement servletSecurityElement) { >+ >+ Set<String> conflicts = new HashSet<String>(); >+ >+ 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); >+ } else { >+ // Need to overwrite constraint for this pattern >+ // so remove every pattern found >+ >+ // TODO spec 13.4.2 appears to say only the >+ // conflicting pattern is overwritten, not the >+ // entire security constraint. >+ removeConstraint(securityConstraint); >+ } >+ } >+ if (foundConflict) { >+ break; >+ } >+ } >+ if (foundConflict) { >+ break; >+ } >+ } >+ // TODO spec 13.4.2 appears to say that non-conflicting patterns are >+ // still used. >+ // TODO you can't calculate the eventual security constraint now, >+ // you have to wait until the context is started, since application >+ // code can add url patterns after calling setSecurity. >+ if (!foundConflict) { >+ SecurityConstraint[] newSecurityConstraints = >+ SecurityConstraint.createConstraints( >+ servletSecurityElement, >+ urlPattern); >+ for (SecurityConstraint securityConstraint : >+ newSecurityConstraints) { >+ addConstraint(securityConstraint); >+ } >+ } >+ } >+ >+ return conflicts; >+ >+ } >+ >+ >+ /** >+ * Return a File object representing the base directory for the >+ * entire servlet container (i.e. the Engine container if present). >+ */ >+ protected File engineBase() { >+ String base=System.getProperty(Globals.CATALINA_BASE_PROP); >+ if( base == null ) { >+ StandardEngine eng=(StandardEngine)this.getParent().getParent(); >+ base=eng.getBaseDir(); >+ } >+ return (new File(base)); >+ } >+ >+ >+ /** >+ * Bind current thread, both for CL purposes and for JNDI ENC support >+ * during : startup, shutdown and realoading of the context. >+ * >+ * @return the previous context class loader >+ */ >+ protected ClassLoader bindThread() { >+ >+ ClassLoader oldContextClassLoader = >+ Thread.currentThread().getContextClassLoader(); >+ >+ if (getResources() == null) >+ return oldContextClassLoader; >+ >+ if (getLoader().getClassLoader() != null) { >+ Thread.currentThread().setContextClassLoader >+ (getLoader().getClassLoader()); >+ } >+ >+ DirContextURLStreamHandler.bindThread(getResources()); >+ >+ if (isUseNaming()) { >+ try { >+ ContextBindings.bindThread(this, this); >+ } catch (NamingException e) { >+ // Silent catch, as this is a normal case during the early >+ // startup stages >+ } >+ } >+ >+ return oldContextClassLoader; >+ >+ } >+ >+ >+ /** >+ * Unbind thread. >+ */ >+ protected void unbindThread(ClassLoader oldContextClassLoader) { >+ >+ if (isUseNaming()) { >+ ContextBindings.unbindThread(this, this); >+ } >+ >+ DirContextURLStreamHandler.unbindThread(); >+ >+ Thread.currentThread().setContextClassLoader(oldContextClassLoader); >+ } >+ >+ >+ >+ /** >+ * Get base path. >+ */ >+ protected String getBasePath() { >+ String docBase = null; >+ Container container = this; >+ while (container != null) { >+ if (container instanceof Host) >+ break; >+ container = container.getParent(); >+ } >+ File file = new File(getDocBase()); >+ if (!file.isAbsolute()) { >+ if (container == null) { >+ docBase = (new File(engineBase(), getDocBase())).getPath(); >+ } else { >+ // Use the "appBase" property of this container >+ file = ((Host) container).getAppBaseFile(); >+ docBase = (new File(file, getDocBase())).getPath(); >+ } >+ } else { >+ docBase = file.getPath(); >+ } >+ return docBase; >+ } >+ >+ >+ /** >+ * Get naming context full name. >+ */ >+ private String getNamingContextName() { >+ if (namingContextName == null) { >+ Container parent = getParent(); >+ if (parent == null) { >+ namingContextName = getName(); >+ } else { >+ Stack<String> stk = new Stack<String>(); >+ 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. >+ */ >+ public NamingContextListener getNamingContextListener() { >+ return namingContextListener; >+ } >+ >+ >+ /** >+ * Naming context listener setter. >+ */ >+ public void setNamingContextListener(NamingContextListener namingContextListener) { >+ this.namingContextListener = namingContextListener; >+ } >+ >+ >+ /** >+ * Return the request processing paused flag for this Context. >+ */ >+ @Override >+ public boolean getPaused() { >+ >+ return (this.paused); >+ >+ } >+ >+ >+ public String getHostname() { >+ Container parentHost = getParent(); >+ if (parentHost != null) { >+ hostName = parentHost.getName(); >+ } >+ if ((hostName == null) || (hostName.length() < 1)) >+ hostName = "_"; >+ return hostName; >+ } >+ >+ >+ @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; >+ } >+ >+ >+ /** >+ * 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 = getName(); >+ if (temp.startsWith("/")) >+ temp = temp.substring(1); >+ temp = temp.replace('/', '_'); >+ temp = temp.replace('\\', '_'); >+ if (temp.length() < 1) >+ temp = "_"; >+ 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()) { >+ File catalinaHome = engineBase(); >+ String catalinaHomePath = null; >+ try { >+ catalinaHomePath = catalinaHome.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 >+ */ >+ private boolean validateURLPattern(String urlPattern) { >+ >+ if (urlPattern == null) >+ return (false); >+ if (urlPattern.indexOf('\n') >= 0 || urlPattern.indexOf('\r') >= 0) { >+ return (false); >+ } >+ 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()) { >+ if(urlPattern.endsWith("*") && (urlPattern.length() < 2 || >+ urlPattern.charAt(urlPattern.length()-2) != '/')) { >+ log.info("Suspicious url pattern: \"" + urlPattern + "\"" + >+ " in context [" + getName() + "] - see" + >+ " section SRV.11.2 of the Servlet specification" ); >+ } >+ } >+ } >+ >+ >+ // ------------------------------------------------------------- Operations >+ >+ >+ /** >+ * JSR77 deploymentDescriptor attribute >+ * >+ * @return string deployment descriptor >+ */ >+ public String getDeploymentDescriptor() { >+ >+ InputStream stream = null; >+ ServletContext servletContext = getServletContext(); >+ if (servletContext != null) { >+ stream = servletContext.getResourceAsStream( >+ org.apache.catalina.startup.Constants.ApplicationWebXml); >+ } >+ if (stream == null) { >+ return ""; >+ } >+ StringBuilder sb = new StringBuilder(); >+ BufferedReader br = null; >+ try { >+ br = new BufferedReader(new InputStreamReader(stream)); >+ String strRead = ""; >+ while (strRead != null) { >+ sb.append(strRead); >+ strRead = br.readLine(); >+ } >+ } catch (IOException e) { >+ return ""; >+ } finally { >+ if (br != null) { >+ try { >+ br.close(); >+ } catch (IOException ioe) {/*Ignore*/} >+ } >+ } >+ >+ return sb.toString(); >+ } >+ >+ >+ /** >+ * JSR77 servlets attribute >+ * >+ * @return list of all servlets ( we know about ) >+ */ >+ public String[] getServlets() { >+ >+ String[] result = null; >+ >+ Container[] children = findChildren(); >+ if (children != null) { >+ result = new String[children.length]; >+ for( int i=0; i< children.length; i++ ) { >+ result[i] = children[i].getObjectName().toString(); >+ } >+ } >+ >+ return result; >+ } >+ >+ >+ @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(); >+ >+ if (processTlds) { >+ this.addLifecycleListener(new TldConfig()); >+ } >+ >+ // 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 javax.naming.directory.DirContext getStaticResources() { >+ >+ return getResources(); >+ >+ } >+ >+ >+ /** >+ * Return the naming resources associated with this web application. >+ * FIXME: Fooling introspection ... >+ */ >+ public javax.naming.directory.DirContext findStaticResources() { >+ >+ return getResources(); >+ >+ } >+ >+ >+ /** >+ * Return the naming resources associated with this web application. >+ */ >+ public String[] getWelcomeFiles() { >+ >+ return findWelcomeFiles(); >+ >+ } >+ >+ /** >+ * Set the validation feature of the XML parser used when >+ * parsing xml instances. >+ * @param webXmlValidation true to enable xml instance validation >+ */ >+ @Override >+ public void setXmlValidation(boolean webXmlValidation){ >+ >+ this.webXmlValidation = webXmlValidation; >+ >+ } >+ >+ /** >+ * Get the server.xml <context> attribute's xmlValidation. >+ * @return true if validation is enabled. >+ * >+ */ >+ @Override >+ public boolean getXmlValidation(){ >+ return webXmlValidation; >+ } >+ >+ >+ /** >+ * Get the server.xml <context> attribute's xmlNamespaceAware. >+ * @return true if namespace awarenes is enabled. >+ */ >+ @Override >+ public boolean getXmlNamespaceAware(){ >+ return webXmlNamespaceAware; >+ } >+ >+ >+ /** >+ * Set the namespace aware feature of the XML parser used when >+ * parsing xml instances. >+ * @param webXmlNamespaceAware true to enable namespace awareness >+ */ >+ @Override >+ public void setXmlNamespaceAware(boolean webXmlNamespaceAware){ >+ this.webXmlNamespaceAware= webXmlNamespaceAware; >+ } >+ >+ >+ /** >+ * Set the validation feature of the XML parser used when >+ * parsing tlds files. >+ * @param tldValidation true to enable xml instance validation >+ */ >+ @Override >+ public void setTldValidation(boolean tldValidation){ >+ >+ this.tldValidation = tldValidation; >+ >+ } >+ >+ /** >+ * Get the server.xml <context> attribute's webXmlValidation. >+ * @return true if validation is enabled. >+ * >+ */ >+ @Override >+ public boolean getTldValidation(){ >+ return tldValidation; >+ } >+ >+ /** >+ * Sets the process TLDs attribute. >+ * >+ * @param newProcessTlds The new value >+ */ >+ public void setProcessTlds(boolean newProcessTlds) { >+ processTlds = newProcessTlds; >+ } >+ >+ /** >+ * Returns the processTlds attribute value. >+ */ >+ public boolean getProcessTlds() { >+ return processTlds; >+ } >+ >+ /** >+ * Get the server.xml <host> attribute's xmlNamespaceAware. >+ * @return true if namespace awarenes is enabled. >+ */ >+ @Override >+ public boolean getTldNamespaceAware(){ >+ return tldNamespaceAware; >+ } >+ >+ >+ /** >+ * Set the namespace aware feature of the XML parser used when >+ * parsing xml instances. >+ * @param tldNamespaceAware true to enable namespace awareness >+ */ >+ @Override >+ public void setTldNamespaceAware(boolean tldNamespaceAware){ >+ this.tldNamespaceAware= tldNamespaceAware; >+ } >+ >+ >+ /** >+ * Support for "stateManageable" JSR77 >+ */ >+ public boolean isStateManageable() { >+ return true; >+ } >+ >+ public void startRecursive() throws LifecycleException { >+ // nothing to start recursive, the servlets will be started by load-on-startup >+ start(); >+ } >+ >+ /** >+ * 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; >+ } >+ >+ public boolean isEventProvider() { >+ return false; >+ } >+ >+ public boolean isStatisticsProvider() { >+ return false; >+ } >+ >+ private abstract static class RunnableWithLifecycleException >+ implements Runnable { >+ >+ protected LifecycleException le = null; >+ >+ public LifecycleException getLifecycleException() { >+ return le; >+ } >+ } >+} >diff --git a/java/org/apache/catalina/core/StandardHost.java b/java/org/apache/catalina/core/StandardHost.java >index 3b1fb50..5419f1f 100644 >--- a/java/org/apache/catalina/core/StandardHost.java >+++ b/java/org/apache/catalina/core/StandardHost.java >@@ -1,851 +1,857 @@ >-/* >- * 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.util.ArrayList; >-import java.util.List; >-import java.util.Locale; >-import java.util.Map; >-import java.util.WeakHashMap; >-import java.util.regex.Pattern; >- >-import org.apache.catalina.Container; >-import org.apache.catalina.Context; >-import org.apache.catalina.Globals; >-import org.apache.catalina.Host; >-import org.apache.catalina.Lifecycle; >-import org.apache.catalina.LifecycleEvent; >-import org.apache.catalina.LifecycleException; >-import org.apache.catalina.LifecycleListener; >-import org.apache.catalina.Valve; >-import org.apache.catalina.loader.WebappClassLoader; >-import org.apache.catalina.mbeans.MBeanUtils; >-import org.apache.catalina.valves.ValveBase; >-import org.apache.tomcat.util.ExceptionUtils; >- >- >-/** >- * Standard implementation of the <b>Host</b> interface. Each >- * child container must be a Context implementation to process the >- * requests directed to a particular web application. >- * >- * @author Craig R. McClanahan >- * @author Remy Maucherat >- * @version $Id$ >- */ >- >-public class StandardHost extends ContainerBase implements Host { >- >- private static final org.apache.juli.logging.Log log= >- org.apache.juli.logging.LogFactory.getLog( StandardHost.class ); >- >- // ----------------------------------------------------------- Constructors >- >- >- /** >- * Create a new StandardHost component with the default basic Valve. >- */ >- public StandardHost() { >- >- super(); >- pipeline.setBasic(new StandardHostValve()); >- >- } >- >- >- // ----------------------------------------------------- Instance Variables >- >- >- /** >- * The set of aliases for this Host. >- */ >- private String[] aliases = new String[0]; >- >- private final Object aliasesLock = new Object(); >- >- >- /** >- * The application root for this Host. >- */ >- private String appBase = "webapps"; >- private volatile File appBaseFile = null; >- >- /** >- * The XML root for this Host. >- */ >- private String xmlBase = null; >- >- /** >- * The auto deploy flag for this Host. >- */ >- private boolean autoDeploy = true; >- >- >- /** >- * The Java class name of the default context configuration class >- * for deployed web applications. >- */ >- private String configClass = >- "org.apache.catalina.startup.ContextConfig"; >- >- >- /** >- * The Java class name of the default Context implementation class for >- * deployed web applications. >- */ >- private String contextClass = >- "org.apache.catalina.core.StandardContext"; >- >- >- /** >- * The deploy on startup flag for this Host. >- */ >- private boolean deployOnStartup = true; >- >- >- /** >- * deploy Context XML config files property. >- */ >- private boolean deployXML = true; >- >- >- /** >- * Should XML files be copied to $CATALINA_BASE/conf/<engine>/<host> by >- * default when a web application is deployed? >- */ >- private boolean copyXML = false; >- >- >- /** >- * The Java class name of the default error reporter implementation class >- * for deployed web applications. >- */ >- private String errorReportValveClass = >- "org.apache.catalina.valves.ErrorReportValve"; >- >- /** >- * The descriptive information string for this implementation. >- */ >- private static final String info = >- "org.apache.catalina.core.StandardHost/1.0"; >- >- >- /** >- * Unpack WARs property. >- */ >- private boolean unpackWARs = true; >- >- >- /** >- * Work Directory base for applications. >- */ >- private String workDir = null; >- >- >- /** >- * Should we create directories upon startup for appBase and xmlBase >- */ >- private boolean createDirs = true; >- >- >- /** >- * Track the class loaders for the child web applications so memory leaks >- * can be detected. >- */ >- private Map<ClassLoader, String> childClassLoaders = >- new WeakHashMap<ClassLoader, String>(); >- >- >- /** >- * Any file or directory in {@link #appBase} that this pattern matches will >- * be ignored by the automatic deployment process (both >- * {@link #deployOnStartup} and {@link #autoDeploy}). >- */ >- private Pattern deployIgnore = null; >- >- >- // ------------------------------------------------------------- Properties >- >- >- /** >- * Return the application root for this Host. This can be an absolute >- * pathname, a relative pathname, or a URL. >- */ >- @Override >- public String getAppBase() { >- return (this.appBase); >- } >- >- >- /** >- * ({@inheritDoc} >- */ >- @Override >- public File getAppBaseFile() { >- >- if (appBaseFile != null) { >- return appBaseFile; >- } >- >- File file = new File(getAppBase()); >- >- // If not absolute, make it absolute >- if (!file.isAbsolute()) { >- // This system property should always be set >- file = new File(System.getProperty(Globals.CATALINA_BASE_PROP), >- file.getPath()); >- } >- >- // Make it canonical if possible >- try { >- file = file.getCanonicalFile(); >- } catch (IOException ioe) { >- // Ignore >- } >- >- this.appBaseFile = file; >- return file; >- } >- >- >- /** >- * Set the application root for this Host. This can be an absolute >- * pathname, a relative pathname, or a URL. >- * >- * @param appBase The new application root >- */ >- @Override >- public void setAppBase(String appBase) { >- >- String oldAppBase = this.appBase; >- this.appBase = appBase; >- support.firePropertyChange("appBase", oldAppBase, this.appBase); >- this.appBaseFile = null; >- } >- >- >- /** >- * Return the XML root for this Host. This can be an absolute >- * pathname, a relative pathname, or a URL. >- * If null, defaults to ${catalina.base}/conf/ directory >- */ >- @Override >- public String getXmlBase() { >- >- return (this.xmlBase); >- >- } >- >- >- /** >- * Set the Xml root for this Host. This can be an absolute >- * pathname, a relative pathname, or a URL. >- * If null, defaults to ${catalina.base}/conf/ directory >- * >- * @param xmlBase The new XML root >- */ >- @Override >- public void setXmlBase(String xmlBase) { >- >- String oldXmlBase = this.xmlBase; >- this.xmlBase = xmlBase; >- support.firePropertyChange("xmlBase", oldXmlBase, this.xmlBase); >- >- } >- >- >- /** >- * Returns true if the Host will attempt to create directories for appBase and xmlBase >- * unless they already exist. >- */ >- @Override >- public boolean getCreateDirs() { >- return createDirs; >- } >- >- /** >- * Set to true if the Host should attempt to create directories for xmlBase and appBase upon startup >- * @param createDirs >- */ >- @Override >- public void setCreateDirs(boolean createDirs) { >- this.createDirs = createDirs; >- } >- >- /** >- * Return the value of the auto deploy flag. If true, it indicates that >- * this host's child webapps will be dynamically deployed. >- */ >- @Override >- public boolean getAutoDeploy() { >- >- return (this.autoDeploy); >- >- } >- >- >- /** >- * Set the auto deploy flag value for this host. >- * >- * @param autoDeploy The new auto deploy flag >- */ >- @Override >- public void setAutoDeploy(boolean autoDeploy) { >- >- boolean oldAutoDeploy = this.autoDeploy; >- this.autoDeploy = autoDeploy; >- support.firePropertyChange("autoDeploy", oldAutoDeploy, >- this.autoDeploy); >- >- } >- >- >- /** >- * Return the Java class name of the context configuration class >- * for new web applications. >- */ >- @Override >- public String getConfigClass() { >- >- return (this.configClass); >- >- } >- >- >- /** >- * Set the Java class name of the context configuration class >- * for new web applications. >- * >- * @param configClass The new context configuration class >- */ >- @Override >- public void setConfigClass(String configClass) { >- >- String oldConfigClass = this.configClass; >- this.configClass = configClass; >- support.firePropertyChange("configClass", >- oldConfigClass, this.configClass); >- >- } >- >- >- /** >- * Return the Java class name of the Context implementation class >- * for new web applications. >- */ >- public String getContextClass() { >- >- return (this.contextClass); >- >- } >- >- >- /** >- * Set the Java class name of the Context implementation class >- * for new web applications. >- * >- * @param contextClass The new context implementation class >- */ >- public void setContextClass(String contextClass) { >- >- String oldContextClass = this.contextClass; >- this.contextClass = contextClass; >- support.firePropertyChange("contextClass", >- oldContextClass, this.contextClass); >- >- } >- >- >- /** >- * Return the value of the deploy on startup flag. If true, it indicates >- * that this host's child webapps should be discovered and automatically >- * deployed at startup time. >- */ >- @Override >- public boolean getDeployOnStartup() { >- >- return (this.deployOnStartup); >- >- } >- >- >- /** >- * Set the deploy on startup flag value for this host. >- * >- * @param deployOnStartup The new deploy on startup flag >- */ >- @Override >- public void setDeployOnStartup(boolean deployOnStartup) { >- >- boolean oldDeployOnStartup = this.deployOnStartup; >- this.deployOnStartup = deployOnStartup; >- support.firePropertyChange("deployOnStartup", oldDeployOnStartup, >- this.deployOnStartup); >- >- } >- >- >- /** >- * Deploy XML Context config files flag accessor. >- */ >- public boolean isDeployXML() { >- >- return (deployXML); >- >- } >- >- >- /** >- * Deploy XML Context config files flag mutator. >- */ >- public void setDeployXML(boolean deployXML) { >- >- this.deployXML = deployXML; >- >- } >- >- >- /** >- * Return the copy XML config file flag for this component. >- */ >- public boolean isCopyXML() { >- >- return (this.copyXML); >- >- } >- >- >- /** >- * Set the copy XML config file flag for this component. >- * >- * @param copyXML The new copy XML flag >- */ >- public void setCopyXML(boolean copyXML) { >- >- this.copyXML= copyXML; >- >- } >- >- >- /** >- * Return the Java class name of the error report valve class >- * for new web applications. >- */ >- public String getErrorReportValveClass() { >- >- return (this.errorReportValveClass); >- >- } >- >- >- /** >- * Set the Java class name of the error report valve class >- * for new web applications. >- * >- * @param errorReportValveClass The new error report valve class >- */ >- public void setErrorReportValveClass(String errorReportValveClass) { >- >- String oldErrorReportValveClassClass = this.errorReportValveClass; >- this.errorReportValveClass = errorReportValveClass; >- support.firePropertyChange("errorReportValveClass", >- oldErrorReportValveClassClass, >- this.errorReportValveClass); >- >- } >- >- >- /** >- * Return the canonical, fully qualified, name of the virtual host >- * this Container represents. >- */ >- @Override >- public String getName() { >- >- return (name); >- >- } >- >- >- /** >- * Set the canonical, fully qualified, name of the virtual host >- * this Container represents. >- * >- * @param name Virtual host name >- * >- * @exception IllegalArgumentException if name is null >- */ >- @Override >- public void setName(String name) { >- >- if (name == null) >- throw new IllegalArgumentException >- (sm.getString("standardHost.nullName")); >- >- name = name.toLowerCase(Locale.ENGLISH); // Internally all names are lower case >- >- String oldName = this.name; >- this.name = name; >- support.firePropertyChange("name", oldName, this.name); >- >- } >- >- >- /** >- * Unpack WARs flag accessor. >- */ >- public boolean isUnpackWARs() { >- >- return (unpackWARs); >- >- } >- >- >- /** >- * Unpack WARs flag mutator. >- */ >- public void setUnpackWARs(boolean unpackWARs) { >- >- this.unpackWARs = unpackWARs; >- >- } >- >- >- /** >- * Host work directory base. >- */ >- public String getWorkDir() { >- >- return (workDir); >- } >- >- >- /** >- * Host work directory base. >- */ >- public void setWorkDir(String workDir) { >- >- this.workDir = workDir; >- } >- >- >- /** >- * Return the regular expression that defines the files and directories in >- * the host's {@link #appBase} that will be ignored by the automatic >- * deployment process. >- */ >- @Override >- public String getDeployIgnore() { >- if (deployIgnore == null) { >- return null; >- } >- return this.deployIgnore.toString(); >- } >- >- >- /** >- * Return the compiled regular expression that defines the files and >- * directories in the host's {@link #appBase} that will be ignored by the >- * automatic deployment process. >- */ >- @Override >- public Pattern getDeployIgnorePattern() { >- return this.deployIgnore; >- } >- >- >- /** >- * Set the regular expression that defines the files and directories in >- * the host's {@link #appBase} that will be ignored by the automatic >- * deployment process. >- */ >- @Override >- public void setDeployIgnore(String deployIgnore) { >- String oldDeployIgnore; >- if (this.deployIgnore == null) { >- oldDeployIgnore = null; >- } else { >- oldDeployIgnore = this.deployIgnore.toString(); >- } >- if (deployIgnore == null) { >- this.deployIgnore = null; >- } else { >- this.deployIgnore = Pattern.compile(deployIgnore); >- } >- support.firePropertyChange("deployIgnore", >- oldDeployIgnore, >- deployIgnore); >- } >- >- >- // --------------------------------------------------------- Public Methods >- >- >- /** >- * Add an alias name that should be mapped to this same Host. >- * >- * @param alias The alias to be added >- */ >- @Override >- public void addAlias(String alias) { >- >- alias = alias.toLowerCase(Locale.ENGLISH); >- >- synchronized (aliasesLock) { >- // Skip duplicate aliases >- for (int i = 0; i < aliases.length; i++) { >- if (aliases[i].equals(alias)) >- return; >- } >- // Add this alias to the list >- String newAliases[] = new String[aliases.length + 1]; >- for (int i = 0; i < aliases.length; i++) >- newAliases[i] = aliases[i]; >- newAliases[aliases.length] = alias; >- aliases = newAliases; >- } >- // Inform interested listeners >- fireContainerEvent(ADD_ALIAS_EVENT, alias); >- >- } >- >- >- /** >- * Add a child Container, only if the proposed child is an implementation >- * of Context. >- * >- * @param child Child container to be added >- */ >- @Override >- public void addChild(Container child) { >- >- child.addLifecycleListener(new MemoryLeakTrackingListener()); >- >- if (!(child instanceof Context)) >- throw new IllegalArgumentException >- (sm.getString("standardHost.notContext")); >- super.addChild(child); >- >- } >- >- >- /** >- * Used to ensure the regardless of {@link Context} implementation, a record >- * is kept of the class loader used every time a context starts. >- */ >- private class MemoryLeakTrackingListener implements LifecycleListener { >- @Override >- public void lifecycleEvent(LifecycleEvent event) { >- if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) { >- if (event.getSource() instanceof Context) { >- Context context = ((Context) event.getSource()); >- childClassLoaders.put(context.getLoader().getClassLoader(), >- context.getServletContext().getContextPath()); >- } >- } >- } >- } >- >- >- /** >- * Attempt to identify the contexts that have a class loader memory leak. >- * This is usually triggered on context reload. Note: This method attempts >- * to force a full garbage collection. This should be used with extreme >- * caution on a production system. >- */ >- public String[] findReloadedContextMemoryLeaks() { >- >- System.gc(); >- >- List<String> result = new ArrayList<String>(); >- >- for (Map.Entry<ClassLoader, String> entry : >- childClassLoaders.entrySet()) { >- ClassLoader cl = entry.getKey(); >- if (cl instanceof WebappClassLoader) { >- if (!((WebappClassLoader) cl).isStarted()) { >- result.add(entry.getValue()); >- } >- } >- } >- >- return result.toArray(new String[result.size()]); >- } >- >- /** >- * Return the set of alias names for this Host. If none are defined, >- * a zero length array is returned. >- */ >- @Override >- public String[] findAliases() { >- >- synchronized (aliasesLock) { >- return (this.aliases); >- } >- >- } >- >- >- /** >- * Return descriptive information about this Container implementation and >- * the corresponding version number, in the format >- * <code><description>/<version></code>. >- */ >- @Override >- public String getInfo() { >- >- return (info); >- >- } >- >- >- /** >- * Remove the specified alias name from the aliases for this Host. >- * >- * @param alias Alias name to be removed >- */ >- @Override >- public void removeAlias(String alias) { >- >- alias = alias.toLowerCase(Locale.ENGLISH); >- >- synchronized (aliasesLock) { >- >- // Make sure this alias is currently present >- int n = -1; >- for (int i = 0; i < aliases.length; i++) { >- if (aliases[i].equals(alias)) { >- n = i; >- break; >- } >- } >- if (n < 0) >- return; >- >- // Remove the specified alias >- int j = 0; >- String results[] = new String[aliases.length - 1]; >- for (int i = 0; i < aliases.length; i++) { >- if (i != n) >- results[j++] = aliases[i]; >- } >- aliases = results; >- >- } >- >- // Inform interested listeners >- fireContainerEvent(REMOVE_ALIAS_EVENT, alias); >- >- } >- >- >- /** >- * 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("StandardHost["); >- sb.append(getName()); >- sb.append("]"); >- return (sb.toString()); >- >- } >- >- /** >- * 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 { >- >- // Set error report valve >- String errorValve = getErrorReportValveClass(); >- if ((errorValve != null) && (!errorValve.equals(""))) { >- try { >- boolean found = false; >- Valve[] valves = getPipeline().getValves(); >- for (Valve valve : valves) { >- if (errorValve.equals(valve.getClass().getName())) { >- found = true; >- break; >- } >- } >- if(!found) { >- Valve valve = >- (Valve) Class.forName(errorValve).newInstance(); >- getPipeline().addValve(valve); >- } >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- log.error(sm.getString( >- "standardHost.invalidErrorReportValveClass", >- errorValve), t); >- } >- } >- super.startInternal(); >- } >- >- >- // -------------------- JMX -------------------- >- /** >- * Return the MBean Names of the Valves associated with this Host >- * >- * @exception Exception if an MBean cannot be created or registered >- */ >- public String [] getValveNames() >- throws Exception >- { >- Valve [] valves = this.getPipeline().getValves(); >- String [] mbeanNames = new String[valves.length]; >- for (int i = 0; i < valves.length; i++) { >- if( valves[i] == null ) continue; >- if( ((ValveBase)valves[i]).getObjectName() == null ) continue; >- mbeanNames[i] = ((ValveBase)valves[i]).getObjectName().toString(); >- } >- >- return mbeanNames; >- >- } >- >- public String[] getAliases() { >- synchronized (aliasesLock) { >- return aliases; >- } >- } >- >- @Override >- protected String getObjectNameKeyProperties() { >- >- StringBuilder keyProperties = new StringBuilder("type=Host"); >- keyProperties.append(MBeanUtils.getContainerKeyProperties(this)); >- >- return keyProperties.toString(); >- } >- >-} >+/* >+ * 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.util.ArrayList; >+import java.util.List; >+import java.util.Locale; >+import java.util.Map; >+import java.util.WeakHashMap; >+import java.util.concurrent.ExecutorService; >+import java.util.regex.Pattern; >+ >+import org.apache.catalina.Container; >+import org.apache.catalina.Context; >+import org.apache.catalina.Globals; >+import org.apache.catalina.Host; >+import org.apache.catalina.Lifecycle; >+import org.apache.catalina.LifecycleEvent; >+import org.apache.catalina.LifecycleException; >+import org.apache.catalina.LifecycleListener; >+import org.apache.catalina.Valve; >+import org.apache.catalina.loader.WebappClassLoader; >+import org.apache.catalina.mbeans.MBeanUtils; >+import org.apache.catalina.valves.ValveBase; >+import org.apache.tomcat.util.ExceptionUtils; >+ >+ >+/** >+ * Standard implementation of the <b>Host</b> interface. Each >+ * child container must be a Context implementation to process the >+ * requests directed to a particular web application. >+ * >+ * @author Craig R. McClanahan >+ * @author Remy Maucherat >+ * @version $Id$ >+ */ >+ >+public class StandardHost extends ContainerBase implements Host { >+ >+ private static final org.apache.juli.logging.Log log= >+ org.apache.juli.logging.LogFactory.getLog( StandardHost.class ); >+ >+ // ----------------------------------------------------------- Constructors >+ >+ >+ /** >+ * Create a new StandardHost component with the default basic Valve. >+ */ >+ public StandardHost() { >+ >+ super(); >+ pipeline.setBasic(new StandardHostValve()); >+ >+ } >+ >+ >+ // ----------------------------------------------------- Instance Variables >+ >+ >+ /** >+ * The set of aliases for this Host. >+ */ >+ private String[] aliases = new String[0]; >+ >+ private final Object aliasesLock = new Object(); >+ >+ >+ /** >+ * The application root for this Host. >+ */ >+ private String appBase = "webapps"; >+ private volatile File appBaseFile = null; >+ >+ /** >+ * The XML root for this Host. >+ */ >+ private String xmlBase = null; >+ >+ /** >+ * The auto deploy flag for this Host. >+ */ >+ private boolean autoDeploy = true; >+ >+ >+ /** >+ * The Java class name of the default context configuration class >+ * for deployed web applications. >+ */ >+ private String configClass = >+ "org.apache.catalina.startup.ContextConfig"; >+ >+ >+ /** >+ * The Java class name of the default Context implementation class for >+ * deployed web applications. >+ */ >+ private String contextClass = >+ "org.apache.catalina.core.StandardContext"; >+ >+ >+ /** >+ * The deploy on startup flag for this Host. >+ */ >+ private boolean deployOnStartup = true; >+ >+ >+ /** >+ * deploy Context XML config files property. >+ */ >+ private boolean deployXML = true; >+ >+ >+ /** >+ * Should XML files be copied to $CATALINA_BASE/conf/<engine>/<host> by >+ * default when a web application is deployed? >+ */ >+ private boolean copyXML = false; >+ >+ >+ /** >+ * The Java class name of the default error reporter implementation class >+ * for deployed web applications. >+ */ >+ private String errorReportValveClass = >+ "org.apache.catalina.valves.ErrorReportValve"; >+ >+ /** >+ * The descriptive information string for this implementation. >+ */ >+ private static final String info = >+ "org.apache.catalina.core.StandardHost/1.0"; >+ >+ >+ /** >+ * Unpack WARs property. >+ */ >+ private boolean unpackWARs = true; >+ >+ >+ /** >+ * Work Directory base for applications. >+ */ >+ private String workDir = null; >+ >+ >+ /** >+ * Should we create directories upon startup for appBase and xmlBase >+ */ >+ private boolean createDirs = true; >+ >+ >+ /** >+ * Track the class loaders for the child web applications so memory leaks >+ * can be detected. >+ */ >+ private Map<ClassLoader, String> childClassLoaders = >+ new WeakHashMap<ClassLoader, String>(); >+ >+ >+ /** >+ * Any file or directory in {@link #appBase} that this pattern matches will >+ * be ignored by the automatic deployment process (both >+ * {@link #deployOnStartup} and {@link #autoDeploy}). >+ */ >+ private Pattern deployIgnore = null; >+ >+ >+ // ------------------------------------------------------------- Properties >+ >+ @Override >+ public ExecutorService getStartStopExecutor() { >+ return startStopExecutor; >+ } >+ >+ >+ /** >+ * Return the application root for this Host. This can be an absolute >+ * pathname, a relative pathname, or a URL. >+ */ >+ @Override >+ public String getAppBase() { >+ return (this.appBase); >+ } >+ >+ >+ /** >+ * ({@inheritDoc} >+ */ >+ @Override >+ public File getAppBaseFile() { >+ >+ if (appBaseFile != null) { >+ return appBaseFile; >+ } >+ >+ File file = new File(getAppBase()); >+ >+ // If not absolute, make it absolute >+ if (!file.isAbsolute()) { >+ // This system property should always be set >+ file = new File(System.getProperty(Globals.CATALINA_BASE_PROP), >+ file.getPath()); >+ } >+ >+ // Make it canonical if possible >+ try { >+ file = file.getCanonicalFile(); >+ } catch (IOException ioe) { >+ // Ignore >+ } >+ >+ this.appBaseFile = file; >+ return file; >+ } >+ >+ >+ /** >+ * Set the application root for this Host. This can be an absolute >+ * pathname, a relative pathname, or a URL. >+ * >+ * @param appBase The new application root >+ */ >+ @Override >+ public void setAppBase(String appBase) { >+ >+ String oldAppBase = this.appBase; >+ this.appBase = appBase; >+ support.firePropertyChange("appBase", oldAppBase, this.appBase); >+ this.appBaseFile = null; >+ } >+ >+ >+ /** >+ * Return the XML root for this Host. This can be an absolute >+ * pathname, a relative pathname, or a URL. >+ * If null, defaults to ${catalina.base}/conf/ directory >+ */ >+ @Override >+ public String getXmlBase() { >+ >+ return (this.xmlBase); >+ >+ } >+ >+ >+ /** >+ * Set the Xml root for this Host. This can be an absolute >+ * pathname, a relative pathname, or a URL. >+ * If null, defaults to ${catalina.base}/conf/ directory >+ * >+ * @param xmlBase The new XML root >+ */ >+ @Override >+ public void setXmlBase(String xmlBase) { >+ >+ String oldXmlBase = this.xmlBase; >+ this.xmlBase = xmlBase; >+ support.firePropertyChange("xmlBase", oldXmlBase, this.xmlBase); >+ >+ } >+ >+ >+ /** >+ * Returns true if the Host will attempt to create directories for appBase and xmlBase >+ * unless they already exist. >+ */ >+ @Override >+ public boolean getCreateDirs() { >+ return createDirs; >+ } >+ >+ /** >+ * Set to true if the Host should attempt to create directories for xmlBase and appBase upon startup >+ * @param createDirs >+ */ >+ @Override >+ public void setCreateDirs(boolean createDirs) { >+ this.createDirs = createDirs; >+ } >+ >+ /** >+ * Return the value of the auto deploy flag. If true, it indicates that >+ * this host's child webapps will be dynamically deployed. >+ */ >+ @Override >+ public boolean getAutoDeploy() { >+ >+ return (this.autoDeploy); >+ >+ } >+ >+ >+ /** >+ * Set the auto deploy flag value for this host. >+ * >+ * @param autoDeploy The new auto deploy flag >+ */ >+ @Override >+ public void setAutoDeploy(boolean autoDeploy) { >+ >+ boolean oldAutoDeploy = this.autoDeploy; >+ this.autoDeploy = autoDeploy; >+ support.firePropertyChange("autoDeploy", oldAutoDeploy, >+ this.autoDeploy); >+ >+ } >+ >+ >+ /** >+ * Return the Java class name of the context configuration class >+ * for new web applications. >+ */ >+ @Override >+ public String getConfigClass() { >+ >+ return (this.configClass); >+ >+ } >+ >+ >+ /** >+ * Set the Java class name of the context configuration class >+ * for new web applications. >+ * >+ * @param configClass The new context configuration class >+ */ >+ @Override >+ public void setConfigClass(String configClass) { >+ >+ String oldConfigClass = this.configClass; >+ this.configClass = configClass; >+ support.firePropertyChange("configClass", >+ oldConfigClass, this.configClass); >+ >+ } >+ >+ >+ /** >+ * Return the Java class name of the Context implementation class >+ * for new web applications. >+ */ >+ public String getContextClass() { >+ >+ return (this.contextClass); >+ >+ } >+ >+ >+ /** >+ * Set the Java class name of the Context implementation class >+ * for new web applications. >+ * >+ * @param contextClass The new context implementation class >+ */ >+ public void setContextClass(String contextClass) { >+ >+ String oldContextClass = this.contextClass; >+ this.contextClass = contextClass; >+ support.firePropertyChange("contextClass", >+ oldContextClass, this.contextClass); >+ >+ } >+ >+ >+ /** >+ * Return the value of the deploy on startup flag. If true, it indicates >+ * that this host's child webapps should be discovered and automatically >+ * deployed at startup time. >+ */ >+ @Override >+ public boolean getDeployOnStartup() { >+ >+ return (this.deployOnStartup); >+ >+ } >+ >+ >+ /** >+ * Set the deploy on startup flag value for this host. >+ * >+ * @param deployOnStartup The new deploy on startup flag >+ */ >+ @Override >+ public void setDeployOnStartup(boolean deployOnStartup) { >+ >+ boolean oldDeployOnStartup = this.deployOnStartup; >+ this.deployOnStartup = deployOnStartup; >+ support.firePropertyChange("deployOnStartup", oldDeployOnStartup, >+ this.deployOnStartup); >+ >+ } >+ >+ >+ /** >+ * Deploy XML Context config files flag accessor. >+ */ >+ public boolean isDeployXML() { >+ >+ return (deployXML); >+ >+ } >+ >+ >+ /** >+ * Deploy XML Context config files flag mutator. >+ */ >+ public void setDeployXML(boolean deployXML) { >+ >+ this.deployXML = deployXML; >+ >+ } >+ >+ >+ /** >+ * Return the copy XML config file flag for this component. >+ */ >+ public boolean isCopyXML() { >+ >+ return (this.copyXML); >+ >+ } >+ >+ >+ /** >+ * Set the copy XML config file flag for this component. >+ * >+ * @param copyXML The new copy XML flag >+ */ >+ public void setCopyXML(boolean copyXML) { >+ >+ this.copyXML= copyXML; >+ >+ } >+ >+ >+ /** >+ * Return the Java class name of the error report valve class >+ * for new web applications. >+ */ >+ public String getErrorReportValveClass() { >+ >+ return (this.errorReportValveClass); >+ >+ } >+ >+ >+ /** >+ * Set the Java class name of the error report valve class >+ * for new web applications. >+ * >+ * @param errorReportValveClass The new error report valve class >+ */ >+ public void setErrorReportValveClass(String errorReportValveClass) { >+ >+ String oldErrorReportValveClassClass = this.errorReportValveClass; >+ this.errorReportValveClass = errorReportValveClass; >+ support.firePropertyChange("errorReportValveClass", >+ oldErrorReportValveClassClass, >+ this.errorReportValveClass); >+ >+ } >+ >+ >+ /** >+ * Return the canonical, fully qualified, name of the virtual host >+ * this Container represents. >+ */ >+ @Override >+ public String getName() { >+ >+ return (name); >+ >+ } >+ >+ >+ /** >+ * Set the canonical, fully qualified, name of the virtual host >+ * this Container represents. >+ * >+ * @param name Virtual host name >+ * >+ * @exception IllegalArgumentException if name is null >+ */ >+ @Override >+ public void setName(String name) { >+ >+ if (name == null) >+ throw new IllegalArgumentException >+ (sm.getString("standardHost.nullName")); >+ >+ name = name.toLowerCase(Locale.ENGLISH); // Internally all names are lower case >+ >+ String oldName = this.name; >+ this.name = name; >+ support.firePropertyChange("name", oldName, this.name); >+ >+ } >+ >+ >+ /** >+ * Unpack WARs flag accessor. >+ */ >+ public boolean isUnpackWARs() { >+ >+ return (unpackWARs); >+ >+ } >+ >+ >+ /** >+ * Unpack WARs flag mutator. >+ */ >+ public void setUnpackWARs(boolean unpackWARs) { >+ >+ this.unpackWARs = unpackWARs; >+ >+ } >+ >+ >+ /** >+ * Host work directory base. >+ */ >+ public String getWorkDir() { >+ >+ return (workDir); >+ } >+ >+ >+ /** >+ * Host work directory base. >+ */ >+ public void setWorkDir(String workDir) { >+ >+ this.workDir = workDir; >+ } >+ >+ >+ /** >+ * Return the regular expression that defines the files and directories in >+ * the host's {@link #appBase} that will be ignored by the automatic >+ * deployment process. >+ */ >+ @Override >+ public String getDeployIgnore() { >+ if (deployIgnore == null) { >+ return null; >+ } >+ return this.deployIgnore.toString(); >+ } >+ >+ >+ /** >+ * Return the compiled regular expression that defines the files and >+ * directories in the host's {@link #appBase} that will be ignored by the >+ * automatic deployment process. >+ */ >+ @Override >+ public Pattern getDeployIgnorePattern() { >+ return this.deployIgnore; >+ } >+ >+ >+ /** >+ * Set the regular expression that defines the files and directories in >+ * the host's {@link #appBase} that will be ignored by the automatic >+ * deployment process. >+ */ >+ @Override >+ public void setDeployIgnore(String deployIgnore) { >+ String oldDeployIgnore; >+ if (this.deployIgnore == null) { >+ oldDeployIgnore = null; >+ } else { >+ oldDeployIgnore = this.deployIgnore.toString(); >+ } >+ if (deployIgnore == null) { >+ this.deployIgnore = null; >+ } else { >+ this.deployIgnore = Pattern.compile(deployIgnore); >+ } >+ support.firePropertyChange("deployIgnore", >+ oldDeployIgnore, >+ deployIgnore); >+ } >+ >+ >+ // --------------------------------------------------------- Public Methods >+ >+ >+ /** >+ * Add an alias name that should be mapped to this same Host. >+ * >+ * @param alias The alias to be added >+ */ >+ @Override >+ public void addAlias(String alias) { >+ >+ alias = alias.toLowerCase(Locale.ENGLISH); >+ >+ synchronized (aliasesLock) { >+ // Skip duplicate aliases >+ for (int i = 0; i < aliases.length; i++) { >+ if (aliases[i].equals(alias)) >+ return; >+ } >+ // Add this alias to the list >+ String newAliases[] = new String[aliases.length + 1]; >+ for (int i = 0; i < aliases.length; i++) >+ newAliases[i] = aliases[i]; >+ newAliases[aliases.length] = alias; >+ aliases = newAliases; >+ } >+ // Inform interested listeners >+ fireContainerEvent(ADD_ALIAS_EVENT, alias); >+ >+ } >+ >+ >+ /** >+ * Add a child Container, only if the proposed child is an implementation >+ * of Context. >+ * >+ * @param child Child container to be added >+ */ >+ @Override >+ public void addChild(Container child) { >+ >+ child.addLifecycleListener(new MemoryLeakTrackingListener()); >+ >+ if (!(child instanceof Context)) >+ throw new IllegalArgumentException >+ (sm.getString("standardHost.notContext")); >+ super.addChild(child); >+ >+ } >+ >+ >+ /** >+ * Used to ensure the regardless of {@link Context} implementation, a record >+ * is kept of the class loader used every time a context starts. >+ */ >+ private class MemoryLeakTrackingListener implements LifecycleListener { >+ @Override >+ public void lifecycleEvent(LifecycleEvent event) { >+ if (event.getType().equals(Lifecycle.AFTER_START_EVENT)) { >+ if (event.getSource() instanceof Context) { >+ Context context = ((Context) event.getSource()); >+ childClassLoaders.put(context.getLoader().getClassLoader(), >+ context.getServletContext().getContextPath()); >+ } >+ } >+ } >+ } >+ >+ >+ /** >+ * Attempt to identify the contexts that have a class loader memory leak. >+ * This is usually triggered on context reload. Note: This method attempts >+ * to force a full garbage collection. This should be used with extreme >+ * caution on a production system. >+ */ >+ public String[] findReloadedContextMemoryLeaks() { >+ >+ System.gc(); >+ >+ List<String> result = new ArrayList<String>(); >+ >+ for (Map.Entry<ClassLoader, String> entry : >+ childClassLoaders.entrySet()) { >+ ClassLoader cl = entry.getKey(); >+ if (cl instanceof WebappClassLoader) { >+ if (!((WebappClassLoader) cl).isStarted()) { >+ result.add(entry.getValue()); >+ } >+ } >+ } >+ >+ return result.toArray(new String[result.size()]); >+ } >+ >+ /** >+ * Return the set of alias names for this Host. If none are defined, >+ * a zero length array is returned. >+ */ >+ @Override >+ public String[] findAliases() { >+ >+ synchronized (aliasesLock) { >+ return (this.aliases); >+ } >+ >+ } >+ >+ >+ /** >+ * Return descriptive information about this Container implementation and >+ * the corresponding version number, in the format >+ * <code><description>/<version></code>. >+ */ >+ @Override >+ public String getInfo() { >+ >+ return (info); >+ >+ } >+ >+ >+ /** >+ * Remove the specified alias name from the aliases for this Host. >+ * >+ * @param alias Alias name to be removed >+ */ >+ @Override >+ public void removeAlias(String alias) { >+ >+ alias = alias.toLowerCase(Locale.ENGLISH); >+ >+ synchronized (aliasesLock) { >+ >+ // Make sure this alias is currently present >+ int n = -1; >+ for (int i = 0; i < aliases.length; i++) { >+ if (aliases[i].equals(alias)) { >+ n = i; >+ break; >+ } >+ } >+ if (n < 0) >+ return; >+ >+ // Remove the specified alias >+ int j = 0; >+ String results[] = new String[aliases.length - 1]; >+ for (int i = 0; i < aliases.length; i++) { >+ if (i != n) >+ results[j++] = aliases[i]; >+ } >+ aliases = results; >+ >+ } >+ >+ // Inform interested listeners >+ fireContainerEvent(REMOVE_ALIAS_EVENT, alias); >+ >+ } >+ >+ >+ /** >+ * 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("StandardHost["); >+ sb.append(getName()); >+ sb.append("]"); >+ return (sb.toString()); >+ >+ } >+ >+ /** >+ * 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 { >+ >+ // Set error report valve >+ String errorValve = getErrorReportValveClass(); >+ if ((errorValve != null) && (!errorValve.equals(""))) { >+ try { >+ boolean found = false; >+ Valve[] valves = getPipeline().getValves(); >+ for (Valve valve : valves) { >+ if (errorValve.equals(valve.getClass().getName())) { >+ found = true; >+ break; >+ } >+ } >+ if(!found) { >+ Valve valve = >+ (Valve) Class.forName(errorValve).newInstance(); >+ getPipeline().addValve(valve); >+ } >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ log.error(sm.getString( >+ "standardHost.invalidErrorReportValveClass", >+ errorValve), t); >+ } >+ } >+ super.startInternal(); >+ } >+ >+ >+ // -------------------- JMX -------------------- >+ /** >+ * Return the MBean Names of the Valves associated with this Host >+ * >+ * @exception Exception if an MBean cannot be created or registered >+ */ >+ public String [] getValveNames() >+ throws Exception >+ { >+ Valve [] valves = this.getPipeline().getValves(); >+ String [] mbeanNames = new String[valves.length]; >+ for (int i = 0; i < valves.length; i++) { >+ if( valves[i] == null ) continue; >+ if( ((ValveBase)valves[i]).getObjectName() == null ) continue; >+ mbeanNames[i] = ((ValveBase)valves[i]).getObjectName().toString(); >+ } >+ >+ return mbeanNames; >+ >+ } >+ >+ public String[] getAliases() { >+ synchronized (aliasesLock) { >+ return aliases; >+ } >+ } >+ >+ @Override >+ protected String getObjectNameKeyProperties() { >+ >+ StringBuilder keyProperties = new StringBuilder("type=Host"); >+ keyProperties.append(MBeanUtils.getContainerKeyProperties(this)); >+ >+ return keyProperties.toString(); >+ } >+ >+} >diff --git a/java/org/apache/catalina/core/mbeans-descriptors.xml b/java/org/apache/catalina/core/mbeans-descriptors.xml >index b9253c2..426e2e2 100644 >--- a/java/org/apache/catalina/core/mbeans-descriptors.xml >+++ b/java/org/apache/catalina/core/mbeans-descriptors.xml >@@ -1,1843 +1,1851 @@ >-<?xml version="1.0"?> >-<!-- >- 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. >---> >-<mbeans-descriptors> >- >- <mbean name="ApplicationFilterConfig" >- description="Wrapper that represents an individual servlet-filter definition" >- domain="Catalina" >- group="Filter" >- type="org.apache.catalina.core.ApplicationFilterConfig"> >- >- <attribute name="filterName" >- description="The name used to reference the filter in web.xml" >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="filterClass" >- description="Fully qualified class name of the filter object" >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="filterInitParameterMap" >- description="Return the initiaization parameters associated with this filter" >- type="java.util.Map" >- writeable="false" /> >- >- </mbean> >- >- <mbean name="NamingContextListener" >- description="Helper class used to initialize and populate the JNDI context associated with each context and server" >- domain="Catalina" >- group="Listener" >- type="org.apache.catalina.core.NamingContextListener"> >- >- <attribute name="className" >- description="Fully qualified class name of the managed object" >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="name" >- description="Name of the associated naming context" >- type="java.lang.String" >- writeable="false"/> >- >- </mbean> >- >- <mbean name="StandardContext" >- description="Standard Context Component" >- domain="Catalina" >- group="Context" >- type="org.apache.catalina.core.StandardContext" >- className="org.apache.catalina.mbeans.ContextMBean"> >- >- <attribute name="allowLinking" >- description="Allow symlinking to outside the webapp root directory, if the webapp is an exploded directory" >- is="true" >- type="boolean"/> >- >- <attribute name="aliases" >- description="List of resource aliases" >- type="java.lang.String" /> >- >- <attribute name="altDDName" >- description="The alternate deployment descriptor name." >- type="java.lang.String" /> >- >- <attribute name="antiJARLocking" >- description="Take care to not lock jar files" >- type="boolean" /> >- >- <attribute name="antiResourceLocking" >- description="Take care to not lock resources" >- type="boolean" /> >- >- <attribute name="baseName" >- description="The base name used for directories, WAR files (with .war appended) and context.xml files (with .xml appended)." >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="cacheMaxSize" >- description="Maximum cache size in KB" >- type="int"/> >- >- <attribute name="cacheObjectMaxSize" >- description="Maximum cached object size in KB" >- type="int"/> >- >- <attribute name="cacheTTL" >- description="Time interval in ms between cache refeshes" >- type="int"/> >- >- <attribute name="cachingAllowed" >- description="Should we cache static resources for this webapp" >- is="true" >- type="boolean"/> >- >- <attribute name="children" >- description="Object names of all children" >- type="[Ljavax.management.ObjectName;"/> >- >- <attribute name="clearReferencesStatic" >- description="Should Tomcat attempt to null out any static or final fields from loaded classes when a web application is stopped as a work around for apparent garbage collection bugs and application coding errors?" >- type="boolean"/> >- >- <attribute name="clearReferencesStopThreads" >- description="Should Tomcat attempt to terminate threads that have been started by the web application? Advisable to be used only in a development environment." >- type="boolean"/> >- >- <attribute name="clearReferencesStopTimerThreads" >- description="Should Tomcat attempt to terminate TimerThreads that have been started by the web application? Advisable to be used only in a development environment." >- type="boolean"/> >- >- <attribute name="configFile" >- description="Location of the context.xml resource or file" >- type="java.net.URL"/> >- >- <attribute name="configured" >- description="The correctly configured flag for this Context." >- type="boolean" >- writeable="false" /> >- >- <attribute name="cookies" >- description="Should we attempt to use cookies for session id communication?" >- type="boolean"/> >- >- <attribute name="compilerClasspath" >- description="The compiler classpath to use" >- type="java.lang.String"/> >- >- <attribute name="crossContext" >- description="Should we allow the ServletContext.getContext() method to access the context of other web applications in this server?" >- type="boolean"/> >- >- <attribute name="defaultContextXml" >- description="Location of the default context.xml resource or file" >- type="java.lang.String"/> >- >- <attribute name="defaultWebXml" >- description="Location of the default web.xml resource or file" >- type="java.lang.String"/> >- >- <attribute name="delegate" >- description="" >- type="boolean"/> >- >- <attribute name="deploymentDescriptor" >- description="String deployment descriptor " >- type="java.lang.String" >- writeable="false" /> >- >- <attribute name="displayName" >- description="The display name of this web application" >- type="java.lang.String"/> >- >- <attribute name="distributable" >- description="The distributable flag for this web application." >- type="boolean"/> >- >- <attribute name="docBase" >- description="The document root for this web application" >- type="java.lang.String"/> >- >- <attribute name="encodedPath" >- description="The encoded path" >- type="java.lang.String" >- writeable="false" /> >- >- <attribute name="eventProvider" >- description="Event provider support for this managed object" >- is="true" >- type="boolean" >- writeable="false" /> >- >- <attribute name="ignoreAnnotations" >- description="Ignore annotations flag." >- type="boolean" /> >- >- <attribute name="instanceManager" >- description="Object that creates and destroys servlets, filters, and listeners. Include dependency injection and postConstruct/preDestory handling" >- type="org.apache.catalina.instanceManagement.InstanceManager" /> >- >- <attribute name="javaVMs" >- description="The Java virtual machines on which this module is running" >- type="[Ljava.lang.String;"/> >- >- <attribute name="loader" >- description="Associated loader." >- type="org.apache.catalina.Loader" /> >- >- <attribute name="logEffectiveWebXml" >- description="Should the effective web.xml be logged when the context starts?" >- type="boolean" /> >- >- <attribute name="logger" >- description="Associated logger." >- type="org.apache.commons.logging.Log" /> >- >- <attribute name="managedResource" >- description="The managed resource this MBean is associated with" >- type="java.lang.Object"/> >- >- <attribute name="manager" >- description="Associated manager." >- type="org.apache.catalina.Manager" /> >- >- <attribute name="mappingObject" >- description="The object used for mapping" >- type="java.lang.Object"/> >- >- <attribute name="namingContextListener" >- description="Associated naming context listener." >- type="org.apache.catalina.core.NamingContextListener" /> >- >- <attribute name="objectName" >- description="Name of the object" >- type="java.lang.String" >- writeable="false" /> >- >- <attribute name="originalDocBase" >- description="The original document root for this web application" >- type="java.lang.String" /> >- >- <attribute name="override" >- description="The default context.xml override flag for this web application" >- type="boolean"/> >- >- <attribute name="name" >- description="The name of this Context" >- type="java.lang.String"/> >- >- <attribute name="parentClassLoader" >- description="Parent class loader." >- type="java.lang.ClassLoader" /> >- >- <attribute name="path" >- description="The context path for this Context" >- type="java.lang.String"/> >- >- <attribute name="paused" >- description="The request processing pause flag (while reloading occurs)" >- type="boolean" >- writeable="false" /> >- >- <attribute name="privileged" >- description="Access to tomcat internals" >- type="boolean"/> >- >- <attribute name="processingTime" >- description="Cumulative execution times of all servlets in this context" >- type="long" >- writeable="false" /> >- >- <attribute name="publicId" >- description="The public identifier of the DTD for the web application deployment descriptor version that is being parsed" >- type="java.lang.String" >- writeable="false" /> >- >- <attribute name="realm" >- description="Associated realm." >- type="org.apache.catalina.Realm" /> >- >- <attribute name="reloadable" >- description="The reloadable flag for this web application" >- type="boolean"/> >- >- <attribute name="renewThreadsWhenStoppingContext" >- description="Should Tomcat renew the threads of the thread pool when the application is stopped to avoid memory leaks because of uncleaned ThreadLocal variables." >- type="boolean"/> >- >- <attribute name="saveConfig" >- description="Should the configuration be written as needed on startup" >- is="true" >- type="boolean"/> >- >- <attribute name="server" >- description="The J2EE Server this module is deployed on" >- type="java.lang.String"/> >- >- <attribute name="servlets" >- description="JSR77 list of servlets" >- type="[Ljava.lang.String;" >- writeable="false"/> >- >- <attribute name="sessionCookieName" >- description="The name to use for session cookies.'null' indicates that the name is controlled by the application." >- type="java.lang.String"/> >- >- <attribute name="sessionCookieDomain" >- description="The domain to use for session cookies.'null' indicates that the domain is controlled by the application." >- type="java.lang.String"/> >- >- <attribute name="sessionCookiePath" >- description="The path to use for session cookies.'null' indicates that the path is controlled by the application." >- type="java.lang.String"/> >- >- <attribute name="sessionTimeout" >- description="The session timeout (in minutes) for this web application" >- type="int"/> >- >- <attribute name="startTime" >- description="Time (in milliseconds since January 1, 1970, 00:00:00) when this context was started" >- type="long" >- writeable="false" /> >- >- <attribute name="startupTime" >- description="Time (in milliseconds) it took to start this context" >- type="long"/> >- >- <attribute name="stateManageable" >- description="State management support for this managed object" >- is="true" >- type="boolean" >- writeable="false" /> >- >- <attribute name="stateName" >- description="The name of the LifecycleState that this component is currently in" >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="staticResources" >- description="Static resources associated with the context." >- type="javax.naming.directory.DirContext" >- writeable="false"/> >- >- <attribute name="statisticsProvider" >- description="Performance statistics support for this managed object" >- is="true" >- type="boolean" >- writeable="false" /> >- >- <attribute name="swallowOutput" >- description="Flag to set to cause the system.out and system.err to be redirected to the logger when executing a servlet" >- type="boolean"/> >- >- <attribute name="tldNamespaceAware" >- description="Should TLD XML namespace validation be turned on?" >- type="boolean"/> >- >- <attribute name="tldScanTime" >- description="Time spend scanning jars for TLDs for this context" >- type="long"/> >- >- <attribute name="tldValidation" >- description="Should TLD XML validation be turned on?" >- type="boolean"/> >- >- <attribute name="unloadDelay" >- description="Amount of ms that the container will wait for servlets to unload" >- type="long"/> >- >- <attribute name="unpackWAR" >- description="Unpack WAR property" >- type="boolean"/> >- >- <attribute name="useHttpOnly" >- description="Indicates that session cookies should use HttpOnly" >- type="boolean"/> >- >- <attribute name="useNaming" >- description="Create a JNDI naming context for this application?" >- is="true" >- type="boolean"/> >- >- <attribute name="webappVersion" >- description="The version of this web application - used in parallel deployment to differentiate different versions of the same web application" >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="welcomeFiles" >- description="The welcome files for this context" >- type="[Ljava.lang.String;" >- writeable="false"/> >- >- <attribute name="workDir" >- description="The pathname to the work directory for this context" >- type="java.lang.String"/> >- >- <attribute name="xmlValidation" >- description="Should XML validation be turned on?" >- type="boolean"/> >- >- <attribute name="xmlNamespaceAware" >- description="Should XML namespace validation be turned on?" >- type="boolean"/> >- >- <operation name="addApplicationListener" >- description="Add a new Listener class name to the set of Listeners configured for this application." >- impact="ACTION" >- returnType="void"> >- <parameter name="listener" >- description="Java class name of a listener class" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addApplicationParameter" >- description="Add a new application parameter for this application." >- impact="ACTION" >- returnType="void"> >- <parameter name="listener" >- description="Java class name of a listener class" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addChild" >- description="Add a child to this Context" >- impact="ACTION" >- returnType="void"> >- <parameter name="type" >- description="Type(classname) of the new child to be added" >- type="java.lang.String"/> >- <parameter name="name" >- description="Name of the child to be added" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addInstanceListener" >- description="Add the classname of an InstanceListener to be added to each Wrapper appended to this Context." >- impact="ACTION" >- returnType="void"> >- <parameter name="listener" >- description="Java class name of an InstanceListener class" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addLifecycleListener" >- description="Add a lifecycle listener to this Context" >- impact="ACTION" >- returnType="void"> >- <parameter name="type" >- description="Type(classname) of the new lifecycle listener to be added" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addLocaleEncodingMappingParameter" >- description="Add a Locale Encoding Mapping" >- impact="ACTION" >- returnType="void"> >- <parameter name="locale" >- description="Locale to map an encoding for" >- type="java.lang.String"/> >- <parameter name="encoding" >- description="Encoding to be used for a give locale" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addMimeMapping" >- description="Add a new MIME mapping, replacing any existing mapping for the specified extension." >- impact="ACTION" >- returnType="void"> >- <parameter name="extension" >- description="Filename extension being mapped" >- type="java.lang.String"/> >- <parameter name="mimeType" >- description="Corresponding MIME type" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addParameter" >- description="Add a new context initialization parameter, replacing any existing value for the specified name." >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="Name of the new parameter" >- type="java.lang.String"/> >- <parameter name="value" >- description="Value of the new parameter" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addRoleMapping" >- description="Add a security role reference for this web application." >- impact="ACTION" >- returnType="void"> >- <parameter name="role" >- description="Security role used in the application" >- type="java.lang.String"/> >- <parameter name="link" >- description="Actual security role to check for" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addSecurityRole" >- description="Add a new security role for this web application." >- impact="ACTION" >- returnType="void"> >- <parameter name="role" >- description="New security role" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addServletMapping" >- description="Add a new servlet mapping, replacing any existing mapping for the specified pattern." >- impact="ACTION" >- returnType="void"> >- <parameter name="pattern" >- description="URL pattern to be mapped" >- type="java.lang.String"/> >- <parameter name="name" >- description="Name of the corresponding servlet to execute" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addServletMapping" >- description="Add a new servlet mapping, replacing any existing mapping for the specified pattern." >- impact="ACTION" >- returnType="void"> >- <parameter name="pattern" >- description="URL pattern to be mapped" >- type="java.lang.String"/> >- <parameter name="name" >- description="Name of the corresponding servlet to execute" >- type="java.lang.String"/> >- <parameter name="jspWildcard" >- description="'true' if name identifies the JspServlet and pattern contains a wildcard; 'false' otherwise" >- type="boolean"/> >- </operation> >- >- <operation name="addValve" >- description="Add a valve to this Context" >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="valveType" >- description="Type(classname) of the new valve to be added" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addWatchedResource" >- description=" Add a resource which will be watched for reloading by the host auto deployer." >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="Path to the resource, relative to docBase" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addWelcomeFile" >- description="Add a new welcome file to the set recognized by this Context." >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="New welcome file name" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addWrapperLifecycle" >- description="Add the classname of a LifecycleListener to be added to each Wrapper appended to this Context." >- impact="ACTION" >- returnType="void"> >- <parameter name="listener" >- description="Java class name of a LifecycleListener class" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addWrapperListener" >- description="Add the classname of a ContainerListener to be added to each Wrapper appended to this Context." >- impact="ACTION" >- returnType="void"> >- <parameter name="listener" >- description="Java class name of a ContainerListener class" >- type="java.lang.String"/> >- </operation> >- >- <operation name="destroy" >- description="Destroy the context" >- impact="ACTION" >- returnType="void"> >- </operation> >- >- <operation name="findApplicationListeners" >- description="Return the set of application listener class names configured for this application." >- impact="INFO" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findApplicationParameters" >- description="Return the set of application parameters for this application." >- impact="INFO" >- returnType="java.lang.String"> >- </operation> >- >- <operation name="findConstraints" >- description="Return the set of security constraints for this web application. If there are none, a zero-length array is returned." >- impact="INFO" >- returnType="java.lang.String"> >- </operation> >- >- <operation name="findContainerListenerNames" >- description="Return the set of container listener class names configured for this application." >- impact="INFO" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findErrorPage" >- description="Return the error page entry for the specified HTTP error code, if any; otherwise return null" >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="errorCode" >- description="Error code to look up" >- type="int"/> >- </operation> >- >- <operation name="findErrorPage" >- description="Return the error page entry for the specified Java exception type, if any; otherwise return null." >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="exceptionType" >- description="Exception type to look up" >- type="java.lang.String"/> >- </operation> >- >- <operation name="findErrorPages" >- description="Return the set of defined error pages for all specified error codes and exception types." >- impact="INFO" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findFilterDef" >- description="Return the filter definition for the specified filter name, if any; otherwise return null." >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="exceptionType" >- description="Exception type to look up" >- type="java.lang.String"/> >- </operation> >- >- <operation name="findFilterDefs" >- description="Return the set of defined filters for this Context." >- impact="INFO" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findFilterMaps" >- description="Return the set of filter mappings for this Context." >- impact="INFO" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findInstanceListeners" >- description="Return the set of InstanceListener classes that will be added to newly created Wrappers automatically." >- impact="INFO" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findLifecycleListenerNames" >- description="Return the set of lifecycle listener class names configured for this application." >- impact="INFO" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findMimeMapping" >- description="Return the MIME type to which the specified extension is mapped, if any; otherwise return null." >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="extension" >- description="Extension to map to a MIME type" >- type="java.lang.String"/> >- </operation> >- >- <operation name="findMimeMappings" >- description="Return the extensions for which MIME mappings are defined." >- impact="ACTION" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findParameter" >- description="Return the value for the specified context initialization parameter name, if any; otherwise return null." >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="name" >- description="Name of the parameter to return" >- type="java.lang.String"/> >- </operation> >- >- <operation name="findParameters" >- description="Return the names of all defined context initialization parameters for this Context." >- impact="ACTION" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findRoleMapping" >- description="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." >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="role" >- description="Security role to map" >- type="java.lang.String"/> >- </operation> >- >- <operation name="findSecurityRole" >- description="Return 'true' if the specified security role is defined for this application; otherwise return 'false'." >- impact="ACTION" >- returnType="boolean"> >- <parameter name="role" >- description="Security role to verify" >- type="java.lang.String"/> >- </operation> >- >- <operation name="findSecurityRoles" >- description="Return the security roles defined for this application." >- impact="ACTION" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findServletMapping" >- description="Return the servlet name mapped by the specified pattern.." >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="pattern" >- description="Pattern for which a mapping is requested" >- type="java.lang.String"/> >- </operation> >- >- <operation name="findServletMappings" >- description="Return the patterns of all defined servlet mappings for this Context." >- impact="ACTION" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findStatusPage" >- description="Return the context-relative URI of the error page for the specified HTTP status code." >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="status" >- description="HTTP status code to look up" >- type="int"/> >- </operation> >- >- <operation name="findStatusPages" >- description="Return the set of HTTP status codes for which error pages have been specified." >- impact="ACTION" >- returnType="[Lint"> >- </operation> >- >- <operation name="findWatchedResources" >- description="Return the set of watched resources for this Context." >- impact="ACTION" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findWelcomeFile" >- description="Return 'true' if the specified welcome file is defined for this Context; otherwise return 'false'." >- impact="ACTION" >- returnType="boolean"> >- <parameter name="name" >- description="Welcome file to verify" >- type="java.lang.String"/> >- </operation> >- >- <operation name="findWelcomeFiles" >- description="Return the set of welcome files defined for this Context." >- impact="ACTION" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findWrapperLifecycles" >- description="Return the set of LifecycleListener classes that will be added to newly created Wrappers automatically." >- impact="ACTION" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findWrapperListeners" >- description="Return the set of ContainerListener classes that will be added to newly created Wrappers automatically." >- impact="ACTION" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="init" >- description="Register the context into the running server" >- impact="ACTION" >- returnType="void"> >- </operation> >- >- <operation name="start" >- description="Start the context" >- impact="ACTION" >- returnType="void"> >- </operation> >- >- <operation name="stop" >- description="Stop the context" >- impact="ACTION" >- returnType="void"> >- </operation> >- >- <operation name="reload" >- description="Reload the webapplication" >- impact="ACTION" >- returnType="void"> >- </operation> >- >- <operation name="removeApplicationListener" >- description="Remove the specified application listener class from the set of listeners for this application." >- impact="ACTION" >- returnType="void"> >- <parameter name="listener" >- description="Java class name of the listener to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeApplicationParameter" >- description="Remove the application parameter with the specified name from the set for this application." >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="Name of the application parameter to remove" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeChild" >- description="Remove a child from this Context" >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="Name of the existing child Container to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeInstanceListener" >- description="Remove the application parameter with the specified name from the set for this application." >- impact="ACTION" >- returnType="void"> >- <parameter name="listener" >- description="Class name of an InstanceListener class to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeLifecycleListeners" >- description="Removes lifecycle listeners of given class type from this Context" >- impact="ACTION" >- returnType="void"> >- <parameter name="listener" >- description="Type(classname) of the lifecycle listeners to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeMimeMapping" >- description="Remove the MIME mapping for the specified extension, if it exists; otherwise, no action is taken.." >- impact="ACTION" >- returnType="void"> >- <parameter name="extension" >- description="Extension to remove the mapping for" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeParameter" >- description="Remove the context initialization parameter with the specified name, if it exists; otherwise, no action is taken." >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="Name of the parameter to remove" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeRoleMapping" >- description="Remove any security role reference for the specified name" >- impact="ACTION" >- returnType="void"> >- <parameter name="role" >- description="Security role (as used in the application) to remove" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeSecurityRole" >- description="Remove any security role with the specified name." >- impact="ACTION" >- returnType="void"> >- <parameter name="role" >- description="Security role to remove" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeServletMapping" >- description="Remove any servlet mapping for the specified pattern, if it exists; otherwise, no action is taken." >- impact="ACTION" >- returnType="void"> >- <parameter name="pattern" >- description="URL pattern of the mapping to remove" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeValve" >- description="Remove a valve from this Context" >- impact="ACTION" >- returnType="void"> >- <parameter name="valveName" >- description="Objectname of the valve to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeWatchedResource" >- description="Remove the specified watched resource name from the list associated with this Context." >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="Name of the watched resource to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeWelcomeFile" >- description="Remove the specified welcome file name from the list recognized by this Context." >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="Name of the welcome file to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeWrapperLifecycle" >- description="Remove a class name from the set of LifecycleListener classes that will be added to newly created Wrappers." >- impact="ACTION" >- returnType="void"> >- <parameter name="listener" >- description="Class name of a LifecycleListener class to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeWrapperListener" >- description="Remove a class name from the set of ContainerListener classes that will be added to newly created Wrappers." >- impact="ACTION" >- returnType="void"> >- <parameter name="listener" >- description="Class name of a ContainerListener class to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="start" >- description="Start" >- impact="ACTION" >- returnType="void" /> >- >- <operation name="stop" >- description="Stop" >- impact="ACTION" >- returnType="void" /> >- >- </mbean> >- >- <mbean name="StandardContextValve" >- description="Valve that implements the default basic behavior for the >- StandardContext container implementation" >- domain="Catalina" >- group="Valve" >- type="org.apache.catalina.core.StandardContextValve"> >- >- <attribute name="asyncSupported" >- description="Does this valve support async reporting?" >- is="true" >- type="boolean"/> >- >- <attribute name="className" >- description="Fully qualified class name of the managed object" >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="stateName" >- description="The name of the LifecycleState that this component is currently in" >- type="java.lang.String" >- writeable="false"/> >- </mbean> >- >- <mbean name="StandardEngine" >- type="org.apache.catalina.core.StandardEngine" >- description="Standard Engine Component" >- domain="Catalina" >- group="Engine" >- className="org.apache.catalina.mbeans.ContainerMBean"> >- >- <attribute name="backgroundProcessorDelay" >- description="The processor delay for this component." >- type="int"/> >- >- <attribute name="baseDir" >- description="Base dir for this engine, typically same as catalina.base system property" >- type="java.lang.String"/> >- >- <attribute name="defaultHost" >- description="Name of the default Host for this Engine" >- type="java.lang.String"/> >- >- <attribute name="jvmRoute" >- description="Route used for load balancing" >- type="java.lang.String"/> >- >- <attribute name="managedResource" >- description="The managed resource this MBean is associated with" >- type="java.lang.Object"/> >- >- <attribute name="name" >- description="Unique name of this Engine" >- type="java.lang.String"/> >- >- <attribute name="realm" >- description="Associated realm." >- type="org.apache.catalina.Realm" /> >- >- <attribute name="startChildren" >- description="Will children be started automatically when they are added." >- type="boolean"/> >- >- <attribute name="stateName" >- description="The name of the LifecycleState that this component is currently in" >- type="java.lang.String" >- writeable="false"/> >- >- <operation name="addChild" >- description="Add a virtual host" >- impact="ACTION" >- returnType="void"> >- <parameter name="type" >- description="Type(classname) of the new child to be added" >- type="java.lang.String"/> >- <parameter name="name" >- description="Name of the child to be added" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addLifecycleListener" >- description="Add a lifecycle listener to this Engine" >- impact="ACTION" >- returnType="void"> >- <parameter name="type" >- description="Type(classname) of the new lifecycle listener to be added" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addValve" >- description="Add a valve to this Engine" >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="valveType" >- description="Type(classname) of the new valve to be added" >- type="java.lang.String"/> >- </operation> >- >- <operation name="destroy" >- description="Destroy" >- impact="ACTION" >- returnType="void" /> >- >- <operation name="init" >- description="Init" >- impact="ACTION" >- returnType="void" /> >- >- <operation name="removeChild" >- description="Remove a child(Host) from this Engine" >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="Name of the existing child Container to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeLifecycleListeners" >- description="Removes lifecycle listeners of given class type from this Engine" >- impact="ACTION" >- returnType="void"> >- <parameter name="listener" >- description="Type(classname) of the lifecycle listeners to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeValve" >- description="Remove a valve from this Engine" >- impact="ACTION" >- returnType="void"> >- <parameter name="valveName" >- description="Objectname of the valve to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="start" >- description="Start" >- impact="ACTION" >- returnType="void" /> >- >- <operation name="stop" >- description="Stop" >- impact="ACTION" >- returnType="void" /> >- >- </mbean> >- >- >- <mbean name="StandardEngineValve" >- description="Valve that implements the default basic behavior for the >- StandardEngine container implementation" >- domain="Catalina" >- group="Valve" >- type="org.apache.catalina.core.StandardEngineValve"> >- >- <attribute name="asyncSupported" >- description="Does this valve support async reporting?" >- is="true" >- type="boolean"/> >- >- <attribute name="className" >- description="Fully qualified class name of the managed object" >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="stateName" >- description="The name of the LifecycleState that this component is currently in" >- type="java.lang.String" >- writeable="false"/> >- </mbean> >- >- <mbean name="StandardHost" >- description="Standard Host Component" >- domain="Catalina" >- group="Host" >- type="org.apache.catalina.core.StandardHost" >- className="org.apache.catalina.mbeans.ContainerMBean"> >- >- <attribute name="aliases" >- description="Host aliases" >- type="[Ljava.lang.String;"/> >- >- <attribute name="appBase" >- description="The application root for this Host" >- type="java.lang.String"/> >- >- <attribute name="autoDeploy" >- description="The auto deploy flag for this Host" >- type="boolean"/> >- >- <attribute name="backgroundProcessorDelay" >- description="The processor delay for this component." >- type="int"/> >- >- <attribute name="children" >- description="Object names of all children" >- type="[Ljavax.management.ObjectName;"/> >- >- <attribute name="configClass" >- description="The configuration class for contexts" >- type="java.lang.String"/> >- >- <attribute name="contextClass" >- description="The Java class name of the default Context implementation class for deployed web applications." >- type="java.lang.String" >- writeable="false" /> >- >- <attribute name="copyXML" >- description="Should XML files be copied to $CATALINA_BASE/conf/{engine}/{host} by default when a web application is deployed?" >- is="true" >- type="boolean"/> >- >- <attribute name="createDirs" >- description="Should we create directories upon startup for appBase and xmlBase? " >- type="boolean"/> >- >- <attribute name="deployIgnore" >- description="Paths within appBase ignored for automatic deployment" >- type="java.lang.String"/> >- >- <attribute name="deployOnStartup" >- description="The deploy on startup flag for this Host" >- type="boolean"/> >- >- <attribute name="deployXML" >- description="deploy Context XML config files property" >- is="true" >- type="boolean"/> >- >- <attribute name="errorReportValveClass" >- description="The Java class name of the default error reporter implementation class for deployed web applications." >- type="java.lang.String" >- writeable="false" /> >- >- <attribute name="managedResource" >- description="The managed resource this MBean is associated with" >- type="java.lang.Object"/> >- >- <attribute name="name" >- description="Unique name of this Host" >- type="java.lang.String"/> >- >- <attribute name="realm" >- description="Associated realm." >- type="org.apache.catalina.Realm" /> >- >- <attribute name="startChildren" >- description="Will children be started automatically when they are added?" >- type="boolean"/> >- >- <attribute name="stateName" >- description="The name of the LifecycleState that this component is currently in" >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="unpackWARs" >- description="Unpack WARs property" >- is="true" >- type="boolean"/> >- >- <attribute name="valveNames" >- description="Return the MBean Names of the Valves associated with this Host" >- type="[Ljava.lang.String;"/> >- >- <attribute name="workDir" >- description="Work Directory base for applications" >- type="java.lang.String"/> >- >- <attribute name="xmlBase" >- description="The XML root for this Host." >- type="java.lang.String"/> >- >- <operation name="addAlias" >- description="Add an alias name that should be mapped to this Host" >- impact="ACTION" >- returnType="void"> >- <parameter name="alias" >- description="The alias to be added" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addChild" >- description="Add a child(Context) to this Host" >- impact="ACTION" >- returnType="void"> >- <parameter name="type" >- description="Type(classname) of the new child to be added" >- type="java.lang.String"/> >- <parameter name="name" >- description="Name of the child to be added" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addLifecycleListener" >- description="Add a lifecycle listener to this Host" >- impact="ACTION" >- returnType="void"> >- <parameter name="type" >- description="Type(classname) of the new lifecycle listener to be added" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addValve" >- description="Add a valve to this Host" >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="valveType" >- description="Type(classname) of the new valve to be added" >- type="java.lang.String"/> >- </operation> >- >- <operation name="destroy" >- description="Destroy" >- impact="ACTION" >- returnType="void" /> >- >- <operation name="findAliases" >- description="Return the set of alias names for this Host" >- impact="INFO" >- returnType="[Ljava.lang.String;"/> >- >- <operation name="findReloadedContextMemoryLeaks" >- description="Provide a list of contexts that have leaked memory on reload. This will attempt to force a full garbage collection. Use with extreme caution on production systems." >- impact="ACTION" >- returnType="[Ljava.lang.String;" /> >- >- <operation name="init" >- description="Init" >- impact="ACTION" >- returnType="void" /> >- >- <operation name="removeAlias" >- description="Remove the specified alias name from the aliases for this Host" >- impact="ACTION" >- returnType="void"> >- <parameter name="alias" >- description="Alias name to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeChild" >- description="Remove a child(Context) from this Host" >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="Name of the existing child Container to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeLifecycleListeners" >- description="Removes lifecycle listeners of given class type from this Host" >- impact="ACTION" >- returnType="void"> >- <parameter name="listener" >- description="Type(classname) of the lifecycle listeners to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeValve" >- description="Remove a valve from this Host" >- impact="ACTION" >- returnType="void"> >- <parameter name="valveName" >- description="Objectname of the valve to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="start" >- description="Start" >- impact="ACTION" >- returnType="void" /> >- >- <operation name="stop" >- description="Stop" >- impact="ACTION" >- returnType="void" /> >- >- </mbean> >- >- <mbean name="StandardHostValve" >- description="Valve that implements the default basic behavior for the >- StandardHost container implementation" >- domain="Catalina" >- group="Valve" >- type="org.apache.catalina.core.StandardHostValve"> >- >- <attribute name="asyncSupported" >- description="Does this valve support async reporting?" >- is="true" >- type="boolean"/> >- >- <attribute name="className" >- description="Fully qualified class name of the managed object" >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="stateName" >- description="The name of the LifecycleState that this component is currently in" >- type="java.lang.String" >- writeable="false"/> >- </mbean> >- >- <mbean name="StandardServer" >- description="Standard Server Component" >- domain="Catalina" >- group="Server" >- type="org.apache.catalina.core.StandardServer"> >- >- <attribute name="address" >- description="The address on which we wait for shutdown commands." >- type="java.lang.String"/> >- >- <attribute name="managedResource" >- description="The managed resource this MBean is associated with" >- type="java.lang.Object"/> >- >- <attribute name="port" >- description="TCP port for shutdown messages" >- type="int"/> >- >- <attribute name="serverInfo" >- description="Tomcat server release identifier" >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="serviceNames" >- description="Object names of all services we know about" >- type="[Ljavax.management.ObjectName;" >- writeable="false" /> >- >- <attribute name="shutdown" >- description="Shutdown password" >- type="java.lang.String"/> >- >- <attribute name="stateName" >- description="The name of the LifecycleState that this component is currently in" >- type="java.lang.String" >- writeable="false"/> >- >- <operation name="await" >- description="Wait for the shutdown message" >- impact="ACTION" >- returnType="void" /> >- >- <operation name="storeConfig" >- description="Save current state to server.xml file" >- impact="ACTION" >- returnType="void"> >- >- </operation> >- >- </mbean> >- >- >- <mbean name="StandardService" >- description="Standard Service Component" >- domain="Catalina" >- group="Service" >- type="org.apache.catalina.core.StandardService" >- className="org.apache.catalina.mbeans.ServiceMBean"> >- >- <attribute name="connectorNames" >- description="ObjectNames of the connectors" >- type="[Ljavax.management.ObjectName;" >- writeable="false" /> >- >- <attribute name="managedResource" >- description="The managed resource this MBean is associated with" >- type="java.lang.Object"/> >- >- <attribute name="name" >- description="Unique name of this Service" >- type="java.lang.String"/> >- >- <attribute name="stateName" >- description="The name of the LifecycleState that this component is currently in" >- type="java.lang.String" >- writeable="false"/> >- >- <operation name="addConnector" >- description="Add a new connector" >- impact="ACTION" >- returnType="void"> >- <parameter name="address" >- description="The IP address on which to bind" >- type="java.lang.String"/> >- <parameter name="port" >- description="TCP port number to listen on" >- type="int"/> >- <parameter name="isAjp" >- description="Create a AJP/1.3 Connector" >- type="boolean"/> >- <parameter name="isSSL" >- description="Create a secure Connector" >- type="boolean"/> >- </operation> >- >- <operation name="addExecutor" >- description="Adds a named executor to the service" >- impact="ACTION" >- returnType="void"> >- <parameter name="type" >- description="Classname of the Executor to be added" >- type="java.lang.String"/> >- </operation> >- >- <operation name="findConnectors" >- description="Find and return the set of Connectors associated with this Service" >- impact="ACTION" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findExecutors" >- description="Retrieves all executors" >- impact="ACTION" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="getExecutor" >- description="Retrieves executor by name" >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="name" >- description="Name of the executor to be retrieved" >- type="java.lang.String"/> >- </operation> >- >- <operation name="start" >- description="Start" >- impact="ACTION" >- returnType="void" /> >- >- <operation name="stop" >- description="Stop" >- impact="ACTION" >- returnType="void" /> >- </mbean> >- >- <mbean name="StandardThreadExecutor" >- description="Standard implementation of a thread pool" >- domain="Catalina" >- group="Executor" >- type="org.apache.catalina.core.StandardThreadExecutor"> >- >- <attribute name="activeCount" >- description="Number of threads currently processing a task" >- type="int" >- writeable="false" /> >- >- <attribute name="completedTaskCount" >- description="Number of tasks completed by the executor" >- type="int" >- writeable="false" /> >- >- <attribute name="corePoolSize" >- description="Core size of the thread pool" >- type="int" >- writeable="false" /> >- >- <attribute name="daemon" >- description="Run threads in daemon or non-daemon state?" >- type="boolean"/> >- >- <attribute name="largestPoolSize" >- description="Peak number of threads" >- type="int" >- writeable="false" /> >- >- <attribute name="maxIdleTime" >- description="Max number of milliseconds a thread can be idle before it can be shutdown" >- type="int"/> >- >- <attribute name="maxQueueSize" >- description="Maximum number of tasks for the pending task queue" >- type="int"/> >- >- <attribute name="maxThreads" >- description="Maximum number of allocated threads" >- type="int"/> >- >- <attribute name="minSpareThreads" >- description="Minimum number of allocated threads" >- type="int"/> >- >- <attribute name="name" >- description="Unique name of this Executor" >- type="java.lang.String"/> >- >- <attribute name="namePrefix" >- description="Name prefix for thread names created by this executor" >- type="java.lang.String"/> >- >- <attribute name="poolSize" >- description="Number of threads in the pool" >- type="int" >- writeable="false" /> >- >- <attribute name="prestartminSpareThreads" >- description="Prestart threads?" >- type="boolean"/> >- >- <attribute name="queueSize" >- description="Number of tasks waiting to be processed" >- type="int" >- writeable="false" /> >- >- <attribute name="stateName" >- description="The name of the LifecycleState that this component is currently in" >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="threadPriority" >- description="The thread priority for threads in this thread pool" >- type="int"/> >- >- <attribute name="threadRenewalDelay" >- description="After a context is stopped, threads in the pool are renewed. To avoid renewing all threads at the same time, this delay is observed between 2 threads being renewed. Value is in ms, default value is 1000ms. If negative, threads are not renewed." >- type="long"/> >- >- </mbean> >- >- <mbean name="StandardWrapper" >- description="Wrapper that represents an individual servlet definition" >- domain="Catalina" >- group="Wrapper" >- type="org.apache.catalina.core.StandardWrapper" >- className="org.apache.catalina.mbeans.ContainerMBean"> >- >- <attribute name="asyncSupported" >- description="Async support" >- is="true" >- type="boolean"/> >- >- <attribute name="available" >- description="The date and time at which this servlet will become available (in milliseconds since the epoch), or zero if the servlet is available. If this value equals Long.MAX_VALUE, the unavailability of this servlet is considered permanent." >- type="long"/> >- >- <attribute name="backgroundProcessorDelay" >- description="The processor delay for this component." >- type="int" /> >- >- <attribute name="classLoadTime" >- description="Time taken to load the Servlet class" >- type="int" >- writeable="false" /> >- >- <attribute name="countAllocated" >- description="The count of allocations that are currently active (even if they are for the same instance, as will be true on a non-STM servlet)." >- type="int" >- writeable="false" /> >- >- <attribute name="errorCount" >- description="Error count" >- type="int" >- writeable="false" /> >- >- <attribute name="eventProvider" >- description="Event provider support for this managed object" >- is="true" >- type="boolean" >- writeable="false"/> >- >- <attribute name="loadOnStartup" >- description="The load-on-startup order value (negative value means load on first call) for this servlet." >- type="int"/> >- >- <attribute name="loadTime" >- description="Time taken to load and initialise the Servlet" >- type="long" >- writeable="false" /> >- >- <attribute name="maxTime" >- description="Maximum processing time of a request" >- type="long" >- writeable="false" /> >- >- <attribute name="maxInstances" >- description="Maximum number of STM instances." >- type="int" /> >- >- <attribute name="minTime" >- description="Minimum processing time of a request" >- type="long" >- writeable="false" /> >- >- <attribute name="objectName" >- description="Name of the object" >- type="java.lang.String"/> >- >- <attribute name="processingTime" >- description="Total execution time of the servlet's service method" >- type="long" >- writeable="false" /> >- >- <attribute name="requestCount" >- description="Number of requests processed by this wrapper" >- type="int" >- writeable="false" /> >- >- <attribute name="runAs" >- description="The run-as identity for this servlet." >- type="java.lang.String"/> >- >- <attribute name="servletClass" >- description="The run-as identity for this servlet." >- type="java.lang.String" >- writeable="false" /> >- >- <attribute name="singleThreadModel" >- description="Does this servlet implement the SingleThreadModel interface?" >- type="boolean" >- is="true" >- writeable="false" /> >- >- <attribute name="stateManageable" >- description="State management support for this managed object" >- is="true" >- type="boolean" >- writeable="false"/> >- >- <attribute name="stateName" >- description="The name of the LifecycleState that this component is currently in" >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="statisticsProvider" >- description="Performance statistics support for this managed object" >- is="true" >- type="boolean" >- writeable="false"/> >- >- <operation name="addInitParameter" >- description="Add a valve to this Wrapper" >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="Name of this initialization parameter to add" >- type="java.lang.String"/> >- <parameter name="value" >- description="Value of this initialization parameter to add" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addLifecycleListener" >- description="Add a lifecycle listener to this Wrapper" >- impact="ACTION" >- returnType="void"> >- <parameter name="type" >- description="Type(classname) of the new lifecycle listener to be added" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addMapping" >- description="Add a mapping associated with the Wrapper." >- impact="ACTION" >- returnType="void"> >- <parameter name="mapping" >- description="The new wrapper mapping" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addSecurityReference" >- description="Add a new security role reference record to the set of records for this servlet." >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="Role name used within this servlet" >- type="java.lang.String"/> >- <parameter name="link" >- description="Role name used within the web application" >- type="java.lang.String"/> >- </operation> >- >- <operation name="addValve" >- description="Add a valve to this Wrapper" >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="valveType" >- description="Type(classname) of the new valve to be added" >- type="java.lang.String"/> >- </operation> >- >- <operation name="findInitParameter" >- description="Add a mapping associated with the Wrapper." >- impact="ACTION" >- returnType="void"> >- <parameter name="mapping" >- description="The new wrapper mapping" >- type="java.lang.String"/> >- </operation> >- >- <operation name="findInitParameters" >- description="Return the names of all defined initialization parameters for this servlet." >- impact="INFO" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findMappings" >- description="Return the mappings associated with this wrapper" >- impact="INFO" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="findMappingObject" >- description="Return an object which may be utilized for mapping to this component" >- impact="INFO" >- returnType="org.apache.catalina.Wrapper"> >- </operation> >- >- <operation name="findSecurityReference" >- description="Return the security role link for the specified security role reference name." >- impact="ACTION" >- returnType="java.lang.String"> >- <parameter name="name" >- description="Security role reference used within this servle" >- type="java.lang.String"/> >- </operation> >- >- <operation name="findSecurityReferences" >- description="Return the set of security role reference names associated with this servlet" >- impact="INFO" >- returnType="[Ljava.lang.String;"> >- </operation> >- >- <operation name="removeInitParameter" >- description="Remove the specified initialization parameter from this servlet." >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="Name of the initialization parameter to remove" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeLifecycleListeners" >- description="Removes lifecycle listeners of given class type from this Wrapper" >- impact="ACTION" >- returnType="void"> >- <parameter name="listener" >- description="Type(classname) of the lifecycle listeners to be removed" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeMapping" >- description="Remove a mapping associated with the wrapper." >- impact="ACTION" >- returnType="void"> >- <parameter name="mapping" >- description="The pattern to remove" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeSecurityReference" >- description="Remove any security role reference for the specified role name." >- impact="ACTION" >- returnType="void"> >- <parameter name="name" >- description="Security role used within this servlet to be removeds" >- type="java.lang.String"/> >- </operation> >- >- <operation name="removeValve" >- description="Remove a valve from this Wrapper" >- impact="ACTION" >- returnType="void"> >- <parameter name="valveName" >- description="Objectname of the valve to be removed" >- type="java.lang.String"/> >- </operation> >- >- </mbean> >- >- <mbean name="StandardWrapperValve" >- description="Valve that implements the default basic behavior for the StandardWrapper container implementation" >- domain="Catalina" >- group="Valve" >- type="org.apache.catalina.core.StandardWrapperValve"> >- >- <attribute name="asyncSupported" >- description="Does this valve support async reporting?" >- type="boolean"/> >- >- <attribute name="className" >- description="Fully qualified class name of the managed object" >- type="java.lang.String" >- writeable="false"/> >- >- <attribute name="stateName" >- description="The name of the LifecycleState that this component is currently in" >- type="java.lang.String" >- writeable="false"/> >- </mbean> >- >-</mbeans-descriptors> >+<?xml version="1.0"?> >+<!-- >+ 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. >+--> >+<mbeans-descriptors> >+ >+ <mbean name="ApplicationFilterConfig" >+ description="Wrapper that represents an individual servlet-filter definition" >+ domain="Catalina" >+ group="Filter" >+ type="org.apache.catalina.core.ApplicationFilterConfig"> >+ >+ <attribute name="filterName" >+ description="The name used to reference the filter in web.xml" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="filterClass" >+ description="Fully qualified class name of the filter object" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="filterInitParameterMap" >+ description="Return the initiaization parameters associated with this filter" >+ type="java.util.Map" >+ writeable="false" /> >+ >+ </mbean> >+ >+ <mbean name="NamingContextListener" >+ description="Helper class used to initialize and populate the JNDI context associated with each context and server" >+ domain="Catalina" >+ group="Listener" >+ type="org.apache.catalina.core.NamingContextListener"> >+ >+ <attribute name="className" >+ description="Fully qualified class name of the managed object" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="name" >+ description="Name of the associated naming context" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ </mbean> >+ >+ <mbean name="StandardContext" >+ description="Standard Context Component" >+ domain="Catalina" >+ group="Context" >+ type="org.apache.catalina.core.StandardContext" >+ className="org.apache.catalina.mbeans.ContextMBean"> >+ >+ <attribute name="allowLinking" >+ description="Allow symlinking to outside the webapp root directory, if the webapp is an exploded directory" >+ is="true" >+ type="boolean"/> >+ >+ <attribute name="aliases" >+ description="List of resource aliases" >+ type="java.lang.String" /> >+ >+ <attribute name="altDDName" >+ description="The alternate deployment descriptor name." >+ type="java.lang.String" /> >+ >+ <attribute name="antiJARLocking" >+ description="Take care to not lock jar files" >+ type="boolean" /> >+ >+ <attribute name="antiResourceLocking" >+ description="Take care to not lock resources" >+ type="boolean" /> >+ >+ <attribute name="baseName" >+ description="The base name used for directories, WAR files (with .war appended) and context.xml files (with .xml appended)." >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="cacheMaxSize" >+ description="Maximum cache size in KB" >+ type="int"/> >+ >+ <attribute name="cacheObjectMaxSize" >+ description="Maximum cached object size in KB" >+ type="int"/> >+ >+ <attribute name="cacheTTL" >+ description="Time interval in ms between cache refeshes" >+ type="int"/> >+ >+ <attribute name="cachingAllowed" >+ description="Should we cache static resources for this webapp" >+ is="true" >+ type="boolean"/> >+ >+ <attribute name="children" >+ description="Object names of all children" >+ type="[Ljavax.management.ObjectName;"/> >+ >+ <attribute name="clearReferencesStatic" >+ description="Should Tomcat attempt to null out any static or final fields from loaded classes when a web application is stopped as a work around for apparent garbage collection bugs and application coding errors?" >+ type="boolean"/> >+ >+ <attribute name="clearReferencesStopThreads" >+ description="Should Tomcat attempt to terminate threads that have been started by the web application? Advisable to be used only in a development environment." >+ type="boolean"/> >+ >+ <attribute name="clearReferencesStopTimerThreads" >+ description="Should Tomcat attempt to terminate TimerThreads that have been started by the web application? Advisable to be used only in a development environment." >+ type="boolean"/> >+ >+ <attribute name="configFile" >+ description="Location of the context.xml resource or file" >+ type="java.net.URL"/> >+ >+ <attribute name="configured" >+ description="The correctly configured flag for this Context." >+ type="boolean" >+ writeable="false" /> >+ >+ <attribute name="cookies" >+ description="Should we attempt to use cookies for session id communication?" >+ type="boolean"/> >+ >+ <attribute name="compilerClasspath" >+ description="The compiler classpath to use" >+ type="java.lang.String"/> >+ >+ <attribute name="crossContext" >+ description="Should we allow the ServletContext.getContext() method to access the context of other web applications in this server?" >+ type="boolean"/> >+ >+ <attribute name="defaultContextXml" >+ description="Location of the default context.xml resource or file" >+ type="java.lang.String"/> >+ >+ <attribute name="defaultWebXml" >+ description="Location of the default web.xml resource or file" >+ type="java.lang.String"/> >+ >+ <attribute name="delegate" >+ description="" >+ type="boolean"/> >+ >+ <attribute name="deploymentDescriptor" >+ description="String deployment descriptor " >+ type="java.lang.String" >+ writeable="false" /> >+ >+ <attribute name="displayName" >+ description="The display name of this web application" >+ type="java.lang.String"/> >+ >+ <attribute name="distributable" >+ description="The distributable flag for this web application." >+ type="boolean"/> >+ >+ <attribute name="docBase" >+ description="The document root for this web application" >+ type="java.lang.String"/> >+ >+ <attribute name="encodedPath" >+ description="The encoded path" >+ type="java.lang.String" >+ writeable="false" /> >+ >+ <attribute name="eventProvider" >+ description="Event provider support for this managed object" >+ is="true" >+ type="boolean" >+ writeable="false" /> >+ >+ <attribute name="ignoreAnnotations" >+ description="Ignore annotations flag." >+ type="boolean" /> >+ >+ <attribute name="instanceManager" >+ description="Object that creates and destroys servlets, filters, and listeners. Include dependency injection and postConstruct/preDestory handling" >+ type="org.apache.catalina.instanceManagement.InstanceManager" /> >+ >+ <attribute name="javaVMs" >+ description="The Java virtual machines on which this module is running" >+ type="[Ljava.lang.String;"/> >+ >+ <attribute name="loader" >+ description="Associated loader." >+ type="org.apache.catalina.Loader" /> >+ >+ <attribute name="logEffectiveWebXml" >+ description="Should the effective web.xml be logged when the context starts?" >+ type="boolean" /> >+ >+ <attribute name="logger" >+ description="Associated logger." >+ type="org.apache.commons.logging.Log" /> >+ >+ <attribute name="managedResource" >+ description="The managed resource this MBean is associated with" >+ type="java.lang.Object"/> >+ >+ <attribute name="manager" >+ description="Associated manager." >+ type="org.apache.catalina.Manager" /> >+ >+ <attribute name="mappingObject" >+ description="The object used for mapping" >+ type="java.lang.Object"/> >+ >+ <attribute name="namingContextListener" >+ description="Associated naming context listener." >+ type="org.apache.catalina.core.NamingContextListener" /> >+ >+ <attribute name="objectName" >+ description="Name of the object" >+ type="java.lang.String" >+ writeable="false" /> >+ >+ <attribute name="originalDocBase" >+ description="The original document root for this web application" >+ type="java.lang.String" /> >+ >+ <attribute name="override" >+ description="The default context.xml override flag for this web application" >+ type="boolean"/> >+ >+ <attribute name="name" >+ description="The name of this Context" >+ type="java.lang.String"/> >+ >+ <attribute name="parentClassLoader" >+ description="Parent class loader." >+ type="java.lang.ClassLoader" /> >+ >+ <attribute name="path" >+ description="The context path for this Context" >+ type="java.lang.String"/> >+ >+ <attribute name="paused" >+ description="The request processing pause flag (while reloading occurs)" >+ type="boolean" >+ writeable="false" /> >+ >+ <attribute name="privileged" >+ description="Access to tomcat internals" >+ type="boolean"/> >+ >+ <attribute name="processingTime" >+ description="Cumulative execution times of all servlets in this context" >+ type="long" >+ writeable="false" /> >+ >+ <attribute name="publicId" >+ description="The public identifier of the DTD for the web application deployment descriptor version that is being parsed" >+ type="java.lang.String" >+ writeable="false" /> >+ >+ <attribute name="realm" >+ description="Associated realm." >+ type="org.apache.catalina.Realm" /> >+ >+ <attribute name="reloadable" >+ description="The reloadable flag for this web application" >+ type="boolean"/> >+ >+ <attribute name="renewThreadsWhenStoppingContext" >+ description="Should Tomcat renew the threads of the thread pool when the application is stopped to avoid memory leaks because of uncleaned ThreadLocal variables." >+ type="boolean"/> >+ >+ <attribute name="saveConfig" >+ description="Should the configuration be written as needed on startup" >+ is="true" >+ type="boolean"/> >+ >+ <attribute name="server" >+ description="The J2EE Server this module is deployed on" >+ type="java.lang.String"/> >+ >+ <attribute name="servlets" >+ description="JSR77 list of servlets" >+ type="[Ljava.lang.String;" >+ writeable="false"/> >+ >+ <attribute name="sessionCookieName" >+ description="The name to use for session cookies.'null' indicates that the name is controlled by the application." >+ type="java.lang.String"/> >+ >+ <attribute name="sessionCookieDomain" >+ description="The domain to use for session cookies.'null' indicates that the domain is controlled by the application." >+ type="java.lang.String"/> >+ >+ <attribute name="sessionCookiePath" >+ description="The path to use for session cookies.'null' indicates that the path is controlled by the application." >+ type="java.lang.String"/> >+ >+ <attribute name="sessionTimeout" >+ description="The session timeout (in minutes) for this web application" >+ type="int"/> >+ >+ <attribute name="startTime" >+ description="Time (in milliseconds since January 1, 1970, 00:00:00) when this context was started" >+ type="long" >+ writeable="false" /> >+ >+ <attribute name="startupTime" >+ description="Time (in milliseconds) it took to start this context" >+ type="long"/> >+ >+ <attribute name="stateManageable" >+ description="State management support for this managed object" >+ is="true" >+ type="boolean" >+ writeable="false" /> >+ >+ <attribute name="stateName" >+ description="The name of the LifecycleState that this component is currently in" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="staticResources" >+ description="Static resources associated with the context." >+ type="javax.naming.directory.DirContext" >+ writeable="false"/> >+ >+ <attribute name="statisticsProvider" >+ description="Performance statistics support for this managed object" >+ is="true" >+ type="boolean" >+ writeable="false" /> >+ >+ <attribute name="swallowOutput" >+ description="Flag to set to cause the system.out and system.err to be redirected to the logger when executing a servlet" >+ type="boolean"/> >+ >+ <attribute name="tldNamespaceAware" >+ description="Should TLD XML namespace validation be turned on?" >+ type="boolean"/> >+ >+ <attribute name="tldScanTime" >+ description="Time spend scanning jars for TLDs for this context" >+ type="long"/> >+ >+ <attribute name="tldValidation" >+ description="Should TLD XML validation be turned on?" >+ type="boolean"/> >+ >+ <attribute name="unloadDelay" >+ description="Amount of ms that the container will wait for servlets to unload" >+ type="long"/> >+ >+ <attribute name="unpackWAR" >+ description="Unpack WAR property" >+ type="boolean"/> >+ >+ <attribute name="useHttpOnly" >+ description="Indicates that session cookies should use HttpOnly" >+ type="boolean"/> >+ >+ <attribute name="useNaming" >+ description="Create a JNDI naming context for this application?" >+ is="true" >+ type="boolean"/> >+ >+ <attribute name="webappVersion" >+ description="The version of this web application - used in parallel deployment to differentiate different versions of the same web application" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="welcomeFiles" >+ description="The welcome files for this context" >+ type="[Ljava.lang.String;" >+ writeable="false"/> >+ >+ <attribute name="workDir" >+ description="The pathname to the work directory for this context" >+ type="java.lang.String"/> >+ >+ <attribute name="xmlValidation" >+ description="Should XML validation be turned on?" >+ type="boolean"/> >+ >+ <attribute name="xmlNamespaceAware" >+ description="Should XML namespace validation be turned on?" >+ type="boolean"/> >+ >+ <operation name="addApplicationListener" >+ description="Add a new Listener class name to the set of Listeners configured for this application." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="listener" >+ description="Java class name of a listener class" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addApplicationParameter" >+ description="Add a new application parameter for this application." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="listener" >+ description="Java class name of a listener class" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addChild" >+ description="Add a child to this Context" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="type" >+ description="Type(classname) of the new child to be added" >+ type="java.lang.String"/> >+ <parameter name="name" >+ description="Name of the child to be added" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addInstanceListener" >+ description="Add the classname of an InstanceListener to be added to each Wrapper appended to this Context." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="listener" >+ description="Java class name of an InstanceListener class" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addLifecycleListener" >+ description="Add a lifecycle listener to this Context" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="type" >+ description="Type(classname) of the new lifecycle listener to be added" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addLocaleEncodingMappingParameter" >+ description="Add a Locale Encoding Mapping" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="locale" >+ description="Locale to map an encoding for" >+ type="java.lang.String"/> >+ <parameter name="encoding" >+ description="Encoding to be used for a give locale" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addMimeMapping" >+ description="Add a new MIME mapping, replacing any existing mapping for the specified extension." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="extension" >+ description="Filename extension being mapped" >+ type="java.lang.String"/> >+ <parameter name="mimeType" >+ description="Corresponding MIME type" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addParameter" >+ description="Add a new context initialization parameter, replacing any existing value for the specified name." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="Name of the new parameter" >+ type="java.lang.String"/> >+ <parameter name="value" >+ description="Value of the new parameter" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addRoleMapping" >+ description="Add a security role reference for this web application." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="role" >+ description="Security role used in the application" >+ type="java.lang.String"/> >+ <parameter name="link" >+ description="Actual security role to check for" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addSecurityRole" >+ description="Add a new security role for this web application." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="role" >+ description="New security role" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addServletMapping" >+ description="Add a new servlet mapping, replacing any existing mapping for the specified pattern." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="pattern" >+ description="URL pattern to be mapped" >+ type="java.lang.String"/> >+ <parameter name="name" >+ description="Name of the corresponding servlet to execute" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addServletMapping" >+ description="Add a new servlet mapping, replacing any existing mapping for the specified pattern." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="pattern" >+ description="URL pattern to be mapped" >+ type="java.lang.String"/> >+ <parameter name="name" >+ description="Name of the corresponding servlet to execute" >+ type="java.lang.String"/> >+ <parameter name="jspWildcard" >+ description="'true' if name identifies the JspServlet and pattern contains a wildcard; 'false' otherwise" >+ type="boolean"/> >+ </operation> >+ >+ <operation name="addValve" >+ description="Add a valve to this Context" >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="valveType" >+ description="Type(classname) of the new valve to be added" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addWatchedResource" >+ description=" Add a resource which will be watched for reloading by the host auto deployer." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="Path to the resource, relative to docBase" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addWelcomeFile" >+ description="Add a new welcome file to the set recognized by this Context." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="New welcome file name" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addWrapperLifecycle" >+ description="Add the classname of a LifecycleListener to be added to each Wrapper appended to this Context." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="listener" >+ description="Java class name of a LifecycleListener class" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addWrapperListener" >+ description="Add the classname of a ContainerListener to be added to each Wrapper appended to this Context." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="listener" >+ description="Java class name of a ContainerListener class" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="destroy" >+ description="Destroy the context" >+ impact="ACTION" >+ returnType="void"> >+ </operation> >+ >+ <operation name="findApplicationListeners" >+ description="Return the set of application listener class names configured for this application." >+ impact="INFO" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findApplicationParameters" >+ description="Return the set of application parameters for this application." >+ impact="INFO" >+ returnType="java.lang.String"> >+ </operation> >+ >+ <operation name="findConstraints" >+ description="Return the set of security constraints for this web application. If there are none, a zero-length array is returned." >+ impact="INFO" >+ returnType="java.lang.String"> >+ </operation> >+ >+ <operation name="findContainerListenerNames" >+ description="Return the set of container listener class names configured for this application." >+ impact="INFO" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findErrorPage" >+ description="Return the error page entry for the specified HTTP error code, if any; otherwise return null" >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="errorCode" >+ description="Error code to look up" >+ type="int"/> >+ </operation> >+ >+ <operation name="findErrorPage" >+ description="Return the error page entry for the specified Java exception type, if any; otherwise return null." >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="exceptionType" >+ description="Exception type to look up" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="findErrorPages" >+ description="Return the set of defined error pages for all specified error codes and exception types." >+ impact="INFO" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findFilterDef" >+ description="Return the filter definition for the specified filter name, if any; otherwise return null." >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="exceptionType" >+ description="Exception type to look up" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="findFilterDefs" >+ description="Return the set of defined filters for this Context." >+ impact="INFO" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findFilterMaps" >+ description="Return the set of filter mappings for this Context." >+ impact="INFO" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findInstanceListeners" >+ description="Return the set of InstanceListener classes that will be added to newly created Wrappers automatically." >+ impact="INFO" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findLifecycleListenerNames" >+ description="Return the set of lifecycle listener class names configured for this application." >+ impact="INFO" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findMimeMapping" >+ description="Return the MIME type to which the specified extension is mapped, if any; otherwise return null." >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="extension" >+ description="Extension to map to a MIME type" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="findMimeMappings" >+ description="Return the extensions for which MIME mappings are defined." >+ impact="ACTION" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findParameter" >+ description="Return the value for the specified context initialization parameter name, if any; otherwise return null." >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="name" >+ description="Name of the parameter to return" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="findParameters" >+ description="Return the names of all defined context initialization parameters for this Context." >+ impact="ACTION" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findRoleMapping" >+ description="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." >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="role" >+ description="Security role to map" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="findSecurityRole" >+ description="Return 'true' if the specified security role is defined for this application; otherwise return 'false'." >+ impact="ACTION" >+ returnType="boolean"> >+ <parameter name="role" >+ description="Security role to verify" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="findSecurityRoles" >+ description="Return the security roles defined for this application." >+ impact="ACTION" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findServletMapping" >+ description="Return the servlet name mapped by the specified pattern.." >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="pattern" >+ description="Pattern for which a mapping is requested" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="findServletMappings" >+ description="Return the patterns of all defined servlet mappings for this Context." >+ impact="ACTION" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findStatusPage" >+ description="Return the context-relative URI of the error page for the specified HTTP status code." >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="status" >+ description="HTTP status code to look up" >+ type="int"/> >+ </operation> >+ >+ <operation name="findStatusPages" >+ description="Return the set of HTTP status codes for which error pages have been specified." >+ impact="ACTION" >+ returnType="[Lint"> >+ </operation> >+ >+ <operation name="findWatchedResources" >+ description="Return the set of watched resources for this Context." >+ impact="ACTION" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findWelcomeFile" >+ description="Return 'true' if the specified welcome file is defined for this Context; otherwise return 'false'." >+ impact="ACTION" >+ returnType="boolean"> >+ <parameter name="name" >+ description="Welcome file to verify" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="findWelcomeFiles" >+ description="Return the set of welcome files defined for this Context." >+ impact="ACTION" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findWrapperLifecycles" >+ description="Return the set of LifecycleListener classes that will be added to newly created Wrappers automatically." >+ impact="ACTION" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findWrapperListeners" >+ description="Return the set of ContainerListener classes that will be added to newly created Wrappers automatically." >+ impact="ACTION" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="init" >+ description="Register the context into the running server" >+ impact="ACTION" >+ returnType="void"> >+ </operation> >+ >+ <operation name="start" >+ description="Start the context" >+ impact="ACTION" >+ returnType="void"> >+ </operation> >+ >+ <operation name="stop" >+ description="Stop the context" >+ impact="ACTION" >+ returnType="void"> >+ </operation> >+ >+ <operation name="reload" >+ description="Reload the webapplication" >+ impact="ACTION" >+ returnType="void"> >+ </operation> >+ >+ <operation name="removeApplicationListener" >+ description="Remove the specified application listener class from the set of listeners for this application." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="listener" >+ description="Java class name of the listener to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeApplicationParameter" >+ description="Remove the application parameter with the specified name from the set for this application." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="Name of the application parameter to remove" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeChild" >+ description="Remove a child from this Context" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="Name of the existing child Container to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeInstanceListener" >+ description="Remove the application parameter with the specified name from the set for this application." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="listener" >+ description="Class name of an InstanceListener class to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeLifecycleListeners" >+ description="Removes lifecycle listeners of given class type from this Context" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="listener" >+ description="Type(classname) of the lifecycle listeners to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeMimeMapping" >+ description="Remove the MIME mapping for the specified extension, if it exists; otherwise, no action is taken.." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="extension" >+ description="Extension to remove the mapping for" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeParameter" >+ description="Remove the context initialization parameter with the specified name, if it exists; otherwise, no action is taken." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="Name of the parameter to remove" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeRoleMapping" >+ description="Remove any security role reference for the specified name" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="role" >+ description="Security role (as used in the application) to remove" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeSecurityRole" >+ description="Remove any security role with the specified name." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="role" >+ description="Security role to remove" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeServletMapping" >+ description="Remove any servlet mapping for the specified pattern, if it exists; otherwise, no action is taken." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="pattern" >+ description="URL pattern of the mapping to remove" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeValve" >+ description="Remove a valve from this Context" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="valveName" >+ description="Objectname of the valve to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeWatchedResource" >+ description="Remove the specified watched resource name from the list associated with this Context." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="Name of the watched resource to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeWelcomeFile" >+ description="Remove the specified welcome file name from the list recognized by this Context." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="Name of the welcome file to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeWrapperLifecycle" >+ description="Remove a class name from the set of LifecycleListener classes that will be added to newly created Wrappers." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="listener" >+ description="Class name of a LifecycleListener class to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeWrapperListener" >+ description="Remove a class name from the set of ContainerListener classes that will be added to newly created Wrappers." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="listener" >+ description="Class name of a ContainerListener class to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="start" >+ description="Start" >+ impact="ACTION" >+ returnType="void" /> >+ >+ <operation name="stop" >+ description="Stop" >+ impact="ACTION" >+ returnType="void" /> >+ >+ </mbean> >+ >+ <mbean name="StandardContextValve" >+ description="Valve that implements the default basic behavior for the >+ StandardContext container implementation" >+ domain="Catalina" >+ group="Valve" >+ type="org.apache.catalina.core.StandardContextValve"> >+ >+ <attribute name="asyncSupported" >+ description="Does this valve support async reporting?" >+ is="true" >+ type="boolean"/> >+ >+ <attribute name="className" >+ description="Fully qualified class name of the managed object" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="stateName" >+ description="The name of the LifecycleState that this component is currently in" >+ type="java.lang.String" >+ writeable="false"/> >+ </mbean> >+ >+ <mbean name="StandardEngine" >+ type="org.apache.catalina.core.StandardEngine" >+ description="Standard Engine Component" >+ domain="Catalina" >+ group="Engine" >+ className="org.apache.catalina.mbeans.ContainerMBean"> >+ >+ <attribute name="backgroundProcessorDelay" >+ description="The processor delay for this component." >+ type="int"/> >+ >+ <attribute name="baseDir" >+ description="Base dir for this engine, typically same as catalina.base system property" >+ type="java.lang.String"/> >+ >+ <attribute name="defaultHost" >+ description="Name of the default Host for this Engine" >+ type="java.lang.String"/> >+ >+ <attribute name="jvmRoute" >+ description="Route used for load balancing" >+ type="java.lang.String"/> >+ >+ <attribute name="managedResource" >+ description="The managed resource this MBean is associated with" >+ type="java.lang.Object"/> >+ >+ <attribute name="name" >+ description="Unique name of this Engine" >+ type="java.lang.String"/> >+ >+ <attribute name="realm" >+ description="Associated realm." >+ type="org.apache.catalina.Realm" /> >+ >+ <attribute name="startChildren" >+ description="Will children be started automatically when they are added." >+ type="boolean"/> >+ >+ <attribute name="startStopThreads" >+ description="The number of threads to use when starting and stopping child Hosts" >+ type="int"/> >+ >+ <attribute name="stateName" >+ description="The name of the LifecycleState that this component is currently in" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <operation name="addChild" >+ description="Add a virtual host" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="type" >+ description="Type(classname) of the new child to be added" >+ type="java.lang.String"/> >+ <parameter name="name" >+ description="Name of the child to be added" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addLifecycleListener" >+ description="Add a lifecycle listener to this Engine" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="type" >+ description="Type(classname) of the new lifecycle listener to be added" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addValve" >+ description="Add a valve to this Engine" >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="valveType" >+ description="Type(classname) of the new valve to be added" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="destroy" >+ description="Destroy" >+ impact="ACTION" >+ returnType="void" /> >+ >+ <operation name="init" >+ description="Init" >+ impact="ACTION" >+ returnType="void" /> >+ >+ <operation name="removeChild" >+ description="Remove a child(Host) from this Engine" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="Name of the existing child Container to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeLifecycleListeners" >+ description="Removes lifecycle listeners of given class type from this Engine" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="listener" >+ description="Type(classname) of the lifecycle listeners to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeValve" >+ description="Remove a valve from this Engine" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="valveName" >+ description="Objectname of the valve to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="start" >+ description="Start" >+ impact="ACTION" >+ returnType="void" /> >+ >+ <operation name="stop" >+ description="Stop" >+ impact="ACTION" >+ returnType="void" /> >+ >+ </mbean> >+ >+ >+ <mbean name="StandardEngineValve" >+ description="Valve that implements the default basic behavior for the >+ StandardEngine container implementation" >+ domain="Catalina" >+ group="Valve" >+ type="org.apache.catalina.core.StandardEngineValve"> >+ >+ <attribute name="asyncSupported" >+ description="Does this valve support async reporting?" >+ is="true" >+ type="boolean"/> >+ >+ <attribute name="className" >+ description="Fully qualified class name of the managed object" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="stateName" >+ description="The name of the LifecycleState that this component is currently in" >+ type="java.lang.String" >+ writeable="false"/> >+ </mbean> >+ >+ <mbean name="StandardHost" >+ description="Standard Host Component" >+ domain="Catalina" >+ group="Host" >+ type="org.apache.catalina.core.StandardHost" >+ className="org.apache.catalina.mbeans.ContainerMBean"> >+ >+ <attribute name="aliases" >+ description="Host aliases" >+ type="[Ljava.lang.String;"/> >+ >+ <attribute name="appBase" >+ description="The application root for this Host" >+ type="java.lang.String"/> >+ >+ <attribute name="autoDeploy" >+ description="The auto deploy flag for this Host" >+ type="boolean"/> >+ >+ <attribute name="backgroundProcessorDelay" >+ description="The processor delay for this component." >+ type="int"/> >+ >+ <attribute name="children" >+ description="Object names of all children" >+ type="[Ljavax.management.ObjectName;"/> >+ >+ <attribute name="configClass" >+ description="The configuration class for contexts" >+ type="java.lang.String"/> >+ >+ <attribute name="contextClass" >+ description="The Java class name of the default Context implementation class for deployed web applications." >+ type="java.lang.String" >+ writeable="false" /> >+ >+ <attribute name="copyXML" >+ description="Should XML files be copied to $CATALINA_BASE/conf/{engine}/{host} by default when a web application is deployed?" >+ is="true" >+ type="boolean"/> >+ >+ <attribute name="createDirs" >+ description="Should we create directories upon startup for appBase and xmlBase? " >+ type="boolean"/> >+ >+ <attribute name="deployIgnore" >+ description="Paths within appBase ignored for automatic deployment" >+ type="java.lang.String"/> >+ >+ <attribute name="deployOnStartup" >+ description="The deploy on startup flag for this Host" >+ type="boolean"/> >+ >+ <attribute name="deployXML" >+ description="deploy Context XML config files property" >+ is="true" >+ type="boolean"/> >+ >+ <attribute name="errorReportValveClass" >+ description="The Java class name of the default error reporter implementation class for deployed web applications." >+ type="java.lang.String" >+ writeable="false" /> >+ >+ <attribute name="managedResource" >+ description="The managed resource this MBean is associated with" >+ type="java.lang.Object"/> >+ >+ <attribute name="name" >+ description="Unique name of this Host" >+ type="java.lang.String"/> >+ >+ <attribute name="realm" >+ description="Associated realm." >+ type="org.apache.catalina.Realm" /> >+ >+ <attribute name="startChildren" >+ description="Will children be started automatically when they are added?" >+ type="boolean"/> >+ >+ <attribute name="startStopThreads" >+ description="The number of threads to use when starting, stopping and deploying child Contexts" >+ type="int"/> >+ >+ <attribute name="stateName" >+ description="The name of the LifecycleState that this component is currently in" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="unpackWARs" >+ description="Unpack WARs property" >+ is="true" >+ type="boolean"/> >+ >+ <attribute name="valveNames" >+ description="Return the MBean Names of the Valves associated with this Host" >+ type="[Ljava.lang.String;"/> >+ >+ <attribute name="workDir" >+ description="Work Directory base for applications" >+ type="java.lang.String"/> >+ >+ <attribute name="xmlBase" >+ description="The XML root for this Host." >+ type="java.lang.String"/> >+ >+ <operation name="addAlias" >+ description="Add an alias name that should be mapped to this Host" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="alias" >+ description="The alias to be added" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addChild" >+ description="Add a child(Context) to this Host" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="type" >+ description="Type(classname) of the new child to be added" >+ type="java.lang.String"/> >+ <parameter name="name" >+ description="Name of the child to be added" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addLifecycleListener" >+ description="Add a lifecycle listener to this Host" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="type" >+ description="Type(classname) of the new lifecycle listener to be added" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addValve" >+ description="Add a valve to this Host" >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="valveType" >+ description="Type(classname) of the new valve to be added" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="destroy" >+ description="Destroy" >+ impact="ACTION" >+ returnType="void" /> >+ >+ <operation name="findAliases" >+ description="Return the set of alias names for this Host" >+ impact="INFO" >+ returnType="[Ljava.lang.String;"/> >+ >+ <operation name="findReloadedContextMemoryLeaks" >+ description="Provide a list of contexts that have leaked memory on reload. This will attempt to force a full garbage collection. Use with extreme caution on production systems." >+ impact="ACTION" >+ returnType="[Ljava.lang.String;" /> >+ >+ <operation name="init" >+ description="Init" >+ impact="ACTION" >+ returnType="void" /> >+ >+ <operation name="removeAlias" >+ description="Remove the specified alias name from the aliases for this Host" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="alias" >+ description="Alias name to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeChild" >+ description="Remove a child(Context) from this Host" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="Name of the existing child Container to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeLifecycleListeners" >+ description="Removes lifecycle listeners of given class type from this Host" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="listener" >+ description="Type(classname) of the lifecycle listeners to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeValve" >+ description="Remove a valve from this Host" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="valveName" >+ description="Objectname of the valve to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="start" >+ description="Start" >+ impact="ACTION" >+ returnType="void" /> >+ >+ <operation name="stop" >+ description="Stop" >+ impact="ACTION" >+ returnType="void" /> >+ >+ </mbean> >+ >+ <mbean name="StandardHostValve" >+ description="Valve that implements the default basic behavior for the >+ StandardHost container implementation" >+ domain="Catalina" >+ group="Valve" >+ type="org.apache.catalina.core.StandardHostValve"> >+ >+ <attribute name="asyncSupported" >+ description="Does this valve support async reporting?" >+ is="true" >+ type="boolean"/> >+ >+ <attribute name="className" >+ description="Fully qualified class name of the managed object" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="stateName" >+ description="The name of the LifecycleState that this component is currently in" >+ type="java.lang.String" >+ writeable="false"/> >+ </mbean> >+ >+ <mbean name="StandardServer" >+ description="Standard Server Component" >+ domain="Catalina" >+ group="Server" >+ type="org.apache.catalina.core.StandardServer"> >+ >+ <attribute name="address" >+ description="The address on which we wait for shutdown commands." >+ type="java.lang.String"/> >+ >+ <attribute name="managedResource" >+ description="The managed resource this MBean is associated with" >+ type="java.lang.Object"/> >+ >+ <attribute name="port" >+ description="TCP port for shutdown messages" >+ type="int"/> >+ >+ <attribute name="serverInfo" >+ description="Tomcat server release identifier" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="serviceNames" >+ description="Object names of all services we know about" >+ type="[Ljavax.management.ObjectName;" >+ writeable="false" /> >+ >+ <attribute name="shutdown" >+ description="Shutdown password" >+ type="java.lang.String"/> >+ >+ <attribute name="stateName" >+ description="The name of the LifecycleState that this component is currently in" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <operation name="await" >+ description="Wait for the shutdown message" >+ impact="ACTION" >+ returnType="void" /> >+ >+ <operation name="storeConfig" >+ description="Save current state to server.xml file" >+ impact="ACTION" >+ returnType="void"> >+ >+ </operation> >+ >+ </mbean> >+ >+ >+ <mbean name="StandardService" >+ description="Standard Service Component" >+ domain="Catalina" >+ group="Service" >+ type="org.apache.catalina.core.StandardService" >+ className="org.apache.catalina.mbeans.ServiceMBean"> >+ >+ <attribute name="connectorNames" >+ description="ObjectNames of the connectors" >+ type="[Ljavax.management.ObjectName;" >+ writeable="false" /> >+ >+ <attribute name="managedResource" >+ description="The managed resource this MBean is associated with" >+ type="java.lang.Object"/> >+ >+ <attribute name="name" >+ description="Unique name of this Service" >+ type="java.lang.String"/> >+ >+ <attribute name="stateName" >+ description="The name of the LifecycleState that this component is currently in" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <operation name="addConnector" >+ description="Add a new connector" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="address" >+ description="The IP address on which to bind" >+ type="java.lang.String"/> >+ <parameter name="port" >+ description="TCP port number to listen on" >+ type="int"/> >+ <parameter name="isAjp" >+ description="Create a AJP/1.3 Connector" >+ type="boolean"/> >+ <parameter name="isSSL" >+ description="Create a secure Connector" >+ type="boolean"/> >+ </operation> >+ >+ <operation name="addExecutor" >+ description="Adds a named executor to the service" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="type" >+ description="Classname of the Executor to be added" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="findConnectors" >+ description="Find and return the set of Connectors associated with this Service" >+ impact="ACTION" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findExecutors" >+ description="Retrieves all executors" >+ impact="ACTION" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="getExecutor" >+ description="Retrieves executor by name" >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="name" >+ description="Name of the executor to be retrieved" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="start" >+ description="Start" >+ impact="ACTION" >+ returnType="void" /> >+ >+ <operation name="stop" >+ description="Stop" >+ impact="ACTION" >+ returnType="void" /> >+ </mbean> >+ >+ <mbean name="StandardThreadExecutor" >+ description="Standard implementation of a thread pool" >+ domain="Catalina" >+ group="Executor" >+ type="org.apache.catalina.core.StandardThreadExecutor"> >+ >+ <attribute name="activeCount" >+ description="Number of threads currently processing a task" >+ type="int" >+ writeable="false" /> >+ >+ <attribute name="completedTaskCount" >+ description="Number of tasks completed by the executor" >+ type="int" >+ writeable="false" /> >+ >+ <attribute name="corePoolSize" >+ description="Core size of the thread pool" >+ type="int" >+ writeable="false" /> >+ >+ <attribute name="daemon" >+ description="Run threads in daemon or non-daemon state?" >+ type="boolean"/> >+ >+ <attribute name="largestPoolSize" >+ description="Peak number of threads" >+ type="int" >+ writeable="false" /> >+ >+ <attribute name="maxIdleTime" >+ description="Max number of milliseconds a thread can be idle before it can be shutdown" >+ type="int"/> >+ >+ <attribute name="maxQueueSize" >+ description="Maximum number of tasks for the pending task queue" >+ type="int"/> >+ >+ <attribute name="maxThreads" >+ description="Maximum number of allocated threads" >+ type="int"/> >+ >+ <attribute name="minSpareThreads" >+ description="Minimum number of allocated threads" >+ type="int"/> >+ >+ <attribute name="name" >+ description="Unique name of this Executor" >+ type="java.lang.String"/> >+ >+ <attribute name="namePrefix" >+ description="Name prefix for thread names created by this executor" >+ type="java.lang.String"/> >+ >+ <attribute name="poolSize" >+ description="Number of threads in the pool" >+ type="int" >+ writeable="false" /> >+ >+ <attribute name="prestartminSpareThreads" >+ description="Prestart threads?" >+ type="boolean"/> >+ >+ <attribute name="queueSize" >+ description="Number of tasks waiting to be processed" >+ type="int" >+ writeable="false" /> >+ >+ <attribute name="stateName" >+ description="The name of the LifecycleState that this component is currently in" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="threadPriority" >+ description="The thread priority for threads in this thread pool" >+ type="int"/> >+ >+ <attribute name="threadRenewalDelay" >+ description="After a context is stopped, threads in the pool are renewed. To avoid renewing all threads at the same time, this delay is observed between 2 threads being renewed. Value is in ms, default value is 1000ms. If negative, threads are not renewed." >+ type="long"/> >+ >+ </mbean> >+ >+ <mbean name="StandardWrapper" >+ description="Wrapper that represents an individual servlet definition" >+ domain="Catalina" >+ group="Wrapper" >+ type="org.apache.catalina.core.StandardWrapper" >+ className="org.apache.catalina.mbeans.ContainerMBean"> >+ >+ <attribute name="asyncSupported" >+ description="Async support" >+ is="true" >+ type="boolean"/> >+ >+ <attribute name="available" >+ description="The date and time at which this servlet will become available (in milliseconds since the epoch), or zero if the servlet is available. If this value equals Long.MAX_VALUE, the unavailability of this servlet is considered permanent." >+ type="long"/> >+ >+ <attribute name="backgroundProcessorDelay" >+ description="The processor delay for this component." >+ type="int" /> >+ >+ <attribute name="classLoadTime" >+ description="Time taken to load the Servlet class" >+ type="int" >+ writeable="false" /> >+ >+ <attribute name="countAllocated" >+ description="The count of allocations that are currently active (even if they are for the same instance, as will be true on a non-STM servlet)." >+ type="int" >+ writeable="false" /> >+ >+ <attribute name="errorCount" >+ description="Error count" >+ type="int" >+ writeable="false" /> >+ >+ <attribute name="eventProvider" >+ description="Event provider support for this managed object" >+ is="true" >+ type="boolean" >+ writeable="false"/> >+ >+ <attribute name="loadOnStartup" >+ description="The load-on-startup order value (negative value means load on first call) for this servlet." >+ type="int"/> >+ >+ <attribute name="loadTime" >+ description="Time taken to load and initialise the Servlet" >+ type="long" >+ writeable="false" /> >+ >+ <attribute name="maxTime" >+ description="Maximum processing time of a request" >+ type="long" >+ writeable="false" /> >+ >+ <attribute name="maxInstances" >+ description="Maximum number of STM instances." >+ type="int" /> >+ >+ <attribute name="minTime" >+ description="Minimum processing time of a request" >+ type="long" >+ writeable="false" /> >+ >+ <attribute name="objectName" >+ description="Name of the object" >+ type="java.lang.String"/> >+ >+ <attribute name="processingTime" >+ description="Total execution time of the servlet's service method" >+ type="long" >+ writeable="false" /> >+ >+ <attribute name="requestCount" >+ description="Number of requests processed by this wrapper" >+ type="int" >+ writeable="false" /> >+ >+ <attribute name="runAs" >+ description="The run-as identity for this servlet." >+ type="java.lang.String"/> >+ >+ <attribute name="servletClass" >+ description="The run-as identity for this servlet." >+ type="java.lang.String" >+ writeable="false" /> >+ >+ <attribute name="singleThreadModel" >+ description="Does this servlet implement the SingleThreadModel interface?" >+ type="boolean" >+ is="true" >+ writeable="false" /> >+ >+ <attribute name="stateManageable" >+ description="State management support for this managed object" >+ is="true" >+ type="boolean" >+ writeable="false"/> >+ >+ <attribute name="stateName" >+ description="The name of the LifecycleState that this component is currently in" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="statisticsProvider" >+ description="Performance statistics support for this managed object" >+ is="true" >+ type="boolean" >+ writeable="false"/> >+ >+ <operation name="addInitParameter" >+ description="Add a valve to this Wrapper" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="Name of this initialization parameter to add" >+ type="java.lang.String"/> >+ <parameter name="value" >+ description="Value of this initialization parameter to add" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addLifecycleListener" >+ description="Add a lifecycle listener to this Wrapper" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="type" >+ description="Type(classname) of the new lifecycle listener to be added" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addMapping" >+ description="Add a mapping associated with the Wrapper." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="mapping" >+ description="The new wrapper mapping" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addSecurityReference" >+ description="Add a new security role reference record to the set of records for this servlet." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="Role name used within this servlet" >+ type="java.lang.String"/> >+ <parameter name="link" >+ description="Role name used within the web application" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="addValve" >+ description="Add a valve to this Wrapper" >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="valveType" >+ description="Type(classname) of the new valve to be added" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="findInitParameter" >+ description="Add a mapping associated with the Wrapper." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="mapping" >+ description="The new wrapper mapping" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="findInitParameters" >+ description="Return the names of all defined initialization parameters for this servlet." >+ impact="INFO" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findMappings" >+ description="Return the mappings associated with this wrapper" >+ impact="INFO" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="findMappingObject" >+ description="Return an object which may be utilized for mapping to this component" >+ impact="INFO" >+ returnType="org.apache.catalina.Wrapper"> >+ </operation> >+ >+ <operation name="findSecurityReference" >+ description="Return the security role link for the specified security role reference name." >+ impact="ACTION" >+ returnType="java.lang.String"> >+ <parameter name="name" >+ description="Security role reference used within this servle" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="findSecurityReferences" >+ description="Return the set of security role reference names associated with this servlet" >+ impact="INFO" >+ returnType="[Ljava.lang.String;"> >+ </operation> >+ >+ <operation name="removeInitParameter" >+ description="Remove the specified initialization parameter from this servlet." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="Name of the initialization parameter to remove" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeLifecycleListeners" >+ description="Removes lifecycle listeners of given class type from this Wrapper" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="listener" >+ description="Type(classname) of the lifecycle listeners to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeMapping" >+ description="Remove a mapping associated with the wrapper." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="mapping" >+ description="The pattern to remove" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeSecurityReference" >+ description="Remove any security role reference for the specified role name." >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="name" >+ description="Security role used within this servlet to be removeds" >+ type="java.lang.String"/> >+ </operation> >+ >+ <operation name="removeValve" >+ description="Remove a valve from this Wrapper" >+ impact="ACTION" >+ returnType="void"> >+ <parameter name="valveName" >+ description="Objectname of the valve to be removed" >+ type="java.lang.String"/> >+ </operation> >+ >+ </mbean> >+ >+ <mbean name="StandardWrapperValve" >+ description="Valve that implements the default basic behavior for the StandardWrapper container implementation" >+ domain="Catalina" >+ group="Valve" >+ type="org.apache.catalina.core.StandardWrapperValve"> >+ >+ <attribute name="asyncSupported" >+ description="Does this valve support async reporting?" >+ type="boolean"/> >+ >+ <attribute name="className" >+ description="Fully qualified class name of the managed object" >+ type="java.lang.String" >+ writeable="false"/> >+ >+ <attribute name="stateName" >+ description="The name of the LifecycleState that this component is currently in" >+ type="java.lang.String" >+ writeable="false"/> >+ </mbean> >+ >+</mbeans-descriptors> >diff --git a/java/org/apache/catalina/startup/ContextConfig.java b/java/org/apache/catalina/startup/ContextConfig.java >index c1d5175..8997531 100644 >--- a/java/org/apache/catalina/startup/ContextConfig.java >+++ b/java/org/apache/catalina/startup/ContextConfig.java >@@ -126,12 +126,6 @@ public class ContextConfig > protected static final LoginConfig DUMMY_LOGIN_CONFIG = > new LoginConfig("NONE", null, null, null); > >- /** >- * The <code>Digester</code> we will use to process web application >- * context files. >- */ >- protected static Digester contextDigester = null; >- > > /** > * The set of Authenticators that we know how to configure. The key is >@@ -142,32 +136,6 @@ public class ContextConfig > > > /** >- * The <code>Digester</code>s available to process web deployment descriptor >- * files. >- */ >- protected static Digester[] webDigesters = new Digester[4]; >- >- >- /** >- * The <code>Digester</code>s available to process web fragment deployment >- * descriptor files. >- */ >- protected static Digester[] webFragmentDigesters = new Digester[4]; >- >- >- /** >- * The <code>Rule</code>s used to parse the web.xml >- */ >- protected static WebRuleSet webRuleSet = new WebRuleSet(false); >- >- >- /** >- * The <code>Rule</code>s used to parse the web-fragment.xml >- */ >- protected static WebRuleSet webFragmentRuleSet = new WebRuleSet(true); >- >- >- /** > * Deployment count. > */ > protected static long deploymentCount = 0L; >@@ -235,12 +203,14 @@ public class ContextConfig > * deployment descriptor files. > */ > protected Digester webDigester = null; >+ protected WebRuleSet webRuleSet = null; > > /** > * The <code>Digester</code> we will use to process web fragment > * deployment descriptor files. > */ > protected Digester webFragmentDigester = null; >+ protected WebRuleSet webFragmentRuleSet = null; > > > // ------------------------------------------------------------- Properties >@@ -484,60 +454,21 @@ public class ContextConfig > > > /** >- * Create (if necessary) and return a Digester configured to process the >+ * Create and return a Digester configured to process the > * web application deployment descriptor (web.xml). > */ > public void createWebXmlDigester(boolean namespaceAware, > boolean validation) { > >- if (!namespaceAware && !validation) { >- if (webDigesters[0] == null) { >- webDigesters[0] = DigesterFactory.newDigester(validation, >- namespaceAware, webRuleSet); >- webFragmentDigesters[0] = DigesterFactory.newDigester(validation, >- namespaceAware, webFragmentRuleSet); >- webDigesters[0].getParser(); >- webFragmentDigesters[0].getParser(); >- } >- webDigester = webDigesters[0]; >- webFragmentDigester = webFragmentDigesters[0]; >- >- } else if (!namespaceAware && validation) { >- if (webDigesters[1] == null) { >- webDigesters[1] = DigesterFactory.newDigester(validation, >- namespaceAware, webRuleSet); >- webFragmentDigesters[1] = DigesterFactory.newDigester(validation, >- namespaceAware, webFragmentRuleSet); >- webDigesters[1].getParser(); >- webFragmentDigesters[1].getParser(); >- } >- webDigester = webDigesters[1]; >- webFragmentDigester = webFragmentDigesters[1]; >- >- } else if (namespaceAware && !validation) { >- if (webDigesters[2] == null) { >- webDigesters[2] = DigesterFactory.newDigester(validation, >- namespaceAware, webRuleSet); >- webFragmentDigesters[2] = DigesterFactory.newDigester(validation, >- namespaceAware, webFragmentRuleSet); >- webDigesters[2].getParser(); >- webFragmentDigesters[2].getParser(); >- } >- webDigester = webDigesters[2]; >- webFragmentDigester = webFragmentDigesters[2]; >- >- } else { >- if (webDigesters[3] == null) { >- webDigesters[3] = DigesterFactory.newDigester(validation, >- namespaceAware, webRuleSet); >- webFragmentDigesters[3] = DigesterFactory.newDigester(validation, >- namespaceAware, webFragmentRuleSet); >- webDigesters[3].getParser(); >- webFragmentDigesters[3].getParser(); >- } >- webDigester = webDigesters[3]; >- webFragmentDigester = webFragmentDigesters[3]; >- } >+ webRuleSet = new WebRuleSet(false); >+ webDigester = DigesterFactory.newDigester(validation, >+ namespaceAware, webRuleSet); >+ webDigester.getParser(); >+ >+ webFragmentRuleSet = new WebRuleSet(true); >+ webFragmentDigester = DigesterFactory.newDigester(validation, >+ namespaceAware, webFragmentRuleSet); >+ webFragmentDigester.getParser(); > } > > >@@ -575,7 +506,7 @@ public class ContextConfig > /** > * Process the default configuration file, if it exists. > */ >- protected void contextConfig() { >+ protected void contextConfig(Digester digester) { > > // Open the default context.xml file, if it exists > if( defaultContextXml==null && context instanceof StandardContext ) { >@@ -592,7 +523,7 @@ public class ContextConfig > if (defaultContextFile.exists()) { > try { > URL defaultContextUrl = defaultContextFile.toURI().toURL(); >- processContextConfig(defaultContextUrl); >+ processContextConfig(digester, defaultContextUrl); > } catch (MalformedURLException e) { > log.error(sm.getString( > "contextConfig.badUrl", defaultContextFile), e); >@@ -604,7 +535,7 @@ public class ContextConfig > if (hostContextFile.exists()) { > try { > URL hostContextUrl = hostContextFile.toURI().toURL(); >- processContextConfig(hostContextUrl); >+ processContextConfig(digester, hostContextUrl); > } catch (MalformedURLException e) { > log.error(sm.getString( > "contextConfig.badUrl", hostContextFile), e); >@@ -612,7 +543,7 @@ public class ContextConfig > } > } > if (context.getConfigFile() != null) >- processContextConfig(context.getConfigFile()); >+ processContextConfig(digester, context.getConfigFile()); > > } > >@@ -620,7 +551,7 @@ public class ContextConfig > /** > * Process a context.xml. > */ >- protected void processContextConfig(URL contextXml) { >+ protected void processContextConfig(Digester digester, URL contextXml) { > > if (log.isDebugEnabled()) > log.debug("Processing context [" + context.getName() >@@ -646,44 +577,42 @@ public class ContextConfig > > if (source == null) > return; >- synchronized (contextDigester) { >- try { >- source.setByteStream(stream); >- contextDigester.setClassLoader(this.getClass().getClassLoader()); >- contextDigester.setUseContextClassLoader(false); >- contextDigester.push(context.getParent()); >- contextDigester.push(context); >- XmlErrorHandler errorHandler = new XmlErrorHandler(); >- contextDigester.setErrorHandler(errorHandler); >- contextDigester.parse(source); >- if (errorHandler.getWarnings().size() > 0 || >- errorHandler.getErrors().size() > 0) { >- errorHandler.logFindings(log, contextXml.toString()); >- ok = false; >- } >- if (log.isDebugEnabled()) >- log.debug("Successfully processed context [" + context.getName() >- + "] configuration file [" + contextXml + "]"); >- } catch (SAXParseException e) { >- log.error(sm.getString("contextConfig.contextParse", >- context.getName()), e); >- log.error(sm.getString("contextConfig.defaultPosition", >- "" + e.getLineNumber(), >- "" + e.getColumnNumber())); >- ok = false; >- } catch (Exception e) { >- log.error(sm.getString("contextConfig.contextParse", >- context.getName()), e); >+ >+ try { >+ source.setByteStream(stream); >+ digester.setClassLoader(this.getClass().getClassLoader()); >+ digester.setUseContextClassLoader(false); >+ digester.push(context.getParent()); >+ digester.push(context); >+ XmlErrorHandler errorHandler = new XmlErrorHandler(); >+ digester.setErrorHandler(errorHandler); >+ digester.parse(source); >+ if (errorHandler.getWarnings().size() > 0 || >+ errorHandler.getErrors().size() > 0) { >+ errorHandler.logFindings(log, contextXml.toString()); > ok = false; >- } finally { >- contextDigester.reset(); >- try { >- if (stream != null) { >- stream.close(); >- } >- } catch (IOException e) { >- log.error(sm.getString("contextConfig.contextClose"), e); >+ } >+ if (log.isDebugEnabled()) >+ log.debug("Successfully processed context [" + context.getName() >+ + "] configuration file [" + contextXml + "]"); >+ } catch (SAXParseException e) { >+ log.error(sm.getString("contextConfig.contextParse", >+ context.getName()), e); >+ log.error(sm.getString("contextConfig.defaultPosition", >+ "" + e.getLineNumber(), >+ "" + e.getColumnNumber())); >+ ok = false; >+ } catch (Exception e) { >+ log.error(sm.getString("contextConfig.contextParse", >+ context.getName()), e); >+ ok = false; >+ } finally { >+ try { >+ if (stream != null) { >+ stream.close(); > } >+ } catch (IOException e) { >+ log.error(sm.getString("contextConfig.contextClose"), e); > } > } > } >@@ -836,17 +765,15 @@ public class ContextConfig > protected void init() { > // Called from StandardContext.init() > >- if (contextDigester == null){ >- contextDigester = createContextDigester(); >- contextDigester.getParser(); >- } >+ Digester contextDigester = createContextDigester(); >+ contextDigester.getParser(); > > if (log.isDebugEnabled()) > log.debug(sm.getString("contextConfig.init")); > context.setConfigured(false); > ok = true; > >- contextConfig(); >+ contextConfig(contextDigester); > > createWebXmlDigester(context.getXmlNamespaceAware(), > context.getXmlValidation()); >@@ -1229,7 +1156,7 @@ public class ContextConfig > defaults.add(getDefaultWebXmlFragment()); > > WebXml webXml = createWebXml(); >- >+ > // Parse context level web.xml > InputSource contextWebXml = getContextWebXmlSource(); > parseWebXml(contextWebXml, webXml, false); >@@ -1802,9 +1729,6 @@ public class ContextConfig > > XmlErrorHandler handler = new XmlErrorHandler(); > >- // Web digesters and rulesets are shared between contexts but are not >- // thread safe. Whilst there should only be one thread at a time >- // processing a config, play safe and sync. > Digester digester; > WebRuleSet ruleSet; > if (fragment) { >@@ -1815,41 +1739,36 @@ public class ContextConfig > ruleSet = webRuleSet; > } > >- // Sync on the ruleSet since the same ruleSet is shared across all four >- // digesters >- synchronized(ruleSet) { >- >- digester.push(dest); >- digester.setErrorHandler(handler); >- >- if(log.isDebugEnabled()) { >- log.debug(sm.getString("contextConfig.applicationStart", >- source.getSystemId())); >- } >+ digester.push(dest); >+ digester.setErrorHandler(handler); >+ >+ if(log.isDebugEnabled()) { >+ log.debug(sm.getString("contextConfig.applicationStart", >+ source.getSystemId())); >+ } > >- try { >- digester.parse(source); >+ try { >+ digester.parse(source); > >- if (handler.getWarnings().size() > 0 || >- handler.getErrors().size() > 0) { >- ok = false; >- handler.logFindings(log, source.getSystemId()); >- } >- } catch (SAXParseException e) { >- log.error(sm.getString("contextConfig.applicationParse", >- source.getSystemId()), e); >- log.error(sm.getString("contextConfig.applicationPosition", >- "" + e.getLineNumber(), >- "" + e.getColumnNumber())); >- ok = false; >- } catch (Exception e) { >- log.error(sm.getString("contextConfig.applicationParse", >- source.getSystemId()), e); >+ if (handler.getWarnings().size() > 0 || >+ handler.getErrors().size() > 0) { > ok = false; >- } finally { >- digester.reset(); >- ruleSet.recycle(); >- } >+ handler.logFindings(log, source.getSystemId()); >+ } >+ } catch (SAXParseException e) { >+ log.error(sm.getString("contextConfig.applicationParse", >+ source.getSystemId()), e); >+ log.error(sm.getString("contextConfig.applicationPosition", >+ "" + e.getLineNumber(), >+ "" + e.getColumnNumber())); >+ ok = false; >+ } catch (Exception e) { >+ log.error(sm.getString("contextConfig.applicationParse", >+ source.getSystemId()), e); >+ ok = false; >+ } finally { >+ digester.reset(); >+ ruleSet.recycle(); > } > } > >@@ -2239,7 +2158,8 @@ public class ContextConfig > > /** > * process filter annotation and merge with existing one! >- * FIXME: refactoring method to long and has redundant subroutines with processAnnotationWebServlet! >+ * FIXME: refactoring method too long and has redundant subroutines with >+ * processAnnotationWebServlet! > * @param className > * @param ae > * @param fragment >diff --git a/java/org/apache/catalina/startup/HostConfig.java b/java/org/apache/catalina/startup/HostConfig.java >index faa033d..4b0be0b 100644 >--- a/java/org/apache/catalina/startup/HostConfig.java >+++ b/java/org/apache/catalina/startup/HostConfig.java >@@ -1,1456 +1,1543 @@ >-/* >- * 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.startup; >- >- >-import java.io.BufferedOutputStream; >-import java.io.File; >-import java.io.FileInputStream; >-import java.io.FileOutputStream; >-import java.io.IOException; >-import java.io.InputStream; >-import java.io.OutputStream; >-import java.net.URL; >-import java.util.ArrayList; >-import java.util.HashMap; >-import java.util.HashSet; >-import java.util.LinkedHashMap; >-import java.util.List; >-import java.util.Locale; >-import java.util.Set; >-import java.util.jar.JarEntry; >-import java.util.jar.JarFile; >-import java.util.regex.Matcher; >-import java.util.regex.Pattern; >- >-import javax.management.ObjectName; >- >-import org.apache.catalina.Container; >-import org.apache.catalina.Context; >-import org.apache.catalina.Engine; >-import org.apache.catalina.Globals; >-import org.apache.catalina.Host; >-import org.apache.catalina.Lifecycle; >-import org.apache.catalina.LifecycleEvent; >-import org.apache.catalina.LifecycleListener; >-import org.apache.catalina.core.ContainerBase; >-import org.apache.catalina.core.StandardHost; >-import org.apache.catalina.util.ContextName; >-import org.apache.catalina.util.IOTools; >-import org.apache.juli.logging.Log; >-import org.apache.juli.logging.LogFactory; >-import org.apache.tomcat.util.ExceptionUtils; >-import org.apache.tomcat.util.digester.Digester; >-import org.apache.tomcat.util.modeler.Registry; >-import org.apache.tomcat.util.res.StringManager; >- >- >-/** >- * Startup event listener for a <b>Host</b> that configures the properties >- * of that Host, and the associated defined contexts. >- * >- * @author Craig R. McClanahan >- * @author Remy Maucherat >- * @version $Id$ >- */ >-public class HostConfig >- implements LifecycleListener { >- >- private static final Log log = LogFactory.getLog( HostConfig.class ); >- >- // ----------------------------------------------------- Instance Variables >- >- >- /** >- * Config base. >- */ >- protected File configBase = null; >- >- >- /** >- * The Java class name of the Context configuration class we should use. >- */ >- protected String configClass = "org.apache.catalina.startup.ContextConfig"; >- >- >- /** >- * The Java class name of the Context implementation we should use. >- */ >- protected String contextClass = "org.apache.catalina.core.StandardContext"; >- >- >- /** >- * The Host we are associated with. >- */ >- protected Host host = null; >- >- >- /** >- * The JMX ObjectName of this component. >- */ >- protected ObjectName oname = null; >- >- >- /** >- * The string resources for this package. >- */ >- protected static final StringManager sm = >- StringManager.getManager(Constants.Package); >- >- >- /** >- * Should we deploy XML Context config files packaged with WAR files and >- * directories? >- */ >- protected boolean deployXML = false; >- >- >- /** >- * Should XML files be copied to $CATALINA_BASE/conf/<engine>/<host> by >- * default when a web application is deployed? >- */ >- protected boolean copyXML = false; >- >- >- /** >- * Should we unpack WAR files when auto-deploying applications in the >- * <code>appBase</code> directory? >- */ >- protected boolean unpackWARs = false; >- >- >- /** >- * Map of deployed applications. >- */ >- protected HashMap<String, DeployedApplication> deployed = >- new HashMap<String, DeployedApplication>(); >- >- >- /** >- * List of applications which are being serviced, and shouldn't be >- * deployed/undeployed/redeployed at the moment. >- */ >- protected ArrayList<String> serviced = new ArrayList<String>(); >- >- >- /** >- * The <code>Digester</code> instance used to parse context descriptors. >- */ >- protected static Digester digester = createDigester(); >- >- /** >- * The list of Wars in the appBase to be ignored because they are invalid >- * (e.g. contain /../ sequences). >- */ >- protected Set<String> invalidWars = new HashSet<String>(); >- >- // ------------------------------------------------------------- Properties >- >- >- /** >- * Return the Context configuration class name. >- */ >- public String getConfigClass() { >- >- return (this.configClass); >- >- } >- >- >- /** >- * Set the Context configuration class name. >- * >- * @param configClass The new Context configuration class name. >- */ >- public void setConfigClass(String configClass) { >- >- this.configClass = configClass; >- >- } >- >- >- /** >- * Return the Context implementation class name. >- */ >- public String getContextClass() { >- >- return (this.contextClass); >- >- } >- >- >- /** >- * Set the Context implementation class name. >- * >- * @param contextClass The new Context implementation class name. >- */ >- public void setContextClass(String contextClass) { >- >- this.contextClass = contextClass; >- >- } >- >- >- /** >- * Return the deploy XML config file flag for this component. >- */ >- public boolean isDeployXML() { >- >- return (this.deployXML); >- >- } >- >- >- /** >- * Set the deploy XML config file flag for this component. >- * >- * @param deployXML The new deploy XML flag >- */ >- public void setDeployXML(boolean deployXML) { >- >- this.deployXML= deployXML; >- >- } >- >- >- /** >- * Return the copy XML config file flag for this component. >- */ >- public boolean isCopyXML() { >- >- return (this.copyXML); >- >- } >- >- >- /** >- * Set the copy XML config file flag for this component. >- * >- * @param copyXML The new copy XML flag >- */ >- public void setCopyXML(boolean copyXML) { >- >- this.copyXML= copyXML; >- >- } >- >- >- /** >- * Return the unpack WARs flag. >- */ >- public boolean isUnpackWARs() { >- >- return (this.unpackWARs); >- >- } >- >- >- /** >- * Set the unpack WARs flag. >- * >- * @param unpackWARs The new unpack WARs flag >- */ >- public void setUnpackWARs(boolean unpackWARs) { >- >- this.unpackWARs = unpackWARs; >- >- } >- >- >- // --------------------------------------------------------- Public Methods >- >- >- /** >- * Process the START event for an associated Host. >- * >- * @param event The lifecycle event that has occurred >- */ >- @Override >- public void lifecycleEvent(LifecycleEvent event) { >- >- if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) >- check(); >- >- // Identify the host we are associated with >- try { >- host = (Host) event.getLifecycle(); >- if (host instanceof StandardHost) { >- setCopyXML(((StandardHost) host).isCopyXML()); >- setDeployXML(((StandardHost) host).isDeployXML()); >- setUnpackWARs(((StandardHost) host).isUnpackWARs()); >- } >- } catch (ClassCastException e) { >- log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e); >- return; >- } >- >- // Process the event that has occurred >- if (event.getType().equals(Lifecycle.START_EVENT)) >- start(); >- else if (event.getType().equals(Lifecycle.STOP_EVENT)) >- stop(); >- >- } >- >- >- /** >- * Add a serviced application to the list. >- */ >- public synchronized void addServiced(String name) { >- serviced.add(name); >- } >- >- >- /** >- * Is application serviced ? >- * @return state of the application >- */ >- public synchronized boolean isServiced(String name) { >- return (serviced.contains(name)); >- } >- >- >- /** >- * Removed a serviced application from the list. >- */ >- public synchronized void removeServiced(String name) { >- serviced.remove(name); >- } >- >- >- /** >- * Get the instant where an application was deployed. >- * @return 0L if no application with that name is deployed, or the instant >- * on which the application was deployed >- */ >- public long getDeploymentTime(String name) { >- DeployedApplication app = deployed.get(name); >- if (app == null) { >- return 0L; >- } >- >- return app.timestamp; >- } >- >- >- /** >- * Has the specified application been deployed? Note applications defined >- * in server.xml will not have been deployed. >- * @return <code>true</code> if the application has been deployed and >- * <code>false</code> if the application has not been deployed or does not >- * exist >- */ >- public boolean isDeployed(String name) { >- DeployedApplication app = deployed.get(name); >- if (app == null) { >- return false; >- } >- >- return true; >- } >- >- >- // ------------------------------------------------------ Protected Methods >- >- >- /** >- * Create the digester which will be used to parse context config files. >- */ >- protected static Digester createDigester() { >- Digester digester = new Digester(); >- digester.setValidating(false); >- // Add object creation rule >- digester.addObjectCreate("Context", "org.apache.catalina.core.StandardContext", >- "className"); >- // Set the properties on that object (it doesn't matter if extra >- // properties are set) >- digester.addSetProperties("Context"); >- return (digester); >- } >- >- protected File returnCanonicalPath(String path) { >- File file = new File(path); >- File base = new File(System.getProperty(Globals.CATALINA_BASE_PROP)); >- if (!file.isAbsolute()) >- file = new File(base,path); >- try { >- return file.getCanonicalFile(); >- } catch (IOException e) { >- return file; >- } >- } >- >- >- /** >- * Return a File object representing the "configuration root" directory >- * for our associated Host. >- */ >- protected File configBase() { >- >- if (configBase != null) { >- return configBase; >- } >- >- if (host.getXmlBase()!=null) { >- configBase = returnCanonicalPath(host.getXmlBase()); >- } else { >- StringBuilder xmlDir = new StringBuilder("conf"); >- Container parent = host.getParent(); >- if (parent instanceof Engine) { >- xmlDir.append('/'); >- xmlDir.append(parent.getName()); >- } >- xmlDir.append('/'); >- xmlDir.append(host.getName()); >- configBase = returnCanonicalPath(xmlDir.toString()); >- } >- return (configBase); >- >- } >- >- /** >- * Get the name of the configBase. >- * For use with JMX management. >- */ >- public String getConfigBaseName() { >- return configBase().getAbsolutePath(); >- } >- >- >- /** >- * Deploy applications for any directories or WAR files that are found >- * in our "application root" directory. >- */ >- protected void deployApps() { >- >- File appBase = host.getAppBaseFile(); >- File configBase = configBase(); >- String[] filteredAppPaths = filterAppPaths(appBase.list()); >- // Deploy XML descriptors from configBase >- deployDescriptors(configBase, configBase.list()); >- // Deploy WARs, and loop if additional descriptors are found >- deployWARs(appBase, filteredAppPaths); >- // Deploy expanded folders >- deployDirectories(appBase, filteredAppPaths); >- >- } >- >- >- /** >- * Filter the list of application file paths to remove those that match >- * the regular expression defined by {@link Host#getDeployIgnore()}. >- * >- * @param unfilteredAppPaths The list of application paths to filtert >- * >- * @return The filtered list of application paths >- */ >- protected String[] filterAppPaths(String[] unfilteredAppPaths) { >- Pattern filter = host.getDeployIgnorePattern(); >- if (filter == null) { >- return unfilteredAppPaths; >- } >- >- List<String> filteredList = new ArrayList<String>(); >- Matcher matcher = null; >- for (String appPath : unfilteredAppPaths) { >- if (matcher == null) { >- matcher = filter.matcher(appPath); >- } else { >- matcher.reset(appPath); >- } >- if (matcher.matches()) { >- if (log.isDebugEnabled()) { >- log.debug(sm.getString("hostConfig.ignorePath", appPath)); >- } >- } else { >- filteredList.add(appPath); >- } >- } >- return filteredList.toArray(new String[filteredList.size()]); >- } >- >- >- /** >- * Deploy applications for any directories or WAR files that are found >- * in our "application root" directory. >- */ >- protected void deployApps(String name) { >- >- File appBase = host.getAppBaseFile(); >- File configBase = configBase(); >- ContextName cn = new ContextName(name); >- String baseName = cn.getBaseName(); >- >- // Deploy XML descriptors from configBase >- File xml = new File(configBase, baseName + ".xml"); >- if (xml.exists()) >- deployDescriptor(cn, xml); >- // Deploy WARs, and loop if additional descriptors are found >- File war = new File(appBase, baseName + ".war"); >- if (war.exists()) >- deployWAR(cn, war); >- // Deploy expanded folders >- File dir = new File(appBase, baseName); >- if (dir.exists()) >- deployDirectory(cn, dir); >- } >- >- >- /** >- * Deploy XML context descriptors. >- */ >- protected void deployDescriptors(File configBase, String[] files) { >- >- if (files == null) >- return; >- >- for (int i = 0; i < files.length; i++) { >- File contextXml = new File(configBase, files[i]); >- >- if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".xml")) { >- ContextName cn = new ContextName(files[i]); >- String name = cn.getName(); >- >- if (isServiced(name)) >- continue; >- >- deployDescriptor(cn, contextXml); >- } >- } >- } >- >- >- /** >- * @param cn >- * @param contextXml >- */ >- protected void deployDescriptor(ContextName cn, File contextXml) { >- if (deploymentExists(cn.getName())) { >- return; >- } >- >- DeployedApplication deployedApp = new DeployedApplication(cn.getName()); >- >- // Assume this is a configuration descriptor and deploy it >- if(log.isInfoEnabled()) { >- log.info(sm.getString("hostConfig.deployDescriptor", >- contextXml.getAbsolutePath())); >- } >- >- Context context = null; >- try { >- synchronized (digester) { >- try { >- context = (Context) digester.parse(contextXml); >- if (context == null) { >- log.error(sm.getString( >- "hostConfig.deployDescriptor.error", >- contextXml.getAbsolutePath())); >- return; >- } >- } finally { >- digester.reset(); >- } >- } >- >- Class<?> clazz = Class.forName(host.getConfigClass()); >- LifecycleListener listener = >- (LifecycleListener) clazz.newInstance(); >- context.addLifecycleListener(listener); >- >- context.setConfigFile(contextXml.toURI().toURL()); >- context.setName(cn.getName()); >- context.setPath(cn.getPath()); >- context.setWebappVersion(cn.getVersion()); >- // Add the associated docBase to the redeployed list if it's a WAR >- boolean isExternalWar = false; >- boolean isExternal = false; >- if (context.getDocBase() != null) { >- File docBase = new File(context.getDocBase()); >- if (!docBase.isAbsolute()) { >- docBase = new File(host.getAppBaseFile(), context.getDocBase()); >- } >- // If external docBase, register .xml as redeploy first >- if (!docBase.getCanonicalPath().startsWith( >- host.getAppBaseFile().getAbsolutePath() + File.separator)) { >- isExternal = true; >- deployedApp.redeployResources.put( >- contextXml.getAbsolutePath(), >- Long.valueOf(contextXml.lastModified())); >- deployedApp.redeployResources.put(docBase.getAbsolutePath(), >- Long.valueOf(docBase.lastModified())); >- if (docBase.getAbsolutePath().toLowerCase(Locale.ENGLISH).endsWith(".war")) { >- isExternalWar = true; >- } >- } else { >- log.warn(sm.getString("hostConfig.deployDescriptor.localDocBaseSpecified", >- docBase)); >- // Ignore specified docBase >- context.setDocBase(null); >- } >- } >- host.addChild(context); >- // Get paths for WAR and expanded WAR in appBase >- >- // default to appBase dir + name >- File expandedDocBase = new File(host.getAppBaseFile(), cn.getBaseName()); >- if (context.getDocBase() != null) { >- // first assume docBase is absolute >- expandedDocBase = new File(context.getDocBase()); >- if (!expandedDocBase.isAbsolute()) { >- // if docBase specified and relative, it must be relative to appBase >- expandedDocBase = new File(host.getAppBaseFile(), context.getDocBase()); >- } >- } >- // Add the eventual unpacked WAR and all the resources which will be >- // watched inside it >- if (isExternalWar && unpackWARs) { >- deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), >- Long.valueOf(expandedDocBase.lastModified())); >- deployedApp.redeployResources.put(contextXml.getAbsolutePath(), >- Long.valueOf(contextXml.lastModified())); >- addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), context); >- } else { >- // Find an existing matching war and expanded folder >- if (!isExternal) { >- File warDocBase = new File(expandedDocBase.getAbsolutePath() + ".war"); >- if (warDocBase.exists()) { >- deployedApp.redeployResources.put(warDocBase.getAbsolutePath(), >- Long.valueOf(warDocBase.lastModified())); >- } >- } >- if (expandedDocBase.exists()) { >- deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), >- Long.valueOf(expandedDocBase.lastModified())); >- addWatchedResources(deployedApp, >- expandedDocBase.getAbsolutePath(), context); >- } else { >- addWatchedResources(deployedApp, null, context); >- } >- // Add the context XML to the list of files which should trigger a redeployment >- if (!isExternal) { >- deployedApp.redeployResources.put( >- contextXml.getAbsolutePath(), >- Long.valueOf(contextXml.lastModified())); >- } >- } >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- log.error(sm.getString("hostConfig.deployDescriptor.error", >- contextXml.getAbsolutePath()), t); >- } >- >- if (context != null && host.findChild(context.getName()) != null) { >- deployed.put(context.getName(), deployedApp); >- } >- } >- >- >- /** >- * Deploy WAR files. >- */ >- protected void deployWARs(File appBase, String[] files) { >- >- if (files == null) >- return; >- >- for (int i = 0; i < files.length; i++) { >- >- if (files[i].equalsIgnoreCase("META-INF")) >- continue; >- if (files[i].equalsIgnoreCase("WEB-INF")) >- continue; >- File war = new File(appBase, files[i]); >- if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".war") && war.isFile() >- && !invalidWars.contains(files[i]) ) { >- >- ContextName cn = new ContextName(files[i]); >- >- // Check for WARs with /../ /./ or similar sequences in the name >- if (!validateContextPath(appBase, cn.getBaseName())) { >- log.error(sm.getString( >- "hostConfig.illegalWarName", files[i])); >- invalidWars.add(files[i]); >- continue; >- } >- >- if (isServiced(cn.getName())) >- continue; >- >- deployWAR(cn, war); >- } >- } >- } >- >- >- private boolean validateContextPath(File appBase, String contextPath) { >- // More complicated than the ideal as the canonical path may or may >- // not end with File.separator for a directory >- >- StringBuilder docBase; >- String canonicalDocBase = null; >- >- try { >- String canonicalAppBase = appBase.getCanonicalPath(); >- docBase = new StringBuilder(canonicalAppBase); >- if (canonicalAppBase.endsWith(File.separator)) { >- docBase.append(contextPath.substring(1).replace( >- '/', File.separatorChar)); >- } else { >- docBase.append(contextPath.replace('/', File.separatorChar)); >- } >- // At this point docBase should be canonical but will not end >- // with File.separator >- >- canonicalDocBase = >- (new File(docBase.toString())).getCanonicalPath(); >- >- // If the canonicalDocBase ends with File.separator, add one to >- // docBase before they are compared >- if (canonicalDocBase.endsWith(File.separator)) { >- docBase.append(File.separator); >- } >- } catch (IOException ioe) { >- return false; >- } >- >- // Compare the two. If they are not the same, the contextPath must >- // have /../ like sequences in it >- return canonicalDocBase.equals(docBase.toString()); >- } >- >- /** >- * @param cn >- * @param war >- */ >- protected void deployWAR(ContextName cn, File war) { >- >- if (deploymentExists(cn.getName())) >- return; >- >- // Checking for a nested /META-INF/context.xml >- JarFile jar = null; >- JarEntry entry = null; >- InputStream istream = null; >- BufferedOutputStream ostream = null; >- File xml; >- if (copyXML) { >- xml = new File(configBase(), cn.getBaseName() + ".xml"); >- } else { >- xml = new File(host.getAppBaseFile(), >- cn.getBaseName() + "/META-INF/context.xml"); >- } >- boolean xmlInWar = false; >- >- if (deployXML && !xml.exists()) { >- try { >- jar = new JarFile(war); >- entry = jar.getJarEntry(Constants.ApplicationContextXml); >- if (entry != null) { >- xmlInWar = true; >- } >- if ((copyXML || unpackWARs) && xmlInWar) { >- istream = jar.getInputStream(entry); >- >- ostream = >- new BufferedOutputStream >- (new FileOutputStream(xml), 1024); >- byte buffer[] = new byte[1024]; >- while (true) { >- int n = istream.read(buffer); >- if (n < 0) { >- break; >- } >- ostream.write(buffer, 0, n); >- } >- ostream.flush(); >- ostream.close(); >- ostream = null; >- istream.close(); >- istream = null; >- } >- } catch (IOException e) { >- /* Ignore */ >- } finally { >- if (ostream != null) { >- try { >- ostream.close(); >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- } >- ostream = null; >- } >- if (istream != null) { >- try { >- istream.close(); >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- } >- istream = null; >- } >- entry = null; >- if (jar != null) { >- try { >- jar.close(); >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- } >- jar = null; >- } >- } >- } >- >- DeployedApplication deployedApp = new DeployedApplication(cn.getName()); >- >- // Deploy the application in this WAR file >- if(log.isInfoEnabled()) >- log.info(sm.getString("hostConfig.deployWar", >- war.getAbsolutePath())); >- >- try { >- Context context = null; >- if (deployXML && xml.exists()) { >- synchronized (digester) { >- try { >- context = (Context) digester.parse(xml); >- if (context == null) { >- log.error(sm.getString( >- "hostConfig.deployDescriptor.error", >- war.getAbsolutePath())); >- return; >- } >- } finally { >- digester.reset(); >- } >- } >- context.setConfigFile(xml.toURI().toURL()); >- } else if (deployXML && xmlInWar) { >- synchronized (digester) { >- try { >- jar = new JarFile(war); >- entry = >- jar.getJarEntry(Constants.ApplicationContextXml); >- istream = jar.getInputStream(entry); >- context = (Context) digester.parse(istream); >- >- if (context == null) { >- log.error(sm.getString( >- "hostConfig.deployDescriptor.error", >- war.getAbsolutePath())); >- return; >- } >- context.setConfigFile(new URL("jar:" + >- war.toURI().toString() + "!/" + >- Constants.ApplicationContextXml)); >- } finally { >- if (istream != null) { >- try { >- istream.close(); >- } catch (IOException e) { >- /* Ignore */ >- } >- istream = null; >- } >- entry = null; >- if (jar != null) { >- try { >- jar.close(); >- } catch (IOException e) { >- /* Ignore */ >- } >- jar = null; >- } >- digester.reset(); >- } >- } >- } else { >- context = (Context) Class.forName(contextClass).newInstance(); >- } >- >- // Populate redeploy resources with the WAR file >- deployedApp.redeployResources.put >- (war.getAbsolutePath(), Long.valueOf(war.lastModified())); >- >- if (deployXML && xml.exists() && copyXML) { >- deployedApp.redeployResources.put(xml.getAbsolutePath(), >- Long.valueOf(xml.lastModified())); >- } >- >- Class<?> clazz = Class.forName(host.getConfigClass()); >- LifecycleListener listener = >- (LifecycleListener) clazz.newInstance(); >- context.addLifecycleListener(listener); >- >- context.setName(cn.getName()); >- context.setPath(cn.getPath()); >- context.setWebappVersion(cn.getVersion()); >- context.setDocBase(cn.getBaseName() + ".war"); >- host.addChild(context); >- // If we're unpacking WARs, the docBase will be mutated after >- // starting the context >- if (unpackWARs && (context.getDocBase() != null)) { >- File docBase = new File(host.getAppBaseFile(), cn.getBaseName()); >- deployedApp.redeployResources.put(docBase.getAbsolutePath(), >- Long.valueOf(docBase.lastModified())); >- addWatchedResources(deployedApp, docBase.getAbsolutePath(), >- context); >- if (deployXML && !copyXML && (xmlInWar || xml.exists())) { >- deployedApp.redeployResources.put(xml.getAbsolutePath(), >- Long.valueOf(xml.lastModified())); >- } >- } else { >- addWatchedResources(deployedApp, null, context); >- } >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- log.error(sm.getString("hostConfig.deployWar.error", >- war.getAbsolutePath()), t); >- } >- >- deployed.put(cn.getName(), deployedApp); >- } >- >- >- /** >- * Deploy directories. >- */ >- protected void deployDirectories(File appBase, String[] files) { >- >- if (files == null) >- return; >- >- for (int i = 0; i < files.length; i++) { >- >- if (files[i].equalsIgnoreCase("META-INF")) >- continue; >- if (files[i].equalsIgnoreCase("WEB-INF")) >- continue; >- File dir = new File(appBase, files[i]); >- if (dir.isDirectory()) { >- ContextName cn = new ContextName(files[i]); >- >- if (isServiced(cn.getName())) >- continue; >- >- deployDirectory(cn, dir); >- } >- } >- } >- >- >- /** >- * @param cn >- * @param dir >- */ >- protected void deployDirectory(ContextName cn, File dir) { >- >- if (deploymentExists(cn.getName())) >- return; >- >- DeployedApplication deployedApp = new DeployedApplication(cn.getName()); >- >- // Deploy the application in this directory >- if( log.isInfoEnabled() ) >- log.info(sm.getString("hostConfig.deployDir", >- dir.getAbsolutePath())); >- try { >- Context context = null; >- File xml = new File(dir, Constants.ApplicationContextXml); >- File xmlCopy = null; >- if (deployXML && xml.exists()) { >- synchronized (digester) { >- try { >- context = (Context) digester.parse(xml); >- if (context == null) { >- log.error(sm.getString( >- "hostConfig.deployDescriptor.error", >- xml)); >- return; >- } >- } finally { >- digester.reset(); >- } >- } >- if (copyXML) { >- xmlCopy = new File(configBase(), cn.getBaseName() + ".xml"); >- InputStream is = null; >- OutputStream os = null; >- try { >- is = new FileInputStream(xml); >- os = new FileOutputStream(xmlCopy); >- IOTools.flow(is, os); >- // Don't catch IOE - let the outer try/catch handle it >- } finally { >- try { >- if (is != null) is.close(); >- } catch (IOException e){ >- // Ignore >- } >- try { >- if (os != null) os.close(); >- } catch (IOException e){ >- // Ignore >- } >- } >- context.setConfigFile(xmlCopy.toURI().toURL()); >- } else { >- context.setConfigFile(xml.toURI().toURL()); >- } >- } else { >- context = (Context) Class.forName(contextClass).newInstance(); >- } >- >- Class<?> clazz = Class.forName(host.getConfigClass()); >- LifecycleListener listener = >- (LifecycleListener) clazz.newInstance(); >- context.addLifecycleListener(listener); >- >- context.setName(cn.getName()); >- context.setPath(cn.getPath()); >- context.setWebappVersion(cn.getVersion()); >- context.setDocBase(cn.getBaseName()); >- host.addChild(context); >- deployedApp.redeployResources.put(dir.getAbsolutePath(), >- Long.valueOf(dir.lastModified())); >- if (deployXML && xml.exists()) { >- if (xmlCopy == null) { >- deployedApp.redeployResources.put( >- xml.getAbsolutePath(), >- Long.valueOf(xml.lastModified())); >- } else { >- deployedApp.redeployResources.put( >- xmlCopy.getAbsolutePath(), >- Long.valueOf(xmlCopy.lastModified())); >- } >- } >- addWatchedResources(deployedApp, dir.getAbsolutePath(), context); >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- log.error(sm.getString("hostConfig.deployDir.error", >- dir.getAbsolutePath()), t); >- } >- >- deployed.put(cn.getName(), deployedApp); >- } >- >- >- /** >- * Check if a webapp is already deployed in this host. >- * >- * @param contextName of the context which will be checked >- */ >- protected boolean deploymentExists(String contextName) { >- return (deployed.containsKey(contextName) || >- (host.findChild(contextName) != null)); >- } >- >- >- /** >- * Add watched resources to the specified Context. >- * @param app HostConfig deployed app >- * @param docBase web app docBase >- * @param context web application context >- */ >- protected void addWatchedResources(DeployedApplication app, String docBase, >- Context context) { >- // FIXME: Feature idea. Add support for patterns (ex: WEB-INF/*, >- // WEB-INF/*.xml), where we would only check if at least one >- // resource is newer than app.timestamp >- File docBaseFile = null; >- if (docBase != null) { >- docBaseFile = new File(docBase); >- if (!docBaseFile.isAbsolute()) { >- docBaseFile = new File(host.getAppBaseFile(), docBase); >- } >- } >- String[] watchedResources = context.findWatchedResources(); >- for (int i = 0; i < watchedResources.length; i++) { >- File resource = new File(watchedResources[i]); >- if (!resource.isAbsolute()) { >- if (docBase != null) { >- resource = new File(docBaseFile, watchedResources[i]); >- } else { >- if(log.isDebugEnabled()) >- log.debug("Ignoring non-existent WatchedResource '" + >- resource.getAbsolutePath() + "'"); >- continue; >- } >- } >- if(log.isDebugEnabled()) >- log.debug("Watching WatchedResource '" + >- resource.getAbsolutePath() + "'"); >- app.reloadResources.put(resource.getAbsolutePath(), >- Long.valueOf(resource.lastModified())); >- } >- } >- >- >- /** >- * Check resources for redeployment and reloading. >- */ >- protected synchronized void checkResources(DeployedApplication app) { >- String[] resources = >- app.redeployResources.keySet().toArray(new String[0]); >- for (int i = 0; i < resources.length; i++) { >- File resource = new File(resources[i]); >- if (log.isDebugEnabled()) >- log.debug("Checking context[" + app.name + >- "] redeploy resource " + resource); >- if (resource.exists()) { >- long lastModified = >- app.redeployResources.get(resources[i]).longValue(); >- if ((!resource.isDirectory()) && >- resource.lastModified() > lastModified) { >- // Undeploy application >- if (log.isInfoEnabled()) >- log.info(sm.getString("hostConfig.undeploy", app.name)); >- ContainerBase context = >- (ContainerBase) host.findChild(app.name); >- try { >- host.removeChild(context); >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- log.warn(sm.getString >- ("hostConfig.context.remove", app.name), t); >- } >- // Delete other redeploy resources >- for (int j = i + 1; j < resources.length; j++) { >- try { >- File current = new File(resources[j]); >- current = current.getCanonicalFile(); >- if ((current.getAbsolutePath().startsWith( >- host.getAppBaseFile().getAbsolutePath() + >- File.separator)) >- || (current.getAbsolutePath().startsWith( >- configBase().getAbsolutePath()))) { >- if (log.isDebugEnabled()) >- log.debug("Delete " + current); >- ExpandWar.delete(current); >- } >- } catch (IOException e) { >- log.warn(sm.getString >- ("hostConfig.canonicalizing", app.name), e); >- } >- } >- deployed.remove(app.name); >- return; >- } >- } else { >- // There is a chance the the resource was only missing >- // temporarily eg renamed during a text editor save >- try { >- Thread.sleep(500); >- } catch (InterruptedException e1) { >- // Ignore >- } >- // Recheck the resource to see if it was really deleted >- if (resource.exists()) { >- continue; >- } >- long lastModified = >- app.redeployResources.get(resources[i]).longValue(); >- if (lastModified == 0L) { >- continue; >- } >- // Undeploy application >- if (log.isInfoEnabled()) >- log.info(sm.getString("hostConfig.undeploy", app.name)); >- ContainerBase context = >- (ContainerBase) host.findChild(app.name); >- try { >- host.removeChild(context); >- } catch (Throwable t) { >- ExceptionUtils.handleThrowable(t); >- log.warn(sm.getString >- ("hostConfig.context.remove", app.name), t); >- } >- // Delete all redeploy resources >- for (int j = i + 1; j < resources.length; j++) { >- try { >- File current = new File(resources[j]); >- current = current.getCanonicalFile(); >- if ((current.getAbsolutePath().startsWith( >- host.getAppBaseFile().getAbsolutePath() + File.separator)) >- || (current.getAbsolutePath().startsWith( >- configBase().getAbsolutePath()))) { >- if (log.isDebugEnabled()) >- log.debug("Delete " + current); >- ExpandWar.delete(current); >- } >- } catch (IOException e) { >- log.warn(sm.getString >- ("hostConfig.canonicalizing", app.name), e); >- } >- } >- // Delete reload resources as well (to remove any remaining .xml >- // descriptor) >- String[] resources2 = >- app.reloadResources.keySet().toArray(new String[0]); >- for (int j = 0; j < resources2.length; j++) { >- try { >- File current = new File(resources2[j]); >- current = current.getCanonicalFile(); >- if ((current.getAbsolutePath().startsWith( >- host.getAppBaseFile().getAbsolutePath() + File.separator)) >- || ((current.getAbsolutePath().startsWith( >- configBase().getAbsolutePath()) >- && (current.getAbsolutePath().endsWith(".xml"))))) { >- if (log.isDebugEnabled()) >- log.debug("Delete " + current); >- ExpandWar.delete(current); >- } >- } catch (IOException e) { >- log.warn(sm.getString >- ("hostConfig.canonicalizing", app.name), e); >- } >- } >- deployed.remove(app.name); >- return; >- } >- } >- resources = app.reloadResources.keySet().toArray(new String[0]); >- for (int i = 0; i < resources.length; i++) { >- File resource = new File(resources[i]); >- if (log.isDebugEnabled()) >- log.debug("Checking context[" + app.name + >- "] reload resource " + resource); >- long lastModified = >- app.reloadResources.get(resources[i]).longValue(); >- if ((!resource.exists() && lastModified != 0L) >- || (resource.lastModified() != lastModified)) { >- // Reload application >- if(log.isInfoEnabled()) >- log.info(sm.getString("hostConfig.reload", app.name)); >- Container context = host.findChild(app.name); >- try { >- // Might not have started if start failed last time >- if (context.getState().isAvailable()) { >- context.stop(); >- } >- } catch (Exception e) { >- log.warn(sm.getString >- ("hostConfig.context.restart", app.name), e); >- } >- // If the context was not started (for example an error >- // in web.xml) we'll still get to try to start >- try { >- context.start(); >- } catch (Exception e) { >- log.warn(sm.getString >- ("hostConfig.context.restart", app.name), e); >- } >- // Update times >- app.reloadResources.put(resources[i], >- Long.valueOf(resource.lastModified())); >- app.timestamp = System.currentTimeMillis(); >- return; >- } >- } >- } >- >- >- /** >- * Process a "start" event for this Host. >- */ >- public void start() { >- >- if (log.isDebugEnabled()) >- log.debug(sm.getString("hostConfig.start")); >- >- try { >- ObjectName hostON = host.getObjectName(); >- oname = new ObjectName >- (hostON.getDomain() + ":type=Deployer,host=" + host.getName()); >- Registry.getRegistry(null, null).registerComponent >- (this, oname, this.getClass().getName()); >- } catch (Exception e) { >- log.error(sm.getString("hostConfig.jmx.register", oname), e); >- } >- >- if (host.getCreateDirs()) { >- File[] dirs = new File[] {host.getAppBaseFile(),configBase()}; >- for (int i=0; i<dirs.length; i++) { >- if (!dirs[i].mkdirs() && !dirs[i].isDirectory()) { >- log.error(sm.getString("hostConfig.createDirs",dirs[i])); >- } >- } >- } >- >- if (!host.getAppBaseFile().isDirectory()) { >- log.error(sm.getString("hostConfig.appBase", host.getName(), >- host.getAppBaseFile().getPath())); >- host.setDeployOnStartup(false); >- host.setAutoDeploy(false); >- } >- >- if (host.getDeployOnStartup()) >- deployApps(); >- >- } >- >- >- /** >- * Process a "stop" event for this Host. >- */ >- public void stop() { >- >- if (log.isDebugEnabled()) >- log.debug(sm.getString("hostConfig.stop")); >- >- if (oname != null) { >- try { >- Registry.getRegistry(null, null).unregisterComponent(oname); >- } catch (Exception e) { >- log.error(sm.getString("hostConfig.jmx.unregister", oname), e); >- } >- } >- oname = null; >- configBase = null; >- >- } >- >- >- /** >- * Check status of all webapps. >- */ >- protected void check() { >- >- if (host.getAutoDeploy()) { >- // Check for resources modification to trigger redeployment >- DeployedApplication[] apps = >- deployed.values().toArray(new DeployedApplication[0]); >- for (int i = 0; i < apps.length; i++) { >- if (!isServiced(apps[i].name)) >- checkResources(apps[i]); >- } >- // Hotdeploy applications >- deployApps(); >- } >- >- } >- >- >- /** >- * Check status of a specific webapp, for use with stuff like management webapps. >- */ >- public void check(String name) { >- DeployedApplication app = deployed.get(name); >- if (app != null) { >- checkResources(app); >- } else { >- deployApps(name); >- } >- } >- >- /** >- * Add a new Context to be managed by us. >- * Entry point for the admin webapp, and other JMX Context controllers. >- */ >- public void manageApp(Context context) { >- >- String contextName = context.getName(); >- >- if (deployed.containsKey(contextName)) >- return; >- >- DeployedApplication deployedApp = new DeployedApplication(contextName); >- >- // Add the associated docBase to the redeployed list if it's a WAR >- boolean isWar = false; >- if (context.getDocBase() != null) { >- File docBase = new File(context.getDocBase()); >- if (!docBase.isAbsolute()) { >- docBase = new File(host.getAppBaseFile(), context.getDocBase()); >- } >- deployedApp.redeployResources.put(docBase.getAbsolutePath(), >- Long.valueOf(docBase.lastModified())); >- if (docBase.getAbsolutePath().toLowerCase(Locale.ENGLISH).endsWith(".war")) { >- isWar = true; >- } >- } >- host.addChild(context); >- // Add the eventual unpacked WAR and all the resources which will be >- // watched inside it >- if (isWar && unpackWARs) { >- File docBase = new File(host.getAppBaseFile(), context.getBaseName()); >- deployedApp.redeployResources.put(docBase.getAbsolutePath(), >- Long.valueOf(docBase.lastModified())); >- addWatchedResources(deployedApp, docBase.getAbsolutePath(), context); >- } else { >- addWatchedResources(deployedApp, null, context); >- } >- deployed.put(contextName, deployedApp); >- } >- >- /** >- * Remove a webapp from our control. >- * Entry point for the admin webapp, and other JMX Context controllers. >- */ >- public void unmanageApp(String contextName) { >- if(isServiced(contextName)) { >- deployed.remove(contextName); >- host.removeChild(host.findChild(contextName)); >- } >- } >- >- // ----------------------------------------------------- Instance Variables >- >- >- /** >- * This class represents the state of a deployed application, as well as >- * the monitored resources. >- */ >- protected static class DeployedApplication { >- public DeployedApplication(String name) { >- this.name = name; >- } >- >- /** >- * Application context path. The assertion is that >- * (host.getChild(name) != null). >- */ >- public String name; >- >- /** >- * Any modification of the specified (static) resources will cause a >- * redeployment of the application. If any of the specified resources is >- * removed, the application will be undeployed. Typically, this will >- * contain resources like the context.xml file, a compressed WAR path. >- * The value is the last modification time. >- */ >- public LinkedHashMap<String, Long> redeployResources = >- new LinkedHashMap<String, Long>(); >- >- /** >- * Any modification of the specified (static) resources will cause a >- * reload of the application. This will typically contain resources >- * such as the web.xml of a webapp, but can be configured to contain >- * additional descriptors. >- * The value is the last modification time. >- */ >- public HashMap<String, Long> reloadResources = >- new HashMap<String, Long>(); >- >- /** >- * Instant where the application was last put in service. >- */ >- public long timestamp = System.currentTimeMillis(); >- } >- >-} >+/* >+ * 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.startup; >+ >+ >+import java.io.BufferedOutputStream; >+import java.io.File; >+import java.io.FileInputStream; >+import java.io.FileOutputStream; >+import java.io.IOException; >+import java.io.InputStream; >+import java.io.OutputStream; >+import java.net.URL; >+import java.util.ArrayList; >+import java.util.HashMap; >+import java.util.HashSet; >+import java.util.LinkedHashMap; >+import java.util.List; >+import java.util.Locale; >+import java.util.Map; >+import java.util.Set; >+import java.util.concurrent.ConcurrentHashMap; >+import java.util.concurrent.ExecutorService; >+import java.util.concurrent.Future; >+import java.util.jar.JarEntry; >+import java.util.jar.JarFile; >+import java.util.regex.Matcher; >+import java.util.regex.Pattern; >+ >+import javax.management.ObjectName; >+ >+import org.apache.catalina.Container; >+import org.apache.catalina.Context; >+import org.apache.catalina.Engine; >+import org.apache.catalina.Globals; >+import org.apache.catalina.Host; >+import org.apache.catalina.Lifecycle; >+import org.apache.catalina.LifecycleEvent; >+import org.apache.catalina.LifecycleListener; >+import org.apache.catalina.core.ContainerBase; >+import org.apache.catalina.core.StandardHost; >+import org.apache.catalina.util.ContextName; >+import org.apache.catalina.util.IOTools; >+import org.apache.juli.logging.Log; >+import org.apache.juli.logging.LogFactory; >+import org.apache.tomcat.util.ExceptionUtils; >+import org.apache.tomcat.util.digester.Digester; >+import org.apache.tomcat.util.modeler.Registry; >+import org.apache.tomcat.util.res.StringManager; >+ >+ >+/** >+ * Startup event listener for a <b>Host</b> that configures the properties >+ * of that Host, and the associated defined contexts. >+ * >+ * @author Craig R. McClanahan >+ * @author Remy Maucherat >+ * @version $Id$ >+ */ >+public class HostConfig >+ implements LifecycleListener { >+ >+ private static final Log log = LogFactory.getLog( HostConfig.class ); >+ >+ // ----------------------------------------------------- Instance Variables >+ >+ >+ /** >+ * Config base. >+ */ >+ protected File configBase = null; >+ >+ >+ /** >+ * The Java class name of the Context configuration class we should use. >+ */ >+ protected String configClass = "org.apache.catalina.startup.ContextConfig"; >+ >+ >+ /** >+ * The Java class name of the Context implementation we should use. >+ */ >+ protected String contextClass = "org.apache.catalina.core.StandardContext"; >+ >+ >+ /** >+ * The Host we are associated with. >+ */ >+ protected Host host = null; >+ >+ >+ /** >+ * The JMX ObjectName of this component. >+ */ >+ protected ObjectName oname = null; >+ >+ >+ /** >+ * The string resources for this package. >+ */ >+ protected static final StringManager sm = >+ StringManager.getManager(Constants.Package); >+ >+ >+ /** >+ * Should we deploy XML Context config files packaged with WAR files and >+ * directories? >+ */ >+ protected boolean deployXML = false; >+ >+ >+ /** >+ * Should XML files be copied to $CATALINA_BASE/conf/<engine>/<host> by >+ * default when a web application is deployed? >+ */ >+ protected boolean copyXML = false; >+ >+ >+ /** >+ * Should we unpack WAR files when auto-deploying applications in the >+ * <code>appBase</code> directory? >+ */ >+ protected boolean unpackWARs = false; >+ >+ >+ /** >+ * Map of deployed applications. >+ */ >+ protected Map<String, DeployedApplication> deployed = >+ new ConcurrentHashMap<String, DeployedApplication>(); >+ >+ >+ /** >+ * List of applications which are being serviced, and shouldn't be >+ * deployed/undeployed/redeployed at the moment. >+ */ >+ protected ArrayList<String> serviced = new ArrayList<String>(); >+ >+ >+ /** >+ * The <code>Digester</code> instance used to parse context descriptors. >+ */ >+ protected static Digester digester = createDigester(); >+ >+ /** >+ * The list of Wars in the appBase to be ignored because they are invalid >+ * (e.g. contain /../ sequences). >+ */ >+ protected Set<String> invalidWars = new HashSet<String>(); >+ >+ // ------------------------------------------------------------- Properties >+ >+ >+ /** >+ * Return the Context configuration class name. >+ */ >+ public String getConfigClass() { >+ >+ return (this.configClass); >+ >+ } >+ >+ >+ /** >+ * Set the Context configuration class name. >+ * >+ * @param configClass The new Context configuration class name. >+ */ >+ public void setConfigClass(String configClass) { >+ >+ this.configClass = configClass; >+ >+ } >+ >+ >+ /** >+ * Return the Context implementation class name. >+ */ >+ public String getContextClass() { >+ >+ return (this.contextClass); >+ >+ } >+ >+ >+ /** >+ * Set the Context implementation class name. >+ * >+ * @param contextClass The new Context implementation class name. >+ */ >+ public void setContextClass(String contextClass) { >+ >+ this.contextClass = contextClass; >+ >+ } >+ >+ >+ /** >+ * Return the deploy XML config file flag for this component. >+ */ >+ public boolean isDeployXML() { >+ >+ return (this.deployXML); >+ >+ } >+ >+ >+ /** >+ * Set the deploy XML config file flag for this component. >+ * >+ * @param deployXML The new deploy XML flag >+ */ >+ public void setDeployXML(boolean deployXML) { >+ >+ this.deployXML= deployXML; >+ >+ } >+ >+ >+ /** >+ * Return the copy XML config file flag for this component. >+ */ >+ public boolean isCopyXML() { >+ >+ return (this.copyXML); >+ >+ } >+ >+ >+ /** >+ * Set the copy XML config file flag for this component. >+ * >+ * @param copyXML The new copy XML flag >+ */ >+ public void setCopyXML(boolean copyXML) { >+ >+ this.copyXML= copyXML; >+ >+ } >+ >+ >+ /** >+ * Return the unpack WARs flag. >+ */ >+ public boolean isUnpackWARs() { >+ >+ return (this.unpackWARs); >+ >+ } >+ >+ >+ /** >+ * Set the unpack WARs flag. >+ * >+ * @param unpackWARs The new unpack WARs flag >+ */ >+ public void setUnpackWARs(boolean unpackWARs) { >+ >+ this.unpackWARs = unpackWARs; >+ >+ } >+ >+ >+ // --------------------------------------------------------- Public Methods >+ >+ >+ /** >+ * Process the START event for an associated Host. >+ * >+ * @param event The lifecycle event that has occurred >+ */ >+ @Override >+ public void lifecycleEvent(LifecycleEvent event) { >+ >+ if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) >+ check(); >+ >+ // Identify the host we are associated with >+ try { >+ host = (Host) event.getLifecycle(); >+ if (host instanceof StandardHost) { >+ setCopyXML(((StandardHost) host).isCopyXML()); >+ setDeployXML(((StandardHost) host).isDeployXML()); >+ setUnpackWARs(((StandardHost) host).isUnpackWARs()); >+ } >+ } catch (ClassCastException e) { >+ log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e); >+ return; >+ } >+ >+ // Process the event that has occurred >+ if (event.getType().equals(Lifecycle.START_EVENT)) >+ start(); >+ else if (event.getType().equals(Lifecycle.STOP_EVENT)) >+ stop(); >+ >+ } >+ >+ >+ /** >+ * Add a serviced application to the list. >+ */ >+ public synchronized void addServiced(String name) { >+ serviced.add(name); >+ } >+ >+ >+ /** >+ * Is application serviced ? >+ * @return state of the application >+ */ >+ public synchronized boolean isServiced(String name) { >+ return (serviced.contains(name)); >+ } >+ >+ >+ /** >+ * Removed a serviced application from the list. >+ */ >+ public synchronized void removeServiced(String name) { >+ serviced.remove(name); >+ } >+ >+ >+ /** >+ * Get the instant where an application was deployed. >+ * @return 0L if no application with that name is deployed, or the instant >+ * on which the application was deployed >+ */ >+ public long getDeploymentTime(String name) { >+ DeployedApplication app = deployed.get(name); >+ if (app == null) { >+ return 0L; >+ } >+ >+ return app.timestamp; >+ } >+ >+ >+ /** >+ * Has the specified application been deployed? Note applications defined >+ * in server.xml will not have been deployed. >+ * @return <code>true</code> if the application has been deployed and >+ * <code>false</code> if the application has not been deployed or does not >+ * exist >+ */ >+ public boolean isDeployed(String name) { >+ DeployedApplication app = deployed.get(name); >+ if (app == null) { >+ return false; >+ } >+ >+ return true; >+ } >+ >+ >+ // ------------------------------------------------------ Protected Methods >+ >+ >+ /** >+ * Create the digester which will be used to parse context config files. >+ */ >+ protected static Digester createDigester() { >+ Digester digester = new Digester(); >+ digester.setValidating(false); >+ // Add object creation rule >+ digester.addObjectCreate("Context", "org.apache.catalina.core.StandardContext", >+ "className"); >+ // Set the properties on that object (it doesn't matter if extra >+ // properties are set) >+ digester.addSetProperties("Context"); >+ return (digester); >+ } >+ >+ protected File returnCanonicalPath(String path) { >+ File file = new File(path); >+ File base = new File(System.getProperty(Globals.CATALINA_BASE_PROP)); >+ if (!file.isAbsolute()) >+ file = new File(base,path); >+ try { >+ return file.getCanonicalFile(); >+ } catch (IOException e) { >+ return file; >+ } >+ } >+ >+ >+ /** >+ * Return a File object representing the "configuration root" directory >+ * for our associated Host. >+ */ >+ protected File configBase() { >+ >+ if (configBase != null) { >+ return configBase; >+ } >+ >+ if (host.getXmlBase()!=null) { >+ configBase = returnCanonicalPath(host.getXmlBase()); >+ } else { >+ StringBuilder xmlDir = new StringBuilder("conf"); >+ Container parent = host.getParent(); >+ if (parent instanceof Engine) { >+ xmlDir.append('/'); >+ xmlDir.append(parent.getName()); >+ } >+ xmlDir.append('/'); >+ xmlDir.append(host.getName()); >+ configBase = returnCanonicalPath(xmlDir.toString()); >+ } >+ return (configBase); >+ >+ } >+ >+ /** >+ * Get the name of the configBase. >+ * For use with JMX management. >+ */ >+ public String getConfigBaseName() { >+ return configBase().getAbsolutePath(); >+ } >+ >+ >+ /** >+ * Deploy applications for any directories or WAR files that are found >+ * in our "application root" directory. >+ */ >+ protected void deployApps() { >+ >+ File appBase = host.getAppBaseFile(); >+ File configBase = configBase(); >+ String[] filteredAppPaths = filterAppPaths(appBase.list()); >+ // Deploy XML descriptors from configBase >+ deployDescriptors(configBase, configBase.list()); >+ // Deploy WARs, and loop if additional descriptors are found >+ deployWARs(appBase, filteredAppPaths); >+ // Deploy expanded folders >+ deployDirectories(appBase, filteredAppPaths); >+ >+ } >+ >+ >+ /** >+ * Filter the list of application file paths to remove those that match >+ * the regular expression defined by {@link Host#getDeployIgnore()}. >+ * >+ * @param unfilteredAppPaths The list of application paths to filtert >+ * >+ * @return The filtered list of application paths >+ */ >+ protected String[] filterAppPaths(String[] unfilteredAppPaths) { >+ Pattern filter = host.getDeployIgnorePattern(); >+ if (filter == null) { >+ return unfilteredAppPaths; >+ } >+ >+ List<String> filteredList = new ArrayList<String>(); >+ Matcher matcher = null; >+ for (String appPath : unfilteredAppPaths) { >+ if (matcher == null) { >+ matcher = filter.matcher(appPath); >+ } else { >+ matcher.reset(appPath); >+ } >+ if (matcher.matches()) { >+ if (log.isDebugEnabled()) { >+ log.debug(sm.getString("hostConfig.ignorePath", appPath)); >+ } >+ } else { >+ filteredList.add(appPath); >+ } >+ } >+ return filteredList.toArray(new String[filteredList.size()]); >+ } >+ >+ >+ /** >+ * Deploy applications for any directories or WAR files that are found >+ * in our "application root" directory. >+ */ >+ protected void deployApps(String name) { >+ >+ File appBase = host.getAppBaseFile(); >+ File configBase = configBase(); >+ ContextName cn = new ContextName(name); >+ String baseName = cn.getBaseName(); >+ >+ if (deploymentExists(baseName)) { >+ return; >+ } >+ >+ // Deploy XML descriptors from configBase >+ File xml = new File(configBase, baseName + ".xml"); >+ if (xml.exists()) >+ deployDescriptor(cn, xml); >+ // Deploy WARs, and loop if additional descriptors are found >+ File war = new File(appBase, baseName + ".war"); >+ if (war.exists()) >+ deployWAR(cn, war); >+ // Deploy expanded folders >+ File dir = new File(appBase, baseName); >+ if (dir.exists()) >+ deployDirectory(cn, dir); >+ } >+ >+ >+ /** >+ * Deploy XML context descriptors. >+ */ >+ protected void deployDescriptors(File configBase, String[] files) { >+ >+ if (files == null) >+ return; >+ >+ ExecutorService es = host.getStartStopExecutor(); >+ List<Future<?>> results = new ArrayList<Future<?>>(); >+ >+ for (int i = 0; i < files.length; i++) { >+ File contextXml = new File(configBase, files[i]); >+ >+ if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".xml")) { >+ ContextName cn = new ContextName(files[i]); >+ >+ if (isServiced(cn.getName()) || deploymentExists(cn.getName())) >+ continue; >+ >+ results.add( >+ es.submit(new DeployDescriptor(this, cn, contextXml))); >+ } >+ } >+ >+ for (Future<?> result : results) { >+ try { >+ result.get(); >+ } catch (Exception e) { >+ log.error(sm.getString( >+ "hostConfig.deployDescriptor.threaded.error"), e); >+ } >+ } >+ } >+ >+ >+ /** >+ * @param cn >+ * @param contextXml >+ */ >+ protected void deployDescriptor(ContextName cn, File contextXml) { >+ >+ DeployedApplication deployedApp = new DeployedApplication(cn.getName()); >+ >+ // Assume this is a configuration descriptor and deploy it >+ if(log.isInfoEnabled()) { >+ log.info(sm.getString("hostConfig.deployDescriptor", >+ contextXml.getAbsolutePath())); >+ } >+ >+ Context context = null; >+ try { >+ synchronized (digester) { >+ try { >+ context = (Context) digester.parse(contextXml); >+ if (context == null) { >+ log.error(sm.getString( >+ "hostConfig.deployDescriptor.error", >+ contextXml.getAbsolutePath())); >+ return; >+ } >+ } finally { >+ digester.reset(); >+ } >+ } >+ >+ Class<?> clazz = Class.forName(host.getConfigClass()); >+ LifecycleListener listener = >+ (LifecycleListener) clazz.newInstance(); >+ context.addLifecycleListener(listener); >+ >+ context.setConfigFile(contextXml.toURI().toURL()); >+ context.setName(cn.getName()); >+ context.setPath(cn.getPath()); >+ context.setWebappVersion(cn.getVersion()); >+ // Add the associated docBase to the redeployed list if it's a WAR >+ boolean isExternalWar = false; >+ boolean isExternal = false; >+ if (context.getDocBase() != null) { >+ File docBase = new File(context.getDocBase()); >+ if (!docBase.isAbsolute()) { >+ docBase = new File(host.getAppBaseFile(), context.getDocBase()); >+ } >+ // If external docBase, register .xml as redeploy first >+ if (!docBase.getCanonicalPath().startsWith( >+ host.getAppBaseFile().getAbsolutePath() + File.separator)) { >+ isExternal = true; >+ deployedApp.redeployResources.put( >+ contextXml.getAbsolutePath(), >+ Long.valueOf(contextXml.lastModified())); >+ deployedApp.redeployResources.put(docBase.getAbsolutePath(), >+ Long.valueOf(docBase.lastModified())); >+ if (docBase.getAbsolutePath().toLowerCase(Locale.ENGLISH).endsWith(".war")) { >+ isExternalWar = true; >+ } >+ } else { >+ log.warn(sm.getString("hostConfig.deployDescriptor.localDocBaseSpecified", >+ docBase)); >+ // Ignore specified docBase >+ context.setDocBase(null); >+ } >+ } >+ host.addChild(context); >+ // Get paths for WAR and expanded WAR in appBase >+ >+ // default to appBase dir + name >+ File expandedDocBase = new File(host.getAppBaseFile(), cn.getBaseName()); >+ if (context.getDocBase() != null) { >+ // first assume docBase is absolute >+ expandedDocBase = new File(context.getDocBase()); >+ if (!expandedDocBase.isAbsolute()) { >+ // if docBase specified and relative, it must be relative to appBase >+ expandedDocBase = new File(host.getAppBaseFile(), context.getDocBase()); >+ } >+ } >+ // Add the eventual unpacked WAR and all the resources which will be >+ // watched inside it >+ if (isExternalWar && unpackWARs) { >+ deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), >+ Long.valueOf(expandedDocBase.lastModified())); >+ deployedApp.redeployResources.put(contextXml.getAbsolutePath(), >+ Long.valueOf(contextXml.lastModified())); >+ addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), context); >+ } else { >+ // Find an existing matching war and expanded folder >+ if (!isExternal) { >+ File warDocBase = new File(expandedDocBase.getAbsolutePath() + ".war"); >+ if (warDocBase.exists()) { >+ deployedApp.redeployResources.put(warDocBase.getAbsolutePath(), >+ Long.valueOf(warDocBase.lastModified())); >+ } >+ } >+ if (expandedDocBase.exists()) { >+ deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), >+ Long.valueOf(expandedDocBase.lastModified())); >+ addWatchedResources(deployedApp, >+ expandedDocBase.getAbsolutePath(), context); >+ } else { >+ addWatchedResources(deployedApp, null, context); >+ } >+ // Add the context XML to the list of files which should trigger a redeployment >+ if (!isExternal) { >+ deployedApp.redeployResources.put( >+ contextXml.getAbsolutePath(), >+ Long.valueOf(contextXml.lastModified())); >+ } >+ } >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ log.error(sm.getString("hostConfig.deployDescriptor.error", >+ contextXml.getAbsolutePath()), t); >+ } >+ >+ if (context != null && host.findChild(context.getName()) != null) { >+ deployed.put(context.getName(), deployedApp); >+ } >+ } >+ >+ >+ /** >+ * Deploy WAR files. >+ */ >+ protected void deployWARs(File appBase, String[] files) { >+ >+ if (files == null) >+ return; >+ >+ ExecutorService es = host.getStartStopExecutor(); >+ List<Future<?>> results = new ArrayList<Future<?>>(); >+ >+ for (int i = 0; i < files.length; i++) { >+ >+ if (files[i].equalsIgnoreCase("META-INF")) >+ continue; >+ if (files[i].equalsIgnoreCase("WEB-INF")) >+ continue; >+ File war = new File(appBase, files[i]); >+ if (files[i].toLowerCase(Locale.ENGLISH).endsWith(".war") && war.isFile() >+ && !invalidWars.contains(files[i]) ) { >+ >+ ContextName cn = new ContextName(files[i]); >+ >+ // Check for WARs with /../ /./ or similar sequences in the name >+ if (!validateContextPath(appBase, cn.getBaseName())) { >+ log.error(sm.getString( >+ "hostConfig.illegalWarName", files[i])); >+ invalidWars.add(files[i]); >+ continue; >+ } >+ >+ if (isServiced(cn.getName()) || deploymentExists(cn.getName())) >+ continue; >+ >+ results.add(es.submit(new DeployWar(this, cn, war))); >+ } >+ } >+ >+ for (Future<?> result : results) { >+ try { >+ result.get(); >+ } catch (Exception e) { >+ log.error(sm.getString( >+ "hostConfig.deployWar.threaded.error"), e); >+ } >+ } >+ } >+ >+ >+ private boolean validateContextPath(File appBase, String contextPath) { >+ // More complicated than the ideal as the canonical path may or may >+ // not end with File.separator for a directory >+ >+ StringBuilder docBase; >+ String canonicalDocBase = null; >+ >+ try { >+ String canonicalAppBase = appBase.getCanonicalPath(); >+ docBase = new StringBuilder(canonicalAppBase); >+ if (canonicalAppBase.endsWith(File.separator)) { >+ docBase.append(contextPath.substring(1).replace( >+ '/', File.separatorChar)); >+ } else { >+ docBase.append(contextPath.replace('/', File.separatorChar)); >+ } >+ // At this point docBase should be canonical but will not end >+ // with File.separator >+ >+ canonicalDocBase = >+ (new File(docBase.toString())).getCanonicalPath(); >+ >+ // If the canonicalDocBase ends with File.separator, add one to >+ // docBase before they are compared >+ if (canonicalDocBase.endsWith(File.separator)) { >+ docBase.append(File.separator); >+ } >+ } catch (IOException ioe) { >+ return false; >+ } >+ >+ // Compare the two. If they are not the same, the contextPath must >+ // have /../ like sequences in it >+ return canonicalDocBase.equals(docBase.toString()); >+ } >+ >+ /** >+ * @param cn >+ * @param war >+ */ >+ protected void deployWAR(ContextName cn, File war) { >+ >+ // Checking for a nested /META-INF/context.xml >+ JarFile jar = null; >+ JarEntry entry = null; >+ InputStream istream = null; >+ BufferedOutputStream ostream = null; >+ File xml; >+ if (copyXML) { >+ xml = new File(configBase(), cn.getBaseName() + ".xml"); >+ } else { >+ xml = new File(host.getAppBaseFile(), >+ cn.getBaseName() + "/META-INF/context.xml"); >+ } >+ boolean xmlInWar = false; >+ >+ if (deployXML && !xml.exists()) { >+ try { >+ jar = new JarFile(war); >+ entry = jar.getJarEntry(Constants.ApplicationContextXml); >+ if (entry != null) { >+ xmlInWar = true; >+ } >+ if ((copyXML || unpackWARs) && xmlInWar) { >+ istream = jar.getInputStream(entry); >+ >+ ostream = >+ new BufferedOutputStream >+ (new FileOutputStream(xml), 1024); >+ byte buffer[] = new byte[1024]; >+ while (true) { >+ int n = istream.read(buffer); >+ if (n < 0) { >+ break; >+ } >+ ostream.write(buffer, 0, n); >+ } >+ ostream.flush(); >+ ostream.close(); >+ ostream = null; >+ istream.close(); >+ istream = null; >+ } >+ } catch (IOException e) { >+ /* Ignore */ >+ } finally { >+ if (ostream != null) { >+ try { >+ ostream.close(); >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ } >+ ostream = null; >+ } >+ if (istream != null) { >+ try { >+ istream.close(); >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ } >+ istream = null; >+ } >+ entry = null; >+ if (jar != null) { >+ try { >+ jar.close(); >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ } >+ jar = null; >+ } >+ } >+ } >+ >+ DeployedApplication deployedApp = new DeployedApplication(cn.getName()); >+ >+ // Deploy the application in this WAR file >+ if(log.isInfoEnabled()) >+ log.info(sm.getString("hostConfig.deployWar", >+ war.getAbsolutePath())); >+ >+ try { >+ Context context = null; >+ if (deployXML && xml.exists()) { >+ synchronized (digester) { >+ try { >+ context = (Context) digester.parse(xml); >+ if (context == null) { >+ log.error(sm.getString( >+ "hostConfig.deployDescriptor.error", >+ war.getAbsolutePath())); >+ return; >+ } >+ } finally { >+ digester.reset(); >+ } >+ } >+ context.setConfigFile(xml.toURI().toURL()); >+ } else if (deployXML && xmlInWar) { >+ synchronized (digester) { >+ try { >+ jar = new JarFile(war); >+ entry = >+ jar.getJarEntry(Constants.ApplicationContextXml); >+ istream = jar.getInputStream(entry); >+ context = (Context) digester.parse(istream); >+ >+ if (context == null) { >+ log.error(sm.getString( >+ "hostConfig.deployDescriptor.error", >+ war.getAbsolutePath())); >+ return; >+ } >+ context.setConfigFile(new URL("jar:" + >+ war.toURI().toString() + "!/" + >+ Constants.ApplicationContextXml)); >+ } finally { >+ if (istream != null) { >+ try { >+ istream.close(); >+ } catch (IOException e) { >+ /* Ignore */ >+ } >+ istream = null; >+ } >+ entry = null; >+ if (jar != null) { >+ try { >+ jar.close(); >+ } catch (IOException e) { >+ /* Ignore */ >+ } >+ jar = null; >+ } >+ digester.reset(); >+ } >+ } >+ } else { >+ context = (Context) Class.forName(contextClass).newInstance(); >+ } >+ >+ // Populate redeploy resources with the WAR file >+ deployedApp.redeployResources.put >+ (war.getAbsolutePath(), Long.valueOf(war.lastModified())); >+ >+ if (deployXML && xml.exists() && copyXML) { >+ deployedApp.redeployResources.put(xml.getAbsolutePath(), >+ Long.valueOf(xml.lastModified())); >+ } >+ >+ Class<?> clazz = Class.forName(host.getConfigClass()); >+ LifecycleListener listener = >+ (LifecycleListener) clazz.newInstance(); >+ context.addLifecycleListener(listener); >+ >+ context.setName(cn.getName()); >+ context.setPath(cn.getPath()); >+ context.setWebappVersion(cn.getVersion()); >+ context.setDocBase(cn.getBaseName() + ".war"); >+ host.addChild(context); >+ // If we're unpacking WARs, the docBase will be mutated after >+ // starting the context >+ if (unpackWARs && (context.getDocBase() != null)) { >+ File docBase = new File(host.getAppBaseFile(), cn.getBaseName()); >+ deployedApp.redeployResources.put(docBase.getAbsolutePath(), >+ Long.valueOf(docBase.lastModified())); >+ addWatchedResources(deployedApp, docBase.getAbsolutePath(), >+ context); >+ if (deployXML && !copyXML && (xmlInWar || xml.exists())) { >+ deployedApp.redeployResources.put(xml.getAbsolutePath(), >+ Long.valueOf(xml.lastModified())); >+ } >+ } else { >+ addWatchedResources(deployedApp, null, context); >+ } >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ log.error(sm.getString("hostConfig.deployWar.error", >+ war.getAbsolutePath()), t); >+ } >+ >+ deployed.put(cn.getName(), deployedApp); >+ } >+ >+ >+ /** >+ * Deploy directories. >+ */ >+ protected void deployDirectories(File appBase, String[] files) { >+ >+ if (files == null) >+ return; >+ >+ ExecutorService es = host.getStartStopExecutor(); >+ List<Future<?>> results = new ArrayList<Future<?>>(); >+ >+ for (int i = 0; i < files.length; i++) { >+ >+ if (files[i].equalsIgnoreCase("META-INF")) >+ continue; >+ if (files[i].equalsIgnoreCase("WEB-INF")) >+ continue; >+ File dir = new File(appBase, files[i]); >+ if (dir.isDirectory()) { >+ ContextName cn = new ContextName(files[i]); >+ >+ if (isServiced(cn.getName()) || deploymentExists(cn.getName())) >+ continue; >+ >+ results.add(es.submit(new DeployDirectory(this, cn, dir))); >+ } >+ } >+ >+ for (Future<?> result : results) { >+ try { >+ result.get(); >+ } catch (Exception e) { >+ log.error(sm.getString( >+ "hostConfig.deployDir.threaded.error"), e); >+ } >+ } >+ } >+ >+ >+ /** >+ * @param cn >+ * @param dir >+ */ >+ protected void deployDirectory(ContextName cn, File dir) { >+ >+ DeployedApplication deployedApp = new DeployedApplication(cn.getName()); >+ >+ // Deploy the application in this directory >+ if( log.isInfoEnabled() ) >+ log.info(sm.getString("hostConfig.deployDir", >+ dir.getAbsolutePath())); >+ try { >+ Context context = null; >+ File xml = new File(dir, Constants.ApplicationContextXml); >+ File xmlCopy = null; >+ if (deployXML && xml.exists()) { >+ synchronized (digester) { >+ try { >+ context = (Context) digester.parse(xml); >+ if (context == null) { >+ log.error(sm.getString( >+ "hostConfig.deployDescriptor.error", >+ xml)); >+ return; >+ } >+ } finally { >+ digester.reset(); >+ } >+ } >+ if (copyXML) { >+ xmlCopy = new File(configBase(), cn.getBaseName() + ".xml"); >+ InputStream is = null; >+ OutputStream os = null; >+ try { >+ is = new FileInputStream(xml); >+ os = new FileOutputStream(xmlCopy); >+ IOTools.flow(is, os); >+ // Don't catch IOE - let the outer try/catch handle it >+ } finally { >+ try { >+ if (is != null) is.close(); >+ } catch (IOException e){ >+ // Ignore >+ } >+ try { >+ if (os != null) os.close(); >+ } catch (IOException e){ >+ // Ignore >+ } >+ } >+ context.setConfigFile(xmlCopy.toURI().toURL()); >+ } else { >+ context.setConfigFile(xml.toURI().toURL()); >+ } >+ } else { >+ context = (Context) Class.forName(contextClass).newInstance(); >+ } >+ >+ Class<?> clazz = Class.forName(host.getConfigClass()); >+ LifecycleListener listener = >+ (LifecycleListener) clazz.newInstance(); >+ context.addLifecycleListener(listener); >+ >+ context.setName(cn.getName()); >+ context.setPath(cn.getPath()); >+ context.setWebappVersion(cn.getVersion()); >+ context.setDocBase(cn.getBaseName()); >+ host.addChild(context); >+ deployedApp.redeployResources.put(dir.getAbsolutePath(), >+ Long.valueOf(dir.lastModified())); >+ if (deployXML && xml.exists()) { >+ if (xmlCopy == null) { >+ deployedApp.redeployResources.put( >+ xml.getAbsolutePath(), >+ Long.valueOf(xml.lastModified())); >+ } else { >+ deployedApp.redeployResources.put( >+ xmlCopy.getAbsolutePath(), >+ Long.valueOf(xmlCopy.lastModified())); >+ } >+ } >+ addWatchedResources(deployedApp, dir.getAbsolutePath(), context); >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ log.error(sm.getString("hostConfig.deployDir.error", >+ dir.getAbsolutePath()), t); >+ } >+ >+ deployed.put(cn.getName(), deployedApp); >+ } >+ >+ >+ /** >+ * Check if a webapp is already deployed in this host. >+ * >+ * @param contextName of the context which will be checked >+ */ >+ protected boolean deploymentExists(String contextName) { >+ return (deployed.containsKey(contextName) || >+ (host.findChild(contextName) != null)); >+ } >+ >+ >+ /** >+ * Add watched resources to the specified Context. >+ * @param app HostConfig deployed app >+ * @param docBase web app docBase >+ * @param context web application context >+ */ >+ protected void addWatchedResources(DeployedApplication app, String docBase, >+ Context context) { >+ // FIXME: Feature idea. Add support for patterns (ex: WEB-INF/*, >+ // WEB-INF/*.xml), where we would only check if at least one >+ // resource is newer than app.timestamp >+ File docBaseFile = null; >+ if (docBase != null) { >+ docBaseFile = new File(docBase); >+ if (!docBaseFile.isAbsolute()) { >+ docBaseFile = new File(host.getAppBaseFile(), docBase); >+ } >+ } >+ String[] watchedResources = context.findWatchedResources(); >+ for (int i = 0; i < watchedResources.length; i++) { >+ File resource = new File(watchedResources[i]); >+ if (!resource.isAbsolute()) { >+ if (docBase != null) { >+ resource = new File(docBaseFile, watchedResources[i]); >+ } else { >+ if(log.isDebugEnabled()) >+ log.debug("Ignoring non-existent WatchedResource '" + >+ resource.getAbsolutePath() + "'"); >+ continue; >+ } >+ } >+ if(log.isDebugEnabled()) >+ log.debug("Watching WatchedResource '" + >+ resource.getAbsolutePath() + "'"); >+ app.reloadResources.put(resource.getAbsolutePath(), >+ Long.valueOf(resource.lastModified())); >+ } >+ } >+ >+ >+ /** >+ * Check resources for redeployment and reloading. >+ */ >+ protected synchronized void checkResources(DeployedApplication app) { >+ String[] resources = >+ app.redeployResources.keySet().toArray(new String[0]); >+ for (int i = 0; i < resources.length; i++) { >+ File resource = new File(resources[i]); >+ if (log.isDebugEnabled()) >+ log.debug("Checking context[" + app.name + >+ "] redeploy resource " + resource); >+ if (resource.exists()) { >+ long lastModified = >+ app.redeployResources.get(resources[i]).longValue(); >+ if ((!resource.isDirectory()) && >+ resource.lastModified() > lastModified) { >+ // Undeploy application >+ if (log.isInfoEnabled()) >+ log.info(sm.getString("hostConfig.undeploy", app.name)); >+ ContainerBase context = >+ (ContainerBase) host.findChild(app.name); >+ try { >+ host.removeChild(context); >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ log.warn(sm.getString >+ ("hostConfig.context.remove", app.name), t); >+ } >+ // Delete other redeploy resources >+ for (int j = i + 1; j < resources.length; j++) { >+ try { >+ File current = new File(resources[j]); >+ current = current.getCanonicalFile(); >+ if ((current.getAbsolutePath().startsWith( >+ host.getAppBaseFile().getAbsolutePath() + >+ File.separator)) >+ || (current.getAbsolutePath().startsWith( >+ configBase().getAbsolutePath()))) { >+ if (log.isDebugEnabled()) >+ log.debug("Delete " + current); >+ ExpandWar.delete(current); >+ } >+ } catch (IOException e) { >+ log.warn(sm.getString >+ ("hostConfig.canonicalizing", app.name), e); >+ } >+ } >+ deployed.remove(app.name); >+ return; >+ } >+ } else { >+ // There is a chance the the resource was only missing >+ // temporarily eg renamed during a text editor save >+ try { >+ Thread.sleep(500); >+ } catch (InterruptedException e1) { >+ // Ignore >+ } >+ // Recheck the resource to see if it was really deleted >+ if (resource.exists()) { >+ continue; >+ } >+ long lastModified = >+ app.redeployResources.get(resources[i]).longValue(); >+ if (lastModified == 0L) { >+ continue; >+ } >+ // Undeploy application >+ if (log.isInfoEnabled()) >+ log.info(sm.getString("hostConfig.undeploy", app.name)); >+ ContainerBase context = >+ (ContainerBase) host.findChild(app.name); >+ try { >+ host.removeChild(context); >+ } catch (Throwable t) { >+ ExceptionUtils.handleThrowable(t); >+ log.warn(sm.getString >+ ("hostConfig.context.remove", app.name), t); >+ } >+ // Delete all redeploy resources >+ for (int j = i + 1; j < resources.length; j++) { >+ try { >+ File current = new File(resources[j]); >+ current = current.getCanonicalFile(); >+ if ((current.getAbsolutePath().startsWith( >+ host.getAppBaseFile().getAbsolutePath() + File.separator)) >+ || (current.getAbsolutePath().startsWith( >+ configBase().getAbsolutePath()))) { >+ if (log.isDebugEnabled()) >+ log.debug("Delete " + current); >+ ExpandWar.delete(current); >+ } >+ } catch (IOException e) { >+ log.warn(sm.getString >+ ("hostConfig.canonicalizing", app.name), e); >+ } >+ } >+ // Delete reload resources as well (to remove any remaining .xml >+ // descriptor) >+ String[] resources2 = >+ app.reloadResources.keySet().toArray(new String[0]); >+ for (int j = 0; j < resources2.length; j++) { >+ try { >+ File current = new File(resources2[j]); >+ current = current.getCanonicalFile(); >+ if ((current.getAbsolutePath().startsWith( >+ host.getAppBaseFile().getAbsolutePath() + File.separator)) >+ || ((current.getAbsolutePath().startsWith( >+ configBase().getAbsolutePath()) >+ && (current.getAbsolutePath().endsWith(".xml"))))) { >+ if (log.isDebugEnabled()) >+ log.debug("Delete " + current); >+ ExpandWar.delete(current); >+ } >+ } catch (IOException e) { >+ log.warn(sm.getString >+ ("hostConfig.canonicalizing", app.name), e); >+ } >+ } >+ deployed.remove(app.name); >+ return; >+ } >+ } >+ resources = app.reloadResources.keySet().toArray(new String[0]); >+ for (int i = 0; i < resources.length; i++) { >+ File resource = new File(resources[i]); >+ if (log.isDebugEnabled()) >+ log.debug("Checking context[" + app.name + >+ "] reload resource " + resource); >+ long lastModified = >+ app.reloadResources.get(resources[i]).longValue(); >+ if ((!resource.exists() && lastModified != 0L) >+ || (resource.lastModified() != lastModified)) { >+ // Reload application >+ if(log.isInfoEnabled()) >+ log.info(sm.getString("hostConfig.reload", app.name)); >+ Container context = host.findChild(app.name); >+ try { >+ // Might not have started if start failed last time >+ if (context.getState().isAvailable()) { >+ context.stop(); >+ } >+ } catch (Exception e) { >+ log.warn(sm.getString >+ ("hostConfig.context.restart", app.name), e); >+ } >+ // If the context was not started (for example an error >+ // in web.xml) we'll still get to try to start >+ try { >+ context.start(); >+ } catch (Exception e) { >+ log.warn(sm.getString >+ ("hostConfig.context.restart", app.name), e); >+ } >+ // Update times >+ app.reloadResources.put(resources[i], >+ Long.valueOf(resource.lastModified())); >+ app.timestamp = System.currentTimeMillis(); >+ return; >+ } >+ } >+ } >+ >+ >+ /** >+ * Process a "start" event for this Host. >+ */ >+ public void start() { >+ >+ if (log.isDebugEnabled()) >+ log.debug(sm.getString("hostConfig.start")); >+ >+ try { >+ ObjectName hostON = host.getObjectName(); >+ oname = new ObjectName >+ (hostON.getDomain() + ":type=Deployer,host=" + host.getName()); >+ Registry.getRegistry(null, null).registerComponent >+ (this, oname, this.getClass().getName()); >+ } catch (Exception e) { >+ log.error(sm.getString("hostConfig.jmx.register", oname), e); >+ } >+ >+ if (host.getCreateDirs()) { >+ File[] dirs = new File[] {host.getAppBaseFile(),configBase()}; >+ for (int i=0; i<dirs.length; i++) { >+ if (!dirs[i].mkdirs() && !dirs[i].isDirectory()) { >+ log.error(sm.getString("hostConfig.createDirs",dirs[i])); >+ } >+ } >+ } >+ >+ if (!host.getAppBaseFile().isDirectory()) { >+ log.error(sm.getString("hostConfig.appBase", host.getName(), >+ host.getAppBaseFile().getPath())); >+ host.setDeployOnStartup(false); >+ host.setAutoDeploy(false); >+ } >+ >+ if (host.getDeployOnStartup()) >+ deployApps(); >+ >+ } >+ >+ >+ /** >+ * Process a "stop" event for this Host. >+ */ >+ public void stop() { >+ >+ if (log.isDebugEnabled()) >+ log.debug(sm.getString("hostConfig.stop")); >+ >+ if (oname != null) { >+ try { >+ Registry.getRegistry(null, null).unregisterComponent(oname); >+ } catch (Exception e) { >+ log.error(sm.getString("hostConfig.jmx.unregister", oname), e); >+ } >+ } >+ oname = null; >+ configBase = null; >+ >+ } >+ >+ >+ /** >+ * Check status of all webapps. >+ */ >+ protected void check() { >+ >+ if (host.getAutoDeploy()) { >+ // Check for resources modification to trigger redeployment >+ DeployedApplication[] apps = >+ deployed.values().toArray(new DeployedApplication[0]); >+ for (int i = 0; i < apps.length; i++) { >+ if (!isServiced(apps[i].name)) >+ checkResources(apps[i]); >+ } >+ // Hotdeploy applications >+ deployApps(); >+ } >+ >+ } >+ >+ >+ /** >+ * Check status of a specific webapp, for use with stuff like management webapps. >+ */ >+ public void check(String name) { >+ DeployedApplication app = deployed.get(name); >+ if (app != null) { >+ checkResources(app); >+ } else { >+ deployApps(name); >+ } >+ } >+ >+ /** >+ * Add a new Context to be managed by us. >+ * Entry point for the admin webapp, and other JMX Context controllers. >+ */ >+ public void manageApp(Context context) { >+ >+ String contextName = context.getName(); >+ >+ if (deployed.containsKey(contextName)) >+ return; >+ >+ DeployedApplication deployedApp = new DeployedApplication(contextName); >+ >+ // Add the associated docBase to the redeployed list if it's a WAR >+ boolean isWar = false; >+ if (context.getDocBase() != null) { >+ File docBase = new File(context.getDocBase()); >+ if (!docBase.isAbsolute()) { >+ docBase = new File(host.getAppBaseFile(), context.getDocBase()); >+ } >+ deployedApp.redeployResources.put(docBase.getAbsolutePath(), >+ Long.valueOf(docBase.lastModified())); >+ if (docBase.getAbsolutePath().toLowerCase(Locale.ENGLISH).endsWith(".war")) { >+ isWar = true; >+ } >+ } >+ host.addChild(context); >+ // Add the eventual unpacked WAR and all the resources which will be >+ // watched inside it >+ if (isWar && unpackWARs) { >+ File docBase = new File(host.getAppBaseFile(), context.getBaseName()); >+ deployedApp.redeployResources.put(docBase.getAbsolutePath(), >+ Long.valueOf(docBase.lastModified())); >+ addWatchedResources(deployedApp, docBase.getAbsolutePath(), context); >+ } else { >+ addWatchedResources(deployedApp, null, context); >+ } >+ deployed.put(contextName, deployedApp); >+ } >+ >+ /** >+ * Remove a webapp from our control. >+ * Entry point for the admin webapp, and other JMX Context controllers. >+ */ >+ public void unmanageApp(String contextName) { >+ if(isServiced(contextName)) { >+ deployed.remove(contextName); >+ host.removeChild(host.findChild(contextName)); >+ } >+ } >+ >+ // ----------------------------------------------------- Instance Variables >+ >+ >+ /** >+ * This class represents the state of a deployed application, as well as >+ * the monitored resources. >+ */ >+ protected static class DeployedApplication { >+ public DeployedApplication(String name) { >+ this.name = name; >+ } >+ >+ /** >+ * Application context path. The assertion is that >+ * (host.getChild(name) != null). >+ */ >+ public String name; >+ >+ /** >+ * Any modification of the specified (static) resources will cause a >+ * redeployment of the application. If any of the specified resources is >+ * removed, the application will be undeployed. Typically, this will >+ * contain resources like the context.xml file, a compressed WAR path. >+ * The value is the last modification time. >+ */ >+ public LinkedHashMap<String, Long> redeployResources = >+ new LinkedHashMap<String, Long>(); >+ >+ /** >+ * Any modification of the specified (static) resources will cause a >+ * reload of the application. This will typically contain resources >+ * such as the web.xml of a webapp, but can be configured to contain >+ * additional descriptors. >+ * The value is the last modification time. >+ */ >+ public HashMap<String, Long> reloadResources = >+ new HashMap<String, Long>(); >+ >+ /** >+ * Instant where the application was last put in service. >+ */ >+ public long timestamp = System.currentTimeMillis(); >+ } >+ >+ private static class DeployDescriptor implements Runnable { >+ >+ private HostConfig config; >+ private ContextName cn; >+ private File descriptor; >+ >+ public DeployDescriptor(HostConfig config, ContextName cn, >+ File descriptor) { >+ this.config = config; >+ this.cn = cn; >+ this.descriptor= descriptor; >+ } >+ >+ @Override >+ public void run() { >+ config.deployDescriptor(cn, descriptor); >+ } >+ } >+ >+ private static class DeployWar implements Runnable { >+ >+ private HostConfig config; >+ private ContextName cn; >+ private File war; >+ >+ public DeployWar(HostConfig config, ContextName cn, File war) { >+ this.config = config; >+ this.cn = cn; >+ this.war = war; >+ } >+ >+ @Override >+ public void run() { >+ config.deployWAR(cn, war); >+ } >+ } >+ >+ private static class DeployDirectory implements Runnable { >+ >+ private HostConfig config; >+ private ContextName cn; >+ private File dir; >+ >+ public DeployDirectory(HostConfig config, ContextName cn, File dir) { >+ this.config = config; >+ this.cn = cn; >+ this.dir = dir; >+ } >+ >+ @Override >+ public void run() { >+ config.deployDirectory(cn, dir); >+ } >+ } >+} >diff --git a/java/org/apache/catalina/startup/LocalStrings.properties b/java/org/apache/catalina/startup/LocalStrings.properties >index 2d18b44..4baddc1 100644 >--- a/java/org/apache/catalina/startup/LocalStrings.properties >+++ b/java/org/apache/catalina/startup/LocalStrings.properties >@@ -83,11 +83,14 @@ hostConfig.createDirs=Unable to create directory for deployment: {0} > hostConfig.deploy=Deploying web application directory {0} > hostConfig.deployDescriptor=Deploying configuration descriptor {0} > hostConfig.deployDescriptor.error=Error deploying configuration descriptor {0} >+hostConfig.deployDescriptor.threaded.error=Error waiting for multi-thread deployment of context descriptors to complete > hostConfig.deployDescriptor.localDocBaseSpecified=A docBase {0} inside the host appBase has been specified, and will be ignored > hostConfig.deployDir=Deploying web application directory {0} > hostConfig.deployDir.error=Error deploying web application directory {0} >+hostConfig.deployDir.threaded.error=Error waiting for multi-thread deployment of directories to completehostConfig.deployWar=Deploying web application archive {0} > hostConfig.deployWar=Deploying web application archive {0} > hostConfig.deployWar.error=Error deploying web application archive {0} >+hostConfig.deployWar.threaded.error=Error waiting for multi-thread deployment of WAR files to complete > hostConfig.deploy.error=Exception while deploying web application directory {0} > hostConfig.deploying=Deploying discovered web applications > hostConfig.expand=Expanding web application archive {0} >diff --git a/java/org/apache/tomcat/util/threads/DedicatedThreadExecutor.java b/java/org/apache/tomcat/util/threads/DedicatedThreadExecutor.java >deleted file mode 100644 >index 43e4411..0000000 >--- a/java/org/apache/tomcat/util/threads/DedicatedThreadExecutor.java >+++ /dev/null >@@ -1,137 +0,0 @@ >-/* >- * 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.tomcat.util.threads; >- >-import java.util.concurrent.Callable; >-import java.util.concurrent.ExecutionException; >-import java.util.concurrent.ExecutorService; >-import java.util.concurrent.Executors; >-import java.util.concurrent.Future; >-import java.util.concurrent.ThreadFactory; >- >-/** >- * A utility class to execute a {@link Callable} in a dedicated thread. >- * It can be used either with an instance to reuse the same thread for each call >- * to {@link #execute(Callable)} or with the static method >- * {@link #executeInOwnThread(Callable)}. When using an instance, >- * {@link #shutdown()} must be called when the instance is no longer needed to >- * dispose of the dedicated thread. >- */ >-public class DedicatedThreadExecutor { >- private final SingleThreadFactory singleThreadFactory = >- new SingleThreadFactory(); >- private final ExecutorService executorService = >- Executors.newSingleThreadExecutor(singleThreadFactory); >- >- /** >- * Executes the given {@link Callable} with the thread spawned for the >- * current {@link DedicatedThreadExecutor} instance, and returns its result. >- * >- * @param <V> >- * the type of the returned value >- * @param callable >- * @return the completed result >- */ >- public <V> V execute(final Callable<V> callable) { >- final Future<V> futureTask = executorService.submit(callable); >- >- boolean interrupted = false; >- V result; >- while (true) { >- try { >- result = futureTask.get(); >- break; >- } catch (InterruptedException e) { >- // keep waiting >- interrupted = true; >- } catch (ExecutionException e) { >- throw new RuntimeException(e); >- } >- } >- if (interrupted) { >- // set interruption status so that the caller may react to it >- Thread.currentThread().interrupt(); >- } >- return result; >- } >- >- /** >- * Stops the dedicated thread and waits for its death. >- */ >- public void shutdown() { >- executorService.shutdown(); >- if (singleThreadFactory.singleThread != null) { >- boolean interrupted = false; >- while (true) { >- try { >- singleThreadFactory.singleThread.join(); >- singleThreadFactory.singleThread = null; >- break; >- } catch (InterruptedException e) { >- // keep waiting >- interrupted = true; >- } >- } >- if (interrupted) { >- // set interruption status so that the caller may react to it >- Thread.currentThread().interrupt(); >- } >- } >- } >- >- /** >- * Executes the given {@link Callable} in a new thread and returns the >- * result after the thread is stopped. >- * >- * @param <V> >- * @param callable >- * @return the completed result >- */ >- public static <V> V executeInOwnThread( >- final Callable<V> callable) { >- DedicatedThreadExecutor executor = new DedicatedThreadExecutor(); >- try { >- return executor.execute(callable); >- } finally { >- executor.shutdown(); >- } >- >- } >- >- // we use a ThreadFactory so that we can later call Thread.join(). >- // Indeed, calling shutdown() on an ExecutorService will eventually stop the >- // thread but it might still be alive when execute() returns (race >- // condition). >- // This can lead to false alarms about potential memory leaks because the >- // thread may have a web application class loader for its context class >- // loader. >- private static class SingleThreadFactory implements ThreadFactory { >- private volatile Thread singleThread; >- >- @Override >- public Thread newThread(Runnable r) { >- if (singleThread != null) { >- throw new IllegalStateException( >- "should not have been called more than once"); >- } >- singleThread = new Thread(r); >- singleThread.setDaemon(true); >- return singleThread; >- } >- >- } >-} >diff --git a/test/org/apache/tomcat/util/threads/DedicatedThreadExecutorTest.java b/test/org/apache/tomcat/util/threads/DedicatedThreadExecutorTest.java >deleted file mode 100644 >index 8d13ccf..0000000 >--- a/test/org/apache/tomcat/util/threads/DedicatedThreadExecutorTest.java >+++ /dev/null >@@ -1,74 +0,0 @@ >-/* >- * 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.tomcat.util.threads; >- >-import java.util.concurrent.Callable; >- >-import static org.junit.Assert.assertEquals; >-import static org.junit.Assert.assertFalse; >-import static org.junit.Assert.assertNotSame; >-import static org.junit.Assert.assertSame; >- >-import org.junit.Test; >- >-public class DedicatedThreadExecutorTest { >- private Thread dedicatedThread; >- >- @Test >- public void testExecute() { >- final Thread testingThread = Thread.currentThread(); >- DedicatedThreadExecutor executor = new DedicatedThreadExecutor(); >- Long result = executor.execute(new Callable<Long>() { >- @Override >- public Long call() throws Exception { >- dedicatedThread = Thread.currentThread(); >- assertNotSame(testingThread, dedicatedThread); >- return Long.valueOf(123); >- } >- }); >- assertEquals(123, result.longValue()); >- >- //check that the same thread is reused >- executor.execute(new Callable<Void>() { >- @Override >- public Void call() throws Exception { >- assertSame(dedicatedThread, Thread.currentThread()); >- return null; >- } >- }); >- >- executor.shutdown(); >- assertFalse(dedicatedThread.isAlive()); >- } >- >- @Test >- public void testExecuteInOwnThread() { >- final Thread testingThread = Thread.currentThread(); >- Long result = >- DedicatedThreadExecutor.executeInOwnThread(new Callable<Long>() { >- @Override >- public Long call() throws Exception { >- dedicatedThread = Thread.currentThread(); >- assertNotSame(testingThread, dedicatedThread); >- return Long.valueOf(456); >- } >- }); >- assertEquals(456, result.longValue()); >- assertFalse(dedicatedThread.isAlive()); >- } >- >-} >diff --git a/webapps/docs/config/engine.xml b/webapps/docs/config/engine.xml >index 07ddec4..c05993b 100644 >--- a/webapps/docs/config/engine.xml >+++ b/webapps/docs/config/engine.xml >@@ -1,257 +1,268 @@ >-<?xml version="1.0"?> >-<!-- >- 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. >---> >-<!DOCTYPE document [ >- <!ENTITY project SYSTEM "project.xml"> >-]> >-<document url="engine.html"> >- >- &project; >- >- <properties> >- <author email="craigmcc@apache.org">Craig R. McClanahan</author> >- <title>The Engine Container</title> >- </properties> >- >-<body> >- >-<section name="Table of Contents"> >-<toc/> >-</section> >- >-<section name="Introduction"> >- >- <p>The <strong>Engine</strong> element represents the entire request >- processing machinery associated with a particular Catalina >- <a href="service.html">Service</a>. It receives and processes >- <em>all</em> requests from one or more <strong>Connectors</strong>, >- and returns the completed response to the Connector for ultimate >- transmission back to the client.</p> >- >- <p>Exactly one <strong>Engine</strong> element MUST be nested inside >- a <a href="service.html">Service</a> element, following all of the >- corresponding Connector elements associated with this Service.</p> >- >-</section> >- >- >-<section name="Attributes"> >- >- <subsection name="Common Attributes"> >- >- <p>All implementations of <strong>Engine</strong> >- support the following attributes:</p> >- >- <attributes> >- >- <attribute name="backgroundProcessorDelay" required="false"> >- <p>This value represents the delay in seconds between the >- invocation of the backgroundProcess method on this engine and >- its child containers, including all hosts and contexts. >- Child containers will not be invoked if their delay value is not >- negative (which would mean they are using their own processing >- thread). Setting this to a positive value will cause >- a thread to be spawn. After waiting the specified amount of time, >- the thread will invoke the backgroundProcess method on this engine >- and all its child containers. If not specified, the default value for >- this attribute is 10, which represent a 10 seconds delay.</p> >- </attribute> >- >- <attribute name="className" required="false"> >- <p>Java class name of the implementation to use. This class must >- implement the <code>org.apache.catalina.Engine</code> interface. >- If not specified, the standard value (defined below) will be used.</p> >- </attribute> >- >- <attribute name="defaultHost" required="true"> >- <p>The default host name, which identifies the >- <a href="host.html">Host</a> that will process requests directed >- to host names on this server, but which are not configured in >- this configuration file. This name MUST match the <code>name</code> >- attributes of one of the <a href="host.html">Host</a> elements >- nested immediately inside.</p> >- </attribute> >- >- <attribute name="jvmRoute" required="false"> >- <p>Identifier which must be used in load balancing scenarios to enable >- session affinity. The identifier, which must be unique across all >- Tomcat servers which participate in the cluster, will be appended to >- the generated session identifier, therefore allowing the front end >- proxy to always forward a particular session to the same Tomcat >- instance.</p> >- </attribute> >- >- <attribute name="name" required="true"> >- <p>Logical name of this Engine, used in log and error messages. <em>When >- using multiple <a href="service.html">Service</a> elements in the same >- <a href="server.html">Server</a>, each Engine MUST be assigned a unique >- name.</em></p> >- </attribute> >- >- </attributes> >- >- </subsection> >- >- >- <subsection name="Standard Implementation"> >- >- <p>The standard implementation of <strong>Engine</strong> is >- <strong>org.apache.catalina.core.StandardEngine</strong>. >- It supports the following additional attributes (in addition to the >- common attributes listed above):</p> >- >- <attributes> >- >- </attributes> >- >- </subsection> >- >- >-</section> >- >- >-<section name="Nested Components"> >- >- <p>You can nest one or more <a href="host.html">Host</a> elements inside >- this <strong>Engine</strong> element, each representing a different virtual >- host associated with this server. At least one <a href="host.html">Host</a> >- is required, and one of the nested <a href="host.html">Hosts</a> MUST >- have a name that matches the name specified for the >- <code>defaultHost</code> attribute, listed above.</p> >- >- <p>You can nest at most one instance of the following utility components >- by nesting a corresponding element inside your <strong>Engine</strong> >- element:</p> >- <ul> >- <li><a href="realm.html"><strong>Realm</strong></a> - >- Configure a realm that will allow its >- database of users, and their associated roles, to be shared across all >- <a href="host.html">Hosts</a> and <a href="context.html">Contexts</a> >- nested inside this Engine, unless overridden by a >- <a href="realm.html">Realm</a> configuration at a lower level.</li> >- </ul> >- >-</section> >- >- >-<section name="Special Features"> >- >- >- <subsection name="Logging"> >- >- <p>An engine is associated with the >- <code>org.apache.catalina.core.ContainerBase.[enginename]</code> >- log category. Note that the brackets are actually part of the name, >- don't omit them.</p> >- >- </subsection> >- >- >- <subsection name="Access Logs"> >- >- <p>When you run a web server, one of the output files normally generated >- is an <em>access log</em>, which generates one line of information for >- each request processed by the server, in a standard format. Catalina >- includes an optional <a href="valve.html">Valve</a> implementation that >- can create access logs in the same standard format created by web servers, >- or in any number of custom formats.</p> >- >- <p>You can ask Catalina to create an access log for all requests >- processed by an <a href="engine.html">Engine</a>, >- <a href="host.html">Host</a>, or <a href="context.html">Context</a> >- by nesting a <a href="valve.html">Valve</a> element like this:</p> >- >-<source> >-<Engine name="Standalone" ...> >- ... >- <Valve className="org.apache.catalina.valves.AccessLogValve" >- prefix="catalina_access_log." suffix=".txt" >- pattern="common"/> >- ... >-</Engine> >-</source> >- >- <p>See <a href="valve.html#Access Log Valve">Access Log Valve</a> >- for more information on the configuration attributes that are >- supported.</p> >- >- </subsection> >- >- >- <subsection name="Lifecycle Listeners"> >- >- <p>If you have implemented a Java object that needs to know when this >- <strong>Engine</strong> is started or stopped, you can declare it by >- nesting a <strong>Listener</strong> element inside this element. The >- class name you specify must implement the >- <code>org.apache.catalina.LifecycleListener</code> interface, and >- it will be notified about the occurrence of the corresponding >- lifecycle events. Configuration of such a listener looks like this:</p> >- >-<source> >-<Engine name="Standalone" ...> >- ... >- <Listener className="com.mycompany.mypackage.MyListener" ... > >- ... >-</Engine> >-</source> >- >- <p>Note that a Listener can have any number of additional properties >- that may be configured from this element. Attribute names are matched >- to corresponding JavaBean property names using the standard property >- method naming patterns.</p> >- >- </subsection> >- >- >- <subsection name="Request Filters"> >- >- <p>You can ask Catalina to check the IP address, or host name, on every >- incoming request directed to the surrounding >- <a href="engine.html">Engine</a>, <a href="host.html">Host</a>, or >- <a href="context.html">Context</a> element. The remote address or name >- will be checked against configured "accept" and/or "deny" >- filters, which are defined using <code>java.util.regex</code> Regular >- Expression syntax. Requests that come from locations that are >- not accepted will be rejected with an HTTP "Forbidden" error. >- Example filter declarations:</p> >- >-<source> >-<Engine name="Standalone" ...> >- ... >- <Valve className="org.apache.catalina.valves.RemoteHostValve" >- allow=".*\.mycompany\.com|www\.yourcompany\.com"/> >- <Valve className="org.apache.catalina.valves.RemoteAddrValve" >- deny="192\.168\.1\.\d+"/> >- ... >-</Engine> >-</source> >- >- <p>See <a href="valve.html#Remote Address Filter">Remote Address Filter</a> >- and <a href="valve.html#Remote Host Filter">Remote Host Filter</a> for >- more information about the configuration options that are supported.</p> >- >- </subsection> >- >- >-</section> >- >- >-</body> >- >- >-</document> >+<?xml version="1.0"?> >+<!-- >+ 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. >+--> >+<!DOCTYPE document [ >+ <!ENTITY project SYSTEM "project.xml"> >+]> >+<document url="engine.html"> >+ >+ &project; >+ >+ <properties> >+ <author email="craigmcc@apache.org">Craig R. McClanahan</author> >+ <title>The Engine Container</title> >+ </properties> >+ >+<body> >+ >+<section name="Table of Contents"> >+<toc/> >+</section> >+ >+<section name="Introduction"> >+ >+ <p>The <strong>Engine</strong> element represents the entire request >+ processing machinery associated with a particular Catalina >+ <a href="service.html">Service</a>. It receives and processes >+ <em>all</em> requests from one or more <strong>Connectors</strong>, >+ and returns the completed response to the Connector for ultimate >+ transmission back to the client.</p> >+ >+ <p>Exactly one <strong>Engine</strong> element MUST be nested inside >+ a <a href="service.html">Service</a> element, following all of the >+ corresponding Connector elements associated with this Service.</p> >+ >+</section> >+ >+ >+<section name="Attributes"> >+ >+ <subsection name="Common Attributes"> >+ >+ <p>All implementations of <strong>Engine</strong> >+ support the following attributes:</p> >+ >+ <attributes> >+ >+ <attribute name="backgroundProcessorDelay" required="false"> >+ <p>This value represents the delay in seconds between the >+ invocation of the backgroundProcess method on this engine and >+ its child containers, including all hosts and contexts. >+ Child containers will not be invoked if their delay value is not >+ negative (which would mean they are using their own processing >+ thread). Setting this to a positive value will cause >+ a thread to be spawn. After waiting the specified amount of time, >+ the thread will invoke the backgroundProcess method on this engine >+ and all its child containers. If not specified, the default value for >+ this attribute is 10, which represent a 10 seconds delay.</p> >+ </attribute> >+ >+ <attribute name="className" required="false"> >+ <p>Java class name of the implementation to use. This class must >+ implement the <code>org.apache.catalina.Engine</code> interface. >+ If not specified, the standard value (defined below) will be used.</p> >+ </attribute> >+ >+ <attribute name="defaultHost" required="true"> >+ <p>The default host name, which identifies the >+ <a href="host.html">Host</a> that will process requests directed >+ to host names on this server, but which are not configured in >+ this configuration file. This name MUST match the <code>name</code> >+ attributes of one of the <a href="host.html">Host</a> elements >+ nested immediately inside.</p> >+ </attribute> >+ >+ <attribute name="jvmRoute" required="false"> >+ <p>Identifier which must be used in load balancing scenarios to enable >+ session affinity. The identifier, which must be unique across all >+ Tomcat servers which participate in the cluster, will be appended to >+ the generated session identifier, therefore allowing the front end >+ proxy to always forward a particular session to the same Tomcat >+ instance.</p> >+ </attribute> >+ >+ <attribute name="name" required="true"> >+ <p>Logical name of this Engine, used in log and error messages. <em>When >+ using multiple <a href="service.html">Service</a> elements in the same >+ <a href="server.html">Server</a>, each Engine MUST be assigned a unique >+ name.</em></p> >+ </attribute> >+ >+ <attribute name="startStopThreads" required="false"> >+ <p>The number of threads this <strong>Engine</strong> will use to start >+ child <a href="host.html">Host</a> elements in parallel. The special >+ value of 0 will result in the value of >+ <code>Runtime.getRuntime().availableProcessors()</code> being used. >+ Negative values will result in >+ <code>Runtime.getRuntime().availableProcessors() + value</code> being >+ used unless this is less than 1 in which case 1 thread will be used. If >+ not specified, the default value of 1 will be used. </p> >+ </attribute> >+ >+ </attributes> >+ >+ </subsection> >+ >+ >+ <subsection name="Standard Implementation"> >+ >+ <p>The standard implementation of <strong>Engine</strong> is >+ <strong>org.apache.catalina.core.StandardEngine</strong>. >+ It supports the following additional attributes (in addition to the >+ common attributes listed above):</p> >+ >+ <attributes> >+ >+ </attributes> >+ >+ </subsection> >+ >+ >+</section> >+ >+ >+<section name="Nested Components"> >+ >+ <p>You can nest one or more <a href="host.html">Host</a> elements inside >+ this <strong>Engine</strong> element, each representing a different virtual >+ host associated with this server. At least one <a href="host.html">Host</a> >+ is required, and one of the nested <a href="host.html">Hosts</a> MUST >+ have a name that matches the name specified for the >+ <code>defaultHost</code> attribute, listed above.</p> >+ >+ <p>You can nest at most one instance of the following utility components >+ by nesting a corresponding element inside your <strong>Engine</strong> >+ element:</p> >+ <ul> >+ <li><a href="realm.html"><strong>Realm</strong></a> - >+ Configure a realm that will allow its >+ database of users, and their associated roles, to be shared across all >+ <a href="host.html">Hosts</a> and <a href="context.html">Contexts</a> >+ nested inside this Engine, unless overridden by a >+ <a href="realm.html">Realm</a> configuration at a lower level.</li> >+ </ul> >+ >+</section> >+ >+ >+<section name="Special Features"> >+ >+ >+ <subsection name="Logging"> >+ >+ <p>An engine is associated with the >+ <code>org.apache.catalina.core.ContainerBase.[enginename]</code> >+ log category. Note that the brackets are actually part of the name, >+ don't omit them.</p> >+ >+ </subsection> >+ >+ >+ <subsection name="Access Logs"> >+ >+ <p>When you run a web server, one of the output files normally generated >+ is an <em>access log</em>, which generates one line of information for >+ each request processed by the server, in a standard format. Catalina >+ includes an optional <a href="valve.html">Valve</a> implementation that >+ can create access logs in the same standard format created by web servers, >+ or in any number of custom formats.</p> >+ >+ <p>You can ask Catalina to create an access log for all requests >+ processed by an <a href="engine.html">Engine</a>, >+ <a href="host.html">Host</a>, or <a href="context.html">Context</a> >+ by nesting a <a href="valve.html">Valve</a> element like this:</p> >+ >+<source> >+<Engine name="Standalone" ...> >+ ... >+ <Valve className="org.apache.catalina.valves.AccessLogValve" >+ prefix="catalina_access_log." suffix=".txt" >+ pattern="common"/> >+ ... >+</Engine> >+</source> >+ >+ <p>See <a href="valve.html#Access Log Valve">Access Log Valve</a> >+ for more information on the configuration attributes that are >+ supported.</p> >+ >+ </subsection> >+ >+ >+ <subsection name="Lifecycle Listeners"> >+ >+ <p>If you have implemented a Java object that needs to know when this >+ <strong>Engine</strong> is started or stopped, you can declare it by >+ nesting a <strong>Listener</strong> element inside this element. The >+ class name you specify must implement the >+ <code>org.apache.catalina.LifecycleListener</code> interface, and >+ it will be notified about the occurrence of the corresponding >+ lifecycle events. Configuration of such a listener looks like this:</p> >+ >+<source> >+<Engine name="Standalone" ...> >+ ... >+ <Listener className="com.mycompany.mypackage.MyListener" ... > >+ ... >+</Engine> >+</source> >+ >+ <p>Note that a Listener can have any number of additional properties >+ that may be configured from this element. Attribute names are matched >+ to corresponding JavaBean property names using the standard property >+ method naming patterns.</p> >+ >+ </subsection> >+ >+ >+ <subsection name="Request Filters"> >+ >+ <p>You can ask Catalina to check the IP address, or host name, on every >+ incoming request directed to the surrounding >+ <a href="engine.html">Engine</a>, <a href="host.html">Host</a>, or >+ <a href="context.html">Context</a> element. The remote address or name >+ will be checked against configured "accept" and/or "deny" >+ filters, which are defined using <code>java.util.regex</code> Regular >+ Expression syntax. Requests that come from locations that are >+ not accepted will be rejected with an HTTP "Forbidden" error. >+ Example filter declarations:</p> >+ >+<source> >+<Engine name="Standalone" ...> >+ ... >+ <Valve className="org.apache.catalina.valves.RemoteHostValve" >+ allow=".*\.mycompany\.com|www\.yourcompany\.com"/> >+ <Valve className="org.apache.catalina.valves.RemoteAddrValve" >+ deny="192\.168\.1\.\d+"/> >+ ... >+</Engine> >+</source> >+ >+ <p>See <a href="valve.html#Remote Address Filter">Remote Address Filter</a> >+ and <a href="valve.html#Remote Host Filter">Remote Host Filter</a> for >+ more information about the configuration options that are supported.</p> >+ >+ </subsection> >+ >+ >+</section> >+ >+ >+</body> >+ >+ >+</document> >diff --git a/webapps/docs/config/host.xml b/webapps/docs/config/host.xml >index 53660f5..ba8f972 100644 >--- a/webapps/docs/config/host.xml >+++ b/webapps/docs/config/host.xml >@@ -1,671 +1,684 @@ >-<?xml version="1.0"?> >-<!-- >- 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. >---> >-<!DOCTYPE document [ >- <!ENTITY project SYSTEM "project.xml"> >-]> >-<document url="host.html"> >- >- &project; >- >- <properties> >- <author email="craigmcc@apache.org">Craig R. McClanahan</author> >- <author email="remm@apache.org">Remy Maucherat</author> >- <author email="yoavs@apache.org">Yoav Shapira</author> >- <title>The Host Container</title> >- </properties> >- >-<body> >- >-<section name="Table of Contents"> >-<toc/> >-</section> >- >-<section name="Introduction"> >- >- <p>The <strong>Host</strong> element represents a <em>virtual host</em>, >- which is an association of a network name for a server (such as >- "www.mycompany.com" with the particular server on which Tomcat is running. >- For clients to be able to connect to a Tomcat server using its network name, >- this name must be registered in the <em>Domain Name Service</em> (DNS) server >- that manages the Internet domain you belong to - contact your Network >- Administrator for more information.</p> >- >- <p>In many cases, System Administrators wish to associate more than >- one network name (such as <code>www.mycompany.com</code> and >- <code>company.com</code>) with the same virtual host and applications. >- This can be accomplished using the <a href="#Host Name Aliases">Host >- Name Aliases</a> feature discussed below.</p> >- >- <p>One or more <strong>Host</strong> elements are nested inside an >- <a href="engine.html">Engine</a> element. Inside the Host element, you >- can nest <a href="context.html">Context</a> elements for the web >- applications associated with this virtual host. Exactly one of the Hosts >- associated with each Engine MUST have a name matching the >- <code>defaultHost</code> attribute of that Engine.</p> >- >- <p>Clients normally use host names to identify the server they wish to connect >- to. This host name is also included in the HTTP request headers. Tomcat >- extracts the host name from the HTTP headers and looks for a >- <strong>Host</strong> with a matching name. If no match is found, the request >- is routed to the default host. The name of the default host does not have to >- match a DNS name (although it can) since any request where the DNS name does >- not match the name of a <strong>Host</strong> element will be routed to the >- default host.</p> >- >- <blockquote><em> >- <p>The description below uses the variable name $CATALINA_BASE to refer the >- base directory against which most relative paths are resolved. If you have >- not configured Tomcat for multiple instances by setting a CATALINA_BASE >- directory, then $CATALINA_BASE will be set to the value of $CATALINA_HOME, >- the directory into which you have installed Tomcat.</p> >- </em></blockquote> >- >-</section> >- >- >-<section name="Attributes"> >- >- <subsection name="Common Attributes"> >- >- <p>All implementations of <strong>Host</strong> >- support the following attributes:</p> >- >- <attributes> >- >- <attribute name="appBase" required="true"> >- <p>The <em>Application Base</em> directory for this virtual host. >- This is the pathname of a directory that may contain web applications >- to be deployed on this virtual host. You may specify an >- absolute pathname, or a pathname that is relative to the >- <code>$CATALINA_BASE</code> directory. See >- <a href="#Automatic Application Deployment">Automatic Application >- Deployment</a> for more information on automatic recognition and >- deployment of web applications. If not specified, the default of >- <code>webapps</code> will be used.</p> >- </attribute> >- >- <attribute name="xmlBase" required="false"> >- <p>The <em>XML Base</em> directory for this virtual host. >- This is the pathname of a directory that may contain context XML >- descriptors to be deployed on this virtual host. You may specify an >- absolute pathname for this directory, or a pathname that is relative >- to the <code>$CATALINA_BASE</code> directory. See >- <a href="#Automatic Application Deployment">Automatic Application >- Deployment</a> for more information on automatic recognition and >- deployment of web applications. If not specified the default of >- <code>[engine_name]/[host_name]</code> will be used.</p> >- </attribute> >- >- <attribute name="createDirs" required="false"> >- <p>If set to true, Tomcat will attempt to create the directories defined >- by the attributes <code>appBase</code> and <code>xmlBase</code> during >- the startup phase. The default value is <code>true</code>. If set to >- true, and directory creation fails, an error message will be printed out >- but will not halt the startup sequence.</p> >- </attribute> >- >- <attribute name="autoDeploy" required="false"> >- <p>This flag value indicates if Tomcat should check periodically for new >- or updated web applications while Tomcat is running. If true, Tomcat >- periodically checks the <code>appBase</code> and <code>xmlBase</code> >- directories and deploys any new web applications or context XML >- descriptors found. Updated web applications or context XML descriptors >- will trigger a reload of the web application. The flag's value defaults >- to true. See >- <a href="#Automatic Application Deployment">Automatic Application >- Deployment</a> for more information.</p> >- </attribute> >- >- <attribute name="backgroundProcessorDelay" required="false"> >- <p>This value represents the delay in seconds between the >- invocation of the backgroundProcess method on this host and >- its child containers, including all contexts. >- Child containers will not be invoked if their delay value is not >- negative (which would mean they are using their own processing >- thread). Setting this to a positive value will cause >- a thread to be spawn. After waiting the specified amount of time, >- the thread will invoke the backgroundProcess method on this host >- and all its child containers. A host will use background processing to >- perform live web application deployment related tasks. If not >- specified, the default value for this attribute is -1, which means >- the host will rely on the background processing thread of its parent >- engine.</p> >- </attribute> >- >- <attribute name="className" required="false"> >- <p>Java class name of the implementation to use. This class must >- implement the <code>org.apache.catalina.Host</code> interface. >- If not specified, the standard value (defined below) will be used.</p> >- </attribute> >- >- <attribute name="deployIgnore" required="false"> >- <p>A regular expression defining paths to ignore when >- <code>autoDeploy</code> and <code>deployOnStartup</code> are set. This >- allows you to keep your configuration in a version control system, for >- example, and not deploy a .svn or CVS folder that happens to be in the >- <code>appBase</code>.</p> >- <p>This regular expression is relative to <code>appBase</code>. It is >- also <em>anchored</em>, meaning the match is performed against the >- entire file/directory name. So, <code>foo</code> matches only a file or >- directory named <code>foo</code> but not <code>foo.war</code>, >- <code>foobar</code>, or <code>myfooapp</code>. To match anything with >- "foo", you could use <code>.*foo.*</code>.</p> >- <p>See <a href="#Automatic Application Deployment">Automatic Application >- Deployment</a> for more information.</p> >- </attribute> >- >- <attribute name="deployOnStartup" required="false"> >- <p>This flag value indicates if web applications from this host should >- be automatically deployed when Tomcat starts. The flag's value defaults >- to true. See >- <a href="#Automatic Application Deployment">Automatic Application >- Deployment</a> for more information.</p> >- </attribute> >- >- <attribute name="name" required="true"> >- <p>Usually the network name of this virtual host, as registered in your >- <em>Domain Name Service</em> server. Regardless of the case used to >- specify the host name, Tomcat will convert it to lower case internally. >- One of the Hosts nested within an <a href="engine.html">Engine</a> MUST >- have a name that matches the <code>defaultHost</code> setting for that >- Engine. See <a href="#Host Name Aliases">Host Name Aliases</a> for >- information on how to assign more than one network name to the same >- virtual host.</p> >- </attribute> >- >- </attributes> >- >- </subsection> >- >- >- <subsection name="Standard Implementation"> >- >- <p>The standard implementation of <strong>Host</strong> is >- <strong>org.apache.catalina.core.StandardHost</strong>. >- It supports the following additional attributes (in addition to the >- common attributes listed above):</p> >- >- <attributes> >- >- <attribute name="copyXML" required="false"> >- <p>Set to <code>true</code> if you want a context XML descriptor >- embedded inside the application (located at >- <code>/META-INF/context.xml</code>) to be copied to <code>xmlBase</code> >- when the application is deployed. On subsequent starts, the copied >- context XML descriptor will be used in preference to any context XML >- descriptor embedded inside the application even if the descriptor >- embedded inside the application is more recent. The flag's value >- defaults to <code>false</code>. Note if <strong>deployXML</strong> >- is <code>false</code>, this attribute will have no effect.</p> >- </attribute> >- >- <attribute name="deployXML" required="false"> >- <p>Set to <code>false</code> if you want to disable parsing the context >- XML descriptor embedded inside the application (located at >- <code>/META-INF/context.xml</code>). Security conscious environments >- should set this to <code>false</code> to prevent applications from >- interacting with the container's configuration. The administrator will >- then be responsible for providing an external context configuration >- file, and putting it in the location defined by the >- <strong>xmlBase</strong> attribute. The flag's value defaults to >- <code>true</code>.</p> >- </attribute> >- >- <attribute name="errorReportValveClass" required="false"> >- <p>Java class name of the error reporting valve which will be used >- by this Host. The responsibility of this valve is to output error >- reports. Setting this property allows to customize the look of the >- error pages which will be generated by Tomcat. This class must >- implement the >- <code>org.apache.catalina.Valve</code> interface. If none is specified, >- the value <code>org.apache.catalina.valves.ErrorReportValve</code> >- will be used by default.</p> >- </attribute> >- >- <attribute name="unpackWARs" required="false"> >- <p>Set to <code>true</code> if you want web applications that are >- placed in the <code>appBase</code> directory as web application >- archive (WAR) files to be unpacked into a corresponding disk directory >- structure, <code>false</code> to run such web applications directly >- from a WAR file. WAR files located outside of the Host's >- <strong>appBase</strong> will not be expanded. See >- <a href="#Automatic Application Deployment">Automatic Application >- Deployment</a> for more information.</p> >- </attribute> >- >- <attribute name="workDir" required="false"> >- <p>Pathname to a scratch directory to be used by applications for >- this Host. Each application will have its own sub directory with >- temporary read-write use. Configuring a Context workDir will override >- use of the Host workDir configuration. This directory will be made >- visible to servlets in the web application by a servlet context >- attribute (of type <code>java.io.File</code>) named >- <code>javax.servlet.context.tempdir</code> as described in the >- Servlet Specification. If not specified, a suitable directory >- underneath <code>$CATALINA_BASE/work</code> will be provided.</p> >- </attribute> >- >- </attributes> >- >- </subsection> >- >- >-</section> >- >- >-<section name="Nested Components"> >- >- <p>You can nest one or more <a href="context.html">Context</a> elements >- inside this <strong>Host</strong> element, each representing a different web >- application associated with this virtual host.</p> >- >- <p>You can nest at most one instance of the following utility components >- by nesting a corresponding element inside your <strong>Host</strong> >- element:</p> >- <ul> >- <li><a href="realm.html"><strong>Realm</strong></a> - >- Configure a realm that will allow its >- database of users, and their associated roles, to be shared across all >- <a href="context.html">Contexts</a> nested inside this Host (unless >- overridden by a <a href="realm.html">Realm</a> configuration >- at a lower level).</li> >- </ul> >- >-</section> >- >- >-<section name="Special Features"> >- >- >- <subsection name="Logging"> >- >- <p>A host is associated with the >- <code>org.apache.catalina.core.ContainerBase.[engine_name].[host_name]</code> >- log category. Note that the brackets are part of the name, >- don't omit them.</p> >- >- </subsection> >- >- >- <subsection name="Access Logs"> >- >- <p>When you run a web server, one of the output files normally generated >- is an <em>access log</em>, which generates one line of information for >- each request processed by the server, in a standard format. Catalina >- includes an optional <a href="valve.html">Valve</a> implementation that >- can create access logs in the same standard format created by web servers, >- or in any number of custom formats.</p> >- >- <p>You can ask Catalina to create an access log for all requests >- processed by an <a href="engine.html">Engine</a>, >- <a href="host.html">Host</a>, or <a href="context.html">Context</a> >- by nesting a <a href="valve.html">Valve</a> element like this:</p> >- >-<source> >-<Host name="localhost" ...> >- ... >- <Valve className="org.apache.catalina.valves.AccessLogValve" >- prefix="localhost_access_log." suffix=".txt" >- pattern="common"/> >- ... >-</Host> >-</source> >- >- <p>See <a href="valve.html#Access Log Valve">Access Log Valve</a> >- for more information on the configuration attributes that are >- supported.</p> >- >- </subsection> >- >- >- <subsection name="Automatic Application Deployment"> >- >- <p>If you are using the standard <strong>Host</strong> implementation, >- the following actions take place automatically when Catalina is first >- started, if the <code>deployOnStartup</code> property is set to >- <code>true</code> (which is the default value):</p> >- <ul> >- <li>Any XML file in the Host's <code>xmlBase</code> directory (by >- default <code>$CATALINA_BASE/conf/[engine_name]/[host_name]</code>) is >- assumed to be a context XML descriptor containing a >- <a href="context.html">Context</a> element (and its associated >- sub-elements) for a single web application. The web applications >- associated with each of these context XML descriptor files will be >- deployed first.<br/> >- The <code>docBase</code> attribute of this <code><Context></code> >- element must only be set if the docBase is outside the Host's >- <code>appBase</code>. For web applications located inside the Host's >- <code>appBase</code>, the <code>docBase</code> will be the name of the >- XML file with ".xml" replaced with ".war" for a web application archive >- or the name of the XML file with ".xml" removed for a directory.<br/> >- The <code>path</code> attribute must not be set. The context path used >- will be a slash character ("/") followed by the name of the XML file >- (less the .xml extension). Multi-level context paths may be defined >- using #, e.g. <code>foo#bar.xml</code> for a context path of >- <code>/foo/bar</code>. The default web application that has a context >- path of <code>/</code> may be defined by using a file called >- <code>ROOT.xml</code>.</li> >- <li>Any web application archive file within the Host's <code>appBase</code> >- directory that has not already been deployed as a result of a context >- XML descriptor, does not have a corresponding directory of the same >- name (without the ".war" extension), and is not excluded by >- <code>deployIgnore</code> will be deployed next. The context path >- used will be a slash character ("/") followed by the web application >- archive name less the ".war" extension. The one exception to this rule >- is that a web application archive named "ROOT.war" will be deployed with >- a context path of <code>/</code>. Multi-level contexts may be defined by >- using #, e.g. use a WAR named <code>foo#bar.war</code> for a context >- path of <code>/foo/bar</code>.<br/> >- If the <code>unpackWARs</code> attribute is <code>true</code>, the web >- application archive file will be expanded to a directory of the same >- name (without the ".war" extension".<br/> >- Note: If you re-deploy an updated WAR file while Tomcat is stopped, be >- sure to delete the associated expanded directory before restarting >- Tomcat, so that the updated WAR file will be re-expanded when Tomcat >- restarts.<br/> >- If <code>copyXml</code> is <code>true</code> (it is <code>false</code> >- by default), any web application archive file within the Hosts's >- <code>appBase</code> directory that does not have a corresponding >- context XML descriptor (with a ".xml" extension rather than a ".war" >- extension) in the Host's <code>xmlBase</code> will be scanned to see >- if it contains a context XML descriptor (located at >- <code>/META-INF/context.xml</code>) and if one is found the descriptor >- will be copied to the <code>xmlBase</code> directory and renamed. >- </li> >- <li>Finally, any sub-directory within the Host's <code>appBase</code> that >- has not already been deployed as a result of a context XML descriptor >- and is not excluded by <code>deployIgnore</code> will be deployed. >- The context path used will be a slash character ("/") followed by the >- directory name, unless the directory name is ROOT, in which case the >- context path will <code>/</code>. Multi-level contexts may be defined by >- using #, e.g. use a directory named <code>foo#bar</code> for a context >- path of <code>/foo/bar</code>.<br/> >- If <code>copyXml</code> is <code>true</code> (it is <code>false</code> >- by default), any directory within the Hosts's <code>appBase</code> >- directory that does not have a corresponding context XML descriptor in >- the Host's <code>xmlBase</code> will be scanned to see if it contains >- a context XML descriptor (located at <code>/META-INF/context.xml</code>) >- and if one is found the descriptor will be copied to the >- <code>xmlBase</code> directory and renamed. >- </li> >- </ul> >- >- <p>In addition to the automatic deployment that occurs at startup time, >- you can also request that new XML configuration files, WAR files, or >- sub-directories that are dropped in to the <code>appBase</code> (or >- <code>xmlBase</code> in the case of an XML configuration file) directory >- while Tomcat is running will be automatically deployed, according to the >- rules described above. The auto deployer will also track web applications >- for the following changes: >- <ul> >- <li>An update to the WEB-INF/web.xml file will trigger a reload of the >- web application</li> >- <li>Deleting a WAR file will trigger an undeploy of the application with >- the removal of any associated expanded directory, context file and >- work directory. Any current user sessions will not be persisted.</li> >- <li>Deleting a directory will trigger an undeploy of the application >- with the removal of any associated context file and work directory. >- Any current user sessions will not be persisted. If there is an >- associated WAR file, it will not be deleted and the application will >- be redeployed from the WAR file the next time the auto deployer checks >- for changes.</li> >- <li>Deleting a context file will trigger an undeploy of the application >- with the removal of any associated work directory. Any current user >- sessions will not be persisted. If there is an associated WAR file >- and/or directory, they will not be deleted and the application will be >- redeployed from the WAR file (or from directory if there is no WAR >- file) the next time the auto deployer checks for changes.</li> >- <li>Updating a WAR file will trigger an undeploy of the application with >- the removal of any associated expanded directory, context file and >- work directory. Any current user sessions will not be persisted.</li> >- <li>Updating a directory (not the directory contents) will trigger an >- undeploy of the application with the removal of any associated context >- file and work directory. Any current user sessions will not be >- persisted. The application will be redeployed the next time the auto >- deployer checks for changes.</li> >- <li>Updating a context file will trigger an undeploy of the application >- with the removal of any associated work directory. Any current user >- sessions will not be persisted. The application will be redeployed the >- next time the auto deployer checks for changes.</li> >- </ul> >- </p> >- >- <p>When using automatic deployment, the <code>docBase</code> defined by >- an XML <a href="context.html">Context</a> file should be outside of the >- <code>appBase</code> directory. If this is not the case, difficulties >- may be experienced deploying the web application or the application may >- be deployed twice. The <code>deployIgnore</code> attribute can be used >- to avoid this situation.</p> >- >- <p>Finally, note that if you are defining contexts explicitly in server.xml, >- you should probably turn off automatic application deployment or specify >- <code>deployIgnore</code> carefully. Otherwise, the web applications >- will each be deployed twice, and that may cause problems for the >- applications.</p> >- >- </subsection> >- >- >- <subsection name="Host Name Aliases"> >- >- <p>In many server environments, Network Administrators have configured >- more than one network name (in the <em>Domain Name Service</em> (DNS) >- server), that resolve to the IP address of the same server. Normally, >- each such network name would be configured as a separate >- <strong>Host</strong> element in <code>conf/server.xml</code>, each >- with its own set of web applications.</p> >- >- <p>However, in some circumstances, it is desirable that two or more >- network names should resolve to the <strong>same</strong> virtual host, >- running the same set of applications. A common use case for this >- scenario is a corporate web site, where it is desirable that users >- be able to utilize either <code>www.mycompany.com</code> or >- <code>company.com</code> to access exactly the same content and >- applications.</p> >- >- <p>This is accomplished by utilizing one or more <strong>Alias</strong> >- elements nested inside your <strong>Host</strong> element. For >- example:</p> >-<source> >-<Host name="www.mycompany.com" ...> >- ... >- <Alias>mycompany.com</Alias> >- ... >-</Host> >-</source> >- >- <p>In order for this strategy to be effective, all of the network names >- involved must be registered in your DNS server to resolve to the >- same computer that is running this instance of Catalina.</p> >- >- </subsection> >- >- >- <subsection name="Lifecycle Listeners"> >- >- <p>If you have implemented a Java object that needs to know when this >- <strong>Host</strong> is started or stopped, you can declare it by >- nesting a <strong>Listener</strong> element inside this element. The >- class name you specify must implement the >- <code>org.apache.catalina.LifecycleListener</code> interface, and >- it will be notified about the occurrence of the corresponding >- lifecycle events. Configuration of such a listener looks like this:</p> >- >-<source> >-<Host name="localhost" ...> >- ... >- <Listener className="com.mycompany.mypackage.MyListener" ... > >- ... >-</Host> >-</source> >- >- <p>Note that a Listener can have any number of additional properties >- that may be configured from this element. Attribute names are matched >- to corresponding JavaBean property names using the standard property >- method naming patterns.</p> >- >- </subsection> >- >- >- <subsection name="Request Filters"> >- >- <p>You can ask Catalina to check the IP address, or host name, on every >- incoming request directed to the surrounding >- <a href="engine.html">Engine</a>, <a href="host.html">Host</a>, or >- <a href="context.html">Context</a> element. The remote address or name >- will be checked against configured "accept" and/or "deny" >- filters, which are defined using <code>java.util.regex</code> Regular >- Expression syntax. Requests that come from locations that are >- not accepted will be rejected with an HTTP "Forbidden" error. >- Example filter declarations:</p> >- >-<source> >-<Host name="localhost" ...> >- ... >- <Valve className="org.apache.catalina.valves.RemoteHostValve" >- allow=".*\.mycompany\.com|www\.yourcompany\.com"/> >- <Valve className="org.apache.catalina.valves.RemoteAddrValve" >- deny="192\.168\.1\.\d+"/> >- ... >-</Host> >-</source> >- >- <p>See <a href="valve.html#Remote Address Filter">Remote Address Filter</a> >- and <a href="valve.html#Remote Host Filter">Remote Host Filter</a> for >- more information about the configuration options that are supported.</p> >- >- </subsection> >- >- >- <subsection name="Single Sign On"> >- >- <p>In many environments, but particularly in portal environments, it >- is desireable to have a user challenged to authenticate themselves only >- once over a set of web applications deployed on a particular virtual >- host. This can be accomplished by nesting an element like this inside >- the Host element for this virtual host:</p> >- >-<source> >-<Host name="localhost" ...> >- ... >- <Valve className="org.apache.catalina.authenticator.SingleSignOn"/> >- ... >-</Host> >-</source> >- >- <p>The Single Sign On facility operates according to the following rules: >- </p> >- <ul> >- <li>All web applications configured for this virtual host must share the >- same <a href="realm.html">Realm</a>. In practice, that means you can >- nest the Realm element inside this Host element (or the surrounding >- <a href="engine.html">Engine</a> element), but not inside a >- <a href="context.html">Context</a> element for one of the involved >- web applications.</li> >- <li>As long as the user accesses only unprotected resources in any of the >- web applications on this virtual host, they will not be challenged >- to authenticate themselves.</li> >- <li>As soon as the user accesses a protected resource in >- <strong>any</strong> web application associated with this virtual >- host, the user will be challenged to authenticate himself or herself, >- using the login method defined for the web application currently >- being accessed.</li> >- <li>Once authenticated, the roles associated with this user will be >- utilized for access control decisions across <strong>all</strong> >- of the associated web applications, without challenging the user >- to authenticate themselves to each application individually.</li> >- <li>As soon as the user logs out of one web application (for example, >- by invalidating the corresponding session if form >- based login is used), the user's sessions in <strong>all</strong> >- web applications will be invalidated. Any subsequent attempt to >- access a protected resource in any application will require the >- user to authenticate himself or herself again.</li> >- <li>The Single Sign On feature utilizes HTTP cookies to transmit a token >- that associates each request with the saved user identity, so it can >- only be utilized in client environments that support cookies.</li> >- </ul> >- >- </subsection> >- >- >- <subsection name="User Web Applications"> >- >- <p>Many web servers can automatically map a request URI starting with >- a tilde character ("~") and a username to a directory (commonly named >- <code>public_html</code>) in that user's home directory on the server. >- You can accomplish the same thing in Catalina by using a special >- <strong>Listener</strong> element like this (on a Unix system that >- uses the <code>/etc/passwd</code> file to identify valid users):</p> >- >-<source> >-<Host name="localhost" ...> >- ... >- <Listener className="org.apache.catalina.startup.UserConfig" >- directoryName="public_html" >- userClass="org.apache.catalina.startup.PasswdUserDatabase"/> >- ... >-</Host> >-</source> >- >- <p>On a server where <code>/etc/passwd</code> is not in use, you can >- request Catalina to consider all directories found in a specified base >- directory (such as <code>c:\Homes</code> in this example) to be >- considered "user home" directories for the purposes of this directive:</p> >- >-<source> >-<Host name="localhost" ...> >- ... >- <Listener className="org.apache.catalina.startup.UserConfig" >- directoryName="public_html" >- homeBase=c:\Homes" >- userClass="org.apache.catalina.startup.HomesUserDatabase"/> >- ... >-</Host> >-</source> >- >- <p>If a user home directory has been set up for a user named >- <code>craigmcc</code>, then its contents will be visible from a >- client browser by making a request to a URL like:</p> >- >-<source> >-http://www.mycompany.com:8080/~craigmcc >-</source> >- >- <p>Successful use of this feature requires recognition of the following >- considerations:</p> >- <ul> >- <li>Each user web application will be deployed with characteristics >- established by the global and host level default context settings.</li> >- <li>It is legal to include more than one instance of this Listener >- element. This would only be useful, however, in circumstances >- where you wanted to configure more than one "homeBase" directory.</li> >- <li>The operating system username under which Catalina is executed >- MUST have read access to each user's web application directory, >- and all of its contents.</li> >- </ul> >- >- </subsection> >- >- >-</section> >- >- >-</body> >- >- >-</document> >+<?xml version="1.0"?> >+<!-- >+ 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. >+--> >+<!DOCTYPE document [ >+ <!ENTITY project SYSTEM "project.xml"> >+]> >+<document url="host.html"> >+ >+ &project; >+ >+ <properties> >+ <author email="craigmcc@apache.org">Craig R. McClanahan</author> >+ <author email="remm@apache.org">Remy Maucherat</author> >+ <author email="yoavs@apache.org">Yoav Shapira</author> >+ <title>The Host Container</title> >+ </properties> >+ >+<body> >+ >+<section name="Table of Contents"> >+<toc/> >+</section> >+ >+<section name="Introduction"> >+ >+ <p>The <strong>Host</strong> element represents a <em>virtual host</em>, >+ which is an association of a network name for a server (such as >+ "www.mycompany.com" with the particular server on which Tomcat is running. >+ For clients to be able to connect to a Tomcat server using its network name, >+ this name must be registered in the <em>Domain Name Service</em> (DNS) server >+ that manages the Internet domain you belong to - contact your Network >+ Administrator for more information.</p> >+ >+ <p>In many cases, System Administrators wish to associate more than >+ one network name (such as <code>www.mycompany.com</code> and >+ <code>company.com</code>) with the same virtual host and applications. >+ This can be accomplished using the <a href="#Host Name Aliases">Host >+ Name Aliases</a> feature discussed below.</p> >+ >+ <p>One or more <strong>Host</strong> elements are nested inside an >+ <a href="engine.html">Engine</a> element. Inside the Host element, you >+ can nest <a href="context.html">Context</a> elements for the web >+ applications associated with this virtual host. Exactly one of the Hosts >+ associated with each Engine MUST have a name matching the >+ <code>defaultHost</code> attribute of that Engine.</p> >+ >+ <p>Clients normally use host names to identify the server they wish to connect >+ to. This host name is also included in the HTTP request headers. Tomcat >+ extracts the host name from the HTTP headers and looks for a >+ <strong>Host</strong> with a matching name. If no match is found, the request >+ is routed to the default host. The name of the default host does not have to >+ match a DNS name (although it can) since any request where the DNS name does >+ not match the name of a <strong>Host</strong> element will be routed to the >+ default host.</p> >+ >+ <blockquote><em> >+ <p>The description below uses the variable name $CATALINA_BASE to refer the >+ base directory against which most relative paths are resolved. If you have >+ not configured Tomcat for multiple instances by setting a CATALINA_BASE >+ directory, then $CATALINA_BASE will be set to the value of $CATALINA_HOME, >+ the directory into which you have installed Tomcat.</p> >+ </em></blockquote> >+ >+</section> >+ >+ >+<section name="Attributes"> >+ >+ <subsection name="Common Attributes"> >+ >+ <p>All implementations of <strong>Host</strong> >+ support the following attributes:</p> >+ >+ <attributes> >+ >+ <attribute name="appBase" required="true"> >+ <p>The <em>Application Base</em> directory for this virtual host. >+ This is the pathname of a directory that may contain web applications >+ to be deployed on this virtual host. You may specify an >+ absolute pathname, or a pathname that is relative to the >+ <code>$CATALINA_BASE</code> directory. See >+ <a href="#Automatic Application Deployment">Automatic Application >+ Deployment</a> for more information on automatic recognition and >+ deployment of web applications. If not specified, the default of >+ <code>webapps</code> will be used.</p> >+ </attribute> >+ >+ <attribute name="xmlBase" required="false"> >+ <p>The <em>XML Base</em> directory for this virtual host. >+ This is the pathname of a directory that may contain context XML >+ descriptors to be deployed on this virtual host. You may specify an >+ absolute pathname for this directory, or a pathname that is relative >+ to the <code>$CATALINA_BASE</code> directory. See >+ <a href="#Automatic Application Deployment">Automatic Application >+ Deployment</a> for more information on automatic recognition and >+ deployment of web applications. If not specified the default of >+ <code>[engine_name]/[host_name]</code> will be used.</p> >+ </attribute> >+ >+ <attribute name="createDirs" required="false"> >+ <p>If set to true, Tomcat will attempt to create the directories defined >+ by the attributes <code>appBase</code> and <code>xmlBase</code> during >+ the startup phase. The default value is <code>true</code>. If set to >+ true, and directory creation fails, an error message will be printed out >+ but will not halt the startup sequence.</p> >+ </attribute> >+ >+ <attribute name="autoDeploy" required="false"> >+ <p>This flag value indicates if Tomcat should check periodically for new >+ or updated web applications while Tomcat is running. If true, Tomcat >+ periodically checks the <code>appBase</code> and <code>xmlBase</code> >+ directories and deploys any new web applications or context XML >+ descriptors found. Updated web applications or context XML descriptors >+ will trigger a reload of the web application. The flag's value defaults >+ to true. See >+ <a href="#Automatic Application Deployment">Automatic Application >+ Deployment</a> for more information.</p> >+ </attribute> >+ >+ <attribute name="backgroundProcessorDelay" required="false"> >+ <p>This value represents the delay in seconds between the >+ invocation of the backgroundProcess method on this host and >+ its child containers, including all contexts. >+ Child containers will not be invoked if their delay value is not >+ negative (which would mean they are using their own processing >+ thread). Setting this to a positive value will cause >+ a thread to be spawn. After waiting the specified amount of time, >+ the thread will invoke the backgroundProcess method on this host >+ and all its child containers. A host will use background processing to >+ perform live web application deployment related tasks. If not >+ specified, the default value for this attribute is -1, which means >+ the host will rely on the background processing thread of its parent >+ engine.</p> >+ </attribute> >+ >+ <attribute name="className" required="false"> >+ <p>Java class name of the implementation to use. This class must >+ implement the <code>org.apache.catalina.Host</code> interface. >+ If not specified, the standard value (defined below) will be used.</p> >+ </attribute> >+ >+ <attribute name="deployIgnore" required="false"> >+ <p>A regular expression defining paths to ignore when >+ <code>autoDeploy</code> and <code>deployOnStartup</code> are set. This >+ allows you to keep your configuration in a version control system, for >+ example, and not deploy a .svn or CVS folder that happens to be in the >+ <code>appBase</code>.</p> >+ <p>This regular expression is relative to <code>appBase</code>. It is >+ also <em>anchored</em>, meaning the match is performed against the >+ entire file/directory name. So, <code>foo</code> matches only a file or >+ directory named <code>foo</code> but not <code>foo.war</code>, >+ <code>foobar</code>, or <code>myfooapp</code>. To match anything with >+ "foo", you could use <code>.*foo.*</code>.</p> >+ <p>See <a href="#Automatic Application Deployment">Automatic Application >+ Deployment</a> for more information.</p> >+ </attribute> >+ >+ <attribute name="deployOnStartup" required="false"> >+ <p>This flag value indicates if web applications from this host should >+ be automatically deployed when Tomcat starts. The flag's value defaults >+ to true. See >+ <a href="#Automatic Application Deployment">Automatic Application >+ Deployment</a> for more information.</p> >+ </attribute> >+ >+ <attribute name="name" required="true"> >+ <p>Usually the network name of this virtual host, as registered in your >+ <em>Domain Name Service</em> server. Regardless of the case used to >+ specify the host name, Tomcat will convert it to lower case internally. >+ One of the Hosts nested within an <a href="engine.html">Engine</a> MUST >+ have a name that matches the <code>defaultHost</code> setting for that >+ Engine. See <a href="#Host Name Aliases">Host Name Aliases</a> for >+ information on how to assign more than one network name to the same >+ virtual host.</p> >+ </attribute> >+ >+ <attribute name="startStopThreads" required="false"> >+ <p>The number of threads this <strong>Host</strong> will use to start >+ child <a href="context.html">Context</a> elements in parallel. The same >+ thread pool will be used to deploy new >+ <a href="context.html">Context</a>s if automatic deployment is being >+ used. The special value of 0 will result in the value of >+ <code>Runtime.getRuntime().availableProcessors()</code> being used. >+ Negative values will result in >+ <code>Runtime.getRuntime().availableProcessors() + value</code> being >+ used unless this is less than 1 in which case 1 thread will be used. If >+ not specified, the default value of 1 will be used.</p> >+ </attribute> >+ >+ </attributes> >+ >+ </subsection> >+ >+ >+ <subsection name="Standard Implementation"> >+ >+ <p>The standard implementation of <strong>Host</strong> is >+ <strong>org.apache.catalina.core.StandardHost</strong>. >+ It supports the following additional attributes (in addition to the >+ common attributes listed above):</p> >+ >+ <attributes> >+ >+ <attribute name="copyXML" required="false"> >+ <p>Set to <code>true</code> if you want a context XML descriptor >+ embedded inside the application (located at >+ <code>/META-INF/context.xml</code>) to be copied to <code>xmlBase</code> >+ when the application is deployed. On subsequent starts, the copied >+ context XML descriptor will be used in preference to any context XML >+ descriptor embedded inside the application even if the descriptor >+ embedded inside the application is more recent. The flag's value >+ defaults to <code>false</code>. Note if <strong>deployXML</strong> >+ is <code>false</code>, this attribute will have no effect.</p> >+ </attribute> >+ >+ <attribute name="deployXML" required="false"> >+ <p>Set to <code>false</code> if you want to disable parsing the context >+ XML descriptor embedded inside the application (located at >+ <code>/META-INF/context.xml</code>). Security conscious environments >+ should set this to <code>false</code> to prevent applications from >+ interacting with the container's configuration. The administrator will >+ then be responsible for providing an external context configuration >+ file, and putting it in the location defined by the >+ <strong>xmlBase</strong> attribute. The flag's value defaults to >+ <code>true</code>.</p> >+ </attribute> >+ >+ <attribute name="errorReportValveClass" required="false"> >+ <p>Java class name of the error reporting valve which will be used >+ by this Host. The responsibility of this valve is to output error >+ reports. Setting this property allows to customize the look of the >+ error pages which will be generated by Tomcat. This class must >+ implement the >+ <code>org.apache.catalina.Valve</code> interface. If none is specified, >+ the value <code>org.apache.catalina.valves.ErrorReportValve</code> >+ will be used by default.</p> >+ </attribute> >+ >+ <attribute name="unpackWARs" required="false"> >+ <p>Set to <code>true</code> if you want web applications that are >+ placed in the <code>appBase</code> directory as web application >+ archive (WAR) files to be unpacked into a corresponding disk directory >+ structure, <code>false</code> to run such web applications directly >+ from a WAR file. WAR files located outside of the Host's >+ <strong>appBase</strong> will not be expanded. See >+ <a href="#Automatic Application Deployment">Automatic Application >+ Deployment</a> for more information.</p> >+ </attribute> >+ >+ <attribute name="workDir" required="false"> >+ <p>Pathname to a scratch directory to be used by applications for >+ this Host. Each application will have its own sub directory with >+ temporary read-write use. Configuring a Context workDir will override >+ use of the Host workDir configuration. This directory will be made >+ visible to servlets in the web application by a servlet context >+ attribute (of type <code>java.io.File</code>) named >+ <code>javax.servlet.context.tempdir</code> as described in the >+ Servlet Specification. If not specified, a suitable directory >+ underneath <code>$CATALINA_BASE/work</code> will be provided.</p> >+ </attribute> >+ >+ </attributes> >+ >+ </subsection> >+ >+ >+</section> >+ >+ >+<section name="Nested Components"> >+ >+ <p>You can nest one or more <a href="context.html">Context</a> elements >+ inside this <strong>Host</strong> element, each representing a different web >+ application associated with this virtual host.</p> >+ >+ <p>You can nest at most one instance of the following utility components >+ by nesting a corresponding element inside your <strong>Host</strong> >+ element:</p> >+ <ul> >+ <li><a href="realm.html"><strong>Realm</strong></a> - >+ Configure a realm that will allow its >+ database of users, and their associated roles, to be shared across all >+ <a href="context.html">Contexts</a> nested inside this Host (unless >+ overridden by a <a href="realm.html">Realm</a> configuration >+ at a lower level).</li> >+ </ul> >+ >+</section> >+ >+ >+<section name="Special Features"> >+ >+ >+ <subsection name="Logging"> >+ >+ <p>A host is associated with the >+ <code>org.apache.catalina.core.ContainerBase.[engine_name].[host_name]</code> >+ log category. Note that the brackets are part of the name, >+ don't omit them.</p> >+ >+ </subsection> >+ >+ >+ <subsection name="Access Logs"> >+ >+ <p>When you run a web server, one of the output files normally generated >+ is an <em>access log</em>, which generates one line of information for >+ each request processed by the server, in a standard format. Catalina >+ includes an optional <a href="valve.html">Valve</a> implementation that >+ can create access logs in the same standard format created by web servers, >+ or in any number of custom formats.</p> >+ >+ <p>You can ask Catalina to create an access log for all requests >+ processed by an <a href="engine.html">Engine</a>, >+ <a href="host.html">Host</a>, or <a href="context.html">Context</a> >+ by nesting a <a href="valve.html">Valve</a> element like this:</p> >+ >+<source> >+<Host name="localhost" ...> >+ ... >+ <Valve className="org.apache.catalina.valves.AccessLogValve" >+ prefix="localhost_access_log." suffix=".txt" >+ pattern="common"/> >+ ... >+</Host> >+</source> >+ >+ <p>See <a href="valve.html#Access Log Valve">Access Log Valve</a> >+ for more information on the configuration attributes that are >+ supported.</p> >+ >+ </subsection> >+ >+ >+ <subsection name="Automatic Application Deployment"> >+ >+ <p>If you are using the standard <strong>Host</strong> implementation, >+ the following actions take place automatically when Catalina is first >+ started, if the <code>deployOnStartup</code> property is set to >+ <code>true</code> (which is the default value):</p> >+ <ul> >+ <li>Any XML file in the Host's <code>xmlBase</code> directory (by >+ default <code>$CATALINA_BASE/conf/[engine_name]/[host_name]</code>) is >+ assumed to be a context XML descriptor containing a >+ <a href="context.html">Context</a> element (and its associated >+ sub-elements) for a single web application. The web applications >+ associated with each of these context XML descriptor files will be >+ deployed first.<br/> >+ The <code>docBase</code> attribute of this <code><Context></code> >+ element must only be set if the docBase is outside the Host's >+ <code>appBase</code>. For web applications located inside the Host's >+ <code>appBase</code>, the <code>docBase</code> will be the name of the >+ XML file with ".xml" replaced with ".war" for a web application archive >+ or the name of the XML file with ".xml" removed for a directory.<br/> >+ The <code>path</code> attribute must not be set. The context path used >+ will be a slash character ("/") followed by the name of the XML file >+ (less the .xml extension). Multi-level context paths may be defined >+ using #, e.g. <code>foo#bar.xml</code> for a context path of >+ <code>/foo/bar</code>. The default web application that has a context >+ path of <code>/</code> may be defined by using a file called >+ <code>ROOT.xml</code>.</li> >+ <li>Any web application archive file within the Host's <code>appBase</code> >+ directory that has not already been deployed as a result of a context >+ XML descriptor, does not have a corresponding directory of the same >+ name (without the ".war" extension), and is not excluded by >+ <code>deployIgnore</code> will be deployed next. The context path >+ used will be a slash character ("/") followed by the web application >+ archive name less the ".war" extension. The one exception to this rule >+ is that a web application archive named "ROOT.war" will be deployed with >+ a context path of <code>/</code>. Multi-level contexts may be defined by >+ using #, e.g. use a WAR named <code>foo#bar.war</code> for a context >+ path of <code>/foo/bar</code>.<br/> >+ If the <code>unpackWARs</code> attribute is <code>true</code>, the web >+ application archive file will be expanded to a directory of the same >+ name (without the ".war" extension".<br/> >+ Note: If you re-deploy an updated WAR file while Tomcat is stopped, be >+ sure to delete the associated expanded directory before restarting >+ Tomcat, so that the updated WAR file will be re-expanded when Tomcat >+ restarts.<br/> >+ If <code>copyXml</code> is <code>true</code> (it is <code>false</code> >+ by default), any web application archive file within the Hosts's >+ <code>appBase</code> directory that does not have a corresponding >+ context XML descriptor (with a ".xml" extension rather than a ".war" >+ extension) in the Host's <code>xmlBase</code> will be scanned to see >+ if it contains a context XML descriptor (located at >+ <code>/META-INF/context.xml</code>) and if one is found the descriptor >+ will be copied to the <code>xmlBase</code> directory and renamed. >+ </li> >+ <li>Finally, any sub-directory within the Host's <code>appBase</code> that >+ has not already been deployed as a result of a context XML descriptor >+ and is not excluded by <code>deployIgnore</code> will be deployed. >+ The context path used will be a slash character ("/") followed by the >+ directory name, unless the directory name is ROOT, in which case the >+ context path will <code>/</code>. Multi-level contexts may be defined by >+ using #, e.g. use a directory named <code>foo#bar</code> for a context >+ path of <code>/foo/bar</code>.<br/> >+ If <code>copyXml</code> is <code>true</code> (it is <code>false</code> >+ by default), any directory within the Hosts's <code>appBase</code> >+ directory that does not have a corresponding context XML descriptor in >+ the Host's <code>xmlBase</code> will be scanned to see if it contains >+ a context XML descriptor (located at <code>/META-INF/context.xml</code>) >+ and if one is found the descriptor will be copied to the >+ <code>xmlBase</code> directory and renamed. >+ </li> >+ </ul> >+ >+ <p>In addition to the automatic deployment that occurs at startup time, >+ you can also request that new XML configuration files, WAR files, or >+ sub-directories that are dropped in to the <code>appBase</code> (or >+ <code>xmlBase</code> in the case of an XML configuration file) directory >+ while Tomcat is running will be automatically deployed, according to the >+ rules described above. The auto deployer will also track web applications >+ for the following changes: >+ <ul> >+ <li>An update to the WEB-INF/web.xml file will trigger a reload of the >+ web application</li> >+ <li>Deleting a WAR file will trigger an undeploy of the application with >+ the removal of any associated expanded directory, context file and >+ work directory. Any current user sessions will not be persisted.</li> >+ <li>Deleting a directory will trigger an undeploy of the application >+ with the removal of any associated context file and work directory. >+ Any current user sessions will not be persisted. If there is an >+ associated WAR file, it will not be deleted and the application will >+ be redeployed from the WAR file the next time the auto deployer checks >+ for changes.</li> >+ <li>Deleting a context file will trigger an undeploy of the application >+ with the removal of any associated work directory. Any current user >+ sessions will not be persisted. If there is an associated WAR file >+ and/or directory, they will not be deleted and the application will be >+ redeployed from the WAR file (or from directory if there is no WAR >+ file) the next time the auto deployer checks for changes.</li> >+ <li>Updating a WAR file will trigger an undeploy of the application with >+ the removal of any associated expanded directory, context file and >+ work directory. Any current user sessions will not be persisted.</li> >+ <li>Updating a directory (not the directory contents) will trigger an >+ undeploy of the application with the removal of any associated context >+ file and work directory. Any current user sessions will not be >+ persisted. The application will be redeployed the next time the auto >+ deployer checks for changes.</li> >+ <li>Updating a context file will trigger an undeploy of the application >+ with the removal of any associated work directory. Any current user >+ sessions will not be persisted. The application will be redeployed the >+ next time the auto deployer checks for changes.</li> >+ </ul> >+ </p> >+ >+ <p>When using automatic deployment, the <code>docBase</code> defined by >+ an XML <a href="context.html">Context</a> file should be outside of the >+ <code>appBase</code> directory. If this is not the case, difficulties >+ may be experienced deploying the web application or the application may >+ be deployed twice. The <code>deployIgnore</code> attribute can be used >+ to avoid this situation.</p> >+ >+ <p>Finally, note that if you are defining contexts explicitly in server.xml, >+ you should probably turn off automatic application deployment or specify >+ <code>deployIgnore</code> carefully. Otherwise, the web applications >+ will each be deployed twice, and that may cause problems for the >+ applications.</p> >+ >+ </subsection> >+ >+ >+ <subsection name="Host Name Aliases"> >+ >+ <p>In many server environments, Network Administrators have configured >+ more than one network name (in the <em>Domain Name Service</em> (DNS) >+ server), that resolve to the IP address of the same server. Normally, >+ each such network name would be configured as a separate >+ <strong>Host</strong> element in <code>conf/server.xml</code>, each >+ with its own set of web applications.</p> >+ >+ <p>However, in some circumstances, it is desirable that two or more >+ network names should resolve to the <strong>same</strong> virtual host, >+ running the same set of applications. A common use case for this >+ scenario is a corporate web site, where it is desirable that users >+ be able to utilize either <code>www.mycompany.com</code> or >+ <code>company.com</code> to access exactly the same content and >+ applications.</p> >+ >+ <p>This is accomplished by utilizing one or more <strong>Alias</strong> >+ elements nested inside your <strong>Host</strong> element. For >+ example:</p> >+<source> >+<Host name="www.mycompany.com" ...> >+ ... >+ <Alias>mycompany.com</Alias> >+ ... >+</Host> >+</source> >+ >+ <p>In order for this strategy to be effective, all of the network names >+ involved must be registered in your DNS server to resolve to the >+ same computer that is running this instance of Catalina.</p> >+ >+ </subsection> >+ >+ >+ <subsection name="Lifecycle Listeners"> >+ >+ <p>If you have implemented a Java object that needs to know when this >+ <strong>Host</strong> is started or stopped, you can declare it by >+ nesting a <strong>Listener</strong> element inside this element. The >+ class name you specify must implement the >+ <code>org.apache.catalina.LifecycleListener</code> interface, and >+ it will be notified about the occurrence of the corresponding >+ lifecycle events. Configuration of such a listener looks like this:</p> >+ >+<source> >+<Host name="localhost" ...> >+ ... >+ <Listener className="com.mycompany.mypackage.MyListener" ... > >+ ... >+</Host> >+</source> >+ >+ <p>Note that a Listener can have any number of additional properties >+ that may be configured from this element. Attribute names are matched >+ to corresponding JavaBean property names using the standard property >+ method naming patterns.</p> >+ >+ </subsection> >+ >+ >+ <subsection name="Request Filters"> >+ >+ <p>You can ask Catalina to check the IP address, or host name, on every >+ incoming request directed to the surrounding >+ <a href="engine.html">Engine</a>, <a href="host.html">Host</a>, or >+ <a href="context.html">Context</a> element. The remote address or name >+ will be checked against configured "accept" and/or "deny" >+ filters, which are defined using <code>java.util.regex</code> Regular >+ Expression syntax. Requests that come from locations that are >+ not accepted will be rejected with an HTTP "Forbidden" error. >+ Example filter declarations:</p> >+ >+<source> >+<Host name="localhost" ...> >+ ... >+ <Valve className="org.apache.catalina.valves.RemoteHostValve" >+ allow=".*\.mycompany\.com|www\.yourcompany\.com"/> >+ <Valve className="org.apache.catalina.valves.RemoteAddrValve" >+ deny="192\.168\.1\.\d+"/> >+ ... >+</Host> >+</source> >+ >+ <p>See <a href="valve.html#Remote Address Filter">Remote Address Filter</a> >+ and <a href="valve.html#Remote Host Filter">Remote Host Filter</a> for >+ more information about the configuration options that are supported.</p> >+ >+ </subsection> >+ >+ >+ <subsection name="Single Sign On"> >+ >+ <p>In many environments, but particularly in portal environments, it >+ is desireable to have a user challenged to authenticate themselves only >+ once over a set of web applications deployed on a particular virtual >+ host. This can be accomplished by nesting an element like this inside >+ the Host element for this virtual host:</p> >+ >+<source> >+<Host name="localhost" ...> >+ ... >+ <Valve className="org.apache.catalina.authenticator.SingleSignOn"/> >+ ... >+</Host> >+</source> >+ >+ <p>The Single Sign On facility operates according to the following rules: >+ </p> >+ <ul> >+ <li>All web applications configured for this virtual host must share the >+ same <a href="realm.html">Realm</a>. In practice, that means you can >+ nest the Realm element inside this Host element (or the surrounding >+ <a href="engine.html">Engine</a> element), but not inside a >+ <a href="context.html">Context</a> element for one of the involved >+ web applications.</li> >+ <li>As long as the user accesses only unprotected resources in any of the >+ web applications on this virtual host, they will not be challenged >+ to authenticate themselves.</li> >+ <li>As soon as the user accesses a protected resource in >+ <strong>any</strong> web application associated with this virtual >+ host, the user will be challenged to authenticate himself or herself, >+ using the login method defined for the web application currently >+ being accessed.</li> >+ <li>Once authenticated, the roles associated with this user will be >+ utilized for access control decisions across <strong>all</strong> >+ of the associated web applications, without challenging the user >+ to authenticate themselves to each application individually.</li> >+ <li>As soon as the user logs out of one web application (for example, >+ by invalidating the corresponding session if form >+ based login is used), the user's sessions in <strong>all</strong> >+ web applications will be invalidated. Any subsequent attempt to >+ access a protected resource in any application will require the >+ user to authenticate himself or herself again.</li> >+ <li>The Single Sign On feature utilizes HTTP cookies to transmit a token >+ that associates each request with the saved user identity, so it can >+ only be utilized in client environments that support cookies.</li> >+ </ul> >+ >+ </subsection> >+ >+ >+ <subsection name="User Web Applications"> >+ >+ <p>Many web servers can automatically map a request URI starting with >+ a tilde character ("~") and a username to a directory (commonly named >+ <code>public_html</code>) in that user's home directory on the server. >+ You can accomplish the same thing in Catalina by using a special >+ <strong>Listener</strong> element like this (on a Unix system that >+ uses the <code>/etc/passwd</code> file to identify valid users):</p> >+ >+<source> >+<Host name="localhost" ...> >+ ... >+ <Listener className="org.apache.catalina.startup.UserConfig" >+ directoryName="public_html" >+ userClass="org.apache.catalina.startup.PasswdUserDatabase"/> >+ ... >+</Host> >+</source> >+ >+ <p>On a server where <code>/etc/passwd</code> is not in use, you can >+ request Catalina to consider all directories found in a specified base >+ directory (such as <code>c:\Homes</code> in this example) to be >+ considered "user home" directories for the purposes of this directive:</p> >+ >+<source> >+<Host name="localhost" ...> >+ ... >+ <Listener className="org.apache.catalina.startup.UserConfig" >+ directoryName="public_html" >+ homeBase=c:\Homes" >+ userClass="org.apache.catalina.startup.HomesUserDatabase"/> >+ ... >+</Host> >+</source> >+ >+ <p>If a user home directory has been set up for a user named >+ <code>craigmcc</code>, then its contents will be visible from a >+ client browser by making a request to a URL like:</p> >+ >+<source> >+http://www.mycompany.com:8080/~craigmcc >+</source> >+ >+ <p>Successful use of this feature requires recognition of the following >+ considerations:</p> >+ <ul> >+ <li>Each user web application will be deployed with characteristics >+ established by the global and host level default context settings.</li> >+ <li>It is legal to include more than one instance of this Listener >+ element. This would only be useful, however, in circumstances >+ where you wanted to configure more than one "homeBase" directory.</li> >+ <li>The operating system username under which Catalina is executed >+ MUST have read access to each user's web application directory, >+ and all of its contents.</li> >+ </ul> >+ >+ </subsection> >+ >+ >+</section> >+ >+ >+</body> >+ >+ >+</document>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 46264
:
22912
|
27755
|
27758
|
27759
|
27760
|
27761
|
27767
|
27769
|
27772
|
27846