This section presents some programming restrictions and rules for using JMS operations within entity components.
Depending on the JMS implementation and the application, it may be desirable to keep the JMS connections open for the life of the bean instance or for the duration of the method call. These two programming modes are illustrated in the following example (this example illustrates a stateful Session Bean):
public class EjbCompBean implements SessionBean { ... QueueConnectionFactory qcf = null; Queue queue = null; public void ejbCreate() { .... ictx = new InitialContext(); qcf = (QueueConnectionFactory) ictx.lookup("java:comp/env/jms/conFactSender"); queue = (Queue) ictx.lookup("java:comp/env/jms/queue1"); } public void doSomethingWithJMS (...) { ... Connection conn = qcf.createConnection(); Session session = conn.createSession(...); ... // JMS operations session.close(); conn.close(); } ... } |
To keep the connection open during the life of a bean instance, the programming style shown in the following example is preferred, since it avoids many connection opening and closing operations:
public class EjbCompBean implements SessionBean { ... ConnectionFactory qcf = null; Queue queue = null; Connection conn = null; public void ejbCreate() { .... ictx = new InitialContext(); cf = (ConnectionFactory) ictx.lookup("java:comp/env/jms/conFactSender"); queue = (Queue) ictx.lookup("queue1"); conn = cf.createConnection(); } public void doSomethingWithJMS (...) { ... Session session = conn.createSession(...); ... // JMS operations session.close(); } public void ejbRemove() { conn.close(); } ... } |
Be aware that maintaining JMS objects in the bean state is not always possible, depending on the type of bean.
For a stateless Session Bean, the bean state is not maintained across method calls. Therefore, the JMS objects should always be initialized and defined in each method that performs JMS operations.
For an Entity Bean, an instance may be passivated, and only the persistent part of the bean state is maintained. Therefore, it is recommended that the JMS objects be initialized and defined in each method performing JMS operations. If these objects are defined in the bean state, they can be initialized in the ejbActivate method (if the connection is created in the ejbActivate method, be sure to close it in the ejbPassivate method).
For a stateful Session Bean (as shown in the previous example), JMS objects can be defined in the bean state. Stateful Session Bean instances can be passivated (not in the current version of JOnAS, but it is scheduled for the summer of 2004). Since connection factories and destinations are serializable objects, they can be initialized only in ejbCreate. However, be aware that a connection must be closed in ejbPassivate (with the state variable set to null) and recreated in ejbActivate.
Note that, due to a known problem with the Sun JDK 1.3 on Linux, the close of the connection can block. The problem is fixed with JDK 1.4.
Currently, it is not possible to start a bean-managed transaction after the creation of a JMS session and have the JMS operations involved in the transaction. In the following code example, the JMS operations will not occur within the ut transaction:
public class EjbCompBean implements SessionBean { ... public void doSomethingWithJMS (...) { ... Connection conn = cf.createConnection(); Session session = conn.createSession(...); ut = ejbContext.getUserTransaction(); ut.begin(); ... // JMS operations ut.commit(); session.close(); conn.close(); } ... } |
To have the session operations involved in the transaction, the session creation and close should be inside the transaction boundaries, and the connection creation and close operations can either be both outside the transaction boundaries or both inside the transaction boundaries, as follows:
public class EjbCompBean implements SessionBean { ... public void doSomethingWithJMS (...) { ... Connection conn = qcf.createConnection(); ut = ejbContext.getUserTransaction(); ut.begin(); Session session = conn.createSession(...); ... // JMS operations session.close(); ut.commit(); conn.close(); } ... } |
or
public class EjbCompBean implements SessionBean { ... public void doSomethingWithJMS (...) { ... ut = ejbContext.getUserTransaction(); ut.begin(); Connection conn = cf.createConnection(); Session session = conn.createSession(...); ... // JMS operations session.close(); conn.close(); ut.commit(); } ... } |
Programming EJB components with bean-managed transactions can result in complex code. Using container-managed transactions can help avoid problems such as those previously described.