This discussion is archived
4 Replies Latest reply: Sep 2, 2009 1:00 PM by Tom B RSS

Injecting JMS Queue / Destination into MDB fails

647944 Newbie
Currently Being Moderated
I am trying to inject a Destination into an EJB3 MDB using
    @Resource(name = "queue/abc/Responses")
    private Destination m_responseQueue;
In the ejb-jar.xml file I declare the following
      <message-driven>
            <ejb-name>JobRequestListener</ejb-name>
            <ejb-class>com.abc.backend.jobs.JobRequestListener</ejb-class>
            <message-destination-link>JobRequests</message-destination-link>
            <!--Inherited From AbstractManagedBean -->
            <resource-ref>
                <res-ref-name>jms/ConnectionFactory</res-ref-name>
                <res-type>javax.jms.ConnectionFactory</res-type>
                <res-auth>Container</res-auth>
            </resource-ref>
            <!--Local Resources -->
            <message-destination-ref>
                <message-destination-ref-name>queue/abc/Responses</message-destination-ref-name>
                <message-destination-type>javax.jms.Queue</message-destination-type>
                <message-destination-usage>Produces</message-destination-usage>
                <message-destination-link>Responses</message-destination-link>
            </message-destination-ref>
        </message-driven>
and in weblogic-ejb-jar.xml I add
    <weblogic-enterprise-bean>
        <ejb-name>JobRequestListener</ejb-name>
        <message-driven-descriptor>
            <pool>
                <max-beans-in-free-pool>20</max-beans-in-free-pool>
                <initial-beans-in-free-pool>10</initial-beans-in-free-pool>
            </pool>
            <destination-jndi-name>queue/abc/JobRequests</destination-jndi-name>
        </message-driven-descriptor>
        <transaction-descriptor>
            <trans-timeout-seconds>315</trans-timeout-seconds>
        </transaction-descriptor>
        <!--Inherited From AbstractManagedBean -->
        <resource-description>
            <res-ref-name>jms/ConnectionFactory</res-ref-name>
            <jndi-name>jms/ABCConnectionFactory</jndi-name>
        </resource-description>
        <!--Local Resources -->         
        <resource-description>
            <res-ref-name>queue/abc/Responses</res-ref-name>
            <jndi-name>queue/abc/Responses</jndi-name>
        </resource-description>
    </weblogic-enterprise-bean>
Initially I didn't have the resource-description in the weblogic-ejb-jar.xml file, but even after adding it I am still getting the following exception during deployment
[EJB:011026]The EJB container failed while creating the java:/comp/env namespace for
 this EJB deployment. weblogic.deployment.EnvironmentException: 
[EJB:010176]The resource-env-ref 'queue/abc/Responses' declared in the ejb-jar.xml 
descriptor or annotation has no JNDI name mapped to it. The resource-ref must
be mapped to a JNDI name using the resource-description element of the 
weblogic-ejb-jar.xml descriptor or corresponding annotation.
     at weblogic.ejb.container.deployer.EnvironmentBuilder.addResourceEnvReferences(EnvironmentBuilder.java:639)
     at weblogic.ejb.container.deployer.EJBDeployer.setupEnvironmentContext(EJBDeployer.java:247)
     at weblogic.ejb.container.deployer.EJBDeployer.setupEnvironmentFor(EJBDeployer.java:1014)
     at weblogic.ejb.container.deployer.EJBDeployer.setupBeanInfos(EJBDeployer.java:908)
     at weblogic.ejb.container.deployer.EJBDeployer.prepare(EJBDeployer.java:1188)
     at weblogic.ejb.container.deployer.EJBModule.prepare(EJBModule.java:425)
By injecting a Queue rather then a destination I can work around this issue, however I would prefer to use a Destination as this allows me to change the behavior of my application without making code changes. It seems like a bug in 10.3 to me.

Edited by: ejb3workshop on Sep 1, 2009 1:44 PM

Edited by: ejb3workshop on Sep 1, 2009 1:59 PM

Edited by: ejb3workshop on Sep 2, 2009 3:11 PM
  • 1. Re: Injecting Destination fails
    647944 Newbie
    Currently Being Moderated
    I even tried using :
            <resource-env-description>
                <resource-env-ref-name>queue/abc/Responses</resource-env-ref-name>
                <jndi-name>queue/abc/Responses</jndi-name>
            </resource-env-description>
    in weblogic-ejb-jar.xml, as well as
                <message-destination-ref>
                    <message-destination-ref-name>queue/abc/Responses</message-destination-ref-name>
                    <message-destination-type>javax.jms.Destination</message-destination-type>
                    <message-destination-usage>Produces</message-destination-usage>
                    <message-destination-link>Responses</message-destination-link>
                </message-destination-ref>
    in ejb-jar.xml, however I am still not able to deploy and start my application. Using resource-env-description instead of resource-description caused the application to fail during startup with "Responses is already bound".
  • 2. Re: Injecting Destination fails
    647944 Newbie
    Currently Being Moderated
    I tried specifying the resource injection via the deployment descriptor rather then via annotations.
    <message-destination-ref>
        <message-destination-ref-name>queue/abc/Responses</message-destination-ref-name>
        <message-destination-type>javax.jms.Destination</message-destination-type>
        <message-destination-usage>Produces</message-destination-usage>
        <message-destination-link>Responses</message-destination-link>
        <injection-target>
            <injection-target-class>com.abc.backend.jobs.JobRequestListene</injection-target-class>
            <injection-target-name>m_responseQueue</injection-target-name>
        </injection-target>
    </message-destination-ref>
    This let's me deploy the application however during startup of the application the following exception occurs:
    <Sep 2, 2009 12:57:34 PM BST> <Info>
    <org.springframework.web.servlet.DispatcherServlet> <BEA-000000> <FrameworkServlet 'abc': initialization completed in 1321 ms> Startup Servlet Initialised <Sep 2, 2009 12:57:34 PM BST> <Emergency> <com.abc.backend.utilities.ConfigurationMonitor> <BEA-000000> <EJB
    Exception: ; nested exception is:
            com.bea.core.repackaged.springframework.beans.factory.BeanCreationException:
    Dependency injection failure: can't find the bean definition about class interface javax.jms.Queue; nested exception is
    com.bea.core.repackaged.springframework.beans.factory.NoSuchBeanDefinitionException:
    No unique bean of type [javax.jms.Queue] is defined: No beans of type javax.jms.Queue;
    I am not quite sure what to make of this exception.

    Edited by: ejb3workshop on Sep 2, 2009 1:10 PM
  • 3. Re: Injecting JMS Queue / Destination into MDB fails
    user161771 - oracle Expert
    Currently Being Moderated
    Perhaps you can explain exactly what you are trying to accomplish or include the full source code for your MDB.

    There are MDB samples using EJB3 here:
    <MIDDLEWARE_HOME>\wlserver_10.3\samples\server\examples\src\examples\ejb\ejb30\src\java\examples\ejb\ejb30\mdb\

    As you can see in the example, it does not require you to use a Destination object, rather that is configured as annotations via MappedName with an activationConfig and associated activationConfigProperty.

    There is also an EJB specific forum.
  • 4. Re: Injecting JMS Queue / Destination into MDB fails
    Tom B Expert
    Currently Being Moderated
    Because JMS resources by the very nature are "undependable", I think it is usually not advisable to inject JMS resources into an EJB except for MDB source destinations. The problem with injection of JMS resources is that if the JMS resource is not available at the point the EJB is originally deployed/initialized, the EJB deployment/initializaition will fail (except for MDBs, which will still deploy if the source is down, and will automatically retry internally). This is goodness for many types of resources, but since JMS resources are not necessarily always available by their very nature (down for maintenance, in the middle of a migration, initializing later in the boot, etc), most messaging applications should be specifically designed to be robustly handle the failure case during runtime.

    Anyhow, EJB3 does not require descriptors.

    I haven't fully vetted the following samples, but I think they should be pretty close to correct.

    Sample MDB code:
    // MDB will still deploy even if the source destination is down (the container will keep retrying internally).
    @MessageDriven(mappedName = "Server1Q1", 
                            activationConfig = {@ActivationConfigProperty(
                                                          propertyName = "connectionFactoryJndiName",
                                                          propertyValue = "Server1CF")})
    public class MyMDB implements MessageListener {
      @EJB
      private MyStateless myStateless;
    
      @TransactionAttribute(TransactionAttributeType.REQUIRED)
      public void onMessage(Message message) {
        System.out.println("Got the message, version 5: "+message);
        myStateless.completeWorkOrder();
      }
    }
    Sample injected JMS resources - no resource descriptors needed:
    @Stateless(mappedName="StatelessBean")
    public class MyStatelessBean implements MyStateless {
      int ctr;
    
      @Resource(mappedName="mdbq2")
      private Queue queue1;
    
      @Resource(mappedName="cfadmin2")
      private QueueConnectionFactory connectionFactory2;
    
      ...
    Sample pseudo-code for non-injected JMS resources, no resource descriptors needed:
    Eg, instead of 
     
     @Resource(mappedName="cfadmin")
     private QueueConnectionFactory cf;
     
    Do this:
     
      // note the semi-colon!  turns off injection, note the type field -- required
      // I'm not sure of exact syntax
      //cfadmin is assumed to be the JNDI name if the
      // JNDI name isn't specified in another parameter...  
      @Resource(mappedName="cfadmin", type="javax.jms.QueueConnectionFactory");   
     
      // this is not injected now
      // cache cf for re-use (performance) 
      private QueueConnectionFactory cf;
     
      @Resource
      private SessionContext sctx;  // inject the session ctx
     
    And in the source code itself, do this:
     
       int tryCount == 3;  
       while (cf != null) {
         try {  
           // not quite sure if this is the righ syntax, but I think "java:/comp/env" prefix 
           // isn't needed for the new EJB3.0 session context
           cf = sctx.lookup("cfadmin");  //cfadmin is mappedname for resource above
         } catch (NNN n) {  // don't know the exact exception
           if (--tryCount == 0) throw n;
           sleep 3 seconds  // don't want to retry in a tight loop
         } 
       }
     
    Tom

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points