Developing Seam Applications

Exclusive offer: get 50% off this eBook here
Seam 2.x Web Development

Seam 2.x Web Development — Save 50%

Build robust web applications with Seam, Facelets, and RichFaces using the JBoss application server

€18.99    €9.50
by David Salter | May 2009 | Java Open Source Web Development

In this article by David Salter, we are going to start learning how to develop applications using Seam, and we will see some of the features of Seam. We will learn the basic structure of a Seam application. We will see in practice how Seam Injection and Outjection work, and we will learn more about Seam components. We will also see exactly how Seam bridges the gap between the Web tier (using Java Server Faces) and the Server tier (using Enterprise Java Beans).

Seam application architecture

As most enterprise Java developers are probably familiar with JSF and JSP, we will be using this as the view technology for our sample applications. Facelets is the recommended view technology for Seam-based applications once we have a solid understanding of Seam.

In a standard Java EE application, Enterprise Application Resource (EAR) files contain one or more Web Application Resource (WAR) files and one or more sets of Java Archive (JAR) files containing Enterprise JavaBeans (EJB) functionality. Seam applications are generally deployed in exactly the same manner as depicted in the following diagram. It is possible to deploy Seam onto a servlet-only container (for example, Tomcat) and use POJOs as the server-side Seam components. However, in this situation, we don't get any of the benefits that EJBs provide, such as security, transaction handling, management, or pooling.

Seam 2.x Web Development

Seam components

Within Seam, components are simple POJOs. There is no need to implement any interfaces or derive classes from a Seam-specific base class to make Seam components classes. For example, a Seam component could be:

  • A simple POJO
  • a stateless Session Bean
  • a stateful Session Bean
  • a JPA entity and so on

Seam components are defined by adding the @Name annotation to a class definition. The @Name annotation takes a single parameter to define the name of the Seam component. The following example shows how a stateless Session Bean is defined as a Seam component called calcAction.

package com.davidsalter.seamcalculator;
@Stateless
@Name("calcAction")
public class CalcAction implements Calc {
...
}

When a Seam application is deployed to JBoss, the log output at startup lists what Seam components are deployed, and what type they are. This can be useful for diagnostic purposes, to ensure that your components are deployed correctly. Output similar to the following will be shown in the JBoss console log when the CalcAction class is deployed:

21:24:24,097 INFO [Initialization] Installing components...
21:24:24,121 INFO [Component] Component: calcAction, scope:
STATELESS, type: STATELESS_SESSION_BEAN, class: com.davidsalter.
seamcalculator.CalcAction, JNDI: SeamCalculator/CalcAction/local

Object Injection and Outjection

One of the benefits of using Seam is that it acts as the "glue" between the web technology and the server-side technology. By this we mean that the Seam Framework allows us to use enterprise beans (for example, Session Beans) directly within the Web tier without having to use Data Transfer Object (DTO) patterns and without worrying about exposing server-side functionality on the client.

Additionally, if we are using Session Beans for our server-side functionality, we don't really have to develop an additional layer of JSF backing beans, which are essentially acting as another layer between our web page and our application logic.

In order to fully understand the benefits of Seam, we need to first describe what we mean by Injection and Outjection.

Injection is the process of the framework setting component values before an object is created. With injection, the framework is responsible for setting components (or injecting them) within other components. Typically, Injection can be used to allow component values to be passed from the web page into Seam components.

Outjection works in the opposite direction to Injection. With Outjection, components are responsible for setting component values back into the framework. Typically, Outjection is used for setting component values back into the Seam Framework, and these values can then be referenced via JSF Expression Language (EL) within JSF pages. This means that Outjection is typically used to allow data values to be passed from Seam components into web pages.

Seam allows components to be injected into different Seam components by using the @In annotation and allows us to outject them by using the @Out annotation. For example, if we have some JSF code that allows us to enter details on a web form, we may use an <h:inputText …/> tag such as this:

<h:inputText value="#{calculator.value1}" required="true"/>

The Seam component calculator could then be injected into a Seam component using the @In annotation as follows:

@In
private Calculator calculator;

With Seam, all of the default values on annotations are the most likely ones to be used. In the preceding example therefore, Seam will look up a component called calculator and inject that into the calculator variable. If we wanted Seam to inject a variable with a different name to the variable that it is being injected into, we can adorn the @In annotation with the value parameter.

@In (value="myCalculator")
private Calculator calculator;

In this example, Seam will look up a component called myCalculator and inject it into the variable calculator.

Similarly, if we want to outject a variable from a Seam component into a JSF page, we would use the @Out annotation.

@Out
private Calculator calculator;

The outjected calculator object could then be used in a JSF page in the following manner:

<h:outputText value="#{calculator.answer}"/>

Example application

To see these concepts in action, and to gain an understanding of how Seam components are used instead of JSF backing beans, let us look at a simple calculator web application. This simple application allows us to enter two numbers on a web page. Clicking the Add button on the web page will cause the sum of the numbers to be displayed.

This basic application will give us an understanding of the layout of a Seam application and how we can inject and outject components between the business layer and the view. The application functionality is shown in the following screenshot.

Seam 2.x Web Development

The sample code for this application can be downloaded from the Packt web site, at http://www.packtpub.com/support.

For this sample application, we have a single JSF page that is responsible for:

  • Reading two numeric values from the user
  • Invoking business logic to add the numbers together
  • Displaying the results of adding the numbers together
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<html>
<head>
<title>Seam Calculator</title>
</head>
<body>
<f:view>
<h:form>
<h:panelGrid columns="2">
Value 1: <h:inputText value="#{calculator.
value1}" />
Value 2: <h:inputText value="#{calculator.
value2}" />
Add them together gives: <h:outputText value="
#{calculator.answer} "/>
</h:panelGrid>
<h:commandButton value="Add" action=
"#{calcAction.calculate}"/>
</h:form>
</f:view>
</body>
</html>

We can see that there is nothing Seam-specific in this JSF page. However, we are binding two inputText areas, one outputText area, and a button action to Seam components by using standard JSF Expression Language.

JSF EL

Seam Binding

calculator.value1

This is bound to the member variable value1 on the Seam component called calculator. This value will be injected into the Seam component.

calculator.value2

This is bound to the member variable value2 on the Seam component called calculator. This value will be injected into the Seam component.

calculator.answer

This is bound to the member variable answer on the Seam component called calculator. This value will be outjected from the Seam component.

calcAction.calculate

This will invoke the method calculate() on the Seam component called calcAction.

Our business logic for this sample application is performed in a simple POJO class called Calculator.java.

package com.davidsalter.seamcalculator;
import java.io.Serializable;
import org.jboss.seam.annotations.Name;

@Name("calculator")
public class Calculator {
private double value1;
private double value2;
private double answer;

public double getValue1() {
return value1;
}

public void setValue1(double value1) {
this.value1 = value1;
}

public double getValue2() {
return value2;
}

public void setValue2(double value2) {
this.value2 = value2;
}

public double getAnswer() {
return answer;
}

public void add() {
this.answer = value1 + value2;
}
}

This class is decorated with the @Name("calculator") annotation, which causes it to be registered to Seam with the name, "calculator". The @Name annotation causes this object to be registered as a Seam component that can subsequently be used within other Seam components via Injection or Outjection by using the @In and @Out annotations.

Finally, we need to have a class that is acting as a backing bean for the JSF page that allows us to invoke our business logic. In this example, we are using a Stateless Session Bean. The Session Bean and its local interface are as follows.

In the Java EE 5 specification, a Stateless Session Bean is used to represent a single application client's communication with an application server. A Stateless Session Bean, as its name suggests, contains no state information; so they are typically used as transaction façades. A Façade is a popular design pattern, which defines how simplified access to a system can be provided. For more information about the Façade pattern, check out the following link: http://java.sun.com/blueprints/corej2eepatterns/Patterns/SessionFacade.html

Defining a Stateless Session Bean using Java EE 5 technologies requires an interface and an implementation class to be defined. The interface defines all of the methods that are available to clients of the Session Bean, whereas the implementation class contains a concrete implementation of the interface. In Java EE 5, a Session Bean interface is annotated with either the @Local or @Remote or both annotations. An @Local interface is used when a Session Bean is to be accessed locally within the same JVM as its client (for example, a web page running within an application server). An @Remote interface is used when a Session Bean's clients are remote to the application server that is running within a different JVM as the application server.

There are many books that cover Stateless Session Beans and EJB 3 in depth, such as EJB 3 Developer's Guide by Michael Sikora, published by Packt Publishing. For more information on this book, check out the following link: http://www.packtpub.com/developer-guide-for-ejb3

In the following code, we are registering our CalcAction class with Seam under the name calcAction. We are also Injecting and Outjecting the calculator variable so that we can use it both to retrieve values from our JSF form and pass them back to the form.

package com.davidsalter.seamcalculator;

import javax.ejb.Stateless;

import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Name;

@Stateless
@Name("calcAction")
public class CalcAction implements Calc {

@In
@Out
private Calculator calculator;

public String calculate() {

calculator.add();
return "";
}
}
package com.davidsalter.seamcalculator;
import javax.ejb.Local;

@Local
public interface Calc {
public String calculate();
}

That's all the code we need to write for our sample application. If we review this code, we can see several key points where Seam has made our application development easier:

  • All of the code that we have developed has been written as POJOs, which will make unit testing a lot easier.
  • We haven't extended or implemented any special Seam interfaces.
  • We've not had to define any JSF backing beans explicitly in XML.
  • We're using Java EE Session Beans to manage all of the business logic and web-tier/business-tier integration.
  • We've not used any DTO objects to transfer data between the web and the business tiers. We're using a Seam component that contains both state and behavior.

If you are familiar with JSF, you can probably see that adding Seam into a fairly standard JSF application has already made our development simpler. Finally, to enable Seam to correctly find our Seam components and deploy them correctly to the application server, we need to create an empty file called seam.properties and place it within the root of the classpath of the EJB JAR file. Because this file is empty, we will not discuss it further here. To deploy the application as a WAR file embedded inside an EAR file, we need to write some deployment descriptors.

Seam 2.x Web Development Build robust web applications with Seam, Facelets, and RichFaces using the JBoss application server
Published: April 2009
eBook Price: €18.99
Book Price: €30.99
See more
Select your format and quantity:

WAR file deployment descriptors

To deploy a WAR file with Seam, we need to define several files within the WEB-INF directory of the archive:

  • web.xml
  • faces-config.xml
  • components.xml

First let's take a look at the web.xml file. This is a fairly standard file that specifies the SeamListener class, which aids internal Seam initialization and cleanup. This file also specifies that all pages with the extension .seam will be run as JSF pages.

<?xml version="1.0" ?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<listener>
<listener-class>org.jboss.seam.servlet.
SeamListener</listener-class>
</listener>
<context-param>
<param-name>javax.faces.DEFAULT_SUFFIX</param-name>
<param-value>.jsp</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>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.seam</url-pattern>
</servlet-mapping>
</web-app>

The faces-config.xml file allows Seam to be integrated into the JSF page life cycle, by adding the org.jboss.seam.jsf.SeamPhaseListener into the life cycle events chain.

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="1.2"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
<lifecycle>
<phase-listener>org.jboss.seam.jsf.
SeamPhaseListener</phase-listener>
</lifecycle>
</faces-config>

Finally, the components.xml file allows any Seam components that we may be using to be configured. In our sample application, the only configuration that we are performing is specifying the JNDI pattern to allow EJB components to be looked up by Seam.

<?xml version="1.0" encoding="UTF-8"?>
<components xmlns="http://jboss.com/products/seam/components"
xmlns:core="http://jboss.com/products/seam/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jboss.com/products/seam/core
http://jboss.com/products/seam/core-2.1.xsd
http://jboss.com/products/seam/components
http://jboss.com/products/seam/components-2.1.xsd">
<core:init jndi-pattern="@jndiPattern@"/>
</components>

It is in this file that we will specify Seam-specific information such as security and web page viewing options.

EAR file deployment descriptors

To deploy an EAR file with Seam on JBoss, we need to define several deployment descriptors within the META-INF directory of the archive:

  • application.xml
  • ejb-jar.xml
  • jboss-app.xml

The application.xml file allows us to define the modules that are to be deployed to JBoss. In this file, we need to specify the WAR file for our application and the JAR file that contains our Session Beans. We must also include a reference to the jboss-seam.jar file.

<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/application_5.xsd"
version="5">
<display-name>SeamCalculator</display-name>

<module>
<web>
<web-uri>SeamCalculator.war</web-uri>
<context-root>/SeamCalculator</context-root>
</web>
</module>

<module>
<ejb>SeamCalculator.jar</ejb>
</module>

<module>
<ejb>jboss-seam.jar</ejb>
</module>
</application>

In the ejb-jar.xml file, we must attach the org.jboss.seam.ejb.SeamInterceptor class onto all our EJBs.

<?xml version="1.0" encoding="UTF-8"?>
<ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
version="3.0">
<interceptors>
<interceptor>
<interceptor-class>org.jboss.seam.ejb.
SeamInterceptor</interceptor-class>
</interceptor>
</interceptors>
<assembly-descriptor>
<interceptor-binding>
<ejb-name>*</ejb-name>
<interceptor-class>org.jboss.seam.ejb.
SeamInterceptor</interceptor-class>
</interceptor-binding>
</assembly-descriptor>
</ejb-jar>

Finally, we can specify a class loader for our Seam application in jboss-app.xml so that there are no conflicts between the classes deployed to the JBoss Application Server and the ones deployed to our application.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE jboss-app
PUBLIC "-//JBoss//DTD J2EE Application 5.0//EN"
"http://www.jboss.org/j2ee/dtd/jboss-app_5_0.dtd">
<jboss-app>
<loader-repository>
seam.jboss.org:loader=SeamCalculator
</loader-repository>
</jboss-app>

Application layout

Before we deploy and run the test application, let's take a look at the layout of our sample application. As you can see in the following screenshot, the layout of the application follows the standard layout of a Java EE application. The application is deployed as a single EAR file. Within the EAR file, we have the Seam JAR file, our EJB JAR file, and our web application EAR file. This is the standard layout that all of our Seam applications are going to follow.

Seam 2.x Web Development

Testing the application

Now that we have looked at the code for both the application and the deployment descriptors, let's build the application and test it before deploying it to the JBoss Application Server.

It is traditionally quite difficult to perform unit tests on enterprise applications because of their nature. Without using Seam, the testing of web pages and Java EE resources (for example, Session Beans) requires that the application be deployed to an application server. This makes testing more difficult and can vastly increase the development time of applications.

However, Seam offers great support for testing applications outside the application server, including support for testing web pages. The standard testing framework used with Seam is TestNG (http://www.testng.org). However, there are some Seam-specific extensions that make testing easier. Let's see how to test the business logic of our application, and indeed any POJOs that we can write, by using a standard TestNG unit test.

TestNG uses Java 5 annotations to allow methods to be declared as tests. To declare a method as a unit test, we simply need to adorn the method with the @Test annotation. Within a test, we can then assert different conditions to test whether our code is working as expected.

We could write a simple test for our calculator application as follows:

package com.davidsalter.seamcalculator.test;

import com.davidsalter.seamcalculator.Calculator;
import org.testng.annotations.Test;

public class CalculatorTest {
private static double tolerance = 0.001;
@Test
public void testAdd() throws Exception {
Calculator testCalculator = new Calculator();
testCalculator.setValue1(10.0);
testCalculator.setValue2(20.0);
testCalculator.add();
assert (testCalculator.getAnswer() - 30.0 < tolerance);
}
}

This test simply instantiates an instance of the Calculator class, sets up some test data, and invokes the add() method before asserting that the answer is as expected.

Before we can run this unit test, we must also define an XML file that details which tests to run. For Seam tests, this file is typically called AllTests.xml. The contents of this file, for our sample application, are as follows:

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Calculator - All" verbose="1">
<test name="Calculator">
<packages>
<package name="com.davidsalter.seamcalculator.test"/>
</packages>
</test>
</suite>

Finally, before we can build and test the application, we need to copy a few JAR files from the Seam installation into our build path. To build and test a basic Seam application, we need to build against some of the Seam JAR files:

  • jboss-seam.jar – This contains the main Seam Framework such as the @In and @Out annotations
  • ejb-api.jar – This contains the references we need to build EJB 3 Session Beans
  • testng.jar – This contains the TestNG framework that allows us to test our application

All of these JAR files can be found in the <jboss_seam>/lib directory, where <jboss_seam> is the directory that you have installed Seam into.

To test the sample application, we need to execute the Test target in the ant build file, as shown in the following screenshot.

Seam 2.x Web Development

Executing the tests should show that one test has been run, and that there were no failures and no skipped tests. Assuming that the test was completed successfully, we can be fairly confident that our application will run correctly when built and deployed to the application server.

Building and deploying the application

In the previous section, we saw how to perform a basic unit test to verify that the application logic is functioning correctly. Once all of our application's unit tests succeed (one of them in this case), we can build the application and deploy it to JBoss.

To build and deploy the application, we use the ant script again. The ant script provides several different targets, allowing the project to be compiled, deployed, and archived into an EAR file. Executing the Info target provides the following help screen, which shows which targets are available.

Seam 2.x Web Development

Ant target

Description

archive

The archive target compiles the project and builds the packaged project output files:

EJB archive JAR

Web application WAR

Enterprise application EAR

clean

The clean target tidies up the project by deleting all of the files that have been generated by building or testing the project.

deploy

The deploy target builds the project, packages up the archives into a deployable format (EAR file), and then deploys the application to the JBoss Application Server.

info

The info target displays a help page listing in which targets are available.

test

The test target runs the application unit tests.

undeploy

The undeploy target undeploys the application from the application server.

Within the JBoss Application Server, applications can be hot deployed by copying them into the <jboss_home>/server/default/deploy directory. Similarly, to undeploy an application, just delete it from the <jboss_home>/server/default/deploy directory.

To build and deploy the application to JBoss, execute the deploy task.

Seam 2.x Web Development

If the JBoss Application Server is running, we should see some log output appear on the JBoss console, ending with a line saying that the application has been deployed successfully, as shown below:

[EARDeployer] Started J2EE application: file:/Applications/
jboss-5.0.0.GA/server/default/deploy/SeamCalculator.ear

If we don't see the application deployed to the JBoss Application Server and there were no errors during compilation, check the value of the jboss.home property within the build.properties file.

Once we see the preceding line on the JBoss console, it means that JBoss has successfully deployed the application and we can test it out.

To run the application, visit the web site http://localhost:8080/SeamCalculator/calc.seam and try adding some numbers together to prove that the application is functioning as expected.

Summary

In this article, we've taken our first real steps into developing Seam applications. We've looked into Seam components and learned that they are declared with the @Name annotation. We've seen how we can inject and outject Seam components by using the @In and @Out annotations respectively. After learning about Seam components, we wrote a simple Seam application using these concepts, which shows the layout for Seam applications.

Seam 2.x Web Development Build robust web applications with Seam, Facelets, and RichFaces using the JBoss application server
Published: April 2009
eBook Price: €18.99
Book Price: €30.99
See more
Select your format and quantity:

About the Author :


David Salter

David Salter is an enterprise software developer who has been developing software professionally since 1991. His relationship with Java goes right back to the beginning, using Java 1.0 to write desktop applications and applets for interactive websites.

David has been developing Enterprise Java applications using both the Java EE standards and open source solutions for the last 10 years.

David is the co-author of Building SOA-based Composite Applications using NetBeans and the author of Seam 2.x Web Development.

Books From Packt

 

Practical Plone 3: A Beginner's Guide to Building Powerful Websites
Practical Plone 3: A Beginner's Guide to Building Powerful Websites

WordPress Plugin Development: Beginner's Guide
WordPress Plugin Development: Beginner's Guide

Spring 2.5 Aspect Oriented Programming
Spring 2.5 Aspect Oriented Programming

Spring Web Flow 2 Web Development
Spring Web Flow 2 Web Development

Grails 1.1 Web Application Development
Grails 1.1 Web Application Development

Drools JBoss Rules 5.0 Developer's Guide
Drools JBoss Rules 5.0 Developer's Guide

Django 1.0 Website Development
Django 1.0 Website Development

Learning jQuery 1.3
Learning jQuery 1.3

 

Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software