1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.apache.geronimo.j2ee.deployment.annotation; 19 20 import java.lang.reflect.Field; 21 import java.lang.reflect.Method; 22 import java.util.ArrayList; 23 import java.util.Arrays; 24 import java.util.List; 25 26 import javax.annotation.Resource; 27 import javax.annotation.Resources; 28 29 import org.slf4j.Logger; 30 import org.slf4j.LoggerFactory; 31 import org.apache.geronimo.common.DeploymentException; 32 import org.apache.xbean.finder.ClassFinder; 33 34 35 /** 36 * Static helper class used to encapsulate all the functions related to the translation of 37 * <strong>@Resource</strong> and <strong>@Resources</strong> annotations to deployment descriptor 38 * tags. The ResourceAnnotationHelper class can be used as part of the deployment of a module into 39 * the Geronimo server. It performs the following major functions: 40 * <p/> 41 * <ol> 42 * <li>Translates annotations into corresponding deployment descriptor elements (so that the 43 * actual deployment descriptor in the module can be updated or even created if necessary) 44 * </ol> 45 * <p/> 46 * <p><strong>Note(s):</strong> 47 * <ul> 48 * <li>The user is responsible for invoking change to metadata-complete 49 * <li>This helper class will validate any changes it makes to the deployment descriptor. An 50 * exception will be thrown if it fails to parse 51 * </ul> 52 * <p/> 53 * <p><strong>Remaining ToDo(s):</strong> 54 * <ul> 55 * <li>Usage of mappedName 56 * </ul> 57 * 58 * @version $Rev: 699352 $ $Date: 2008-09-26 08:00:10 -0700 (Fri, 26 Sep 2008) $ 59 * @since 02-2007 60 */ 61 public final class ResourceAnnotationHelper extends AnnotationHelper { 62 63 // Private instance variables 64 private static final Logger log = LoggerFactory.getLogger(ResourceAnnotationHelper.class); 65 66 // Private constructor to prevent instantiation 67 private ResourceAnnotationHelper() { 68 } 69 70 /** 71 * Update the deployment descriptor from Resource and Resources annotations 72 * @throws Exception if parsing or validation error 73 */ 74 public static void processAnnotations(AnnotatedApp annotatedApp, ClassFinder classFinder, ResourceProcessor resourceProcessor) throws Exception { 75 if (annotatedApp != null) { 76 if (classFinder.isAnnotationPresent(Resources.class)) { 77 processResources(annotatedApp, classFinder, resourceProcessor); 78 } 79 if (classFinder.isAnnotationPresent(Resource.class)) { 80 processResource(annotatedApp, classFinder, resourceProcessor); 81 } 82 } 83 } 84 85 86 /** 87 * Process annotations 88 * 89 * @param annotatedApp 90 * @param classFinder 91 * @param resourceProcessor 92 * @throws Exception 93 */ 94 private static void processResource(AnnotatedApp annotatedApp, ClassFinder classFinder, ResourceProcessor resourceProcessor) throws Exception { 95 log.debug("processResource(): Entry: AnnotatedApp: " + annotatedApp.toString()); 96 97 List<Class> classeswithResource = classFinder.findAnnotatedClasses(Resource.class); 98 List<Method> methodswithResource = classFinder.findAnnotatedMethods(Resource.class); 99 List<Field> fieldswithResource = classFinder.findAnnotatedFields(Resource.class); 100 101 // Class-level annotation 102 for (Class cls : classeswithResource) { 103 Resource resource = (Resource) cls.getAnnotation(Resource.class); 104 if (resource != null) { 105 resourceProcessor.processResource(annotatedApp, resource, cls, null, null); 106 } 107 } 108 109 // Method-level annotation 110 for (Method method : methodswithResource) { 111 Resource resource = (Resource) method.getAnnotation(Resource.class); 112 if (resource != null) { 113 resourceProcessor.processResource(annotatedApp, resource, null, method, null); 114 } 115 } 116 117 // Field-level annotation 118 for (Field field : fieldswithResource) { 119 Resource resource = (Resource) field.getAnnotation(Resource.class); 120 if (resource != null) { 121 resourceProcessor.processResource(annotatedApp, resource, null, null, field); 122 } 123 } 124 125 // Validate deployment descriptor to ensure it's still okay 126 validateDD(annotatedApp); 127 128 log.debug("processResource(): Exit: AnnotatedApp: " + annotatedApp.toString()); 129 } 130 131 132 /** 133 * Process multiple annotations 134 * 135 * @param annotatedApp 136 * @param classFinder 137 * @param resourceProcessor 138 * @throws Exception 139 */ 140 private static void processResources(AnnotatedApp annotatedApp, ClassFinder classFinder, ResourceProcessor resourceProcessor) throws Exception { 141 log.debug("processResources(): Entry"); 142 143 List<Class> classeswithResources = classFinder.findAnnotatedClasses(Resources.class); 144 145 // Class-level annotation(s) 146 List<Resource> resourceList = new ArrayList<Resource>(); 147 for (Class cls : classeswithResources) { 148 Resources resources = (Resources) cls.getAnnotation(Resources.class); 149 if (resources != null) { 150 resourceList.addAll(Arrays.asList(resources.value())); 151 } 152 for (Resource resource : resourceList) { 153 resourceProcessor.processResource(annotatedApp, resource, cls, null, null); 154 } 155 resourceList.clear(); 156 } 157 158 log.debug("processResources(): Exit"); 159 } 160 161 public abstract static class ResourceProcessor extends AnnotationHelper { 162 163 public abstract boolean processResource(AnnotatedApp annotatedApp, Resource annotation, Class cls, Method method, Field field) throws DeploymentException; 164 165 /** 166 * Resource name: 167 * -- When annotation is applied on a class: Name must be provided (cannot be inferred) 168 * -- When annotation is applied on a method: Name is JavaBeans property name qualified 169 * by the class (or as provided on the annotation) 170 * -- When annotation is applied on a field: Name is the field name qualified by the 171 * class (or as provided on the annotation) 172 * 173 * @param annotation 174 * @param method 175 * @param field 176 * @return 177 */ 178 protected static String getResourceName(Resource annotation, Method method, Field field) { 179 return getName(annotation.name(), method, field); 180 } 181 182 protected static String getResourceType(Resource annotation, Method method, Field field) { 183 //------------------------------------------------------------------------------------------ 184 // Resource type: 185 // -- When annotation is applied on a class: Type must be provided (cannot be inferred) 186 // -- When annotation is applied on a method: Type is the JavaBeans property type (or as 187 // provided on the annotation) 188 // -- When annotation is applied on a field: Type is the field type (or as provided on 189 // the annotation) 190 //------------------------------------------------------------------------------------------ 191 String resourceType = annotation.type().getCanonicalName(); 192 if (resourceType.equals("") || resourceType.equals(Object.class.getName())) { 193 if (method != null) { 194 resourceType = method.getParameterTypes()[0].getCanonicalName(); 195 } else if (field != null) { 196 resourceType = field.getType().getName(); 197 } 198 } 199 return resourceType; 200 } 201 } 202 203 }