Help

I finally got around to weaving my modifications for adding GlassFish support to seam-gen (documented here and here) into the Seam project (JBSEAM-1619). While working on integration the changes, I managed to close the few remaining gaps and also add support for JBoss AS 5!

Let me tell you, it was quite a task to fine tune the configuration and build to support all twelve deployment variations; EAR and WAR archives for GlassFish V2/V3, JBoss AS 4.2.x and JBoss AS 5.0.x in both exploded and packaged format. (Double that number if you consider that I added support to both RichFaces and ICEfaces projects). But surprisingly enough, all of them now work out of the box (with the exception of a few small configuration changes you have to make to deploy an EAR project to GlassFish).

The persistence paradox

The biggest challenge was the persistence unit configuration. This stems from the fact that packaging requirements for persistence units differs between EARs and WARs. To complicate matters, there are variations between how application servers interpret and enforce these requirements. I want to spend some time explaining the situation and how I was able to strike a balance, because it's important for understanding how the project build now works.

Let's start by rewinding to the way things were setup. There's an expectation in the JPA specification that the application server will bootstrap the persistence units defined in META-INF/persistence.xml in a Java EE environment. Of course, it would be pretty limiting if that were the only way to use JPA. So an API is provided allowing an application to load a persistence unit manually in a Java SE environment (or when the container doesn't support this expectation). Understandably, it took some time for this expectation to be met as vendors worked to bring their application server into compliance with Java EE 5 (the first specification to include JPA).

For containers that don't support loading persistence units, whether for a specific archive type (EAR or WAR) or in general, Seam can step in and take over this task. That's the purpose of the following component definition, defined in the Seam component descriptor (i.e., components.xml):

<persistence:entity-manager-factory name="entityManagerFactory" persistence-unit-name="example"/>

The value of persistence-unit-name attribute matches the name of one of the persistence units defined in META-INF/persistence.xml.

Versions of JBoss AS prior to JBoss AS 5 do not support loading persistence units in a WAR, so it's necessary to delegate this task to Seam. The same is true for any version of Tomcat. GlassFish is truer to the spec. It will load a persistence unit, but only if it is declared in a persistence unit ref in WEB-INF/web.xml as follows:

<persistence-unit-ref>
    <persistence-unit-ref-name>example/pu</persistence-unit-ref-name>
    <persistence-unit-name>example</persistence-unit-name>
</persistence-unit-ref>

The persistence unit ref has another purpose. After the persistence unit is loaded, the EntityManagerFactory instance will be bound to JNDI using the value of the persistence-unit-ref-name in the java:comp/env namespace (in this example the full JNDI name would be java:comp/env/example/pu). Prior to version 5, JBoss AS did not support this JNDI binding. To provide a temporary workaround, Hibernate can offer to bind the EntityManagerFactory to JNDI itself under the proprietary JBoss AS namespace java:/. This feature is activated if the following property is present in META-INF/persistence.xml:

<property name="jboss.entity.manager.factory.jndi.name" value="java:/exampleEntityManagerFactory"/>

JBoss AS 5 supports the compliant approach to binding the EntityManagerFactory to JNDI, but has another caveat. It automatically loads all persistence units defined in META-INF/persistence.xml regardless of whether they are declared in a persistence unit ref. This fact has confused a lot of people and is the root cause of most broken Seam deployments on JBoss AS 5 right now. Suffice to say, it's best to only define persistence units you intend to load and stand aside and let the container load them.

So far the discussion has applied to WAR deployments. Things get even trickier with EARs. Technically, persistence units (the descriptor and classes) are supposed to be packaged in their own JAR and then packaged in the WAR under the WEB-INF/lib directory or packaged directly in the EAR. However, the persistence units can also be packaged in the EJB JAR. Either way, you really have to know what you are doing to get all the references setup correctly so that the persistence unit is loaded correctly and can be bound to JNDI where the WAR can access it. When the application server works the way it's supposed to, the following persistence unit configuration will suffice:

<persistence-unit-ref>
    <persistence-unit-ref-name>example/pu</persistence-unit-ref-name>
    <persistence-unit-name>../example.jar#example</persistence-unit-name>
</persistence-unit-ref>

Notice how the persistence unit name now includes the relative location of the JAR file within the EAR which contains the persistence unit descriptor and classes. For some reason, GlassFish does not understand this configuration and I've had incorporate a temporary workaround (see resources/WEB-INF/web.xml of a seam-gen EAR project for instructions).

To summarize the various permutations, I have put together a matrix of how persistence units are handled and how they are loaded in seam-gen projects per archive type and environment:

WAR EAR
JBoss AS 4.2 JBoss AS 5.0 GlassFish JBoss AS 4.2 JBoss AS 5.0 GlassFish
Bootstrapped by Seam container container container container container
Depends on persistence unit ref no no yes no no yes
JNDI binding mechanism n/a both standard proprietary both standard
Autodetects entities yes yes yes yes yes no

As you can imaging, dealing with all of these variations requires substantial support from the build. Fortunately, I was able to leverage a feature of Seam that accommodates these needs. You can use Ant-style tokens in the Seam component descriptor and Seam will replace them using the replacement values defined in the components.properties file at the root of the classpath. But even the replacement values have to be dynamic to support the various environments. So I also use Ant-style tokens in that file, which are replaced by the Ant build. So there is a two-phase substitution that occurs. Here's the contents of the components-dev.properties file:

jndiPattern=@ejbJndiPattern@
debug=true
seamBootstrapsPu=@seamBootstrapsPu@
seamEmfRef=@seamEmfRef@
puJndiName=@puJndiName@

Here's the resulting components.properties prepared from this template by a build targeting JBoss AS 5 in an EAR project named example:

jndiPattern=example/#{ejbName}/local
debug=true
seamBootstrapsPu=false
seamEmfRef=#{null}
puJndiName=java:comp/env/example/pu

Here's the components.properties prepared for a build targeting JBoss AS 4 in a WAR project named example:

jndiPattern=example/#{ejbName}/local
debug=true
seamBootstrapsPu=true
seamEmfRef=#{entityManagerFactory}
puJndiName=#{null}

These tokens are applied to the following two component definitions in the Seam component descriptor:

<persistence:managed-persistence-context name="entityManager" auto-create="true"
                       entity-manager-factory="@seamEmfRef@"
                   persistence-unit-jndi-name="@puJndiName@"/>

<persistence:entity-manager-factory name="entityManagerFactory"
                   persistence-unit-name="@projectName@"
                               installed="@seamBootstrapsPu@"/>

Whew! That covers the JPA configuration. For more details on persistence unit configurations in both Java EE and Seam, check out chapter 9 of Seam in Action. I now want to briefly mention the new targets to support deployment to JBoss AS 5 and GlassFish.

JBoss AS 5 and GlassFish targets

As before, the seam-gen project build supports JBoss AS by default. But I'm now able to support both JBoss 4 and JBoss 5 using the same targets by inspecting the JBoss AS 5 installation directory (resolved from jboss.home) to determine which version of JBoss AS is being targeted. I simply check for the presence of a JAR file.

GlassFish does have it's own set of targets. All of the targets that pertain to GlassFish reside in the file glassfish-build.xml at the root of the project. This file is imported into the main Ant build. All of the GlassFish targets are prefixed with gf- and closely mirror the targets for JBoss AS. There are also targets for controlling the GlassFish server. Here's a quick summary of the new targets, which are documented in the glassfish-readme.txt file:

gf-start - Starts GlassFish
gf-debug - Starts GlassFish in debug mode
gf-stop - Stops GlassFish
gf-reboot - Restarts GlassFish
gf-deploy-datasource - Deploys the datasource and connection pool to GlassFish
gf-explode - Deploys the exploded archive to GlassFish (restarts application if already deployed)
gf-hotdeploy - Hot deploys Java classes, Seam components, and web resources
gf-deploy - Deploys the packaged archive to GlassFish
gf-undeploy - Undeploys the exploded or packaged archive from GlassFish
gf-stage - Prepares an exploded archive targeting GlassFish
gf-archive - Prepares a packaged archive targeting GlassFish
gf-prepare - Prepares GlassFish for a seam-gen project deployment (calls gf-deploy-hibernate)
gf-deploy-hibernate - Deploys Hibernate as a JPA provider to GlassFish

You don't have to do anything to enable the support for GlassFish. It's provided right out of the box alongside support for JBoss AS. One of the gaps I was finally able to close as I worked on the GlassFish support was the deployment of an explode EAR. GlassFish kept choking on the jboss-seam.jar, which contains EJBs and is thus considered an EJB module. As it turns out, GlassFish does not support a hybrid of packaged and exploded archives. Thus, when you are deploying an exploded EAR, you need to also explode the jboss-seam.jar file, which the build takes care of for you.

The only trade off I had to make is that Hibernate is expected to be the JPA provider in GlassFish (note the target which deploys Hibernate). It's not that difficult to make the switch to another JPA provider, but suffice to say, Seam works best with Hibernate.

Growing Ivy

Seam projects are know for being pretty old school when it comes to library management. All of the JAR files are just dumped into the lib directory and picked out from there as needed. This makes it very difficult to share a seam-gen project because it's so large. I explained how to use Ivy to manage the dependencies for a seam-gen project in this entry. seam-gen now offers that configuration as an extension. To enable it, you simply run the following seam-gen target:

seam add-ivy

Right now, only RichFaces projects are supported, but supporting ICEfaces projects is just a matter of making a couple of changes to the dependencies.

Wrap up

So there you go, seam-gen is no longer stuck in a JBoss world. And for the early adopters, JBoss AS 5--the pride and joy of JBoss--is now supported. Adding Ivy to the project helps make it more lightweight, provides an easy way to download source JARs, and helps document which versions of the JARs are being used. Just check out Seam from SVN, build and enjoy!

15 comments:
 
14. Mar 2009, 22:53 CET | Link

The GF support of seam-gen is something I've been waiting for a long time. I will give it a try.

Thanks for the work!

ReplyQuote
 
15. Mar 2009, 23:44 CET | Link
Satan

Hi,EAR with JBoss AS 5.0.x,in this case i got a error: EntityManagerFactory not found in JNDI : java:comp/env/example/pu

I use jboss-seam-2.1.2-SNAPSHOT 15/03/09 and jboss-5.0.1.GA. Would you give it a try? thank you very much!

 
16. Mar 2009, 10:50 CET | Link

I just tested and it works for me. Check the logs as the application deploys and make sure you see lines like the following:

04:42:34,271 INFO  [NamingHelper] Creating subcontext: persistence.unit:unitName=vehicles.ear
04:42:34,272 INFO  [SessionFactoryObjectFactory] Bound factory to JNDI name: persistence.unit:unitName=vehicles.ear/vehicles.jar#vehicles
 
16. Mar 2009, 13:26 CET | Link
Geoffrey De Smet
Is maven support planned for seam-gen? Or will you be making maven archetypes which do the same thing as seam-gen?
 
16. Mar 2009, 14:52 CET | Link
Satan

Thank you for reply.i have checked the logs.

16:14:21,285 INFO [NamingHelper] Creating subcontext: persistence.unit:unitName=forum.ear 16:14:21,285 INFO [SessionFactoryObjectFactory] Bound factory to JNDI name: persistence.unit:unitName=forum.ear/forum.jar#forum

but i still get this error:

Exception during request processing: Caused by javax.el.ELException with message: "javax.ejb.EJBTransactionRolledbackException: EntityManagerFactory not found in JNDI : java:comp/env/forum/pu" org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:339) org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:348) org.jboss.el.parser.AstPropertySuffix.invoke(AstPropertySuffix.java:58) org.jboss.el.parser.AstValue.invoke(AstValue.java:96) org.jboss.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276) org.jboss.seam.core.Expressions$2.invoke(Expressions.java:175) org.jboss.seam.navigation.Page.preRender(Page.java:293) org.jboss.seam.navigation.Pages.preRender(Pages.java:366) org.jboss.seam.jsf.SeamPhaseListener.preRenderPage(SeamPhaseListener.java:562) org.jboss.seam.jsf.SeamPhaseListener.beforeRenderResponse(SeamPhaseListener.java:473) org.jboss.seam.jsf.SeamPhaseListener.beforeServletPhase(SeamPhaseListener.java:146) org.jboss.seam.jsf.SeamPhaseListener.beforePhase(SeamPhaseListener.java:116) com.sun.faces.lifecycle.Phase.handleBeforePhase(Phase.java:214) com.sun.faces.lifecycle.Phase.doPhase(Phase.java:96) com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139) javax.faces.webapp.FacesServlet.service(FacesServlet.java:266) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83) org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:178) org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290) org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:390) org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:517) org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:56) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.jboss.seam.web.LoggingFilter.doFilter(LoggingFilter.java:58) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.jboss.seam.web.HotDeployFilter.doFilter(HotDeployFilter.java:53) org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96) org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:235) org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:190) org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:433) org.jboss.web.tomcat.security.JaccContextValve.invoke(JaccContextValve.java:92) org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.process(SecurityContextEstablishmentValve.java:126) org.jboss.web.tomcat.security.SecurityContextEstablishmentValve.invoke(SecurityContextEstablishmentValve.java:70) org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) org.jboss.web.tomcat.service.jca.CachedConnectionValve.invoke(CachedConnectionValve.java:158) org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:330) org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:829) org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:601) org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447) java.lang.Thread.run(Unknown Source)

this is my only component: @Stateless @Name("homeAction") public class HomeAction implements HomeLocal{ @DataModel List<Category> categories; @In EntityManager entityManager; @Override public void loadCategories() { categories = entityManager.createQuery( "select c from Category c order by c.order").getResultList(); } }

If i replace java:comp/env/forum/pu with java:/forumEntityManagerFactory in my persistence-unit-jndi-name. everything works well I Wonder Why

 
19. Mar 2009, 15:16 CET | Link

Just use java:/forumEntityManagerFactory if it works. Don't try to force it. The main reason for standardizing the name is when you need to interoperable. It could be because your bean is a stateless session bean. I'd need to QA that.

 
19. Mar 2009, 15:18 CET | Link

This is the wrong place to discuss a question about Maven 2 version of seam-gen. Please direct questions to this page.

 
01. Apr 2009, 03:45 CET | Link
Wouter van Reeven

Hey Dan,

Thanks for the great work on seam-gen. I tested out the GlassFish support and created this blog post about it:

http://technology.amis.nl/blog/5168/testing-seam-gen-in-seam-212-snapshot-with-glassfish-v2

Thanks, Wouter van Reeven

 
05. Oct 2009, 07:14 CET | Link
Jason
Seam applications does not work with GlassFish.
Each of apps crash on GlassFish due Deployment with different messages on logfile:

1) java.lang.NoClassDefFoundError: javax/faces/application/ApplicationFactory
2) Cannot cast org.hibernate.ejb.HibernatePersistence to javax.persistence.spi.PersistenceProvider
3) LinkageError: javassist/bytecode/ClassFile
4) PersistentPermissionResolver] no permission store available
...

No any Seam example work on GlassFish :(
 
05. Oct 2009, 17:30 CET | Link

The jee5/booking example runs on JBoss AS. Take a look at the readme file there to find out how.

 
05. Oct 2009, 19:42 CET | Link
Jason

Looked and tried, the readme is wrong, jee5/booking runs on JBoss AS as wery well but does not work on GlassFish

 
05. Oct 2009, 20:28 CET | Link

Are you using Glassfish V3? If you are, then of course it's not going to work as Glassfish V3 contains all the RI for the EE6 technologies. So Hibernate as a JPA provider won't work (3.5 will be JPA 2.0 compliant), some of the JSF api's have changed, etc. If you want to use Seam on Glassfish use V2.

 
05. Oct 2009, 21:58 CET | Link
Have you tried the instructions for Seam samples on GlassFish at:

http://blog.arungupta.me/2009/04/totd-77-running-seam-examples-with-glassfish/

?

Can you provide more details about your configuration ?

-Arun
 
09. Sep 2010, 18:24 CET | Link

Hey...thanks for the post, very clear and direct to the point....unfortunately i still can't run my app.....

Situation: Jboss AS 5 - jboss seam 2.2 - seam-gen app (built on a postgres db) - package deployed as ear

For truth, i could run my application, because the deploy goes ok, but the problem is the first time i access a stateful session bean....it says target unreachable, componentName resolved to null....

here's my configuration:

components.xml

<core:init debug="false" jndi-pattern="@jndiPattern@"/>
<persistence:entity-manager-factory installed="false"
  name="entityManagerFactory" persistence-unit-name="SeamADMS"/>

 <persistence:managed-persistence-context name="entityManager" auto-create="true"
  entity-manager-factory="#{admsEntityManagerFactory}" persistence-unit-jndi-name="java:comp/env/SeamADMS/emf"/>

web.xml

<persistence-unit-ref>
      <persistence-unit-ref-name>SeamADMS/emf</persistence-unit-ref-name>
      <persistence-unit-name>SeamADMS</persistence-unit-name>
   </persistence-unit-ref>

persistence.xml:

<persistence-unit name="SeamADMS" transaction-type="JTA">
      <provider>org.hibernate.ejb.HibernatePersistence</provider>
      <jta-data-source>java:/SeamADMSDatasource</jta-data-source>
      <properties>
         <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
         <property name="hibernate.hbm2ddl.auto" value="none"/>
         <property name="hibernate.show_sql" value="true"/>
         <property name="hibernate.format_sql" value="true"/>
         <!-- Only relevant if Seam is loading the persistence unit (Java SE bootstrap) -->
         <property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
         <!-- Aggiunto il parametro jndi, col nome uguale a quello parametrizzato nel components.xml -->
         <property name="jboss.entity.manager.factory.jndi.name" value="java:admsEntityManagerFactory"/>
      </properties>
   </persistence-unit>

my session beans are marked like:

@Stateful
@Scope(ScopeType.SESSION)
@Name("utils")
public class Utils {
	
    @PersistenceContext(type = PersistenceContextType.EXTENDED) EntityManager entityManager;

I run into several configuration during these days, but none of them works, unfortunately.....can u please clearify me the config? or maybe post a simple ear example? Thanks in advance.....

 
24. Jun 2014, 11:55 CET | Link

This market is fast and easy to use, due to the fact that it is an online trading process. Here we are used some simples and easy-to-executeforex trading strategy that any person can use. Lets see the various kinds of Forex strategies methods For example, it also give permits a business in the United States to import goods from the European Union member states like United Kingdom, and pay euros, even though its income is in United States dollars. In foreign exchange markets it also supports direct speculation in the value of currencies, and the carry trade between two currencies.

Post Comment