<document>
<deftable>
web.xml configuration
The course bean
The swap stateless session bean
The swap stateless session interface
The swap servlet
</deftable> CREATE TABLE ejb3_xa_courses ( id INTEGER PRIMARY KEY auto_increment, course VARCHAR(250), teacher VARCHAR(250) ); INSERT INTO basic_courses VALUES('Potions', 'Severus Snape'); INSERT INTO basic_courses VALUES('Transfiguration', 'Minerva McGonagall');

The Course is identical to the basic field bean. It uses FIELD enhancement to define the database columns. @Entity(access=FIELD) @Table(name="ejb3_xa_courses") public class Course { @Id(generate=AUTO) @Column(name="id") private int _id; @Basic @Column(name="course") private String _course; @Basic @Column(name="teacher") private String _teacher; }

import static javax.ejb.TransactionAttributeType.REQUIRED; @javax.ejb.Stateless(name="swap") public class SwapBean implements Swap { @javax.ejb.TransactionAttribute(REQUIRED) public void swap(Course a, Course b) { String teacher = a.getTeacher(); a.setTeacher(b.getTeacher()); b.setTeacher(teacher); } }

The TransactionAttribute marks the transaction type of the method. The two most common types are REQUIRED and SUPPORTS. A REQUIRED method expects to modify the data and wants to ensure the update is consistent. A SUPPORTS method will only read data, so it can avoid the overhead of a transaction.

A transaction is the database equivalent of a `synchronized` lock. Transactions are somewhat more complicated locks because they need to work with multiple machines and possibly multiple databases, but they're still just sophisticated locks. The typical transaction patterns are similar to familiar lock patterns.

A REQUIRED attribute tells Resin that the method must be protected by a transaction. In this case, the swap needs protection from simultaneous threads trying to swap at the same time.

A SUPPORTS attribute would tell Resin that the method doesn't need a transaction, but the method should join any transaction that already exists.

import javax.ejb.EntityManager; import javax.transaction.UserTransaction; public class CourseServlet extends HttpServlet { @javax.ejb.Inject private EntityManager _manager; @javax.ejb.Inject private UserTransaction _uTrans; @javax.ejb.EJB(name="swap") private Swap _swap; ... private void doService(PrintWriter out) throws Exception { CourseBean []course = new CourseBean[2]; course[0] = (CourseBean) _manager.find("CourseBean", new Integer(1)); course[1] = (CourseBean) _manager.find("CourseBean", new Integer(2)); // swap the courses using the session bean _swap.swap(course[0], course[1]); // swap using a user transaction _uTrans.begin(); try { String teacher = course[0].getTeacher(); course[0].setTeacher(course[1].getTeacher()); course[1].setTeacher(teacher); } finally { _uTrans.commit(); } } }

The servlet needs to lookup the EntityManager, UserTransaction, and the Swap bean in JNDI.

<deftable>
ObjectJNDI
EntityManagerjava:comp/EntityManager
UserTransactionjava:comp/UserTransaction
Swapjava:comp/env/ejb/swap
</deftable>

Since Resin's servlets understand the EJB 3.0 injection annotations, the tutorial can just annotate the setters and let Resin configure them. In other cases, it may be necessary to put the JNDI lookup in the servlet's `init()` method.

The first swap in the tutorial switches the teachers using a stateless session bean.

<example> // swap the courses using the session bean _swap.swap(course[0], course[1]);

Because the `swap` method was marked as transaction REQUIRED, Resin will start a transaction if none already exists. If the method exits cleanly, Resin will commit the transaction. If the method throws a RuntimeException, Resin will roll the transaction back.

The `swap` method will throw a runtime exception if the transaction fails to commit. For example, the databse might detect a deadlock and roll the transaction back.

The second swap in the tutorial restores the teachers using the underlying `UserTransaction`. It's essentially identical to the work that the transaction REQUIRED swap method provides. In fact, Resin implements the REQUIRED annotation using UserTransaction.

<example> _uTrans.begin(); try { String teacher = course[0].getTeacher(); course[0].setTeacher(course[1].getTeacher()); course[1].setTeacher(teacher); } finally { _uTrans.commit(); }

The main differences between the two are the added capabilities of the REQUIRED.

- REQUIRED automatically rolls back on a RuntimeException
- REQUIRED joins any existing transaction. In contrast, UserTransaction throws an exception if called in a transaction.

</document>