13 Replies Latest reply on May 6, 2009 3:15 AM by jaikiran

    javax.ejb.EJB Annotations Outside EJB3 Components

    ropalka

      This post relates to: JBWS-2634

      Hi EJB3 Team,

      I need your help. I'm working on the above issue at the moment and there are many issues regarding the EJB specification defaults I'm dealing with.

      Here's my usecase:

      ad1) I defined EJB3 bean:

      package org.jboss.test.ws.jaxws.jbws2634.shared;

      import javax.ejb.Stateless;

      @Stateless
      public class BeanImpl implements BeanIface
      {
      public String printString()
      {
      return "Injected hello message";
      }
      }
      ---
      package org.jboss.test.ws.jaxws.jbws2634.shared;

      public interface BeanIface
      {
      String printString();
      }


      ad2) Then I defined POJO webservice injecting the EJB3 bean:


      package org.jboss.test.ws.jaxws.jbws2634.webservice;

      import javax.ejb.EJB;
      import javax.jws.WebService;

      import org.jboss.test.ws.jaxws.jbws2634.shared.BeanIface;

      @WebService
      (
      serviceName = "EndpointService",
      targetNamespace = "http://jbossws.org/JBWS2634",
      endpointInterface="org.jboss.test.ws.jaxws.jbws2634.webservice.POJOIface"
      )
      public class POJOBean implements POJOIface
      {
      @EJB
      private BeanIface testBean;

      public String getMessage()
      {
      return testBean.printString();
      }
      }
      ---
      package org.jboss.test.ws.jaxws.jbws2634.webservice;

      import javax.jws.WebMethod;
      import javax.jws.WebService;
      import javax.jws.soap.SOAPBinding;

      @WebService
      @SOAPBinding(style = SOAPBinding.Style.RPC)
      public interface POJOIface
      {
      @WebMethod
      String getMessage();
      }


      Issue I'm dealing with:

      * Above usecase doesn't work because I don't know how to construct/obtain injected EJB3 JNDI name. Is it possible to do it outside EJB3 components (in my case from webservice code)?

      I'm able to workaround this problem with specifying name attribute:

      @EJB(name = "jaxws-jbws2634/BeanImpl/local-org.jboss.test.ws.jaxws.jbws2634.shared.BeanIface")
      private BeanIface testBean;

      but I'd like to support both usecases i.e. with/out name EJB annotation attribute.

      Also javax.ejb.EJB annotation is really confusing me. What's the difference between name and mappedName? Where in the EJB spec I can find exhausting description of this annotation?

        • 1. Re: javax.ejb.EJB Annotations Outside EJB3 Components
          jaikiran

           

          "richard.opalka@jboss.com" wrote:

          Also <b>javax.ejb.EJB</b> annotation is really confusing me. What's the difference between <b>name</b> and <b>mappedName</b>?

          The "name" attribute is jndiname within the java:comp/env namespace of the component into which the bean is being injected. So if you have:
          @Stateless
          public AnotherBean...
          {
          
           @EJB(name="someName")
           private BeanOne bean;
          ..
          }

          This means that the BeanOne is available at java:comp/env/someName jndiname of the AnotherBean's java:comp/env namespace.

          The mappedName is actually the global jndiname (not the java:comp/env namespace) of the bean. The mappedName is actually not portable. Each vendor (application server) can implement this the way they want and are even allowed to ignore it.

          Where in the EJB spec I can find exhausting description of this annotation?

          I found this useful http://java.sun.com/products/ejb/javadoc-3_0-fr/javax/ejb/EJB.html

          • 2. Re: javax.ejb.EJB Annotations Outside EJB3 Components
            jaikiran

             

            Above usecase doesn't work because I don't know how to construct/obtain injected EJB3 JNDI name.


            We have a EJBReferenceResolver http://anonsvn.jboss.org/repos/jbossas/projects/ejb3/trunk/common/src/main/java/org/jboss/ejb3/common/resolvers/spi/EjbReferenceResolver.java
            which, given a deployment unit and an EJBReference http://anonsvn.jboss.org/repos/jbossas/projects/ejb3/trunk/common/src/main/java/org/jboss/ejb3/common/resolvers/spi/EjbReference.java resolves the JNDI name.

            Ex: http://anonsvn.jboss.org/repos/jbossas/projects/ejb3/trunk/common/src/main/java/org/jboss/ejb3/common/resolvers/plugins/FirstMatchEjbReferenceResolver.java

            The only thing i am not sure is whether non-EJB3 components (like JBossWS) can use this (i.e. add a dependency on this).


            • 3. Re: javax.ejb.EJB Annotations Outside EJB3 Components
              alrubinger

              Also have a look at the tests to document usage.

              http://anonsvn.jboss.org/repos/jbossas/projects/ejb3/trunk/common/src/test/java/org/jboss/ejb3/test/common/resolvers/unit/EjbReferenceResolverUnitTestCaseBase.java

              Note that FirstMatch..Resolver doesn't take packaging scoping into account (see the JavaDoc) so you may want/need a new impl.

              Also these should move out of ejb3-common. Mudball approach is growing into a mudbeachball.

              S,
              ALR

              • 4. Re: javax.ejb.EJB Annotations Outside EJB3 Components
                ropalka

                Thank you Andrew and Jaikiran very much! Your comments/pointers helped me a lot ;)

                • 5. Re: javax.ejb.EJB Annotations Outside EJB3 Components
                  ropalka

                  Hi EJB3 Folks,

                  is the construction of the ejb reference right in the following code?
                  This is request for review ;)


                  package org.jboss.wsf.container.jboss50.deployment.metadata;

                  import java.lang.reflect.Field;
                  import java.lang.reflect.Method;

                  import javax.ejb.EJB;

                  import org.jboss.deployers.structure.spi.DeploymentUnit;
                  import org.jboss.ejb3.common.resolvers.plugins.FirstMatchEjbReferenceResolver;
                  import org.jboss.ejb3.common.resolvers.spi.EjbReference;
                  import org.jboss.ejb3.common.resolvers.spi.EjbReferenceResolver;
                  import org.jboss.wsf.common.javax.resolvers.AbstractReferenceResolver;

                  final class EjbBeanReferenceResolver
                  extends AbstractReferenceResolver
                  {
                  private final DeploymentUnit unit;
                  private final EjbReferenceResolver delegate = new FirstMatchEjbReferenceResolver();

                  EjbBeanReferenceResolver(final DeploymentUnit unit)
                  {
                  super(EJB.class);
                  this.unit = unit;
                  }

                  @Override
                  protected String resolveField(final Field field)
                  {
                  EJB ejbAnnotation = field.getAnnotation(EJB.class);
                  EjbReference reference = getEjbReference(ejbAnnotation, field.getType());
                  return this.delegate.resolveEjb(unit, reference);
                  }

                  @Override
                  protected String resolveMethod(final Method method)
                  {
                  EJB ejbAnnotation = method.getAnnotation(EJB.class);
                  EjbReference reference = getEjbReference(ejbAnnotation, method.getParameterTypes()[0]);
                  return this.delegate.resolveEjb(unit, reference);
                  }

                  private EjbReference getEjbReference(EJB ejbAnnotation, Class<?> type)
                  {
                  String beanInterface = ejbAnnotation.beanInterface().getName();
                  if ("".equals(beanInterface))
                  {
                  beanInterface = type.getName();
                  }
                  return new EjbReference(ejbAnnotation.beanName(), beanInterface, ejbAnnotation.mappedName());
                  }
                  }

                  • 6. Re: javax.ejb.EJB Annotations Outside EJB3 Components
                    ropalka

                    Little fix, my getEjbReference() method looks like this now (because of @EJB annotation defaults):


                    private EjbReference getEjbReference(EJB ejbAnnotation, Class<?> type)
                    {
                    String beanInterface = ejbAnnotation.beanInterface().getName();
                    if (java.lang.Object.class.getName().equals(beanInterface))
                    {
                    beanInterface = type.getName();
                    }
                    return new EjbReference(ejbAnnotation.beanName(), beanInterface, ejbAnnotation.mappedName());
                    }

                    • 7. Re: javax.ejb.EJB Annotations Outside EJB3 Components
                      jaikiran

                       

                      is the construction of the ejb reference right in the following code?

                      Looks fine :)

                      Just a note though, which ALR already mentioned, the FirstMatchEjbReferenceResolver isn't constrained by the deployment unit passed to it. Consider your application is pacakged as :
                      XYZ.ear
                      |
                      |--- A.jar
                      |
                      |--- B.jar


                      Assuming a deployment unit corresponding to A.jar (which belongs to XYZ.ear) is passed to this resolver, the resolver will not just look for the right EJB within A.jar but will also look for beans from within B.jar.
                      If you want the behaviour to be different, then you will have to use a different implementation other than the FirstMatchEjbReferenceResolver.

                      • 8. Re: javax.ejb.EJB Annotations Outside EJB3 Components
                        alrubinger

                        Also I'd recommend injecting your EjbReferenceResolver delegate so you can swap impls. For instance we install one as an MC Bean:

                        http://anonsvn.jboss.org/repos/jbossas/projects/ejb3/trunk/core/src/main/resources/META-INF/ejb3-deployers-jboss-beans.xml

                        ...grep for bean name "org.jboss.ejb3.EjbReferenceResolver".

                        S,
                        ALR

                        • 9. Re: javax.ejb.EJB Annotations Outside EJB3 Components
                          ropalka

                          Thank you guys. Here's my final solution ;)

                          EJBBeanReferenceResolver.java - JBossWS reference resolving facade
                          jbossws-deployer-jboss-beans.xml - MC driven EjbReferenceResolver injection (search for org.jboss.ejb3.EjbReferenceResolver)

                          • 10. Re: javax.ejb.EJB Annotations Outside EJB3 Components
                            jaikiran

                             

                            <bean name="WSInjectionMetaDataDeploymentAspect" class="org.jboss.wsf.container.jboss50.deployment.metadata.InjectionMetaDataDeploymentAspect">
                             <property name="requires">WebMetaData</property>
                             <property name="provides">InjectionMetaData</property>
                             <property name="ejbReferenceResolver"><inject bean="org.jboss.ejb3.EjbReferenceResolver"/></property>
                             </bean>


                            I did not find the definition for the org.jboss.ejb3.EjbReferenceResolver bean within that jbossws-deployer-jboss-beans.xml. Does this mean that JBossWS will rely on EJB3 deployer jboss-beans.xml to deploy an EjbReferenceResolver? :)

                            I would recommend that you define your own EjbReferenceResolver (with a unique MC bean name) within JBossWS to ensure that any changes to the EJB3 deployer will not affect JBossWS. Something like:

                            <bean name="WSInjectionMetaDataDeploymentAspect" class="org.jboss.wsf.container.jboss50.deployment.metadata.InjectionMetaDataDeploymentAspect">
                             <property name="requires">WebMetaData</property>
                             <property name="provides">InjectionMetaData</property>
                             <property name="ejbReferenceResolver"><inject bean="EJBReferenceResolverForWS"/></property>
                             </bean>
                            
                             <bean name="EJBReferenceResolverForWS" class="org.jboss.ejb3.common.resolvers.spi.EjbReferenceResolver">
                             <constructor factoryClass="org.jboss.ejb3.common.resolvers.spi.EjbReferenceResolverFactory"
                             factoryMethod="newInstance">
                             <parameter>org.jboss.ejb3.common.resolvers.plugins.FirstMatchEjbReferenceResolver</parameter>
                             </constructor>
                             </bean>
                            




                            • 11. Re: javax.ejb.EJB Annotations Outside EJB3 Components
                              wolfc

                              Disregard that last bit.

                              Inject org.jboss.ejb3.common.resolvers.spi.EjbReferenceResolver by interface. That way you'll get the proper one.

                              • 12. Re: javax.ejb.EJB Annotations Outside EJB3 Components
                                ropalka

                                 

                                "jaikiran" wrote:

                                I did not find the definition for the org.jboss.ejb3.EjbReferenceResolver bean within that jbossws-deployer-jboss-beans.xml. Does this mean that JBossWS will rely on EJB3 deployer jboss-beans.xml to deploy an EjbReferenceResolver? :)

                                Exactly
                                "jaikiran" wrote:

                                I would recommend that you define your own EjbReferenceResolver (with a unique MC bean name) within JBossWS to ensure that any changes to the EJB3 deployer will not affect JBossWS.

                                Why? JBossWS depends on EJB3 components. I don't see the reason why we should hide this dependency? We want and we need to be notified about EJB3 deployer changes.

                                • 13. Re: javax.ejb.EJB Annotations Outside EJB3 Components
                                  jaikiran

                                   

                                  "richard.opalka@jboss.com" wrote:

                                  Why? JBossWS depends on EJB3 components. I don't see the reason why we should hide this dependency? We want and we need to be notified about EJB3 deployer changes.


                                  Ignore my previous comments :) I was wrong. Carlo explained to me that, it's EJB3 which should control the reference resolvers.