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.Container;
025: import org.jboss.injection.lang.reflect.BeanProperty;
026: import org.jboss.injection.lang.reflect.BeanPropertyFactory;
027: import org.jboss.injection.lang.reflect.FieldBeanProperty;
028: import org.jboss.injection.lang.reflect.MethodBeanProperty;
029: import org.jboss.logging.Logger;
030: import org.jboss.metamodel.descriptor.EnvEntry;
031: import org.jboss.metamodel.descriptor.EnvironmentRefGroup;
032: import org.jboss.metamodel.descriptor.MessageDestinationRef;
033: import org.jboss.metamodel.descriptor.ResourceEnvRef;
034: import org.jboss.metamodel.descriptor.ResourceRef; //import org.jboss.reflect.plugins.ValueConvertor;
035:
036: import javax.annotation.Resource;
037: import javax.annotation.Resources;
038: import javax.ejb.EJBContext;
039: import javax.ejb.EJBException;
040: import javax.ejb.TimerService;
041: import javax.transaction.UserTransaction;
042: import javax.xml.ws.WebServiceContext;
043:
044: import java.lang.reflect.AccessibleObject;
045: import java.lang.reflect.Field;
046: import java.lang.reflect.Method;
047: import java.util.Collection;
048: import java.util.Map;
049: import java.net.URL;
050: import java.net.MalformedURLException;
051:
052: /**
053: * @author <a href="mailto:bill@jboss.org">Bill Burke</a>
054: * @version $Revision: 63298 $
055: */
056: public class ResourceHandler implements InjectionHandler {
057: private static final Logger log = Logger
058: .getLogger(ResourceHandler.class);
059:
060: private static void loadEnvEntry(InjectionContainer container,
061: Collection<EnvEntry> envEntries) {
062: for (EnvEntry envEntry : envEntries) {
063: String encName = "env/" + envEntry.getEnvEntryName();
064: InjectionUtil.injectionTarget(encName, envEntry, container,
065: container.getEncInjections());
066: if (container.getEncInjectors().containsKey(encName))
067: continue;
068: log.trace("adding env-entry injector " + encName);
069: container.getEncInjectors().put(
070: encName,
071: new EnvEntryEncInjector(encName, envEntry
072: .getEnvEntryType(), envEntry
073: .getEnvEntryValue()));
074: }
075: }
076:
077: private static void loadXmlResourceRefs(
078: InjectionContainer container, Collection<ResourceRef> refs) {
079: for (ResourceRef envRef : refs) {
080: String encName = "env/" + envRef.getResRefName();
081: if (container.getEncInjectors().containsKey(encName))
082: continue;
083: if (envRef.getMappedName() == null
084: || envRef.getMappedName().equals("")) {
085: if (envRef.getResUrl() != null) {
086: try {
087: container.getEncInjectors().put(
088: encName,
089: new ValueEncInjector(encName, new URL(
090: envRef.getResUrl().trim()),
091: "<resource-ref>"));
092: } catch (MalformedURLException e) {
093: throw new RuntimeException(e);
094: }
095: } else {
096: throw new RuntimeException(
097: "mapped-name is required for "
098: + envRef.getResRefName()
099: + " of deployment "
100: + container.getIdentifier());
101: }
102: } else {
103: container.getEncInjectors().put(
104: encName,
105: new LinkRefEncInjector(encName, envRef
106: .getMappedName(), "<resource-ref>"));
107: }
108: InjectionUtil.injectionTarget(encName, envRef, container,
109: container.getEncInjections());
110: }
111: }
112:
113: private static void loadXmlResourceEnvRefs(
114: InjectionContainer container,
115: Collection<ResourceEnvRef> refs) {
116: for (ResourceEnvRef envRef : refs) {
117: // EJBTHREE-712
118: // TODO: refactor with handlePropertyAnnotation
119: String resTypeName = envRef.getResType();
120: try {
121: if (resTypeName != null) {
122: Class<?> resType = Class.forName(resTypeName);
123: if (EJBContext.class.isAssignableFrom(resType)) {
124: AccessibleObject ao = InjectionUtil
125: .findInjectionTarget(container
126: .getClassloader(), envRef
127: .getInjectionTarget());
128: container.getInjectors()
129: .add(
130: new EJBContextPropertyInjector(
131: BeanPropertyFactory
132: .create(ao)));
133: continue;
134: }
135: }
136: } catch (ClassNotFoundException e) {
137: throw new EJBException(e);
138: }
139:
140: String encName = "env/" + envRef.getResRefName();
141: if (container.getEncInjectors().containsKey(encName))
142: continue;
143: if (envRef.getMappedName() == null
144: || envRef.getMappedName().equals("")) {
145: throw new RuntimeException(
146: "mapped-name is required for "
147: + envRef.getResRefName()
148: + " of deployment "
149: + container.getIdentifier());
150: }
151: container.getEncInjectors().put(
152: encName,
153: new LinkRefEncInjector(encName, envRef
154: .getMappedName(), "<resource-ref>"));
155: InjectionUtil.injectionTarget(encName, envRef, container,
156: container.getEncInjections());
157: }
158: }
159:
160: private static void loadXmlMessageDestinationRefs(
161: InjectionContainer container,
162: Collection<MessageDestinationRef> refs) {
163: for (MessageDestinationRef envRef : refs) {
164: String encName = "env/"
165: + envRef.getMessageDestinationRefName();
166: if (container.getEncInjectors().containsKey(encName))
167: continue;
168: if (envRef.getMappedName() == null
169: || envRef.getMappedName().equals("")) {
170: // Look for a message-destination-link
171: String link = envRef.getMessageDestinationLink();
172: if (link != null) {
173: // TODO: Resolve the link...
174: }
175: throw new RuntimeException(
176: "mapped-name is required for "
177: + envRef.getMessageDestinationRefName()
178: + " of deployment "
179: + container.getIdentifier());
180: }
181: container.getEncInjectors().put(
182: encName,
183: new LinkRefEncInjector(encName, envRef
184: .getMappedName(),
185: "<message-destination-ref>"));
186: InjectionUtil.injectionTarget(encName, envRef, container,
187: container.getEncInjections());
188: }
189: }
190:
191: public void loadXml(EnvironmentRefGroup xml,
192: InjectionContainer container) {
193: if (xml == null)
194: return;
195: if (xml.getMessageDestinationRefs() != null)
196: loadXmlMessageDestinationRefs(container, xml
197: .getMessageDestinationRefs());
198: if (xml.getResourceEnvRefs() != null)
199: loadXmlResourceEnvRefs(container, xml.getResourceEnvRefs());
200: if (xml.getResourceRefs() != null)
201: loadXmlResourceRefs(container, xml.getResourceRefs());
202: if (xml.getEnvEntries() != null)
203: loadEnvEntry(container, xml.getEnvEntries());
204: }
205:
206: public void handleClassAnnotations(Class clazz,
207: InjectionContainer container) {
208: Resources resources = container.getAnnotation(Resources.class,
209: clazz);
210: if (resources != null) {
211: for (Resource ref : resources.value()) {
212: handleClassAnnotation(ref, container, clazz);
213: }
214: }
215: Resource res = container.getAnnotation(Resource.class, clazz);
216: if (res != null)
217: handleClassAnnotation(res, container, clazz);
218: }
219:
220: private void handleClassAnnotation(Resource ref,
221: InjectionContainer container, Class clazz) {
222: String encName = ref.name();
223: if (encName == null || encName.equals("")) {
224: throw new RuntimeException(
225: "JBoss requires name() for class level @Resource");
226: }
227: encName = "env/" + ref.name();
228: if (container.getEncInjectors().containsKey(encName))
229: return;
230:
231: String mappedName = ref.mappedName();
232: if (mappedName == null || mappedName.equals("")) {
233: throw new RuntimeException(
234: "You did not specify a @Resource.mappedName() for name: "
235: + ref.name()
236: + ", class: "
237: + clazz.getName()
238: + " and there is no binding for that enc name in XML");
239: }
240:
241: if (ref.type() == URL.class) {
242: // Create a URL from the mappedName
243: try {
244: URL url = new URL(ref.mappedName().trim());
245: container.getEncInjectors()
246: .put(
247: encName,
248: new ValueEncInjector(encName, url,
249: "@Resource"));
250: } catch (MalformedURLException e) {
251: throw new RuntimeException(e);
252: }
253: } else {
254: container.getEncInjectors().put(
255: encName,
256: new LinkRefEncInjector(encName, ref.mappedName(),
257: "@Resource"));
258: }
259: }
260:
261: public void handleMethodAnnotations(Method method,
262: InjectionContainer container,
263: Map<AccessibleObject, Injector> injectors) {
264: Resource ref = container.getAnnotation(Resource.class, method);
265: if (ref == null)
266: return;
267:
268: log.trace("method " + method + " has @Resource");
269:
270: handlePropertyAnnotation(ref, new MethodBeanProperty(method),
271: container, injectors);
272: /*
273: String encName = ref.name();
274: if (encName == null || encName.equals(""))
275: {
276: encName = InjectionUtil.getEncName(method);
277: }
278: else
279: {
280: encName = "env/" + encName;
281: }
282:
283: method.setAccessible(true);
284:
285: if (!method.getName().startsWith("set"))
286: throw new RuntimeException("@Resource can only be used with a set method: " + method);
287: if (method.getParameterTypes().length != 1)
288: throw new RuntimeException("@Resource can only be used with a set method of one parameter: " + method);
289:
290: Class type = method.getParameterTypes()[0];
291: if (!ref.type().equals(Object.class))
292: {
293: type = ref.type();
294: }
295: if (type.equals(UserTransaction.class))
296: {
297: injectors.put(method, new UserTransactionMethodInjector(method, container));
298: }
299: else if (type.equals(TimerService.class))
300: {
301: injectors.put(method, new TimerServiceMethodInjector(method, (Container) container)); // only EJBs
302: }
303: else if (EJBContext.class.isAssignableFrom(type))
304: {
305: injectors.put(method, new EJBContextMethodInjector(method));
306: }
307: else if (type.equals(WebServiceContext.class))
308: {
309: // FIXME: For now we skip it, and rely on the WS stack to perform the injection
310: }
311: else if (type.equals(String.class)
312: || type.equals(Character.class)
313: || type.equals(Byte.class)
314: || type.equals(Short.class)
315: || type.equals(Integer.class)
316: || type.equals(Long.class)
317: || type.equals(Boolean.class)
318: || type.equals(Double.class)
319: || type.equals(Float.class)
320: || type.isPrimitive()
321: )
322: {
323:
324: // don't add an injector if no XML <env-entry is present as there will be no value to inject
325: if (container.getEncInjectors().containsKey(encName))
326: {
327: injectors.put(method, new JndiMethodInjector(method, encName, container.getEnc()));
328: }
329: else if (ref.mappedName() != null && ref.mappedName().length() > 0)
330: {
331: // Use the mappedName as the string value
332: String s = ref.mappedName().trim();
333: try
334: {
335: Object value = ValueConvertor.convertValue(type, s);
336: container.getEncInjectors().put(encName, new ValueEncInjector(encName, value, "@Resource"));
337: injectors.put(method, new JndiMethodInjector(method, encName, container.getEnc()));
338: }
339: catch(Throwable t)
340: {
341: throw new RuntimeException("Failed to convert: "+ref.mappedName()+" to type:"+type, t);
342: }
343: }
344: }
345: else
346: {
347: if (!container.getEncInjectors().containsKey(encName))
348: {
349: String mappedName = ref.mappedName();
350: if (mappedName == null || mappedName.equals(""))
351: {
352: throw new RuntimeException("You did not specify a @Resource.mappedName() on " + method + " and there is no binding for that enc name in XML");
353: }
354: container.getEncInjectors().put(encName, new LinkRefEncInjector(encName, ref.mappedName(), "@Resource"));
355: }
356: injectors.put(method, new JndiMethodInjector(method, encName, container.getEnc()));
357: }
358: */
359: }
360:
361: public void handleFieldAnnotations(Field field,
362: InjectionContainer container,
363: Map<AccessibleObject, Injector> injectors) {
364: Resource ref = container.getAnnotation(Resource.class, field);
365: if (ref == null)
366: return;
367:
368: log.trace("field " + field + " has @Resource");
369:
370: handlePropertyAnnotation(ref, new FieldBeanProperty(field),
371: container, injectors);
372: /*
373: String encName = ref.name();
374: if (encName == null || encName.equals(""))
375: {
376: encName = InjectionUtil.getEncName(field);
377: }
378: else
379: {
380: encName = "env/" + encName;
381: }
382:
383: field.setAccessible(true);
384:
385: Class type = field.getType();
386: if (!ref.type().equals(Object.class))
387: {
388: type = ref.type();
389: }
390: if (type.equals(UserTransaction.class))
391: {
392: injectors.put(field, new UserTransactionFieldInjector(field, container));
393: }
394: else if (type.equals(TimerService.class))
395: {
396: injectors.put(field, new TimerServiceFieldInjector(field, (Container) container)); // only EJBs
397: }
398: else if (EJBContext.class.isAssignableFrom(type))
399: {
400: injectors.put(field, new EJBContextFieldInjector(field));
401: }
402: else if (type.equals(WebServiceContext.class))
403: {
404: // FIXME: For now we skip it, and rely on the WS stack to perform the injection
405: }
406: else if (type.equals(String.class)
407: || type.equals(Character.class)
408: || type.equals(Byte.class)
409: || type.equals(Short.class)
410: || type.equals(Integer.class)
411: || type.equals(Long.class)
412: || type.equals(Boolean.class)
413: || type.equals(Double.class)
414: || type.equals(Float.class)
415: || type.isPrimitive()
416: )
417: {
418: // don't add an injector if no XML <env-entry is present as there will be no value to inject
419: if (container.getEncInjectors().containsKey(encName))
420: {
421: injectors.put(field, new JndiFieldInjector(field, encName, container.getEnc()));
422: }
423: else if (ref.mappedName() != null && ref.mappedName().length() > 0)
424: {
425: // Use the mappedName as the string value
426: String s = ref.mappedName().trim();
427: try
428: {
429: Object value = ValueConvertor.convertValue(type, s);
430: container.getEncInjectors().put(encName, new ValueEncInjector(encName, value, "@Resource"));
431: injectors.put(field, new JndiFieldInjector(field, encName, container.getEnc()));
432: }
433: catch(Throwable t)
434: {
435: throw new RuntimeException("Failed to convert: "+ref.mappedName()+" to type:"+type, t);
436: }
437: }
438: else
439: {
440: log.warn("Not injecting " + field.getName() + ", no matching enc injector " + encName + " found");
441: }
442: }
443: else
444: {
445: if (!container.getEncInjectors().containsKey(encName))
446: {
447: String mappedName = ref.mappedName();
448: if (mappedName == null || mappedName.equals(""))
449: {
450: throw new RuntimeException("You did not specify a @Resource.mappedName() on " + field + " and there is no binding for enc name " + encName + " in XML");
451: }
452: container.getEncInjectors().put(encName, new LinkRefEncInjector(encName, ref.mappedName(), "@Resource"));
453: }
454: injectors.put(field, new JndiFieldInjector(field, encName, container.getEnc()));
455: }
456: */
457: }
458:
459: private void handlePropertyAnnotation(Resource ref,
460: BeanProperty property, InjectionContainer container,
461: Map<AccessibleObject, Injector> injectors) {
462: assert ref != null;
463: assert property != null;
464: assert container != null;
465: assert injectors != null;
466:
467: String encName = ref.name();
468: if (encName == null || encName.equals("")) {
469: //encName = InjectionUtil.getEncName(field);
470: encName = property.getDeclaringClass().getName() + "/"
471: + property.getName();
472: }
473: if (!encName.startsWith("env/")) {
474: encName = "env/" + encName;
475: }
476:
477: AccessibleObject accObj = property.getAccessibleObject();
478:
479: Class<?> type = property.getType();
480: if (!ref.type().equals(Object.class)) {
481: type = ref.type();
482: }
483: if (type.equals(UserTransaction.class)) {
484: injectors.put(accObj, new UserTransactionPropertyInjector(
485: property, container));
486: } else if (type.equals(TimerService.class)) {
487: injectors.put(accObj, new TimerServicePropertyInjector(
488: property, (Container) container)); // only EJBs
489: } else if (EJBContext.class.isAssignableFrom(type)) {
490: injectors.put(accObj, new EJBContextPropertyInjector(
491: property));
492: } else if (type.equals(WebServiceContext.class)) {
493: injectors.put(accObj,
494: new WebServiceContextPropertyInjector(property));
495: } else if (type.equals(String.class)
496: || type.equals(Character.class)
497: || type.equals(Byte.class) || type.equals(Short.class)
498: || type.equals(Integer.class)
499: || type.equals(Long.class)
500: || type.equals(Boolean.class)
501: || type.equals(Double.class)
502: || type.equals(Float.class) || type.isPrimitive()) {
503: // don't add an injector if no XML <env-entry is present as there will be no value to inject
504: if (container.getEncInjectors().containsKey(encName)) {
505: injectors.put(accObj, new JndiPropertyInjector(
506: property, encName, container.getEnc()));
507: } else if (ref.mappedName() != null
508: && ref.mappedName().length() > 0) {
509: // Use the mappedName as the string value
510: String s = ref.mappedName().trim();
511: try {
512: throw new RuntimeException("NYI");
513: // Object value = ValueConvertor.convertValue(type, s);
514: // container.getEncInjectors().put(encName, new ValueEncInjector(encName, value, "@Resource"));
515: // injectors.put(accObj, new JndiPropertyInjector(property, encName, container.getEnc()));
516: } catch (Throwable t) {
517: throw new RuntimeException("Failed to convert: "
518: + ref.mappedName() + " to type:" + type, t);
519: }
520: } else {
521: log.warn("Not injecting " + property.getName()
522: + ", no matching enc injector " + encName
523: + " found");
524: }
525: } else {
526: if (!container.getEncInjectors().containsKey(encName)) {
527: String mappedName = ref.mappedName();
528: if (mappedName == null || mappedName.equals("")) {
529: // TODO: is this a nice trick?
530: // if(ConnectionFactory.class.isAssignableFrom(type))
531: // {
532: // // neat little trick
533: // mappedName = "java:/ConnectionFactory";
534: // }
535: // else
536: throw new RuntimeException(
537: "You did not specify a @Resource.mappedName() on "
538: + accObj
539: + " and there is no binding for enc name "
540: + encName + " in XML");
541: }
542: container.getEncInjectors().put(
543: encName,
544: new LinkRefEncInjector(encName, ref
545: .mappedName(), "@Resource"));
546: }
547: injectors.put(accObj, new JndiPropertyInjector(property,
548: encName, container.getEnc()));
549: }
550: }
551: }
|