Wednesday, May 25, 2011

Using Seam 3 with Glassfish 3.1

Seam 3 builds on top of the Java EE 6 standards, filling in holes and omissions in the functionality provided by the specs and providing important enhancements that many programmers would otherwise find themselves implementing themselves. Seam 3 Solder in particular addreses some of the frustrating limitations in the CDI and Java EE 6 specs, providing well-engineered and easily re-used solutions to common problems.

Being a JBoss project, Seam 3 is unsurprisingly better tested on the JBoss application server. However, its goals explicitly cover portability and it's supposed to work on Glassfish and - where possible - even on servlet containers like Tomcat and Jetty. Perhaps unsurprisingly, Glassfish doesn't get as much attention , so it's a bit harder to use Seam 3.0.0.Final on Glassfish than it is on JBoss. It appears that it was also harder for the Seam 3 folks to get quick fixes for the many Glassfish bugs they found into Glassfish than it was for them to get fixes into JBoss AS, so many of the fixes for issues found in Seam 3 won't hit a Glassfish stable release until 3.2 comes out, if then.

In the mean time, there are some quirks to work around. The Seam 3 project documents Glassfish 3.1 compatibility issues here and you should read that document before continuing.

Many of the issues are solved pretty easily once you know what to do and where to look. It's well worth using Seam 3 instead of rolling your own solutions to many of the problems it tackles, so read on.

Update Weld (the CDI implementation) in Glassfish

Some of the bugs were in Weld. Those have been fixed, but Glassfish has not yet been updated to the latest Weld release. You can, and should, update Glassfish to the latest Weld yourself by updating weld-osgi-bundle.jar according to these instructions on the Seam Glassfish 3.1 compatibility page.

This will resolve several issues immediately, and will get you side-benefits like improved error messages from Weld in some previously hard-to-debug cases.

Work around Glassfish's over-strict class scanner

The biggest issue you will run into is a Glassfish limitation (GLASSFISH-14808) that causes Glassfish to try to resolve a reference to a class that is supposed to be hidden by the @Veto annotation and to abort deployment when the resolution fails. Because of this problem, dependencies of Seam 3 modules that are supposed to be optional become mandatory on Glassfish 3.1.

There doesn't seem to be any listing of the dependencies of a given module when deployed under Glassfish 3.1, so it's a bit of a guessing game. One thing that will help you a lot, though, is the Seam 3 project's Maven infrastructure, which provides the Seam 3 BOM as a central place to manage dependencies rather than doing it directly in the parent POM. This wonderful choice allows 3rd party Maven projects to import the Seam 3 BOM into their dependencyManagement sections, making it trivial to use the correct versions of the correct optional dependencies and to use all the right versions of all the Seam 3 modules together.

To use the Seam 3 BOM, import it into your DependencyManagement section.

<project ...>
    ...
    <dependencyManagement>
        <dependencies>
             <dependency>
                <groupId>org.jboss.seam</groupId>
                <artifactId>seam-bom</artifactId>
                <version>${seam.version}</version>
                <scope>import</scope>
                <type>pom</type>
             </dependency>
             ...
        </dependencies>
    </dependencyManagement>
</project>

You may now specify Seam 3 dependencies without an explicit version, as if you'd declared them in your dependencyManagement section directly. For example, with Seam 3 Faces:

<dependency>
   <groupId>org.jboss.seam.faces</groupId>
   <artifactId>seam-faces-api</artifactId>
   <!-- Override the Seam 3 BOM managed version, because Seam 3 Faces 3.0.1 is required to use Seam 3 Faces on Glassfish 3.1 -->
   <version>3.0.1.Final</version>
</dependency>
<dependency>
   <groupId>org.jboss.seam.faces</groupId>
   <artifactId>seam-faces-impl</artifactId>
   <scope>runtime</scope>
   <!-- Override the Seam 3 BOM managed version, because Seam 3 Faces 3.0.1 is required to use Seam 3 Faces on Glassfish 3.1 -->
   <version>3.0.1.Final</version>
</dependency>
<!-- Required by Seam Faces (via Seam Solder and/or Seam International) on GF 3.1, but not explicitly depended on -->
<dependency>
    <groupId>joda-time</groupId>
    <artifactId>joda-time</artifactId>
    <scope>runtime</scope>
</dependency>
<!-- Required by Seam Faces on GF 3.1, but not explicitly depended on -->
<dependency>
    <groupId>com.ocpsoft</groupId>
    <artifactId>prettyfaces-jsf2</artifactId>
    <scope>runtime</scope>
</dependency>

Using the Seam 3 BOM won't magically add the optional dependencies that're required on Glassfish 3.1, but it'll make managing them easier. You can still override versions specified by the BOM, as shown above where we force the use of Seam 3 Faces 3.0.1 because Seam 3 Faces 3.0.0.Final didn't work quite right on Glassfish 3.1.

If you deploy a project that uses Seam 3 to Glassfish and deployment fails with classNotDef errors, most likely you need to add another optional dependency that turns out not to be optional on GF 3.1. Look up which artifact the missing class is in and add it. Make sure to add them as runtime dependencies so you don't accidentally introduce a real dependency on them in your code!

For example, if I deploy Seam 3 Faces without the above added dependencies I'll see errors like:

SEVERE: Class [ org/joda/time/DateTimeZone ] not found. Error while loading [ class org.jboss.seam.international.datetimezone.DefaultDateTimeZoneProducer ]
...
SEVERE: Exception while loading the app
SEVERE: Exception while loading the app : org/joda/time/DateTimeZone
java.lang.ClassNotFoundException: org.joda.time.DateTimeZone
 at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1518)
        ...
...
WARNING: The log message is null.

if JodaTime is not added as a dependency. Similarly:

Error occurred during deployment: Exception while loading the app : com/ocpsoft/pretty/faces/spi/ConfigurationProvider. Please see server.log for more details.

SEVERE: Exception while loading the app
WARNING: The log message is null.
SEVERE: Exception while loading the app : com/ocpsoft/pretty/faces/spi/ConfigurationProvider
java.lang.ClassNotFoundException: com.ocpsoft.pretty.faces.spi.ConfigurationProvider
 at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1518)
 at org.glassfish.web.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1368)
        ...

if PrettyFaces isn't added.

Weird BeanManager exceptions

On deployment I also sometimes encounter an incredibly verbose 300+ line spew of exceptions including key lines:

CONFIGURATION FAILED! Failed to locate BeanManager using any of these providers: org.jboss.seam.solder.beanManager.DefaultJndiBeanManagerProvider(11), org.jboss.seam.solder.beanManager.ServletContainerJndiBeanManagerProvider(10). Please see server.log for more details.

org.jboss.seam.solder.beanManager.BeanManagerUnavailableException: Failed to locate BeanManager using any of these providers: org.jboss.seam.solder.beanManager.DefaultJndiBeanManagerProvider(11), org.jboss.seam.solder.beanManager.ServletContainerJndiBeanManagerProvider(10)
 at org.jboss.seam.solder.beanManager.BeanManagerLocator.getBeanManager(BeanManagerLocator.java:91)
 ...

SEVERE: PWC1306: Startup of context /myapproot failed due to previous errors
SEVERE: PWC1305: Exception during cleanup after start failed
org.apache.catalina.LifecycleException: PWC2769: Manager has not yet been started
 at org.apache.catalina.session.StandardManager.stop(StandardManager.java:872)
 at org.apache.catalina.core.StandardContext.stop(StandardContext.java:5509)
 ...

Stopping and re-starting Glassfish then re-deploying tends to resolve the issue, and it only happens after another failed deployment. It's not clear why it happens yet.

3 comments:

  1. Hi Craig,

    Have you been able to upgrade to Weld 1.1.1 in Glassfish 3.1 using the guidelines http://seamframework.org/Seam3/CompatibilityHome. I tried but had to revert because I got weird issues concerning EJB remote interfaces.

    ReplyDelete
  2. @mpashworth Yes, I was able to update Weld. It sounds like your code may've triggered some new or different glassfish/weld integration bug. Please reprort it - including a self-contained test case - on the Glasfish JIRA.

    ReplyDelete
  3. It might be worth updating this post to say that most (if not all) of these problems are fixed in Glassfish 3.1.1.

    ReplyDelete