001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.injection;
023:
024: import org.jboss.ejb3.EJBContainer;
025: import org.jboss.logging.Logger;
026: import org.jboss.metamodel.descriptor.InjectionTarget;
027: import org.jboss.metamodel.descriptor.Ref;
028:
029: import java.lang.reflect.AccessibleObject;
030: import java.lang.reflect.Field;
031: import java.lang.reflect.Method;
032: import java.lang.reflect.Modifier;
033: import java.util.Collection;
034: import java.util.HashMap;
035: import java.util.HashSet;
036: import java.util.Map;
037: import java.util.Set;
038:
039: /**
040: * Comment
041: *
042: * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
043: * @version $Revision: 60233 $
044: */
045: public class InjectionUtil {
046: private static final Logger log = Logger
047: .getLogger(InjectionUtil.class);
048:
049: /**
050: * This method will take a set of XML loaded injectors and collapse them based on spec inheritance rules
051: * It will remove injectors that should not be used in the injection of the base component class.
052: *
053: * @param visitedMethods
054: * @param clazz
055: * @param xmlDefinedInjectors
056: * @param classInjectors
057: */
058: public static void collapseXmlMethodInjectors(
059: Set<String> visitedMethods,
060: Class clazz,
061: Map<String, Map<AccessibleObject, Injector>> xmlDefinedInjectors,
062: Map<AccessibleObject, Injector> classInjectors) {
063: if (clazz == null || clazz.equals(Object.class)) {
064: return;
065: }
066: Map<AccessibleObject, Injector> xmlInjectors = xmlDefinedInjectors
067: .get(clazz.getName());
068: if (xmlInjectors != null) {
069: Method[] methods = clazz.getDeclaredMethods();
070: for (Method method : methods) {
071: if (method.getParameterTypes().length != 1)
072: continue;
073:
074: if (!Modifier.isPrivate(method.getModifiers())) {
075: if (visitedMethods.contains(method.getName())) {
076: xmlInjectors.remove(method); // if not private then it has been overriden
077: continue;
078: }
079: visitedMethods.add(method.getName());
080: }
081: }
082: classInjectors.putAll(xmlInjectors);
083: }
084: // recursion needs to come last as the method could be overriden and we don't want the overriding method to be ignored
085: collapseXmlMethodInjectors(visitedMethods, clazz
086: .getSuperclass(), xmlDefinedInjectors, classInjectors);
087: }
088:
089: public static void processMethodAnnotations(
090: InjectionContainer container,
091: Collection<InjectionHandler> handlers,
092: Set<String> visitedMethods, Class clazz,
093: Map<AccessibleObject, Injector> classInjectors) {
094: if (clazz == null || clazz.equals(Object.class)) {
095: return;
096: }
097: Method[] methods = clazz.getDeclaredMethods();
098: for (Method method : methods) {
099: if (method.getParameterTypes().length != 1)
100: continue;
101:
102: if (!Modifier.isPrivate(method.getModifiers())) {
103: if (visitedMethods.contains(method.getName())) {
104: continue;
105: }
106: visitedMethods.add(method.getName());
107: }
108:
109: if (handlers != null) {
110: for (InjectionHandler handler : handlers) {
111: handler.handleMethodAnnotations(method, container,
112: classInjectors);
113: }
114: }
115: }
116: // recursion needs to come last as the method could be overriden and we don't want the overriding method to be ignored
117: processMethodAnnotations(container, handlers, visitedMethods,
118: clazz.getSuperclass(), classInjectors);
119: }
120:
121: public static void processFieldAnnotations(
122: InjectionContainer container,
123: Collection<InjectionHandler> handlers, Class clazz,
124: Map<AccessibleObject, Injector> classInjectors) {
125: if (clazz == null || clazz.equals(Object.class)) {
126: return;
127: }
128:
129: if (handlers != null) {
130: Field[] fields = clazz.getDeclaredFields();
131: for (Field field : fields) {
132: log.trace("process field annotation for "
133: + field.toGenericString());
134: for (InjectionHandler handler : handlers) {
135: handler.handleFieldAnnotations(field, container,
136: classInjectors);
137: }
138: }
139: }
140:
141: // recursion needs to come last as the method could be overriden and we don't want the overriding method to be ignored
142: processFieldAnnotations(container, handlers, clazz
143: .getSuperclass(), classInjectors);
144: }
145:
146: public static void processClassAnnotations(
147: InjectionContainer container,
148: Collection<InjectionHandler> handlers, Class clazz) {
149: if (clazz == null || clazz.equals(Object.class)) {
150: return;
151: }
152:
153: if (handlers != null) {
154: for (InjectionHandler handler : handlers) {
155: handler.handleClassAnnotations(clazz, container);
156: }
157: }
158:
159: // recursion needs to come last as the method could be overriden and we don't want the overriding method to be ignored
160: processClassAnnotations(container, handlers, clazz
161: .getSuperclass());
162: }
163:
164: public static Map<AccessibleObject, Injector> processAnnotations(
165: InjectionContainer container,
166: Collection<InjectionHandler> handlers, Class clazz) {
167: Map<AccessibleObject, Injector> classInjectors = new HashMap<AccessibleObject, Injector>();
168: HashSet<String> visitedMethods = new HashSet<String>();
169: collapseXmlMethodInjectors(visitedMethods, clazz, container
170: .getEncInjections(), classInjectors);
171:
172: processClassAnnotations(container, handlers, clazz);
173: visitedMethods = new HashSet<String>();
174: processMethodAnnotations(container, handlers, visitedMethods,
175: clazz, classInjectors);
176: processFieldAnnotations(container, handlers, clazz,
177: classInjectors);
178: return classInjectors;
179: }
180:
181: public static AccessibleObject findInjectionTarget(
182: ClassLoader loader, InjectionTarget target) {
183: Class clazz = null;
184: try {
185: clazz = loader.loadClass(target.getTargetClass());
186: } catch (ClassNotFoundException e) {
187: throw new RuntimeException("<injection-target> class: "
188: + target.getTargetClass()
189: + " was not found nin deployment");
190: }
191:
192: for (Field field : clazz.getDeclaredFields()) {
193: if (target.getTargetName().equals(field.getName()))
194: return field;
195: }
196:
197: for (java.lang.reflect.Method method : clazz
198: .getDeclaredMethods()) {
199: if (method.getName().equals(target.getTargetName()))
200: return method;
201: }
202:
203: throw new RuntimeException(
204: "<injection-target> could not be found: "
205: + target.getTargetClass() + "."
206: + target.getTargetName());
207:
208: }
209:
210: public static String getEncName(Class type) {
211: return "env/" + type.getName();
212: }
213:
214: public static String getEncName(Method method) {
215: String encName = method.getName().substring(3);
216: if (encName.length() > 1) {
217: encName = encName.substring(0, 1).toLowerCase()
218: + encName.substring(1);
219: } else {
220: encName = encName.toLowerCase();
221: }
222:
223: encName = getEncName(method.getDeclaringClass()) + "/"
224: + encName;
225: return encName;
226: }
227:
228: public static String getEncName(Field field) {
229: return getEncName(field.getDeclaringClass()) + "/"
230: + field.getName();
231: }
232:
233: public static Object getAnnotation(Class annotation,
234: EJBContainer container, Class annotatedClass,
235: boolean isContainer) {
236: if (isContainer) {
237: return container.resolveAnnotation(annotation);
238: } else {
239: return annotatedClass.getAnnotation(annotation);
240: }
241: }
242:
243: public static Object getAnnotation(Class annotation,
244: EJBContainer container, Method method, boolean isContainer) {
245: if (isContainer) {
246: return container.resolveAnnotation(method, annotation);
247: } else {
248: return method.getAnnotation(annotation);
249: }
250: }
251:
252: public static Object getAnnotation(Class annotation,
253: EJBContainer container, Field field, boolean isContainer) {
254: if (isContainer) {
255: return container.resolveAnnotation(field, annotation);
256: } else {
257: return field.getAnnotation(annotation);
258: }
259: }
260:
261: public static Class injectionTarget(String encName, Ref ref,
262: InjectionContainer container,
263: Map<String, Map<AccessibleObject, Injector>> classInjectors) {
264: if (ref.getInjectionTarget() != null) {
265: Class injectionType;
266: // todo, get injection target class
267: AccessibleObject ao = findInjectionTarget(container
268: .getClassloader(), ref.getInjectionTarget());
269: Map<AccessibleObject, Injector> injectors = classInjectors
270: .get(ref.getInjectionTarget().getTargetClass());
271: if (injectors == null) {
272: injectors = new HashMap<AccessibleObject, Injector>();
273: classInjectors.put(ref.getInjectionTarget()
274: .getTargetClass().trim(), injectors);
275: }
276: if (ao instanceof Field) {
277: injectionType = ((Field) ao).getType();
278: injectors.put(ao, new JndiFieldInjector((Field) ao,
279: encName, container.getEnc()));
280: } else {
281: injectionType = ((Method) ao).getParameterTypes()[0];
282: injectors.put(ao, new JndiMethodInjector((Method) ao,
283: encName, container.getEnc()));
284: }
285: return injectionType;
286: } else {
287: return null;
288: }
289:
290: }
291: }
|