Book Image

Java EE 7 Developer Handbook

By : Peter A. Pilgrim
Book Image

Java EE 7 Developer Handbook

By: Peter A. Pilgrim

Overview of this book

<p>The seventh edition of the Enterprise Java platform is aimed at helping Java engineers take advantage of the advancements in HTML5 and web standards. Web Sockets, asynchronous input and output with Servlets, and strong type safety through the CDI containers will ensure that Java EE 7 remains popular for server-side applications.<br />If you are a user aiming to get acquainted with the Java EE 7 platform, this book is for you.</p> <p>"Java EE 7 Developer Handbook" provides a solid foundation of knowledge for developers to build business applications. Following the lead of Agile practices, there is a focus on writing tests to demonstrate test-driven development principles, using the embedded GlassFish 4.0 container examples and the Gradle build system. You will learn about CDI, EJB, JPA, JMS, MDB, Servlets, WebSocket, JAX-RS, Bean Validation, and so much more.</p> <p>"Java EE 7 Developer Handbook" is designed as a companion to the professional software developer who quickly needs to lookup some working code, understand the basics of the framework, and then go out and fulfill the business contract with the customer. Typically, engineers are under pressure to develop professional code that is of high quality and contains a low number of bugs. Java EE 7 Developer Handbook relies heavily on the Arquillian framework to illustrate how much easier it is to write Java EE tests, and together with the modern practice of writing containerless applications that actually embed an application container, developing agile Java EE suddenly becomes reasonable, smart, pragmatic, and achievable.</p> <p>You will start off with an overview of the Java EE platform: the containers, the design, and architecture. From there, you can follow the path of the CDI, the true gem of the framework, and then the server side end point, EJB. It is completely up to you when and if you want to learn about Java persistence. However, don’t miss out on the highlights of Java EE 7 such as WebSocket, Bean Validation, and asynchronous Servlet API.</p> <p>"Java EE 7 Developer Handbook" is a vertical slice through standard Java enterprise architecture. If you have been wondering why developers have invested so much time and effort into learning topics such as Enterprise Java Beans, you will quickly understand why when you find out the difference between stateful and stateless Beans. Best of all, this book covers the topic from the perspective of new API and new modern practices. For instance, you, the developer and designer, are expected to write applications with annotations in comparison with J2EE. Java EE 7 Developer Handbook incorporates helpful hints and tips to get the developer up to speed in a short amount of time on EJB, CDI, Persistence, Servlet, JMS, WebSocket, JAX-RS and Bean Validation, and much more.</p> <p>"Java EE 7 Developer Handbook" is the reference guide you need beside you at your desk.</p>
Table of Contents (23 chapters)
Java EE 7 Developer Handbook
Credits
About the Author
Acknowledgment
About the Reviewers
www.PacktPub.com
Preface
Index

Transaction services


JTA provides transaction support to EJB and now in Java EE 7 to CDI managed beans annotated with @Transactional. The EJB specification provides declarative services to session and singleton beans. In the EJB container, the transactions are either Container-Managed Transactions (CMT) or Bean-Managed Transactions (BMT).

Container-Managed Transactions (CMT)

Container-Managed Transactions are normally annotated on EJBs with the declaration @javax.ejb.TransactionAttribute. This annotation can be applied to the type or to individual methods. It accepts a @javax.ejb.TransactionAttributeType enumeration value.

For CDI managed beans the JTA 1.2 specification provides a brand new annotation @javax.transactional.Transactional, to elevate ordinary POJOs into the transactional instances. The annotation accepts a nested enumerated class @javax.transactional.Transactional.TxType as a value.

Transaction demarcation in the older J2EE specification was outlined in an XML deployment descriptor (/META-INF/ejb-jar.xml) as part of the EJB module. It is still possible to override annotated EJBs with customized transaction service and using XML.

We now outline the CMT services available in Java EE 7 in the following table:

TransactionAttribute or TxType

Description

REQUIRED

The container or interceptor creates a new transaction upon entering the target method, if there is no existing transaction already. Upon completion of the target method, it commits the transaction. This is the default transaction attribute value.

REQUIRES_NEW

The container or interceptor always creates a new transaction before entering the target method. Upon completion it commits the transaction.

MANDATORY

The container or interceptor expects an existing transaction to be already in effect before entering the method. If this is not the case, the EJB container raises an exception EJBTransactionRequired or CDI interceptor throws a TransactionalException exception with nested TransactionRequiredException.

SUPPORTS

The container or interceptor effectively performs no special operations because the target method is invariant to the existence of a current transaction. If a transaction exists, then the target method is invoked in a transactional scope. Otherwise it is invoked without a transaction context. On return from the target method, any preceding transaction context will remain in effect.

NOT_SUPPORTED

The container or interceptor disassociates any transaction context, if it exists, before calling the target method. Upon return from the target method, any proceeding transaction context is re-associated with the thread context, which preserves consistency to those operations.

NEVER

The container or interceptor will only execute the target if there is no associated and existing transaction context. If there is a transaction context, then the EJB container will raise EJBException or the CDI interceptor throws a TransactionalException with nested InvalidTransactionException.

CDI managed beans that take part in CMT rely on the existence of a dedicated interceptor that lies behind the scenes handling the transactional services and communicates with JTA and Java Transaction Services (JTS). This implementation-defined interceptor is provided by Java EE 7 product.

Container-managed EntityManager instances must be JTA types so that they can join transactions.

Bean-Managed Transactions (BMT)

Bean-managed transactions are types of transactions where the application EJB or CDI managed bean takes control of transaction management itself. First of all, UserTransaction is injected into the bean or it is retrieved by dependency lookup through JNDI.

For EJB that are using legacy J2EE constraint that you are upgrading to Java EE 7, it may help to inject javax.ejb.EJBContext as a resource. Working with the BMT is a matter of working with the UserTransaction object. Ensure that you demarcate the transaction boundaries accordingly with the begin() call. At the end of the transaction, either you call commit() for normal termination or call rollback() for abnormal circumstances.

Here is a stateless session bean that demonstrates how to apply the transaction services:

@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class InvoiceServiceBMT {
  @Resource EJBContext context;

  public Invoice saveInvoice( Invoice invoice ) throws Exception { 
      UserTransaction tx = context.getUserTransaction();
    try {
      tx.begin();
      em.persist(invoice);
      tx.commit();
    } catch (Exception e) {
      tx.rollback();
    }
    return invoice;
  }
  /* ... */
}

To achieve BMT, we declare the EJB InvoiceServiceBMT with the @TransactionManagement annotation with the value BEAN to override the default value CONTAINER. Inside the method, we explicitly create a new transaction context and execute the necessary business logic.

We can also achieve a halfway house solution, where the EJB is still known to the container, but it creates its own transaction context. Here is an alternative implementation:

@Stateless
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public class InvoiceServiceBMTAlt {
  @Resource EJBContext context;

  public Invoice saveInvoice( Invoice invoice ) 
  throws Exception { /* same impl */ }
  /* ... */
}

We set transaction context to SUPPORTS, because it is immaterial whether this InvoiceServiceBMTAlt has an existing transaction context or not before the saveInvoice() target method is called. Inside the method, we create a new transaction context. So effectively this BMT bean is creating its own REQUIRES_NEW feature.

The same technique can be achieved with CDI managed beans by injecting the @UserTransaction object instance. CDI managed beans, by default, do not take part in EJB transactions, and therefore @TransactionManagement does not apply to them.

Bean-managed EntityManager instances must be either JTA or non-JTA types. If they are of the latter type then they cannot participate in JTA transactions.

Isolation levels

Isolation levels are an important part of transaction management, because they allows administrators to configure interference between concurrency operations in the enterprise application. Transaction isolation affects the overall consistency. There are different levels of isolation, namely: dirty reads, non-repeatable reads, phantom reads, and serializable. To understand these levels, one needs at least two concurrent transactions: TX1 and TX2.

A dirty read occurs when a transaction TX1 reads uncommitted changes made by another concurrency transaction TX2. The situation is especially unpalatable when TX2 roll backs it transaction, which means that TX1 reads something it shouldn't have.

A non-repeatable read occurs when a transaction TX1 reads shared data, at least twice, in order of sequence for time intervals: t1 and t3. Where t1 happens before t2, which happens before t3. The other concurrent transaction TX2 meanwhile updates shared data at time interval t2 and then commits, thereby invalidating TX1 second read at time interval t3.

A phantom read occurs when a transaction TX1 reads shared data at least twice in order of sequence time intervals t1 and t3 just like an unrepeatable read. Except this time, the number of rows read by TX at t1 is [A1] and at t3 they are [A1, A2]. Meanwhile, the other concurrent transaction TX2 inserts a new row of data [A2] at time interval t2 and commits, which causes the ghostly apparition: a phantom record.

When two transactions like TX1 and TX2 are sequentially processed, one after the other, such that there is no such of interference, their concurrency operations are then serializable.

JDBC provides four transaction isolation levels: Read Uncommited, Read Committed, Repeatable Read, and Serializable. Depending on the level chosen they will eliminate the issues around dirty reads, non-repeatable reads, and phantom reads.

The following diagram describes the various isolation levels:

JDBC allows a Java application to query the isolation level of the database through the java.sql.Connection and the getTransactionIsolation() method. An application can also call setTransactionIsolation() to set up a new isolation, say from TRANSACTION_READ_COMMITTED to TRANSACTION_SERIALIZABLE as long as the database server and the JDBC driver can support it.

For a Java SE application this is acceptable, however, for Java EE application the data sources and entity manager configurations are generally shared across EJB and web modules. Changing the resource dependencies programmatically can lead to trouble for shared applications and modules. Java EE 7 products typically furnish an administration console, which allow a data source's isolation levels to be configured at deployment.

Here is a summary of the isolation levels and their impact on consistency:

Isolation Level

Dirty Reads

Non-Repeatable Reads

Phantom Reads

READ_UNCOMMITED

Can occur

Can occur

Can occur

READ_COMMITED

Prevented

Can occur

Can occur

REPEATABLE_READ

Prevented

Prevented

Can occur

SERIALIZABLE

Prevented

Prevented

Prevented

Generally, for Java EE 7 applications that inject EntityManagers and DataSource instance, it may be unwise to configure isolation level programmatically.

Nevertheless, there are some techniques to show and here is one that unwraps the JDBC connection behind EntityManager:

@Stateless 
public class ReceiptGenerator {
  @PersistenceContext("mastersAtWorkDB")
  EntityManager em;
  
  public void generateReceipt() {
    em.flush();
    Connection conx = em.unwrap(Connection.class);
    int savedLevel = conx.getTransactionLevel();
    conx.setTransactionLevel(Connection.TRANSACTION_SERIALIZABLE);
    doMoreWork();
    em.flush();
    conx.setTransactionLevel(savedLevel);
    /* ... */
  }
  /* ... */
}

The entity manager's unwrap method allows the application to gain access to the vendor provider classes for the JPA implementation. In the example, we only want access to the JDBC connection. Given vendor provider like Hibernate JPA, we could reveal EntityManager and retrieve Hibernate's session object instance using the unwrap facility. There are inherent dangers to changing isolation levels in mid flow with concurrency transaction operations, because we are reliant on the JPA provider's synchronization pending instances to the database at the time of the flush() calls.

In summary, JPA in the form of Java EE 7 does not support custom isolation levels. However, different vendors of JPA providers and Java EE 7 products do provide extensions, which may be configured through an additional XML deployment descriptor and annotations. The buck stops with the underlying database server and isolation levels that they actually do support. For example, if you use Oracle and attempt to configure REPEATABLE_READ, it will downgrade the isolation level to READ_COMMITTED instead (http://docs.oracle.com/cd/B12037_01/server.101/b10743/consist.htm#i5702).

JNDI lookup

Developers can always perform a dependency lookup of the current transaction context. The UserTransaction instance inside a Java EE application is as follows:

InitialContext jndiContext = new InitialContext();
UserTransaction tx = jndiContext.lookup(
  "java:comp/UserTransaction")

The preceding example of code is found commonly in legacy J2EE applications based on JDK 1.4 and predates Java annotations.

This concludes the section on Java EE 7 transactions.