Copyright © 2008 Red Hat, Inc
Copyright © 2008 Red Hat, Inc. This material may only be distributed subject to the terms and conditions set forth in the Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License (which is presently available at http://creativecommons.org/licenses/by-nc-sa/3.0/).
Red Hat and the Red Hat "Shadow Man" logo are registered trademarks of Red Hat, Inc. in the United States and other countries.
All other trademarks referenced herein are the property of their respective owners.
The GPG fingerprint of the security@redhat.com key is:
CA 20 86 86 2B D6 9D FC 65 F6 EC C4 21 91 80 CD DB 42 A6 0E
1801 Varsity Drive
Raleigh, NC 27606-2072
USA
Phone: +1 919 754 3700
Phone: 888 733 4281
Fax: +1 919 754 3701
PO Box 13588
Research Triangle Park, NC 27709
USA
Sep, 2007
This book is a Reference Guide to Seam 1.2 for JBoss Enterprise Application Platform 4.3.
dataTable
If you spot a typo in this guide, or if you have thought of a way to make this manual better, we would love to hear from you! Submit a report in JIRA against the Product: JBoss Enterprise Application Platform, Version: <version>, Component: Doc. If you have a suggestion for improving the documentation, try to be as specific as possible. If you have found an error, include the section number and some of the surrounding text so we can find it easily.
Seam is an application framework for Java EE 5. It is inspired by the following principles:
JSF and EJB 3.0 are two of the best new features of Java EE 5. EJB3 is a brand new component model for server side business and persistence logic. Meanwhile, JSF is a great component model for the presentation tier. Unfortunately, neither component model is able to solve all problems in computing by itself. Indeed, JSF and EJB3 work best used together. But the Java EE 5 specification provides no standard way to integrate the two component models. Fortunately, the creators of both models foresaw this situation and provided standard extension points to allow extension and integration of other solutions.
Seam unifies the component models of JSF and EJB3, eliminating glue code, and letting the developer think about the business problem.
Seam supports two open source JSF-based AJAX solutions: ICEfaces and Ajax4JSF. These solutions let you add AJAX capability to your user interface without the need to write any JavaScript code.
Seam also provides a built-in JavaScript remoting layer for EJB3 components. AJAX clients can easily call server-side components and subscribe to JMS topics, without the need for an intermediate action layer.
Neither of these approaches would work well, were it not for Seam's built-in concurrency and state management, which ensures that many concurrent fine-grained, asynchronous AJAX requests are handled safely and efficiently on the server side.
Optionally, Seam integrates transparent business process management via jBPM. You won't believe how easy it is to implement complex workflows using jBPM and Seam.
Seam even allows definition of presentation tier conversation flow by the same means.
JSF provides an incredibly rich event model for the presentation tier. Seam enhances this model by exposing jBPM's business process related events via exactly the same event handling mechanism, providing a uniform event model for Seam's uniform component model.
Seam provides a uniform component model. A Seam component may be stateful, with the state associated to any one of a number of contexts, ranging from the long-running business process to a single web request.
There is no distinction between presentation tier components and business logic components in Seam. It is possible to write Seam applications where "everything" is an EJB. This may come as a surprise if you are used to thinking of EJBs as coarse-grained, heavyweight objects that are a pain in the backside to create! However, EJB 3.0 completely changes the nature of EJB from the point of view of the developer. An EJB is a fine-grained object - nothing more complex than an annotated JavaBean. Seam even encourages you to use session beans as JSF action listeners!
Unlike plain Java EE or J2EE components, Seam components may simultaneously access state associated with the web request and state held in transactional resources (without the need to propagate web request state manually via method parameters). You might object that the application layering imposed upon you by the old J2EE platform was a Good Thing. Well, nothing stops you creating an equivalent layered architecture using Seam - the difference is that you get to architect your own application and decide what the layers are and how they work together.
We are all used to the concept of declarative transaction management and J2EE declarative security from EJB 2.x. EJB 3.0 even introduces declarative persistence context management. These are three examples of a broader problem of managing state that is associated with a particular context, while ensuring that all needed cleanup occurs when the context ends. Seam takes the concept of declarative state management much further and applies it to application state. Traditionally, J2EE applications almost always implement state management manually, by getting and setting servlet session and request attributes. This approach to state management is the source of many bugs and memory leaks when applications fail to clean up session attributes, or when session data associated with different workflows collides in a multi-window application. Seam has the potential to almost entirely eliminate this class of bugs.
Declarative application state management is made possible by the richness of the context model defined by Seam. Seam extends the context model defined by the servlet spec—request, session, application—with two new contexts—conversation and business process—that are more meaningful from the point of view of the business logic.
The notion of Inversion of Control or dependency injection exists in both JSF and EJB3, as well as in numerous so-called "lighweight containers". Most of these containers emphasize injection of components that implement stateless services. Even when injection of stateful components is supported (such as in JSF), it is virtually useless for handling application state because the scope of the stateful component cannot be defined with sufficient flexibility.
Bijection differs from IoC in that it is dynamic, contextual, and bidirectional. You can think of it as a mechanism for aliasing contextual variables (names in the various contexts bound to the current thread) to attributes of the component. Bijection allows auto-assembly of stateful components by the container. It even allows a component to safely and easily manipulate the value of a context variable, just by assigning to an attribute of the component.
Optionally, Seam applications may take advantage of workspace management, allowing users to freely switch between different conversations (workspaces) in a single browser window. Seam provides not only correct multi-window operation, but also multi-window-like operation in a single window!
EJB 3.0 embraces annotations and "configuration by exception" as the easiest way to provide information to the container in a declarative form. Unfortunately, JSF is still heavily dependent on verbose XML configuration files. Seam extends the annotations provided by EJB 3.0 with a set of annotations for declarative state management and declarative context demarcation. This lets you eliminate the noisy JSF managed bean declarations and reduce the required XML to just that information which truly belongs in XML (the JSF navigation rules).
Seam components, being POJOs, are by nature unit testable. But for complex applications, unit testing alone is insufficient. Integration testing has traditionally been a messy and difficult task for Java web applications. Therefore, Seam provides for testability of Seam applications as a core feature of the framework. You can easily write JUnit or TestNG tests that reproduce a whole interaction with a user, exercising all components of the system apart from the view (the JSP or Facelets page). You can run these tests directly inside your IDE, where Seam will automatically deploy EJB components into the JBoss Embeddable EJB3 container.
Seam works in any application server that supports EJB 3.0. You can even use Seam in a servlet container like Tomcat, or in any J2EE application server, by leveraging the new JBoss Embeddable EJB3 container.
However, we realize that not everyone is ready to make the switch to EJB 3.0. So, in the interim, you can use Seam as a framework for applications that use JSF for presentation, Hibernate (or plain JDBC) for persistence and JavaBeans for application logic. Then, when you're ready to make the switch to EJB 3.0, migration will be straightforward.
It turns out that the combination of Seam, JSF and EJB3 is the simplest way to write a complex web application in Java. You won't believe how little code is required!
In this tutorial, we'll assume that you are using JBoss AS 4.2 with Seam, as in the case of JBoss Enterprise Application Platform.
The directory structure of each example in Seam follows this pattern:
Web pages, images and stylesheets may be found in examples/
registration/view
Resources such as deployment descriptors and data import scripts may be found in examples/
registration/resources
Java source code may be found in examples/
registration/src
The Ant build script is examples/
registration/build.xml
First, make sure you have Ant correctly installed, with $ANT_HOME and $JAVA_HOME set correctly. Next, make sure you set the location of your JBoss AS installation in the build.properties file in the root folder of your Seam installation. If you haven't already done so, start JBoss AS now by typing bin/run.sh or bin/run.bat in the root directory of your JBoss installation.
By default the examples will deploy to the default configuration of the server. These examples should be deployed to the production configuration if they are to be used with JBoss Enterprise Application Platform 4.2, and the example build.xml file should be modified to reflect this before building and deploying. Two lines should be changed in this file:
<property name="deploy.dir" value="${jboss.home}/server/production/deploy"/>
<property name="webroot.dir"
value="${deploy.dir}/jboss-web.deployer/ROOT.war"/>
Now, build and deploy the example by typing ant deploy in the examples/ directory.
registration
Try it out by accessing http://localhost:8080/seam-registration/ with your web browser.
First, make sure you have Ant correctly installed, with $ANT_HOME and $JAVA_HOME set correctly. Next, make sure you set the location of your Tomcat installation in the build.properties file in the root folder of your Seam installation.
Now, build and deploy the example by typing ant deploy.tomcat in the examples/ directory.
registration
Finally, start Tomcat.
Try it out by accessing http://localhost:8080/jboss-seam-registration/ with your web browser.
When you deploy the example to Tomcat, any EJB3 components will run inside the JBoss Embeddable EJB3 container, a complete standalone EJB3 container environment.
The registration example is a fairly trivial application that lets a new user store his username, real name and password in the database. The example isn't intended to show off all of the cool functionality of Seam. However, it demonstrates the use of an EJB3 session bean as a JSF action listener, and basic configuration of Seam.
We'll go slowly, since we realize you might not yet be familiar with EJB 3.0.
The start page displays a very basic form with three input fields. Try filling them in and then submitting the form. This will save a user object in the database.
The example is implemented with two JSP pages, one entity bean and one stateless session bean.
Let's take a look at the code, starting from the "bottom".
We need an EJB entity bean for user data. This class defines persistence and validation declaratively, via annotations. It also needs some extra annotations that define the class as a Seam component.
@Entity
@Name("user")
@Scope(SESSION)
@Table(name="users")
public class User implements Serializable
{
private static final long serialVersionUID = 1881413500711441951L;
private String username;
private String password;
private String name;
public User(String name, String password, String username)
{
this.name = name;
this.password = password;
this.username = username;
}
public User() {}
@NotNull @Length(min=5, max=15)
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
@NotNull
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
@Id @NotNull @Length(min=5, max=15)
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
}
|
The EJB3 standard |
|
A Seam component needs a component name specified by the |
|
Whenever Seam instantiates a component, it binds the new instance to a context variable in the component's default context. The default context is specified using the |
|
The EJB standard |
|
|
|
An empty constructor is both required by both the EJB specification and by Seam. |
|
The |
|
The EJB standard |
The most important things to notice in this example are the @Name and @Scope annotations. These annotations establish that this class is a Seam component.
We'll see below that the properties of our User class are bound to directly to JSF components and are populated by JSF during the update model values phase. We don't need any tedious glue code to copy data back and forth between the JSP pages and the entity bean domain model.
However, entity beans shouldn't do transaction management or database access. So we can't use this component as a JSF action listener. For that we need a session bean.
Most Seam application use session beans as JSF action listeners (you can use JavaBeans instead if you like).
We have exactly one JSF action in our application, and one session bean method attached to it. In this case, we'll use a stateless session bean, since all the state associated with our action is held by the User bean.
This is the only really interesting code in the example!
@Stateless
@Name("register")
public class RegisterAction implements Register
{
@In
private User user;
@PersistenceContext
private EntityManager em;
@Logger
private Log log;
public String register()
{
List existing = em.createQuery(
"select username from User where username=#{user.username}")
.getResultList();
if (existing.size()==0)
{
em.persist(user);
log.info("Registered new user #{user.username}");
return "/registered.jsp";
}
else
{
FacesMessages.instance().add("User #{user.username} already exists");
return null;
}
}
}
|
The EJB standard |
|
The |
|
The EJB standard |
|