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: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
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 }