BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles Introduction to JBoss Seam

Introduction to JBoss Seam

This item in japanese

Bookmarks
This article is an edited, InfoQ-exclusive excerpt of chapters 1 and 2 from the soon-to-be-released book JBoss Seam: Power and Flexibility Beyond Java EE 5.0 by Michael Yuan and Thomas Heute.

What is Seam?

JBoss Seam is a "lightweight framework for Java EE 5.0". What does that mean? Isn't Java EE (Enterprise Edition) 5.0 itself a collection of "frameworks"? Why do you need another one that is outside of the official specification? Well, we view Seam as the "missing framework" that should have been included in Java EE 5.0. It sits on top of Java EE 5.0 frameworks to provide a consistent and easy-to-understand programming model for all components in an enterprise web application. It also makes stateful applications and business process-driven applications a breeze to develop. In another words, Seam is all about developer productivity and application scalability.

1. Integrate and Enhance Java EE Frameworks

The core frameworks in Java EE 5.0 are EJB (Enterprise JavaBeans) 3.0 and JSF (JavaServer Faces) 1.2. EJB 3.0 (EJB3, hereafter) is a POJO (Plain Old Java Objects) based lightweight framework for business services and database persistence. JSF is a MVC (Model-View-Controller) component framework for web applications. Most Java EE 5.0 web applications will have both EJB3 modules for business logic and JSF modules for the web front end. However, while EJB3 and JSF are complementary to each other, they are designed as separate frameworks each with its own philosophy. For instance, EJB3 uses annotations to configure services, while JSF makes use of XML files. Furthermore, EJB3 and JSF components are not aware of each other at the framework level. To make EJB3 and JSF work together, you need artificial facade objects (i.e., JSF backing beans) to tie business components to web pages, and boilerplate code (a.k.a plumbing code) to make method calls across framework boundaries. Gluing those technologies together is part of Seam's responsibilities.

Seam collapses the artificial layer between EJB3 and JSF. It provides a consistent, annotation-based approach to integrate EJB3 and JSF. With a few simple annotations, the EJB3 business components in Seam can now be used directly to back JSF web forms or handle web UI events. Seam allows developers to use the "same kind of stuff", annotated POJOs, for all application components. Compared with applications developed in other web frameworks, Seam applications are conceptually simple and require significantly less code (both in Java and XML) for the same functionalities. If you are impatient and want a quick preview of how simple a Seam application is, you can have a look at the hello world example described lower in this article.

Seam also makes it easy to accomplish tasks that were "difficult" on JSF. For instance, one of the major complaints of JSF is that it relies too much on HTTP POST. It is hard to bookmark a JSF web page and then get it via HTTP GET. Well, with Seam, generating a bookmarkable RESTful web page is very easy. Seam provides a number JSF component tags and annotations that would increase the "web friendliness" and web page efficiency of JSF applications.

At the same time, Seam expands the EJB3 component model to POJOs and brings the stateful context from the web tier to the business components. Furthermore, Seam integrates a number of leading other open source frameworks such as jBPM, JBoss Rules (a.k.a Drools), JBoss Portal, JBoss Microcontainer etc. Seam not only "wire them together" but also enhance the frameworks in similar ways it does to the JSF + EJB3 combination.

While Seam is rooted in Java EE 5.0, its application is not limited to Java EE 5.0 servers. Your Seam applications can be deployed in J2EE 1.4 application servers as well as in plain Tomcat servers. That means you can obtain production support for your Seam applications today!

1 + 1 > 2

It would be a mistake to think that Seam is just another integration framework that wires various frameworks together. Seam provides its own managed stateful context that allows the frameworks to deeply integrate with others via annotations, EL (Expression Language) expressions etc. That level of integration comes from Seam developer's intimate knowledge of the third party frameworks.

2. A Web Frameworks that Understands ORM

Object Relational Mapping (ORM) solutions are widely used in today's enterprise applications. However, most current business and web frameworks are not designed for ORM. They do not manage the persistence context over the entire web interaction lifecycle from the request comes in to the response is fully rendered. That has resulted in all kinds of ORM errors included the dreaded LazyInitializationException, and gave rise to ugly hacks like the "Data Transfer Object" (DTO).

Seam was invented by Gavin King, the inventor of the most popular ORM solution in the world (Hibernate). It is designed from the ground up to promote ORM best practices. With Seam, there is no more DTOs to write; lazy loading just works; and the ORM performance can be greatly improved since the extended persistence context acts as a natural cache to reduce database round trips.

Furthermore, since Seam integrates the ORM layer with the business and presentation layer, we can display ORM objects direct, you can even use database validator annotations on input forms , and redirect ORM exceptions to custom error pages.

3. Designed for Stateful Web Applications

Seam is designed for stateful web applications. Web applications are inherently multi-user applications, and e-commerce applications are inherently stateful and transactional. However, most existing web application frameworks are geared toward stateless applications. You have to fiddle with the HTTP session objects to manage user states. That not only clutters your application with code un-related to the core business logic, but also brings on an array of performance issues.

In Seam, all the basic application components are inherently stateful. They are much easier to use than the HTTP session since their states are declaratively managed by Seam. There is no need to write distracting state management code in a Seam application -- just annotate the component with its scope, lifecycle methods, and other stateful properties -- and Seam takes over the rest. Seam stateful components also provide much finer control over user states than the plain HTTP session does. For instance, you can have multiple "conversations", each consisting of a sequence of web requests and business method calls, in a HTTP session.

Furthermore, database caches and transactions can be automatically tied with the application state in Seam. Seam automatically holds database updates in memory and only commits to the database at the end of a conversation. The in-memory cache greatly reduces database load in complex stateful applications.

In addition to all the above, Seam takes state management in web applications a big step further by supporting integration with the Open Source JBoss jBPM business process engine. You can now specify the work flows of different people in the organization (i.e., customers, managers, technical support etc.) and use the work flow to drive the application, instead of relying on the UI event handlers and databases.

4. Web 2.0 Ready

Seam is fully optimized for Web 2.0 style applications. It provides multiple ways for AJAX (Asynchronous JavaScript And XML, a technology to add interactivity to web pages) support -- from drop-in JavaScript-less AJAX components, AJAX-enabling existing JSF components, to a custom JavaScript library that provide direct access to Seam server components from the browser as Javascript objects. Internally, Seam provides an advanced concurrency model to efficiently manage multiple AJAX requests from the same user.

A big challenge for AJAX applications is the increased database load. An AJAX application makes much more frequent requests to the server than its non-AJAX counterpart does. If all those AJAX requests have to be served by the database, the database would not be able to handle the load. The stateful persistence context in Seam acts as an in-memory cache. It can hold information throughout a long running conversation, and hence helps to reduce the database round trips.

Web 2.0 applications also tend to employ complex relational models for its data (e.g., a social network site is all about managing and presenting the relationships between "users"). For those sites, lazy loading in the ORM layer is crucial. Otherwise, a single query could cascade to loading the entire database. As we discussed earlier, Seam is the only web framework today that supports lazy loading correctly for web applications.

5. POJO Services via Dependency Bijection

Seam is a "lightweight framework" because it promotes the use of POJO (plain old Java objects) as service components. There are no framework interfaces or abstract classes to "hook" components into the application. The question, of course, is how do those POJOs interact with each other to form an application? How do they interact with container services (e.g., the database persistence service)?

Seam wires POJO components together using a popular design pattern known as "dependency injection" (DI). Under this pattern, the Seam framework manages the lifecyle of all the components. When a component needs to use another, it declares this dependency to Seam using annotations. Seam determines where to get this dependent component based on the application's current state and "injects" it into the asking component.

Expanding on the dependency injection concept, a Seam component A can also create another component B and "outjects" the created component B back to Seam for other components, such as C, to use later.

This type of bi-directional dependency management is widely used in even the simplest Seam web applications (e.g., the hello world example in Chapter 2). In Seam terms, we call this "dependency bijection".

6. Configuration by Exception

The key design principal that makes Seam so easy to use is "Configuration by exception". The idea is to have a set of common-sense default behavior for the components. The developer only needs to configure the component explicitly when the desired behavior is not the default. For instance, when Seam injects component A as a property of component B, the Seam name of component A defaults to the recipient property name in component B. There are many little things like that in Seam. The overall result is that configuration metadata in Seam is much simpler than competing Java frameworks. As a result, most Seam applications can be adequately configured with a small number of simple Java annotations. Developers benefit from reduced complexity and, in the end, much less lines of code for the same functionalities developed in competing frameworks.

7. Avoid XML Abuse

As you probably noticed, Java annotations play a crucial role in expressing and managing Seam configuration metadata. That is done by design to make the framework easier to work with.

In the early days of J2EE, XML was viewed as the "holy grail" for configuration management. Framework designers throw all kinds of configuration information, including Java class and method names, in XML files without much thought about the consequence to developers. In retrospect, that was a big mistake. XML configuration files are highly repetitive. They have to repeat information already in the code in order to connect the configuration to the code. Those repetitions make the application prone to minor errors (e.g., a mis-spelled class name would show up as an hard-to-debug error at runtime). The lack of reasonable default configuration settings further compounds this problem. In fact, in some frameworks, the amount of boilerplate code disguised as XML may rival or even exceed the amount of actual Java code in the application. For J2EE developers, this abuse of XML is commonly known as the "XML hell".

The enterprise Java community recognizes this problem with XML abuse and has very successful attempts to replace XML files with annotations in Java source code. EJB3 is the effort by the official Java standardization body to promote the use of annotations in enterprise Java components. EJB3 makes XML files completely optional, and it is definitely a step toward the right direction. Seam adds to EJB3 annotations and expands the annotation-based programming model to the entire web application.

Of course, XML is not entirely bad for configuration data. Seam designers recognize that XML is well-suited to specify web application pages flows or define business process work flows. The XML file allows us to centrally manage the work flow for the entire application, as opposed to scatter the information around in Java source files. The work flow information has little coupling with the source code -- and hence the XML files do not need to duplicate typed information already available in the code.

8. Designed for Testing

Seam is designed from ground up for easy testing. Since all Seam components are just annotated POJOs, they are very easy to unit test. You can just create instances of the POJOs using the regular Java new keyword and then run any methods in your testing framework (e.g., JUnit or TestNG). If you need to test the interaction between multiple Seam components, you can instantiate those components individually and then setup their relationships manually (i.e., use the setter methods explicitly instead of relying on Seam's dependency injection features).

For integrated testing of the entire Seam application, it is a little more complex since you have to run the application inside a Seam container. Seam comes with an embeddable lightweight container that helps this type of testing. In your test framework, you can load the Seam container programatically and then run the tests.

9. Great Tools Support

Tools support is crucial for an application framework that focuses on developer productivity. Seam is distributed with a command line application generator called Seam Gen. Seam Gen closely resembles the tools available in Ruby-On-Rails. It supports features like generating complete CRUD applications from a database, quick developer turn around for web applications via the "edit / save / reload browser" actions, testing support etc.

But more importantly, Seam Gen generated projects work out-of-the-box with leading Java IDEs such as Eclipse and NetBeans. With Seam Gen, you can get started with Seam in no time!

10. Let's Start Coding!

In a nutshell, Seam simplifies the developer overhead for Java EE applications, and at the same time, adds powerful new features beyond Java EE 5.0. In this next section (excerpted from chapter 2 in the book), we will show you some real code examples to illustrate how Seam works.  You can find the source code download for all example applications in the book from the book web site http://www.michaelyuan.com/seam/.

Seam Hello World

The most basic and widely used functionality of JBoss Seam is to be the glue between EJB3 and JSF. Seam allows seamless (no pun intended!) integration between the two frameworks through managed components. It extends the EJB3 annotated POJO (plain old Java objects) programming model to the entire web application. There is no more artificially required JNDI lookup, verbose JSF backing bean declaration, excessive facade business methods, and painstakingly passing objects between tiers etc.

Continue to use Java EE patterns in Seam

In traditional Java EE applications, some design patterns, such as JNDI lookup, XML declaration of components, value objects, business facade, are mandatory. Seam eliminates those artificial requirements with annotated POJOs. However, you are still free to use those patterns when they are truely needed in your Seam applications.

Writing a Seam web application is conceptually very simple. You just need to code the following components:

  • Entity objects represent the data model. The entity objects could be entity beans in the Java Persistence API (JPA, a.k.a, EJB3 persistence) or Hibernate POJOs. They are automatically mapped to relational database tables.
  • JSF web pages display the user interface. The pages capture user input via forms and display result data. The form fields and data display tables are mapped to entity beans or collections of entity beans.
  • EJB3 session beans or annotated Seam POJOs act as UI event handlers for the JSF web pages. They process user input encapsulated in entity beans and generate data objects for display in the next step (or page).

All the above components are managed by Seam and they are automatically injected into the right pages / objects at runtime. For instance, when the user clicks a button to submit a JSF form, Seam automatically parses the form fields and constructs an entity bean. Then, Seam passes the entity bean into the event handler session bean, which is also created by Seam, for processing. You do not need to manage component lifecycles and relationships between components in your own code. There is no boilerplate code and no XML file for dependency management.

In this chapter, we use a hello world example to show exactly how Seam glues together a web application. The example application works like this: The user can enter her name on a web form to "say hello" to Seam. Once she submits, the application saves her name to a relational database and displays all the users that have said hello to Seam. The example project is in the HelloWorld folder in the source code download for this book. To build it, you must have Apache ANT 1.6+ (http://ant.apache.org/) installed. Enter the helloworld directory and run the command ant. The build result is the build/jars/helloworld.ear file, which you can directly copy into your JBoss AS instance's server/default/deploy directory. Now, start JBoss AS, and the application is available at the URL http://localhost:8080/helloworld/.

Install JBoss AS

To run examples in the book, we recommend you to use the JEMS (JBoss Enterprise Middleware Suite) GUI installer to install a Seam-compatible version of JBoss AS. The JEMS installer can be downloaded from http://labs.jboss.com/portal/jemsinstaller/downloads. Please refer to Appendix A, Install and Deploy JBoss AS if you need further help on JBoss AS installation and application deployment.

You are welcome to use the sample application as a template to jump start your own Seam projects (see Appendix B, Use Example Applications as Templates). Or, you can use the command line tool Seam Gen (see Chapter 4, Rapid Application Development Tools) to automatically generate project templates, including all configuration files, for you. In this chapter, we will not spend too much time explaining the details of the directory structure in the source code project. Instead, we focus on the code and configuration artifacts a developer must write or manage to build a Seam application. This way, you can apply the knowledge to any project structure without being confined to our template.

Source Code Directories

A Seam application consists of Java classes and XML/text configuration files. In the book's example projects, the Java source code files are in the src directory, the web pages are in the view directory, and all configuration files are in the resources directory. See more in Appendix B, Use Example Applications as Templates.

1.  Create a Data Model

The data model in the hello world application is simply a Person class with a name and an id property. The @Entity annotation tells the container to map this class to a relational database table, with each property a column in the table. Each Person instance corresponds to a row of data in the table. Since Seam is "configuration by exception", the container simply uses the class name property name for the table name and column name. The @Id and @GeneratedValue annotations on the id property indicates that the id column is for the primary key and its value is automatically generated by the application server for each Person object saved into the database.

@Entity
@Name("person")
public class Person implements Serializable {

private long id;
private String name;

@Id @GeneratedValue
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 most important annotation in the Person class is the @Name annotation. It specifies the string name the Person bean should be registered under Seam. In other Seam components (e.g., pages and session beans), you can reference the managed Person bean for this component using the "person" name.

2. Map the Data Model to a Web Form

In the JSF page, we use the Person bean to back the form input text field. The #{person.name} symbol refers to the name property on the Seam component named "person", which is an instance of the Person entity bean.

<h:form>
Please enter your name:<br/>
<h:inputText value="#{person.name}" size="15"/><br/>
<h:commandButton type="submit" value="Say Hello"
action="#{manager.sayHello}"/>
</h:form>

Below the entry form, the JSF page displays all people who has said "hello" to Seam in the database. The list of people is stored in a Seam component named "fans". The fans component is a List <Person> object. The JSF dataTable iterates through the list and displays each Person object in a row. The fan symbol is the iterator for the fans list. Figure 2.1, The Hello World web page shows the web page.

<h:dataTable value="#{fans}" var="fan">
<h:column>
<h:outputText value="#{fan.name}"/>
</h:column>
</h:dataTable>

Figure 2.1. The Hello World web page

When the user clicks on the "Say Hello" button to submit the form, Seam creates the person managed component with the input data. It then invokes the sayHello() method on Seam component named "manager" (i.e., #{manager.sayHello} is the UI event handler for the form submit button), which saves the person object to the database and refreshes the fans list. The manager component is an EJB3 session bean and we will discuss it in the next section.

3. Handle Web Events

The manager component in Seam is the ManagerAction session bean, as specified by the @Name annotation on the class. The ManagerAction class has person and fans fields annotated with the @In and @Out annotations.

@Stateless
@Name("manager")
public class ManagerAction implements Manager {

@In @Out
private Person person;

@Out
private List <Person> fans;

The @In and @Out annotations are at the heart of the Seam programming model. So, let's look at exactly what they do here.

  • The @In annotation tells Seam to assign the person component, which is composed from the JSF form data, to the person field (dependency injection) before executing any method in the session bean. You can specify an arbitrary name for the injected component in @In. But if there is no named specified, as it is here, Seam will just inject the component with the same type and same name as the receiving field variable.
  • The @Out annotations tell Seam to assign values of the fans and person fields to the managed components of the same names after any method execution. We call this action "dependency outjection" in Seam. This way, in the ManagerAction.sayHello() method, we simply need to update the fans and person field values and they will be automatically available on the web page.

    What is bijection

    In Seam documentation, you sometimes see the term "bijection". That refers to the two-way injection and outjection interaction between Seam components and the Seam managed context.

    Since the person field already contains the form data via injection, the sayHello() method simply saves it to the database via the JPA EntityManager, which is injected via the @PersistenceContext annotation. Then it refreshes the fans and person objects, which are outjected after the method exits. The sayHello() returns null to indicate that the current JSF page will be re-displayed with the most up-to-date model data after the call.

      @PersistenceContext
    private EntityManager em;

    public String sayHello () {
    em.persist (person);
    person = new Person ();
    fans = em.createQuery("select p from Person p")
    .getResultList();

    return null;
    }

    We are almost done, except for one little thing. As you probably noticed, the ManagerAction bean class implements the Manager interface. In order to conform to the EJB3 session bean specification, we need an interface that lists all the business methods in the bean. Below is the code for the Manager interface. Fortunately, it is easy to automatically generate this interface from any modern IDE tool.

    @Local
    public interface Manager {
    public String sayHello ();
    }

    That is all the code you need for the Hello World example. In the next two sections, we cover alternative ways to do things and the configuration of Seam applications. You can skip the rest of the chapter for now if you want to jump right into the code and customize the helloworld project for your own small database application.

    4. Better Understand the Seam Programming Model

    Now we have rushed through the Hello World example application. But we have left off some important topics, such as alternative ways to do things and important features not covered by the above code. In this section, let's go through those topics. They help you gain a deeper understanding of Seam. But for the impatient, you can skip this section and come back later.

    4.1. Seam POJO Components

    In the above example, we used an EJB3 session bean to implement the application logic. But we are not limited to use EJB3 components in Seam. In fact, in Seam, any POJO with a @Name annotation can be turned into a managed component.

    For instance, we can make ManagerAction a POJO instead of a EJB3 session bean.

    @Name("manager")
    public class ManagerAction {

    @In (create=true)
    private EntityManager em;

    ... ...
    }

    Using POJOs to replace EJB3 beans has pros and cons. POJOs are slightly simpler to program since they do not require EJB3-specific annotations and interfaces (see above). If all your business components are Seam POJOs, you can run your Seam application outside of the EJB3 application server (see Chapter 23, Seam Without EJB3).

    However, POJOs also have less features than EJB3 components since POJOs cannot get EJB3 container services. Examples of EJB3 services you lose in non-EJB3 Seam POJOs include the following.

    • The @PersistenceContext injection no longer works in POJOs. In order to obtain an EntityManager in a Seam POJO, you have to initialize the EntityManager in Seam configuration file and then use the Seam @In annotation to inject it into the POJO.
    • There is no support for declarative method-level transaction in POJOs. Instead, you can configure Seam to demarcate a database transaction from when the web request is received until the response page is rendered.
    • Seam POJOs cannot be message-driven components.
    • No support for @Asynchronous methods.
    • No support for container managed security.
    • No transaction or component level persistence contexts. All persistence contexts in Seam POJOs are "extended" (see Section 7.1,"The Default Conversation Scope" for more details).
    • No integration into the container's management architecture (ie. JMX console services).
    • No Java remoting (RMI) into Seam POJO methods.
    • Seam POJOs cannot be @WebService components.
    • No JCA integration.

    So, why would anyone want to use POJO components when deploying in an EJB3 container? Well, POJO components are good for pure "business logic" components, which delegate data access, messaging, and other infrastructure functionalities to other components. For instance, we can use POJO components to manage Seam data access objects.  The "business logic" POJO is useful since they can be re-used in other frameworks if you need to. But all in all, their application is much smaller than EJB3 components, especially in small to middle sized applications. So, in most examples throughout this book, we use EJB3 components.

    4.2. Ease of Testing

    As we mentioned in Chapter 1, What is Seam, Seam is built from ground up to enable easy and out-of-the-container testing. In the helloworld project, we included two test cases for unit testing and integrated JSF testing in the test folder. The Seam testing infrastructure mocks the database, JSF, Seam context, and other application server services in plain Java SE environment. Just run ant test to run those tests.

    4.3. Getter / Setter Based Bijection

    In the Hello World example, we demonstrated how to biject Seam components against field variables. You can also biject components against getter and setter methods. For instance, the following code would work just fine.

    private Person person;
    private List <Person> fans;

    @In
    public void setPerson (Person person) {
    this.person = person;
    }
    @Out
    public Person getPerson () {
    return person;
    }
    @Out
    public List <Person> getFans () {
    return fans;
    }

    While the above getter / setter methods are trivial, the real value of bijection via getter / setter methods is that you can add custom logic to manipulate the bijection process. For instance, you can validate the injected object or retrieve the outjected object on the fly from the database.

    4.4. Avoid Excessive Bijection

    Dependency bijection is a very useful design pattern. However, like any other design pattern, there is always a danger of overusing it. Too much dependency bijection can make the code harder to read since the developer must mentally figure out where each component is injected from. Too much bijection could also adds performance overhead since the bijection happens at runtime.

    In the Hello World example, there is a simple way to reduce and even eliminate the bijection: just make the data components properties of the business component. This way, in the JSF pages, we only need to reference the business component and there is no bijection needed to tie the business and data components. For instance, we can change the ManagerAction class to the following.

    @Stateless
    @Name("manager")
    public class ManagerAction implements Manager {

    private Person person;
    public Person getPerson () {return person;}
    public void setPerson (Person person) {
    this.person = person;
    }

    private List <Person> fans;
    public List<Person> getFans () {return fans;}

    ... ...
    }

    Then, on the web page, we reference the properties as follows.

    <h:form>

    Please enter your name:<br/>

    <h:inputText value="#{manager.person.name}"/>
    <br/>
    <h:commandButton type="submit" value="Say Hello"
    action="#{manager.sayHello}"/>
    </h:form>
    ... ...
    <h:dataTable value="#{manager.fans}" var="fan">
    <h:column>
    <h:outputText value="#{fan.name}"/>
    </h:column>
    </h:dataTable>

    The bottom line is that Seam is versatile when it comes to dependency management. It is generally a good practice to encapsulate the data component with its data access business component. This is especially the case for stateful business components.

    4.5. Page navigation in JSF

    In this example, we have a single page application. After each button click, JSF re-renders the page with updated data model values. Obviously, most web applications would have more than one page. In JSF, an UI event handler method can determine which page to display next by returning the string name of a navigation rule. For instance, you can define the following navigation rule in the navigation.xml file.

    <navigation-case>
    <from-outcome>anotherPage</from-outcome>
    <to-view-id>/anotherPage.jsp</to-view-id>
    </navigation-case>

    Then, if the sayHello() method returns the string value "anotherPage", JSF would display the anotherPage.jsp page next. This gives us programatic control over which page to display next from inside the UI event handler method.

    4.6. Access database via the EntityManager

    The JPA (Java Persistence API, a.k.a EJB3 Entity Bean Persistence) EntityManager manages the mapping between relational database tables and entity bean objects. The EntityManager is created by the application server at runtime. You can inject an EntityManager instance using the @PersistenceContext annotation.

    The EntityManager.persist() method saves an entity bean object as a row in its mapped relational table. The EntityManager.query() method runs an SQL-like query to retrieve data from the database in the form of a collection of entity bean objects. Please refer to the JPA documentation for more on how to use the EntityManager and the query language. In this book, we only use the simplest queries.

    By default, the EntityManager saves data to the embedded HSQL database. If you are running the application in JBoss AS on the local machine, you can open a GUI console for the HSQL database via the following steps: go to page http://localhost:8080/jmx-console/, click on the database=localDB,service=Hypersonic MBean, and then click on the "invoke" button under the startDatabaseManager method. You can execute any SQL commands against the database from the console.

    5. Configuration and Packaging

    Next, let's move on to configuration files and application packaging next. You can actually generate almost all the configuration files and build script via the Seam Gen command line utility, or you can simply reuse the ones in the sample application source project. So, if you want to learn Seam programming techniques first and worry about configuration / deployment later, that is fine. You can safely skip this section and come back later when you need it.

    In this section, we focus on the Seam EJB3 component configuration here. Seam POJO configuration and deployment outside of JBoss AS is of course also possible.

    Most Seam configuration files are XML files. But wait! Hadn't we just promised that Seam would get us out of the "XML hell" in J2EE and Spring? How come it has XML files too? Well, as it turns out, there are some good uses for XML files! XML files are very good for deployment time configuration (e.g., the root URL of the web application and the location of the backend database) because it allows us to make deploy-time changes without changing and re-compiling the code; they are good for gluing different sub-systems in the application server together (e.g., to configure how JSF components interacts with Seam EJB3 components); XML files are also good for presentation related content (e.g., the web page and page navigation flow).

    What we are against is to replicate information already exist in the Java source code to XML files. As you will soon see, this simple Seam application has several XML configuration files. All of them are very short and none of them concerns information already available in the Java code. In another word, there is no "XML code" in Seam.

    Furthermore, most content in those XML files are fairly static. So, you can easily reuse those files for your own Seam applications. Please refer to Appendix B, Use Example Applications as Templates for instructions on how to use the sample application as a template for your own applications.

    We will use the next several pages to detail the configuration files and packaging structure of the sample application. If you are impatient and are happy with the application template, you can skip those. Anyway, without further ado, let's look into how the hello world example application is configured and packaged. To build a deployable Seam application for JBoss AS, we have to package all the above Java classes and configuration files in an Enterprise Application aRchive (EAR) file. In this example, the EAR file is helloworld.ear. It contains three JAR files and two XML configuration files.

    helloworld.ear
    |+ app.war // Contains web pages etc.
    |+ app.jar // Contains Seam components
    |+ jboss-seam.jar // The Seam library
    |+ META-INF
    |+ application.xml
    |+ jboss-app.xml

    Source Code Directories

    In the source code project, the resources/WEB-INF directory contains the configuration files that go into app.war/WEB-INF; the resources/META-INF directory contains files that go into app.jar/META-INF and helloworld.ear/META-INF; the resources directory root has files that go into the root directory of app.jar.

    The application.xml file lists the JAR files in the EAR and specifies the root URL for this application.

    <application>
    <display-name>Seam Hello World</display-name>

    <module>
    <web>
    <web-uri>app.war</web-uri>
    <context-root>/helloworld</context-root>
    </web>
    </module>

    <module>
    <ejb>app.jar</ejb>
    </module>

    <module>
    <java>jboss-seam.jar</java>
    </module>

    </application>

    The jboss-app.xml file specifies the class loader for this application. Each EAR application should have a unique string name for the class loader. Here, we use the application name in the class loader name to avoid repetition.

    <jboss-app>
    <loader-repository>
    helloworld:archive=helloworld.ear
    </loader-repository>
    </jboss-app>

    The jboss-seam.jar file is the Seam library JAR file from the Seam distribution. The app.war and app.jar files are built by us. So, let's look into the app.war and app.jar files next.

    5.1. The WAR file

    The app.war file is a JAR file packaged to the Web Application aRchive (WAR) specification. It contains the web pages as well as standard JSF / Seam configuration files. You can also put JSF-specific library files in the WEB-INF/lib directory (e.g., the jboss-seam-ui.jar).

    app.war
    |+ hello.jsp
    |+ index.html
    |+ WEB-INF
    |+ web.xml
    |+ faces-config.xml
    |+ components.xml
    |+ navigation.xml

    The web.xml file is required by all Java EE web applications. JSF uses it to configure the JSF controller servlet and Seam uses it intercept all web requests. The configuration in this file is pretty standard.

    <web-app version="2.4"
    xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="..."
    xsi:schemaLocation="...">

    <!-- Seam -->
    <listener>
    <listener-class>
    org.jboss.seam.servlet.SeamListener
    </listener-class>
    </listener>

    <!-- MyFaces -->
    <listener>
    <listener-class>
    org.apache.myfaces.webapp.StartupServletContextListener
    </listener-class>
    </listener>

    <context-param>
    <param-name>
    javax.faces.STATE_SAVING_METHOD
    </param-name>
    <param-value>client</param-value>
    </context-param>

    <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>
    javax.faces.webapp.FacesServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Faces Servlet Mapping -->
    <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.seam</url-pattern>
    </servlet-mapping>
    <context-param>
    <param-name>javax.faces.CONFIG_FILES</param-name>
    <param-value>/WEB-INF/navigation.xml</param-value>
    </context-param>
    </web-app>

    The faces-config.xml file is a standard configuration file for JSF. Seam uses it to add the Seam interceptor into the JSF lifecycle.

    <faces-config>

    <lifecycle>
    <phase-listener>
    org.jboss.seam.jsf.SeamPhaseListener
    </phase-listener>
    </lifecycle>

    </faces-config>

    The navigation.xml file contains JSF page navigation rules for multi-page applications. Since the hello world example only has a single page, this file is empty here.

    The components.xml file contains Seam-specific configuration options. It is also pretty much application-independent with the exception of the jndi-pattern property, which must include the EAR file's base name for Seam to access EJB3 beans by their full JNDI name.

    <components ...>

    <core:init
    jndi-pattern="helloworld/#{ejbName}/local"
    debug="false"/>

    <core:manager conversation-timeout="120000"/>

    </components>

    5.2. The Seam Components JAR

    The app.jar file contains all EJB3 bean classes (both entity beans and session beans), as well as EJB3 related configuration files.

    app.jar
    |+ Person.class // entity bean
    |+ Manager.class // session bean interface
    |+ ManagerAction.class // session bean
    |+ seam.properties // empty file but needed
    |+ META-INF
    |+ ejb-jar.xml
    |+ persistence.xml

    The seam.properties file is empty here but it is required for JBoss to know that this JAR file contains Seam EJB3 bean classes, and process the annotations accordingly.

    The ejb-jar.xml file contains extra configurations that can override or supplement the annotations on EJB3 beans. In a Seam application, it adds the Seam interceptor to all EJB3 classes. We can reuse the same file for all Seam applications.

    <ejb-jar>
    <assembly-descriptor>
    <interceptor-binding>
    <ejb-name>*</ejb-name>
    <interceptor-class>
    org.jboss.seam.ejb.SeamInterceptor
    </interceptor-class>
    </interceptor-binding>
    </assembly-descriptor>
    </ejb-jar>

    The persistence.xml file configures the backend database source for the EJB3 entity beans. In this example, we just use the default HSQL database embedded inside JBoss AS (i.e., the java:/DefaultDS data source).

    <persistence>
    <persistence-unit name="helloworld">
    <provider>
    org.hibernate.ejb.HibernatePersistence
    </provider>
    <jta-data-source>java:/DefaultDS</jta-data-source>
    <properties>
    <property name="hibernate.dialect"
    value="org.hibernate.dialect.HSQLDialect"/>
    <property name="hibernate.hbm2ddl.auto"
    value="create-drop"/>
    <property name="hibernate.show_sql" value="true"/>
    </properties>
    </persistence-unit>
    </persistence>

    So, that's all the configuration and packaging a simple Seam application needs. We will cover more configuration options and library files as we move to more advanced topics in this book. Again, the simplest way to start your Seam application is not to worry about those configuration files at all and start from a ready-made application template.

    6. How is this Simple?

    That's it for the hello world application. With three simple Java classes, a JSF page, and a bunch of largely static configuration files, we have a complete database driven web application. The entire application requires less than 30 lines of Java code and no "XML code". However, if you are coming from a PHP background, you might still be asking: "How is this simple? I can do that in PHP with less code!"

    Well, the answer is that Seam applications are conceptually much simpler than PHP (or any other scripting language) applications. The Seam component model allows us to add more functionalities to the application in a controlled and maintainable manner. As we will soon see, Seam components make it a breeze to develop stateful and transactional web applications. The object-relational mapping framework (i.e., entity beans) allows us to focus on the abstract data model without having to deal with database-specific SQL statements.

    This article was based on an excerpt from chapters 1 and 2 - in the rest of this book, we will discuss how to develop increasingly complex Seam applications using Seam components. See also the table of contents showing all the topics in the book.

    See also two interviews with Seam creator Gavin King, from previous news articles about Seam:

    About the author

    Dr. Michael Yuan is the author of JBoss Seam: Simplicity and Power Beyond Java EE 5.0 - a book on next generation web application frameworks. He is also the author of Nokia Smartphone Hacks and other 3 technology books. Michael specializes in lightweight enterprise / web application, and end-to-end mobile application development. You can contact him via his blog.

    Rate this Article

    Adoption
    Style

    Hello stranger!

    You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

    Get the most out of the InfoQ experience.

    Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

    Community comments

    • should be,,,

      by Ohtani Shinpei,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      >JBoss Seam is a new full-stack web application framework that unifies and integrates Ajax, JSF, EJB2, Portlets, and BPM.

      should be EJB3, not EJB2, isn't it?

    • Testing seams incomplete

      by Matt Raible,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      The testing section "seams" incomplete: ;-)


      For integrated testing of the entire Seam application, it is a little more complex since you have to run the application inside a Seam container. Seam comes with an embeddable lightweight container that helps this type of testing. In your test framework, you can load the Seam container programatically and then run the tests. For more details on embeddable Seam container, please refer to

      Refer to what?

    • Re: should be,,,

      by Michael Yuan,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Yes, it should be EJB3 NOT EJB2. Floyd, can you make the change?

      It is important to note that Seam expands the "programming model" of EJB3 to POJOs -- so it can run outside of the EJB3 container as well. See more here and here.

    • Re: Testing seams incomplete

      by Michael Yuan,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Oh that refers to the chapters 20 and 21 of the book. I will fix the link.

      But to get a taste of how out-of-container testing work in Seam, check out the "examples/booking" project in the Seam distro. Run "ant test" and see the tests (unit tests and integrated tests with JSF EL) running in the console. Out-of-container testing is automatically supported in Seam Gen generated projects.

    • Seam Case Study

      by Stefane Fermigier,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      In case you have missed it during the JBossWorld Conference in Berlin, here is a case study of a "real life" application built with JBoss Seam:

      "Nuxeo EP 5 Open Source Enterprise Content Management - A Seam Case Study" On Slideshare

      Same, as PDF

    • Injections through configuration

      by AdiSesha Reddy,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Clean and impressive introduction to Seam.
      Is there any option to manage injections through configuration file rather than through annotations?-Adi

    • Re: Testing seams incomplete

      by Floyd Marinescu,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Hi Michael, sorry about that - messed up on the editting, will fix immediately, and also 'ejb 3'

    • Re: Injections through configuration

      by Michael Yuan,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Is there any option to manage injections through configuration file rather than through annotations?


      The components.xml file allows you to inject some of the Seam built-in components into each other via XML configuration (e.g., inject an EntityManager into a Seam CRUD DAO object). However, so far, there is no generic way to inject arbitary user-defined component via XML (we believe annotation is a lot easier to use).

      But, in Seam 1.2, we plan to support Spring integration. That would allow you to make Seam components available as Spring beans.

    • Re: Testing seams incomplete

      by Michael Yuan,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Hi Michael, sorry about that - messed up on the editting, will fix immediately, and also 'ejb 3'


      Thanks Floyd!

    • Re: Injections through configuration

      by Gavin King,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Is there any option to manage injections through configuration file rather than through annotations?


      We consider "configuration" to be a separate problem to bijection, in that configuration should happen statically when components are instantiated, instead of dynamically when they are invoked. So Seam provides the components.xml file format, which lets you do stuff like:

      <components xmlns="http://jboss.com/products/seam/components" 
      xmlns:core="http://jboss.com/products/seam/core"
      xmlns:drools="http://jboss.com/products/seam/drools">

      <drools:rule-base name="ruleBase" rule-files="numberguess.drl"/>
      <drools:managed-working-memory name="workingMemory" rule-base="#{ruleBase}"/>

      <core:jbpm>
      <core:pageflow-definitions>
      <value>pageflow.jpdl.xml</value>
      </core:pageflow-definitions>
      </core:jbpm>

      <core:init debug="true"/>
      <core:microcontainer installed="@microcontainer@"/>

      </components>


      Or even - don't get scared, this is a complex example:

      <components xmlns="http://jboss.com/products/seam/components"
      xmlns:fwk="http://jboss.com/products/seam/framework"
      xmlns:core="http://jboss.com/products/seam/core"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation=
      "http://jboss.com/products/seam/framework jboss.com/products/seam/framework-1.1.xsd
      jboss.com/products/seam/core jboss.com/products/seam/core-1.1.xsd
      jboss.com/products/seam/components jboss.com/products/seam/components-1.1.xsd">

      <factory name="contact" value="#{contactHome.instance}"/>
      <fwk:entity-home name="contactHome"
      entity-class="org.jboss.seam.example.contactlist.Contact"
      entity-manager="#{entityManager}"/>


      <factory name="comment" value="#{commentHome.instance}"/>
      <fwk:entity-home name="commentHome"
      entity-class="org.jboss.seam.example.contactlist.Comment"
      entity-manager="#{entityManager}"
      new-instance="#{newComment}"/>

      <component name="newComment"
      class="org.jboss.seam.example.contactlist.Comment">
      <property name="contact">#{contact}</property>
      <property name="created">#{currentDatetime}</property>
      </component>


      <fwk:entity-query name="contacts"
      max-results="20"
      entity-manager="#{entityManager}">
      <fwk:ejbql>from Contact</fwk:ejbql>
      <fwk:order>lastName</fwk:order>
      <fwk:restrictions>
      <value>lower(firstName) like lower( #{exampleContact.firstName} + '%' )</value>
      <value>lower(lastName) like lower( #{exampleContact.lastName} + '%' )</value>
      </fwk:restrictions>
      </fwk:entity-query>

      <component name="exampleContact"
      class="org.jboss.seam.example.contactlist.Contact"/>

      </components>


      This facility is basically a mix of JSF style configuration, which uses EL for injection of other components, and XML namespace support similar to what you see in Spring 2.0. In Seam, the namespace stuff is stupendously easy to do. You just add one package-level annotation, and write the schema. Done.

    • Re: Injections through configuration

      by AdiSesha Reddy,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Sorry, I should have used 'XML'(the way you specify dependencies,in Spring) instead of 'Configuration'

    • Get rid of the „lightweight”-illusion!

      by Stefan Frank,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      How does a framewok qualify as lightweight?!

      In terms of the jars you need to import to make the framework run? Then seam is definitely not lightweight, as it comes with 30MB of libraries you need to get a hello world to run, the appserver not yet included.

      In terms of the number of things that can go broke?!
      With the sheer number of integrated components (embedded container, drools, jbpm, hibernate etc.) - there are lots of things that can go wrong. Sure, everything works fine when you stay on the path, but if you dare to venture a little left or right, you can get quickly bitten by kernel-exceptions,xfid not founds, empty pages and other strange beasts. Plenty of knobs and levers, plenty of things that can go wrong.

      In terms of configuration?
      Using annotations is a big plus and will get you rid of a lot of configuration you used to do in xml. But there there is still lots of components that have to be configured, and annotations don't go all the way. In a reasonably sized project, you will still end up with a slightly reduced mix of annotations, xml and properties that have to work together.

      In terms of the number of things it does?!
      Then, again, seam does not qualify, as it aims to do everything from simple crud over pdf-generation up to workflow- and rules integration. Sure, all of this is optional, but then again java also qualifies as "lightweight": Nobody ever forced you to do something more meaningful than "Hello World".

      Is the fact that you can use "POJO"'s enough to qualify a framework as lightweight?!
      I doubt that you can really call an annotated pojo, that got treated by cglib and gets hidden behind an aop-framework does really still qualify as pojo. If everything works fine, you may not notice the plumbing, but when your stacktrace brings up several hundred lines of code that show libraries with strange and funny names, the pojo-illusion fades rather quickly...


      Don't get me wrong here, I really love seam and gavin king and the other jboss-people are doing a terrific job at integrating stuff at a breakneck speed, but we should really try to stay honest and strip off the "lightweight"-buzzword from our articles. It is misleading and says absolutely nothing at all about the framework.

    • Re: Get rid of the „lightweight”-illusion!

      by Jim Hazen,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      The author defines lightweight to mean the following...

      There are no framework interfaces or abstract classes to "hook" components into the application.

      This seems to be a pretty common definition of lightweight as applied to frameworks these days. This is in contrast to other frameworks that require the extension of framework classes or the implementation of framework interfaces in order to take advantage of their middleware features. EJB2 is probably the most popular example of a heavyweight framework.

      The lightweightness however, only extends to the weight added to your business codebase. You are correct in observing that many "lightweight" frameworks have dependencies on third party libraries. In some cases, many, many libraries.

      The test here is whether it is possible to swap out middleware providers like Seam for a similar framework (perhaps a WebBeans RI) without modifications to your business code. Also, when it's all said and done, is it possible to package up everything and take it with you? An EAR with a Seam based application can be packaged and moved from one operating environment to another. The business code, like a turtle, can take its house with it (even with the inclusion of many dependent jars). Unlike heavyweight frameworks where your only choice is to move from house to house and make due with whatever accommodations are present when you arrive.

      Also, don't think that lightweight means simple or "doesn't do a lot". Batman's utility belt is lightweight and it provides many things. Lightweight frameworks often do some very heavy lifting and can be quite complex.

      Perhaps the buzzword should be "unobtrusive" or "TD - Transparently Declarative", but it isn't. For whatever reason folks have decided to go with "lightweight" as shorthand for what I've tried to describe above. In the end no matter what buzzword is chosen some people will feel mislead or confused.

      I do agree though that some people tout being lightweight as a bigger selling point than the features actually being provided. That will eventually change as being lightweight becomes the norm. Nobody advertises for example that Seam is an object oriented framework. Until then "lightweight" is a nice single word description that conveys all of what I took paragraphs to explain, and what the author achieved in a single line.

    • Tutorial: Achieve Rapid Application Development with Seam+Eclipse+Tomcat

      by TechieExchange TechieExchange,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Hi,
      I wrote a step-by-step screencast tutorial to make Seam development as RAD - Rapid Application Development with Eclipse and Tomcat, focussing on developer productivity.

      techieexchange.wordpress.com/2007/11/11/rad-sea...

    • bijection

      by kevin o'brien,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      I have some confusion here over the term "bijection", as used here.

      In one case we have:
      "a Seam component A can also create another component B and "outjects" the created component B back to Seam for other components, such as C, to use later."
      ... which seems to say that bijection is the injection of a component caused by the creation of one component, which can then be used by a second component.

      In another case we have:
      "This type of bi-directional dependency management is widely used in even the simplest Seam web applications

      In Seam documentation, you sometimes see the term "bijection". That refers to the two-way injection and outjection interaction between Seam components and the Seam managed context."
      ... which seems to say that bijection is the in/outjection of a component after a method call.

      Am I missing some of the subtlety in this term??

    • First SEAM working example

      by Binod Suman,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Really this is very nice and useful discussion on jboss forum. Since last 10 days, I was searching any link or blog to show step by step seam setup example. But I didnt get, then thought to create one blog on Seam. I think, it is very useful who wants to start work on Jboss SEAM.

      binodjsf.blogspot.com/

      Thanks,

      Binod Suman

    • Seam simple running example. How to setup first Seam Project

      by Binod Suman,

      Your message is awaiting moderation. Thank you for participating in the discussion.

      Really this is very nice and useful discussion on jboss forum. Since last 10 days, I was searching any link or blog to show step by step seam setup example. But I didnt get, then thought to create one blog on Seam. I think, it is very useful who wants to start work on Jboss SEAM.

      binodjsf.blogspot.com/

      Thanks,

      Binod Suman

    Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

    Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

    BT