16 May 2011

JSF 2.0, JPA 2.0 and Bean Validation on WebLogic Server

For some time now, I’ve been meaning to build a simple application to demonstrate the use of JSF 2.0, JPA 2.0 and Bean Validation with WebLogic Server 10.3.4.  But I hadn’t gotten around to it until I had a couple of hours free late last week.

Seeing as I didn’t have all that much time, I thought I’d try and repurpose the Java EE 6 CRUD (create-remove-update-delete) application that NetBeans generates for GlassFish 3.x, and see if I could get it to run on WebLogic Server. 

The short answer to that was a resounding yes, with only a few minor changes or tricks.

In this blog, I’m going to step through what I did and highlight the changes that I played around with in order to make it work.  I'm not going to make this a tutorial (at this point) since most of the steps that are required are simply using the NetBeans IDE and its wizards to generate the requisite components and pages.

Developing the Application
  1. The starting point for this app was a single table, Widgets, created in a local Derby database. 

  2. Using NetBeans 7.0, a new Java EE Enterprise Application was created, using Java EE 6 and targetted at the GlassFish 3.1 server installed with NetBeans.  This produces two child projects: a Web project and an EJB project.



  3. In the EJB project, use the "Entity Classes from Database" to generate a JPA 2.0 Entity from the Widget table.



    Worth pointing out here is the use of the Bean Validation specification to declare constraints on the various fields of the Widget entity. 

    I particularly appreciated the smarts NetBeans uses to provide a suggested @Pattern regular expression for an email field

    @Pattern(regexp="[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", message="Invalid email")//if the field contains email address consider using this annotation to enforce field validation
    @Size(max = 100)
    @Column(name = "EMAIL")   
    private String email;

  4. Next, invoke the "Sessions Bean For Entity Classes ..." to generate a session facade with CRUD methods for the Widget entity. 



    Worth noting here are two points:   First, the use of a Generics based Abstract class for the base CRUD operations, which is then subclassed by the WidgetFacade session bean to work specifically with the Widget entity.  Second, the use of the JPA 2.0 Criteria API to build a number of queries in the base class.

    public List<T> findRange(int[] range) {
        javax.persistence.criteria.CriteriaQuery cq getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        q.setMaxResults(range[1] - range[0]);
        q.setFirstResult(range[0]);
        return q.getResultList();
    }

    This session bean is created with a local interface since the EJB 3.0 implementation in WebLogic Server requires the use of a business interface.

  5. In the persistence.xml file, a trick worth keeping in mind here which may save you some pain later is to explicitly specify the JPA provider to use.  This helps later on when you deploy the completed application to WebLogic Server, where the default JPA provider is Kodo/OpenJPA.  This can be overridden at the WLS domain level, but setting it in persistence.xml within the application itself is an easy way to do it now.

    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>

    For more details on changing the default JPA provider for a WLS domain, see here:

    http://buttso.blogspot.com/2010/05/changing-default-jpa-provider-in.html

  6. With the EJB project now complete, the JSF pages can be generated for the application.  In the Web project, this is done using the "JSF Pages from Entity Classes ..." wizard. 



    What this wizard generates is a set of JSF pages to represent each of the CRUD operations, a Controller ManagedBean to handle the various tasks required by each of the JSF view pages and the data interactions (with paging) and a EJB 3.1 @Stateless session bean to act as a session facade on the Widget entity.

    The new EJB in WAR packaging option available with Java EE 6 is not yet available on WebLogic Server, so the first trick here is to change the Web project to use the session facade that has already been generated in the EJB project.  This is possible because the NetBeans wizards generate the same underlying code for the session facade whether it is for an EJB specific project or as part of the JSF Pages for Entity Classes wizard. 

    Delete the session bean bean in the Web project, then adjust the JSF controller to use the local interface for the session bean in the EJB project:

    //@EJB
    //private sab.demo.widget.service.WidgetFacade ejbFacade;
    @EJB
    private sab.demo.widget.service.WidgetFacadeLocal ejbFacade;

    Note that EJB 3.1 supports a No-Interface view of an EJB, which WebLogic Server doesn't yet support.  So here we have changed the injection point to use the Local interface from our EJB project.

    There is also a getFacade method which needs this simple type change as well:

    //private WidgetFacade getFacade() {
    private WidgetFacadeLocal getFacade() {
        return ejbFacade;
    }

  7. Delete the persistence.xml file generated within the Web project, since this will now be supplied with the EJB project.

  8. Modify the web.xml file and change the "version" attribute to be "2.5" to specify a valid version for WebLogic Server:

    <web-app version="2.5" ... >

  9. Using the "New ..." wizard, add a WebLogic Deployment descriptor to the Web project, and specify a shared library reference to the JSF 2.0 shared library that WebLogic Server supplies.

    <?xml version="1.0" encoding="UTF-8"?>
    <weblogic-web-app>
        <context-root>Widget</context-root>
        <library-ref>
            <library-name>jsf</library-name>
           <specification-version>2.0</specification-version>
           <implementation-version>1.0.0.0_2-0-2</implementation-version>
        </library-ref>   
    </weblogic-web-app>

    See the links for more details about JSF 2.0 and WebLogic Server, including instructions for how to deploy and reference the shared-library:

    http://buttso.blogspot.com/2010/05/jsf-20-support-in-weblogic-server-1033.html
    http://buttso.blogspot.com/2011/03/jsf-with-managed-beans-and-dependency.html

  10. Build the final application into an EAR file that is ready for deployment.

    Deploying the Application to WebLogic Server
    1. To deploy a JSF 2.0 application to WebLogic Server, the JSF 2.0 shared-library must be deployed.  See links referenced above for details on how to do this.

      http://buttso.blogspot.com/2010/05/jsf-20-support-in-weblogic-server-1033.html
      http://buttso.blogspot.com/2011/03/jsf-with-managed-beans-and-dependency.html

    2. To use JPA 2.0 with WebLogic Server, two optional libraries within the WebLogic Server installation must be placed into the classpath.  This can be automated through the use of a SmartUpdate patch, or it can be performed manually by setting a PRE_CLASSPATH environment variable and specifying the required libraries before starting the WebLogic Server domain. 

      $ export PRE_CLASSPATH=/Users/sbutton/Java/wls-1035-dev/modules/com.oracle.jpa2support_1.0.0.0_2-0.jar:/Users/sbutton/Java/wls-1035-dev/modules/javax.persistence_1.0.0.0_2-0-0.jar
      See the documentation for more details as needed:

      http://download.oracle.com/docs/cd/E17904_01/web.1111/e13720/using_toplink.htm#CIHDJHHI

    3. The application is also using the Bean Validation specification which is not supplied with WebLogic Server 10.3.4.  To ensure that the JSF 2.0 and JPA 2.0 implementation in TopLink can see the Bean Validation implementation and automatically enlist it's services, I added it as an additional library to the PRE_CLASSPATH environment variable:

      $ export PRE_CLASSPATH=${PRE_CLASSPATH):/Users/sbutton/Java/glassfish-31/glassfish3/glassfish/modules/bean-validator.jar

      Note here I am just referencing the library from a local GlassFish installation I have.  I could copy this library out into a separate location or even download it independently and reference it.  Call me lazy if you will ... :-)

    4. Start a WebLogic Server domain

    5. Using the WebLogic Console, configure the required datasource (jdbc/sample) to point at the Derby database and test to ensure it is working.

    6. Using the console, deploy the application.


    Test the application

    With the application deployed, it can be tested to observe the JSF 2.0, JPA 2.0 and Bean Validation uses working on WebLogic Server.

    For instance, create a new Widget and specify an incorrect email address.  You'll see that JSF will automatically detect the invalid value based on the @Pattern constraint set on the Widget entity, and display the accompanying message as an error message on the page.


    Correcting the email address value, the entry can be successfully be saved.



    Looking at the stdout on the console where the WLS domain was started, the use of JPA 2.0 via EclipseLink and the automatic enlistment of the Bean Validation implementation can be seen in the lines below:

    <May 16, 2011 3:58:26 PM CST> <Notice> <WebLogicServer> <BEA-000360> <Server started in RUNNING mode>
    May 16, 2011 3:58:40 PM org.hibernate.validator.util.Version <clinit>
    INFO: Hibernate Validator 4.1.0.Final
    May 16, 2011 3:58:40 PM org.hibernate.validator.engine.resolver.DefaultTraversableResolver detectJPA
    INFO: Instantiated an instance of org.hibernate.validator.engine.resolver.JPATraversableResolver.
    <May 16, 2011 3:58:40 PM CST> <Notice> <EclipseLink> <BEA-2005000> <2011-05-16 15:58:40.781--ServerSession(1625943009)--EclipseLink, version: Eclipse Persistence Services - 2.1.3.v20110304-r9073>
    <May 16, 2011 3:58:40 PM CST> <Notice> <EclipseLink> <BEA-2005000> <2011-05-16 15:58:40.782--ServerSession(1625943009)--Server: 10.3.5.0>
    <May 16, 2011 3:58:41 PM CST> <Notice> <EclipseLink> <BEA-2005000> <2011-05-16 15:58:41.266--ServerSession(1625943009)--file:/Users/sbutton/Projects/Domains/wls1035/servers/AdminServer/tmp/_WL_user/Widget/qb0nwv/Widget-EJB.jar_Widget-EJBPU login successful>

    If you forget to specify the JPA provider using the <provider> element in config.xml and deploy the application to a default WLS domain, then you may see the following error message when you try and access the application:


    This exception indicates that an application is using the JPA 2.0 API, but WebLogic Server can't find a JPA 2.0 provider.  This is the default condition of a WLS domain where the Kodo/Open JPA 1.0 provider is supplied at runtime.
     
    This can be easily modified as described above by specifying an explicit <provider> value for EclipseLink (or Hibernate if you are using that) or by altering the default JPA provider at the domain level using the WebLogic Console:



    Summary

    It proved to be quite straight forward to take the Java EE 6 CRUD application generated by NetBeans and alter it slightly to deploy and run successfully on WebLogic Server 10.3.4, using it's JSF 2.0 and JPA 2.0 support.

    1 comment:

    Anonymous said...

    The only tutorial I found which explains EJB3.1+WebLogic+Netbeans+JSF2! Great job - my last search result after 4 hours of searching. Thanks.