001: package org.objectweb.celtix.common.injection;
002:
003: import java.lang.annotation.Annotation;
004: import java.lang.reflect.Field;
005: import java.lang.reflect.InvocationTargetException;
006: import java.lang.reflect.Method;
007: import java.util.Collection;
008: import java.util.LinkedList;
009: import java.util.List;
010: import java.util.logging.Level;
011: import java.util.logging.Logger;
012: import javax.annotation.PostConstruct;
013: import javax.annotation.Resource;
014: import javax.annotation.Resources;
015: import org.objectweb.celtix.common.annotation.AnnotationProcessor;
016: import org.objectweb.celtix.common.annotation.AnnotationVisitor;
017: import org.objectweb.celtix.common.logging.LogUtils;
018: import org.objectweb.celtix.resource.ResourceManager;
019:
020: /**
021: * injects references specified using @Resource annotation
022: *
023: */
024: public class ResourceInjector implements AnnotationVisitor {
025:
026: private static final Logger LOG = LogUtils
027: .getL7dLogger(ResourceInjector.class);
028:
029: private final ResourceManager resourceManager;
030: private Object target;
031:
032: public ResourceInjector(ResourceManager resMgr) {
033: resourceManager = resMgr;
034: }
035:
036: public void inject(Object o) {
037:
038: AnnotationProcessor processor = new AnnotationProcessor(o);
039: processor.accept(this );
040:
041: invokePostConstruct();
042: }
043:
044: // Implementation of org.objectweb.celtix.common.annotation.AnnotationVisitor
045:
046: public final void visitClass(final Class<?> clz,
047: final Annotation annotation) {
048:
049: assert annotation instanceof Resource
050: || annotation instanceof Resources : annotation;
051:
052: if (annotation instanceof Resource) {
053: injectResourceClassLevel(clz, (Resource) annotation);
054: } else if (annotation instanceof Resources) {
055: Resources resources = (Resources) annotation;
056: for (Resource resource : resources.value()) {
057: injectResourceClassLevel(clz, resource);
058: }
059: }
060:
061: }
062:
063: private void injectResourceClassLevel(Class<?> clz, Resource res) {
064: if (res.name() == null || "".equals(res.name())) {
065: LOG.log(Level.INFO, "RESOURCE_NAME_NOT_SPECIFIED", target
066: .getClass().getName());
067: return;
068: }
069:
070: Object resource = null;
071: // first find a setter that matches this resource
072: Method setter = findSetterForResource(res);
073: if (setter != null) {
074: Class<?> type = getResourceType(res, setter);
075: resource = resourceManager
076: .resolveResource(res.name(), type);
077: if (resource == null) {
078: LOG.log(Level.INFO, "RESOURCE_RESOLVE_FAILED");
079: return;
080: }
081:
082: invokeSetter(setter, resource);
083: return;
084: }
085:
086: Field field = findFieldForResource(res);
087: if (field != null) {
088: Class<?> type = getResourceType(res, field);
089: resource = resourceManager
090: .resolveResource(res.name(), type);
091: if (resource == null) {
092: LOG.log(Level.INFO, "RESOURCE_RESOLVE_FAILED");
093: return;
094: }
095: injectField(field, resource);
096: return;
097: }
098: LOG.log(Level.SEVERE, "NO_SETTER_OR_FIELD_FOR_RESOURCE",
099: getTarget().getClass().getName());
100: }
101:
102: public final List<Class<? extends Annotation>> getTargetAnnotations() {
103: List<Class<? extends Annotation>> al = new LinkedList<Class<? extends Annotation>>();
104: al.add(Resource.class);
105: al.add(Resources.class);
106: return al;
107: }
108:
109: public final void visitField(final Field field,
110: final Annotation annotation) {
111:
112: assert annotation instanceof Resource : annotation;
113:
114: Resource res = (Resource) annotation;
115:
116: String name = getFieldNameForResource(res, field);
117: Class<?> type = getResourceType(res, field);
118:
119: Object resource = resourceManager.resolveResource(name, type);
120: if (resource != null) {
121: injectField(field, resource);
122: } else {
123: LOG.log(Level.INFO, "RESOURCE_RESOLVE_FAILED", name);
124: }
125: }
126:
127: public final void visitMethod(final Method method,
128: final Annotation annotation) {
129:
130: assert annotation instanceof Resource : annotation;
131:
132: Resource res = (Resource) annotation;
133:
134: String resourceName = getResourceName(res, method);
135: Class<?> clz = getResourceType(res, method);
136:
137: Object resource = resourceManager.resolveResource(resourceName,
138: clz);
139: if (resource != null) {
140: invokeSetter(method, resource);
141: } else {
142: LOG.log(Level.INFO, "RESOURCE_RESOLVE_FAILED",
143: new Object[] { resourceName, clz });
144: }
145: }
146:
147: public final void setTarget(final Object object) {
148: target = object;
149: }
150:
151: public final Object getTarget() {
152: return target;
153: }
154:
155: private Field findFieldForResource(Resource res) {
156: assert target != null;
157: assert res.name() != null;
158:
159: for (Field field : target.getClass().getFields()) {
160: if (field.getName().equals(res.name())) {
161: return field;
162: }
163: }
164:
165: for (Field field : target.getClass().getDeclaredFields()) {
166: if (field.getName().equals(res.name())) {
167: return field;
168: }
169: }
170: return null;
171: }
172:
173: private Method findSetterForResource(Resource res) {
174: assert target != null;
175:
176: String setterName = resourceNameToSetter(res.name());
177: Method setterMethod = null;
178:
179: for (Method method : getTarget().getClass().getMethods()) {
180: if (setterName.equals(method.getName())) {
181: setterMethod = method;
182: break;
183: }
184: }
185:
186: if (setterMethod != null
187: && setterMethod.getParameterTypes().length != 1) {
188: LOG.log(Level.WARNING,
189: "SETTER_INJECTION_WITH_INCORRECT_TYPE",
190: setterMethod);
191: }
192: return setterMethod;
193: }
194:
195: private String resourceNameToSetter(String resName) {
196:
197: return "set" + Character.toUpperCase(resName.charAt(0))
198: + resName.substring(1);
199: }
200:
201: private void invokeSetter(Method method, Object resource) {
202: try {
203: method.invoke(getTarget(), resource);
204: } catch (IllegalAccessException e) {
205: LOG.log(Level.SEVERE, "INJECTION_SETTER_NOT_VISIBLE",
206: method);
207: } catch (InvocationTargetException e) {
208: LogUtils.log(LOG, Level.SEVERE,
209: "INJECTION_SETTER_RAISED_EXCEPTION", e, method);
210: }
211: }
212:
213: private String getResourceName(Resource res, Method method) {
214: assert method != null;
215: assert res != null;
216: assert method.getName().startsWith("set") : method;
217:
218: if (res.name() == null || "".equals(res.name())) {
219: String name = method.getName();
220: name = name.substring(3);
221: name = Character.toLowerCase(name.charAt(0))
222: + name.substring(1);
223: return name;
224: }
225: return res.name();
226: }
227:
228: private void injectField(Field field, Object resource) {
229: assert field != null;
230: assert resource != null;
231:
232: boolean accessible = field.isAccessible();
233: try {
234: if (field.getType().isAssignableFrom(resource.getClass())) {
235: field.setAccessible(true);
236: field.set(getTarget(), resource);
237: }
238: } catch (IllegalAccessException e) {
239: e.printStackTrace();
240: LOG.severe("FAILED_TO_INJECT_FIELD");
241: } finally {
242: field.setAccessible(accessible);
243: }
244: }
245:
246: private void invokePostConstruct() {
247:
248: boolean accessible = false;
249: for (Method method : getPostConstructMethods()) {
250: PostConstruct pc = method
251: .getAnnotation(PostConstruct.class);
252: if (pc != null) {
253: try {
254: method.setAccessible(true);
255: method.invoke(target);
256: } catch (IllegalAccessException e) {
257: LOG.log(Level.WARNING,
258: "INJECTION_COMPLETE_NOT_VISIBLE", method);
259: } catch (InvocationTargetException e) {
260: LOG.log(Level.WARNING,
261: "INJECTION_COMPLETE_THREW_EXCEPTION", e);
262: } finally {
263: method.setAccessible(accessible);
264: }
265: }
266: }
267: }
268:
269: private Collection<Method> getPostConstructMethods() {
270:
271: Collection<Method> methods = new LinkedList<Method>();
272: addPostConstructMethods(getTarget().getClass().getMethods(),
273: methods);
274: addPostConstructMethods(getTarget().getClass()
275: .getDeclaredMethods(), methods);
276: return methods;
277: }
278:
279: private void addPostConstructMethods(Method[] methods,
280: Collection<Method> postConstructMethods) {
281: for (Method method : methods) {
282: if (method.getAnnotation(PostConstruct.class) != null
283: && !postConstructMethods.contains(method)) {
284: postConstructMethods.add(method);
285: }
286: }
287: }
288:
289: /**
290: * making this protected to keep pmd happy
291: */
292: protected Class<?> getResourceType(Resource res, Field field) {
293: assert res != null;
294: Class type = res.type();
295: if (res.type() == null || Object.class == res.type()) {
296: type = field.getType();
297: }
298: return type;
299: }
300:
301: private Class<?> getResourceType(Resource res, Method method) {
302: return res.type() != null && !Object.class.equals(res.type()) ? res
303: .type()
304: : method.getParameterTypes()[0];
305: }
306:
307: private String getFieldNameForResource(Resource res, Field field) {
308: assert res != null;
309: if (res.name() == null || "".equals(res.name())) {
310: return field.getName();
311: }
312: return res.name();
313: }
314:
315: }
|