From 0a150b3e4e9876da9af836211b163b98780b4d98 Mon Sep 17 00:00:00 2001 From: remm Date: Mon, 28 May 2007 10:35:32 +0000 Subject: [PATCH] - Switch from AnnotationProcessor to InstanceManager. - Submitted by David Jecks, with some modifications: package names, addition of an extra method to allow injecting already instantiated objects, and a system property in Jasper (to specify to use the instance manager to create tag instances). git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@542189 13f79535-47bb-0310-9956-ffa450edef68 --- java/org/apache/AnnotationProcessor.java | 37 -- java/org/apache/InstanceManager.java | 45 +++ .../catalina/core/ApplicationFilterConfig.java | 124 ++---- .../catalina/core/DefaultInstanceManager.java | 437 +++++++++++++++++++++ .../apache/catalina/core/LocalStrings.properties | 9 +- java/org/apache/catalina/core/StandardContext.java | 112 ++++-- java/org/apache/catalina/core/StandardWrapper.java | 169 +------- .../apache/catalina/core/mbeans-descriptors.xml | 6 +- .../apache/catalina/deploy/ContextEnvironment.java | 16 +- java/org/apache/catalina/deploy/Injectable.java | 29 ++ .../apache/catalina/deploy/InjectionTarget.java | 55 +++ .../catalina/deploy/MessageDestinationRef.java | 14 +- java/org/apache/catalina/deploy/ResourceBase.java | 18 +- .../catalina/security/SecurityClassLoad.java | 3 + .../catalina/startup/ConnectorCreateRule.java | 17 +- java/org/apache/catalina/startup/WebRuleSet.java | 302 +++++++------- .../catalina/util/DefaultAnnotationProcessor.java | 244 ------------ java/org/apache/jasper/Constants.java | 3 + java/org/apache/jasper/JspCompilationContext.java | 17 +- java/org/apache/jasper/compiler/Generator.java | 101 ++--- .../apache/jasper/runtime/AnnotationHelper.java | 61 --- .../jasper/runtime/InstanceManagerFactory.java | 44 +++ java/org/apache/jasper/runtime/TagHandlerPool.java | 43 +- .../apache/jasper/servlet/JspServletWrapper.java | 31 +- 24 files changed, 1062 insertions(+), 875 deletions(-) delete mode 100644 java/org/apache/AnnotationProcessor.java create mode 100644 java/org/apache/InstanceManager.java create mode 100644 java/org/apache/catalina/core/DefaultInstanceManager.java create mode 100644 java/org/apache/catalina/deploy/Injectable.java create mode 100644 java/org/apache/catalina/deploy/InjectionTarget.java delete mode 100644 java/org/apache/catalina/util/DefaultAnnotationProcessor.java delete mode 100644 java/org/apache/jasper/runtime/AnnotationHelper.java create mode 100644 java/org/apache/jasper/runtime/InstanceManagerFactory.java diff --git a/java/org/apache/AnnotationProcessor.java b/java/org/apache/AnnotationProcessor.java deleted file mode 100644 index 97f9475c0..000000000 --- a/java/org/apache/AnnotationProcessor.java +++ /dev/null @@ -1,37 +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; - -import java.lang.reflect.InvocationTargetException; - -import javax.naming.NamingException; - -/** - * Comment - * - * @author Bill Burke - * @version $Revision$ - */ -public interface AnnotationProcessor { - public void postConstruct(Object instance) - throws IllegalAccessException, InvocationTargetException; - public void preDestroy(Object instance) - throws IllegalAccessException, InvocationTargetException; - public void processAnnotations(Object instance) - throws IllegalAccessException, InvocationTargetException, NamingException; -} diff --git a/java/org/apache/InstanceManager.java b/java/org/apache/InstanceManager.java new file mode 100644 index 000000000..01ec95ce4 --- /dev/null +++ b/java/org/apache/InstanceManager.java @@ -0,0 +1,45 @@ +/* + * 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; + +import java.lang.reflect.InvocationTargetException; + +import javax.naming.NamingException; + +/** + * @version $Rev:$ $Date:$ + */ +public interface InstanceManager { + + public Object newInstance(String className) + throws IllegalAccessException, InvocationTargetException, NamingException, + InstantiationException, ClassNotFoundException; + + public Object newInstance(String fqcn, ClassLoader classLoader) + throws IllegalAccessException, InvocationTargetException, NamingException, + InstantiationException, ClassNotFoundException; + + public void newInstance(Object o) + throws IllegalAccessException, InvocationTargetException, NamingException; + + public void destroyInstance(Object o) + throws IllegalAccessException, InvocationTargetException; +} diff --git a/java/org/apache/catalina/core/ApplicationFilterConfig.java b/java/org/apache/catalina/core/ApplicationFilterConfig.java index 87f75fe0c..7e3f500cb 100644 --- a/java/org/apache/catalina/core/ApplicationFilterConfig.java +++ b/java/org/apache/catalina/core/ApplicationFilterConfig.java @@ -19,14 +19,12 @@ package org.apache.catalina.core; -import java.io.IOException; -import java.io.InputStream; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashMap; import java.util.Map; -import java.util.Properties; import javax.naming.NamingException; import javax.servlet.Filter; @@ -34,7 +32,7 @@ import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; -import org.apache.AnnotationProcessor; +import org.apache.InstanceManager; import org.apache.catalina.Context; import org.apache.catalina.Globals; import org.apache.catalina.deploy.FilterDef; @@ -58,7 +56,7 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable { protected static StringManager sm = StringManager.getManager(Constants.Package); - + // ----------------------------------------------------------- Constructors @@ -78,8 +76,8 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable { * @exception InstantiationException if an exception occurs while * instantiating the filter object * @exception ServletException if thrown by the filter's init() method - * @throws NamingException - * @throws InvocationTargetException + * @throws NamingException + * @throws InvocationTargetException */ public ApplicationFilterConfig(Context context, FilterDef filterDef) throws ClassCastException, ClassNotFoundException, @@ -88,22 +86,6 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable { super(); - if (restrictedFilters == null) { - restrictedFilters = new Properties(); - try { - InputStream is = - this.getClass().getClassLoader().getResourceAsStream - ("org/apache/catalina/core/RestrictedFilters.properties"); - if (is != null) { - restrictedFilters.load(is); - } else { - context.getLogger().error(sm.getString("applicationFilterConfig.restrictedFiltersResources")); - } - } catch (IOException e) { - context.getLogger().error(sm.getString("applicationFilterConfig.restrictedServletsResources"), e); - } - } - this.context = context; setFilterDef(filterDef); @@ -130,13 +112,12 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable { */ private FilterDef filterDef = null; - /** - * Restricted filters (which can only be loaded by a privileged webapp). + * the InstanceManager used to create and destroy filter instances. */ - protected static Properties restrictedFilters = null; + private transient InstanceManager instanceManager; + - // --------------------------------------------------- FilterConfig Methods @@ -223,11 +204,11 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable { * @exception InstantiationException if an exception occurs while * instantiating the filter object * @exception ServletException if thrown by the filter's init() method - * @throws NamingException - * @throws InvocationTargetException + * @throws NamingException + * @throws InvocationTargetException */ Filter getFilter() throws ClassCastException, ClassNotFoundException, - IllegalAccessException, InstantiationException, ServletException, + IllegalAccessException, InstantiationException, ServletException, InvocationTargetException, NamingException { // Return the existing filter instance, if any @@ -236,32 +217,10 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable { // Identify the class loader we will be using String filterClass = filterDef.getFilterClass(); - ClassLoader classLoader = null; - if (filterClass.startsWith("org.apache.catalina.")) - classLoader = this.getClass().getClassLoader(); - else - classLoader = context.getLoader().getClassLoader(); - - ClassLoader oldCtxClassLoader = - Thread.currentThread().getContextClassLoader(); + this.filter = (Filter) getInstanceManager().newInstance(filterClass); - // Instantiate a new instance of this filter and return it - Class clazz = classLoader.loadClass(filterClass); - if (!isFilterAllowed(clazz)) { - throw new SecurityException - (sm.getString("applicationFilterConfig.privilegedFilter", - filterClass)); - } - this.filter = (Filter) clazz.newInstance(); - if (!context.getIgnoreAnnotations()) { - if (context instanceof StandardContext) { - AnnotationProcessor processor = ((StandardContext)context).getAnnotationProcessor(); - processor.processAnnotations(this.filter); - processor.postConstruct(this.filter); - } - } if (context instanceof StandardContext && - ((StandardContext) context).getSwallowOutput()) { + context.getSwallowOutput()) { try { SystemLogHandler.startCapture(); filter.init(this); @@ -289,30 +248,6 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable { } - - /** - * Return true if loading this filter is allowed. - */ - protected boolean isFilterAllowed(Class filterClass) { - - // Privileged webapps may load all servlets without restriction - if (context.getPrivileged()) { - return true; - } - - Class clazz = filterClass; - while (clazz != null && !clazz.getName().equals("javax.servlet.Filter")) { - if ("restricted".equals(restrictedFilters.getProperty(clazz.getName()))) { - return (false); - } - clazz = clazz.getSuperclass(); - } - - return (true); - - } - - /** * Release the Filter instance associated with this FilterConfig, * if there is one. @@ -323,17 +258,17 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable { { if (Globals.IS_SECURITY_ENABLED) { try { - SecurityUtil.doAsPrivilege("destroy", filter); - } catch(java.lang.Exception ex){ + SecurityUtil.doAsPrivilege("destroy", filter); + } catch(java.lang.Exception ex){ context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex); } SecurityUtil.remove(filter); - } else { + } else { filter.destroy(); } if (!context.getIgnoreAnnotations()) { try { - ((StandardContext)context).getAnnotationProcessor().preDestroy(this.filter); + ((StandardContext) context).getInstanceManager().destroyInstance(this.filter); } catch (Exception e) { context.getLogger().error("ApplicationFilterConfig.preDestroy", e); } @@ -358,8 +293,8 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable { * @exception InstantiationException if an exception occurs while * instantiating the filter object * @exception ServletException if thrown by the filter's init() method - * @throws NamingException - * @throws InvocationTargetException + * @throws NamingException + * @throws InvocationTargetException */ void setFilterDef(FilterDef filterDef) throws ClassCastException, ClassNotFoundException, @@ -373,17 +308,17 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable { if (this.filter != null){ if( Globals.IS_SECURITY_ENABLED) { try{ - SecurityUtil.doAsPrivilege("destroy", filter); - } catch(java.lang.Exception ex){ + SecurityUtil.doAsPrivilege("destroy", filter); + } catch(java.lang.Exception ex){ context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex); } SecurityUtil.remove(filter); - } else { + } else { filter.destroy(); } if (!context.getIgnoreAnnotations()) { try { - ((StandardContext)context).getAnnotationProcessor().preDestroy(this.filter); + ((StandardContext) context).getInstanceManager().destroyInstance(this.filter); } catch (Exception e) { context.getLogger().error("ApplicationFilterConfig.preDestroy", e); } @@ -403,5 +338,18 @@ final class ApplicationFilterConfig implements FilterConfig, Serializable { // -------------------------------------------------------- Private Methods + private InstanceManager getInstanceManager() { + if (instanceManager == null) { + if (context instanceof StandardContext) { + instanceManager = ((StandardContext)context).getInstanceManager(); + } else { + instanceManager = new DefaultInstanceManager(null, + new HashMap>(), + context, + getClass().getClassLoader()); + } + } + return instanceManager; + } } diff --git a/java/org/apache/catalina/core/DefaultInstanceManager.java b/java/org/apache/catalina/core/DefaultInstanceManager.java new file mode 100644 index 000000000..d019c3853 --- /dev/null +++ b/java/org/apache/catalina/core/DefaultInstanceManager.java @@ -0,0 +1,437 @@ +/* + * 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.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Map; +import java.util.Properties; +import java.security.AccessController; +import java.security.PrivilegedExceptionAction; +import java.security.PrivilegedActionException; +import java.io.InputStream; +import java.io.IOException; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.annotation.Resource; +import javax.ejb.EJB; +import javax.naming.Context; +import javax.naming.NamingException; +import javax.persistence.PersistenceContext; +import javax.persistence.PersistenceUnit; +import javax.xml.ws.WebServiceRef; +import javax.servlet.Filter; +import javax.servlet.Servlet; + +import org.apache.InstanceManager; +import org.apache.catalina.security.SecurityUtil; +import org.apache.catalina.ContainerServlet; +import org.apache.catalina.core.Constants; +import org.apache.catalina.util.StringManager; + +/** + * @version $Rev:$ $Date:$ + */ +public class DefaultInstanceManager implements InstanceManager { + + private final Context context; + private final Map> injectionMap; + protected final ClassLoader classLoader; + protected final ClassLoader containerClassLoader; + protected boolean privileged; + protected boolean ignoreAnnotations; + private Properties restrictedFilters = new Properties(); + private Properties restrictedListeners = new Properties(); + private Properties restrictedServlets = new Properties(); + + public DefaultInstanceManager(Context context, Map> injectionMap, org.apache.catalina.Context catalinaContext, ClassLoader containerClassLoader) { + classLoader = catalinaContext.getLoader().getClassLoader(); + privileged = catalinaContext.getPrivileged(); + this.containerClassLoader = containerClassLoader; + ignoreAnnotations = catalinaContext.getIgnoreAnnotations(); + StringManager sm = StringManager.getManager(Constants.Package); + try { + InputStream is = + this.getClass().getClassLoader().getResourceAsStream + ("org/apache/catalina/core/RestrictedServlets.properties"); + if (is != null) { + restrictedServlets.load(is); + } else { + catalinaContext.getLogger().error(sm.getString("defaultInstanceManager.restrictedServletsResource")); + } + } catch (IOException e) { + catalinaContext.getLogger().error(sm.getString("defaultInstanceManager.restrictedServletsResource"), e); + } + + try { + InputStream is = + this.getClass().getClassLoader().getResourceAsStream + ("org/apache/catalina/core/RestrictedListeners.properties"); + if (is != null) { + restrictedFilters.load(is); + } else { + catalinaContext.getLogger().error(sm.getString("defaultInstanceManager.restrictedListenersResources")); + } + } catch (IOException e) { + catalinaContext.getLogger().error(sm.getString("defaultInstanceManager.restrictedListenersResources"), e); + } + try { + InputStream is = + this.getClass().getClassLoader().getResourceAsStream + ("org/apache/catalina/core/RestrictedFilters.properties"); + if (is != null) { + restrictedFilters.load(is); + } else { + catalinaContext.getLogger().error(sm.getString("defaultInstanceManager.restrictedFiltersResources")); + } + } catch (IOException e) { + catalinaContext.getLogger().error(sm.getString("defaultInstanceManager.restrictedServletsResources"), e); + } + this.context = context; + this.injectionMap = injectionMap; + } + + public Object newInstance(String className) throws IllegalAccessException, InvocationTargetException, NamingException, InstantiationException, ClassNotFoundException { + Class clazz = loadClassMaybePrivileged(className, classLoader); + return newInstance(clazz.newInstance(), clazz); + } + + public Object newInstance(final String className, final ClassLoader classLoader) throws IllegalAccessException, NamingException, InvocationTargetException, InstantiationException, ClassNotFoundException { + Class clazz = classLoader.loadClass(className); + return newInstance(clazz.newInstance(), clazz); + } + + public void newInstance(Object o) + throws IllegalAccessException, InvocationTargetException, NamingException { + newInstance(o, o.getClass()); + } + + private Object newInstance(Object instance, Class clazz) throws IllegalAccessException, InvocationTargetException, NamingException { + if (!ignoreAnnotations) { + Map injections = injectionMap.get(clazz.getName()); + processAnnotations(instance, injections); + postConstruct(instance, clazz); + } + return instance; + } + + public void destroyInstance(Object instance) throws IllegalAccessException, InvocationTargetException { + if (!ignoreAnnotations) { + preDestroy(instance, instance.getClass()); + } + } + + /** + * Call postConstruct method on the specified instance recursively from deepest superclass to actual class. + * + * @param instance object to call postconstruct methods on + * @param clazz (super) class to examine for postConstruct annotation. + * @throws IllegalAccessException if postConstruct method is inaccessible. + * @throws java.lang.reflect.InvocationTargetException + * if call fails + */ + protected void postConstruct(Object instance, Class clazz) + throws IllegalAccessException, InvocationTargetException { + Class superClass = clazz.getSuperclass(); + if (superClass != Object.class) { + postConstruct(instance, superClass); + } + + Method[] methods = clazz.getDeclaredMethods(); + Method postConstruct = null; + for (Method method : methods) { + 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; + } + } + + // At the end the postconstruct annotated + // method is invoked + if (postConstruct != null) { + boolean accessibility = postConstruct.isAccessible(); + postConstruct.setAccessible(true); + postConstruct.invoke(instance); + postConstruct.setAccessible(accessibility); + } + + } + + + /** + * Call preDestroy method on the specified instance recursively from deepest superclass to actual class. + * + * @param instance object to call preDestroy methods on + * @param clazz (super) class to examine for preDestroy annotation. + * @throws IllegalAccessException if preDestroy method is inaccessible. + * @throws java.lang.reflect.InvocationTargetException + * if call fails + */ + protected void preDestroy(Object instance, Class clazz) + throws IllegalAccessException, InvocationTargetException { + Class superClass = clazz.getSuperclass(); + if (superClass != Object.class) { + preDestroy(instance, superClass); + } + + Method[] methods = clazz.getDeclaredMethods(); + Method preDestroy = null; + for (Method method : methods) { + if (method.isAnnotationPresent(PreDestroy.class)) { + if ((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; + break; + } + } + + // At the end the postconstruct annotated + // method is invoked + if (preDestroy != null) { + boolean accessibility = preDestroy.isAccessible(); + preDestroy.setAccessible(true); + preDestroy.invoke(instance); + preDestroy.setAccessible(accessibility); + } + + } + + + /** + * Inject resources in specified instance. + * + * @param instance instance to inject into + * @param injections map of injections for this class from xml deployment descriptor + * @throws IllegalAccessException if injection target is inaccessible + * @throws javax.naming.NamingException if value cannot be looked up in jndi + * @throws java.lang.reflect.InvocationTargetException + * if injection fails + */ + protected void processAnnotations(Object instance, Map injections) + throws IllegalAccessException, InvocationTargetException, NamingException { + + if (context == null) { + // No resource injection + return; + } + + // Initialize fields annotations + Field[] fields = instance.getClass().getDeclaredFields(); + for (Field field : fields) { + if (injections != null && injections.containsKey(field.getName())) { + lookupFieldResource(context, instance, field, injections.get(field.getName())); + } else if (field.isAnnotationPresent(Resource.class)) { + Resource annotation = field.getAnnotation(Resource.class); + lookupFieldResource(context, instance, field, annotation.name()); + } else if (field.isAnnotationPresent(EJB.class)) { + EJB annotation = field.getAnnotation(EJB.class); + lookupFieldResource(context, instance, field, annotation.name()); + } else if (field.isAnnotationPresent(WebServiceRef.class)) { + WebServiceRef annotation = + field.getAnnotation(WebServiceRef.class); + lookupFieldResource(context, instance, field, annotation.name()); + } else if (field.isAnnotationPresent(PersistenceContext.class)) { + PersistenceContext annotation = + field.getAnnotation(PersistenceContext.class); + lookupFieldResource(context, instance, field, annotation.name()); + } else if (field.isAnnotationPresent(PersistenceUnit.class)) { + PersistenceUnit annotation = + field.getAnnotation(PersistenceUnit.class); + lookupFieldResource(context, instance, field, annotation.name()); + } + } + + // Initialize methods annotations + Method[] methods = instance.getClass().getDeclaredMethods(); + for (Method method : methods) { + String methodName = method.getName(); + if (injections != null && methodName.startsWith("set") && methodName.length() > 3) { + String fieldName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4); + if (injections.containsKey(fieldName)) { + lookupMethodResource(context, instance, method, injections.get(fieldName)); + break; + } + } + if (method.isAnnotationPresent(Resource.class)) { + Resource annotation = method.getAnnotation(Resource.class); + lookupMethodResource(context, instance, method, annotation.name()); + } else if (method.isAnnotationPresent(EJB.class)) { + EJB annotation = method.getAnnotation(EJB.class); + lookupMethodResource(context, instance, method, annotation.name()); + } else if (method.isAnnotationPresent(WebServiceRef.class)) { + WebServiceRef annotation = + method.getAnnotation(WebServiceRef.class); + lookupMethodResource(context, instance, method, annotation.name()); + } else if (method.isAnnotationPresent(PersistenceContext.class)) { + PersistenceContext annotation = + method.getAnnotation(PersistenceContext.class); + lookupMethodResource(context, instance, method, annotation.name()); + } else if (method.isAnnotationPresent(PersistenceUnit.class)) { + PersistenceUnit annotation = + method.getAnnotation(PersistenceUnit.class); + lookupMethodResource(context, instance, method, annotation.name()); + } + } + + } + + + protected Class loadClassMaybePrivileged(final String className, final ClassLoader classLoader) throws ClassNotFoundException { + Class clazz; + if (SecurityUtil.isPackageProtectionEnabled()) { + try { + clazz = AccessController.doPrivileged(new PrivilegedExceptionAction() { + + public Class run() throws Exception { + return loadClass(className, classLoader); + } + }); + } catch (PrivilegedActionException e) { + Throwable t = e.getCause(); + if (t instanceof ClassNotFoundException) { + throw (ClassNotFoundException) t; + } + throw new RuntimeException(t); + } + } else { + clazz = loadClass(className, classLoader); + } + checkAccess(clazz); + return clazz; + } + + protected Class loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException { + if (className.startsWith("org.apache.catalina")) { + return containerClassLoader.loadClass(className); + } + try { + Class clazz = containerClassLoader.loadClass(className); + if (ContainerServlet.class.isAssignableFrom(clazz)) { + return clazz; + } + } catch (Throwable t) { + //ignore + } + return classLoader.loadClass(className); + } + + private void checkAccess(Class clazz) { + if (privileged) return; + if (clazz.isAssignableFrom(Filter.class)) { + checkAccess(clazz, restrictedFilters); + } else if (clazz.isAssignableFrom(Servlet.class)) { + checkAccess(clazz, restrictedServlets); + } else { + checkAccess(clazz, restrictedListeners); + } + } + + private void checkAccess(Class clazz, Properties restricted) { + while (clazz != null) { + if ("restricted".equals(restricted.getProperty(clazz.getName()))) { + throw new SecurityException("Restricted class" + clazz); + } + clazz = clazz.getSuperclass(); + } + + } + + /** + * Inject resources in specified field. + * + * @param context jndi context to extract value from + * @param instance object to inject into + * @param field field target for injection + * @param name jndi name value is bound under + * @throws IllegalAccessException if field is inaccessible + * @throws javax.naming.NamingException if value is not accessible in naming context + */ + protected static void lookupFieldResource(Context context, + Object instance, Field field, String name) + throws NamingException, IllegalAccessException { + + Object lookedupResource; + boolean accessibility; + + if ((name != null) && + (name.length() > 0)) { + lookedupResource = context.lookup(name); + } else { + lookedupResource = context.lookup(instance.getClass().getName() + "/" + field.getName()); + } + + accessibility = field.isAccessible(); + field.setAccessible(true); + field.set(instance, lookedupResource); + field.setAccessible(accessibility); + } + + /** + * Inject resources in specified method. + * + * @param context jndi context to extract value from + * @param instance object to inject into + * @param method field target for injection + * @param name jndi name value is bound under + * @throws IllegalAccessException if method is inaccessible + * @throws javax.naming.NamingException if value is not accessible in naming context + * @throws java.lang.reflect.InvocationTargetException + * if setter call fails + */ + protected static void lookupMethodResource(Context context, + Object instance, Method method, String name) + throws NamingException, IllegalAccessException, InvocationTargetException { + + if (!method.getName().startsWith("set") + || method.getParameterTypes().length != 1 + || !method.getReturnType().getName().equals("void")) { + throw new IllegalArgumentException("Invalid method resource injection annotation"); + } + + Object lookedupResource; + boolean accessibility; + + if ((name != null) && + (name.length() > 0)) { + lookedupResource = context.lookup(name); + } else { + lookedupResource = + context.lookup(instance.getClass().getName() + "/" + method.getName().substring(3)); + } + + accessibility = method.isAccessible(); + method.setAccessible(true); + method.invoke(instance, lookedupResource); + method.setAccessible(accessibility); + } +} diff --git a/java/org/apache/catalina/core/LocalStrings.properties b/java/org/apache/catalina/core/LocalStrings.properties index b78f1d00a..0c3c0a123 100644 --- a/java/org/apache/catalina/core/LocalStrings.properties +++ b/java/org/apache/catalina/core/LocalStrings.properties @@ -185,7 +185,6 @@ 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.privilegedServlet=Servlet of class {0} is privileged and cannot be loaded by this web application standardWrapper.releaseFilters=Release filters exception for servlet {0} standardWrapper.serviceException=Servlet.service() for servlet {0} threw exception standardWrapper.statusHeader=HTTP Status {0} - {1} @@ -194,7 +193,9 @@ 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 -standardWrapper.restrictedServletsResource=Restricted servlets property file not found -applicationFilterConfig.restrictedFiltersResource=Restricted filters property file not found -applicationFilterConfig.privilegedFilter=Filter of class {0} is privileged and cannot be loaded by this web application +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 \ No newline at end of file diff --git a/java/org/apache/catalina/core/StandardContext.java b/java/org/apache/catalina/core/StandardContext.java index 13027b8f9..82d52d7b6 100644 --- a/java/org/apache/catalina/core/StandardContext.java +++ b/java/org/apache/catalina/core/StandardContext.java @@ -31,6 +31,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.Stack; import java.util.TreeMap; @@ -59,7 +61,7 @@ import javax.servlet.ServletRequestListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionListener; -import org.apache.AnnotationProcessor; +import org.apache.InstanceManager; import org.apache.catalina.Container; import org.apache.catalina.ContainerListener; import org.apache.catalina.Context; @@ -77,6 +79,8 @@ 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; @@ -88,7 +92,6 @@ import org.apache.catalina.session.StandardManager; import org.apache.catalina.startup.ContextConfig; import org.apache.catalina.startup.TldConfig; import org.apache.catalina.util.CharsetMapper; -import org.apache.catalina.util.DefaultAnnotationProcessor; import org.apache.catalina.util.ExtensionValidator; import org.apache.catalina.util.RequestUtil; import org.apache.catalina.util.URLEncoder; @@ -174,9 +177,9 @@ public class StandardContext /** - * Annotation processor. + * Lifecycle provider. */ - private AnnotationProcessor annotationProcessor = null; + private InstanceManager instanceManager = null; /** @@ -679,13 +682,13 @@ public class StandardContext // ----------------------------------------------------- Context Properties - public AnnotationProcessor getAnnotationProcessor() { - return annotationProcessor; + public InstanceManager getInstanceManager() { + return instanceManager; } - public void setAnnotationProcessor(AnnotationProcessor annotationProcessor) { - this.annotationProcessor = annotationProcessor; + public void setInstanceManager(InstanceManager instanceManager) { + this.instanceManager = instanceManager; } @@ -3758,7 +3761,6 @@ public class StandardContext log.debug("Configuring application event listeners"); // Instantiate the required listeners - ClassLoader loader = getLoader().getClassLoader(); String listeners[] = findApplicationListeners(); Object results[] = new Object[listeners.length]; boolean ok = true; @@ -3767,13 +3769,7 @@ public class StandardContext getLogger().debug(" Configuring event listener class '" + listeners[i] + "'"); try { - Class clazz = loader.loadClass(listeners[i]); - results[i] = clazz.newInstance(); - // Annotation processing - if (!getIgnoreAnnotations()) { - getAnnotationProcessor().processAnnotations(results[i]); - getAnnotationProcessor().postConstruct(results[i]); - } + results[i] = instanceManager.newInstance(listeners[i]); } catch (Throwable t) { getLogger().error (sm.getString("standardContext.applicationListener", @@ -3873,29 +3869,26 @@ public class StandardContext ok = false; } } - // Annotation processing - if (!getIgnoreAnnotations()) { - try { - getAnnotationProcessor().preDestroy(listeners[j]); - } catch (Throwable t) { - getLogger().error - (sm.getString("standardContext.listenerStop", - listeners[j].getClass().getName()), t); - ok = false; - } + try { + getInstanceManager().destroyInstance(listeners[j]); + } catch (Throwable t) { + getLogger().error + (sm.getString("standardContext.listenerStop", + listeners[j].getClass().getName()), t); + ok = false; } } } // Annotation processing listeners = getApplicationEventListeners(); - if (!getIgnoreAnnotations() && listeners != null) { + if (listeners != null) { for (int i = 0; i < listeners.length; i++) { int j = (listeners.length - 1) - i; if (listeners[j] == null) continue; try { - getAnnotationProcessor().preDestroy(listeners[j]); + getInstanceManager().destroyInstance(listeners[j]); } catch (Throwable t) { getLogger().error (sm.getString("standardContext.listenerStop", @@ -4300,21 +4293,18 @@ public class StandardContext // Binding thread oldCCL = bindThread(); - // Set annotation processing parameter for Jasper (unfortunately, since - // this can be configured in many places and not just in /WEB-INF/web.xml, - // there are not many solutions) - // Initialize annotation processor - if (ok && !getIgnoreAnnotations()) { - if (annotationProcessor == null) { + if (ok ) { + if (instanceManager == null) { + javax.naming.Context context = null; if (isUseNaming() && namingContextListener != null) { - annotationProcessor = - new DefaultAnnotationProcessor(namingContextListener.getEnvContext()); - } else { - annotationProcessor = new DefaultAnnotationProcessor(null); + context = namingContextListener.getEnvContext(); } + Map> injectionMap = + buildInjectionMap(getIgnoreAnnotations() ? new NamingResources(): getNamingResources()); + instanceManager = new DefaultInstanceManager + (context, injectionMap, this, this.getClass().getClassLoader()); + getServletContext().setAttribute(InstanceManager.class.getName(), instanceManager); } - getServletContext().setAttribute - (AnnotationProcessor.class.getName(), annotationProcessor); } try { @@ -4395,6 +4385,48 @@ public class StandardContext //cacheContext(); } + private Map> buildInjectionMap(NamingResources namingResources) { + Map> injectionMap = new HashMap>(); + for (Injectable resource: namingResources.findLocalEjbs()) { + addInjectionTarget(resource, injectionMap); + } + for (Injectable resource: namingResources.findEjbs()) { + addInjectionTarget(resource, injectionMap); + } + for (Injectable resource: namingResources.findEnvironments()) { + addInjectionTarget(resource, injectionMap); + } + for (Injectable resource: namingResources.findMessageDestinationRefs()) { + addInjectionTarget(resource, injectionMap); + } + for (Injectable resource: namingResources.findResourceEnvRefs()) { + addInjectionTarget(resource, injectionMap); + } + for (Injectable resource: namingResources.findResources()) { + addInjectionTarget(resource, injectionMap); + } + for (Injectable resource: namingResources.findServices()) { + addInjectionTarget(resource, injectionMap); + } + return injectionMap; + } + + private void addInjectionTarget(Injectable resource, Map> injectionMap) { + List injectionTargets = resource.getInjectionTargets(); + if (injectionTargets != null && injectionTargets.size() > 0) { + String jndiName = resource.getName(); + for (InjectionTarget injectionTarget: injectionTargets) { + String clazz = injectionTarget.getTargetClass(); + Map injections = injectionMap.get(clazz); + if (injections == null) { + injections = new HashMap(); + injectionMap.put(clazz, injections); + } + injections.put(injectionTarget.getTargetName(), jndiName); + } + } + } + /** * Processes TLDs. * diff --git a/java/org/apache/catalina/core/StandardWrapper.java b/java/org/apache/catalina/core/StandardWrapper.java index 8c6120478..6aec0974d 100644 --- a/java/org/apache/catalina/core/StandardWrapper.java +++ b/java/org/apache/catalina/core/StandardWrapper.java @@ -18,27 +18,14 @@ package org.apache.catalina.core; -import java.lang.reflect.Method; -import java.io.IOException; -import java.io.InputStream; import java.io.PrintStream; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; -import java.util.Properties; import java.util.Stack; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import javax.servlet.Servlet; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.SingleThreadModel; -import javax.servlet.UnavailableException; + import javax.management.ListenerNotFoundException; import javax.management.MBeanNotificationInfo; import javax.management.Notification; @@ -47,6 +34,14 @@ import javax.management.NotificationEmitter; import javax.management.NotificationFilter; import javax.management.NotificationListener; import javax.management.ObjectName; +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.SingleThreadModel; +import javax.servlet.UnavailableException; import org.apache.PeriodicEventListener; import org.apache.catalina.Container; @@ -56,8 +51,8 @@ import org.apache.catalina.Globals; import org.apache.catalina.InstanceEvent; import org.apache.catalina.InstanceListener; import org.apache.catalina.LifecycleException; -import org.apache.catalina.Loader; import org.apache.catalina.Wrapper; +import org.apache.InstanceManager; import org.apache.catalina.security.SecurityUtil; import org.apache.catalina.util.Enumerator; import org.apache.catalina.util.InstanceSupport; @@ -96,22 +91,6 @@ public class StandardWrapper pipeline.setBasic(swValve); broadcaster = new NotificationBroadcasterSupport(); - if (restrictedServlets == null) { - restrictedServlets = new Properties(); - try { - InputStream is = - this.getClass().getClassLoader().getResourceAsStream - ("org/apache/catalina/core/RestrictedServlets.properties"); - if (is != null) { - restrictedServlets.load(is); - } else { - log.error(sm.getString("standardWrapper.restrictedServletsResource")); - } - } catch (IOException e) { - log.error(sm.getString("standardWrapper.restrictedServletsResource"), e); - } - } - } @@ -287,12 +266,7 @@ public class StandardWrapper ServletRequest.class, ServletResponse.class}; - /** - * Restricted servlets (which can only be loaded by a privileged webapp). - */ - protected static Properties restrictedServlets = null; - - + // ------------------------------------------------------------- Properties @@ -1032,83 +1006,9 @@ public class StandardWrapper (sm.getString("standardWrapper.notClass", getName())); } - // Acquire an instance of the class loader to be used - Loader loader = getLoader(); - if (loader == null) { - unavailable(null); - throw new ServletException - (sm.getString("standardWrapper.missingLoader", getName())); - } - - ClassLoader classLoader = loader.getClassLoader(); - - // Special case class loader for a container provided servlet - // - if (isContainerProvidedServlet(actualClass) && - ! ((Context)getParent()).getPrivileged() ) { - // If it is a priviledged context - using its own - // class loader will work, since it's a child of the container - // loader - classLoader = this.getClass().getClassLoader(); - } - - // Load the specified servlet class from the appropriate class loader - Class classClass = null; - try { - if (SecurityUtil.isPackageProtectionEnabled()){ - final ClassLoader fclassLoader = classLoader; - final String factualClass = actualClass; - try{ - classClass = (Class)AccessController.doPrivileged( - new PrivilegedExceptionAction(){ - public Object run() throws Exception{ - if (fclassLoader != null) { - return fclassLoader.loadClass(factualClass); - } else { - return Class.forName(factualClass); - } - } - }); - } catch(PrivilegedActionException pax){ - Exception ex = pax.getException(); - if (ex instanceof ClassNotFoundException){ - throw (ClassNotFoundException)ex; - } else { - getServletContext().log( "Error loading " - + fclassLoader + " " + factualClass, ex ); - } - } - } else { - if (classLoader != null) { - classClass = classLoader.loadClass(actualClass); - } else { - classClass = Class.forName(actualClass); - } - } - } catch (ClassNotFoundException e) { - unavailable(null); - getServletContext().log( "Error loading " + classLoader + " " + actualClass, e ); - throw new ServletException - (sm.getString("standardWrapper.missingClass", actualClass), - e); - } - - if (classClass == null) { - unavailable(null); - throw new ServletException - (sm.getString("standardWrapper.missingClass", actualClass)); - } - - // Instantiate and initialize an instance of the servlet class itself + InstanceManager instanceManager = ((StandardContext)getParent()).getInstanceManager(); try { - servlet = (Servlet) classClass.newInstance(); - // Annotation processing - if (!((Context) getParent()).getIgnoreAnnotations()) { - if (getParent() instanceof StandardContext) { - ((StandardContext)getParent()).getAnnotationProcessor().processAnnotations(servlet); - ((StandardContext)getParent()).getAnnotationProcessor().postConstruct(servlet); - } - } + servlet = (Servlet) instanceManager.newInstance(actualClass); } catch (ClassCastException e) { unavailable(null); // Restore the context ClassLoader @@ -1116,7 +1016,7 @@ public class StandardWrapper (sm.getString("standardWrapper.notServlet", actualClass), e); } catch (Throwable e) { unavailable(null); - + // Added extra log statement for Bugzilla 36630: // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630 if(log.isDebugEnabled()) { @@ -1128,14 +1028,6 @@ public class StandardWrapper (sm.getString("standardWrapper.instantiate", actualClass), e); } - // Check if loading the servlet in this web application should be - // allowed - if (!isServletAllowed(servlet)) { - throw new SecurityException - (sm.getString("standardWrapper.privilegedServlet", - actualClass)); - } - // Special handling for ContainerServlet instances if ((servlet instanceof ContainerServlet) && (isContainerProvidedServlet(actualClass) || @@ -1387,7 +1279,7 @@ public class StandardWrapper // Annotation processing if (!((Context) getParent()).getIgnoreAnnotations()) { - ((StandardContext)getParent()).getAnnotationProcessor().preDestroy(instance); + ((StandardContext)getParent()).getInstanceManager().destroyInstance(instance); } } catch (Throwable t) { @@ -1430,7 +1322,7 @@ public class StandardWrapper } // Annotation processing if (!((Context) getParent()).getIgnoreAnnotations()) { - ((StandardContext)getParent()).getAnnotationProcessor().preDestroy(s); + ((StandardContext)getParent()).getInstanceManager().destroyInstance(s); } } } catch (Throwable t) { @@ -1608,33 +1500,6 @@ public class StandardWrapper } - /** - * Return true if loading this servlet is allowed. - */ - protected boolean isServletAllowed(Object servlet) { - - // Privileged webapps may load all servlets without restriction - if (((Context) getParent()).getPrivileged()) { - return true; - } - - if (servlet instanceof ContainerServlet) { - return (false); - } - - Class clazz = servlet.getClass(); - while (clazz != null && !clazz.getName().equals("javax.servlet.http.HttpServlet")) { - if ("restricted".equals(restrictedServlets.getProperty(clazz.getName()))) { - return (false); - } - clazz = clazz.getSuperclass(); - } - - return (true); - - } - - protected Method[] getAllDeclaredMethods(Class c) { if (c.equals(javax.servlet.http.HttpServlet.class)) { diff --git a/java/org/apache/catalina/core/mbeans-descriptors.xml b/java/org/apache/catalina/core/mbeans-descriptors.xml index c97c20759..c59cb0292 100644 --- a/java/org/apache/catalina/core/mbeans-descriptors.xml +++ b/java/org/apache/catalina/core/mbeans-descriptors.xml @@ -25,9 +25,9 @@ is="true" type="boolean"/> - + injectionTargets = new ArrayList(); + + public void addInjectionTarget(String injectionTargetName, String jndiName) { + InjectionTarget target = new InjectionTarget(injectionTargetName, jndiName); + injectionTargets.add(target); + } + + public List getInjectionTargets() { + return injectionTargets; + } + // --------------------------------------------------------- Public Methods diff --git a/java/org/apache/catalina/deploy/Injectable.java b/java/org/apache/catalina/deploy/Injectable.java new file mode 100644 index 000000000..78d5146b8 --- /dev/null +++ b/java/org/apache/catalina/deploy/Injectable.java @@ -0,0 +1,29 @@ +/* + * 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.deploy; + +import java.util.List; + +public interface Injectable { + public String getName(); + public void addInjectionTarget(String injectionTargetName, String jndiName); + public List getInjectionTargets(); +} diff --git a/java/org/apache/catalina/deploy/InjectionTarget.java b/java/org/apache/catalina/deploy/InjectionTarget.java new file mode 100644 index 000000000..d02686b48 --- /dev/null +++ b/java/org/apache/catalina/deploy/InjectionTarget.java @@ -0,0 +1,55 @@ +/* + * 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.deploy; + +/** + * @version $Rev:$ $Date:$ + */ +public class InjectionTarget { + private String targetClass; + private String targetName; + + + public InjectionTarget() { + } + + public InjectionTarget(String targetClass, String targetName) { + this.targetClass = targetClass; + this.targetName = targetName; + } + + public String getTargetClass() { + return targetClass; + } + + public void setTargetClass(String targetClass) { + this.targetClass = targetClass; + } + + public String getTargetName() { + return targetName; + } + + public void setTargetName(String targetName) { + this.targetName = targetName; + } + +} diff --git a/java/org/apache/catalina/deploy/MessageDestinationRef.java b/java/org/apache/catalina/deploy/MessageDestinationRef.java index b3c63d125..c7a8fba8c 100644 --- a/java/org/apache/catalina/deploy/MessageDestinationRef.java +++ b/java/org/apache/catalina/deploy/MessageDestinationRef.java @@ -19,6 +19,8 @@ package org.apache.catalina.deploy; import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; /** @@ -31,7 +33,7 @@ import java.io.Serializable; * @since Tomcat 5.0 */ -public class MessageDestinationRef implements Serializable { +public class MessageDestinationRef implements Serializable, Injectable { // ------------------------------------------------------------- Properties @@ -106,6 +108,16 @@ public class MessageDestinationRef implements Serializable { this.usage = usage; } + private List injectionTargets = new ArrayList(); + + public void addInjectionTarget(String injectionTargetName, String jndiName) { + InjectionTarget target = new InjectionTarget(injectionTargetName, jndiName); + injectionTargets.add(target); + } + + public List getInjectionTargets() { + return injectionTargets; + } // --------------------------------------------------------- Public Methods diff --git a/java/org/apache/catalina/deploy/ResourceBase.java b/java/org/apache/catalina/deploy/ResourceBase.java index def136791..0579789f9 100644 --- a/java/org/apache/catalina/deploy/ResourceBase.java +++ b/java/org/apache/catalina/deploy/ResourceBase.java @@ -21,6 +21,8 @@ package org.apache.catalina.deploy; import java.io.Serializable; import java.util.Iterator; import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; /** @@ -30,7 +32,7 @@ import java.util.HashMap; * @version $Revision$ $Date$ */ -public class ResourceBase implements Serializable { +public class ResourceBase implements Serializable, Injectable { // ------------------------------------------------------------- Properties @@ -111,8 +113,18 @@ public class ResourceBase implements Serializable { public Iterator listProperties() { return properties.keySet().iterator(); } - - + + private List injectionTargets = new ArrayList(); + + public void addInjectionTarget(String injectionTargetName, String jndiName) { + InjectionTarget target = new InjectionTarget(injectionTargetName, jndiName); + injectionTargets.add(target); + } + + public List getInjectionTargets() { + return injectionTargets; + } + // -------------------------------------------------------- Package Methods diff --git a/java/org/apache/catalina/security/SecurityClassLoad.java b/java/org/apache/catalina/security/SecurityClassLoad.java index 71c644d0d..a71bbf3ad 100644 --- a/java/org/apache/catalina/security/SecurityClassLoad.java +++ b/java/org/apache/catalina/security/SecurityClassLoad.java @@ -65,6 +65,9 @@ public final class SecurityClassLoad { loader.loadClass (basePackage + "core.StandardWrapper$1"); + loader.loadClass + (basePackage + + "core.ApplicationHttpRequest$AttributeNamesEnumerator"); } diff --git a/java/org/apache/catalina/startup/ConnectorCreateRule.java b/java/org/apache/catalina/startup/ConnectorCreateRule.java index d4bd86940..9a6275e2f 100644 --- a/java/org/apache/catalina/startup/ConnectorCreateRule.java +++ b/java/org/apache/catalina/startup/ConnectorCreateRule.java @@ -20,13 +20,12 @@ package org.apache.catalina.startup; +import org.apache.catalina.Executor; +import org.apache.catalina.Service; import org.apache.catalina.connector.Connector; +import org.apache.tomcat.util.IntrospectionUtils; import org.apache.tomcat.util.digester.Rule; import org.xml.sax.Attributes; -import org.apache.catalina.Service; -import org.apache.catalina.Executor; -import org.apache.tomcat.util.IntrospectionUtils; -import java.lang.reflect.Method; /** @@ -51,14 +50,14 @@ public class ConnectorCreateRule extends Rule { ex = svc.getExecutor(attributes.getValue("executor")); } Connector con = new Connector(attributes.getValue("protocol")); - if ( ex != null ) _setExecutor(con,ex); + if ( ex != null ) setExecutor(con,ex); digester.push(con); } - public void _setExecutor(Connector con, Executor ex) throws Exception { - Method m = IntrospectionUtils.findMethod(con.getProtocolHandler().getClass(),"setExecutor",new Class[] {java.util.concurrent.Executor.class}); - m.invoke(con.getProtocolHandler(),new Object[] {ex}); + public void setExecutor(Connector con, Executor ex) throws Exception { + IntrospectionUtils.callMethod1(con.getProtocolHandler(), "setExecutor", + ex, java.util.concurrent.Executor.class.getName(), getClass().getClassLoader()); } @@ -66,7 +65,7 @@ public class ConnectorCreateRule extends Rule { * Process the end of this element. */ public void end() throws Exception { - Object top = digester.pop(); + digester.pop(); } diff --git a/java/org/apache/catalina/startup/WebRuleSet.java b/java/org/apache/catalina/startup/WebRuleSet.java index cd8fd4ccf..0579cba7d 100644 --- a/java/org/apache/catalina/startup/WebRuleSet.java +++ b/java/org/apache/catalina/startup/WebRuleSet.java @@ -138,58 +138,7 @@ public class WebRuleSet extends RuleSetBase { digester.addRule(prefix + "web-app/distributable", new SetDistributableRule()); - digester.addObjectCreate(prefix + "web-app/ejb-local-ref", - "org.apache.catalina.deploy.ContextLocalEjb"); - digester.addRule(prefix + "web-app/ejb-local-ref", - new SetNextNamingRule("addLocalEjb", - "org.apache.catalina.deploy.ContextLocalEjb")); - - digester.addCallMethod(prefix + "web-app/ejb-local-ref/description", - "setDescription", 0); - digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-link", - "setLink", 0); - digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-name", - "setName", 0); - digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-type", - "setType", 0); - digester.addCallMethod(prefix + "web-app/ejb-local-ref/local", - "setLocal", 0); - digester.addCallMethod(prefix + "web-app/ejb-local-ref/local-home", - "setHome", 0); - - digester.addObjectCreate(prefix + "web-app/ejb-ref", - "org.apache.catalina.deploy.ContextEjb"); - digester.addRule(prefix + "web-app/ejb-ref", - new SetNextNamingRule("addEjb", - "org.apache.catalina.deploy.ContextEjb")); - - digester.addCallMethod(prefix + "web-app/ejb-ref/description", - "setDescription", 0); - digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-link", - "setLink", 0); - digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-name", - "setName", 0); - digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-type", - "setType", 0); - digester.addCallMethod(prefix + "web-app/ejb-ref/home", - "setHome", 0); - digester.addCallMethod(prefix + "web-app/ejb-ref/remote", - "setRemote", 0); - - digester.addObjectCreate(prefix + "web-app/env-entry", - "org.apache.catalina.deploy.ContextEnvironment"); - digester.addRule(prefix + "web-app/env-entry", - new SetNextNamingRule("addEnvironment", - "org.apache.catalina.deploy.ContextEnvironment")); - - digester.addCallMethod(prefix + "web-app/env-entry/description", - "setDescription", 0); - digester.addCallMethod(prefix + "web-app/env-entry/env-entry-name", - "setName", 0); - digester.addCallMethod(prefix + "web-app/env-entry/env-entry-type", - "setType", 0); - digester.addCallMethod(prefix + "web-app/env-entry/env-entry-value", - "setValue", 0); + configureNamingRules(digester); digester.addObjectCreate(prefix + "web-app/error-page", "org.apache.catalina.deploy.ErrorPage"); @@ -281,6 +230,156 @@ public class WebRuleSet extends RuleSetBase { digester.addCallParam(prefix + "web-app/mime-mapping/extension", 0); digester.addCallParam(prefix + "web-app/mime-mapping/mime-type", 1); + + digester.addObjectCreate(prefix + "web-app/security-constraint", + "org.apache.catalina.deploy.SecurityConstraint"); + digester.addSetNext(prefix + "web-app/security-constraint", + "addConstraint", + "org.apache.catalina.deploy.SecurityConstraint"); + + digester.addRule(prefix + "web-app/security-constraint/auth-constraint", + new SetAuthConstraintRule()); + digester.addCallMethod(prefix + "web-app/security-constraint/auth-constraint/role-name", + "addAuthRole", 0); + digester.addCallMethod(prefix + "web-app/security-constraint/display-name", + "setDisplayName", 0); + digester.addCallMethod(prefix + "web-app/security-constraint/user-data-constraint/transport-guarantee", + "setUserConstraint", 0); + + digester.addObjectCreate(prefix + "web-app/security-constraint/web-resource-collection", + "org.apache.catalina.deploy.SecurityCollection"); + digester.addSetNext(prefix + "web-app/security-constraint/web-resource-collection", + "addCollection", + "org.apache.catalina.deploy.SecurityCollection"); + digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/http-method", + "addMethod", 0); + digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/url-pattern", + "addPattern", 0); + digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/web-resource-name", + "setName", 0); + + digester.addCallMethod(prefix + "web-app/security-role/role-name", + "addSecurityRole", 0); + + digester.addRule(prefix + "web-app/servlet", + new WrapperCreateRule()); + digester.addSetNext(prefix + "web-app/servlet", + "addChild", + "org.apache.catalina.Container"); + + digester.addCallMethod(prefix + "web-app/servlet/init-param", + "addInitParameter", 2); + digester.addCallParam(prefix + "web-app/servlet/init-param/param-name", + 0); + digester.addCallParam(prefix + "web-app/servlet/init-param/param-value", + 1); + + digester.addCallMethod(prefix + "web-app/servlet/jsp-file", + "setJspFile", 0); + digester.addCallMethod(prefix + "web-app/servlet/load-on-startup", + "setLoadOnStartupString", 0); + digester.addCallMethod(prefix + "web-app/servlet/run-as/role-name", + "setRunAs", 0); + + digester.addCallMethod(prefix + "web-app/servlet/security-role-ref", + "addSecurityReference", 2); + digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-link", 1); + digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-name", 0); + + digester.addCallMethod(prefix + "web-app/servlet/servlet-class", + "setServletClass", 0); + digester.addCallMethod(prefix + "web-app/servlet/servlet-name", + "setName", 0); + + digester.addRule(prefix + "web-app/servlet-mapping", + new CallMethodMultiRule("addServletMapping", 2, 0)); + digester.addCallParam(prefix + "web-app/servlet-mapping/servlet-name", 1); + digester.addRule(prefix + "web-app/servlet-mapping/url-pattern", new CallParamMultiRule(0)); + + digester.addRule(prefix + "web-app/session-config", + sessionConfig); + + digester.addCallMethod(prefix + "web-app/session-config/session-timeout", + "setSessionTimeout", 1, + new Class[] { Integer.TYPE }); + digester.addCallParam(prefix + "web-app/session-config/session-timeout", 0); + + digester.addCallMethod(prefix + "web-app/taglib", + "addTaglib", 2); + digester.addCallParam(prefix + "web-app/taglib/taglib-location", 1); + digester.addCallParam(prefix + "web-app/taglib/taglib-uri", 0); + + digester.addCallMethod(prefix + "web-app/welcome-file-list/welcome-file", + "addWelcomeFile", 0); + + digester.addCallMethod(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping", + "addLocaleEncodingMappingParameter", 2); + digester.addCallParam(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping/locale", 0); + digester.addCallParam(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping/encoding", 1); + + } + + protected void configureNamingRules(Digester digester) { + //ejb-local-ref + digester.addObjectCreate(prefix + "web-app/ejb-local-ref", + "org.apache.catalina.deploy.ContextLocalEjb"); + digester.addRule(prefix + "web-app/ejb-local-ref", + new SetNextNamingRule("addLocalEjb", + "org.apache.catalina.deploy.ContextLocalEjb")); + + digester.addCallMethod(prefix + "web-app/ejb-local-ref/description", + "setDescription", 0); + digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-link", + "setLink", 0); + digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-name", + "setName", 0); + digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-type", + "setType", 0); + digester.addCallMethod(prefix + "web-app/ejb-local-ref/local", + "setLocal", 0); + digester.addCallMethod(prefix + "web-app/ejb-local-ref/local-home", + "setHome", 0); + configureInjectionRules(digester, "web-app/ejb-local-ref/"); + + //ejb-ref + digester.addObjectCreate(prefix + "web-app/ejb-ref", + "org.apache.catalina.deploy.ContextEjb"); + digester.addRule(prefix + "web-app/ejb-ref", + new SetNextNamingRule("addEjb", + "org.apache.catalina.deploy.ContextEjb")); + + digester.addCallMethod(prefix + "web-app/ejb-ref/description", + "setDescription", 0); + digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-link", + "setLink", 0); + digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-name", + "setName", 0); + digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-type", + "setType", 0); + digester.addCallMethod(prefix + "web-app/ejb-ref/home", + "setHome", 0); + digester.addCallMethod(prefix + "web-app/ejb-ref/remote", + "setRemote", 0); + configureInjectionRules(digester, "web-app/ejb-ref/"); + + //env-entry + digester.addObjectCreate(prefix + "web-app/env-entry", + "org.apache.catalina.deploy.ContextEnvironment"); + digester.addRule(prefix + "web-app/env-entry", + new SetNextNamingRule("addEnvironment", + "org.apache.catalina.deploy.ContextEnvironment")); + + digester.addCallMethod(prefix + "web-app/env-entry/description", + "setDescription", 0); + digester.addCallMethod(prefix + "web-app/env-entry/env-entry-name", + "setName", 0); + digester.addCallMethod(prefix + "web-app/env-entry/env-entry-type", + "setType", 0); + digester.addCallMethod(prefix + "web-app/env-entry/env-entry-value", + "setValue", 0); + configureInjectionRules(digester, "web-app/env-entry/"); + + //resource-env-ref digester.addObjectCreate(prefix + "web-app/resource-env-ref", "org.apache.catalina.deploy.ContextResourceEnvRef"); digester.addRule(prefix + "web-app/resource-env-ref", @@ -291,7 +390,9 @@ public class WebRuleSet extends RuleSetBase { "setName", 0); digester.addCallMethod(prefix + "web-app/resource-env-ref/resource-env-ref-type", "setType", 0); + configureInjectionRules(digester, "web-app/ejb-local-ref/"); + //message-destination digester.addObjectCreate(prefix + "web-app/message-destination", "org.apache.catalina.deploy.MessageDestination"); digester.addSetNext(prefix + "web-app/message-destination", @@ -309,6 +410,7 @@ public class WebRuleSet extends RuleSetBase { digester.addCallMethod(prefix + "web-app/message-destination/message-destination-name", "setName", 0); + //message-destination-ref digester.addObjectCreate(prefix + "web-app/message-destination-ref", "org.apache.catalina.deploy.MessageDestinationRef"); digester.addSetNext(prefix + "web-app/message-destination-ref", @@ -326,6 +428,9 @@ public class WebRuleSet extends RuleSetBase { digester.addCallMethod(prefix + "web-app/message-destination-ref/message-destination-usage", "setUsage", 0); + configureInjectionRules(digester, "web-app/message-destination-ref/"); + + //resource-ref digester.addObjectCreate(prefix + "web-app/resource-ref", "org.apache.catalina.deploy.ContextResource"); digester.addRule(prefix + "web-app/resource-ref", @@ -342,37 +447,9 @@ public class WebRuleSet extends RuleSetBase { "setScope", 0); digester.addCallMethod(prefix + "web-app/resource-ref/res-type", "setType", 0); + configureInjectionRules(digester, "web-app/resource-ref/"); - digester.addObjectCreate(prefix + "web-app/security-constraint", - "org.apache.catalina.deploy.SecurityConstraint"); - digester.addSetNext(prefix + "web-app/security-constraint", - "addConstraint", - "org.apache.catalina.deploy.SecurityConstraint"); - - digester.addRule(prefix + "web-app/security-constraint/auth-constraint", - new SetAuthConstraintRule()); - digester.addCallMethod(prefix + "web-app/security-constraint/auth-constraint/role-name", - "addAuthRole", 0); - digester.addCallMethod(prefix + "web-app/security-constraint/display-name", - "setDisplayName", 0); - digester.addCallMethod(prefix + "web-app/security-constraint/user-data-constraint/transport-guarantee", - "setUserConstraint", 0); - - digester.addObjectCreate(prefix + "web-app/security-constraint/web-resource-collection", - "org.apache.catalina.deploy.SecurityCollection"); - digester.addSetNext(prefix + "web-app/security-constraint/web-resource-collection", - "addCollection", - "org.apache.catalina.deploy.SecurityCollection"); - digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/http-method", - "addMethod", 0); - digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/url-pattern", - "addPattern", 0); - digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/web-resource-name", - "setName", 0); - - digester.addCallMethod(prefix + "web-app/security-role/role-name", - "addSecurityRole", 0); - + //service-ref digester.addObjectCreate(prefix + "web-app/service-ref", "org.apache.catalina.deploy.ContextService"); digester.addRule(prefix + "web-app/service-ref", @@ -405,7 +482,7 @@ public class WebRuleSet extends RuleSetBase { digester.addRule(prefix + "web-app/service-ref/handler", new SetNextRule("addHandler", "org.apache.catalina.deploy.ContextHandler")); - + digester.addCallMethod(prefix + "web-app/service-ref/handler/handler-name", "setName", 0); digester.addCallMethod(prefix + "web-app/service-ref/handler/handler-class", @@ -424,65 +501,20 @@ public class WebRuleSet extends RuleSetBase { "addSoapRole", 0); digester.addCallMethod(prefix + "web-app/service-ref/handler/port-name", "addPortName", 0); - - digester.addRule(prefix + "web-app/servlet", - new WrapperCreateRule()); - digester.addSetNext(prefix + "web-app/servlet", - "addChild", - "org.apache.catalina.Container"); - - digester.addCallMethod(prefix + "web-app/servlet/init-param", - "addInitParameter", 2); - digester.addCallParam(prefix + "web-app/servlet/init-param/param-name", - 0); - digester.addCallParam(prefix + "web-app/servlet/init-param/param-value", - 1); - - digester.addCallMethod(prefix + "web-app/servlet/jsp-file", - "setJspFile", 0); - digester.addCallMethod(prefix + "web-app/servlet/load-on-startup", - "setLoadOnStartupString", 0); - digester.addCallMethod(prefix + "web-app/servlet/run-as/role-name", - "setRunAs", 0); - - digester.addCallMethod(prefix + "web-app/servlet/security-role-ref", - "addSecurityReference", 2); - digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-link", 1); - digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-name", 0); - - digester.addCallMethod(prefix + "web-app/servlet/servlet-class", - "setServletClass", 0); - digester.addCallMethod(prefix + "web-app/servlet/servlet-name", - "setName", 0); + configureInjectionRules(digester, "web-app/service-ref/"); - digester.addRule(prefix + "web-app/servlet-mapping", - new CallMethodMultiRule("addServletMapping", 2, 0)); - digester.addCallParam(prefix + "web-app/servlet-mapping/servlet-name", 1); - digester.addRule(prefix + "web-app/servlet-mapping/url-pattern", new CallParamMultiRule(0)); - digester.addRule(prefix + "web-app/session-config", - sessionConfig); - - digester.addCallMethod(prefix + "web-app/session-config/session-timeout", - "setSessionTimeout", 1, - new Class[] { Integer.TYPE }); - digester.addCallParam(prefix + "web-app/session-config/session-timeout", 0); - - digester.addCallMethod(prefix + "web-app/taglib", - "addTaglib", 2); - digester.addCallParam(prefix + "web-app/taglib/taglib-location", 1); - digester.addCallParam(prefix + "web-app/taglib/taglib-uri", 0); + } - digester.addCallMethod(prefix + "web-app/welcome-file-list/welcome-file", - "addWelcomeFile", 0); + protected void configureInjectionRules(Digester digester, String base) { - digester.addCallMethod(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping", - "addLocaleEncodingMappingParameter", 2); - digester.addCallParam(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping/locale", 0); - digester.addCallParam(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping/encoding", 1); + digester.addCallMethod(prefix + base + "injection-target", "addInjectionTarget", 2); + digester.addCallParam(prefix + base + "injection-target/injection-target-class", 0); + digester.addCallParam(prefix + base + "injection-target/injection-target-name", 1); } + /** * Reset counter used for validating the web.xml file. */ diff --git a/java/org/apache/catalina/util/DefaultAnnotationProcessor.java b/java/org/apache/catalina/util/DefaultAnnotationProcessor.java deleted file mode 100644 index 0c5039cd3..000000000 --- a/java/org/apache/catalina/util/DefaultAnnotationProcessor.java +++ /dev/null @@ -1,244 +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.catalina.util; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.annotation.Resource; -import javax.ejb.EJB; -import javax.naming.NamingException; -import javax.persistence.PersistenceContext; -import javax.persistence.PersistenceUnit; -import javax.xml.ws.WebServiceRef; - -import org.apache.AnnotationProcessor; - - -/** - * Verify the annotation and Process it. - * - * @author Fabien Carrion - * @author Remy Maucherat - * @version $Revision$, $Date$ - */ -public class DefaultAnnotationProcessor implements AnnotationProcessor { - - protected javax.naming.Context context = null; - - public DefaultAnnotationProcessor(javax.naming.Context context) { - this.context = context; - } - - - /** - * Call postConstruct method on the specified instance. - */ - public void postConstruct(Object instance) - throws IllegalAccessException, InvocationTargetException { - - Method[] methods = instance.getClass().getDeclaredMethods(); - Method postConstruct = null; - for (int i = 0; i < methods.length; i++) { - if (methods[i].isAnnotationPresent(PostConstruct.class)) { - if ((postConstruct != null) - || (methods[i].getParameterTypes().length != 0) - || (Modifier.isStatic(methods[i].getModifiers())) - || (methods[i].getExceptionTypes().length > 0) - || (!methods[i].getReturnType().getName().equals("void"))) { - throw new IllegalArgumentException("Invalid PostConstruct annotation"); - } - postConstruct = methods[i]; - } - } - - // At the end the postconstruct annotated - // method is invoked - if (postConstruct != null) { - boolean accessibility = postConstruct.isAccessible(); - postConstruct.setAccessible(true); - postConstruct.invoke(instance); - postConstruct.setAccessible(accessibility); - } - - } - - - /** - * Call preDestroy method on the specified instance. - */ - public void preDestroy(Object instance) - throws IllegalAccessException, InvocationTargetException { - - Method[] methods = instance.getClass().getDeclaredMethods(); - Method preDestroy = null; - for (int i = 0; i < methods.length; i++) { - if (methods[i].isAnnotationPresent(PreDestroy.class)) { - if ((preDestroy != null) - || (methods[i].getParameterTypes().length != 0) - || (Modifier.isStatic(methods[i].getModifiers())) - || (methods[i].getExceptionTypes().length > 0) - || (!methods[i].getReturnType().getName().equals("void"))) { - throw new IllegalArgumentException("Invalid PreDestroy annotation"); - } - preDestroy = methods[i]; - } - } - - // At the end the postconstruct annotated - // method is invoked - if (preDestroy != null) { - boolean accessibility = preDestroy.isAccessible(); - preDestroy.setAccessible(true); - preDestroy.invoke(instance); - preDestroy.setAccessible(accessibility); - } - - } - - - /** - * Inject resources in specified instance. - */ - public void processAnnotations(Object instance) - throws IllegalAccessException, InvocationTargetException, NamingException { - - if (context == null) { - // No resource injection - return; - } - - // Initialize fields annotations - Field[] fields = instance.getClass().getDeclaredFields(); - for (int i = 0; i < fields.length; i++) { - if (fields[i].isAnnotationPresent(Resource.class)) { - Resource annotation = (Resource) fields[i].getAnnotation(Resource.class); - lookupFieldResource(context, instance, fields[i], annotation.name()); - } - if (fields[i].isAnnotationPresent(EJB.class)) { - EJB annotation = (EJB) fields[i].getAnnotation(EJB.class); - lookupFieldResource(context, instance, fields[i], annotation.name()); - } - if (fields[i].isAnnotationPresent(WebServiceRef.class)) { - WebServiceRef annotation = - (WebServiceRef) fields[i].getAnnotation(WebServiceRef.class); - lookupFieldResource(context, instance, fields[i], annotation.name()); - } - if (fields[i].isAnnotationPresent(PersistenceContext.class)) { - PersistenceContext annotation = - (PersistenceContext) fields[i].getAnnotation(PersistenceContext.class); - lookupFieldResource(context, instance, fields[i], annotation.name()); - } - if (fields[i].isAnnotationPresent(PersistenceUnit.class)) { - PersistenceUnit annotation = - (PersistenceUnit) fields[i].getAnnotation(PersistenceUnit.class); - lookupFieldResource(context, instance, fields[i], annotation.name()); - } - } - - // Initialize methods annotations - Method[] methods = instance.getClass().getDeclaredMethods(); - for (int i = 0; i < methods.length; i++) { - if (methods[i].isAnnotationPresent(Resource.class)) { - Resource annotation = (Resource) methods[i].getAnnotation(Resource.class); - lookupMethodResource(context, instance, methods[i], annotation.name()); - } - if (methods[i].isAnnotationPresent(EJB.class)) { - EJB annotation = (EJB) methods[i].getAnnotation(EJB.class); - lookupMethodResource(context, instance, methods[i], annotation.name()); - } - if (methods[i].isAnnotationPresent(WebServiceRef.class)) { - WebServiceRef annotation = - (WebServiceRef) methods[i].getAnnotation(WebServiceRef.class); - lookupMethodResource(context, instance, methods[i], annotation.name()); - } - if (methods[i].isAnnotationPresent(PersistenceContext.class)) { - PersistenceContext annotation = - (PersistenceContext) methods[i].getAnnotation(PersistenceContext.class); - lookupMethodResource(context, instance, methods[i], annotation.name()); - } - if (methods[i].isAnnotationPresent(PersistenceUnit.class)) { - PersistenceUnit annotation = - (PersistenceUnit) methods[i].getAnnotation(PersistenceUnit.class); - lookupMethodResource(context, instance, methods[i], annotation.name()); - } - } - - } - - - /** - * Inject resources in specified field. - */ - protected static void lookupFieldResource(javax.naming.Context context, - Object instance, Field field, String name) - throws NamingException, IllegalAccessException { - - Object lookedupResource = null; - boolean accessibility = false; - - if ((name != null) && - (name.length() > 0)) { - lookedupResource = context.lookup(name); - } else { - lookedupResource = context.lookup(instance.getClass().getName() + "/" + field.getName()); - } - - accessibility = field.isAccessible(); - field.setAccessible(true); - field.set(instance, lookedupResource); - field.setAccessible(accessibility); - } - - - /** - * Inject resources in specified method. - */ - protected static void lookupMethodResource(javax.naming.Context context, - Object instance, Method method, String name) - throws NamingException, IllegalAccessException, InvocationTargetException { - - if (!method.getName().startsWith("set") - || method.getParameterTypes().length != 1 - || !method.getReturnType().getName().equals("void")) { - throw new IllegalArgumentException("Invalid method resource injection annotation"); - } - - Object lookedupResource = null; - boolean accessibility = false; - - if ((name != null) && - (name.length() > 0)) { - lookedupResource = context.lookup(name); - } else { - lookedupResource = - context.lookup(instance.getClass().getName() + "/" + method.getName().substring(3)); - } - - accessibility = method.isAccessible(); - method.setAccessible(true); - method.invoke(instance, lookedupResource); - method.setAccessible(accessibility); - } - - -} diff --git a/java/org/apache/jasper/Constants.java b/java/org/apache/jasper/Constants.java index 4ec2fefa3..8d1a85f81 100644 --- a/java/org/apache/jasper/Constants.java +++ b/java/org/apache/jasper/Constants.java @@ -193,4 +193,7 @@ public class Constants { public static final boolean IS_SECURITY_ENABLED = (System.getSecurityManager() != null); + public static final boolean USE_INSTANCE_MANAGER_FOR_TAGS = + Boolean.valueOf(System.getProperty("org.apache.jasper.Constants.USE_INSTANCE_MANAGER_FOR_TAGS", "false")).booleanValue(); + } diff --git a/java/org/apache/jasper/JspCompilationContext.java b/java/org/apache/jasper/JspCompilationContext.java index 3409040a9..b98e6fe35 100644 --- a/java/org/apache/jasper/JspCompilationContext.java +++ b/java/org/apache/jasper/JspCompilationContext.java @@ -589,12 +589,7 @@ public class JspCompilationContext { try { getJspLoader(); - String name; - if (isTagFile()) { - name = tagInfo.getTagClassName(); - } else { - name = getServletPackageName() + "." + getServletClassName(); - } + String name = getFQCN(); servletClass = jspLoader.loadClass(name); } catch (ClassNotFoundException cex) { throw new JasperException(Localizer.getMessage("jsp.error.unable.load"), @@ -607,6 +602,16 @@ public class JspCompilationContext { return servletClass; } + public String getFQCN() { + String name; + if (isTagFile()) { + name = tagInfo.getTagClassName(); + } else { + name = getServletPackageName() + "." + getServletClassName(); + } + return name; + } + // ==================== protected methods ==================== static Object outputDirLock = new Object(); diff --git a/java/org/apache/jasper/compiler/Generator.java b/java/org/apache/jasper/compiler/Generator.java index e8047cbe7..2dd0963b2 100644 --- a/java/org/apache/jasper/compiler/Generator.java +++ b/java/org/apache/jasper/compiler/Generator.java @@ -73,8 +73,8 @@ class Generator { private static final String VAR_EXPRESSIONFACTORY = System.getProperty("org.apache.jasper.compiler.Generator.VAR_EXPRESSIONFACTORY", "_el_expressionfactory"); - private static final String VAR_ANNOTATIONPROCESSOR = - System.getProperty("org.apache.jasper.compiler.Generator.VAR_ANNOTATIONPROCESSOR", "_jsp_annotationprocessor"); + private static final String VAR_INSTANCEMANAGER = + System.getProperty("org.apache.jasper.compiler.Generator.VAR_INSTANCEMANAGER", "_jsp_instancemanager"); private ServletWriter out; @@ -410,14 +410,14 @@ class Generator { } out.println(".getServletContext()).getExpressionFactory();"); - out.printin(VAR_ANNOTATIONPROCESSOR); - out.print(" = (org.apache.AnnotationProcessor) "); + out.printin(VAR_INSTANCEMANAGER); + out.print(" = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager("); if (ctxt.isTagFile()) { out.print("config"); } else { out.print("getServletConfig()"); } - out.println(".getServletContext().getAttribute(org.apache.AnnotationProcessor.class.getName());"); + out.println(");"); out.popIndent(); out.printil("}"); @@ -521,8 +521,8 @@ class Generator { out.printin("private javax.el.ExpressionFactory "); out.print(VAR_EXPRESSIONFACTORY); out.println(";"); - out.printin("private org.apache.AnnotationProcessor "); - out.print(VAR_ANNOTATIONPROCESSOR); + out.printin("private org.apache.InstanceManager "); + out.print(VAR_INSTANCEMANAGER); out.println(";"); out.println(); } @@ -2142,11 +2142,11 @@ class Generator { String tagHandlerClassName = JspUtil .getCanonicalName(tagHandlerClass); - out.printin(tagHandlerClassName); - out.print(" "); - out.print(tagHandlerVar); - out.print(" = "); if (isPoolingEnabled && !(n.implementsJspIdConsumer())) { + out.printin(tagHandlerClassName); + out.print(" "); + out.print(tagHandlerVar); + out.print(" = "); out.print("("); out.print(tagHandlerClassName); out.print(") "); @@ -2155,14 +2155,7 @@ class Generator { out.print(tagHandlerClassName); out.println(".class);"); } else { - out.print("new "); - out.print(tagHandlerClassName); - out.println("();"); - out.printin("org.apache.jasper.runtime.AnnotationHelper.postConstruct("); - out.print(VAR_ANNOTATIONPROCESSOR); - out.print(", "); - out.print(tagHandlerVar); - out.println(");"); + writeNewInstance(tagHandlerVar, tagHandlerClassName); } // includes setting the context @@ -2220,8 +2213,7 @@ class Generator { out.println("[0]++;"); } out.printin(tagHandlerVar); - out - .println(".setBodyContent((javax.servlet.jsp.tagext.BodyContent) out);"); + out.println(".setBodyContent((javax.servlet.jsp.tagext.BodyContent) out);"); out.printin(tagHandlerVar); out.println(".doInitBody();"); @@ -2247,6 +2239,40 @@ class Generator { n.setEndJavaLine(out.getJavaLine()); } + private void writeNewInstance(String tagHandlerVar, String tagHandlerClassName) { + if (Constants.USE_INSTANCE_MANAGER_FOR_TAGS) { + out.printin(tagHandlerClassName); + out.print(" "); + out.print(tagHandlerVar); + out.print(" = ("); + out.print(tagHandlerClassName); + out.print(")"); + out.print(VAR_INSTANCEMANAGER); + out.print(".newInstance(\""); + out.print(tagHandlerClassName); + out.println("\", this.getClass().getClassLoader());"); + } else { + out.printin(tagHandlerClassName); + out.print(" "); + out.print(tagHandlerVar); + out.print(" = ("); + out.print("new "); + out.print(tagHandlerClassName); + out.println("());"); + out.printin(VAR_INSTANCEMANAGER); + out.print(".newInstance("); + out.print(tagHandlerVar); + out.println(");"); + } + } + + private void writeDestroyInstance(String tagHandlerVar) { + out.printin(VAR_INSTANCEMANAGER); + out.print(".destroyInstance("); + out.print(tagHandlerVar); + out.println(");"); + } + private void generateCustomEnd(Node.CustomTag n, String tagHandlerVar, String tagEvalVar, String tagPushBodyCountVar) { @@ -2308,11 +2334,7 @@ class Generator { } else { out.printin(tagHandlerVar); out.println(".release();"); - out.printin("org.apache.jasper.runtime.AnnotationHelper.preDestroy("); - out.print(VAR_ANNOTATIONPROCESSOR); - out.print(", "); - out.print(tagHandlerVar); - out.println(");"); + writeDestroyInstance(tagHandlerVar); } } if (isTagFile || isFragment) { @@ -2355,11 +2377,7 @@ class Generator { } else { out.printin(tagHandlerVar); out.println(".release();"); - out.printin("org.apache.jasper.runtime.AnnotationHelper.preDestroy("); - out.print(VAR_ANNOTATIONPROCESSOR); - out.print(", "); - out.print(tagHandlerVar); - out.println(");"); + writeDestroyInstance(tagHandlerVar); } if (n.implementsTryCatchFinally()) { @@ -2391,21 +2409,8 @@ class Generator { String tagHandlerClassName = JspUtil .getCanonicalName(tagHandlerClass); - out.printin(tagHandlerClassName); - out.print(" "); - out.print(tagHandlerVar); - out.print(" = "); - out.print("new "); - out.print(tagHandlerClassName); - out.println("();"); + writeNewInstance(tagHandlerVar, tagHandlerClassName); - // Resource injection - out.printin("org.apache.jasper.runtime.AnnotationHelper.postConstruct("); - out.print(VAR_ANNOTATIONPROCESSOR); - out.print(", "); - out.print(tagHandlerVar); - out.println(");"); - generateSetters(n, tagHandlerVar, handlerInfo, true); // JspIdConsumer (after context has been set) @@ -2458,11 +2463,7 @@ class Generator { syncScriptingVars(n, VariableInfo.AT_END); // Resource injection - out.printin("org.apache.jasper.runtime.AnnotationHelper.preDestroy("); - out.print(VAR_ANNOTATIONPROCESSOR); - out.print(", "); - out.print(tagHandlerVar); - out.println(");"); + writeDestroyInstance(tagHandlerVar); n.setEndJavaLine(out.getJavaLine()); } diff --git a/java/org/apache/jasper/runtime/AnnotationHelper.java b/java/org/apache/jasper/runtime/AnnotationHelper.java deleted file mode 100644 index 428f3d284..000000000 --- a/java/org/apache/jasper/runtime/AnnotationHelper.java +++ /dev/null @@ -1,61 +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.jasper.runtime; - -import java.lang.reflect.InvocationTargetException; - -import javax.naming.NamingException; - -import org.apache.AnnotationProcessor; - - -/** - * Verify the annotation and Process it. - * - * @author Fabien Carrion - * @author Remy Maucherat - * @version $Revision$, $Date$ - */ -public class AnnotationHelper { - - - /** - * Call postConstruct method on the specified instance. Note: In Jasper, this - * calls naming resources injection as well. - */ - public static void postConstruct(AnnotationProcessor processor, Object instance) - throws IllegalAccessException, InvocationTargetException, NamingException { - if (processor != null) { - processor.processAnnotations(instance); - processor.postConstruct(instance); - } - } - - - /** - * Call preDestroy method on the specified instance. - */ - public static void preDestroy(AnnotationProcessor processor, Object instance) - throws IllegalAccessException, InvocationTargetException { - if (processor != null) { - processor.preDestroy(instance); - } - } - - -} diff --git a/java/org/apache/jasper/runtime/InstanceManagerFactory.java b/java/org/apache/jasper/runtime/InstanceManagerFactory.java new file mode 100644 index 000000000..d586fdb80 --- /dev/null +++ b/java/org/apache/jasper/runtime/InstanceManagerFactory.java @@ -0,0 +1,44 @@ +/* + * 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.jasper.runtime; + +import javax.servlet.ServletConfig; + +import org.apache.InstanceManager; + +/** + * @version $Rev:$ $Date:$ + */ +public class InstanceManagerFactory { + + private InstanceManagerFactory() { + } + + public static InstanceManager getInstanceManager(ServletConfig config) { + InstanceManager instanceManager = + (InstanceManager) config.getServletContext().getAttribute(InstanceManager.class.getName()); + if (instanceManager == null) { + throw new IllegalStateException("No org.apache.InstanceManager set in ServletContext"); + } + return instanceManager; + } + +} diff --git a/java/org/apache/jasper/runtime/TagHandlerPool.java b/java/org/apache/jasper/runtime/TagHandlerPool.java index 74f2b64bc..b9b32907e 100644 --- a/java/org/apache/jasper/runtime/TagHandlerPool.java +++ b/java/org/apache/jasper/runtime/TagHandlerPool.java @@ -21,7 +21,7 @@ import javax.servlet.ServletConfig; import javax.servlet.jsp.JspException; import javax.servlet.jsp.tagext.Tag; -import org.apache.AnnotationProcessor; +import org.apache.InstanceManager; import org.apache.jasper.Constants; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; @@ -42,7 +42,7 @@ public class TagHandlerPool { // index of next available tag handler private int current; - protected AnnotationProcessor annotationProcessor = null; + protected InstanceManager instanceManager = null; public static TagHandlerPool getTagHandlerPool( ServletConfig config) { TagHandlerPool result=null; @@ -78,8 +78,7 @@ public class TagHandlerPool { } this.handlers = new Tag[maxSize]; this.current = -1; - this.annotationProcessor = - (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName()); + instanceManager = InstanceManagerFactory.getInstanceManager(config); } /** @@ -112,7 +111,7 @@ public class TagHandlerPool { * @throws JspException if a tag handler cannot be instantiated */ public Tag get(Class handlerClass) throws JspException { - Tag handler = null; + Tag handler; synchronized( this ) { if (current >= 0) { handler = handlers[current--]; @@ -123,9 +122,13 @@ public class TagHandlerPool { // Out of sync block - there is no need for other threads to // wait for us to construct a tag for this thread. try { - Tag instance = (Tag) handlerClass.newInstance(); - AnnotationHelper.postConstruct(annotationProcessor, instance); - return instance; + if (Constants.USE_INSTANCE_MANAGER_FOR_TAGS) { + return (Tag) instanceManager.newInstance(handlerClass.getName(), handlerClass.getClassLoader()); + } else { + Tag instance = (Tag) handlerClass.newInstance(); + instanceManager.newInstance(instance); + return instance; + } } catch (Exception e) { throw new JspException(e.getMessage(), e); } @@ -147,13 +150,11 @@ public class TagHandlerPool { } // There is no need for other threads to wait for us to release handler.release(); - if (annotationProcessor != null) { - try { - AnnotationHelper.preDestroy(annotationProcessor, handler); - } catch (Exception e) { - log.warn("Error processing preDestroy on tag instance of " - + handler.getClass().getName(), e); - } + try { + instanceManager.destroyInstance(handler); + } catch (Exception e) { + log.warn("Error processing preDestroy on tag instance of " + + handler.getClass().getName(), e); } } @@ -164,13 +165,11 @@ public class TagHandlerPool { public synchronized void release() { for (int i = current; i >= 0; i--) { handlers[i].release(); - if (annotationProcessor != null) { - try { - AnnotationHelper.preDestroy(annotationProcessor, handlers[i]); - } catch (Exception e) { - log.warn("Error processing preDestroy on tag instance of " - + handlers[i].getClass().getName(), e); - } + try { + instanceManager.destroyInstance(handlers[i]); + } catch (Exception e) { + log.warn("Error processing preDestroy on tag instance of " + + handlers[i].getClass().getName(), e); } } } diff --git a/java/org/apache/jasper/servlet/JspServletWrapper.java b/java/org/apache/jasper/servlet/JspServletWrapper.java index 99a43979d..12d0cdcde 100644 --- a/java/org/apache/jasper/servlet/JspServletWrapper.java +++ b/java/org/apache/jasper/servlet/JspServletWrapper.java @@ -31,7 +31,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.jsp.tagext.TagInfo; -import org.apache.AnnotationProcessor; +import org.apache.InstanceManager; import org.apache.jasper.JasperException; import org.apache.jasper.JspCompilationContext; import org.apache.jasper.Options; @@ -39,6 +39,7 @@ import org.apache.jasper.compiler.ErrorDispatcher; import org.apache.jasper.compiler.JavacErrorDetail; import org.apache.jasper.compiler.JspRuntimeContext; import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.runtime.InstanceManagerFactory; import org.apache.jasper.runtime.JspSourceDependent; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; @@ -68,7 +69,6 @@ public class JspServletWrapper { private Servlet theServlet; private String jspUri; - private Class servletClass; private Class tagHandlerClass; private JspCompilationContext ctxt; private long available = 0L; @@ -139,15 +139,10 @@ public class JspServletWrapper { destroy(); Servlet servlet = null; - + try { - servletClass = ctxt.load(); - servlet = (Servlet) servletClass.newInstance(); - AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName()); - if (annotationProcessor != null) { - annotationProcessor.processAnnotations(servlet); - annotationProcessor.postConstruct(servlet); - } + InstanceManager instanceManager = InstanceManagerFactory.getInstanceManager(config); + servlet = (Servlet) instanceManager.newInstance(ctxt.getFQCN(), ctxt.getJspLoader()); } catch (IllegalAccessException e) { throw new JasperException(e); } catch (InstantiationException e) { @@ -442,15 +437,13 @@ public class JspServletWrapper { public void destroy() { if (theServlet != null) { theServlet.destroy(); - AnnotationProcessor annotationProcessor = (AnnotationProcessor) config.getServletContext().getAttribute(AnnotationProcessor.class.getName()); - if (annotationProcessor != null) { - try { - annotationProcessor.preDestroy(theServlet); - } catch (Exception e) { - // Log any exception, since it can't be passed along - log.error(Localizer.getMessage("jsp.error.file.not.found", - e.getMessage()), e); - } + InstanceManager instanceManager = InstanceManagerFactory.getInstanceManager(config); + try { + instanceManager.destroyInstance(theServlet); + } catch (Exception e) { + // Log any exception, since it can't be passed along + log.error(Localizer.getMessage("jsp.error.file.not.found", + e.getMessage()), e); } } } -- 2.11.0