0001: /**
0002: * EasyBeans
0003: * Copyright (C) 2006-2007 Bull S.A.S.
0004: * Contact: easybeans@ow2.org
0005: *
0006: * This library is free software; you can redistribute it and/or
0007: * modify it under the terms of the GNU Lesser General Public
0008: * License as published by the Free Software Foundation; either
0009: * version 2.1 of the License, or any later version.
0010: *
0011: * This library is distributed in the hope that it will be useful,
0012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * Lesser General Public License for more details.
0015: *
0016: * You should have received a copy of the GNU Lesser General Public
0017: * License along with this library; if not, write to the Free Software
0018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
0019: * USA
0020: *
0021: * --------------------------------------------------------------------------
0022: * $Id: InjectionClassAdapter.java 2057 2007-11-21 15:35:32Z benoitf $
0023: * --------------------------------------------------------------------------
0024: */package org.ow2.easybeans.enhancer.injection;
0025:
0026: import static org.ow2.easybeans.injection.JNDILookupHelper.JndiType.JAVA_COMP;
0027: import static org.ow2.easybeans.injection.JNDILookupHelper.JndiType.JAVA_COMP_ENV;
0028: import static org.ow2.easybeans.injection.JNDILookupHelper.JndiType.REGISTRY;
0029:
0030: import java.net.URL;
0031: import java.util.ArrayList;
0032: import java.util.Arrays;
0033: import java.util.List;
0034: import java.util.Map;
0035:
0036: import javax.ejb.EJBContext;
0037: import javax.ejb.MessageDrivenContext;
0038: import javax.ejb.SessionContext;
0039: import javax.ejb.TimerService;
0040: import javax.jms.ConnectionFactory;
0041: import javax.jms.Queue;
0042: import javax.jms.QueueConnectionFactory;
0043: import javax.jms.Topic;
0044: import javax.jms.TopicConnectionFactory;
0045: import javax.mail.Session;
0046: import javax.mail.internet.MimePartDataSource;
0047: import javax.persistence.EntityManager;
0048: import javax.persistence.EntityManagerFactory;
0049: import javax.sql.DataSource;
0050: import javax.transaction.UserTransaction;
0051:
0052: import org.ow2.easybeans.asm.ClassAdapter;
0053: import org.ow2.easybeans.asm.ClassVisitor;
0054: import org.ow2.easybeans.asm.MethodVisitor;
0055: import org.ow2.easybeans.asm.Opcodes;
0056: import org.ow2.easybeans.asm.Type;
0057: import org.omg.CORBA.ORB;
0058: import org.ow2.easybeans.api.Factory;
0059: import org.ow2.easybeans.api.container.EZBEJBContext;
0060: import org.ow2.easybeans.api.container.EZBMDBContext;
0061: import org.ow2.easybeans.api.container.EZBSessionContext;
0062: import org.ow2.easybeans.deployment.annotations.JMethod;
0063: import org.ow2.easybeans.deployment.annotations.impl.JAnnotationResource;
0064: import org.ow2.easybeans.deployment.annotations.impl.JEjbEJB;
0065: import org.ow2.easybeans.deployment.annotations.impl.JavaxPersistenceContext;
0066: import org.ow2.easybeans.deployment.annotations.impl.JavaxPersistenceUnit;
0067: import org.ow2.easybeans.deployment.annotations.metadata.ClassAnnotationMetadata;
0068: import org.ow2.easybeans.deployment.annotations.metadata.EjbJarAnnotationMetadata;
0069: import org.ow2.easybeans.deployment.annotations.metadata.FieldAnnotationMetadata;
0070: import org.ow2.easybeans.deployment.annotations.metadata.MethodAnnotationMetadata;
0071: import org.ow2.easybeans.deployment.resolver.JNDIResolver;
0072: import org.ow2.easybeans.enhancer.CommonClassGenerator;
0073: import org.ow2.easybeans.enhancer.interceptors.EasyBeansInvocationContextGenerator;
0074: import org.ow2.easybeans.enhancer.lib.MethodRenamer;
0075: import org.ow2.easybeans.injection.JNDILookupHelper.JndiType;
0076: import org.ow2.util.log.Log;
0077: import org.ow2.util.log.LogFactory;
0078:
0079: /**
0080: * This class adds methods which will inject resources in the bean class.
0081: * @author Florent Benoit
0082: */
0083: public class InjectionClassAdapter extends ClassAdapter implements
0084: Opcodes {
0085:
0086: /**
0087: * Logger.
0088: */
0089: private static Log logger = LogFactory
0090: .getLog(InjectionClassAdapter.class);
0091:
0092: /**
0093: * Metadata available by this adapter for a class.
0094: */
0095: private ClassAnnotationMetadata classAnnotationMetadata;
0096:
0097: /**
0098: * Map containing informations for enhancers.
0099: */
0100: private Map<String, Object> map = null;
0101:
0102: /**
0103: * Is that generated method is static (client case).
0104: */
0105: private boolean staticMode = false;
0106:
0107: /**
0108: * javax.ejb.EJBContext interface.
0109: */
0110: private static final String EJBCONTEXT = EJBContext.class.getName();
0111:
0112: /**
0113: * javax.ejb.SessionContext interface.
0114: */
0115: private static final String SESSION_CONTEXT = SessionContext.class
0116: .getName();
0117:
0118: /**
0119: * javax.ejb.MessageDrivenContext interface.
0120: */
0121: private static final String MESSAGEDRIVEN_CONTEXT = MessageDrivenContext.class
0122: .getName();
0123:
0124: /**
0125: * org.omg.CORBA.ORB interface.
0126: */
0127: private static final String ORB_ITF = ORB.class.getName();
0128:
0129: /**
0130: * javax.sql.DataSource interface.
0131: */
0132: private static final String DATASOURCE_ITF = DataSource.class
0133: .getName();
0134:
0135: /**
0136: * javax.transaction.UserTransaction interface.
0137: */
0138: private static final String USERTRANSACTION_ITF = UserTransaction.class
0139: .getName();
0140:
0141: /**
0142: * javax.jms.Queue interface.
0143: */
0144: private static final String QUEUE_ITF = Queue.class.getName();
0145:
0146: /**
0147: * javax.jms.QueueConnectionFactory interface.
0148: */
0149: private static final String QUEUECONNECTIONFACTORY_ITF = QueueConnectionFactory.class
0150: .getName();
0151:
0152: /**
0153: * javax.jms.ConnectionFactory interface.
0154: */
0155: private static final String CONNECTIONFACTORY_ITF = ConnectionFactory.class
0156: .getName();
0157:
0158: /**
0159: * javax.mail.MailSession interface.
0160: */
0161: private static final String MAILSESSION_ITF = Session.class
0162: .getName();
0163:
0164: /**
0165: * javax.mail.internet.MimePartDataSource interface.
0166: */
0167: private static final String MIMEPARTDATASOURCE_ITF = MimePartDataSource.class
0168: .getName();
0169:
0170: /**
0171: * javax.jms.Topic interface.
0172: */
0173: private static final String TOPIC_ITF = Topic.class.getName();
0174:
0175: /**
0176: * java.net.URL interface.
0177: */
0178: private static final String URL_ITF = URL.class.getName();
0179:
0180: /**
0181: * javax.jms.TopicConnectionFactory interface.
0182: */
0183: private static final String TOPICCONNECTIONFACTORY_ITF = TopicConnectionFactory.class
0184: .getName();
0185:
0186: /**
0187: * Entity Manager interface.
0188: */
0189: private static final String ENTITYMANAGER_ITF = EntityManager.class
0190: .getName();
0191:
0192: /**
0193: * Entity Manager Factory interface.
0194: */
0195: private static final String ENTITYMANAGERFACTORY_ITF = EntityManagerFactory.class
0196: .getName();
0197:
0198: /**
0199: * javax.ejb.TimerService interface.
0200: */
0201: private static final String TIMERSERVICE_ITF = TimerService.class
0202: .getName();
0203:
0204: /**
0205: * EZBEJBContext type descriptor.
0206: */
0207: private static final String EZB_EJBCONTEXT_DESC = Type
0208: .getDescriptor(EZBEJBContext.class);
0209:
0210: /**
0211: * Defines java.lang.Object class.
0212: */
0213: public static final String JAVA_LANG_OBJECT = "java/lang/Object";
0214:
0215: /**
0216: * Injected method name.
0217: */
0218: public static final String INJECTED_METHOD = "injectedByEasyBeans";
0219:
0220: /**
0221: * JMethod object for injectedByEasyBeans.
0222: */
0223: public static final JMethod INJECTED_JMETHOD = new JMethod(
0224: ACC_PUBLIC,
0225: MethodRenamer.encode(INJECTED_METHOD),
0226: "()V",
0227: null,
0228: new String[] { "org/ow2/easybeans/api/injection/EasyBeansInjectionException" });
0229:
0230: /**
0231: * List of injected methods.
0232: */
0233: public static final String[] INJECTED_METHODS = new String[] {
0234: "getEasyBeansContext", "setEasyBeansContext",
0235: "getEasyBeansFactory", "setEasyBeansFactory" };
0236:
0237: /**
0238: * Replace length to create default JNDI names.
0239: */
0240: private static final int LENGTH = 3;
0241:
0242: /**
0243: * Constructor.
0244: * @param classAnnotationMetadata object containing all attributes of the
0245: * class
0246: * @param cv the class visitor to which this adapter must delegate calls.
0247: * @param map a map allowing to give some objects to the adapter.
0248: * @param staticMode - Is that generated method is static (client case).
0249: */
0250: public InjectionClassAdapter(
0251: final ClassAnnotationMetadata classAnnotationMetadata,
0252: final ClassVisitor cv, final Map<String, Object> map,
0253: final boolean staticMode) {
0254: super (cv);
0255: this .classAnnotationMetadata = classAnnotationMetadata;
0256: this .map = map;
0257: this .staticMode = staticMode;
0258: }
0259:
0260: /**
0261: * Visits the end of the class. This method, which is the last one to be
0262: * called, is used to inform the visitor that all the fields and methods of
0263: * the class have been visited.
0264: */
0265: @Override
0266: public void visitEnd() {
0267: super .visitEnd();
0268:
0269: // now, adds the injected method
0270: addInjectedMethod();
0271:
0272: // Adds methods if it's not a bean (as it should have been already added by the bean class adapter).
0273: // If it's a super class of a bean, as the class that will be instantiated
0274: // is the bean's class, the methods won't be used.
0275: // It it's an interceptor class, the interceptor manager will call the setters methods
0276: if (!classAnnotationMetadata.isBean()) {
0277: addDefaultMethods();
0278: }
0279: }
0280:
0281: /**
0282: * Generated methods allowing to set a context and a factory.
0283: * This allows to set on injectors the bean's session context and its factory.
0284: */
0285: private void addDefaultMethods() {
0286: // Adds the factory attribute and its getter/setter.
0287: CommonClassGenerator.addFieldGettersSetters(cv,
0288: classAnnotationMetadata.getClassName(),
0289: "easyBeansFactory", Factory.class);
0290:
0291: // Adds the easyBeansContext attribute and its getter/setter.
0292: Class<?> contextClass = null;
0293: if (classAnnotationMetadata.isSession()) {
0294: contextClass = EZBSessionContext.class;
0295: } else if (classAnnotationMetadata.isMdb()) {
0296: contextClass = EZBMDBContext.class;
0297: } else {
0298: contextClass = EZBEJBContext.class;
0299: }
0300: CommonClassGenerator.addFieldGettersSetters(cv,
0301: classAnnotationMetadata.getClassName(),
0302: "easyBeansContext", contextClass);
0303: }
0304:
0305: /**
0306: * Generates the injectedByEasyBeans() method on the current class.
0307: */
0308: private void addInjectedMethod() {
0309: int access = ACC_PUBLIC;
0310: if (staticMode) {
0311: access = access + ACC_STATIC;
0312: }
0313:
0314: MethodVisitor mv = cv
0315: .visitMethod(
0316: access,
0317: INJECTED_METHOD,
0318: "()V",
0319: null,
0320: new String[] { "org/ow2/easybeans/api/injection/EasyBeansInjectionException" });
0321: mv.visitCode();
0322:
0323: // First, call the super class method (if the super class has been
0324: // analyzed) and if there is one
0325: String super NameClass = classAnnotationMetadata.getSuperName();
0326: if (super NameClass != null
0327: && !super NameClass.equals(JAVA_LANG_OBJECT)) {
0328: EjbJarAnnotationMetadata jarMetadata = classAnnotationMetadata
0329: .getEjbJarAnnotationMetadata();
0330: ClassAnnotationMetadata super Metadata = jarMetadata
0331: .getClassAnnotationMetadata(super NameClass);
0332: if (super Metadata != null) {
0333: if (!staticMode) {
0334: // generate call to super method : super.INJECTED_METHOD();
0335: mv.visitVarInsn(ALOAD, 0);
0336: mv.visitMethodInsn(INVOKESPECIAL, super Metadata
0337: .getClassName(), INJECTED_METHOD, "()V");
0338: } else {
0339: mv.visitMethodInsn(INVOKESTATIC, super Metadata
0340: .getClassName(), INJECTED_METHOD, "()V");
0341: }
0342: }
0343: }
0344:
0345: // If it is a bean, call the interceptorManager and the attributes (like context and factory)
0346: if (classAnnotationMetadata.isBean()) {
0347: String clNameManager = classAnnotationMetadata
0348: .getClassName()
0349: + EasyBeansInvocationContextGenerator.SUFFIX_INTERCEPTOR_MANAGER;
0350:
0351: // this.interceptorManager.setEasyBeansContext(easyBeansContext);
0352: mv.visitVarInsn(ALOAD, 0);
0353: mv.visitFieldInsn(GETFIELD, classAnnotationMetadata
0354: .getClassName(), "easyBeansInterceptorManager", "L"
0355: + clNameManager + ";");
0356: mv.visitVarInsn(ALOAD, 0);
0357: mv.visitFieldInsn(GETFIELD, classAnnotationMetadata
0358: .getClassName(), "easyBeansContext",
0359: EZB_EJBCONTEXT_DESC);
0360: mv.visitMethodInsn(INVOKEVIRTUAL, clNameManager,
0361: "setEasyBeansContext", "(" + EZB_EJBCONTEXT_DESC
0362: + ")V");
0363:
0364: // this.interceptorManager.injectedByEasyBeans();
0365: mv.visitVarInsn(ALOAD, 0);
0366: mv.visitFieldInsn(GETFIELD, classAnnotationMetadata
0367: .getClassName(), "easyBeansInterceptorManager", "L"
0368: + clNameManager + ";");
0369: mv.visitMethodInsn(INVOKEVIRTUAL, clNameManager,
0370: "injectedByEasyBeans", "()V");
0371:
0372: }
0373:
0374: generateBodyInjectedMethod(mv);
0375:
0376: mv.visitInsn(RETURN);
0377: mv.visitMaxs(0, 0);
0378: mv.visitEnd();
0379: }
0380:
0381: /**
0382: * Generates the body of the injectedByEasyBeans() method if any.<br> Else,
0383: * do nothing.
0384: * @param mv the method visitor object used to add some code.
0385: */
0386: private void generateBodyInjectedMethod(final MethodVisitor mv) {
0387:
0388: // generates injection for annotations on the class itself
0389: generateClassInjection(mv);
0390:
0391: // Generates injection for attributes
0392: generateAttributesInjection(mv);
0393:
0394: // Generates injection for setters methods
0395: generateSettersInjection(mv);
0396:
0397: }
0398:
0399: /**
0400: * Generates the calls to populate ENC environment by using annotations on the class itself.
0401: * @param mv the method visitor used to inject bytecode.
0402: */
0403: private void generateClassInjection(final MethodVisitor mv) {
0404: // Get annotations on the class
0405:
0406: // @PersistenceContexts annotation
0407: List<JavaxPersistenceContext> javaxPersistencePersistenceContexts = classAnnotationMetadata
0408: .getJavaxPersistencePersistenceContexts();
0409: if (javaxPersistencePersistenceContexts != null
0410: && javaxPersistencePersistenceContexts.size() > 0) {
0411: // For each javaxPersistenceContext
0412: for (JavaxPersistenceContext javaxPersistenceContext : javaxPersistencePersistenceContexts) {
0413: bindClassPersistenceContext(javaxPersistenceContext, mv);
0414: }
0415: }
0416: // @PersistenceContext annotation
0417: if (classAnnotationMetadata.isPersistenceContext()) {
0418: bindClassPersistenceContext(classAnnotationMetadata
0419: .getJavaxPersistenceContext(), mv);
0420: }
0421:
0422: // @PersistenceUnits annotation
0423: List<JavaxPersistenceUnit> javaxPersistencePersistenceUnits = classAnnotationMetadata
0424: .getJavaxPersistencePersistenceUnits();
0425: if (javaxPersistencePersistenceUnits != null
0426: && javaxPersistencePersistenceUnits.size() > 0) {
0427: // For each javaxPersistenceUnit
0428: for (JavaxPersistenceUnit javaxPersistenceUnit : javaxPersistencePersistenceUnits) {
0429: bindClassPersistenceUnit(javaxPersistenceUnit, mv);
0430: }
0431: }
0432: // @PersistenceUnit annotation
0433: if (classAnnotationMetadata.isPersistenceUnit()) {
0434: bindClassPersistenceUnit(classAnnotationMetadata
0435: .getJavaxPersistenceUnit(), mv);
0436: }
0437:
0438: // @EJBs annotation
0439: List<JEjbEJB> jEjbs = classAnnotationMetadata.getJEjbEJBs();
0440: if (jEjbs != null && jEjbs.size() > 0) {
0441: // For each jEJB
0442: for (JEjbEJB jEJB : jEjbs) {
0443: bindClassEJB(jEJB, mv);
0444: }
0445: }
0446: // @EJB annotation
0447: JEjbEJB jEJB = classAnnotationMetadata.getJEjbEJB();
0448: if (jEJB != null) {
0449: // For each ejb, do :
0450: bindClassEJB(jEJB, mv);
0451: }
0452:
0453: // @Resources annotation
0454: List<JAnnotationResource> jAnnotationResources = classAnnotationMetadata
0455: .getJAnnotationResources();
0456: if (jAnnotationResources != null
0457: && jAnnotationResources.size() > 0) {
0458: // For each jAnnotationResource
0459: for (JAnnotationResource jAnnotationResource : jAnnotationResources) {
0460: bindResource(jAnnotationResource, mv);
0461: }
0462: }
0463: // @Resource annotation
0464: JAnnotationResource jAnnotationResource = classAnnotationMetadata
0465: .getJAnnotationResource();
0466: if (jAnnotationResource != null) {
0467: bindResource(jAnnotationResource, mv);
0468: }
0469:
0470: }
0471:
0472: /**
0473: * Generates the calls to methods that will set the attributes value.
0474: * @param mv the method visitor used to inject bytecode.
0475: */
0476: private void generateAttributesInjection(final MethodVisitor mv) {
0477:
0478: for (FieldAnnotationMetadata fieldMetaData : classAnnotationMetadata
0479: .getFieldAnnotationMetadataCollection()) {
0480:
0481: // Get type of interface
0482: Type typeInterface = Type.getType(fieldMetaData.getJField()
0483: .getDescriptor());
0484: String itfName = typeInterface.getClassName();
0485:
0486: // @PersistenceContext annotation
0487: if (fieldMetaData.isPersistenceContext()) {
0488: // validate
0489: validateAccessFieldAnnotation(fieldMetaData);
0490:
0491: // Check that attribute is EntityManager
0492: if (!ENTITYMANAGER_ITF.equals(itfName)) {
0493: throw new IllegalStateException(
0494: "Trying to applied @PersistenceContext on an invalid field in the class '"
0495: + classAnnotationMetadata
0496: .getClassName()
0497: + "', field = " + fieldMetaData);
0498: }
0499:
0500: JavaxPersistenceContext javaxPersistenceContext = fieldMetaData
0501: .getJavaxPersistenceContext();
0502:
0503: logger
0504: .debug(
0505: "Add injection for PersistenceContext on attribute {0} of class {1}",
0506: fieldMetaData.getFieldName(),
0507: classAnnotationMetadata.getClassName());
0508: // add this.em =
0509: // EntityManagerHelper.getEntityManager(getEasyBeansContext(),
0510: // "myUnitName", PersistenceContextType.EXTENDED);
0511: mv.visitVarInsn(ALOAD, 0);
0512:
0513: // call em helper
0514: addCallEntityManagerHelper(javaxPersistenceContext, mv);
0515:
0516: // Set result in the field
0517: mv.visitFieldInsn(PUTFIELD, classAnnotationMetadata
0518: .getClassName(), fieldMetaData.getFieldName(),
0519: "Ljavax/persistence/EntityManager;");
0520:
0521: // Bind value in JNDI
0522: javaxPersistenceContext.setName(getJndiName(
0523: javaxPersistenceContext.getName(),
0524: fieldMetaData));
0525: bindClassPersistenceContext(javaxPersistenceContext, mv);
0526:
0527: }
0528:
0529: // @PersistenceUnit annotation
0530: if (fieldMetaData.isPersistenceUnit()) {
0531: // validate
0532: validateAccessFieldAnnotation(fieldMetaData);
0533:
0534: // Check that attribute is EntityManager
0535: if (!ENTITYMANAGERFACTORY_ITF.equals(itfName)) {
0536: throw new IllegalStateException(
0537: "Trying to applied @PersistenceUnit on an invalid field in the class '"
0538: + classAnnotationMetadata
0539: .getClassName()
0540: + "', field = " + fieldMetaData);
0541: }
0542: logger
0543: .debug(
0544: "Add injection for PersistenceUnit on attribute {0} of class {1}",
0545: fieldMetaData.getFieldName(),
0546: classAnnotationMetadata.getClassName());
0547:
0548: JavaxPersistenceUnit javaxPersistenceUnit = fieldMetaData
0549: .getJavaxPersistenceUnit();
0550: // add this.emf = EntityManagerHelper.getEntityManagerFactory(getEasyBeansContext(), "myUnitName");
0551:
0552: mv.visitVarInsn(ALOAD, 0);
0553: // get EMF
0554: addCallEntityManagerFactoryHelper(javaxPersistenceUnit,
0555: mv);
0556: // set attribute
0557: mv.visitFieldInsn(PUTFIELD, classAnnotationMetadata
0558: .getClassName(), fieldMetaData.getFieldName(),
0559: "Ljavax/persistence/EntityManagerFactory;");
0560:
0561: // Bind value in JNDI
0562: javaxPersistenceUnit.setName(getJndiName(
0563: javaxPersistenceUnit.getName(), fieldMetaData));
0564: bindClassPersistenceUnit(javaxPersistenceUnit, mv);
0565: }
0566:
0567: // @EJB annotation
0568: JEjbEJB jEjb = fieldMetaData.getJEjbEJB();
0569: if (jEjb != null) {
0570: // validate
0571: validateAccessFieldAnnotation(fieldMetaData);
0572:
0573: logger
0574: .debug(
0575: "Add injection for EJB on attribute {0} of class {1}",
0576: fieldMetaData.getFieldName(),
0577: classAnnotationMetadata.getClassName());
0578:
0579: JNDIResolver jndiResolver = (JNDIResolver) map
0580: .get(JNDIResolver.NAME);
0581: // ejbName ?
0582: String beanName = jEjb.getBeanName();
0583: String jndiName = jndiResolver.getJndiNameInterface(
0584: itfName, beanName);
0585:
0586: if (jndiName == null) {
0587: logger
0588: .error(
0589: "No jndi name found on class {0} for interface {1} and beanName {2}",
0590: classAnnotationMetadata
0591: .getClassName(), itfName,
0592: beanName);
0593: } else {
0594: logger
0595: .debug(
0596: "Asking jndi name on class {0} for interface {1} and beanName {2}. Result = {3}",
0597: classAnnotationMetadata
0598: .getClassName(), itfName,
0599: beanName, jndiName);
0600: callAttributeJndi(jndiName, typeInterface, mv,
0601: fieldMetaData, classAnnotationMetadata
0602: .getClassName(), REGISTRY);
0603: callBindAttributeJndi(jEjb.getName(), jndiName, mv,
0604: fieldMetaData);
0605: }
0606: }
0607:
0608: // @Resource annotation
0609: JAnnotationResource jAnnotationResource = fieldMetaData
0610: .getJAnnotationResource();
0611: if (jAnnotationResource != null) {
0612:
0613: // Set default name if not present.
0614: jAnnotationResource.setName(getJndiName(
0615: jAnnotationResource.getName(), fieldMetaData));
0616:
0617: // Update annotation value with data set on the class
0618: updateAnnotationResource(jAnnotationResource);
0619:
0620: // Get Mapped Name
0621: String mappedName = jAnnotationResource.getMappedName();
0622:
0623: // validate
0624: validateAccessFieldAnnotation(fieldMetaData);
0625:
0626: if (SESSION_CONTEXT.equals(itfName)) {
0627: logger
0628: .debug(
0629: "Add injection for @Resource on attribute {0} of class {1} for the type {2}",
0630: fieldMetaData.getFieldName(),
0631: classAnnotationMetadata
0632: .getClassName(), itfName);
0633:
0634: // this.attribute = getEasyBeansContext();
0635: mv.visitVarInsn(ALOAD, 0);
0636: addCallGetEasyBeansContext(mv,
0637: "javax/ejb/SessionContext");
0638: mv.visitFieldInsn(PUTFIELD, classAnnotationMetadata
0639: .getClassName(), fieldMetaData
0640: .getFieldName(),
0641: "Ljavax/ejb/SessionContext;");
0642: // Define the type (if missing)
0643: jAnnotationResource.setType(SESSION_CONTEXT);
0644:
0645: bindResource(jAnnotationResource, mv);
0646: } else if (MESSAGEDRIVEN_CONTEXT.equals(itfName)) {
0647: logger
0648: .debug(
0649: "Add injection for @Resource on attribute {0} of class {1} for the type {2}",
0650: fieldMetaData.getFieldName(),
0651: classAnnotationMetadata
0652: .getClassName(), itfName);
0653:
0654: // this.attribute = getEasyBeansContext();
0655: mv.visitVarInsn(ALOAD, 0);
0656: addCallGetEasyBeansContext(mv,
0657: "javax/ejb/MessageDrivenContext");
0658: mv.visitFieldInsn(PUTFIELD, classAnnotationMetadata
0659: .getClassName(), fieldMetaData
0660: .getFieldName(),
0661: "Ljavax/ejb/MessageDrivenContext;");
0662: // Define the type (if missing)
0663: jAnnotationResource.setType(MESSAGEDRIVEN_CONTEXT);
0664:
0665: bindResource(jAnnotationResource, mv);
0666:
0667: } else if (EJBCONTEXT.equals(itfName)) {
0668: logger
0669: .debug(
0670: "Add injection for @Resource on attribute {0} of class {1} for the type {2}",
0671: fieldMetaData.getFieldName(),
0672: classAnnotationMetadata
0673: .getClassName(), itfName);
0674:
0675: // this.attribute = getEasyBeansContext();
0676: mv.visitVarInsn(ALOAD, 0);
0677: addCallGetEasyBeansContext(mv,
0678: "javax/ejb/EJBContext");
0679: mv.visitFieldInsn(PUTFIELD, classAnnotationMetadata
0680: .getClassName(), fieldMetaData
0681: .getFieldName(), "Ljavax/ejb/EJBContext;");
0682: // Define the type (if missing)
0683: jAnnotationResource.setType(EJBCONTEXT);
0684:
0685: bindResource(jAnnotationResource, mv);
0686:
0687: } else if (isEnvEntry(typeInterface)) { // Env-Entry
0688: callAttributeJndi(jAnnotationResource.getName(),
0689: typeInterface, mv, fieldMetaData,
0690: classAnnotationMetadata.getClassName(),
0691: JAVA_COMP_ENV);
0692: } else if (isJNDIResourceInjection(itfName)) {
0693: if (mappedName != null && !mappedName.equals("")) {
0694: callAttributeJndi(mappedName, typeInterface,
0695: mv, fieldMetaData,
0696: classAnnotationMetadata.getClassName(),
0697: REGISTRY);
0698: callBindAttributeJndi(jAnnotationResource
0699: .getName(), mappedName, mv,
0700: fieldMetaData);
0701: } else {
0702: callAttributeJndi(
0703: jAnnotationResource.getName(),
0704: typeInterface, mv, fieldMetaData,
0705: classAnnotationMetadata.getClassName(),
0706: JAVA_COMP_ENV);
0707: }
0708: } else if (USERTRANSACTION_ITF.equals(itfName)) {
0709: callAttributeJndi("UserTransaction", typeInterface,
0710: mv, fieldMetaData, classAnnotationMetadata
0711: .getClassName(), JAVA_COMP);
0712: callBindAttributeJndi(
0713: jAnnotationResource.getName(),
0714: "java:comp/UserTransaction", mv,
0715: fieldMetaData);
0716: } else if (URL_ITF.equals(itfName)) {
0717: // Bind object in java:comp/env
0718: callBindLookupURLRef(jAnnotationResource.getName(),
0719: mappedName, mv);
0720:
0721: // Set attribute
0722: callAttributeJndi(jAnnotationResource.getName(),
0723: typeInterface, mv, fieldMetaData,
0724: classAnnotationMetadata.getClassName(),
0725: JAVA_COMP_ENV);
0726:
0727: } else if (TIMERSERVICE_ITF.equals(itfName)) {
0728: // Needs to get timerservice with the bean's context.
0729: //this.fieldtimerService = getEasyBeansContext().getTimerService();
0730: mv.visitVarInsn(ALOAD, 0);
0731: addCallGetEasyBeansContext(mv, null);
0732: mv.visitMethodInsn(INVOKEINTERFACE, Type
0733: .getInternalName(EZBEJBContext.class),
0734: "getTimerService",
0735: "()Ljavax/ejb/TimerService;");
0736: mv
0737: .visitFieldInsn(PUTFIELD,
0738: classAnnotationMetadata
0739: .getClassName(),
0740: fieldMetaData.getFieldName(),
0741: "Ljavax/ejb/TimerService;");
0742: callBindAttributeJndi(
0743: jAnnotationResource.getName(),
0744: "java:comp/TimerService", mv, fieldMetaData);
0745: } else if (ORB_ITF.equals(itfName)) {
0746: // this.orb = ORBInitHelper.getORB(); (non static)
0747: if (!staticMode) {
0748: mv.visitVarInsn(ALOAD, 0);
0749: }
0750: mv
0751: .visitMethodInsn(
0752: INVOKESTATIC,
0753: "org/ow2/easybeans/injection/ORBInitHelper",
0754: "getORB", "()Lorg/omg/CORBA/ORB;");
0755: mv.visitFieldInsn(setField(),
0756: classAnnotationMetadata.getClassName(),
0757: fieldMetaData.getFieldName(),
0758: "Lorg/omg/CORBA/ORB;");
0759:
0760: }
0761:
0762: }
0763:
0764: }
0765: }
0766:
0767: /**
0768: * Update the given resource with given encname with data set on the class.
0769: * @param jAnnotationResource the resource to update
0770: */
0771: private void updateAnnotationResource(
0772: final JAnnotationResource jAnnotationResource) {
0773: // Search if no resource was defined on the class.
0774: List<JAnnotationResource> classResources = null;
0775: JAnnotationResource resClass = classAnnotationMetadata
0776: .getJAnnotationResource();
0777: if (resClass != null) {
0778: classResources = new ArrayList<JAnnotationResource>();
0779: classResources.add(resClass);
0780: } else {
0781: classResources = classAnnotationMetadata
0782: .getJAnnotationResources();
0783: }
0784: // if resources are existing on the class, search matching key.
0785: if (classResources != null) {
0786: for (JAnnotationResource annotationResource : classResources) {
0787: // Matching value
0788: if (jAnnotationResource.getName().equals(
0789: annotationResource.getName())) {
0790: // Update the value if not set
0791: jAnnotationResource
0792: .setMappedName(annotationResource
0793: .getMappedName());
0794: }
0795: }
0796: }
0797:
0798: }
0799:
0800: /**
0801: * Generates the calls to methods that will call the setters methods.
0802: * @param mv the method visitor used to inject bytecode.
0803: */
0804: private void generateSettersInjection(final MethodVisitor mv) {
0805:
0806: for (MethodAnnotationMetadata methodMetaData : classAnnotationMetadata
0807: .getMethodAnnotationMetadataCollection()) {
0808: // Ignore inherited methods (managed by super class)
0809: if (methodMetaData.isInherited()) {
0810: continue;
0811: }
0812:
0813: JAnnotationResource jAnnotationResource = methodMetaData
0814: .getJAnnotationResource();
0815: // @Resource annotation
0816: if (jAnnotationResource != null) {
0817: Type typeInterface = validateSetterMethod(methodMetaData);
0818: String itfName = typeInterface.getClassName();
0819:
0820: // Set default name if not present.
0821: jAnnotationResource.setName(getJndiName(
0822: jAnnotationResource.getName(), methodMetaData));
0823:
0824: // Update annotation value with data set on the class
0825: updateAnnotationResource(jAnnotationResource);
0826:
0827: // Get Mapped Name
0828: String mappedName = jAnnotationResource.getMappedName();
0829:
0830: // Env-Entry
0831: if (isEnvEntry(typeInterface)) {
0832: callMethodJndiEnv(jAnnotationResource.getName(),
0833: typeInterface, mv, methodMetaData,
0834: classAnnotationMetadata.getClassName(),
0835: JAVA_COMP_ENV);
0836: } else if (isJNDIResourceInjection(itfName)) {
0837: if (mappedName != null && !mappedName.equals("")) {
0838: // Get JNDI value from registry and call setter method
0839: callMethodJndiEnv(mappedName, typeInterface,
0840: mv, methodMetaData,
0841: classAnnotationMetadata.getClassName(),
0842: REGISTRY);
0843: // Then bind attribute in ENC
0844: callBindLookupJndiRef(jAnnotationResource
0845: .getName(), mappedName, mv);
0846: } else {
0847: logger
0848: .error(
0849: "Cannot use the Resource annotation {0} as mappedName is null",
0850: jAnnotationResource);
0851: }
0852: } else if (USERTRANSACTION_ITF.equals(itfName)) {
0853: callMethodJndiEnv("UserTransaction", typeInterface,
0854: mv, methodMetaData, classAnnotationMetadata
0855: .getClassName(), JAVA_COMP);
0856: callBindLookupJndiRef(
0857: jAnnotationResource.getName(),
0858: "java:comp/UserTransaction", mv);
0859: } else if (TIMERSERVICE_ITF.equals(itfName)) {
0860: // add call to : setterMethod(getEasyBeansContext().getTimerService());
0861: mv.visitVarInsn(ALOAD, 0);
0862: addCallGetEasyBeansContext(mv, null);
0863: mv
0864: .visitMethodInsn(
0865: INVOKEINTERFACE,
0866: "org/ow2/easybeans/api/container/EZBEJBContext",
0867: "getTimerService",
0868: "()Ljavax/ejb/TimerService;");
0869: mv.visitMethodInsn(INVOKEVIRTUAL,
0870: classAnnotationMetadata.getClassName(),
0871: methodMetaData.getMethodName(),
0872: "(Ljavax/ejb/TimerService;)V");
0873: callBindLookupJndiRef(
0874: jAnnotationResource.getName(),
0875: "java:comp/TimerService", mv);
0876: } else if (SESSION_CONTEXT.equals(itfName)) {
0877: // add call to : setterMethod(getEasyBeansContext());
0878: mv.visitVarInsn(ALOAD, 0);
0879: addCallGetEasyBeansContext(mv,
0880: "javax/ejb/SessionContext");
0881: mv.visitMethodInsn(INVOKEVIRTUAL,
0882: classAnnotationMetadata.getClassName(),
0883: methodMetaData.getMethodName(),
0884: "(Ljavax/ejb/SessionContext;)V");
0885:
0886: // Define the type (if missing)
0887: jAnnotationResource.setType(SESSION_CONTEXT);
0888: bindResource(jAnnotationResource, mv);
0889: } else if (MESSAGEDRIVEN_CONTEXT.equals(itfName)) {
0890: // add call to : setterMethod(getEasyBeansContext());
0891: mv.visitVarInsn(ALOAD, 0);
0892: addCallGetEasyBeansContext(mv,
0893: "javax/ejb/MessageDrivenContext");
0894: mv.visitMethodInsn(INVOKEVIRTUAL,
0895: classAnnotationMetadata.getClassName(),
0896: methodMetaData.getMethodName(),
0897: "(Ljavax/ejb/MessageDrivenContext;)V");
0898:
0899: // Define the type (if missing)
0900: jAnnotationResource.setType(MESSAGEDRIVEN_CONTEXT);
0901: bindResource(jAnnotationResource, mv);
0902: } else if (EJBCONTEXT.equals(itfName)) {
0903: // add call to : setterMethod(getEasyBeansContext());
0904: mv.visitVarInsn(ALOAD, 0);
0905: addCallGetEasyBeansContext(mv,
0906: "javax/ejb/EJBContext");
0907: mv.visitMethodInsn(INVOKEVIRTUAL,
0908: classAnnotationMetadata.getClassName(),
0909: methodMetaData.getMethodName(),
0910: "(Ljavax/ejb/EJBContext;)V");
0911:
0912: // Define the type (if missing)
0913: jAnnotationResource.setType(EJBCONTEXT);
0914: bindResource(jAnnotationResource, mv);
0915: } else if (URL_ITF.equals(itfName)) {
0916: // Bind object in java:comp/env
0917: callBindLookupURLRef(jAnnotationResource.getName(),
0918: mappedName, mv);
0919:
0920: // Get JNDI value from registry and call setter method
0921: callMethodJndiEnv(jAnnotationResource.getName(),
0922: typeInterface, mv, methodMetaData,
0923: classAnnotationMetadata.getClassName(),
0924: JAVA_COMP_ENV);
0925: }
0926: }
0927:
0928: // @EJB annotation
0929: JEjbEJB jEjb = methodMetaData.getJEjbEJB();
0930: if (jEjb != null) {
0931: logger
0932: .debug(
0933: "Add injection for EJB on method {0} of class {1}",
0934: methodMetaData.getMethodName(),
0935: classAnnotationMetadata.getClassName());
0936:
0937: Type typeInterface = validateSetterMethod(methodMetaData);
0938: String itfName = typeInterface.getClassName();
0939:
0940: JNDIResolver jndiResolver = (JNDIResolver) map
0941: .get(JNDIResolver.NAME);
0942: // ejbName ?
0943: String beanName = jEjb.getBeanName();
0944: String jndiName = jndiResolver.getJndiNameInterface(
0945: itfName, beanName);
0946: logger
0947: .debug(
0948: "Asking jndi name on class {0} for interface {1} and beanName {2}. Result = {3}",
0949: classAnnotationMetadata.getClassName(),
0950: itfName, beanName, jndiName);
0951:
0952: callMethodJndiEnv(jndiName, typeInterface, mv,
0953: methodMetaData, classAnnotationMetadata
0954: .getClassName(), REGISTRY);
0955:
0956: // get enc name (or the default name) and bind result
0957: String encName = getJndiName(jEjb.getName(),
0958: methodMetaData);
0959: callBindLookupJndiRef(encName, jndiName, mv);
0960: }
0961:
0962: // @PersistenceContext annotation
0963: if (methodMetaData.isPersistenceContext()) {
0964: Type typeInterface = validateSetterMethod(methodMetaData);
0965: String itfName = typeInterface.getClassName();
0966:
0967: // Check that arg of the method is EntityManager
0968: if (!ENTITYMANAGER_ITF.equals(itfName)) {
0969: throw new IllegalStateException(
0970: "Trying to applied @PersistenceContext on an invalid method in the class '"
0971: + classAnnotationMetadata
0972: .getClassName()
0973: + "', method = " + methodMetaData);
0974: }
0975: logger
0976: .debug(
0977: "Add injection for PersistenceContext on method {0} of class {1}",
0978: methodMetaData.getMethodName(),
0979: classAnnotationMetadata.getClassName());
0980:
0981: JavaxPersistenceContext javaxPersistenceContext = methodMetaData
0982: .getJavaxPersistenceContext();
0983: // add
0984: // setterName(EntityManagerHelper.getEntityManager(getEasyBeansContext(),
0985: // "myUnitName", PersistenceContextType.EXTENDED);
0986:
0987: mv.visitVarInsn(ALOAD, 0);
0988:
0989: // call em helper
0990: addCallEntityManagerHelper(javaxPersistenceContext, mv);
0991:
0992: // call setter method
0993: mv.visitMethodInsn(INVOKEVIRTUAL,
0994: classAnnotationMetadata.getClassName(),
0995: methodMetaData.getMethodName(),
0996: "(Ljavax/persistence/EntityManager;)V");
0997:
0998: // bind value in ENC environment
0999: javaxPersistenceContext.setName(getJndiName(
1000: javaxPersistenceContext.getName(),
1001: methodMetaData));
1002: bindClassPersistenceContext(javaxPersistenceContext, mv);
1003:
1004: }
1005:
1006: // @PersistenceUnit annotation
1007: if (methodMetaData.isPersistenceUnit()) {
1008: Type typeInterface = validateSetterMethod(methodMetaData);
1009: String itfName = typeInterface.getClassName();
1010: // Check that attribute is EntityManager
1011: if (!ENTITYMANAGERFACTORY_ITF.equals(itfName)) {
1012: throw new IllegalStateException(
1013: "Trying to applied @PersistenceUnit on an invalid method in the class '"
1014: + classAnnotationMetadata
1015: .getClassName()
1016: + "', method = " + methodMetaData);
1017: }
1018: logger
1019: .debug(
1020: "Add injection for PersistenceUnit on on method {0} of class {1}",
1021: methodMetaData.getMethodName(),
1022: classAnnotationMetadata.getClassName());
1023:
1024: JavaxPersistenceUnit javaxPersistenceUnit = methodMetaData
1025: .getJavaxPersistenceUnit();
1026:
1027: // add
1028: // setterName(EntityManagerHelper.getEntityManagerFactory(getEasyBeansContext(),
1029: // "myUnitName"));
1030:
1031: mv.visitVarInsn(ALOAD, 0);
1032: // get EMF
1033: addCallEntityManagerFactoryHelper(javaxPersistenceUnit,
1034: mv);
1035: // call setter method
1036: mv.visitMethodInsn(INVOKEVIRTUAL,
1037: classAnnotationMetadata.getClassName(),
1038: methodMetaData.getMethodName(),
1039: "(Ljavax/persistence/EntityManagerFactory;)V");
1040:
1041: // Bind value in JNDI
1042: javaxPersistenceUnit
1043: .setName(getJndiName(javaxPersistenceUnit
1044: .getName(), methodMetaData));
1045: bindClassPersistenceUnit(javaxPersistenceUnit, mv);
1046: }
1047:
1048: }
1049: }
1050:
1051: /**
1052: * Ensure that this method is a valid setter method and return ASM type of the first arg of the method.
1053: * @param methodMetaData the metadata to check
1054: * @return ASM type of the first arg of the method.
1055: */
1056: private Type validateSetterMethod(
1057: final MethodAnnotationMetadata methodMetaData) {
1058: // validate access
1059: validateAccessMethodAnnotation(methodMetaData);
1060:
1061: JMethod jMethod = methodMetaData.getJMethod();
1062: // Should be a setter
1063: if (!jMethod.getName().startsWith("set")
1064: || jMethod.getName().equalsIgnoreCase("set")) {
1065: throw new IllegalStateException(
1066: "Method '"
1067: + jMethod
1068: + "' is invalid. Should be in the setter form setXXX().");
1069: }
1070:
1071: // Get type of interface
1072: // Get arguments of the method.
1073: Type[] args = Type.getArgumentTypes(jMethod.getDescriptor());
1074: if (args.length != 1) {
1075: throw new IllegalStateException("Method args '"
1076: + Arrays.asList(args) + "' for method '" + jMethod
1077: + "' are invalid. Length should be of 1.");
1078: }
1079: return args[0];
1080: }
1081:
1082: /**
1083: * Return true if the given type is a type used in env-entry.
1084: * @param type an ASM type.
1085: * @return true if this entry is used in env-entry.
1086: */
1087: private boolean isEnvEntry(final Type type) {
1088: String itfName = type.getClassName();
1089: return String.class.getName().equals(itfName)
1090: || Boolean.TYPE.getName().equals(itfName)
1091: || Byte.TYPE.getName().equals(itfName)
1092: || Character.TYPE.getName().equals(itfName)
1093: || Double.TYPE.getName().equals(itfName)
1094: || Float.TYPE.getName().equals(itfName)
1095: || Integer.TYPE.getName().equals(itfName)
1096: || Long.TYPE.getName().equals(itfName)
1097: || Short.TYPE.getName().equals(itfName);
1098: }
1099:
1100: /**
1101: * Add a call to getEasyBeansContext() method in the given method visitor.
1102: * @param mv the method visitor on which instructions are added
1103: * @param castDesc the cast to do.
1104: */
1105: private void addCallGetEasyBeansContext(final MethodVisitor mv,
1106: final String castDesc) {
1107: mv.visitVarInsn(ALOAD, 0);
1108: mv.visitMethodInsn(INVOKEVIRTUAL, classAnnotationMetadata
1109: .getClassName(), "getEasyBeansContext", "()"
1110: + EZB_EJBCONTEXT_DESC);
1111: if (castDesc != null) {
1112: mv.visitTypeInsn(CHECKCAST, castDesc);
1113: }
1114: }
1115:
1116: /**
1117: * Add a call to EntityManagerHelper class (PersistenceContext) :
1118: * EntityManagerHelper.getEntityManager(getEasyBeansContext(),
1119: * unitName, type of persistence).
1120: * @param javaxPersistenceContext informations on the persistence context
1121: * @param mv the method visitor on which instructions are added
1122: */
1123: private void addCallEntityManagerHelper(
1124: final JavaxPersistenceContext javaxPersistenceContext,
1125: final MethodVisitor mv) {
1126: // get EasyBeansContext
1127: addCallGetEasyBeansContext(mv, null);
1128:
1129: // Persistence-unit name
1130: mv.visitLdcInsn(javaxPersistenceContext.getUnitName());
1131:
1132: // Transaction Type
1133: mv.visitFieldInsn(GETSTATIC,
1134: "javax/persistence/PersistenceContextType",
1135: javaxPersistenceContext.getType().toString(),
1136: "Ljavax/persistence/PersistenceContextType;");
1137: // Call EntityManagerHelper
1138: mv
1139: .visitMethodInsn(
1140: INVOKESTATIC,
1141: "org/ow2/easybeans/injection/EntityManagerHelper",
1142: "getEntityManager",
1143: "("
1144: + EZB_EJBCONTEXT_DESC
1145: + "Ljava/lang/String;Ljavax/persistence/PersistenceContextType;)"
1146: + "Ljavax/persistence/EntityManager;");
1147: }
1148:
1149: /**
1150: * Add a call to EntityManagerHelper class (PersistenceUnit):
1151: * EntityManagerHelper.getEntityManagerFactory(getEasyBeansContext(), unitName).
1152: * @param javaxPersistenceUnit informations on the persistence unit
1153: * @param mv the method visitor on which instructions are added
1154: */
1155: private void addCallEntityManagerFactoryHelper(
1156: final JavaxPersistenceUnit javaxPersistenceUnit,
1157: final MethodVisitor mv) {
1158: // get EasyBeansContext
1159: addCallGetEasyBeansContext(mv, null);
1160:
1161: // Persistence-unit name
1162: mv.visitLdcInsn(javaxPersistenceUnit.getUnitName());
1163:
1164: mv
1165: .visitMethodInsn(
1166: INVOKESTATIC,
1167: "org/ow2/easybeans/injection/EntityManagerHelper",
1168: "getEntityManagerFactory",
1169: "("
1170: + EZB_EJBCONTEXT_DESC
1171: + "Ljava/lang/String;)Ljavax/persistence/EntityManagerFactory;");
1172: }
1173:
1174: /**
1175: * Generates a call to JNDILookupHelper class to get the java:comp/env name
1176: * requested.
1177: * @param jndiName the name to lookup.
1178: * @param type the ASM type
1179: * @param mv the method visitor to write code.
1180: * @param className the name of the generated class.
1181: * @param jndiType the type of access (registry, java:comp/env, etc)
1182: */
1183: private void callJndi(final String jndiName, final Type type,
1184: final MethodVisitor mv, final String className,
1185: final JndiType jndiType) {
1186: if (!staticMode) {
1187: mv.visitVarInsn(ALOAD, 0);
1188: }
1189: mv.visitLdcInsn(jndiName);
1190: String mName = "";
1191: switch (jndiType) {
1192: case JAVA_COMP:
1193: mName = "getCompJndiName";
1194: break;
1195: case JAVA_COMP_ENV:
1196: mName = "getEnvJndiName";
1197: break;
1198: case REGISTRY:
1199: mName = "getJndiName";
1200: break;
1201: default:
1202: throw new IllegalStateException("invalid type");
1203: }
1204: mv.visitMethodInsn(INVOKESTATIC,
1205: "org/ow2/easybeans/injection/JNDILookupHelper", mName,
1206: "(Ljava/lang/String;)Ljava/lang/Object;");
1207: CommonClassGenerator.transformObjectIntoPrimitive(type, mv);
1208: }
1209:
1210: /**
1211: * Generates a call to JNDILookupHelper class to get the java:comp/env name
1212: * requested.
1213: * @param jndiName the name to lookup.
1214: * @param type the ASM type.
1215: * @param mv the method visitor to write code.
1216: * @param fieldMetaData the metadata of the attribute.
1217: * @param className the name of the generated class.
1218: * @param jndiType the type of access (registry, java:comp/env, etc)
1219: */
1220: private void callAttributeJndi(final String jndiName,
1221: final Type type, final MethodVisitor mv,
1222: final FieldAnnotationMetadata fieldMetaData,
1223: final String className, final JndiType jndiType) {
1224: logger
1225: .debug(
1226: "Add injection for @Resource on attribute {0} of class {1} for the type {2}",
1227: fieldMetaData.getFieldName(), className, type
1228: .getClassName());
1229:
1230: String formattedJndiName = getJndiName(jndiName, fieldMetaData);
1231: callJndi(formattedJndiName, type, mv, className, jndiType);
1232: setField(mv, className, fieldMetaData, type);
1233: }
1234:
1235: /**
1236: * Sets the value of a field.
1237: * @param mv the method visitor to use
1238: * @param className the class which contains the attribute.
1239: * @param fieldMetaData the metadata corresponding to the attribute
1240: * @param type the ASM type of the attribute
1241: */
1242: private void setField(final MethodVisitor mv,
1243: final String className,
1244: final FieldAnnotationMetadata fieldMetaData, final Type type) {
1245: mv.visitFieldInsn(setField(), className, fieldMetaData
1246: .getFieldName(), type.getDescriptor());
1247: }
1248:
1249: /**
1250: * Sets the value of a field.
1251: * @param mv the method visitor to use
1252: * @param className the class which contains the method.
1253: * @param methodMetaData the metadata corresponding to the method *
1254: * @param type the ASM type of the method
1255: */
1256: private void callSetterMethod(final MethodVisitor mv,
1257: final String className,
1258: final MethodAnnotationMetadata methodMetaData,
1259: final Type type) {
1260: mv.visitMethodInsn(INVOKEVIRTUAL, className, methodMetaData
1261: .getMethodName(), methodMetaData.getJMethod()
1262: .getDescriptor());
1263: }
1264:
1265: /**
1266: * Generates a call to JNDILookupHelper class to get the java:comp/env name
1267: * requested.
1268: * @param jndiName the name to lookup.
1269: * @param type the ASM type.
1270: * @param mv the method visitor to write code.
1271: * @param methodMetaData the metadata of the method.
1272: * @param className the name of the generated class.
1273: * @param jndiType the type of access (registry, java:comp/env, etc)
1274: */
1275: private void callMethodJndiEnv(final String jndiName,
1276: final Type type, final MethodVisitor mv,
1277: final MethodAnnotationMetadata methodMetaData,
1278: final String className, final JndiType jndiType) {
1279: logger
1280: .debug(
1281: "Add injection for @Resource on method {0} of class {1} for the type {2}",
1282: methodMetaData.getMethodName(), className, type
1283: .getClassName());
1284:
1285: String checkedJndiName = getJndiName(jndiName, methodMetaData);
1286: callJndi(checkedJndiName, type, mv, className, jndiType);
1287: callSetterMethod(mv, className, methodMetaData, type);
1288: }
1289:
1290: /**
1291: * Ensures that jndiName is valid and return the default value if it is a null value.
1292: * @param jndiName to check
1293: * @param fieldAnnotationMetadata attribute's metadata
1294: * @return jndi name value.
1295: */
1296: private String getJndiName(final String jndiName,
1297: final FieldAnnotationMetadata fieldAnnotationMetadata) {
1298: String newJndiName = jndiName;
1299: if (jndiName == null || "".equals(jndiName)) {
1300: logger.debug("Name property undefined.");
1301: newJndiName = classAnnotationMetadata.getClassName()
1302: .replace("/", ".")
1303: + "/" + fieldAnnotationMetadata.getFieldName();
1304: logger
1305: .debug(
1306: "Getting environment's entry with default JNDI name: {0}",
1307: newJndiName);
1308: }
1309: return newJndiName;
1310: }
1311:
1312: /**
1313: * Ensures that jndiName is valid and return the default value if it is a null value.
1314: * @param jndiName to check
1315: * @param methodMetaData attribute's metadata
1316: * @return jndi name value.
1317: */
1318: private String getJndiName(final String jndiName,
1319: final MethodAnnotationMetadata methodMetaData) {
1320: String newJndiName = jndiName;
1321: if (jndiName == null || "".equals(jndiName)) {
1322: logger.debug("Property name not defined.");
1323: StringBuilder propertyBuilder = new StringBuilder(
1324: methodMetaData.getMethodName());
1325: propertyBuilder.delete(0, LENGTH);
1326: propertyBuilder.setCharAt(0, Character
1327: .toLowerCase(propertyBuilder.charAt(0)));
1328: propertyBuilder.insert(0, classAnnotationMetadata
1329: .getClassName().replace("/", ".")
1330: + "/");
1331: newJndiName = propertyBuilder.toString();
1332: logger
1333: .debug(
1334: "Getting environment's entry with default JNDI name: {0}",
1335: newJndiName);
1336: }
1337:
1338: return newJndiName;
1339: }
1340:
1341: /**
1342: * Generates a call to JNDIBinderHelper class to bind an object into the
1343: * java:comp/env context.
1344: * @param encName the name to bind
1345: * @param jndiName the name to link to (LinkRef)
1346: * @param mv the method visitor to write code.
1347: * @param fieldMetaData the metadata of the attribute (that will be bound)
1348: */
1349: private void callBindAttributeJndi(final String encName,
1350: final String jndiName, final MethodVisitor mv,
1351: final FieldAnnotationMetadata fieldMetaData) {
1352:
1353: // call : JNDIBinderHelper.bindLinkRefEnvJndiName("localName", "jndiName");
1354: mv.visitLdcInsn(getJndiName(encName, fieldMetaData));
1355: mv.visitLdcInsn(jndiName);
1356: mv.visitMethodInsn(INVOKESTATIC,
1357: "org/ow2/easybeans/injection/JNDIBinderHelper",
1358: "bindLinkRefEnvJndiName",
1359: "(Ljava/lang/String;Ljava/lang/String;)V");
1360: }
1361:
1362: /**
1363: * Generates a call to JNDIBinderHelper class to link an URL object into the
1364: * java:comp/env context.
1365: * @param encName the name to bind
1366: * @param url the URL that need to be built
1367: * @param mv the method visitor to write code.
1368: */
1369: private void callBindLookupURLRef(final String encName,
1370: final String url, final MethodVisitor mv) {
1371: // use a LinkRef between JNDI name and ENC name
1372: // call : JNDIBinderHelper.bindLinkRefEnvURL("localName", "url");
1373:
1374: mv.visitLdcInsn(encName);
1375: mv.visitLdcInsn(url);
1376: mv.visitMethodInsn(INVOKESTATIC,
1377: "org/ow2/easybeans/injection/JNDIBinderHelper",
1378: "bindLinkRefEnvURL",
1379: "(Ljava/lang/String;Ljava/lang/String;)V");
1380:
1381: logger.debug("Linking Object with URL '" + url
1382: + "' to ENC name '" + encName + "' for the class '"
1383: + classAnnotationMetadata.getClassName() + "'.");
1384: }
1385:
1386: /**
1387: * Generates a call to JNDIBinderHelper class to link an object into the
1388: * java:comp/env context.
1389: * @param encName the name to bind
1390: * @param jndiName the jndi name to use for the link
1391: * @param mv the method visitor to write code.
1392: */
1393: private void callBindLookupJndiRef(final String encName,
1394: final String jndiName, final MethodVisitor mv) {
1395: // use a LinkRef between JNDI name and ENC name
1396: // call : JNDIBinderHelper.bindLinkRefEnvJndiName("localName", "jndiName");
1397:
1398: mv.visitLdcInsn(encName);
1399: mv.visitLdcInsn(jndiName);
1400: mv.visitMethodInsn(INVOKESTATIC,
1401: "org/ow2/easybeans/injection/JNDIBinderHelper",
1402: "bindLinkRefEnvJndiName",
1403: "(Ljava/lang/String;Ljava/lang/String;)V");
1404:
1405: logger.debug("Linking Object with JNDI name '" + jndiName
1406: + "' to ENC name '" + encName + "' for the class '"
1407: + classAnnotationMetadata.getClassName() + "'.");
1408: }
1409:
1410: /**
1411: * Bind a ref for an EJB in ENC environment.
1412: * @param jEJB annotation to analyze
1413: * @param mv the visitor on which write the bytecode.
1414: */
1415: private void bindClassEJB(final JEjbEJB jEJB, final MethodVisitor mv) {
1416:
1417: // JNDIBinderHelper.bindEnvJndiName("encName",
1418: // JNDILookupHelper.getEnvJndiName("jndiName"));
1419:
1420: // name attribute is mandatory
1421: String encName = jEJB.getName();
1422: if (encName == null || "".equals(encName)) {
1423: throw new IllegalStateException(
1424: "Error when analyzing @EJB annotation '" + jEJB
1425: + "' for the class '"
1426: + classAnnotationMetadata.getClassName()
1427: + "' : No name !");
1428: }
1429:
1430: // jndiName
1431: JNDIResolver jndiResolver = (JNDIResolver) map
1432: .get(JNDIResolver.NAME);
1433: // ejbName ?
1434: String beanName = jEJB.getBeanName();
1435: String jndiName = null;
1436: if (jEJB.getMappedName() != null
1437: && jEJB.getMappedName().length() > 0) {
1438: jndiName = jEJB.getMappedName();
1439: } else {
1440: jndiName = jndiResolver.getJndiNameInterface(jEJB
1441: .getBeanInterface(), beanName);
1442: }
1443:
1444: if (jndiName == null) {
1445: throw new IllegalStateException(
1446: "No JNDI name found when analyzing @EJB annotation '"
1447: + jEJB + "' for the class '"
1448: + classAnnotationMetadata.getClassName()
1449: + "'.");
1450: }
1451:
1452: // inject code
1453: callBindLookupJndiRef(encName, jndiName, mv);
1454: }
1455:
1456: /**
1457: * Bind a ref for a Resource in ENC environment.
1458: * @param jAnnotationResource annotation to analyze
1459: * @param mv the visitor on which write the bytecode.
1460: */
1461: private void bindResource(
1462: final JAnnotationResource jAnnotationResource,
1463: final MethodVisitor mv) {
1464: if (isJNDIResourceInjection(jAnnotationResource.getType())
1465: || SESSION_CONTEXT
1466: .equals(jAnnotationResource.getType())
1467: || EJBCONTEXT.equals(jAnnotationResource.getType())
1468: || USERTRANSACTION_ITF.equals(jAnnotationResource
1469: .getType())
1470: || URL_ITF.equals(jAnnotationResource.getType())
1471: || TIMERSERVICE_ITF.equals(jAnnotationResource
1472: .getType())) {
1473: // get name
1474: String encName = jAnnotationResource.getName();
1475: if (encName == null || "".equals(encName)) {
1476: logger.error("No encName for Annotation resource {0}.",
1477: jAnnotationResource);
1478: return;
1479: }
1480: String jndiName = null;
1481: if (SESSION_CONTEXT.equals(jAnnotationResource.getType())
1482: || EJBCONTEXT.equals(jAnnotationResource.getType())) {
1483: // specify JNDI name
1484: jndiName = "java:comp/EJBContext";
1485: } else if (USERTRANSACTION_ITF.equals(jAnnotationResource
1486: .getType())) {
1487: // specify JNDI name
1488: jndiName = "java:comp/UserTransaction";
1489: } else if (TIMERSERVICE_ITF.equals(jAnnotationResource
1490: .getType())) {
1491: // specify JNDI name
1492: jndiName = "java:comp/TimerService";
1493: } else {
1494: jndiName = jAnnotationResource.getMappedName();
1495: }
1496:
1497: if (jndiName == null) {
1498: logger
1499: .error(
1500: "MappedName for resource annotation {0} is null, no binding to ENC name {1}",
1501: jAnnotationResource, encName);
1502: } else if (URL_ITF.equals(jAnnotationResource.getType())) {
1503: // Binds a reference in context in order to build a new URL object
1504: // The JNDI name is the URL
1505: callBindLookupURLRef(encName, jndiName, mv);
1506: } else {
1507: // inject code for JNDI ref
1508: callBindLookupJndiRef(encName, jndiName, mv);
1509: }
1510: }
1511: }
1512:
1513: /**
1514: * Bind a ref for a PersistenceContext in ENC environment.
1515: * @param javaxPersistenceContext annotation to analyze
1516: * @param mv the visitor on which write the bytecode.
1517: */
1518: private void bindClassPersistenceContext(
1519: final JavaxPersistenceContext javaxPersistenceContext,
1520: final MethodVisitor mv) {
1521:
1522: // Add :
1523: // JNDIBinderHelper.bindEnvJndiName("myName", EntityManagerHelper.getEnt....);
1524:
1525: // if name is not valid, do nothing
1526: String name = javaxPersistenceContext.getName();
1527: if (name == null || "".equals(name)) {
1528: logger
1529: .warn("PersistenceContext '"
1530: + javaxPersistenceContext
1531: + "' has an empty or null name, cannot bind it in ENC.");
1532: return;
1533: }
1534:
1535: // name for ENC
1536: mv.visitLdcInsn(name);
1537:
1538: // call em helper
1539: addCallEntityManagerHelper(javaxPersistenceContext, mv);
1540:
1541: // bind in ENC
1542: mv.visitMethodInsn(INVOKESTATIC,
1543: "org/ow2/easybeans/injection/JNDIBinderHelper",
1544: "bindEnvJndiName",
1545: "(Ljava/lang/String;Ljava/lang/Object;)V");
1546: }
1547:
1548: /**
1549: * Bind a ref for a PersistenceUnit in ENC environment.
1550: * @param javaxPersistenceUnit annotation to analyze
1551: * @param mv the visitor on which write the bytecode.
1552: */
1553: private void bindClassPersistenceUnit(
1554: final JavaxPersistenceUnit javaxPersistenceUnit,
1555: final MethodVisitor mv) {
1556: // Add :
1557: // JNDIBinderHelper.bindEnvJndiName("myName", EntityManagerFactory.getEnt....);
1558:
1559: // if name is not valid, do nothing
1560: String name = javaxPersistenceUnit.getName();
1561: if (name == null || "".equals(name)) {
1562: logger
1563: .warn("PersistenceUnit '"
1564: + javaxPersistenceUnit
1565: + "' has an empty or null name, cannot bind it in ENC.");
1566: return;
1567: }
1568:
1569: // name for ENC
1570: mv.visitLdcInsn(name);
1571:
1572: // get EMF
1573: addCallEntityManagerFactoryHelper(javaxPersistenceUnit, mv);
1574:
1575: // bind in ENC
1576: mv.visitMethodInsn(INVOKESTATIC,
1577: "org/ow2/easybeans/injection/JNDIBinderHelper",
1578: "bindEnvJndiName",
1579: "(Ljava/lang/String;Ljava/lang/Object;)V");
1580: }
1581:
1582: /**
1583: * @return the opCode used for non-static or static mode.
1584: */
1585: private int setField() {
1586: int opCode = PUTFIELD;
1587: if (staticMode) {
1588: opCode = PUTSTATIC;
1589: }
1590: return opCode;
1591: }
1592:
1593: /**
1594: * Check that the annotation is not used on a final field or static field
1595: * (except client mode).
1596: * @param field the attribute to check.
1597: */
1598: private void validateAccessFieldAnnotation(
1599: final FieldAnnotationMetadata field) {
1600: if (accessTest(field.getJField().getAccess(), ACC_FINAL)) {
1601: throw new IllegalStateException(
1602: "The '"
1603: + field
1604: + "' attribute is a final attribute which is not compliant for dependency injection.");
1605: }
1606: if (!staticMode
1607: && accessTest(field.getJField().getAccess(), ACC_STATIC)) {
1608: throw new IllegalStateException(
1609: "The '"
1610: + field
1611: + "' attribute is a static attribute which is not compliant for dependency injection.");
1612: }
1613: }
1614:
1615: /**
1616: * Check that the annotation is not used on a final field or static field
1617: * (except client mode).
1618: * @param methodData the method to check.
1619: */
1620: private void validateAccessMethodAnnotation(
1621: final MethodAnnotationMetadata methodData) {
1622: if (!staticMode
1623: && accessTest(methodData.getJMethod().getAccess(),
1624: ACC_STATIC)) {
1625: throw new IllegalStateException(
1626: "The '"
1627: + methodData
1628: + "' method is a static attribute which is not compliant for dependency injection.");
1629: }
1630: }
1631:
1632: /**
1633: * @param access the full access modified to check
1634: * @param checkedAccess the access to check
1635: * @return true if it is ok, else false.
1636: */
1637: private boolean accessTest(final int access, final int checkedAccess) {
1638: return (access & checkedAccess) == checkedAccess;
1639: }
1640:
1641: /**
1642: * If the resource is a JNDI resource injection, return true.<br>
1643: * This is the case of DataSource, JMS Queues/Topics & JMS factories, etc.
1644: * @param itfName the name of the interface to check.
1645: * @return true if it is a JNDI resource injection
1646: */
1647: private boolean isJNDIResourceInjection(final String itfName) {
1648: return DATASOURCE_ITF.equals(itfName)
1649: || QUEUE_ITF.equals(itfName)
1650: || QUEUECONNECTIONFACTORY_ITF.equals(itfName)
1651: || TOPIC_ITF.equals(itfName)
1652: || CONNECTIONFACTORY_ITF.equals(itfName)
1653: || TOPICCONNECTIONFACTORY_ITF.equals(itfName)
1654: || MAILSESSION_ITF.equals(itfName)
1655: || MIMEPARTDATASOURCE_ITF.equals(itfName);
1656: }
1657: }
|