Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

2.2. Your first Seam application: the registration example

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.

2.2.1. Understanding the code

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".

2.2.1.1. The entity bean: User.java

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;
   }

}
  1. The EJB3 standard @Entity annotation indicates that the User class is an entity bean.
  2. A Seam component needs a component name specified by the @Name annotation. This name must be unique within the Seam application. When JSF asks Seam to resolve a context variable with a name that is the same as a Seam component name, and the context variable is currently undefined (null), Seam will instantiate that component, and bind the new instance to the context variable. In this case, Seam will instantiate a User the first time JSF encounters a variable named user.
  3. 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 @Scope annotation. The User bean is a session scoped component.
  4. The EJB standard @Table annotation indicates that the User class is mapped to the users table.
  5. name, password and username are the persistent attributes of the entity bean. All of our persistent attributes define accessor methods. These are needed when this component is used by JSF in the render response and update model values phases.
  6. An empty constructor is both required by both the EJB specification and by Seam.
  7. The @NotNull and @Length annotations are part of the Hibernate Validator framework. Seam integrates Hibernate Validator and lets you use it for data validation (even if you are not using Hibernate for persistence).
  8. The EJB standard @Id annotation indicates the primary key attribute of the entity bean.
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.
Example 2.1. 

2.2.1.2. The stateless session bean class: RegisterAction.java

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;
      }
   }

}
  1. The EJB standard @Stateless annotation marks this class as stateless session bean.
  2. The @In annotation marks an attribute of the bean as injected by Seam. In this case, the attribute is injected from a context variable named user (the instance variable name).
  3. The EJB standard @PersistenceContext annotation is used to inject the EJB3 entity manager.
  4. The Seam @Logger annotation is used to inject the component's Log instance.
  5. The action listener method uses the standard EJB3 EntityManager API to interact with the database, and returns the JSF outcome. Note that, since this is a sesson bean, a transaction is automatically begun when the register() method is called, and committed when it completes.
  6. Notice that Seam lets you use a JSF EL expression inside EJB-QL. Under the covers, this results in an ordinary JPA setParameter() call on the standard JPA Query object. Nice, huh?
  7. The Log API lets us easily display templated log messages.
  8. JSF action listener methods return a string-valued outcome that determines what page will be displayed next. A null outcome (or a void action listener method) redisplays the previous page. In plain JSF, it is normal to always use a JSF navigation rule to determine the JSF view id from the outcome. For complex application this indirection is useful and a good practice. However, for very simple examples like this one, Seam lets you use the JSF view id as the outcome, eliminating the requirement for a navigation rule. Note that when you use a view id as an outcome, Seam always performs a browser redirect.
  9. Seam provides a number of built-in components to help solve common problems. The FacesMessages component makes it easy to display templated error or success messages. Built-in Seam components may be obtained by injection, or by calling an instance() method.
Note that we did not explicitly specify a @Scope this time. Each Seam component type has a default scope if not explicitly specified. For stateless session beans, the default scope is the stateless context. Actually, all stateless session beans belong in the stateless context.
Our session bean action listener performs the business and persistence logic for our mini-application. In more complex applications, we might need to layer the code and refactor persistence logic into a dedicated data access component. That's perfectly trivial to do. But notice that Seam does not force you into any particular strategy for application layering.
Furthermore, notice that our session bean has simultaneous access to context associated with the web request (the form values in the User object, for example), and state held in transactional resources (the EntityManager object). This is a break from traditional J2EE architectures. Again, if you are more comfortable with the traditional J2EE layering, you can certainly implement that in a Seam application. But for many applications, it's simply not very useful.
Example 2.2. 

2.2.1.3. The session bean local interface: Register.java

Naturally, our session bean needs a local interface.
@Local
public interface Register
{
   public String register();
}
Example 2.3. 

That's the end of the Java code. Now onto the deployment descriptors.

2.2.1.4. The Seam component deployment descriptor: components.xml

If you've used many Java frameworks before, you'll be used to having to declare all your component classes in some kind of XML file that gradually grows more and more unmanageable as your project matures. You'll be relieved to know that Seam does not require that application components be accompanied by XML. Most Seam applications require a very small amount of XML that does not grow very much as the project gets bigger.
Nevertheless, it is often useful to be able to provide for some external configuration of some components (particularly the components built in to Seam). You have a couple of options here, but the most flexible option is to provide this configuration in a file called components.xml, located in the WEB-INF directory. We'll use the components.xml file to tell Seam how to find our EJB components in JNDI:
<components xmlns="https://jboss.com/products/seam/components"
            xmlns:core="https://jboss.com/products/seam/core">
     <core:init jndi-pattern="@jndiPattern@"/>
</components>
Example 2.4. 

This code configures a property named jndiPattern of a built-in Seam component named org.jboss.seam.core.init.

2.2.1.5. The web deployment description: web.xml

The presentation layer for our mini-application will be deployed in a WAR. So we'll need a web deployment descriptor.
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
    xmlns="https://java.sun.com/xml/ns/javaee"
    xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="https://java.sun.com/xml/ns/javaee
        https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <!- - Seam - ->

    <listener>
        <listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
    </listener>
    
     <listener>
         <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
    </listener>

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

    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.jspx</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>
Example 2.5. 

This web.xml file configures Seam and Glassfish. The configuration you see here is pretty much identical in all Seam applications.

2.2.1.6. The JSF configration: faces-config.xml

All Seam applications use JSF views as the presentation layer. So we'll need faces-config.xml.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE faces-config 
PUBLIC "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
                            "https://java.sun.com/dtd/web-facesconfig_1_0.dtd">
<faces-config>

    <!- - A phase listener is needed by all Seam applications - ->
    
    <lifecycle>
        <phase-listener>org.jboss.seam.jsf.SeamPhaseListener</phase-listener>
    </lifecycle>

</faces-config>
Example 2.6. 

The faces-config.xml file integrates Seam into JSF. Note that we don't need any JSF managed bean declarations! The managed beans are the Seam components. In Seam applications, the faces-config.xml is used much less often than in plain JSF.
In fact, once you have all the basic descriptors set up, the only XML you need to write as you add new functionality to a Seam application is the navigation rules, and possibly jBPM process definitions. Seam takes the view that process flow and configuration data are the only things that truly belong in XML.
In this simple example, we don't even need a navigation rule, since we decided to embed the view id in our action code.

2.2.1.7. The EJB deployment descriptor: ejb-jar.xml

The ejb-jar.xml file integrates Seam with EJB3, by attaching the SeamInterceptor to all session beans in the archive.
<ejb-jar xmlns="https://java.sun.com/xml/ns/javaee" 
         xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" 
         xsi:schemaLocation="https://java.sun.com/xml/ns/javaee 
                           https://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>

2.2.1.8. The EJB persistence deployment descriptor: persistence.xml

The persistence.xml file tells the EJB persistence provider where to find the datasource, and contains some vendor-specific settings. In this case, enables automatic schema export at startup time.
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="https://java.sun.com/xml/ns/persistence" 
             xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://java.sun.com/xml/ns/persistence 
                           https://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" 
             version="1.0">
    <persistence-unit name="userDatabase">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <jta-data-source>java:/DefaultDS</jta-data-source>
      <properties>
         <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
      </properties>
    </persistence-unit>
</persistence>

2.2.1.9. The view: register.jsp and registered.jsp

The view pages for a Seam application could be implemented using any technology that supports JSF. In this example we use JSP, since it is familiar to most developers and since we have minimal requirements here anyway. (But if you take our advice, you'll use Facelets for your own applications.)
<%@ taglib uri="https://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="https://java.sun.com/jsf/core" prefix="f" %>
<%@ taglib uri="https://jboss.com/products/seam/taglib" prefix="s" %>
<html>
 <head>
  <title>Register New User</title>
 </head>
 <body>
  <f:view>
   <h:form>
     <table border="0">
       <s:validateAll>
         <tr>
           <td>Username</td>
           <td><h:inputText value="#{user.username}"/></td>
         </tr>
         <tr>
           <td>Real Name</td>
           <td><h:inputText value="#{user.name}"/></td>
         </tr>
         <tr>
           <td>Password</td>
           <td><h:inputSecret value="#{user.password}"/></td>
         </tr>
       </s:validateAll>
     </table>
     <h:messages/>
     <h:commandButton type="submit" value="Register" action="#{register.register}"/>
   </h:form>
  </f:view>
 </body>
</html>
Example 2.7. 

The only thing here that is specific to Seam is the <s:validateAll> tag. This JSF component tells JSF to validate all the contained input fields against the Hibernate Validator annotations specified on the entity bean.
<%@ taglib uri="https://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="https://java.sun.com/jsf/core" prefix="f" %>
<html>
 <head>
  <title>Successfully Registered New User</title>
 </head>
 <body>
  <f:view>
    Welcome, <h:outputText value="#{user.name}"/>, 
    you are successfully registered as <h:outputText value="#{user.username}"/>.
  </f:view>
 </body>
</html>
Example 2.8. 

This is a boring old JSP pages using standard JSF components. There is nothing specific to Seam here.

2.2.1.10. The EAR deployment descriptor: application.xml

Finally, since our application is deployed as an EAR, we need a deployment descriptor there, too.
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="https://java.sun.com/xml/ns/javaee" 
             xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="https://java.sun.com/xml/ns/javaee 
                                   https://java.sun.com/xml/ns/javaee/application_5.xsd"
             version="5">
             
    <display-name>Seam Registration</display-name>

    <module>
        <web>
            <web-uri>jboss-seam-registration.war</web-uri>
            <context-root>/seam-registration</context-root>
        </web>
    </module>
    <module>
        <ejb>jboss-seam-registration.jar</ejb>
    </module>
    <module>
        <java>jboss-seam.jar</java>
    </module>
    <module>
        <java>el-ri.jar</java>
    </module>
    
</application>
Example 2.9. 

This deployment descriptor links modules in the enterprise archive and binds the web application to the context root /seam-registration.

 
 
  Published under the terms of the Open Publication License Design by Interspire