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: */package org.apache.geronimo.j2ee.deployment.annotation;
017:
018: import java.lang.reflect.Field;
019: import java.lang.reflect.Method;
020: import java.util.ArrayList;
021: import java.util.Arrays;
022: import java.util.List;
023:
024: import javax.annotation.Resource;
025: import javax.annotation.Resources;
026:
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029: import org.apache.geronimo.common.DeploymentException;
030: import org.apache.xbean.finder.ClassFinder;
031:
032: /**
033: * Static helper class used to encapsulate all the functions related to the translation of
034: * <strong>@Resource</strong> and <strong>@Resources</strong> annotations to deployment descriptor
035: * tags. The ResourceAnnotationHelper class can be used as part of the deployment of a module into
036: * the Geronimo server. It performs the following major functions:
037: * <p/>
038: * <ol>
039: * <li>Translates annotations into corresponding deployment descriptor elements (so that the
040: * actual deployment descriptor in the module can be updated or even created if necessary)
041: * </ol>
042: * <p/>
043: * <p><strong>Note(s):</strong>
044: * <ul>
045: * <li>The user is responsible for invoking change to metadata-complete
046: * <li>This helper class will validate any changes it makes to the deployment descriptor. An
047: * exception will be thrown if it fails to parse
048: * </ul>
049: * <p/>
050: * <p><strong>Remaining ToDo(s):</strong>
051: * <ul>
052: * <li>Usage of mappedName
053: * </ul>
054: *
055: * @version $Rev: 525609 $ $Date: 2007-04-04 14:20:03 -0700 (Wed, 04 Apr 2007) $
056: * @since 02-2007
057: */
058: public final class ResourceAnnotationHelper extends AnnotationHelper {
059:
060: // Private instance variables
061: private static final Log log = LogFactory
062: .getLog(ResourceAnnotationHelper.class);
063:
064: // Private constructor to prevent instantiation
065: private ResourceAnnotationHelper() {
066: }
067:
068: /**
069: * Update the deployment descriptor from Resource and Resources annotations
070: * @throws Exception if parsing or validation error
071: */
072: public static void processAnnotations(AnnotatedApp annotatedApp,
073: ClassFinder classFinder, ResourceProcessor resourceProcessor)
074: throws Exception {
075: if (annotatedApp != null) {
076: if (classFinder.isAnnotationPresent(Resources.class)) {
077: processResources(annotatedApp, classFinder,
078: resourceProcessor);
079: }
080: if (classFinder.isAnnotationPresent(Resource.class)) {
081: processResource(annotatedApp, classFinder,
082: resourceProcessor);
083: }
084: }
085: }
086:
087: /**
088: * Process annotations
089: *
090: * @param annotatedApp
091: * @param classFinder
092: * @param resourceProcessor
093: * @throws Exception
094: */
095: private static void processResource(AnnotatedApp annotatedApp,
096: ClassFinder classFinder, ResourceProcessor resourceProcessor)
097: throws Exception {
098: log.debug("processResource(): Entry: AnnotatedApp: "
099: + annotatedApp.toString());
100:
101: List<Class> classeswithResource = classFinder
102: .findAnnotatedClasses(Resource.class);
103: List<Method> methodswithResource = classFinder
104: .findAnnotatedMethods(Resource.class);
105: List<Field> fieldswithResource = classFinder
106: .findAnnotatedFields(Resource.class);
107:
108: // Class-level annotation
109: for (Class cls : classeswithResource) {
110: Resource resource = (Resource) cls
111: .getAnnotation(Resource.class);
112: if (resource != null) {
113: resourceProcessor.processResource(annotatedApp,
114: resource, cls, null, null);
115: }
116: }
117:
118: // Method-level annotation
119: for (Method method : methodswithResource) {
120: Resource resource = (Resource) method
121: .getAnnotation(Resource.class);
122: if (resource != null) {
123: resourceProcessor.processResource(annotatedApp,
124: resource, null, method, null);
125: }
126: }
127:
128: // Field-level annotation
129: for (Field field : fieldswithResource) {
130: Resource resource = (Resource) field
131: .getAnnotation(Resource.class);
132: if (resource != null) {
133: resourceProcessor.processResource(annotatedApp,
134: resource, null, null, field);
135: }
136: }
137:
138: // Validate deployment descriptor to ensure it's still okay
139: validateDD(annotatedApp);
140:
141: log.debug("processResource(): Exit: AnnotatedApp: "
142: + annotatedApp.toString());
143: }
144:
145: /**
146: * Process multiple annotations
147: *
148: * @param annotatedApp
149: * @param classFinder
150: * @param resourceProcessor
151: * @throws Exception
152: */
153: private static void processResources(AnnotatedApp annotatedApp,
154: ClassFinder classFinder, ResourceProcessor resourceProcessor)
155: throws Exception {
156: log.debug("processResources(): Entry");
157:
158: List<Class> classeswithResources = classFinder
159: .findAnnotatedClasses(Resources.class);
160:
161: // Class-level annotation(s)
162: List<Resource> resourceList = new ArrayList<Resource>();
163: for (Class cls : classeswithResources) {
164: Resources resources = (Resources) cls
165: .getAnnotation(Resources.class);
166: if (resources != null) {
167: resourceList.addAll(Arrays.asList(resources.value()));
168: }
169: for (Resource resource : resourceList) {
170: resourceProcessor.processResource(annotatedApp,
171: resource, cls, null, null);
172: }
173: resourceList.clear();
174: }
175:
176: log.debug("processResources(): Exit");
177: }
178:
179: public abstract static class ResourceProcessor extends
180: AnnotationHelper {
181:
182: public abstract boolean processResource(
183: AnnotatedApp annotatedApp, Resource annotation,
184: Class cls, Method method, Field field)
185: throws DeploymentException;
186:
187: /**
188: * Resource name:
189: * -- When annotation is applied on a class: Name must be provided (cannot be inferred)
190: * -- When annotation is applied on a method: Name is JavaBeans property name qualified
191: * by the class (or as provided on the annotation)
192: * -- When annotation is applied on a field: Name is the field name qualified by the
193: * class (or as provided on the annotation)
194: *
195: * @param annotation
196: * @param method
197: * @param field
198: * @return
199: */
200: protected static String getResourceName(Resource annotation,
201: Method method, Field field) {
202: String resourceName = annotation.name();
203: if (resourceName.equals("")) {
204: if (method != null) {
205: StringBuilder stringBuilder = new StringBuilder(
206: method.getName().substring(3));
207: stringBuilder.setCharAt(0, Character
208: .toLowerCase(stringBuilder.charAt(0)));
209: resourceName = method.getDeclaringClass().getName()
210: + "/" + stringBuilder.toString();
211: } else if (field != null) {
212: resourceName = field.getDeclaringClass().getName()
213: + "/" + field.getName();
214: }
215: }
216: return resourceName;
217: }
218:
219: protected static String getResourceType(Resource annotation,
220: Method method, Field field) {
221: //------------------------------------------------------------------------------------------
222: // Resource type:
223: // -- When annotation is applied on a class: Type must be provided (cannot be inferred)
224: // -- When annotation is applied on a method: Type is the JavaBeans property type (or as
225: // provided on the annotation)
226: // -- When annotation is applied on a field: Type is the field type (or as provided on
227: // the annotation)
228: //------------------------------------------------------------------------------------------
229: String resourceType = annotation.type().getCanonicalName();
230: if (resourceType.equals("")
231: || resourceType.equals(Object.class.getName())) {
232: if (method != null) {
233: resourceType = method.getParameterTypes()[0]
234: .getCanonicalName();
235: } else if (field != null) {
236: resourceType = field.getType().getName();
237: }
238: }
239: return resourceType;
240: }
241: }
242:
243: }
|