07 June 2011

Java EE 6 Server Comparison: Glassfish

In April 2010, I started a Java EE 6 project, and Glassfish 3.0 was the obvious server choice, or rather, the only option at that time. For the next couple of months, I spent a considerable amount of time not working on my application, but analyzing, reporting and working around bugs in the server, mainly in the CDI and JPA areas. This appeared to be the price you had pay for being an early adopter of the new Java Enterprise standard.


There was an unbearably long gap between the 3.0.1 release in June 2010 and the 3.1 release in February 2011. Glassfish 3.0.1 was still buggy, and the only solution to get my project done on Glassfish 3.0.1 was to stop using CDI completely, reverting to Java EE 5 style @EJB and @Resource injections.

I was hoping for Glassfish 3.1 to be the first stable release without blocker bugs - but it was not.

Weld, the CDI reference implementation shared by Glassfish and JBoss, is still broken in Glassfish 3.1. The problem can be fixed by replacing weld-osgi-bundle.jar with a newer version, or by using a more recent promoted build of Glassfish.

So this article is based on Glassfish 3.1.1-b06 which includes Weld-1.1.1.Final and to my great relief, this version seems to fix all bugs and memory issues encountered in previous releases.

Glassfish has an extensive documentation set, and this blog already has a tutorial on setting up Eclipse and Glassfish, so I'll only briefly touch the basics in this article.

Preparing the Server


The first thing I do with every Glassfish installation is changing its logging configuration from JUL to SLF4J and Logback, since the default output is pretty unreadable and my application uses SLF4J anyway. Actually, my posts on this topic belong to the most popular articles on this blog, so it seems I'm not alone.

The next thing to do (with any server, not only Glassfish) is to copy the JDBC driver for your database to the appropriate location where the container classloader can pick it up before loading your web application. So I copied the MySQL driver to domains/domain1/lib.

After that I was ready to start Glassfish using

bin/asadmin start-domain -v

and to configure my data source using the Admin Console web interface at http://localhost:4848.

Selecting Resources | JDBC | JDBC Connection Pools, I created a MySQL connection pool and then mapped it to the JNDI name jdbc/myapp via Resources | JDBC | JDBC Resources.

Troubleshooting


At this point, I was ready to deploy my web app, either by uploading it via the Admin Console, or by copying it to domains/domain1/autodeploy, or directly from my Eclipse workspace using Run on Server (which of course requires installing the latest Glassfish plugin for Eclipse).

My WAR still included the full set of third-party transitive dependencies from the original Maven build for Tomcat and Spring, some of which are also used by Glassfish itself, with different versions, so I prepared myself for a number of classloader conflicts.

Actually, there were none. Glassfish uses the standard parent classloader delegation model by default, instead of following the recommendation of the Servlet Specification. (You can override the default by a configuration switch.) So even though my webapp included a whole lot of Java EE API JARs from org.apache.geronimo.specs and its own JAXB version, Glassfish would simply ignore the classes included in my WAR and load the ones from its own modules.

My WAR also included Hibernate and its dependencies. As my META-INF/persistence.xml did not explicitly define a persistence provider, Glassfish at first used its built-in provider Eclipselink. This was enough to exhibit a JPQL bug in my application. (Hibernate is known to accept broken JPQL syntax for backward compatibility with its own HQL language, and there is no configuration option to enforce standard compliance.) Eclipselink also complained about a missing SEQUENCE table in my database schema, so I left it at that and added

<provider>org.hibernate.ejb.HibernatePersistence</provider>

to my persistence.xml

After that, I could deploy my web app and open its start page in my browser. Only when undeploying or redeploying the application, there was an error message about an unloaded Hibernate class (which I cannot remember from Glassfish 3.0.1). Anyway, I knew that bundling the JPA provider in the WAR is not the recommended way, so I excluded Hibernate and its dependencies from my WAR and copied the corresponding JARs to domains/domain1/lib.

Finally, I had to solve a runtime issue caused by a version conflict in Woodstox. Glassfish includes Woodstox 3.2.1, whereas my application requires Woodstox 4.1.1 with some new parser options. To get on with my experiments, I simply deleted the missing option from my source code and filed an enhancement request for Glassfish to upgrade Woodstox in its 3.1.1 release.

Eclipse Integration


Complementing the broken 3.1 release, the Glassfish Eclipse plugin was also broken in its default configuration at that time, failing to deploy applications, but this could be worked around by disabling the directory deployment option in the plugin's Server configuration. The current version Oracle Glassfish Server Tools 1.7.1 (released in May 2011) works without problems.

A point to be improved is the publishing behaviour of the plugin. My application has some 30 Maven modules, represented as individual Eclipse projects. When the application is started via the Eclipse plugin, editing and saving a class from the top-level web project will publish and redeploy the application. Editing a class in any other module does not trigger a redeploy, even after clicking the Publish button. You have to clean the top-level project to force a redeploy.

Editing a JSP page or a CSS file in the top-level project also causes a redeploy. This could be optimized by simply publishing the changed resource to the running application.

Performance Measurements


  • Empty server startup time: 3.1 s
  • Empty server memory usage: 37 MB heap, 28 MB PermGen
  • MyApp deployment time: 13 s
  • Server + MyApp restart time: 15 s
  • Server + MyApp memory usage: 156 MB heap, 83 MB PermGen
  • MyApp redeployment time: 10 s
  • Server + MyApp startup time from Eclipse: 14 s
  • Server + MyApp memory usage from Eclipse: 170 MB heap, 89 MB PermGen
  • MyApp redeployment on Eclipse save: 10.5 s

Glassfish is really fast, but I'm not satisfied with its memory footprint, compared to the original Tomcat/Spring version of my application. This is a known issue which can be narrowed down to a single internal metadata cache. The Oracle team is currently working on this, and I'm hoping to see the memory footprint cut drastically in the forthcoming 3.1.1 release.

[Update 10 Jun 2011: Tim Quinn from Oracle committed some changes to reduce the memory footprint. I've retested my application with the nightly build glassfish-3.1.1-b07-06_09_2011, and the heap is now less than 70 MB. Great news!]

I have redeployed my application 20 times in a row, and there were no classloader or other memory leaks.

Summary


Glassfish is more than the Java EE 6 Reference Implementation, it is the reference for Java EE 6 servers. Of course, Glassfish is not perfect and it may be second to one or the other of its competitors in certain areas, but the total package of documentation, community support, first-class technology, and an ever growing number of tutorials, presentations and videos provides a very productive basis for Java Enterprise development.

Regarding the shared Sun/Oracle background, Glassfish may have some natural bias towards Netbeans, but nevertheless the Glassfish Eclipse plugin is stable and rich enough for professional use.

Most of the things that could be improved in and about Glassfish are organizational rather than technical aspects.

The most pressing issue is release management. I cannot help feeling that the 3.0, 3.0.1 and 3.1 releases were more determined by timelines and management requirements than by stability. There was an urgent need for a 3.0.2 maintenance release that never came. Working with 3.1 pre-release promoted builds was a tedious two steps forward, one step back experience.

From this background, the announcement that the Glassfish 3.1.1 release will be delayed to "include more changes requested by the community" is very good news.

Since its acquisition of Sun, Oracle has not exactly gained the best of reputations in dealing with Open Source projects. There are plenty of reasons for criticizing Oracle's moves in the Java Community during the last twelve months, but lack of support for Glassfish is definitely not one of them.

One of the less successful innovations was the migration of the java.net infrastructure, running the Glassfish forums, among others. The forum continues to be a useful information source, but its usability has degraded a lot.

Anyway, the Glassfish community is not a one-way road, you do get feedback in the forum, both from users and from Oracle engineers, most of the bugs I reported have been fixed, many of them within a few days, and even though Oracle may be more of a benevolent dictator than a neutral community sponsor, I don't really mind as long as the entire ecosystem is thriving.

Read the whole story


4 comments:

Laird Nelson said...

What a fantastic blog post. Keep up the good work.

Cameron said...

Thanks for the write-up. We've got a lot of great plans for investing in both Java EE as a platform, and our application server software, so stay tuned, and be involved! :-)

Cameron Purdy | Oracle

alexismp said...

Thanks for a detailed article and content.
GlassFish 3.1.1 is around the corner

Craig Ringer said...

Thanks for writing this up. More people need to tell the truth about Java EE 6 (it might be great once it's less buggy) rather than the hype.