Skip navigation
2011

This time I would like to guide you through migration of Seam Booking example which is Enterprise application - EAR.

 

Seam EAR migration is a little complicated in comparing to Seam JPA example. But what we have learnt from JPA example migration, we can use also in this EAR migration.

 

Basic overview of migration steps:

# Initialization of JSF 1.2 instead of default JSF 2,

# Bundling older hibernate jars than what are provided in JBoss AS7 by default,

# Changes in JNDI bindings  due new [Java EE 6 JNDI portable syntax|http://download.oracle.com/javaee/6/tutorial/doc/gipjf.html#girgn]. (Note: there is a little mistake in that tutorial - see [JAVAEETUTORIAL-44|http://java.net/jira/browse/JAVAEETUTORIAL-44]

 

First 2 steps we've done already in [JPA example migration|http://community.jboss.org/blogs/marek-novotny/2011/07/15/seam-2-jpa-example-on-jboss-as7], but third step is new one because of using EJBs in EAR.

 

So let's start:

 

# Add new file jboss-deployment-structure.xml with the following content into _jboss-seam-booking.ear/META-INF/_:{code:xml}

<jboss-deployment-structure xmlns="urn:jboss:deployment-structure:1.0">

  <deployment>

        <dependencies>

          <module name="org.apache.log4j" export="true"/>

          <module name="org.dom4j" export="true"/>

          <module name="org.apache.commons.logging" export="true"/>

          <module name="org.apache.commons.collections" export="true"/>

          <module name="javax.faces.api" slot="1.2" export="true"/>

          <module name="com.sun.jsf-impl" slot="1.2" export="true"/>

        </dependencies>

  </deployment>

  <sub-deployment name="booking-web.war">

      <exclusions>

          <module name="javax.faces.api" slot="main"/>

          <module name="com.sun.jsf-impl" slot="main"/>

        </exclusions>

        <dependencies>

          <module name="javax.faces.api" slot="1.2"/>

          <module name="com.sun.jsf-impl" slot="1.2"/>

        </dependencies>

  </sub-deployment>

</jboss-deployment-structure>

{code}

# Next remove/comment hibernate property for cache provider class in jboss-seam-booking.jar/META-INF/persistence.xml:

{code:xml}

<!-- <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/> -->

{code}

# Add the following dependencies from seam distribution (seam/lib directory) into jboss-seam-booking.ear/lib directory, which are in JBoss AS 5/6 in different versions:{noformat}slf4j-api.jar

slf4j-log4j12.jar

hibernate-core.jar

hibernate-entitymanager.jar

hibernate-validator.jar

hibernate-annotations.jar

hibernate-commons-annotations.jar{noformat}

# Next we need to change JNDI lookup strings in jboss-seam-booking.war/WEB--INF/components.xml. Because of new JNDI portable rules, AS7 now binds EJBs with JNDI portable rules like for instance:

{noformat}

java:global/seam-booking/booking-ejb/HotelSearchingAction!org.jboss.seam.example.booking.HotelSearching

java:app/booking-ejb/HotelSearchingAction!org.jboss.seam.example.booking.HotelSearching

java:module/HotelSearchingAction!org.jboss.seam.example.booking.HotelSearching

java:global/seam-booking/booking-ejb/HotelSearchingAction

java:app/booking-ejb/HotelSearchingAction

java:module/HotelSearchingAction

{noformat} and for Seam framework EJBs like for instance:

{noformat}

java:global/seam-booking/jboss-seam/EjbSynchronizations!org.jboss.seam.transaction.LocalEjbSynchronizations

java:app/jboss-seam/EjbSynchronizations!org.jboss.seam.transaction.LocalEjbSynchronizations

java:module/EjbSynchronizations!org.jboss.seam.transaction.LocalEjbSynchronizations

java:global/seam-booking/jboss-seam/EjbSynchronizations

java:app/jboss-seam/EjbSynchronizations

java:module/EjbSynchronizations

{noformat}

Notice difference between _java:app/jboss-seam/EjbSynchronizations_ and _java:app/booking-ejb/HotelSearchingAction_.

We can't use the single jndiPattern like we did before in JBoss AS 5/6. So there are a few solutions to do it, I chose adding jndi-name for every EJB into WEB-INF/components.xml:

{code:xml}

<component class="org.jboss.seam.transaction.EjbSynchronizations" jndi-name="java:app/jboss-seam/EjbSynchronizations"/>

<component class="org.jboss.seam.async.TimerServiceDispatcher" jndi-name="java:app/jboss-seam/TimerServiceDispatcher"/>

<component class="org.jboss.seam.example.booking.AuthenticatorAction" jndi-name="java:app/booking-ejb/AuthenticatorAction" />

<component class="org.jboss.seam.example.booking.BookingListAction"  jndi-name="java:app/booking-ejb/BookingListAction" />

<component class="org.jboss.seam.example.booking.RegisterAction" jndi-name="java:app/booking-ejb/RegisterAction" />

<component class="org.jboss.seam.example.booking.HotelSearchingAction" jndi-name="java:app/booking-ejb/HotelSearchingAction" />

<component class="org.jboss.seam.example.booking.HotelBookingAction" jndi-name="java:app/booking-ejb/HotelBookingAction" />

<component class="org.jboss.seam.example.booking.ChangePasswordAction" jndi-name="java:app/booking-ejb/ChangePasswordAction" />

{code}

You can alternatively add @JNDIName(value="") annotation with JNDI path. Example of changed SLSB is below, look at _@JndiName_ annotation, detailed description is at Seam2 reference documentation:

{code:java}

@Stateless

@Name("authenticator")

@JndiName(value="java:app/booking-ejb/AuthenticatorAction")

public class AuthenticatorAction

    implements Authenticator

{

...

}

{code}

 

That is all in Booking example modifications.

 

Unfortunatelly the example how is done will deploy with error in JSF initialization.

{noformat}

ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/seam-booking]] (MSC service thread 1-1) Exception sending context initialized event to listener instance of class com.sun.faces.config.ConfigureListener: com.sun.faces.config.ConfigurationException: CONFIGURATION FAILED! org.jboss.seam.jsf.SeamApplicationFactory

        at com.sun.faces.config.ConfigManager.initialize(ConfigManager.java:215) [jsf-impl-1.2_13.jar:1.2_13-b01-FCS]

        at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:196) [jsf-impl-1.2_13.jar:1.2_13-b01-FCS]

        at org.apache.catalina.core.StandardContext.contextListenerStart(StandardContext.java:3368) [jbossweb-7.0.0.CR4.jar:7.0.0.Final]

        at org.apache.catalina.core.StandardContext.start(StandardContext.java:3821) [jbossweb-7.0.0.CR4.jar:7.0.0.Final]

        at org.jboss.as.web.deployment.WebDeploymentService.start(WebDeploymentService.java:70) [jboss-as-web-7.0.0.Final.jar:7.0.0.Final]

        at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1765)

        at org.jboss.msc.service.ServiceControllerImpl$ClearTCCLTask.run(ServiceControllerImpl.java:2291)

        at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [:1.6.0_26]

        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [:1.6.0_26]

        at java.lang.Thread.run(Thread.java:662) [:1.6.0_26]

Caused by: java.lang.InstantiationException: org.jboss.seam.jsf.SeamApplicationFactory

        at java.lang.Class.newInstance0(Class.java:340) [:1.6.0_26]

        at java.lang.Class.newInstance(Class.java:308) [:1.6.0_26]

        at javax.faces.FactoryFinder.getImplGivenPreviousImpl(FactoryFinder.java:537) [jsf-api-1.2_13.jar:1.2_13-b01-FCS]

        at javax.faces.FactoryFinder.getImplementationInstance(FactoryFinder.java:405) [jsf-api-1.2_13.jar:1.2_13-b01-FCS]

        at javax.faces.FactoryFinder.access$400(FactoryFinder.java:135) [jsf-api-1.2_13.jar:1.2_13-b01-FCS]

        at javax.faces.FactoryFinder$FactoryManager.getFactory(FactoryFinder.java:717) [jsf-api-1.2_13.jar:1.2_13-b01-FCS]

        at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:239) [jsf-api-1.2_13.jar:1.2_13-b01-FCS]

        at com.sun.faces.config.processor.FactoryConfigProcessor.verifyFactoriesExist(FactoryConfigProcessor.java:186) [jsf-impl-1.2_13.jar:1.2_13-b01-FCS]

        at com.sun.faces.config.processor.FactoryConfigProcessor.process(FactoryConfigProcessor.java:131) [jsf-impl-1.2_13.jar:1.2_13-b01-FCS]

        at com.sun.faces.config.ConfigManager.initialize(ConfigManager.java:205) [jsf-impl-1.2_13.jar:1.2_13-b01-FCS]

{noformat}

 

This is a bug in AS 7 Final. But I don't write this blog if there is not a way how to work around it ;-).

I discussed the issue with AS 7 developers and they fixed it in upstream sources.

So we need to download AS7 snapshot or build AS 7 from git sources. The easier is to get working binaries at [latest JBoss AS7 snapshot|http://hudson.jboss.org/jenkins/view/JBoss AS/job/JBoss-AS-7.0.x/lastSuccessfulBuild/artifact/build/target/jboss-7.0.x.zip]

 

And that is realy all!

 

I am just succesfully customized Seam 2 JPA example to deploy and run on JBoss AS 7 server, so I will share steps which are required to do for that.

 

First JBoss AS 7 is great in start up time, deployment time, classloading isolation and much more. See JBoss AS7 page for more and detailed description!

 

Just quick info - Seam 2 JPA example is demonstrating JPA 1 usage, it uses JSF 1.2 and Richfaces 3.3.3.Final. Thanks to great classloading isolation Seam 2 can live and works just fine in JBoss AS7 although it is primarily targeted for Java EE 6, where are JSF2, JPA 2.

 

First step in customizing the example is set up of datasource. JBoss AS 7 release is changing the name of default datasource, which is for demos/examples. Now the default datasource is called java:jboss/datasources/ExampleDS, you have to just change the referenced datasource JNDI in the example or create new datasource with old name java:/DefaultDS.

 

I created new datasource with old name, because I am using many old examples and I don't want to change them all. New datasource is basically a clone of existing ExampleDS.

 

Start Jboss AS7 standalone instance by writing in terminal:

<installed_path_to_jbossas7>/bin/standalone.sh(on linux)
<installed_path_to_jbossas7>/bin/standalone.bat(on windows)

In another terminal window start CLI admin interface by:

<installed_path_to_jbossas7>/bin/jboss-admin.sh --connect(on linux)
<installed_path_to_jbossas7>/bin/jboss-admin.bat --connect(on windows)

Then write the command for creating actual datasource:

add-data-source --jndi-name=java:/DefaultDS --connection-url=jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 --username=sa --password=sa --pool-name=DefaultDS_pool --driver-name=h2

 

The above command is self describing ;-).

 

Now a few customizations which are done in jboss-seam-jpa.war:

  1. Remove jboss-web.xml from jboss-seam-jpa.war/WEB-INF/ - defined class loading in jboss-web.xml is now default behaviour.

  2. Comment or remove hibernate property

    <property name="hibernate.cache.provider_class" value="org.hibernate.cache.HashtableCacheProvider"/>

    in jboss-seam-jpa.war/WEB-INF/classes/META-INF/persistence.xml

     

  3. Add the following dependencies from seam distribution (seam/lib directory) into jboss-seam-jpa.war/WEB-INF/lib directory, which are in JBoss AS 5/6 in different versions:
    slf4j-api.jar
    slf4j-log4j12.jar

    hibernate-core.jar
    hibernate-entitymanager.jar
    hibernate-validator.jar
    hibernate-annotations.jar
    hibernate-commons-annotations.jar
  4. Create new file jboss-deployment-structure.xml and add it to jboss-seam-jpa.war/WEB-INF/ with the following content:
<jboss-deployment-structure> 
   <deployment>
        <exclusions>
          <module name="javax.faces.api" slot="main"/>
          <module name="com.sun.jsf-impl" slot="main"/>
        </exclusions>
        <dependencies>
          <module name="org.apache.commons.logging" />
          <module name="org.apache.commons.collections" />
          <module name="org.apache.log4j" />
          <module name="org.dom4j" />
          <module name="javax.faces.api" slot="1.2"/>
          <module name="com.sun.jsf-impl" slot="1.2"/>
        </dependencies>
    </deployment>   
</jboss-deployment-structure>

 

 

I will shortly describe why I did step 3 and 4. By default Jboss AS 7 is configured for JSF2, but Seam 2 is integrated with JSF 1.2, so thanks to class loading isolation we can have in Jboss AS 7 set up more than one version of the same library in our case JSF 1.2 and JSF 2. Both JSF's implementations are preconfigured in AS7 release, we just have to include 1.2 slot and default JSF 2  to exclude from web application deployment. The remaining two dependencies – dom4j and commons logging is provided by container and Seam 2 expects them as provided.

 

Last step 4 is replacement of provided hibernate dependencies and their dependencies, which are bundled directly in web application WEB-INF/lib subdirectory. This is because Seam 2 is integrated with older hibernate versions which is not backward compatible with hibernate what is in AS7.

 

Enjoy new JBoss AS 7 with „old“ Seam2!