<?xml version="1.0" encoding="UTF-8"?>
<section version="5.0" 
         xmlns="http://docbook.org/ns/docbook" 
         xmlns:xlink="http://www.w3.org/1999/xlink" 
         xmlns:xi="http://www.w3.org/2001/XInclude" 
         xmlns:svg="http://www.w3.org/2000/svg" 
         xmlns:mml="http://www.w3.org/1998/Math/MathML" 
         xmlns:html="http://www.w3.org/1999/xhtml" 
         xmlns:db="http://docbook.org/ns/docbook" 
         xml:lang="en" 
         xml:id="mdb">

  <info><title>EJB Programmer's Guide: Message-drivenBeans</title></info>
    
    <para>
      The EJB 2.1 specification defines a new kind of EJB component for
      receiving asynchronous messages. This implements some type of "asynchronous
      EJB component method invocation" mechanism. The Message-driven Bean (also
      referred to as MDB in the following) is an Enterprise JavaBean, not an Entity
      Bean or a Session Bean, which plays the role of a JMS MessageListener.
    </para>
    <para>
      The EJB 2.1 specification contains detailed information about MDB.  The Java
      Message Service Specification 1.1 contains detailed information about JMS.
      This chapter focuses on the use of Message-driven beans within the JOnAS
      server.
    </para>
    <section xml:id="ejb2.mdb.What"><info><title>Description of a Message-driven Bean</title></info>
      <para>
        A Message-driven Bean is an EJB component that can be considered as a JMS MessageListener, i.e., processing JMS messages asynchronously; it implements the 
    onMessage(javax.jms.Message)
     method, defined in the 
    javax.jms.MessageListener
     interface. It is associated with a JMS destination, i.e., a Queue for "point-to-point" messaging or a Topic for "publish/subscribe." The 
    onMessage
     method is activated on receipt of messages sent by a client application to the corresponding JMS destination. It is possible to associate a JMS message selector to filter the messages that the Message-driven Bean should receive.  
 </para>
      <para>      JMS messages do not carry any context, thus the 
      onMessage
       method will execute without pre-existing transactional context. However, a new transaction can be initiated at this moment (refer to the 
      <xref linkend="ejb2.mdb.Transact" /> section for more details). The 
      onMessage
       method can call other methods on the MDB itself or on other beans, and can involve other resources by accessing databases or by sending messages. Such resources are accessed the same way as for other beans (entity or session), i.e., through resource references declared in the deployment descriptor.
      </para>
      <para>
        The JOnAS container maintains a pool of MDB instances, allowing large
        volumes of messages to be processed concurrently. An MDB is similar in some
        ways to a stateless session bean: its instances are relatively short-lived,
        it retains no state for a specific client, and several instances may be
        running at the same time.
      </para>
    </section>

  <section xml:id="ejb2.mdb.Developing"><info><title>Developing a Message-drivenBean</title></info>
    
    <para>
      The MDB class must implement the 
      javax.jms.MessageListener
       and the 
      javax.ejb.MessageDrivenBean
       interfaces. In addition to the 
      onMessage
       method, the following must be implemented:
    </para>
    <itemizedlist>
      <listitem><para>
        A public constructor with no argument.
      </para></listitem>
      <listitem><para>
        public void ejbCreate()
        : with no arguments, called at the bean     instantiation time. It may be used to allocate some resources, such as     connection factories, for example if the bean sends messages, or     datasources or if the bean accesses databases.
      </para></listitem>
      <listitem><para>
        public void ejbRemove()
        : usually used to free the resources     allocated in the ejbCreate method.
      </para></listitem>
      <listitem><para>
        public void setMessageDrivenContext(MessageDrivenContext mdc)
        :     called by the container after the instance creation, with no transaction     context. The JOnAS container provides the bean with a container context     that can be used for transaction management, e.g., for calling     
        setRollbackOnly(), getRollbackOnly(), getUserTransaction()
        .
      </para></listitem>
    </itemizedlist>
    <para>
      The following is an example of an MDB class:
    </para>

    <screen>
        public class MdbBean  implements MessageDrivenBean, MessageListener {
        
            private transient MessageDrivenContext mdbContext;
        
            public MdbBean() {}
        
            public void setMessageDrivenContext(MessageDrivenContext ctx) {
                mdbContext = ctx;
            }
        
            public void ejbRemove() {}
        
            public void ejbCreate() {}
        
            public void onMessage(Message message) {
                try {
                    TextMessage mess = (TextMessage)message;
                    System.out.println( "Message received: "+mess.getText());
                }catch(JMSException ex){
                    System.err.println("Exception caught: "+ex);
                }
            }
        }
            
      </screen>
      <para>
        The destination associated to an MDB is specified in the deployment
        descriptor of the bean. A destination is a JMS-administered object,
        accessible via JNDI. The description of an MDB in the EJB 2.0 deployment
        descriptor contains the following elements, which are specific to MDBs:
      </para>
      <itemizedlist>
        <listitem><para>
          the JMS acknowledgment mode: auto-acknowledge or dups-ok-acknowledge
              (refer to the JMS specification for the definition of these modes)
        </para></listitem>
        <listitem><para>
          an eventual JMS message selector: this is a JMS concept which allows
              the filtering of the messages sent to the destination
        </para></listitem>
        <listitem><para>
          a message-driven-destination, which contains the destination type
              (Queue or Topic) and the subscription durability (in case of Topic)
        </para></listitem>
      </itemizedlist>
      <para>
        The following example illustrates such a deployment descriptor:
      </para>
      <screen>
          &lt;enterprise-beans&gt;
            &lt;message-driven&gt;
              &lt;description&gt;Describe here the message driven bean Mdb&lt;/description&gt;
              &lt;display-name&gt;Message Driven Bean Mdb&lt;/display-name&gt;
              &lt;ejb-name&gt;Mdb&lt;/ejb-name&gt;
              &lt;ejb-class&gt;samplemdb.MdbBean&lt;/ejb-class&gt;
              &lt;transaction-type&gt;Container&lt;/transaction-type&gt;
              &lt;message-selector&gt;Weight &gt;= 60.00 AND LName LIKE 'Sm_th'&lt;/message-selector&gt;
              &lt;message-driven-destination&gt;
                &lt;destination-type&gt;javax.jms.Topic&lt;/destination-type&gt;
                &lt;subscription-durability&gt;NonDurable&lt;/subscription-durability&gt;
              &lt;/message-driven-destination&gt;
              &lt;acknowledge-mode&gt;Auto-acknowledge&lt;/acknowledge-mode&gt;
            &lt;/message-driven&gt;
          &lt;/enterprise-beans&gt;
            
      </screen>
      <para>
        If the transaction type is "container," the transactional behavior of the
        MDB's methods are defined as for other enterprise beans in the deployment
        descriptor, as in the following example:
      </para>
      <screen>
          &lt;assembly-descriptor&gt;
            &lt;container-transaction&gt;
              &lt;method&gt;
                &lt;ejb-name&gt;Mdb&lt;/ejb-name&gt;
                &lt;method-name&gt;*&lt;/method-name&gt;
              &lt;/method&gt;
              &lt;trans-attribute&gt;Required&lt;/trans-attribute&gt;
            &lt;/container-transaction&gt;
          &lt;/assembly-descriptor&gt;
            
      </screen>
      <para>
        For the onMessage method, only the Required or NotSupported
        transaction attributes must be used, since there can be no pre-existing transaction context.
      </para>
      <para>
        For the message selector specified in the previous example, the sent JMS
        messages are expected to have two properties, "Weight" and "LName," for
        example assigned in the JMS client program sending the messages, as
        follows:
      </para>
      <screen>
         message.setDoubleProperty("Weight",75.5);
         message.setStringProperty("LName","Smith");
      </screen>
      <para>
        Such a message will be received by the Message-driven bean. The message
        selector syntax is based on a subset of the SQL92. Only messages whose
        headers and properties match the selector are delivered. Refer to the JMS
        specification for more details.
      </para>
      <para>
        The JNDI name of a destination associated with an MDB is defined in the
        JOnAS-specific deployment descriptor, within a 
          jonas-message-driven
        element, as illustrated in the following:
      </para>
      <screen>
          &lt;jonas-message-driven&gt;
            &lt;ejb-name&gt;Mdb&lt;/ejb-name&gt;
            &lt;jonas-message-driven-destination&gt;
              &lt;jndi-name&gt;sampleTopic&lt;/jndi-name&gt;
            &lt;/jonas-message-driven-destination&gt;
          &lt;/jonas-message-driven&gt;
            
      </screen>
      <para>
        Once the destination is established, a client application can send
        messages to the MDB through a destination object obtained via JNDI as
        follows:
      </para>
      <para>
        <code>
          Queue q = context.lookup("sampleTopic");
        </code>
      </para>
      <para>
        If the client sending messages to the MDB is an EJB component itself, it
        is preferable that it use a resource environment reference to obtain the
        destination object. The use of resource environment references is described
        in the JMS User's Guide
         (Writing JMS operations within an application component /
        Accessing the destination object section).
      </para>
    </section>

    <section xml:id="ejb2.mdb.Admin"><info><title>Administration aspects</title></info>
      
      <para>
      It is assumed at this point that the JOnAS server will make use of an
      existing JMS implementation, e.g., Joram, SwiftMQ.</para>
      
      
      <para>
        The default policy is that the MDB developer and deployer are not
        concerned with JMS administration. This means that the developer/deployer
        will not create or use any JMS Connection factories and will not create a JMS
        destination (which is necessary for performing JMS operations within an EJB
        component, refer to the JMS User's Guide); they will simply define the type of
        destination in the deployment descriptor and identify its JNDI name in the
        JOnAS-specific deployment descriptor, as described in the previous section.
        This means that JOnAS will implicitly create the necessary administered
        objects by using the proprietary administration APIs of the JMS
        implementation (since the administration APIs are not standardized). To
        perform such administration operations, JOnAS uses wrappers to the JMS
        provider administration API. For Joram, the wrapper is
        
          org.objectweb.jonas_jms.JmsAdminForJoram
         (which is the default wrapper
        class defined by the 
          jonas.service.jms.mom
         property in the
        
          jonas.properties
         file). For SwiftMQ, a
        
          com.swiftmq.appserver.jonas.JmsAdminForSwiftMQ
         class can be obtained
        from the 
      <link xlink:href="http://www.swiftmq.com/">
        SwiftMQ
      </link>
         site.
      </para>
      <para>
        For the purpose of this implicit administration phase, the deployer must
        add the 'jms' service in the list of the JOnAS services. For the example
        provided, the jonas.properties file should contain the following:
      </para>
      <screen>
// The jms service must be added
jonas.services                 registry,security,jtm,dbm,jms,ejb
jonas.service.ejb.descriptors  samplemdb.jar
jonas.service.jms.topics       sampleTopic    // not mandatory
      </screen>
      <para>
        The destination objects may or may not pre-exist. The EJB server will not
        create the corresponding JMS destination object if it already exists. (Refer
        also to the JMS administration guide). The 
        <code>
          sampleTopic
        </code>
         should be explicitly
        declared only if the JOnAS Server is going to create it first, even if the
        Message-driven bean is not loaded, or if it is used by another client before
        the Message-driven bean is loaded. In general, it is not necessary to declare
        the 
        <code>
          sampleTopic
        </code>
        .
      </para>
      <para>
        JOnAS uses a 
          pool of threads
         for executing Message-driven
        bean instances on message reception, thus allowing large volumes of messages
        to be processed concurrently. As previously explained, MDB instances are
        stateless and several instances may execute concurrently on behalf of the
        same MDB. The default size of the pool of thread is 10, and it may be
        customized via the jonas property
        
          jonas.service.ejb.mdbthreadpoolsize
        , which is specified in
        the 
          jonas.properties
         file as in the following example:
      </para>
      <screen>
            jonas.service.ejb.mdbthreadpoolsize   50
            
      </screen>
    </section>

    <section xml:id="ejb2.mdb.Running"><info><title>Running a Message-driven Bean</title></info>
      
      <para>
        To deploy and run a Message-driven Bean, perform the following steps:
      </para>
      <itemizedlist>
        <listitem><para>
          Verify that a registry is running.
        </para></listitem>
        <listitem>
          <para>
            Start the Message-Oriented Middleware (the JMS provider
                implementation). Refer to the section "
          <xref linkend="ejb2.mdb.LaunchingMom" />."
          </para>
        </listitem>
        <listitem>
          <para>
            Create and register in JNDI the JMS destination object that will be
                used by the MDB.
          </para>
          <para>
            This can be done automatically by the JMS service or explicitly by the
                proprietary administration facilities of the JMS provider (See JMS administration). 
            The JMS service creates the destination object if
                this destination is declared in the 
              jonas.properties
                file (as specified in the previous section).
          </para>
        </listitem>
        <listitem>
          <para>
            Deploy the MDB component in JOnAS.
          </para>
          <para>
            Note that, if the destination object is not already created when
                deploying an MDB, the container asks the JMS service to create it based
                on the deployment descriptor content.
          </para>
        </listitem>
        <listitem><para>
          Run the EJB client application.
        </para></listitem>
        <listitem><para>
          Stop the application.</para>
              
          <para>
            When using JMS, it is very important to stop JOnAS using the
                
              jonas stop
             command; it should not be stopped directly by
                killing it.
          </para>
        </listitem>
      </itemizedlist>

      <section xml:id="ejb2.mdb.LaunchingMom"><info><title>Launching the Message-OrientedMiddleware</title></info>
        
      <para>
        If the configuration property 
        jonas.services
         contains the jms service, then the JOnAS JMS service will be launched and may try to launch a JMS implementation (a MOM).
      </para>
      <para>
        For launching the MOM, three possibilities can be considered:
      </para>
      <orderedlist>
        <listitem>
      <para>
          Launching the MOM in the same JVM as JOnAS
      </para>
          <para>
            This is the default situation obtained by assigning the     
            <code>
              true
            </code>
             value to the configuration property     
            jonas.service.jms.collocated
             in the     
            jonas.properties
             file.
          </para>
          <screen>
           // The jms service must be in the list
           jonas.services                security,jtm,dbm,jms,ejb
           jonas.service.jms.collocated  true
          </screen>
          <para>
            In this case, the MOM is automatically launched by the JOnAS JMS     service at the JOnAS launching time (command 
            <code>
              jonas     start
            </code>
            ).
          </para>
        </listitem>
        <listitem>
      <para>
          Launching the MOM in a separate JVM
      </para>
          <para>
            The Joram MOM can be launched using the command:
          </para>
          <para>
            <code>
              JmsServer
            </code>
          </para>
          <para>
            For other MOMs, the proprietary command should be used.
          </para>
          <para>
            The configuration property     
            jonas.service.jms.collocated
             must be set to     
            <code>
              false
            </code>
             in the 
            jonas.properties
             file. Setting     this property is sufficient if the JORAM's JVM runs on the same host as     JONAS, and if the MOM is launched with its default options (unchanged     
            a3servers.xml
             configuration file under JONAS_BASE/conf     or JONAS_ROOT/conf if JONAS_BASE not defined).
          </para>
          <screen>
// The jms service must be in the list
jonas.services               security,jtm,dbm,jms,ejb 
jonas.service.jms.collocated false
          </screen>
          <para>
            To use a specific configuration for the MOM, such as changing the     default host (which is localhost) or the default connection port number     (which is 16010), requires defining the additional     
            jonas.service.jms.url
             configuration property as     presented in the following case.
          </para>
        </listitem>
        <listitem>
      <para>
          Launching the MOM on another host
      </para>
          <para>
            This requires defining the 
            jonas.service.jms.url
                 configuration property. When using Joram, its value should be the Joram     URL 
            <code>
              joram://host:port
            </code>
             where 
            <code>
              host
            </code>
             is the host     name, and 
            <code>
              port
            </code>
             is the connection port (by default, 16010).     For SwiftMQ, the value of the URL is similar to the following:     
            <literal>
              smqp://host:4001/timeout=10000
            </literal>
            .
          </para>
          <screen>
// The jms service must be in the list
jonas.services                security,jtm,dbm,jms,ejb
jonas.service.jms.collocated  false
jonas.service.jms.url         joram://host2:16010
 
          </screen>
        </listitem>
      </orderedlist>
      <itemizedlist>
        <listitem>
      <para>
          Change Joram default configuration
      </para>
          <para>
            As mentioned previously, the default host or default connection port     number may need to be changed. This requires modifying the     
            a3servers.xml
             configuration file provided by the JOnAS     delivery in JONAS_ROOT/conf directory. For this, JOnAS must be configured     with the property 
            jonas.service.jms.collocated
             set to     
            <code>
              false
            </code>
            , and the property     
            jonas.service.jms.url
             set to     
            <code>
              joram://host:port
            </code>
            . Additionally, the MOM must have been     previously launched with the JmsServer command. This command defines a     
            <code>
              Transaction
            </code>
             property set to     
            <code>
              fr.dyade.aaa.util.NullTransaction
            </code>
            . If the messages need to     be persistent, replace the     
            <code>
              -DTransaction=fr.dyade.aaa.util.NullTransaction
            </code>
             option with     the 
            <code>
              -DTransaction=fr.dyade.aaa.util.NTransaction
            </code>
             option.     Refer to the Joram documentation for more details about this command. To     define a more complex configuration (e.g., distribution, multi-servers),     refer to the Joram documentation on 
            <link xlink:href="http://joram.objectweb.org">
              http://joram.objectweb.org
            </link>
            .
          </para>
        </listitem>
      </itemizedlist>
       </section>
    </section>

    <section xml:id="ejb2.mdb.Transact"><info><title>Transactional aspects</title></info>
      
      
      <para>
      Because a transactional context cannot be carried by a message (according to
      the EJB 2.0 specification), an MDB will never execute within an existing
      transaction. However, a transaction may be started during the onMessage
      method execution, either due to a "required" transaction attribute
      (container-managed transaction) or because it is explicitly started within
      the method (if the MDB is bean-managed transacted). In the second case, the
      message receipt will not be part of the transaction. In the first case,
      container-managed transaction, the container will start a new transaction
      before de-queueing the JMS message (the receipt of which will, thus, be part
      of the started transaction), then enlist the resource manager associated with
      the arriving message and all the resource managers accessed by the onMessage
      method. If the onMessage method invokes other enterprise beans, the container
      passes the transaction context with the invocation. Therefore, the
      transaction started at the 
        onMessage
       method execution may involve
      several operations, such as accessing a database (via a call to an entity
      bean, or by using a "datasource" resource), or sending messages (by using a
      "connection factory" resource).
      </para>
      
      
    </section>

    <section xml:id="ejb2.mdb.Example"><info><title>Example</title></info>
      
      <para>
           JOnAS provides examples that are located in the 
    examples/src/mdb
     install directory. 
    samplemdb
     is a very simple example, the code of which is used in the previous topics for illustrating how to use Message-driven beans. 
    sampleappli
     is a more complex example that shows how the sending of JMS messages and updates in a database via JDBC may be involved in the same distributed transaction. 
     The following figure illustrates the architecture of this example application. 
        <mediaobject>
          <imageobject>
            <imagedata fileref="../../../../resources/images/eb_img_31.gif"/>
          </imageobject>
        </mediaobject>
      </para>
    <para>
      There are two Message-driven beans in this example:
    </para>
    <itemizedlist>
      <listitem><para>
        <code>
          StockHandlerBean
        </code>
             is a Message-driven bean listening to a topic and receiving Map messages.     The 
        <literal>
          onMessage
        </literal>
         method runs in the scope of a transaction started     by the container. It sends a Text message on a Queue (OrdersQueue) and     updates a Stock element by decreasing the stock quantity. If the stock     quantity becomes negative, an exception is received and the current     transaction is marked for rollback.
      </para></listitem>
      <listitem>
        <para>
          <code>
            OrderBean
          </code>
               is another Message-driven bean listening on the OrdersQueue Queue. On     receipt of a Text message on this queue, it writes the corresponding     String as a new line in a file ("Order.txt").
        </para>
      </listitem>
    </itemizedlist>
    <para>
      The example also includes a CMP entity bean 
      <code>
        Stock
      </code>
       that handles a stock table.
    </para>
    <para>
      A Stock item is composed of a Stockid (String), which is the primary key, and a Quantity (int). The method decreaseQuantity(int qty) decreases the quantity for the corresponding stockid, but can throw a RemoteException "Negative stock."
    </para>
    <para>
      The client application 
      <code>
        SampleAppliClient
      </code>
       is a JMS Client that sends several messages on the topic 
      StockHandlerTopic
      . It uses Map messages with three fields: "CustomerId," "ProductId," "Quantity." Before sending messages, this client calls the 
      <code>
        EnvBean
      </code>
       for creating the 
      StockTable
       in the database with known values in order to check the results of updates at the end of the test. Eleven messages are sent, the corresponding transactions are committed, and the last message sent causes the transaction to be rolled back.
    </para>
    <section><info><title>Compiling this example</title></info>
      
      <para>
        To compile 
        <code>
          examples/src/mdb/sampleappli
        </code>
        , use 
        Ant
         with the 
        <code>
          $JONAS_ROOT/examples/src/build.xml
        </code>
         file.
      </para>
    </section>
    <section><info><title>Running this example</title></info>
      
      <para>
       The default configuration of the JMS service in 
      <code>
        jonas.properties
      </code>
       is the following: 
      </para>
      <screen>
// The jms service must be added
jonas.services                 jmx,security,jtm,dbm,jms,ejb  
jonas.service.ejb.descriptors  sampleappli.jar
jonas.service.jms.topics       StockHandlerTopic
jonas.service.jms.queues       OrdersQueue
jonas.service.jms.collocated   true
      </screen>
      <para>
       This indicates that the JMS Server will be launched in the same JVM as the JOnAS Server, and the JMS-administered objects 
      <code>
        StockHandlerTopic
      </code>
       (Topic) and 
      <code>
        OrdersQueue
      </code>
       (Queue) will be created and registered in JNDI, if not already existing. 
      </para>
      <itemizedlist>
        <listitem><para>
          Run the JOnAS Server. 
          <screen>
jonas start
          </screen>
        </para></listitem>
        <listitem><para>
          Deploy the sampleappli container. 
          <screen>
jonas admin -a sampleappli.jar
          </screen>
        </para></listitem>
        <listitem><para>
          Run the EJB client. 
          <screen>
jclient sampleappli.SampleAppliClient
          </screen>
        </para></listitem>
        <listitem><para>
          Stop the server. 
          <screen>
jonas stop
          </screen>
        </para></listitem>
      </itemizedlist>
    </section>
  </section>
</section>