Skip navigation

In my previous blog entry I converted a standard JSF / EJB 3.0 application to one that uses JBoss' Seam framework. I covered Seam's primary feature, direct integration of JSF with EJB 3.0, eliminating the Managed Bean. In this entry, I'm going to show off Seam's validation support.

Getting Started
Adding Validation

In our simple registration application, we currently have 3 fields, 2 of which have a required length and a third which just can't be null. These constraints are currently managed in our view. For example, for username:

http://weblogs.java.net/blog/bleonard/archive/2006/05/seam2/viewconstraints.png

One obvious weakness to this approach is that any alternative views (MIDlet, Rich Client) would require implementation of the same constraints.

The Seam framework allows us to specify these constraints on the model directly. Seam incorporates the Hibernate Validator framework, which works regardless of your persistence provider. So for example, on the username property of our User entity, we can specify the following:

http://weblogs.java.net/blog/bleonard/archive/2006/05/seam2/modelconstraints.png

Try the following:

  1. Add the annotations above to the User.java entity class.
  2. Remove the constraints from the userName field in register.jsp.
  3. Open RegisterActionBean.java and add the @Valid annotation to the user field and the @IfInvalid annotation to the register method.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/seam2/@Valid.png

    The @Valid annotation forces validation on the User entity. The @IfInvalid annotation tells seem what to do in the case validation fails, which in this case is to redisplay the data entry page.

  4. Run the application. Enter a Real Name and Password but leave the Username field empty and try to Register.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/seam2/testvalidation.png

  5. Complete the validation by adding a @Length annotation to the getPassword method and a@NotNull annotation to the getName() method. Don't forget to remove the validation code from the JSP.

      Here's the completed application. You'll have to resolve the same reference problems as you did in the previous blog entry.
Addendum
In order to display individual component messages, you just need to assign an HtmlMessage component to each of the input fields in your JSP. Note, for the association to work, you also have to add an id property to each of the input fields. Finally, notice the globalOnly property added to the HtmlMessages component. This prevents the individual component messages from being displayed twice. 

componentmessages.png

I should also point out that since writing this blog I have learned that the @IfInvalid annotation has been deprecated. Support for the new s:validateAll and s:validate JSF tags will be in the next binary release of Seam, I assume 1.0.0CR4.

JBoss does a nice job of documenting their sample registration Seam application. To really help you learn the framework, including its benefits, I thought I walk you through the steps required to port a standard JSF / EJB 3.0 application to one that uses the Seam framework. To be consistent with JBoss' example, I've rewritten the registration application using standard JSF / EJB 3.0. Now let's port it back :-).

Getting Started
  • Downloadand install the NetBeans 5.5 Beta.
  • Download and install JBoss 4.0.4. During installation, be sure to select the ejb3 profile.
  • Download and extract JBoss Seam 1.0.0.CR3 (this is important, CR2 doesn't work with JBoss 4.0.4 GA)
  • Download and extract the Registration application.
Step 1: Add the JBoss Server to NetBeans
  1. Switch to the Runtime tab and right-click the Servers node to add a server.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/jbosscrud/addserver.png

  2. Select JBoss Application Server 4 from the Server drop down list. Change the name to JBoss Application Server 4.0.4.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/jbosscrud/addserver2.png

  3. Complete the Add Server wizard.
  4. Stop the Sun Java System Application Server if it is running (both servers use http port 8080 as their default).
  5. Right-click the new JBoss server node and choose Start:

    http://weblogs.java.net/blog/bleonard/archive/2006/05/jbosscrud/startserver.png

Step 2: Open the Registration Project

The Registration application is a NetBeans Enterprise Application Project, which is actually comprised of 3 projects: Registration, Registration-EJBModule and Registration-WebModule. Registraiton-EJBModule and Registration-WebModule are J2EE Modules of the Registration project. Registration-EJBModule generates the EJB jar file. Registration-WebModule generates the war file and Registration generates the ear file which contains the jar and war.

  1. Open the Registration project. The Enterprise Application Project stores the absolute location to its J2EE Modules. So, unless you extracted your project to the exact same location as me, you will see this dialog when you open the project.

  2. http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/refproblems.png



  3. Click Close. The Registration project will be in bold red.
  4. Right click the project and select Resolve Reference Problems from the context menu.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/resloverefs.png

  5. Use the Resolve Reference Problems dialog to map each module to its project, which you'll find are subdirectories beneath the Registration directory.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/resloverefs3.png
  6. After the references are resolved, right-click the Registration project and select Open Required Projects (now that the dependencies are correct, these dependent projects will always open for you).

    http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/openrequired.png

  7. You'll notice the Registration-WebModule also has a reference problem, as it references the Registration-EJBModule. Use the same steps to correct the reference.
 
Step 3: Test Run the Registration Project

Remember, this is a standard JSF / EJB 3.0 project. Verify that it works before trying to use the Seam framework.

  1. Press F6 to run the project. This will build, package, deploy, start JBoss and launch the application in a browser for you.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/run1.png

    It's a simple application, but it will demonstrate a lot of the functionality provided by the Seam framework, such as: 
    • Elimination of the Managed Bean - we will be able to completely eliminate our managed bean. Our web module will no longer contain any java files.
    • Validation - the 3 fields above are required. Also, Username and Password require and entry between 5 and 15 characters. We'll be able to specify these requirements in our entity class, rather then in our JSP.
    • Additional Seam Components - such as a convenience class for providing messaging back to the user.
 
Step 4: Add and Integrate the Seam Framework Into Your Project

In this step we're only going to integrate the required Seam components so that we can begin using the framework. We won't actually start using Seam until the next step. If NetBeans had direct support for the Seam framework, this is the stuff you'd expect the IDE to do for you.

Create the Seam Library

  1. Open the Library Manager (Tools menu) and create a new library called JBossSeam.
  2. Set the Classpath to jboss-seam.jar.
  3. Set the Sources to the JBoss Seam src directory.
  4. Set the Javadoc to the JBoss Seam doc directory.

This library is now available for use by any project.

Add the Seam Library to Your Project

  1. Right-click the Libraries node of the Registration-EJBModule project and choose Add Library.
  2. Add the JBossSeam library to the project.

Configure web.xml

  1. In the Registration-WebModule, open web.xml (under Configuration Files)
  2. Remove the javax.faces.CONFIG_FILES context parameter to work around a bug in MyFaces. You can read all the gory details here.
  3. Add the following Context Parameter:
         Param Name: org.jboss.seam.core.init.jndiPattern
         Param Value: registration/#{ejbName}/local

         http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/addcontextparam.png

    Seam is going to bind your JSF action directly to a session bean, and it needs this pattern to do the JNDI lookup on your behalf.registration is the name of the ear file, so that would need to change accordingly for each application.

  4. Add the following Web Application Listener: org.jboss.seam.servlet.SeamListener.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/addlistener.png

Configure faces-config.xml

  1. Open faces-config.xml and add the following phase listener:

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


Add the Seam.properties file
It's interesting, the seam.properties file is empty, but Seam will not work without it.

  1. Press Ctrl+N to create a new file. Make sure Registration-EJBModule is selected as the project and select the Other Category > Properties File File Type.
  2. Name the file seam and put it in thesrc\conf Folder.

Unfortunately, the Seam framework expects to find this file in the root of the EJB jar file and not in the META-INF directory, so we have to create a custom Ant target to put it there.

  1. Switch to the Files tab and open Registration-EJBModule's build.xml.
  2. Add the following target:

     
    <target name="-pre-compile">
        <copy file="${meta.inf}/seam.properties" todir="${build.dir}/ear-module"/> </target>

Configure ejb-jar.xml

  1. Add the following assembly descriptor to ejb-jar.xml:

     
       <assembly-descriptor>
          <interceptor-binding>
             <ejb-name>*</ejb-name>
             <interceptor-class>org.jboss.seam.ejb.SeamInterceptor</interceptor-class>       </interceptor-binding>
       </assembly-descriptor>
    The SeamInterceptor integrates Seam with the Session Beans.

Test Your Changes
We haven't actually done anything with Seam, but we want to make sure our app still runs and we'll use the log to verify Sean was loaded successfully.

  1. Press F6 to run the project. The registration application should still run successfully and you should see an entry like the following in the JBoss log file.

    2006-05-24 19:13:27,968 INFO [javax.servlet.ServletContextListener] Welcome to Seam 1.0.0.CR3
 
Step 5: Eliminating Your Managed Bean

Mapping Directly to the Entity Class
In this section we're going to inject our JSF context variables directly into our entity class, which will allow us to eliminate the managed bean. If we look at our faces-config.xml, our managed bean is named "user" and has a "request" scope.

http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/managedbeanname.png

With Seam, we're going to provide this configuration information directly in our entity class, using annotations.

  1. Open User.java and add 2 new annotations:@Name("user") and@Scope(ScopeType.EVENT)

    http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/@name.png

    The SeamListener will now map the JSF "user" context variable directly to our entity class, bypassing our managed bean, and set the scope of the context variable to request.

Mapping Directly to the Action Class
Currently, JSF calls our managed bean which in turn calls our action class. If we give our action class a name, we can bind to it directly from JSF, like we did above with the entity class.

  1. Open RegisterAction.java and add a Name annotation:@Name("register")

    http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/@name2.png
  2. Open register.jsp and change the action on the command button from user.register (the call to our managed bean) to register.register (the call directly to our action class).

    http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/register.png

Now, action methods in JSF cannot take any arguments, which was true of the register method in our managed bean, but not the case with the register method in our action class.
http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/registermethod.png

To get past this problem, we'll use another Seam feature,bijection (because it's bidirectional), to inject the User context object above into our action class.

  1. Add a user field to RegisterAction.java, annotated with @In, as follows:

    http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/@In.png
  2. Then remove the arguments from the register method and pull the necessary values from the injected user field. Your updated method should look as follows:

    http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/registermethod2.png
    Also notice the convenience class FacesMessages that allows me to easily add a templated error message. This is one of the built-in Seam components that streamlines development.

  3. Don't forget to update the register method signature in the RegisterActionLocal interface.

Delete the Managed Bean
Are you ready?

  1. Delete the managed bean, BackingBean.java (yes, it's ok, you can do it).

    http://weblogs.java.net/blog/bleonard/archive/2006/05/seam/deletemanagedbean.png
  2. Delete the managed-bean entry from faces-config.xml. Otherwise, the faces servlet will fail trying to load the managed bean we just deleted.
Step 6: Test Our Seam Managed Application
  1. Press F6 to run the application. It should behave exactly as before, yet under the covers, it's now using Seam.

    Here's the completed application. You'll have to reslove the same reference problems as you did above.
Next Steps

I'd also like to use Seam to handle validation as well as page navigation. However, this blog entry has grown longer than I expected. Stay tuned for an additional entry covering these Seam features.

 

 



Last month, my colleague Geertjan wrote a couple of pretty popular blog entries:The Best Feature of the Upcoming NetBeans IDE 5.5 (Part 1) and (Part 2). It basically showcases 2 new wizards in NetBeans 5.5: Entity Classes from Database and JSF Pages from Entity Class, that when run back to back essentially create a fully functional CRUD (Create, Read, Update, Delete) application. I was curious how this would work with JBoss, so below for you I document my experiences.

Getting Started
  • Downloadand install the NetBeans 5.5 Beta.
  • Download and install JBoss 4.0.4. During installation, be sure to select the ejb3 profile.
Step 1: Add the JBoss Server to NetBeans
  1. Switch to the Runtime tab and right-click the Servers node to add a server.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/jbosscrud/addserver.png

  2. Select JBoss Application Server 4 from the Server drop down list. Change the name to JBoss Application Server 4.0.4.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/jbosscrud/addserver2.png

  3. Complete the Add Server wizard.
  4. Stop the Sun Java System Application Server if it is running (both servers use http port 8080 as their default).
  5. Right-click the new JBoss server node and choose Start:

    http://weblogs.java.net/blog/bleonard/archive/2006/05/jbosscrud/startserver.png

Step 2: Create the Project

JBoss doesn't ship any sample data with it's HSQLDB. However, there are a few system tables in place to support JMS, so to keep things as simple as possible, we'll go with one of those: JMS_USERS.

  1. Create a New Web Application Project namedJMSUserEditor. Be sure to select JBoss as the Server (Note, although JBoss supports components of the Java EE 5 specification, notably EJB 3.0, JBoss 4.0.4 is a J2EE 1.4 compliant application server. Therefore, Java EE 5 is not an available option for J2EE Version.). Also, uncheck the option to Set Source Level to 1.4, as we will be using annotations which require Java 5.0.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/jbosscrud/newwebapp.png

  2. On Step 3 of the wizard, Frameworks, be sure to select Java Server Faces and click Finish.
Step 3: Prepare the Project for JBoss

There are a couple of additional steps we need to take in order for the project to run successfully on JBoss. Issues have been filed and these steps will not be necessary with the 5.5 final release.

  1. Remove the JSF and JSTL libraries from the project (Issue 76733). Open the Project Properties, select the Libraries node and Remove the JSF and JSTL libraries from the project.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/jbosscrud/removelibs.png

  2. Add the MyFaces Context Listener to web.xml (Issue 74392). Open the web.xml and expand the Web Application Listeners node. Click Add and add the org.apache.myfaces.webapp.StartupServletContextListenerclass.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/jbosscrud/addlistener.png
  3. Press F6 to test run the project. If you can load the page that says Java Server Faces, your project is set up correctly:

    http://weblogs.java.net/blog/bleonard/archive/2006/05/jbosscrud/testrun2.png
Step 4: Setup the Database
Follow the steps from this blog entry to set up HSQLDB to run in server mode. This will allow the wizards in the next step to connect to the database. It will also allow you to use NetBeans' database explorer tools to browse the data.

Step 5: Create the Persistence Unit
  1. Press Ctrl+N to create a new file and select the Persistence Category > Persistence Unit.
  2. Set the Persistence Unit Name to default and click Finish.
  3. Press Alt+Shift+Right to open the XML view and replace the persistence unit with the following:
  <persistence-unit name="default">
    <jta-data-source>java:/DefaultDS</jta-data-source>
    <properties>
      <property name="hibernate.hbm2ddl.auto" value=""/>
      <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/>
    </properties>
  </persistence-unit>
 
Step 6: Create the Entity Classes
  1. Press Ctrl+N to create a new file and select the Persistence Category > Entity Class from Database File Type.
  2. Select the Database Connection jdbc:hsqldb:hsql://localhost:1701 [sa on PUBLIC]and the JMS_USERS table.

    http://weblogs.java.net/blog/bleonard/archive/2006/05/jbosscrud/entityfromdb.png

    Click Next.

  3. Set the Package to entity and click Finish.
Step 7: Create the JSF Pages
  1. Press Ctrl+N to create a new file and select the Persistence Category > JSF Pages from Entity Class File Type.
  2. Add the JmsUsers Entity Class to the Selected Entity Classes. Click Next.
  3. Set the Package to controller and click Finish.
Step 8: Run Your Application
  1. Press F6 to run the application. http://weblogs.java.net/blog/bleonard/archive/2006/05/jbosscrud/secondrun.png

The theme of JavaOne 2006 is Java EE 5. However, it there was an unofficial theme, I'd have to say it's NetBeans - the tool is simply EVERYWHERE. Therefore, I shouldn't have been surprised when I was browsing through the JavaOne Book Store and noticed this post on the cash register:

bestseller.JPG

Mixed among the other hot topics of the year - EJB 3.0 and AJAX - you see the NetBeans IDE Field Guild. Congratulations to Patrick, Ludo, Greg, Charlie and Chris for putting together a great 2nd edition to compliment the 5.0 release.

Filter Blog

By date: