Author: markt
Date: Thu Jan 10 11:47:49 2013
New Revision: 1431300
URL: http://svn.apache.org/viewvc?rev=1431300&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/tc7.0.x/trunk/test/org/apache/catalina/startup/TesterServletWithLifeCycleMethods.java
- copied unchanged from r1431293,
tomcat/trunk/test/org/apache/catalina/startup/TesterServletWithLifeCycleMethods.java
tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/web-1lifecyclecallback.xml
- copied unchanged from r1431293,
tomcat/trunk/test/org/apache/catalina/startup/web-1lifecyclecallback.xml
tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/web-2lifecyclecallback.xml
- copied unchanged from r1431293,
tomcat/trunk/test/org/apache/catalina/startup/web-2lifecyclecallback.xml
Modified:
tomcat/tc7.0.x/trunk/ (props changed)
tomcat/tc7.0.x/trunk/java/org/apache/catalina/Context.java
tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java
tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/LocalStrings.properties
tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContext.java
tomcat/tc7.0.x/trunk/java/org/apache/catalina/deploy/WebXml.java
tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/FailedContext.java
tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties
tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/WebRuleSet.java
tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Introspection.java
tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestStandardContext.java
tomcat/tc7.0.x/trunk/test/org/apache/catalina/deploy/TestWebXml.java
tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/TestContextConfig.java
tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/TestWebRuleSet.java
tomcat/tc7.0.x/trunk/test/webapp-3.0-fragments/WEB-INF/web.xml
tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
Merged /tomcat/trunk:r1431293
Modified: tomcat/tc7.0.x/trunk/java/org/apache/catalina/Context.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/Context.java?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/Context.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/Context.java Thu Jan 10
11:47:49 2013
@@ -21,6 +21,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;
@@ -1424,5 +1425,101 @@ public interface Context extends Contain
* part of a redirect response.
*/
public boolean getSendRedirectBody();
-}
+ /**
+ * 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/tc7.0.x/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java
(original)
+++
tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/DefaultInstanceManager.java
Thu Jan 10 11:47:49 2013
@@ -19,10 +19,10 @@ package org.apache.catalina.core;
import java.beans.Introspector;
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;
@@ -80,6 +80,8 @@ public class DefaultInstanceManager impl
private final Properties restrictedServlets = new Properties();
private final Map<Class<?>, AnnotationCacheEntry[]> annotationCache =
new WeakHashMap<Class<?>, AnnotationCacheEntry[]>();
+ 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();
@@ -126,6 +128,8 @@ public class DefaultInstanceManager impl
}
this.context = context;
this.injectionMap = injectionMap;
+ this.postConstructMethods = catalinaContext.findPostConstructMethods();
+ this.preDestroyMethods = catalinaContext.findPreDestroyMethods();
}
@Override
@@ -332,7 +336,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
@@ -389,41 +395,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
@@ -711,6 +706,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/tc7.0.x/trunk/java/org/apache/catalina/core/LocalStrings.properties
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/LocalStrings.properties?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/LocalStrings.properties
(original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/LocalStrings.properties
Thu Jan 10 11:47:49 2013
@@ -145,6 +145,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.reloadingFailed=Reloading this Context failed due to previous
errors
standardContext.reloadingStarted=Reloading Context with name [{0}] has started
Modified:
tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContext.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContext.java?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContext.java
(original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/core/StandardContext.java Thu
Jan 10 11:47:49 2013
@@ -864,6 +864,12 @@ public class StandardContext extends Con
private boolean jndiExceptionOnFailedWrite = true;
+ private Map<String, String> postConstructMethods =
+ new HashMap<String, String>();
+ private Map<String, String> preDestroyMethods =
+ new HashMap<String, String>();
+
+
// ----------------------------------------------------- Context Properties
@Override
@@ -5994,6 +6000,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/tc7.0.x/trunk/java/org/apache/catalina/deploy/WebXml.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/deploy/WebXml.java?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/deploy/WebXml.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/deploy/WebXml.java Thu Jan 10
11:47:49 2013
@@ -568,6 +568,29 @@ public class WebXml {
return localeEncodingMappings;
}
+ // post-construct elements
+ private Map<String, String> postConstructMethods =
+ new HashMap<String, String>();
+ 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<String, String>();
+ 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
@@ -1075,6 +1098,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());
@@ -1374,6 +1423,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());
+ }
}
/**
@@ -1870,6 +1927,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;
}
@@ -2094,6 +2173,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/tc7.0.x/trunk/java/org/apache/catalina/startup/FailedContext.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/FailedContext.java?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/FailedContext.java
(original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/FailedContext.java
Thu Jan 10 11:47:49 2013
@@ -20,6 +20,7 @@ import java.beans.PropertyChangeListener
import java.io.IOException;
import java.net.URL;
import java.util.Locale;
+import java.util.Map;
import java.util.Set;
import javax.naming.directory.DirContext;
@@ -656,4 +657,28 @@ public class FailedContext extends Lifec
@Override
public Object getMappingObject() { return null; }
+
+ @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/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties
(original)
+++
tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/LocalStrings.properties
Thu Jan 10 11:47:49 2013
@@ -136,6 +136,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/tc7.0.x/trunk/java/org/apache/catalina/startup/WebRuleSet.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/WebRuleSet.java?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/WebRuleSet.java
(original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/startup/WebRuleSet.java Thu
Jan 10 11:47:49 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/tc7.0.x/trunk/java/org/apache/catalina/util/Introspection.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Introspection.java?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Introspection.java
(original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/catalina/util/Introspection.java Thu
Jan 10 11:47:49 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/tc7.0.x/trunk/test/org/apache/catalina/core/TestStandardContext.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestStandardContext.java?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestStandardContext.java
(original)
+++ tomcat/tc7.0.x/trunk/test/org/apache/catalina/core/TestStandardContext.java
Thu Jan 10 11:47:49 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/tc7.0.x/trunk/test/org/apache/catalina/deploy/TestWebXml.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/deploy/TestWebXml.java?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/test/org/apache/catalina/deploy/TestWebXml.java
(original)
+++ tomcat/tc7.0.x/trunk/test/org/apache/catalina/deploy/TestWebXml.java Thu
Jan 10 11:47:49 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<WebXml>();
+ 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<WebXml>();
+ 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<WebXml>();
+ 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/tc7.0.x/trunk/test/org/apache/catalina/startup/TestContextConfig.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/TestContextConfig.java?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
---
tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/TestContextConfig.java
(original)
+++
tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/TestContextConfig.java
Thu Jan 10 11:47:49 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/tc7.0.x/trunk/test/org/apache/catalina/startup/TestWebRuleSet.java
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/TestWebRuleSet.java?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/TestWebRuleSet.java
(original)
+++ tomcat/tc7.0.x/trunk/test/org/apache/catalina/startup/TestWebRuleSet.java
Thu Jan 10 11:47:49 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 {
Modified: tomcat/tc7.0.x/trunk/test/webapp-3.0-fragments/WEB-INF/web.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/webapp-3.0-fragments/WEB-INF/web.xml?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/test/webapp-3.0-fragments/WEB-INF/web.xml (original)
+++ tomcat/tc7.0.x/trunk/test/webapp-3.0-fragments/WEB-INF/web.xml Thu Jan 10
11:47:49 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
Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1431300&r1=1431299&r2=1431300&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Thu Jan 10 11:47:49 2013
@@ -114,6 +114,10 @@
RemoteIpFilter. Patch by Violeta Georgieva. (markt)
</fix>
<fix>
+ <bug>54379</bug>: Implement support for post-construct and pre-destroy
+ elements in web.xml. Patch by Violeta Georgieva. (markt)
+ </fix>
+ <fix>
<bug>54380</bug>: Do not try to register servlets or contexts into the
mapper too early (which just caused a warning to be logged). (kkolinko)
</fix>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]