6 Replies Latest reply on May 19, 2013 10:42 AM by sfcoy

    Message-driven bean activation-config and JNDI

    pedrolamarao

      I am trying to figure out how much flexibility I have while configuring a message-driven bean.

      I have arrived at a configuration I was sure would work but it does not.

      I am not sure if my assumptions are incorrect or if there is a bug involved.

       

      All modules are contained in an EAR.

      The application.xml contains:

       

      <resource-ref>

          <res-ref-name>messageQueue</res-ref-name>

          <lookup-name>java:jboss/queue/sandbox</lookup-name>

      </resource-ref>

       

      One module inside this EAR contains a Session EJB class with the following method:

       

      @Resource(name="messageQueue", lookup="java:app/env/messageQueue")

      public void setQueue (Queue queue)

      {

          this.queue = queue;

      }

       

      Another module inside this EAR contains a Message Driven EJB class with the following fragment in ejb-jar.xml:

       

      <message-driven>

          <ejb-name>SandboxMessageListenerBean</ejb-name>

          <activation-config>           

              <activation-config-property>

                  <activation-config-property-name>destinationType</activation-config-property-name>

                  <activation-config-property-value>javax.jms.Queue</activation-config-property-value>

              </activation-config-property>

              <activation-config-property>

                  <activation-config-property-name>destination</activation-config-property-name>

                  <activation-config-property-value>java:app/env/messageQueue</activation-config-property-value>

              </activation-config-property>

          </activation-config>

      </message-driven>

       

      After deploying the EAR, we determine the "queue" attribute is correctly injected in the Session EJB, and infer java:app/env/messageQueue is properly bound, but the Message Driven EJB is apparently not configured correctly.

       

      JBoss continuously registers in the server.log these messages:

       

      15:23:01,038 INFO  [org.hornetq.ra.inflow.HornetQActivation] (default-threads - 1) Attempting to reconnect org.hornetq.ra.inflow.HornetQActivationSpec(ra=org.hornetq.ra.HornetQResourceAdapter@1b0a4ee3 destination=java:app/env/messageQueue destinationType=javax.jms.Queue ack=Auto-acknowledge durable=false clientID=null user=null maxSession=15)

      15:23:01,043 INFO  [org.hornetq.ra.inflow.HornetQActivation] (default-threads - 1) awaiting topic/queue creation java:app/env/messageQueue

       

      My configuration is Windows 7 64 bits + system locale pt_BR + Oracle JDK 1.7.0 u17 + JBoss AS branch 7.1 snapshot from commit ID e395398 (current HEAD).

       

      Please advise.

        • 1. Re: Message-driven bean activation-config and JNDI
          jaysensharma

          Hi,

           

              You will need to change the

           

                  <activation-config-property>

                      <activation-config-property-name>destination</activation-config-property-name>

                      <activation-config-property-value>java:app/env/messageQueue</activation-config-property-value>

                  </activation-config-property>

           

          To Folowing:

          ===========

           

                  <activation-config-property>

                      <activation-config-property-name>destination</activation-config-property-name>

                      <activation-config-property-value>java:jboss/queue/sandbox</activation-config-property-value>

                  </activation-config-property>

           

           

          You are getting repeated message as following Because your MDB is not able to find the JMSQueue (you need to mention the correct JNDI name of your Queue in the activation-config-property-value):

          15:23:01,043 INFO  [org.hornetq.ra.inflow.HornetQActivation] (default-threads - 1) awaiting topic/queue creation java:app/env/messageQueue

          • 2. Re: Message-driven bean activation-config and JNDI
            pedrolamarao

            Hi,

             

            if I put a global JNDI name in that field as you suggest the configuration works as expected.

             

            I want to know why the configuration does not work when I put an app/env relative name in that field.

            This fact contradicts my intuition about how the application server manages JNDI contexts.

            • 3. Re: Message-driven bean activation-config and JNDI
              jaikiran

              There are 2 issues in those configs.

               

              1) By default, a resource-ref binds to java:comp/env and not java:app/env. Of course you can explicitly set res-ref-name to java:app/env/foo so that it can be bound in that namespace.

               

              2) The value for the destination is a JNDI name that should be accessible to the JMS implementation (HornetQ) in this case, via JNDI. java:app/ namespace is only available within the app to which the deployment belongs. So the JMS implementation can't access that java:app/. You could use java:global/ namespace if you want to, in which case the resource-ref too needs to bind it to java:global/ namespace.

              • 4. Re: Message-driven bean activation-config and JNDI
                pedrolamarao

                okay, after more experience, I've understood your point (1). I initially thought that inner contexts (like java:comp) would somehow delegate to outer contexts (like java:module), and if we say "dataSource", lookup would eventually search all contexts up to java:global.

                 

                But I don't quite get your point (2). You say the JMS implementation has no access to java:app; I assume you also mean it has no access to java:module and java:comp.

                 

                But that does not seem to be the case of the JPA implementation. With the following jboss-web.xml and persistence.xml, everything works as expected. Why?

                 

                <jboss-web>

                    <context-root>/foo</context-root>

                    <resource-ref>

                        <res-ref-name>dataSource</res-ref-name>

                        <lookup-name>java:jboss/datasources/xDS</lookup-name>

                    </resource-ref>

                </jboss-web>

                 

                <persistence version="2.0">

                    <persistence-unit name="foo">

                        <jta-data-source>java:module/env/dataSource</jta-data-source>

                    </persistence-unit>

                </persistence>

                 

                Message was edited by: Pedro Lamarão -- spelling etc.

                • 5. Re: Message-driven bean activation-config and JNDI
                  sfcoy

                  Pedro Lamarão wrote:

                   

                  ...

                   

                  All modules are contained in an EAR.

                  The application.xml contains:

                   

                  <resource-ref>

                      <res-ref-name>messageQueue</res-ref-name>

                      <lookup-name>java:jboss/queue/sandbox</lookup-name>

                  </resource-ref>

                   

                  ...

                   

                  application.xml? Really?

                  • 6. Re: Message-driven bean activation-config and JNDI
                    sfcoy

                    The java:comp/env... namespace has always been "special" in Java (2) EE land.

                     

                    The "comp" is short for component. JNDI names in this namespace are local to the component, where a component is an individual EJB or a complete web module (WAR).

                     

                    The "env" is short for environment, and the java:comp/env namespace is also known as the component environment naming context or ENC.

                     

                    As this name was local only to the component in question, server vendors needed to provide a mechanism to map the local java:comp/... name to a real object.

                    Sometimes this would be a value provided directly in a web.xml or ejb-jar.xml file in an env-entry:

                    {code:xml}<env-entry>

                         <description>

                              The maximum number of tax exemptions allowed to be set.

                         </description>

                         <env-entry-name>maxExemptions</env-entry-name>

                         <env-entry-type>java.lang.Integer</env-entry-type>

                         <env-entry-value>15</env-entry-value>

                    </env-entry>{code}

                    Prior to Jave EE 5, you would look this up in JNDI:

                    {code:java}try {

                         Context context = new InitialContext();

                         Integer maxExemptions = (Integer)context.lookup("java:comp/env/maxExemptions");

                         ...

                    } catch (NamingException e) {

                    ...

                    }{code}

                    Subsequently, you can now use @Resource much more simply:

                    {code:java}@Resource private Integer maxExemptions;{code}

                     

                    Othertimes, you may be looking up some other resource such as a DataSource. ENC (java:comp/env/...) names require a resource-ref in web.xml or ejb-jar.xml:

                    {code:xml}<resource-ref>

                         <res-ref-name>jdbc/EmployeeAppDB</res-ref-name>

                         <res-type>javax.sql.DataSource</res-type>

                         <res-auth>Container</res-auth>

                         <res-sharing-scope>Shareable</res-sharing-scope>

                    </resource-ref>{code}

                    The same lookup methods work here. There are also ejb-ref, resource-env-ref, and message-destination-ref forms in deployment descriptors with different purpose dependent sub-elements.

                     

                    However, the catch is that the DataSource lookup must return an object that is managed by the server, rather than a value from the deployment descriptor. Normally objects like DataSources are configured in an application server and bound into JNDI with a (vendor dependent) global name, such as java:jboss/datasources/ApplicationDB.

                     

                    So, you want to lookup "java:comp/env/jdbc/EmployeeAppDB", but this object is actually residing at "java:jboss/datasources/ApplicationDB"?

                     

                    This is the purpose of the <resource-ref> element in your jboss-web. It maps the local component name to the name of the managed object in the server.

                    <res-ref-name> is the portion of the name following "java:comp/env" (which is fixed and therefore redundant). In my example a jboss-web resource-ref would look like:

                    {code:xml}<resource-ref>

                         <res-ref-name>jdbc/EmployeeAppDB</res-ref-name>

                         <mapped-name>java:jboss/datasources/ApplicationDB</mapped-name>

                    </resource-ref>{code}

                     

                    The long hand JNDI lookup in java would look like:

                    {code:java}DataSource employeeDS = (DataSource)context.lookup("java:comp/env/jdbc/EmployeeAppDB");{code}

                     

                    or using @Resource:

                    {code:java}@Resource(name="jdbc/EmployeeAppDB") private DataSource employeeDS;{code}

                     

                    This may seem complicated but it's valuable for a number of reasons, including:

                    • ENC based lookup names in java code are completely decoupled from physical server names
                    • ENC based lookup names are portable across vendors
                    • component references often associate other useful attributes with the object (such as how a database connection should be authenticated)

                     

                    This kind of name mapping was so ubiquitous that the Java EE 5 spec added a <mapped-name> element to the <resource-ref> and other similar definitions found in web.xml and ejb-jar.xml. However, its use in these deployment descriptors is completely non-portable.

                     

                    Java EE 6 expanded the notion of "component" scoped references so that you can now specify "module", "application" and "global" scoped references. But these still need to be mapped to the actual managed objects in the server.

                     

                    * in my experience only 1 in 10 enterprise java developers have any kind of grip on this. They just use the global server managed name everywhere instead.