Lightweight application frameworks are all the rage in the enterprise Java community in the past couple of years. From the pioneering Spring and Hibernate frameworks, to the infusion of technologies like aspect-oriented programming and metadata annotation, to the new standard EJB 3.0 (and Java EE 5.0) specifications, lightweight frameworks have gradually become mainstream. The rise of lightweight technologies was largely due to developers' rebellion against the "heavyweight" of EJB 2.1 (and earlier). Lightweight frameworks aim to make developers more productive and the application less error-prone by removing the rigid EJB 2.1 infrastructure classes/interfaces and excessive XML deployment descriptors (commonly known as "XML hell" in EJB 2.1). Beyond that, lightweight frameworks have also promoted better and cleaner application architectures, and make it easier to reuse business components when you switch vendors.
The core principle shared by all lightweight enterprise Java frameworks is the use of plain old Java objects (POJOs) for the data access and business logic. There are no more infrastructure classes or interfaces to inherit or implement. You just create a POJO to model your data or to implement a business process using the data. Then the POJOs are "wired" together using metadata. For instance, you can wire a POJO to a container service that maps the object to an entry in a relational database; you can wire a POJO method to a transactional service to guarantee the atomicy of its database operations or to a security service to limit access to the method; you can also wire POJOs together with each other. A key technique in the wiring of POJOs is a design pattern called Dependency Injection (DI). DI uses the lightweight framework container (e.g., a Spring container or an EJB 3.0 container) to inject services or other objects into a POJO. This way, all object instances are created and managed by the container. There is no need for each POJO to manage the life cycle of its service objects or to look up services. DI eliminates a lot of boilerplate code in applications and makes them easier to understand and maintain.
The major differences between lightweight frameworks are how they wire container services together and implement Dependency Injection. The service architecture and metadata expression are the key issues here. In this issue of JDJ, Chris Richardson, author of Manning's new POJO in Action book, explains how popular lightweight frameworks such as Spring, Hibernate and EJB 3.0 deliver services to POJOs.
While different lightweight frameworks support different metadata syntax for POJO wiring, developers naturally still want to reuse POJOs across frameworks. In his "Spring and EJB 3.0 in Harmony" article, Aleš Justin, an avid Spring and JBoss user, explores how to write a Spring deployer in JBoss. Using the deployer, you can deploy Spring POJOs side-by-side with EJB 3.0 POJOs in the JBoss Application Server. Very cool!
Now, Spring, Hibernate, and EJB 3.0 are lightweight frameworks for the enterprise middle tier. They are great for implementing business and persistence logic. However, to use them in Web applications, you often still need to provide your own integration code with the servlet/Struts/JSF-driven Web tier. Can we use business POJOs directly in the Web tier? In the Spring world, the Spring MVC framework is a relatively new Web framework that works well with Spring business POJOs. What about the standard-based EJB 3.0 world? Is there a framework that allows developers to write complete Web applications using EJB 3.0-style POJOs and annotations? The answer is the JBoss Seam framework. To understand Seam, let's look at a very simple Hello World application: it has a simple Web page where you can enter your name to "say hello" to Seam. When you click submit, your name is added to the database and the page displays all persons who have said hello so far. The application requires only three simple components. First, write an EJB 3.0 entity bean, the Greeter class, to represent a greeter (i.e., the data model). The @Entity annotation tells the container that the Greeter POJO is automatically mapped to a relational database table. The @Name annotation specifies that Seam manages the Greeter instances under the name "greeter". When other application components request an instance of the Greeter bean from Seam, they should use the name "greeter".
@Entity
@Name("greeter")
public class Greeter implements Serializable {
private long id;
private String name;
@Id(generate=AUTO)
public long getId() { return id;}
public void setId(long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
The Web page looks like the following. Notice that the textfield is mapped to the Seam-managed Greeter entity bean via the name "greeter". When a user enters a value in the text field, Seam automatically creates a Greeter instance encapsulating the user input. When the user submits the form, the event handler method manager.sayHello() is invoked by Seam. This method is defined in an EJB 3.0 session bean POJO under the Seam name "manager", which we will discuss next.
<h:form>
Please enter your name:<br/>
<h:inputText value="#{greeter.name}" size="15"/><br/>
<h:commandButton type="submit" value="Say Hello"
action="#{manager.sayHello}"/>
</h:form>
The event handler session bean, ManagerAction, has a Seam name "manager" as described above, so that it can be referenced in the JSF page. Via the @In annotation, Seam automatically injects the managed Greeter POJO, which has Seam name "greeter', into the ManagerAction property of the same name. The "greeter" object is already populated with the user input from the JSF page. The sayHello() method saves the entity bean POJO to the database and retrieves the current list of greeters, which is out-jected into the Seam context via the @Out annotation.
@Stateless
@Interceptors(SeamInterceptor.class)
@Name("manager")
public class ManagerAction implements Manager {
@In
private Greeter greeter;
@Out
private List <Greeter> allGreeters;
@PersistenceContext
private EntityManager em;
public String sayHello () {
em.persist (greeter);
allGreeters = em.createQuery("from Greeter g").getResultList();
return null;
}
}
Since the allGreeters list is out-jected into theSeam context, the JSF page can refer to it and display the name list.
<p>The following persons have said "hello" to JBoss Seam:</p>
<h:dataTable value="#{allGreeters}" var="person">
<h:column>
<h:outputText value="#{person.name}"/>
</h:column>
</h:dataTable>
Now, you can see JBoss Seam is a powerful glue that connects EJB 3.0 POJOs and JSF pages. It also expands the dependency injection pattern into a bi-directional injection. As a result, everything is managed by the Seam context and developers can focus on their core business logic, which is the ultimate goal of any lightweight Java framework. In addition, the Seam context also manages HTTP session state and even workflow in external business process engines (e.g., the jBPM engine). Norman Richards, author of JBoss Developer's Notebook and XDoclet in Action, will tell you more about how Seam makes it super easy to develop stateful Web applications in his article "Seam: The Next Evolution of Web Applications."
By all indications, lightweight technologies are the future of enterprise Java. Learn it, master it, and use it in your best-of-breed new Internet applications!