001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018 package org.apache.geronimo.j2ee.deployment.annotation; 019 020 import java.lang.reflect.Field; 021 import java.lang.reflect.Method; 022 import java.util.ArrayList; 023 import java.util.Arrays; 024 import java.util.List; 025 026 import javax.annotation.Resource; 027 import javax.annotation.Resources; 028 029 import org.apache.commons.logging.Log; 030 import org.apache.commons.logging.LogFactory; 031 import org.apache.geronimo.common.DeploymentException; 032 import org.apache.xbean.finder.ClassFinder; 033 034 035 /** 036 * Static helper class used to encapsulate all the functions related to the translation of 037 * <strong>@Resource</strong> and <strong>@Resources</strong> annotations to deployment descriptor 038 * tags. The ResourceAnnotationHelper class can be used as part of the deployment of a module into 039 * the Geronimo server. It performs the following major functions: 040 * <p/> 041 * <ol> 042 * <li>Translates annotations into corresponding deployment descriptor elements (so that the 043 * actual deployment descriptor in the module can be updated or even created if necessary) 044 * </ol> 045 * <p/> 046 * <p><strong>Note(s):</strong> 047 * <ul> 048 * <li>The user is responsible for invoking change to metadata-complete 049 * <li>This helper class will validate any changes it makes to the deployment descriptor. An 050 * exception will be thrown if it fails to parse 051 * </ul> 052 * <p/> 053 * <p><strong>Remaining ToDo(s):</strong> 054 * <ul> 055 * <li>Usage of mappedName 056 * </ul> 057 * 058 * @version $Rev: 525609 $ $Date: 2007-04-04 17:20:03 -0400 (Wed, 04 Apr 2007) $ 059 * @since 02-2007 060 */ 061 public final class ResourceAnnotationHelper extends AnnotationHelper { 062 063 // Private instance variables 064 private static final Log log = LogFactory.getLog(ResourceAnnotationHelper.class); 065 066 // Private constructor to prevent instantiation 067 private ResourceAnnotationHelper() { 068 } 069 070 /** 071 * Update the deployment descriptor from Resource and Resources annotations 072 * @throws Exception if parsing or validation error 073 */ 074 public static void processAnnotations(AnnotatedApp annotatedApp, ClassFinder classFinder, ResourceProcessor resourceProcessor) throws Exception { 075 if (annotatedApp != null) { 076 if (classFinder.isAnnotationPresent(Resources.class)) { 077 processResources(annotatedApp, classFinder, resourceProcessor); 078 } 079 if (classFinder.isAnnotationPresent(Resource.class)) { 080 processResource(annotatedApp, classFinder, resourceProcessor); 081 } 082 } 083 } 084 085 086 /** 087 * Process annotations 088 * 089 * @param annotatedApp 090 * @param classFinder 091 * @param resourceProcessor 092 * @throws Exception 093 */ 094 private static void processResource(AnnotatedApp annotatedApp, ClassFinder classFinder, ResourceProcessor resourceProcessor) throws Exception { 095 log.debug("processResource(): Entry: AnnotatedApp: " + annotatedApp.toString()); 096 097 List<Class> classeswithResource = classFinder.findAnnotatedClasses(Resource.class); 098 List<Method> methodswithResource = classFinder.findAnnotatedMethods(Resource.class); 099 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 String resourceName = annotation.name(); 180 if (resourceName.equals("")) { 181 if (method != null) { 182 StringBuilder stringBuilder = new StringBuilder(method.getName().substring(3)); 183 stringBuilder.setCharAt(0, Character.toLowerCase(stringBuilder.charAt(0))); 184 resourceName = method.getDeclaringClass().getName() + "/" + stringBuilder.toString(); 185 } else if (field != null) { 186 resourceName = field.getDeclaringClass().getName() + "/" + field.getName(); 187 } 188 } 189 return resourceName; 190 } 191 192 protected static String getResourceType(Resource annotation, Method method, Field field) { 193 //------------------------------------------------------------------------------------------ 194 // Resource type: 195 // -- When annotation is applied on a class: Type must be provided (cannot be inferred) 196 // -- When annotation is applied on a method: Type is the JavaBeans property type (or as 197 // provided on the annotation) 198 // -- When annotation is applied on a field: Type is the field type (or as provided on 199 // the annotation) 200 //------------------------------------------------------------------------------------------ 201 String resourceType = annotation.type().getCanonicalName(); 202 if (resourceType.equals("") || resourceType.equals(Object.class.getName())) { 203 if (method != null) { 204 resourceType = method.getParameterTypes()[0].getCanonicalName(); 205 } else if (field != null) { 206 resourceType = field.getType().getName(); 207 } 208 } 209 return resourceType; 210 } 211 } 212 213 }