From d627905f4bf35f76b3cc72703af39d2e298ea875 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Thu, 10 Sep 2009 11:51:11 +0000 Subject: [PATCH] JETTY-780 git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@859 7e9141cc-0065-0410-87d8-b60c137991c4 --- VERSION.txt | 1 + .../jetty/annotations/AnnotationParser.java | 8 +- .../PostConstructAnnotationHandler.java | 51 ++-- .../PreDestroyAnnotationHandler.java | 47 ++-- .../ResourceAnnotationHandler.java | 241 ++++++++--------- .../ResourcesAnnotationHandler.java | 82 +++--- .../annotations/RunAsAnnotationHandler.java | 17 +- .../org/eclipse/jetty/annotations/Util.java | 75 +++++- .../eclipse/jetty/annotations/ServletC.java | 8 +- .../annotations/TestAnnotationParser.java | 19 +- .../annotations/TestServletAnnotations.java | 75 +++++- .../annotations/resources/ResourceB.java | 4 +- .../resources/TestResourceAnnotations.java | 48 ++-- .../jetty/plus/annotation/Injection.java | 249 +++++++++++++----- .../plus/annotation/InjectionCollection.java | 122 ++++----- .../plus/annotation/LifeCycleCallback.java | 43 +-- .../LifeCycleCallbackCollection.java | 27 +- .../eclipse/jetty/plus/annotation/RunAs.java | 23 +- .../plus/annotation/RunAsCollection.java | 10 +- .../plus/webapp/AbstractConfiguration.java | 1 - 20 files changed, 679 insertions(+), 472 deletions(-) diff --git a/VERSION.txt b/VERSION.txt index 693ec7c3f8b..150eb9a852a 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -6,6 +6,7 @@ jetty-7.0.0.RC6-SNAPSHOT + 288055 jetty-client fails to resolve failed resolution attempts correctly + 288153 jetty-client resend doesn't reset exchange + 288182 PUT request fails during retry + + JETTY-780 CNFE during startup of webapp with spring-context >= 2.5.1 + JETTY-1080 modify previous fix to work on windows + JETTY-1084 HEAD command not setting content-type in response under certain circumstances + JETTY-1086 Use UncheckedPrintWriter diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java index ffcebd28675..7cd647a4dbb 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java @@ -164,7 +164,7 @@ public class AnnotationParser String annotation, Listvalues); public void handleMethod (String className, String methodName, int access, - String params, String signature,String[] exceptions, + String desc, String signature,String[] exceptions, String annotation, Listvalues); public void handleField (String className, String fieldName, int access, @@ -180,7 +180,7 @@ public class AnnotationParser public interface MethodHandler { - public void handle (String className, String methodName, int access, String params, String signature,String[] exceptions); + public void handle (String className, String methodName, int access, String desc, String signature,String[] exceptions); } public interface FieldHandler @@ -325,7 +325,7 @@ public class AnnotationParser public MethodVisitor visitMethod (final int access, final String name, - final String params, + final String methodDesc, final String signature, final String[] exceptions) { @@ -343,7 +343,7 @@ public class AnnotationParser AnnotationHandler handler = AnnotationParser.this._annotationHandlers.get(_annotationName); if (handler != null) { - handler.handleMethod(_className, name, access, params, signature, exceptions, _annotationName, _annotationValues); + handler.handleMethod(_className, name, access, methodDesc, signature, exceptions, _annotationName, _annotationValues); } } }; diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PostConstructAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PostConstructAnnotationHandler.java index c3a7d934a31..01d0ae8ac7d 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PostConstructAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PostConstructAnnotationHandler.java @@ -13,25 +13,24 @@ package org.eclipse.jetty.annotations; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.List; import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler; import org.eclipse.jetty.annotations.AnnotationParser.Value; import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection; import org.eclipse.jetty.plus.annotation.PostConstructCallback; -import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.webapp.WebAppContext; public class PostConstructAnnotationHandler implements AnnotationHandler { protected WebAppContext _wac; + protected LifeCycleCallbackCollection _callbacks; public PostConstructAnnotationHandler (WebAppContext wac) { _wac = wac; + _callbacks = (LifeCycleCallbackCollection)_wac.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION); } @@ -47,35 +46,39 @@ public class PostConstructAnnotationHandler implements AnnotationHandler Log.warn("@PostConstruct annotation not applicable to fields: "+className+"."+fieldName); } - public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation, + public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation, List values) - { - - LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)_wac.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION); - Class clazz = null; + { try { - clazz = Loader.loadClass(null, className); - Method m = clazz.getDeclaredMethod(methodName, Util.convertTypes(params)); - - if (!Util.isServletType(m.getDeclaringClass())) + org.objectweb.asm.Type[] args = org.objectweb.asm.Type.getArgumentTypes(desc); + + if (args.length != 0) { - Log.debug("Ignoring "+m.getName()+" as non-servlet type"); + Log.warn("Skipping PostConstruct annotation on "+className+"."+methodName+": has parameters"); + return; + } + if (org.objectweb.asm.Type.getReturnType(desc) != org.objectweb.asm.Type.VOID_TYPE) + { + Log.warn("Skipping PostConstruct annotation on "+className+"."+methodName+": is not void"); + return; + } + + if (exceptions != null && exceptions.length != 0) + { + Log.warn("Skipping PostConstruct annotation on "+className+"."+methodName+": throws checked exceptions"); + return; + } + + if ((access & org.objectweb.asm.Opcodes.ACC_STATIC) > 0) + { + Log.warn("Skipping PostConstruct annotation on "+className+"."+methodName+": is static"); return; } - if (m.getParameterTypes().length != 0) - throw new IllegalStateException(m+" has parameters"); - if (m.getReturnType() != Void.TYPE) - throw new IllegalStateException(m+" is not void"); - if (m.getExceptionTypes().length != 0) - throw new IllegalStateException(m+" throws checked exceptions"); - if (Modifier.isStatic(m.getModifiers())) - throw new IllegalStateException(m+" is static"); PostConstructCallback callback = new PostConstructCallback(); - callback.setTargetClass(m.getDeclaringClass()); - callback.setTarget(m); - callbacks.add(callback); + callback.setTarget(className, methodName); + _callbacks.add(callback); } catch (Exception e) { diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PreDestroyAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PreDestroyAnnotationHandler.java index e75143f8902..4b1bd57e03d 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PreDestroyAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/PreDestroyAnnotationHandler.java @@ -13,25 +13,24 @@ package org.eclipse.jetty.annotations; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.List; import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler; import org.eclipse.jetty.annotations.AnnotationParser.Value; import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection; import org.eclipse.jetty.plus.annotation.PreDestroyCallback; -import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.webapp.WebAppContext; public class PreDestroyAnnotationHandler implements AnnotationHandler { WebAppContext _wac; + LifeCycleCallbackCollection _callbacks; public PreDestroyAnnotationHandler (WebAppContext wac) { _wac = wac; + _callbacks = (LifeCycleCallbackCollection)_wac.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION); } public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation, @@ -46,35 +45,39 @@ public class PreDestroyAnnotationHandler implements AnnotationHandler Log.warn("@PreDestroy annotation not applicable for fields: "+className+"."+fieldName); } - public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation, + public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation, List values) { - LifeCycleCallbackCollection callbacks = (LifeCycleCallbackCollection)_wac.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION); - - Class clazz = null; try { - clazz = Loader.loadClass(null, className); + org.objectweb.asm.Type[] args = org.objectweb.asm.Type.getArgumentTypes(desc); - Method m = clazz.getDeclaredMethod(methodName, Util.convertTypes(params)); - if (!Util.isServletType(m.getDeclaringClass())) + if (args.length != 0) { - Log.debug("Ignored "+m.getName()+" as non-servlet type"); + Log.warn("Skipping PreDestroy annotation on "+className+"."+methodName+": has parameters"); + return; + } + if (org.objectweb.asm.Type.getReturnType(desc) != org.objectweb.asm.Type.VOID_TYPE) + { + Log.warn("Skipping PreDestroy annotation on "+className+"."+methodName+": is not void"); + return; + } + + if (exceptions != null && exceptions.length != 0) + { + Log.warn("Skipping PreDestroy annotation on "+className+"."+methodName+": throws checked exceptions"); + return; + } + + if ((access & org.objectweb.asm.Opcodes.ACC_STATIC) > 0) + { + Log.warn("Skipping PreDestroy annotation on "+className+"."+methodName+": is static"); return; } - if (m.getParameterTypes().length != 0) - throw new IllegalStateException(m+" has parameters"); - if (m.getReturnType() != Void.TYPE) - throw new IllegalStateException(m+" is not void"); - if (m.getExceptionTypes().length != 0) - throw new IllegalStateException(m+" throws checked exceptions"); - if (Modifier.isStatic(m.getModifiers())) - throw new IllegalStateException(m+" is static"); PreDestroyCallback callback = new PreDestroyCallback(); - callback.setTargetClass(m.getDeclaringClass()); - callback.setTarget(m); - callbacks.add(callback); + callback.setTarget(className, methodName); + _callbacks.add(callback); } catch (Exception e) { diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourceAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourceAnnotationHandler.java index 47d0b130dc9..8e80112662c 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourceAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourceAnnotationHandler.java @@ -13,12 +13,8 @@ package org.eclipse.jetty.annotations; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.List; -import javax.annotation.Resource; import javax.naming.InitialContext; import javax.naming.NameNotFoundException; import javax.naming.NamingException; @@ -27,18 +23,18 @@ import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler; import org.eclipse.jetty.annotations.AnnotationParser.Value; import org.eclipse.jetty.plus.annotation.Injection; import org.eclipse.jetty.plus.annotation.InjectionCollection; -import org.eclipse.jetty.util.IntrospectionUtil; -import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.webapp.WebAppContext; public class ResourceAnnotationHandler implements AnnotationHandler { protected WebAppContext _wac; + protected InjectionCollection _injections; public ResourceAnnotationHandler (WebAppContext wac) { _wac = wac; + _injections = (InjectionCollection)_wac.getAttribute(InjectionCollection.INJECTION_COLLECTION); } @@ -50,37 +46,26 @@ public class ResourceAnnotationHandler implements AnnotationHandler public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation, List values) { - Class clazz = null; - try + String name = null; + String mappedName = null; + String resourceType = null; + if (values != null) { - clazz = Loader.loadClass(null, className); - } - catch (Exception e) - { - Log.warn(e); - } - if (!Util.isServletType(clazz)) - { - Log.debug("Ignoring @Resource annotation on on-servlet type class "+clazz.getName()); - return; - } - - //Handle Resource annotation - add namespace entries - Resource resource = (Resource)clazz.getAnnotation(Resource.class); - if (resource != null) - { - String name = resource.name(); - String mappedName = resource.mappedName(); - Resource.AuthenticationType auth = resource.authenticationType(); - Class type = resource.type(); - boolean shareable = resource.shareable(); + for (Value v : values) + { + if ("name".equals(v.getName())) + name = (String)v.getValue(); + else if ("mappedName".equals(v.getName())) + mappedName = (String)v.getValue(); + else if ("type".equals(v.getName())) + resourceType = (String)v.getValue(); + } if (name==null || name.trim().equals("")) throw new IllegalStateException ("Class level Resource annotations must contain a name (Common Annotations Spec Section 2.3)"); try { - //TODO don't ignore the shareable, auth etc etc if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name,mappedName)) if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name,mappedName)) throw new IllegalStateException("No resource at "+(mappedName==null?name:mappedName)); @@ -95,52 +80,46 @@ public class ResourceAnnotationHandler implements AnnotationHandler public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, List values) { - InjectionCollection injections = (InjectionCollection)_wac.getAttribute(InjectionCollection.INJECTION_COLLECTION); - Class clazz = null; try { - clazz = Loader.loadClass(null, className); - Field f = clazz.getDeclaredField(fieldName); - - if (!Util.isServletType(clazz)) + //JavaEE Spec 5.2.3: Field cannot be static + if ((access & org.objectweb.asm.Opcodes.ACC_STATIC) > 0) { - Log.debug("Ignoring @Resource annotation on on-servlet type field "+fieldName); + Log.warn("Skipping Resource annotation on "+className+"."+fieldName+": cannot be static"); return; } - Resource resource = (Resource)f.getAnnotation(Resource.class); - if (resource == null) - return; - - //JavaEE Spec 5.2.3: Field cannot be static - if (Modifier.isStatic(f.getModifiers())) - throw new IllegalStateException(f+" cannot be static"); //JavaEE Spec 5.2.3: Field cannot be final - if (Modifier.isFinal(f.getModifiers())) - throw new IllegalStateException(f+" cannot be final"); + if ((access & org.objectweb.asm.Opcodes.ACC_FINAL) > 0) + { + Log.warn("Skipping Resource annotation on "+className+"."+fieldName+": cannot be final"); + return; + } //work out default name - String name = f.getDeclaringClass().getCanonicalName()+"/"+f.getName(); - //allow @Resource name= to override the field name - name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name); - - //get the type of the Field - Class type = f.getType(); - //if @Resource specifies a type, check it is compatible with field type - if ((resource.type() != null) - && - !resource.type().equals(Object.class) - && - (!IntrospectionUtil.isTypeCompatible(type, resource.type(), false))) - throw new IllegalStateException("@Resource incompatible type="+resource.type()+ " with field type ="+f.getType()); - - //get the mappedName if there is one - String mappedName = (resource.mappedName()!=null && !resource.mappedName().trim().equals("")?resource.mappedName():null); - //get other parts that can be specified in @Resource - Resource.AuthenticationType auth = resource.authenticationType(); - boolean shareable = resource.shareable(); + String name = className+"/"+fieldName; + String mappedName = null; + org.objectweb.asm.Type resourceType = null; + if (values != null) + { + for (Value val :values) + { + //allow @Resource name= to override the field name + if (val.getName().equals("name") && !"".equals((String)val.getValue())) + name = (String)(val.getValue()); + //get the mappedName if there is one + else if (val.getName().equals("mappedName") && !"".equals((String)val.getValue())) + mappedName = (String)val.getValue(); + //save @Resource type, so we can check it is compatible with field type later + else if (val.getName().equals("type")) + { + resourceType = (org.objectweb.asm.Type)(val.getValue()); + } + } + } + //check if an injection has already been setup for this target by web.xml - Injection webXmlInjection = injections.getInjection(f.getDeclaringClass(), f); + Injection webXmlInjection = _injections.getInjection(name, className, fieldName); if (webXmlInjection == null) { try @@ -171,14 +150,15 @@ public class ResourceAnnotationHandler implements AnnotationHandler Log.debug("Bound "+(mappedName==null?name:mappedName) + " as "+ name); // Make the Injection for it if the binding succeeded Injection injection = new Injection(); - injection.setTargetClass(f.getDeclaringClass()); + injection.setTarget(className, fieldName, Util.asCanonicalName(resourceType)); injection.setJndiName(name); injection.setMappingName(mappedName); - injection.setTarget(f); - injections.add(injection); + _injections.add(injection); } - else if (!Util.isEnvEntryType(type)) + else if (!Util.isEnvEntryType(fieldType)) { + System.err.println(fieldType); + //if this is an env-entry type resource and there is no value bound for it, it isn't //an error, it just means that perhaps the code will use a default value instead // JavaEE Spec. sec 5.4.1.3 @@ -191,18 +171,10 @@ public class ResourceAnnotationHandler implements AnnotationHandler //if this is an env-entry type resource and there is no value bound for it, it isn't //an error, it just means that perhaps the code will use a default value instead // JavaEE Spec. sec 5.4.1.3 - if (!Util.isEnvEntryType(type)) + if (!Util.isEnvEntryType(fieldType)) throw new IllegalStateException(e); } } - else - { - //if an injection is already set up for this name, then the types must be compatible - //JavaEE spec sec 5.2.4 - Object val = webXmlInjection.lookupInjectedValue(); - if (!IntrospectionUtil.isTypeCompatible(type, value.getClass(), false)) - throw new IllegalStateException("Type of field="+type+" is not compatible with Resource type="+val.getClass()); - } } catch (Exception e) { @@ -217,23 +189,12 @@ public class ResourceAnnotationHandler implements AnnotationHandler * processed when an instance of the class is created. * @param injections */ - public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation, + public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation, List values) { - InjectionCollection injections = (InjectionCollection)_wac.getAttribute(InjectionCollection.INJECTION_COLLECTION); - Class clazz = null; try { - clazz = Loader.loadClass(null, className); - - Class[] args = Util.convertTypes(params); - Method m = clazz.getDeclaredMethod(methodName, args); - - if (!Util.isServletType(m.getDeclaringClass())) - { - Log.debug("Ignoring @Resource annotation on on-servlet type method "+m.getName()); - return; - } + /* * Commons Annotations Spec 2.3 * " The Resource annotation is used to declare a reference to a resource. @@ -251,44 +212,60 @@ public class ResourceAnnotationHandler implements AnnotationHandler * Which IMHO, put more succinctly means "If you find a @Resource on any method * or field, inject it!". */ - Resource resource = (Resource)m.getAnnotation(Resource.class); - if (resource == null) - return; - //JavaEE Spec 5.2.3: Method cannot be static - if (Modifier.isStatic(m.getModifiers())) - throw new IllegalStateException(m+" cannot be static"); + if ((access & org.objectweb.asm.Opcodes.ACC_STATIC) > 0) + { + Log.warn("Skipping Resource annotation on "+className+"."+methodName+": cannot be static"); + return; + } - - // Check it is a valid javabean - if (!IntrospectionUtil.isJavaBeanCompliantSetter(m)) - throw new IllegalStateException(m+" is not a java bean compliant setter method"); + // Check it is a valid javabean: must be void return type, the name must start with "set" and it must have + // only 1 parameter + if (!methodName.startsWith("set")) + { + Log.warn("Skipping Resource annotation on "+className+"."+methodName+": invalid java bean, does not start with 'set'"); + return; + } + org.objectweb.asm.Type[] args = org.objectweb.asm.Type.getArgumentTypes(desc); + if (args == null || args.length != 1) + { + Log.warn("Skipping Resource annotation on "+className+"."+methodName+": invalid java bean, not single argument to method"); + return; + } + org.objectweb.asm.Type retVal = org.objectweb.asm.Type.getReturnType(desc); + if (!org.objectweb.asm.Type.VOID_TYPE.equals(retVal)) + { + Log.warn("Skipping Resource annotation on "+className+"."+methodName+": invalid java bean, not void"); + return; + } + //default name is the javabean property name - String name = m.getName().substring(3); + String name = methodName.substring(3); name = name.substring(0,1).toLowerCase()+name.substring(1); - name = m.getDeclaringClass().getCanonicalName()+"/"+name; - //allow default name to be overridden - name = (resource.name()!=null && !resource.name().trim().equals("")? resource.name(): name); - //get the mappedName if there is one - String mappedName = (resource.mappedName()!=null && !resource.mappedName().trim().equals("")?resource.mappedName():null); - - Class type = m.getParameterTypes()[0]; - - //get other parts that can be specified in @Resource - Resource.AuthenticationType auth = resource.authenticationType(); - boolean shareable = resource.shareable(); - - //if @Resource specifies a type, check it is compatible with setter param - if ((resource.type() != null) - && - !resource.type().equals(Object.class) - && - (!IntrospectionUtil.isTypeCompatible(type, resource.type(), false))) - throw new IllegalStateException("@Resource incompatible type="+resource.type()+ " with method param="+type+ " for "+m); + name = className+"/"+name; + String mappedName = null; + org.objectweb.asm.Type resourceType = null; + if (values != null) + { + for (Value v : values) + { + //allow default name to be overridden + if ("name".equals(v.getName())) + name = (String)(v.getValue()); + //get the mappedName if there is one + else if ("mappedName".equals(v.getName()) && !"".equals((String)(v.getValue()))) + mappedName = (String)(v.getValue()); + else if ("type".equals(v.getName())) + { + resourceType = (org.objectweb.asm.Type)(v.getValue()); + } + //TODO: authentication and shareable + } + } //check if an injection has already been setup for this target by web.xml - Injection webXmlInjection = injections.getInjection(m.getDeclaringClass(), m); + Injection webXmlInjection = _injections.getInjection(name, className, methodName, Util.asCanonicalName(args[0])); if (webXmlInjection == null) { try @@ -327,13 +304,12 @@ public class ResourceAnnotationHandler implements AnnotationHandler Log.debug("Bound "+(mappedName==null?name:mappedName) + " as "+ name); // Make the Injection for it Injection injection = new Injection(); - injection.setTargetClass(m.getDeclaringClass()); + injection.setTarget(className, methodName, Util.asCanonicalName(args[0]), Util.asCanonicalName(resourceType)); injection.setJndiName(name); injection.setMappingName(mappedName); - injection.setTarget(m); - injections.add(injection); + _injections.add(injection); } - else if (!Util.isEnvEntryType(type)) + else if (!Util.isEnvEntryType(args[0].getDescriptor())) { //if this is an env-entry type resource and there is no value bound for it, it isn't @@ -347,19 +323,10 @@ public class ResourceAnnotationHandler implements AnnotationHandler //if this is an env-entry type resource and there is no value bound for it, it isn't //an error, it just means that perhaps the code will use a default value instead // JavaEE Spec. sec 5.4.1.3 - if (!Util.isEnvEntryType(type)) + if (!Util.isEnvEntryType(args[0].getDescriptor())) throw new IllegalStateException(e); } } - else - { - //if an injection is already set up for this name, then the types must be compatible - //JavaEE spec sec 5.2.4 - - Object value = webXmlInjection.lookupInjectedValue(); - if (!IntrospectionUtil.isTypeCompatible(type, value.getClass(), false)) - throw new IllegalStateException("Type of field="+type+" is not compatible with Resource type="+value.getClass()); - } } catch (Exception e) { diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourcesAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourcesAnnotationHandler.java index 575428fedff..0b7455449e4 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourcesAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ResourcesAnnotationHandler.java @@ -15,13 +15,11 @@ package org.eclipse.jetty.annotations; import java.util.List; -import javax.annotation.Resource; -import javax.annotation.Resources; import javax.naming.NamingException; import org.eclipse.jetty.annotations.AnnotationParser.AnnotationHandler; +import org.eclipse.jetty.annotations.AnnotationParser.ListValue; import org.eclipse.jetty.annotations.AnnotationParser.Value; -import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.webapp.WebAppContext; @@ -38,55 +36,43 @@ public class ResourcesAnnotationHandler implements AnnotationHandler public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation, List values) { - Class clazz = null; - try + if (values != null && values.size() == 1) { - clazz = Loader.loadClass(null,className); - } - catch (Exception e) - { - Log.warn(e); - return; - } - if (!Util.isServletType(clazz)) - { - Log.debug("@Resources annotation ignored on on-servlet type class "+clazz.getName()); - return; - } - //Handle Resources annotation - add namespace entries - Resources resources = (Resources)clazz.getAnnotation(Resources.class); - if (resources == null) - return; - - Resource[] resArray = resources.value(); - if (resArray==null||resArray.length==0) - return; - - for (int j=0;j list = (List)(values.get(0).getValue()); + for (ListValue resource : list) { - Log.warn ("@Resource annotations on classes must contain a name (Common Annotations Spec Section 2.3)"); - break; - } - try - { - //TODO don't ignore the shareable, auth etc etc - if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name, mappedName)) - if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name, mappedName)) - throw new IllegalStateException("No resource bound at "+(mappedName==null?name:mappedName)); - } - catch (NamingException e) - { - Log.warn(e); + List resourceValues = resource.getList(); + String name = null; + String mappedName = null; + for (Value v:resourceValues) + { + if ("name".equals(v.getName())) + name = (String)v.getValue(); + else if ("mappedName".equals(v.getName())) + mappedName = (String)v.getValue(); + } + if (name == null) + Log.warn ("Skipping Resources(Resource) annotation with no name on class "+className); + else + { + try + { + //TODO don't ignore the shareable, auth etc etc + if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac, name, mappedName)) + if (!org.eclipse.jetty.plus.jndi.NamingEntryUtil.bindToENC(_wac.getServer(), name, mappedName)) + Log.warn("Skipping Resources(Resource) annotation on "+className+" for name "+name+": No resource bound at "+(mappedName==null?name:mappedName)); + } + catch (NamingException e) + { + Log.warn(e); + } + } } } + else + { + Log.warn("Skipping empty or incorrect Resources annotation on "+className); + } } public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/RunAsAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/RunAsAnnotationHandler.java index 0df27141677..64502e98ada 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/RunAsAnnotationHandler.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/RunAsAnnotationHandler.java @@ -37,27 +37,22 @@ public class RunAsAnnotationHandler implements AnnotationHandler List values) { RunAsCollection runAsCollection = (RunAsCollection)_wac.getAttribute(RunAsCollection.RUNAS_COLLECTION); - Class clazz = null; + try { - clazz = Loader.loadClass(null, className); - if (!javax.servlet.Servlet.class.isAssignableFrom(clazz)) + if (values != null && values.size() == 1) { - Log.debug("@RunAs annotation ignored on on-servlet class "+clazz.getName()); - return; - } - RunAs runAs = (RunAs)clazz.getAnnotation(RunAs.class); - if (runAs != null) - { - String role = runAs.value(); + String role = (String)values.get(0).getValue(); if (role != null) { org.eclipse.jetty.plus.annotation.RunAs ra = new org.eclipse.jetty.plus.annotation.RunAs(); - ra.setTargetClass(clazz); + ra.setTargetClassName(className); ra.setRoleName(role); runAsCollection.add(ra); } } + else + Log.warn("Bad value for @RunAs annotation on class "+className); } catch (Exception e) { diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java index d3996913e43..c3bfbbb3657 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java @@ -17,6 +17,7 @@ import java.lang.reflect.Array; import java.util.List; import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.TypeUtil; import org.objectweb.asm.Type; /** @@ -26,9 +27,14 @@ import org.objectweb.asm.Type; */ public class Util { - private static Class[] __envEntryTypes = + private static Class[] __envEntryClassTypes = new Class[] {String.class, Character.class, Integer.class, Boolean.class, Double.class, Byte.class, Short.class, Long.class, Float.class}; + + private static String[] __envEntryTypes = + new String[] { Type.getDescriptor(String.class), Type.getDescriptor(Character.class), Type.getDescriptor(Integer.class), Type.getDescriptor(Boolean.class), + Type.getDescriptor(Double.class), Type.getDescriptor(Byte.class), Type.getDescriptor(Short.class), Type.getDescriptor(Long.class), Type.getDescriptor(Float.class)}; + /** * Check if the presented method belongs to a class that is one * of the classes with which a servlet container should be concerned. @@ -53,11 +59,21 @@ public class Util } public static boolean isEnvEntryType (Class type) + { + boolean result = false; + for (int i=0;i<__envEntryClassTypes.length && !result;i++) + { + result = (type.equals(__envEntryClassTypes[i])); + } + return result; + } + + public static boolean isEnvEntryType (String desc) { boolean result = false; for (int i=0;i<__envEntryTypes.length && !result;i++) { - result = (type.equals(__envEntryTypes[i])); + result = (desc.equals(__envEntryTypes[i])); } return result; } @@ -152,4 +168,59 @@ public class Util } + public static String asCanonicalName (Type t) + { + if (t == null) + return null; + + switch (t.getSort()) + { + case Type.BOOLEAN: + { + return TypeUtil.toName(Boolean.TYPE); + } + case Type.ARRAY: + { + return t.getElementType().getClassName(); + } + case Type.BYTE: + { + return TypeUtil.toName(Byte.TYPE); + } + case Type.CHAR: + { + return TypeUtil.toName(Character.TYPE); + } + case Type.DOUBLE: + { + return TypeUtil.toName(Double.TYPE); + } + case Type.FLOAT: + { + return TypeUtil.toName(Float.TYPE); + } + case Type.INT: + { + return TypeUtil.toName(Integer.TYPE); + } + case Type.LONG: + { + return TypeUtil.toName(Long.TYPE); + } + case Type.OBJECT: + { + return t.getClassName(); + } + case Type.SHORT: + { + return TypeUtil.toName(Short.TYPE); + } + case Type.VOID: + { + return null; + } + default: + return null; + } + } } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java index 8ddbab2592a..4d931f77034 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java @@ -17,6 +17,7 @@ import java.io.IOException; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; +import javax.annotation.Resources; import javax.annotation.security.RunAs; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -26,11 +27,14 @@ import javax.servlet.http.HttpServletResponse; - +@Resources({ + @Resource(name="apple", mappedName="foo"), + @Resource(name="banana", mappedName="foo") +}) @RunAs("admin") public class ServletC extends HttpServlet { - @Resource (mappedName="foo") + @Resource (mappedName="foo", type=Double.class) private Double foo; @PreDestroy diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java index 62cb0eae6fc..3a924426053 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java @@ -58,10 +58,25 @@ public class TestAnnotationParser extends TestCase } - public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation, + public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation, List values) { - assertEquals("org.eclipse.jetty.annotations.ClassA", className); + System.err.println("Sample annotated method : classname="+className+" methodName="+methodName+" access="+access+" desc="+desc+" signature="+signature); + + org.objectweb.asm.Type retType = org.objectweb.asm.Type.getReturnType(desc); + System.err.println("REturn type = "+retType); + org.objectweb.asm.Type[] params = org.objectweb.asm.Type.getArgumentTypes(desc); + if (params == null) + System.err.println("No params"); + else + System.err.println(params.length+" params"); + + if (exceptions == null) + System.err.println("No exceptions"); + else + System.err.println(exceptions.length+" exceptions"); + + assertEquals("org.eclipse.jetty.annotations.ClassA", className); assertTrue(methods.contains(methodName)); assertEquals("org.eclipse.jetty.annotations.Sample", annotation); } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java index 9bd076bea08..bed64136787 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java @@ -54,12 +54,23 @@ public class TestServletAnnotations extends TestCase assertNotNull (values); assertNotNull (annotation); assertTrue (annotation.endsWith("Resource")); - assertEquals (1, values.size()); - Value anv = values.get(0); - assertEquals ("mappedName", anv.getName()); - assertEquals ("foo", anv.getValue()); - System.err.print(annotation+": "); - System.err.println(anv); + + for (Value v :values) + { + if (v.getName().equals("mappedName")) + assertEquals ("foo", v.getValue()); + else if (v.getName().equals("type")) + { + try + { + assertEquals(fieldType, ((org.objectweb.asm.Type)v.getValue()).getDescriptor()); + } + catch (Exception e) + { + fail(e.getMessage()); + } + } + } } public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation, @@ -76,7 +87,7 @@ public class TestServletAnnotations extends TestCase List values) {} - public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation, + public void handleMethod(String className, String methodName, int access, String desc, String signature, String[] exceptions, String annotation, List values) { assertEquals ("org.eclipse.jetty.annotations.ServletC", className); @@ -91,8 +102,12 @@ public class TestServletAnnotations extends TestCase assertTrue(annotation.endsWith("PostConstruct")); assertTrue(values.isEmpty()); } - System.err.println(annotation+": "+methodName); - + + assertEquals (org.objectweb.asm.Type.VOID_TYPE, org.objectweb.asm.Type.getReturnType(desc)); + assertEquals(0, org.objectweb.asm.Type.getArgumentTypes(desc).length); + int isstatic = access & org.objectweb.asm.Opcodes.ACC_STATIC; + + assertTrue (isstatic == 0); } public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, List values) @@ -108,9 +123,7 @@ public class TestServletAnnotations extends TestCase assertEquals(1, values.size()); Value anv = values.get(0); assertEquals("value", anv.getName()); - assertEquals("admin", anv.getValue()); - System.err.print(annotation+": "); - System.err.println(anv); + assertEquals("admin", anv.getValue()); } public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation, @@ -121,9 +134,45 @@ public class TestServletAnnotations extends TestCase {} } + + class ResourcesAnnotationHandler implements AnnotationHandler + { + public void handleClass (String className, int version, int access, String signature, String superName, String[] interfaces, String annotation, + List values) + { + assertNotNull (values); + for (Value v : values) + { + List list = (List)(v.getValue()); + for (Object o : list) + { + AnnotationParser.ListValue lv = (AnnotationParser.ListValue)o; + List theValues = lv.getList(); + for (Value vv : theValues) + { + if ("name".equals((String)vv.getName())) + { + if (!"apple".equals((String)vv.getValue()) && !"banana".equals((String)vv.getValue())) + fail("Wrong name "+vv.getName()); + } + else if ("mappedName".equals((String)vv.getName())) + assertEquals("foo", (String)vv.getValue()); + + } + } + } + } + public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation, + List values) + {} + public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, + List values) + {} + } + - + parser.registerAnnotationHandler("javax.annotation.Resources", new ResourcesAnnotationHandler()); parser.registerAnnotationHandler("javax.annotation.Resource", new ResourceAnnotationHandler ()); parser.registerAnnotationHandler("javax.annotation.PostConstruct", new CallbackAnnotationHandler()); parser.registerAnnotationHandler("javax.annotation.PreDestroy", new CallbackAnnotationHandler()); diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/ResourceB.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/ResourceB.java index dbbb1ada70c..1f2bf1d7ed7 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/ResourceB.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/ResourceB.java @@ -21,8 +21,8 @@ import javax.annotation.Resources; * */ @Resources({ - @Resource(name="fluff", mappedName="resA"), - @Resource(name="stuff", mappedName="resB") + @Resource(name="peach", mappedName="resA"), + @Resource(name="pear", mappedName="resB") }) public class ResourceB extends ResourceA { diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/TestResourceAnnotations.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/TestResourceAnnotations.java index 1c707393244..956aebeb7d8 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/TestResourceAnnotations.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/resources/TestResourceAnnotations.java @@ -2,6 +2,7 @@ package org.eclipse.jetty.annotations.resources; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import javax.naming.Context; @@ -78,29 +79,32 @@ public class TestResourceAnnotations extends TestCase //we should have Injections assertNotNull(injections); - List fieldInjections = injections.getFieldInjections(ResourceB.class); - assertNotNull(fieldInjections); + List resBInjections = injections.getInjections(ResourceB.class.getCanonicalName()); + assertNotNull(resBInjections); //only 1 field injection because the other has no Resource mapping - assertEquals(1, fieldInjections.size()); + assertEquals(1, resBInjections.size()); + Injection fi = resBInjections.get(0); + assertEquals ("f", fi.getFieldName()); - Injection fi = fieldInjections.get(0); - assertEquals ("f", fi.getTarget().getName()); - - fieldInjections = injections.getFieldInjections(ResourceA.class); - assertNotNull(fieldInjections); - assertEquals(4, fieldInjections.size()); - - - //no method injections on class ResourceB - List methodInjections = injections.getMethodInjections(ResourceB.class); - assertNotNull(methodInjections); - assertEquals(0, methodInjections.size()); - - //3 method injections on class ResourceA - methodInjections = injections.getMethodInjections(ResourceA.class); - assertNotNull(methodInjections); - assertEquals(3, methodInjections.size()); + //3 method injections on class ResourceA, 4 field injections + List resAInjections = injections.getInjections(ResourceA.class.getCanonicalName()); + assertNotNull(resAInjections); + assertEquals(7, resAInjections.size()); + int fieldCount = 0; + int methodCount = 0; + Iterator itor = resAInjections.iterator(); + while (itor.hasNext()) + { + Injection x = itor.next(); + if (x.isField()) + fieldCount++; + else + methodCount++; + } + assertEquals(4, fieldCount); + assertEquals(3, methodCount); + //test injection ResourceB binst = new ResourceB(); @@ -166,8 +170,8 @@ public class TestResourceAnnotations extends TestCase } }); - assertEquals(resourceA.getObjectToBind(), env.lookup("fluff")); - assertEquals(resourceB.getObjectToBind(), env.lookup("stuff")); + assertEquals(resourceA.getObjectToBind(), env.lookup("peach")); + assertEquals(resourceB.getObjectToBind(), env.lookup("pear")); } } diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java index 34acce9d583..bab996a0647 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/Injection.java @@ -21,6 +21,8 @@ import javax.naming.InitialContext; import javax.naming.NamingException; import org.eclipse.jetty.util.IntrospectionUtil; +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; /** @@ -37,6 +39,11 @@ public class Injection private String _jndiName; private String _mappingName; private Member _target; + private String _className; + private String _fieldName; + private String _methodName; + private String _paramCanonicalName; + private String _annotationResourceType; public Injection () @@ -51,13 +58,35 @@ public class Injection return _targetClass; } - - /** - * @param name the _className to set - */ - public void setTargetClass(Class clazz) + + public String getTargetClassName() { - _targetClass = clazz; + return _className; + } + + public String getFieldName () + { + return _fieldName; + } + + public String getMethodName () + { + return _methodName; + } + + public String getParamCanonicalName () + { + return _paramCanonicalName; + } + + public boolean isField () + { + return (_fieldName != null); + } + + public boolean isMethod () + { + return (_methodName != null); } /** @@ -97,15 +126,28 @@ public class Injection return _target; } + + /** - * @param target the target to set + * Set up an injection target that is a field + * @param className + * @param fieldName */ - public void setTarget(Member target) + public void setTarget (String className, String fieldName, String annotationResourceType) { - this._target = target; + _className = className; + _fieldName = fieldName; + _annotationResourceType = annotationResourceType; } - - //TODO: define an equals method + + public void setTarget (String className, String methodName, String paramCanonicalName, String annotationResourceType) + { + _className = className; + _methodName = methodName; + _paramCanonicalName = paramCanonicalName; + _annotationResourceType = annotationResourceType; + } + public void setTarget (Class clazz, String targetName, Class targetType) { @@ -116,6 +158,9 @@ public class Injection Log.debug("Looking for method for setter: "+setter+" with arg "+targetType); _target = IntrospectionUtil.findMethod(clazz, setter, new Class[] {targetType}, true, false); _targetClass = clazz; + _className = clazz.getCanonicalName(); + _methodName = targetName; + _paramCanonicalName = targetType.getCanonicalName(); } catch (NoSuchMethodException me) { @@ -123,7 +168,9 @@ public class Injection try { _target = IntrospectionUtil.findField(clazz, targetName, targetType, true, false); - _targetClass = clazz; + _targetClass = clazz; + _className = clazz.getCanonicalName(); + _fieldName = targetName; } catch (NoSuchFieldException fe) { @@ -139,16 +186,29 @@ public class Injection * @throws Exception */ public void inject (Object injectable) - { - Member theTarget = getTarget(); - if (theTarget instanceof Field) + { + try { - injectField((Field)theTarget, injectable); + if (_target == null) + loadField(); + + if (_target == null) + loadMethod(); } - else if (theTarget instanceof Method) + catch (Exception e) { - injectMethod((Method)theTarget, injectable); + throw new IllegalStateException (e); } + + if (_target != null) + { + if (_target instanceof Field) + injectField((Field)_target, injectable); + else + injectMethod((Method)_target, injectable); + } + else + throw new IllegalStateException ("No method or field to inject with "+getJndiName()); } @@ -171,66 +231,135 @@ public class Injection * @param field * @param injectable */ - public void injectField (Field field, Object injectable) - { - try + protected void injectField (Field field, Object injectable) + { + if (validateInjection()) { - //validateInjection(field, injectable); - boolean accessibility = field.isAccessible(); - field.setAccessible(true); - field.set(injectable, lookupInjectedValue()); - field.setAccessible(accessibility); - } - catch (Exception e) - { - Log.warn(e); - throw new IllegalStateException("Inject failed for field "+field.getName()); + try + { + System.err.println("Value to inject="+lookupInjectedValue()); + boolean accessibility = field.isAccessible(); + field.setAccessible(true); + field.set(injectable, lookupInjectedValue()); + field.setAccessible(accessibility); + System.err.println("Injected field "+_fieldName+" of class "+_className); + } + catch (Exception e) + { + Log.warn(e); + throw new IllegalStateException("Inject failed for field "+field.getName()); + } } + else + throw new IllegalStateException ("Invalid injection for "+_className+"."+_fieldName); } - + /** * Inject value from jndi into a setter method of an instance * @param method * @param injectable */ - public void injectMethod (Method method, Object injectable) + protected void injectMethod (Method method, Object injectable) { - //validateInjection(method, injectable); - try + if (validateInjection()) { - boolean accessibility = method.isAccessible(); - method.setAccessible(true); - method.invoke(injectable, new Object[] {lookupInjectedValue()}); - method.setAccessible(accessibility); - } - catch (Exception e) - { - Log.warn(e); - throw new IllegalStateException("Inject failed for method "+method.getName()); + try + { + System.err.println("Value to inject="+lookupInjectedValue()); + boolean accessibility = method.isAccessible(); + method.setAccessible(true); + method.invoke(injectable, new Object[] {lookupInjectedValue()}); + method.setAccessible(accessibility); + System.err.println("Injected method "+_methodName+" of class "+_className); + } + catch (Exception e) + { + Log.warn(e); + throw new IllegalStateException("Inject failed for method "+method.getName()); + } } + else + throw new IllegalStateException("Invalid injection for "+_className+"."+_methodName); + } + + + + protected void loadField() + throws ClassNotFoundException, NoSuchFieldException + { + if (_fieldName == null || _className == null) + return; + + if (_targetClass == null) + _targetClass = Loader.loadClass(null, _className); + + _target = _targetClass.getDeclaredField(_fieldName); } - - - private void validateInjection (Method method, Object injectable) - throws NoSuchMethodException + /** + * Load the target class and method. + * A valid injection target method only has 1 argument. + * @throws ClassNotFoundException + * @throws NoSuchMethodException + */ + protected void loadMethod () + throws ClassNotFoundException, NoSuchMethodException { - if ((injectable==null) || (method==null)) + if (_methodName == null || _className == null) return; - //check the injection target actually has a matching method - //TODO: think about this, they have to be assignable - injectable.getClass().getMethod(method.getName(), method.getParameterTypes()); + + if (_targetClass == null) + _targetClass = Loader.loadClass(null, _className); + System.err.println("Loaded target class "+_targetClass.getName()); + + System.err.println("Looking for method "+_methodName +" with argument of type "+_paramCanonicalName+" on class "+_className); + Class arg = TypeUtil.fromName(_paramCanonicalName); + + if (arg == null) + arg = Loader.loadClass(null, _paramCanonicalName); + System.err.println("Loaded type: "+arg.getName()); + _target = _targetClass.getDeclaredMethod(_methodName, new Class[] {arg}); } - private void validateInjection (Field field, Object injectable) - throws NoSuchFieldException + + private boolean validateInjection () { - if ((field==null) || (injectable==null)) - return; + + //check that if the injection came from an annotation, the type specified in the annotation + //is compatible with the field or method to inject + //JavaEE spec sec 5.2.4 + if (_annotationResourceType != null) + { + System.err.println("Validating against annotationResourceType="+_annotationResourceType); + if (_target == null) + return false; + + try + { + Class annotationType = TypeUtil.fromName(_annotationResourceType); + if (annotationType == null) + annotationType = Loader.loadClass(null, _annotationResourceType); - Field f = injectable.getClass().getField(field.getName()); - if (!f.getType().isAssignableFrom(field.getType())) - throw new NoSuchFieldException("Mismatching type of field: "+f.getType().getName()+" v "+field.getType().getName()); - } + if (_target instanceof Field) + { + return ((Field)_target).getType().isAssignableFrom(annotationType); + } + else if (_target instanceof Method) + { + Class[] args = ((Method)_target).getParameterTypes(); + return args[0].isAssignableFrom(annotationType); + } + + return false; + } + catch (Exception e) + { + Log.warn("Unable to verify injection for "+_className+"."+ (_fieldName==null?_methodName:_fieldName)); + return false; + } + } + else + return true; + } } diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/InjectionCollection.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/InjectionCollection.java index 3c9dc0df763..439ba958679 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/InjectionCollection.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/InjectionCollection.java @@ -19,6 +19,7 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; @@ -32,87 +33,74 @@ import org.eclipse.jetty.util.log.Log; public class InjectionCollection { public static final String INJECTION_COLLECTION = "org.eclipse.jetty.injectionCollection"; - private HashMap, List> fieldInjectionsMap = new HashMap, List>();//map of classname to field injections - private HashMap, List> methodInjectionsMap = new HashMap, List>();//map of classname to method injections - + private HashMap> _injectionMap = new HashMap>();//map of classname to injections public void add (Injection injection) { - if ((injection==null) || (injection.getTarget()==null) || (injection.getTargetClass()==null)) + if ((injection==null) || injection.getTargetClassName()==null) return; if (Log.isDebugEnabled()) - Log.debug("Adding injection for class="+injection.getTargetClass()+ " on a "+injection.getTarget()); - Map, List> injectionsMap = null; - if (injection.getTarget() instanceof Field) - injectionsMap = fieldInjectionsMap; - if (injection.getTarget() instanceof Method) - injectionsMap = methodInjectionsMap; + Log.debug("Adding injection for class="+(injection.getTargetClassName()+ " on a "+(injection.isField()?injection.getFieldName():injection.getMethodName()))); + - List injections = (List)injectionsMap.get(injection.getTargetClass()); + List injections = (List)_injectionMap.get(injection.getTargetClassName()); if (injections==null) { injections = new ArrayList(); - injectionsMap.put(injection.getTargetClass(), injections); + _injectionMap.put(injection.getTargetClassName(), injections); } injections.add(injection); } - public List getFieldInjections (Class clazz) - { - if (clazz==null) - return null; - List list = (List)fieldInjectionsMap.get(clazz); - if (list == null) - list = Collections.emptyList(); - return list; - } - - public List getMethodInjections (Class clazz) - { - if (clazz==null) - return null; - List list = (List)methodInjectionsMap.get(clazz); - if (list == null) - list = Collections.emptyList(); - return list; - } - public List getInjections (Class clazz) + public List getInjections (String className) { - if (clazz==null) - return null; - - List results = new ArrayList (); - results.addAll(getFieldInjections(clazz)); - results.addAll(getMethodInjections(clazz)); - return results; - } - - public Injection getInjection (Class clazz, Member member) - { - if (clazz==null) - return null; - if (member==null) - return null; - Map, List> map = null; - if (member instanceof Field) - map = fieldInjectionsMap; - else if (member instanceof Method) - map = methodInjectionsMap; - - if (map==null) + if (className==null) return null; - List injections = (List)map.get(clazz); + return _injectionMap.get(className); + } + + + public Injection getInjection (String jndiName, String className, String fieldName) + { + if (fieldName == null || className == null) + return null; + + List injections = getInjections(className); + if (injections == null) + return null; + Iterator itor = injections.iterator(); Injection injection = null; - for (int i=0;injections!=null && i injections = getInjections(className); + if (injections == null) + return null; + Iterator itor = injections.iterator(); + Injection injection = null; + while (itor.hasNext() && injection == null) + { + Injection i = itor.next(); + if (methodName.equals(i.getMethodName()) && paramCanonicalName.equals(i.getParamCanonicalName())) + injection = i; + } + return injection; } @@ -127,21 +115,13 @@ public class InjectionCollection //looking at it's class hierarchy Class clazz = injectable.getClass(); - while (clazz != null) { - //Do field injections - List injections = getFieldInjections(clazz); - for (Injection i : injections) + List injections = _injectionMap.get(clazz.getCanonicalName()); + if (injections != null) { - i.inject(injectable); - } - - //Do method injections - injections = getMethodInjections(clazz); - for (Injection i : injections) - { - i.inject(injectable); + for (Injection i : injections) + i.inject(injectable); } clazz = clazz.getSuperclass(); diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallback.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallback.java index 5497fab03c0..1ac9876d8be 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallback.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallback.java @@ -17,6 +17,7 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.eclipse.jetty.util.IntrospectionUtil; +import org.eclipse.jetty.util.Loader; @@ -30,6 +31,8 @@ public abstract class LifeCycleCallback public static final Object[] __EMPTY_ARGS = new Object[] {}; private Method _target; private Class _targetClass; + private String _className; + private String _methodName; public LifeCycleCallback() @@ -44,16 +47,16 @@ public abstract class LifeCycleCallback { return _targetClass; } - - - /** - * @param name the class to set - */ - public void setTargetClass(Class clazz) + + public String getTargetClassName() { - _targetClass = clazz; + return _className; } + public String getMethodName() + { + return _methodName; + } /** * @return the target @@ -62,17 +65,13 @@ public abstract class LifeCycleCallback { return _target; } - - /** - * @param target the target to set - */ - public void setTarget(Method target) + + + public void setTarget (String className, String methodName) { - this._target = target; + _className = className; + _methodName = methodName; } - - - public void setTarget (Class clazz, String methodName) { @@ -82,6 +81,8 @@ public abstract class LifeCycleCallback validate(clazz, method); _target = method; _targetClass = clazz; + _className = clazz.getCanonicalName(); + _methodName = methodName; } catch (NoSuchMethodException e) { @@ -95,12 +96,20 @@ public abstract class LifeCycleCallback public void callback (Object instance) throws Exception { - if (getTarget() != null) + if (_target == null) + { + if (_targetClass == null) + _targetClass = Loader.loadClass(null, _className); + _target = _targetClass.getDeclaredMethod(_methodName, new Class[]{}); //TODO + } + + if (_target != null) { boolean accessibility = getTarget().isAccessible(); getTarget().setAccessible(true); getTarget().invoke(instance, __EMPTY_ARGS); getTarget().setAccessible(accessibility); + System.err.println("Calling callback on "+_className+"."+_methodName); } } diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallbackCollection.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallbackCollection.java index 35491656b99..89e370cb0cb 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallbackCollection.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/LifeCycleCallbackCollection.java @@ -29,8 +29,8 @@ import org.eclipse.jetty.util.log.Log; public class LifeCycleCallbackCollection { public static final String LIFECYCLE_CALLBACK_COLLECTION = "org.eclipse.jetty.lifecyleCallbackCollection"; - private HashMap postConstructCallbacksMap = new HashMap(); - private HashMap preDestroyCallbacksMap = new HashMap(); + private HashMap> postConstructCallbacksMap = new HashMap>(); + private HashMap> preDestroyCallbacksMap = new HashMap>(); @@ -43,12 +43,12 @@ public class LifeCycleCallbackCollection */ public void add (LifeCycleCallback callback) { - if ((callback==null) || (callback.getTargetClass()==null) || (callback.getTarget()==null)) + if ((callback==null) || (callback.getTargetClassName()==null)) return; if (Log.isDebugEnabled()) Log.debug("Adding callback for class="+callback.getTargetClass()+ " on "+callback.getTarget()); - Map map = null; + Map> map = null; if (callback instanceof PreDestroyCallback) map = preDestroyCallbacksMap; if (callback instanceof PostConstructCallback) @@ -56,13 +56,12 @@ public class LifeCycleCallbackCollection if (map == null) throw new IllegalArgumentException ("Unsupported lifecycle callback type: "+callback); - - List callbacks = (List)map.get(callback.getTargetClass()); + List callbacks = map.get(callback.getTargetClassName()); if (callbacks==null) { - callbacks = new ArrayList(); - map.put(callback.getTargetClass(), callbacks); + callbacks = new ArrayList(); + map.put(callback.getTargetClassName(), callbacks); } //don't add another callback for exactly the same method @@ -70,22 +69,22 @@ public class LifeCycleCallbackCollection callbacks.add(callback); } - public List getPreDestroyCallbacks (Object o) + public List getPreDestroyCallbacks (Object o) { if (o == null) return null; Class clazz = o.getClass(); - return (List)preDestroyCallbacksMap.get(clazz); + return preDestroyCallbacksMap.get(clazz.getName()); } - public List getPostConstructCallbacks (Object o) + public List getPostConstructCallbacks (Object o) { if (o == null) return null; Class clazz = o.getClass(); - return (List)postConstructCallbacksMap.get(clazz); + return postConstructCallbacksMap.get(clazz.getName()); } /** @@ -101,7 +100,7 @@ public class LifeCycleCallbackCollection return; Class clazz = o.getClass(); - List callbacks = (List)postConstructCallbacksMap.get(clazz); + List callbacks = postConstructCallbacksMap.get(clazz.getName()); if (callbacks == null) return; @@ -123,7 +122,7 @@ public class LifeCycleCallbackCollection return; Class clazz = o.getClass(); - List callbacks = (List)preDestroyCallbacksMap.get(clazz); + List callbacks = preDestroyCallbacksMap.get(clazz.getName()); if (callbacks == null) return; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAs.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAs.java index 70055bc8cf9..c619a7802eb 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAs.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAs.java @@ -25,21 +25,21 @@ import org.eclipse.jetty.servlet.ServletHolder; */ public class RunAs { - private Class _targetClass; + private String _className; private String _roleName; public RunAs() {} - public void setTargetClass (Class clazz) + public void setTargetClassName (String className) { - _targetClass=clazz; + _className = className; } - - public Class getTargetClass () + + public String getTargetClassName() { - return _targetClass; + return _className; } public void setRoleName (String roleName) @@ -58,16 +58,9 @@ public class RunAs { if (holder == null) return; - String className = getServletClassNameForHolder(holder); + String className = holder.getClassName(); - if (className.equals(_targetClass.getName())) + if (className.equals(_className)) holder.setRunAsRole(_roleName); } - - public static String getServletClassNameForHolder (ServletHolder holder) - throws ServletException - { - return holder.getClassName(); - } - } diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAsCollection.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAsCollection.java index 34e6c40dc60..9acb5afe285 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAsCollection.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/RunAsCollection.java @@ -35,12 +35,12 @@ public class RunAsCollection public void add (RunAs runAs) { - if ((runAs==null) || (runAs.getTargetClass()==null)) + if ((runAs==null) || (runAs.getTargetClassName()==null)) return; if (Log.isDebugEnabled()) - Log.debug("Adding run-as for class="+runAs.getTargetClass()); - _runAsMap.put(runAs.getTargetClass().getName(), runAs); + Log.debug("Adding run-as for class="+runAs.getTargetClassName()); + _runAsMap.put(runAs.getTargetClassName(), runAs); } public RunAs getRunAs (Object o) @@ -54,7 +54,7 @@ public class RunAsCollection ServletHolder holder = (ServletHolder)o; - String className = RunAs.getServletClassNameForHolder(holder); + String className = holder.getClassName(); return (RunAs)_runAsMap.get(className); } @@ -69,7 +69,7 @@ public class RunAsCollection ServletHolder holder = (ServletHolder)o; - String className = RunAs.getServletClassNameForHolder(holder); + String className = holder.getClassName(); RunAs runAs = (RunAs)_runAsMap.get(className); if (runAs == null) return; diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/AbstractConfiguration.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/AbstractConfiguration.java index 1b859f672b4..c98791c6025 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/AbstractConfiguration.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/webapp/AbstractConfiguration.java @@ -374,7 +374,6 @@ public abstract class AbstractConfiguration implements Configuration { Class clazz = _context.loadClass(targetClassName); Injection injection = new Injection(); - injection.setTargetClass(clazz); injection.setJndiName(jndiName); injection.setTarget(clazz, targetName, valueClass); injections.add(injection);