Author: markt
Date: Thu Jan 10 11:39:46 2013
New Revision: 1431293
URL: http://svn.apache.org/viewvc?rev=1431293&view=rev
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=54379
Implement support for post-construct and pre-destroy elements in web.xml
Patch by Violeta Georgieva.
Added:
tomcat/trunk/test/org/apache/catalina/startup/TesterServletWithLifeCycleMethods.java
(with props)
tomcat/trunk/test/org/apache/catalina/startup/web-1lifecyclecallback.xml
(with props)
tomcat/trunk/test/org/apache/catalina/startup/web-2lifecyclecallback.xml
(with props)
Modified:
tomcat/trunk/java/org/apache/catalina/Context.java
tomcat/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java
tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties
tomcat/trunk/java/org/apache/catalina/core/StandardContext.java
tomcat/trunk/java/org/apache/catalina/deploy/WebXml.java
tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java
tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties
tomcat/trunk/java/org/apache/catalina/startup/WebRuleSet.java
tomcat/trunk/java/org/apache/catalina/util/Introspection.java
tomcat/trunk/test/org/apache/catalina/core/TestStandardContext.java
tomcat/trunk/test/org/apache/catalina/core/TesterContext.java
tomcat/trunk/test/org/apache/catalina/deploy/TestWebXml.java
tomcat/trunk/test/org/apache/catalina/startup/TestContextConfig.java
tomcat/trunk/test/org/apache/catalina/startup/TestWebRuleSet.java
tomcat/trunk/test/webapp-3.0-fragments/WEB-INF/web.xml
Modified: tomcat/trunk/java/org/apache/catalina/Context.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Context.java?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/Context.java (original)
+++ tomcat/trunk/java/org/apache/catalina/Context.java Thu Jan 10 11:39:46 2013
@@ -18,6 +18,7 @@ package org.apache.catalina;
import java.net.URL;
import java.util.Locale;
+import java.util.Map;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
@@ -1420,5 +1421,101 @@ public interface Context extends Contain
* JAR.
*/
public boolean getAddWebinfClassesResources();
-}
+ /**
+ * Add a post construct method definition for the given class, if there is
+ * an existing definition for the specified class -
IllegalArgumentException
+ * will be thrown.
+ *
+ * @param clazz Fully qualified class name
+ * @param method
+ * Post construct method name
+ * @throws IllegalArgumentException
+ * if the fully qualified class name or method name are
+ * <code>NULL</code>; if there is already post construct method
+ * definition for the given class
+ */
+ public void addPostConstructMethod(String clazz, String method);
+
+ /**
+ * Add a pre destroy method definition for the given class, if there is an
+ * existing definition for the specified class - IllegalArgumentException
+ * will be thrown.
+ *
+ * @param clazz Fully qualified class name
+ * @param method
+ * Post construct method name
+ * @throws IllegalArgumentException
+ * if the fully qualified class name or method name are
+ * <code>NULL</code>; if there is already pre destroy method
+ * definition for the given class
+ */
+ public void addPreDestroyMethod(String clazz, String method);
+
+ /**
+ * Removes the post construct method definition for the given class, if it
+ * exists; otherwise, no action is taken.
+ *
+ * @param clazz
+ * Fully qualified class name
+ */
+ public void removePostConstructMethod(String clazz);
+
+ /**
+ * Removes the pre destroy method definition for the given class, if it
+ * exists; otherwise, no action is taken.
+ *
+ * @param clazz
+ * Fully qualified class name
+ */
+ public void removePreDestroyMethod(String clazz);
+
+ /**
+ * Returns the method name that is specified as post construct method for
+ * the given class, if it exists; otherwise <code>NULL</code> will be
+ * returned.
+ *
+ * @param clazz
+ * Fully qualified class name
+ *
+ * @return the method name that is specified as post construct method for
+ * the given class, if it exists; otherwise <code>NULL</code> will
+ * be returned.
+ */
+ public String findPostConstructMethod(String clazz);
+
+ /**
+ * Returns the method name that is specified as pre destroy method for the
+ * given class, if it exists; otherwise <code>NULL</code> will be returned.
+ *
+ * @param clazz
+ * Fully qualified class name
+ *
+ * @return the method name that is specified as pre destroy method for the
+ * given class, if it exists; otherwise <code>NULL</code> will be
+ * returned.
+ */
+ public String findPreDestroyMethod(String clazz);
+
+ /**
+ * Returns a map with keys - fully qualified class names of the classes
that
+ * have post construct methods and the values are the corresponding method
+ * names. If there are no such classes an empty map will be returned.
+ *
+ * @return a map with keys - fully qualified class names of the classes
that
+ * have post construct methods and the values are the corresponding
+ * method names.
+ */
+ public Map<String, String> findPostConstructMethods();
+
+ /**
+ * Returns a map with keys - fully qualified class names of the classes
that
+ * have pre destroy methods and the values are the corresponding method
+ * names. If there are no such classes an empty map will be returned.
+ *
+ * @return a map with keys - fully qualified class names of the classes
that
+ * have pre destroy methods and the values are the corresponding
+ * method names.
+ */
+ public Map<String, String> findPreDestroyMethods();
+}
Modified: tomcat/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java
(original)
+++ tomcat/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java Thu
Jan 10 11:39:46 2013
@@ -18,10 +18,10 @@ package org.apache.catalina.core;
import java.io.IOException;
import java.io.InputStream;
+import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
@@ -79,6 +79,8 @@ public class DefaultInstanceManager impl
private final Properties restrictedServlets = new Properties();
private final Map<Class<?>, AnnotationCacheEntry[]> annotationCache =
new WeakHashMap<>();
+ private final Map<String, String> postConstructMethods;
+ private final Map<String, String> preDestroyMethods;
public DefaultInstanceManager(Context context, Map<String, Map<String,
String>> injectionMap, org.apache.catalina.Context catalinaContext, ClassLoader
containerClassLoader) {
classLoader = catalinaContext.getLoader().getClassLoader();
@@ -125,6 +127,8 @@ public class DefaultInstanceManager impl
}
this.context = context;
this.injectionMap = injectionMap;
+ this.postConstructMethods = catalinaContext.findPostConstructMethods();
+ this.preDestroyMethods = catalinaContext.findPreDestroyMethods();
}
@Override
@@ -331,7 +335,9 @@ public class DefaultInstanceManager impl
// Initialize methods annotations
Method[] methods = Introspection.getDeclaredMethods(clazz);
Method postConstruct = null;
+ String postConstructFromXml =
postConstructMethods.get(clazz.getName());
Method preDestroy = null;
+ String preDestroyFromXml =
preDestroyMethods.get(clazz.getName());
for (Method method : methods) {
if (context != null) {
// Resource injection only if JNDI is enabled
@@ -388,41 +394,30 @@ public class DefaultInstanceManager impl
}
}
- if (method.isAnnotationPresent(PostConstruct.class)) {
- if ((postConstruct != null) ||
- (method.getParameterTypes().length != 0) ||
- (Modifier.isStatic(method.getModifiers())) ||
- (method.getExceptionTypes().length > 0) ||
-
(!method.getReturnType().getName().equals("void"))) {
- throw new IllegalArgumentException(
- "Invalid PostConstruct annotation");
- }
- postConstruct = method;
- }
+ postConstruct = findPostConstruct(postConstruct,
postConstructFromXml, method);
- if (method.isAnnotationPresent(PreDestroy.class)) {
- if ((preDestroy != null ||
- method.getParameterTypes().length != 0) ||
- (Modifier.isStatic(method.getModifiers())) ||
- (method.getExceptionTypes().length > 0) ||
-
(!method.getReturnType().getName().equals("void"))) {
- throw new IllegalArgumentException(
- "Invalid PreDestroy annotation");
- }
- preDestroy = method;
- }
+ preDestroy = findPreDestroy(preDestroy, preDestroyFromXml,
method);
}
+
if (postConstruct != null) {
annotations.add(new AnnotationCacheEntry(
postConstruct.getName(),
postConstruct.getParameterTypes(), null,
AnnotationCacheEntryType.POST_CONSTRUCT));
+ } else if (postConstructFromXml != null) {
+ throw new IllegalArgumentException("Post construct method "
+ + postConstructFromXml + " for class " +
clazz.getName()
+ + " is declared in deployment descriptor but cannot be
found.");
}
if (preDestroy != null) {
annotations.add(new AnnotationCacheEntry(
preDestroy.getName(),
preDestroy.getParameterTypes(), null,
AnnotationCacheEntryType.PRE_DESTROY));
+ } else if (preDestroyFromXml != null) {
+ throw new IllegalArgumentException("Pre destroy method "
+ + preDestroyFromXml + " for class " + clazz.getName()
+ + " is declared in deployment descriptor but cannot be
found.");
}
if (annotations.isEmpty()) {
// Use common object to save memory
@@ -703,6 +698,44 @@ public class DefaultInstanceManager impl
return result;
}
+
+ private static Method findPostConstruct(Method currentPostConstruct,
+ String postConstructFromXml, Method method) {
+ return findLifecycleCallback(currentPostConstruct,
+ postConstructFromXml, method, PostConstruct.class);
+ }
+
+ private static Method findPreDestroy(Method currentPreDestroy,
+ String preDestroyFromXml, Method method) {
+ return findLifecycleCallback(currentPreDestroy,
+ preDestroyFromXml, method, PreDestroy.class);
+ }
+
+ private static Method findLifecycleCallback(Method currentMethod,
+ String methodNameFromXml, Method method,
+ Class<? extends Annotation> annotation) {
+ Method result = currentMethod;
+ if (methodNameFromXml != null) {
+ if (method.getName().equals(methodNameFromXml)) {
+ if (!Introspection.isValidLifecycleCallback(method)) {
+ throw new IllegalArgumentException(
+ "Invalid " + annotation.getName() + " annotation");
+ }
+ result = method;
+ }
+ } else {
+ if (method.isAnnotationPresent(annotation)) {
+ if (currentMethod != null ||
+ !Introspection.isValidLifecycleCallback(method)) {
+ throw new IllegalArgumentException(
+ "Invalid " + annotation.getName() + " annotation");
+ }
+ result = method;
+ }
+ }
+ return result;
+ }
+
private static final class AnnotationCacheEntry {
private final String accessibleObjectName;
private final Class<?>[] paramTypes;
Modified: tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties
(original)
+++ tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties Thu Jan
10 11:39:46 2013
@@ -119,6 +119,10 @@ standardContext.notWrapper=Child of a Co
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.postconstruct.duplicate=Duplicate post construct method
definition for class {0}
+standardContext.postconstruct.required=Both fully qualified class name and
method name are required
+standardContext.predestroy.duplicate=Duplicate pre destroy method definition
for class {0}
+standardContext.predestroy.required=Both fully qualified class name and method
name are required
standardContext.reloadingCompleted=Reloading Context with name [{0}] is
completed
standardContext.reloadingStarted=Reloading Context with name [{0}] has started
standardContext.resourcesStart=Error starting static Resources
Modified: tomcat/trunk/java/org/apache/catalina/core/StandardContext.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardContext.java?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/StandardContext.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/StandardContext.java Thu Jan 10
11:39:46 2013
@@ -823,6 +823,10 @@ public class StandardContext extends Con
private boolean jndiExceptionOnFailedWrite = true;
+ private Map<String, String> postConstructMethods = new HashMap<>();
+ private Map<String, String> preDestroyMethods = new HashMap<>();
+
+
// ----------------------------------------------------- Context Properties
@Override
@@ -5844,6 +5848,72 @@ public class StandardContext extends Con
}
+ @Override
+ public void addPostConstructMethod(String clazz, String method) {
+ if (clazz == null || method == null)
+ throw new IllegalArgumentException(
+ sm.getString("standardContext.postconstruct.required"));
+ if (postConstructMethods.get(clazz) != null)
+ throw new IllegalArgumentException(sm.getString(
+ "standardContext.postconstruct.duplicate", clazz));
+
+ postConstructMethods.put(clazz, method);
+ fireContainerEvent("addPostConstructMethod", clazz);
+ }
+
+
+ @Override
+ public void removePostConstructMethod(String clazz) {
+ postConstructMethods.remove(clazz);
+ fireContainerEvent("removePostConstructMethod", clazz);
+ }
+
+
+ @Override
+ public void addPreDestroyMethod(String clazz, String method) {
+ if (clazz == null || method == null)
+ throw new IllegalArgumentException(
+ sm.getString("standardContext.predestroy.required"));
+ if (preDestroyMethods.get(clazz) != null)
+ throw new IllegalArgumentException(sm.getString(
+ "standardContext.predestroy.duplicate", clazz));
+
+ preDestroyMethods.put(clazz, method);
+ fireContainerEvent("addPreDestroyMethod", clazz);
+ }
+
+
+ @Override
+ public void removePreDestroyMethod(String clazz) {
+ preDestroyMethods.remove(clazz);
+ fireContainerEvent("removePreDestroyMethod", clazz);
+ }
+
+
+ @Override
+ public String findPostConstructMethod(String clazz) {
+ return postConstructMethods.get(clazz);
+ }
+
+
+ @Override
+ public String findPreDestroyMethod(String clazz) {
+ return preDestroyMethods.get(clazz);
+ }
+
+
+ @Override
+ public Map<String, String> findPostConstructMethods() {
+ return postConstructMethods;
+ }
+
+
+ @Override
+ public Map<String, String> findPreDestroyMethods() {
+ return preDestroyMethods;
+ }
+
+
/**
* Set the appropriate context attribute for our work directory.
*/
Modified: tomcat/trunk/java/org/apache/catalina/deploy/WebXml.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/deploy/WebXml.java?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/deploy/WebXml.java (original)
+++ tomcat/trunk/java/org/apache/catalina/deploy/WebXml.java Thu Jan 10
11:39:46 2013
@@ -559,6 +559,27 @@ public class WebXml {
return localeEncodingMappings;
}
+ // post-construct elements
+ private Map<String, String> postConstructMethods = new HashMap<>();
+ public void addPostConstructMethods(String clazz, String method) {
+ if (!postConstructMethods.containsKey(clazz)) {
+ postConstructMethods.put(clazz, method);
+ }
+ }
+ public Map<String, String> getPostConstructMethods() {
+ return postConstructMethods;
+ }
+
+ // pre-destroy elements
+ private Map<String, String> preDestroyMethods = new HashMap<>();
+ public void addPreDestroyMethods(String clazz, String method) {
+ if (!preDestroyMethods.containsKey(clazz)) {
+ preDestroyMethods.put(clazz, method);
+ }
+ }
+ public Map<String, String> getPreDestroyMethods() {
+ return preDestroyMethods;
+ }
// Attributes not defined in web.xml or web-fragment.xml
@@ -1066,6 +1087,32 @@ public class WebXml {
}
sb.append('\n');
+ if (!postConstructMethods.isEmpty()) {
+ for (Entry<String, String> entry : postConstructMethods
+ .entrySet()) {
+ sb.append(" <post-construct>\n");
+ appendElement(sb, INDENT4, "lifecycle-callback-class",
+ entry.getKey());
+ appendElement(sb, INDENT4, "lifecycle-callback-method",
+ entry.getValue());
+ sb.append(" </post-construct>\n");
+ }
+ sb.append('\n');
+ }
+
+ if (!preDestroyMethods.isEmpty()) {
+ for (Entry<String, String> entry : preDestroyMethods
+ .entrySet()) {
+ sb.append(" <pre-destroy>\n");
+ appendElement(sb, INDENT4, "lifecycle-callback-class",
+ entry.getKey());
+ appendElement(sb, INDENT4, "lifecycle-callback-method",
+ entry.getValue());
+ sb.append(" </pre-destroy>\n");
+ }
+ sb.append('\n');
+ }
+
for (MessageDestinationRef mdr : messageDestinationRefs.values()) {
sb.append(" <message-destination-ref>\n");
appendElement(sb, INDENT4, "description", mdr.getDescription());
@@ -1365,6 +1412,14 @@ public class WebXml {
}
}
}
+
+ for (Entry<String, String> entry : postConstructMethods.entrySet()) {
+ context.addPostConstructMethod(entry.getKey(), entry.getValue());
+ }
+
+ for (Entry<String, String> entry : preDestroyMethods.entrySet()) {
+ context.addPreDestroyMethod(entry.getKey(), entry.getValue());
+ }
}
/**
@@ -1860,6 +1915,28 @@ public class WebXml {
}
}
+ if (postConstructMethods.isEmpty()) {
+ for (WebXml fragment : fragments) {
+ if (!mergeLifecycleCallback(fragment.getPostConstructMethods(),
+ temp.getPostConstructMethods(), fragment,
+ "Post Construct Methods")) {
+ return false;
+ }
+ }
+ postConstructMethods.putAll(temp.getPostConstructMethods());
+ }
+
+ if (preDestroyMethods.isEmpty()) {
+ for (WebXml fragment : fragments) {
+ if (!mergeLifecycleCallback(fragment.getPreDestroyMethods(),
+ temp.getPreDestroyMethods(), fragment,
+ "Pre Destroy Methods")) {
+ return false;
+ }
+ }
+ preDestroyMethods.putAll(temp.getPreDestroyMethods());
+ }
+
return true;
}
@@ -2084,6 +2161,26 @@ public class WebXml {
}
+ private static <T> boolean mergeLifecycleCallback(
+ Map<String, String> fragmentMap, Map<String, String> tempMap,
+ WebXml fragment, String mapName) {
+ for (Entry<String, String> entry : fragmentMap.entrySet()) {
+ final String key = entry.getKey();
+ final String value = entry.getValue();
+ if (tempMap.containsKey(key)) {
+ if (value != null && !value.equals(tempMap.get(key))) {
+ log.error(sm.getString("webXml.mergeConflictString",
+ mapName, key, fragment.getName(),
fragment.getURL()));
+ return false;
+ }
+ } else {
+ tempMap.put(key, value);
+ }
+ }
+ return true;
+ }
+
+
/**
* Generates the sub-set of the web-fragment.xml files to be processed in
* the order that the fragments must be processed as per the rules in the
Modified: tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/FailedContext.java Thu Jan 10
11:39:46 2013
@@ -20,6 +20,7 @@ import java.beans.PropertyChangeListener
import java.io.File;
import java.net.URL;
import java.util.Locale;
+import java.util.Map;
import java.util.Set;
import javax.servlet.ServletContainerInitializer;
@@ -681,4 +682,28 @@ public class FailedContext extends Lifec
}
@Override
public boolean getAddWebinfClassesResources() { return false; }
+
+ @Override
+ public void addPostConstructMethod(String clazz, String method) { /* NO-OP
*/ }
+
+ @Override
+ public void addPreDestroyMethod(String clazz, String method) { /* NO-OP */
}
+
+ @Override
+ public void removePostConstructMethod(String clazz) { /* NO-OP */ }
+
+ @Override
+ public void removePreDestroyMethod(String clazz) { /* NO-OP */ }
+
+ @Override
+ public String findPostConstructMethod(String clazz) { return null; }
+
+ @Override
+ public String findPreDestroyMethod(String clazz) { return null; }
+
+ @Override
+ public Map<String, String> findPostConstructMethods() { return null; }
+
+ @Override
+ public Map<String, String> findPreDestroyMethods() { return null; }
}
\ No newline at end of file
Modified: tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties
(original)
+++ tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties Thu
Jan 10 11:39:46 2013
@@ -130,6 +130,8 @@ webAnnotationSet.invalidInjection=Invali
webRuleSet.absoluteOrdering=<absolute-ordering> element not valid in
web-fragment.xml and will be ignored
webRuleSet.absoluteOrderingCount=<absolute-ordering> element is limited to 1
occurrence
webRuleSet.nameCount=<name> element is limited to 1 occurrence
+webRuleSet.postconstruct.duplicate=Duplicate post construct method definition
for class {0}
+webRuleSet.predestroy.duplicate=Duplicate pre destroy method definition for
class {0}
webRuleSet.relativeOrdering=<ordering> element not valid in web.xml and will
be ignored
webRuleSet.relativeOrderingCount=<ordering> element is limited to 1 occurrence
xmlErrorHandler.error=Non-fatal error [{0}] reported processing [{1}].
Modified: tomcat/trunk/java/org/apache/catalina/startup/WebRuleSet.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/WebRuleSet.java?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/WebRuleSet.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/WebRuleSet.java Thu Jan 10
11:39:46 2013
@@ -473,6 +473,15 @@ public class WebRuleSet extends RuleSetB
digester.addCallParam(fullPrefix +
"/locale-encoding-mapping-list/locale-encoding-mapping/locale", 0);
digester.addCallParam(fullPrefix +
"/locale-encoding-mapping-list/locale-encoding-mapping/encoding", 1);
+ digester.addRule(fullPrefix + "/post-construct",
+ new LifecycleCallbackRule("addPostConstructMethods", 2, true));
+ digester.addCallParam(fullPrefix +
"/post-construct/lifecycle-callback-class", 0);
+ digester.addCallParam(fullPrefix +
"/post-construct/lifecycle-callback-method", 1);
+
+ digester.addRule(fullPrefix + "/pre-destroy",
+ new LifecycleCallbackRule("addPreDestroyMethods", 2, false));
+ digester.addCallParam(fullPrefix +
"/pre-destroy/lifecycle-callback-class", 0);
+ digester.addCallParam(fullPrefix +
"/pre-destroy/lifecycle-callback-method", 1);
}
protected void configureNamingRules(Digester digester) {
@@ -1293,4 +1302,39 @@ final class MappedNameRule extends Rule
ResourceBase resourceBase = (ResourceBase) digester.peek();
resourceBase.setProperty("mappedName", text.trim());
}
-}
\ No newline at end of file
+}
+
+/**
+ * A rule that fails if more than one post construct or pre destroy methods
+ * are configured per class.
+ */
+final class LifecycleCallbackRule extends CallMethodRule {
+
+ private final boolean postConstruct;
+
+ public LifecycleCallbackRule(String methodName, int paramCount,
+ boolean postConstruct) {
+ super(methodName, paramCount);
+ this.postConstruct = postConstruct;
+ }
+
+ @Override
+ public void end(String namespace, String name) throws Exception {
+ Object[] params = (Object[]) digester.peekParams();
+ if (params != null && params.length == 2) {
+ WebXml webXml = (WebXml) digester.peek();
+ if (postConstruct) {
+ if (webXml.getPostConstructMethods().containsKey(params[0])) {
+ throw new IllegalArgumentException(WebRuleSet.sm.getString(
+ "webRuleSet.postconstruct.duplicate", params[0]));
+ }
+ } else {
+ if (webXml.getPreDestroyMethods().containsKey(params[0])) {
+ throw new IllegalArgumentException(WebRuleSet.sm.getString(
+ "webRuleSet.predestroy.duplicate", params[0]));
+ }
+ }
+ }
+ super.end(namespace, name);
+ }
+}
Modified: tomcat/trunk/java/org/apache/catalina/util/Introspection.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/util/Introspection.java?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/util/Introspection.java (original)
+++ tomcat/trunk/java/org/apache/catalina/util/Introspection.java Thu Jan 10
11:39:46 2013
@@ -19,6 +19,7 @@ package org.apache.catalina.util;
import java.beans.Introspector;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
@@ -68,6 +69,24 @@ public class Introspection {
return false;
}
+ /**
+ * Determines if a method is a valid lifecycle callback method.
+ *
+ * @param method
+ * The method to test
+ *
+ * @return <code>true</code> if the method is a valid lifecycle callback
+ * method, else <code>false</code>
+ */
+ public static boolean isValidLifecycleCallback(Method method) {
+ if (method.getParameterTypes().length != 0
+ || Modifier.isStatic(method.getModifiers())
+ || method.getExceptionTypes().length > 0
+ || !method.getReturnType().getName().equals("void")) {
+ return false;
+ }
+ return true;
+ }
/**
* Obtain the declared fields for a class taking account of any security
Modified: tomcat/trunk/test/org/apache/catalina/core/TestStandardContext.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/core/TestStandardContext.java?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/core/TestStandardContext.java
(original)
+++ tomcat/trunk/test/org/apache/catalina/core/TestStandardContext.java Thu Jan
10 11:39:46 2013
@@ -754,4 +754,38 @@ public class TestStandardContext extends
return false; // Don't care
}
}
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testAddPostConstructMethodNullClassName() {
+ new StandardContext().addPostConstructMethod(null, "");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testAddPostConstructMethodNullMethodName() {
+ new StandardContext().addPostConstructMethod("", null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testAddPostConstructMethodConflicts() {
+ StandardContext standardContext = new StandardContext();
+ standardContext.addPostConstructMethod("a", "a");
+ standardContext.addPostConstructMethod("a", "b");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testAddPreDestroyMethodNullClassName() {
+ new StandardContext().addPreDestroyMethod(null, "");
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testAddPreDestroyMethodNullMethodName() {
+ new StandardContext().addPreDestroyMethod("", null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testAddPreDestroyMethodConflicts() {
+ StandardContext standardContext = new StandardContext();
+ standardContext.addPreDestroyMethod("a", "a");
+ standardContext.addPreDestroyMethod("a", "b");
+ }
}
Modified: tomcat/trunk/test/org/apache/catalina/core/TesterContext.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/core/TesterContext.java?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/core/TesterContext.java (original)
+++ tomcat/trunk/test/org/apache/catalina/core/TesterContext.java Thu Jan 10
11:39:46 2013
@@ -20,6 +20,7 @@ import java.beans.PropertyChangeListener
import java.io.File;
import java.net.URL;
import java.util.Locale;
+import java.util.Map;
import java.util.Set;
import javax.management.ObjectName;
@@ -1112,4 +1113,44 @@ public class TesterContext implements Co
public boolean getAddWebinfClassesResources() {
return false;
}
+
+ @Override
+ public void addPostConstructMethod(String clazz, String method) {
+ // NO-OP
+ }
+
+ @Override
+ public void addPreDestroyMethod(String clazz, String method) {
+ // NO-OP
+ }
+
+ @Override
+ public void removePostConstructMethod(String clazz) {
+ // NO-OP
+ }
+
+ @Override
+ public void removePreDestroyMethod(String clazz) {
+ // NO-OP
+ }
+
+ @Override
+ public String findPostConstructMethod(String clazz) {
+ return null;
+ }
+
+ @Override
+ public String findPreDestroyMethod(String clazz) {
+ return null;
+ }
+
+ @Override
+ public Map<String,String> findPostConstructMethods() {
+ return null;
+ }
+
+ @Override
+ public Map<String,String> findPreDestroyMethods() {
+ return null;
+ }
}
Modified: tomcat/trunk/test/org/apache/catalina/deploy/TestWebXml.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/deploy/TestWebXml.java?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/deploy/TestWebXml.java (original)
+++ tomcat/trunk/test/org/apache/catalina/deploy/TestWebXml.java Thu Jan 10
11:39:46 2013
@@ -17,8 +17,11 @@
package org.apache.catalina.deploy;
-import static org.junit.Assert.assertEquals;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.junit.Assert;
import org.junit.Test;
/**
@@ -32,46 +35,46 @@ public class TestWebXml {
WebXml webxml = new WebXml();
// Defaults
- assertEquals(3, webxml.getMajorVersion());
- assertEquals(0, webxml.getMinorVersion());
+ Assert.assertEquals(3, webxml.getMajorVersion());
+ Assert.assertEquals(0, webxml.getMinorVersion());
// Both get changed
webxml.setVersion("2.5");
- assertEquals(2, webxml.getMajorVersion());
- assertEquals(5, webxml.getMinorVersion());
+ Assert.assertEquals(2, webxml.getMajorVersion());
+ Assert.assertEquals(5, webxml.getMinorVersion());
// Reset
webxml.setVersion("0.0");
- assertEquals(0, webxml.getMajorVersion());
- assertEquals(0, webxml.getMinorVersion());
+ Assert.assertEquals(0, webxml.getMajorVersion());
+ Assert.assertEquals(0, webxml.getMinorVersion());
// null input should be ignored
webxml.setVersion(null);
- assertEquals(0, webxml.getMajorVersion());
- assertEquals(0, webxml.getMinorVersion());
+ Assert.assertEquals(0, webxml.getMajorVersion());
+ Assert.assertEquals(0, webxml.getMinorVersion());
// major only
webxml.setVersion("3");
- assertEquals(3, webxml.getMajorVersion());
- assertEquals(0, webxml.getMinorVersion());
+ Assert.assertEquals(3, webxml.getMajorVersion());
+ Assert.assertEquals(0, webxml.getMinorVersion());
// no minor digit
webxml.setVersion("0.0"); // reset
webxml.setVersion("3.");
- assertEquals(3, webxml.getMajorVersion());
- assertEquals(0, webxml.getMinorVersion());
+ Assert.assertEquals(3, webxml.getMajorVersion());
+ Assert.assertEquals(0, webxml.getMinorVersion());
// minor only
webxml.setVersion("0.0"); // reset
webxml.setVersion(".5");
- assertEquals(0, webxml.getMajorVersion());
- assertEquals(5, webxml.getMinorVersion());
+ Assert.assertEquals(0, webxml.getMajorVersion());
+ Assert.assertEquals(5, webxml.getMinorVersion());
// leading & training zeros
webxml.setVersion("0.0"); // reset
webxml.setVersion("002.500");
- assertEquals(2, webxml.getMajorVersion());
- assertEquals(500, webxml.getMinorVersion());
+ Assert.assertEquals(2, webxml.getMajorVersion());
+ Assert.assertEquals(500, webxml.getMinorVersion());
}
@Test
@@ -81,9 +84,9 @@ public class TestWebXml {
webxml.setPublicId(
org.apache.catalina.startup.Constants.WebDtdPublicId_22);
- assertEquals(2, webxml.getMajorVersion());
- assertEquals(2, webxml.getMinorVersion());
- assertEquals("2.2", webxml.getVersion());
+ Assert.assertEquals(2, webxml.getMajorVersion());
+ Assert.assertEquals(2, webxml.getMinorVersion());
+ Assert.assertEquals("2.2", webxml.getVersion());
}
@Test
@@ -93,9 +96,9 @@ public class TestWebXml {
webxml.setPublicId(
org.apache.catalina.startup.Constants.WebDtdPublicId_23);
- assertEquals(2, webxml.getMajorVersion());
- assertEquals(3, webxml.getMinorVersion());
- assertEquals("2.3", webxml.getVersion());
+ Assert.assertEquals(2, webxml.getMajorVersion());
+ Assert.assertEquals(3, webxml.getMinorVersion());
+ Assert.assertEquals("2.3", webxml.getVersion());
}
@Test
@@ -105,9 +108,9 @@ public class TestWebXml {
webxml.setPublicId(
org.apache.catalina.startup.Constants.WebSchemaPublicId_24);
- assertEquals(2, webxml.getMajorVersion());
- assertEquals(4, webxml.getMinorVersion());
- assertEquals("2.4", webxml.getVersion());
+ Assert.assertEquals(2, webxml.getMajorVersion());
+ Assert.assertEquals(4, webxml.getMinorVersion());
+ Assert.assertEquals("2.4", webxml.getVersion());
}
@Test
@@ -117,9 +120,9 @@ public class TestWebXml {
webxml.setPublicId(
org.apache.catalina.startup.Constants.WebSchemaPublicId_25);
- assertEquals(2, webxml.getMajorVersion());
- assertEquals(5, webxml.getMinorVersion());
- assertEquals("2.5", webxml.getVersion());
+ Assert.assertEquals(2, webxml.getMajorVersion());
+ Assert.assertEquals(5, webxml.getMinorVersion());
+ Assert.assertEquals("2.5", webxml.getVersion());
}
@Test
@@ -129,8 +132,91 @@ public class TestWebXml {
webxml.setPublicId(
org.apache.catalina.startup.Constants.WebSchemaPublicId_30);
- assertEquals(3, webxml.getMajorVersion());
- assertEquals(0, webxml.getMinorVersion());
- assertEquals("3.0", webxml.getVersion());
+ Assert.assertEquals(3, webxml.getMajorVersion());
+ Assert.assertEquals(0, webxml.getMinorVersion());
+ Assert.assertEquals("3.0", webxml.getVersion());
+ }
+
+ @Test
+ public void testLifecycleMethodsWebXml() {
+ WebXml webxml = new WebXml();
+ webxml.addPostConstructMethods("a", "a");
+ webxml.addPreDestroyMethods("b", "b");
+
+ WebXml fragment = new WebXml();
+ fragment.addPostConstructMethods("c", "c");
+ fragment.addPreDestroyMethods("d", "d");
+
+ Set<WebXml> fragments = new HashSet<>();
+ fragments.add(fragment);
+
+ webxml.merge(fragments);
+
+ Map<String, String> postConstructMethods =
webxml.getPostConstructMethods();
+ Map<String, String> preDestroyMethods = webxml.getPreDestroyMethods();
+ Assert.assertEquals(1, postConstructMethods.size());
+ Assert.assertEquals(1, preDestroyMethods.size());
+
+ Assert.assertEquals("a", postConstructMethods.get("a"));
+ Assert.assertEquals("b", preDestroyMethods.get("b"));
+ }
+
+ @Test
+ public void testLifecycleMethodsWebFragments() {
+ WebXml webxml = new WebXml();
+
+ WebXml fragment1 = new WebXml();
+ fragment1.addPostConstructMethods("a", "a");
+ fragment1.addPreDestroyMethods("b", "b");
+
+ WebXml fragment2 = new WebXml();
+ fragment2.addPostConstructMethods("c", "c");
+ fragment2.addPreDestroyMethods("d", "d");
+
+ Set<WebXml> fragments = new HashSet<>();
+ fragments.add(fragment1);
+ fragments.add(fragment2);
+
+ webxml.merge(fragments);
+
+ Map<String, String> postConstructMethods =
webxml.getPostConstructMethods();
+ Map<String, String> preDestroyMethods = webxml.getPreDestroyMethods();
+ Assert.assertEquals(2, postConstructMethods.size());
+ Assert.assertEquals(2, preDestroyMethods.size());
+
+ Assert.assertEquals("a", postConstructMethods.get("a"));
+ Assert.assertEquals("c", postConstructMethods.get("c"));
+ Assert.assertEquals("b", preDestroyMethods.get("b"));
+ Assert.assertEquals("d", preDestroyMethods.get("d"));
+ }
+
+ @Test
+ public void testLifecycleMethodsWebFragmentsWithConflicts() {
+ WebXml webxml = new WebXml();
+
+ WebXml fragment1 = new WebXml();
+ fragment1.addPostConstructMethods("a", "a");
+ fragment1.addPreDestroyMethods("b", "a");
+
+ WebXml fragment2 = new WebXml();
+ fragment2.addPostConstructMethods("a", "b");
+
+ Set<WebXml> fragments = new HashSet<>();
+ fragments.add(fragment1);
+ fragments.add(fragment2);
+
+ Assert.assertFalse(webxml.merge(fragments));
+
+ Assert.assertEquals(0, webxml.getPostConstructMethods().size());
+
+ WebXml fragment3 = new WebXml();
+ fragment3.addPreDestroyMethods("b", "b");
+
+ fragments.remove(fragment2);
+ fragments.add(fragment3);
+
+ Assert.assertFalse(webxml.merge(fragments));
+
+ Assert.assertEquals(0, webxml.getPreDestroyMethods().size());
}
}
Modified: tomcat/trunk/test/org/apache/catalina/startup/TestContextConfig.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/startup/TestContextConfig.java?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/startup/TestContextConfig.java
(original)
+++ tomcat/trunk/test/org/apache/catalina/startup/TestContextConfig.java Thu
Jan 10 11:39:46 2013
@@ -32,6 +32,7 @@ import javax.servlet.http.HttpServletRes
import org.junit.Assert;
import org.junit.Test;
+import org.apache.catalina.Context;
import org.apache.catalina.core.StandardContext;
import org.apache.tomcat.util.buf.ByteChunk;
@@ -106,6 +107,25 @@ public class TestContextConfig extends T
null, HttpServletResponse.SC_NOT_FOUND);
}
+ @Test
+ public void testBug54379() throws Exception {
+ Tomcat tomcat = getTomcatInstance();
+
+ File appDir = new File("test/webapp-3.0-fragments");
+ Context context =
+ tomcat.addWebapp(null, "/test", appDir.getAbsolutePath());
+
+ Tomcat.addServlet(context, "TestServlet",
+
"org.apache.catalina.startup.TesterServletWithLifeCycleMethods");
+ context.addServletMapping("/testServlet", "TestServlet");
+
+ tomcat.enableNaming();
+
+ tomcat.start();
+
+ assertPageContains("/test/testServlet", "postConstruct1()");
+ }
+
private static class CustomDefaultServletSCI
implements ServletContainerInitializer {
Modified: tomcat/trunk/test/org/apache/catalina/startup/TestWebRuleSet.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/startup/TestWebRuleSet.java?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/startup/TestWebRuleSet.java (original)
+++ tomcat/trunk/test/org/apache/catalina/startup/TestWebRuleSet.java Thu Jan
10 11:39:46 2013
@@ -115,6 +115,13 @@ public class TestWebRuleSet {
parse(new WebXml(), "web-1ordering.xml", false, true);
}
+ @Test
+ public void testLifecycleMethodsDefinitions() throws Exception {
+ // post-construct and pre-destroy
+ parse(new WebXml(), "web-1lifecyclecallback.xml", false, true);
+ // conflicting post-construct definitions
+ parse(new WebXml(), "web-2lifecyclecallback.xml", false, false);
+ }
private synchronized void parse(WebXml webXml, String target,
boolean fragment, boolean expected) throws FileNotFoundException {
Added:
tomcat/trunk/test/org/apache/catalina/startup/TesterServletWithLifeCycleMethods.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/startup/TesterServletWithLifeCycleMethods.java?rev=1431293&view=auto
==============================================================================
---
tomcat/trunk/test/org/apache/catalina/startup/TesterServletWithLifeCycleMethods.java
(added)
+++
tomcat/trunk/test/org/apache/catalina/startup/TesterServletWithLifeCycleMethods.java
Thu Jan 10 11:39:46 2013
@@ -0,0 +1,59 @@
+/*
+ * 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.IOException;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class TesterServletWithLifeCycleMethods extends HttpServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ private String result;
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+ throws ServletException, IOException {
+ resp.setContentType("text/plain");
+ resp.getWriter().print(result);
+ }
+
+ @PostConstruct
+ protected void postConstruct() {
+ result = "postConstruct()";
+ }
+
+ @PreDestroy
+ protected void preDestroy() {
+ result = "preDestroy()";
+ }
+
+ protected void postConstruct1() {
+ result = "postConstruct1()";
+ }
+
+ protected void preDestroy1() {
+ result = "preDestroy1()";
+ }
+}
Propchange:
tomcat/trunk/test/org/apache/catalina/startup/TesterServletWithLifeCycleMethods.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: tomcat/trunk/test/org/apache/catalina/startup/web-1lifecyclecallback.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/startup/web-1lifecyclecallback.xml?rev=1431293&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/startup/web-1lifecyclecallback.xml
(added)
+++ tomcat/trunk/test/org/apache/catalina/startup/web-1lifecyclecallback.xml
Thu Jan 10 11:39:46 2013
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ 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.
+-->
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
+ http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0"
+ metadata-complete="true">
+ <post-construct>
+ <lifecycle-callback-class>test.TestServlet</lifecycle-callback-class>
+ <lifecycle-callback-method>postConstruct</lifecycle-callback-method>
+ </post-construct>
+ <pre-destroy>
+ <lifecycle-callback-class>test.TestServlet</lifecycle-callback-class>
+ <lifecycle-callback-method>preDestroy</lifecycle-callback-method>
+ </pre-destroy>
+</web-app>
\ No newline at end of file
Propchange:
tomcat/trunk/test/org/apache/catalina/startup/web-1lifecyclecallback.xml
------------------------------------------------------------------------------
svn:eol-style = native
Added: tomcat/trunk/test/org/apache/catalina/startup/web-2lifecyclecallback.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/startup/web-2lifecyclecallback.xml?rev=1431293&view=auto
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/startup/web-2lifecyclecallback.xml
(added)
+++ tomcat/trunk/test/org/apache/catalina/startup/web-2lifecyclecallback.xml
Thu Jan 10 11:39:46 2013
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+ 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.
+-->
+<web-app xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
+ http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0"
+ metadata-complete="true">
+ <post-construct>
+ <lifecycle-callback-class>test.TestServlet</lifecycle-callback-class>
+ <lifecycle-callback-method>postConstruct1</lifecycle-callback-method>
+ </post-construct>
+ <post-construct>
+ <lifecycle-callback-class>test.TestServlet</lifecycle-callback-class>
+ <lifecycle-callback-method>postConstruct2</lifecycle-callback-method>
+ </post-construct>
+</web-app>
\ No newline at end of file
Propchange:
tomcat/trunk/test/org/apache/catalina/startup/web-2lifecyclecallback.xml
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/trunk/test/webapp-3.0-fragments/WEB-INF/web.xml
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/webapp-3.0-fragments/WEB-INF/web.xml?rev=1431293&r1=1431292&r2=1431293&view=diff
==============================================================================
--- tomcat/trunk/test/webapp-3.0-fragments/WEB-INF/web.xml (original)
+++ tomcat/trunk/test/webapp-3.0-fragments/WEB-INF/web.xml Thu Jan 10 11:39:46
2013
@@ -49,4 +49,12 @@
<jsp-file>/bug5nnnn/bug51396.jsp</jsp-file>
</servlet>
+ <post-construct>
+
<lifecycle-callback-class>org.apache.catalina.startup.TesterServletWithLifeCycleMethods</lifecycle-callback-class>
+ <lifecycle-callback-method>postConstruct1</lifecycle-callback-method>
+ </post-construct>
+ <pre-destroy>
+
<lifecycle-callback-class>org.apache.catalina.startup.TesterServletWithLifeCycleMethods</lifecycle-callback-class>
+ <lifecycle-callback-method>preDestroy1</lifecycle-callback-method>
+ </pre-destroy>
</web-app>
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]