Skip to main content

JSF 2.0 and Tomcat

Posted by cayhorstmann on December 29, 2009 at 2:43 PM PST

As I happily wrote about new features of JSF 2.0, my coauthor David Geary kept asking me how to run the examples in Tomcat 6. I kept putting it off—hunting down all those JAR files and web.xml fragments is just too much like eating soup with a fork. I finally got around to doing the research and thought that others might benefit from the (unhappy) results, if only to realize that this may be the time for switching to GlassFish.

JSF 2.0

This part is easy and has not changed from previous versions. Download the reference implementation and put jsf-api.jar and jsf-impl.jar into the WEB-INF/lib directory.

The Java EE 6 EL

The expression language has changed in minor ways. Perhaps the most useful enhancement for JSF programmers is the use of arguments in action methods. For example,

<h:dataTable var="row" ...>
   ...    
   <h:column>
      <h:commandLink action="#{myBean.doSomething(row)}" .../>
   </h:column>
</h:dataTable>

Before JSF 2.0, you had to fuss with sPAL or a TableModel, so this is definitely an improvement you want to put to work. Unfortunately, the EL is not a part of JSF, so you need to get the bits from somewhere else. This page has links to outdated versions of the API and implementation JARs in the GlassFish Maven repository. You can divine the correct links for the current version (2.2) from there. They are

If you aren't excited about using an unversioned snapshot, you can download and install GlassFish v3 and use modules/javax.servlet.jsp.jar (for the API) and modules/el-impl.jar. Either way, put the two JARs into the WEB-INF/lib directory.

You also need to put this into your web.xml:

<context-param>
   <param-name>com.sun.faces.expressionFactory</param-name>
   <param-value>com.sun.el.ExpressionFactoryImpl</param-value>
</context-param>

CDI

CDI gives a more robust mechanism for managing beans and their dependencies than JSF managed beans. You should probably skip the @ManagedBean annotation altogether and just get going with @Named. (The raison d'être for @ManagedBean is to support an otherwise unmodified Tomcat 6, but you need to modify it anyway, so you might as well do it right.)

More importantly, CDI gives you conversation scope.

Download the reference implementation and add the file artifacts/weld/weld-servlet.jar to WEB-INF/lib.

Put this into your web.xml:

<listener>
   <listener-class>org.jboss.weld.environment.servlet.Listener</listener-class>
</listener>

Bean Validation

Bean validation lets you attach validators where they belong—to the bean properties that are being validated rather than the pages doing the validation. For example,

public class PaymentBean {
   @Size(min=13) private String card;
   @Future public Date getDate() { ... }
   ...
}

This way, you can't have inconsistent validation rules on different pages. JSF 2.0 supports bean validation, but only when an implementation is present.

Download the reference implementation and add the files hibernate-validator-4.0.2.GA.jar, and all JARs in the lib directory to WEB-INF/lib. This is not so wonderful—you get to include yet another copy of slf4j as well as a jpa-api-2.0.Beta-20090815.jar, which isn't exactly confidence-inspiring.

JPA

This can be done—see these instructions. But it doesn't mean that it should be. You'd have to manually obtain an entity manager and manually handle transactions. There are also restrictions on dynamic weaving of entities, and you would need a pretty deep understanding of JPA to understand the ramifications.

Conclusion

You can, with some pain, use JSF 2 with Tomcat 6. The EL support is critical—you don't want an EL expression to fail mysteriously that works fine elsewhere. CDI and bean validation are optional, but they are better solutions than the equivalent JSF facilities, so it makes good sense to learn and use them.

If you use JPA (which you should seriously consider if your application accesses a database), do yourself a favor and use a real app server. But even if you don't, ask yourself what you gain from the Tomcat pain. GlassFish v3 is very fast, easy to manage, and, due to its modular nature, you get as much or as little of EE 6 as you want.

Related Topics >>

Comments

Memory

Great post, thanks for the help! I've used this a few times now for Tomcat 6. It's even nicer now that we don't have to use snapshots and beta jars, less worry it will break. My reason for using Tomcat 6 vs Glassfish 3.01, memory consumption. I have a small app, and my dev server has just over a gig of ram. After startup, using 'top' (I know, not very scientific) with it running on Glassfish 3.01 it consumes about 27% of the ram. Start the admin app and we're almost at 50%. The same app on Tomcat 6 uses 5%. I also find tomcat serves the pages faster. I'm sure there are a few other things I could turn off on Glassfish, but I've already turned off a lot, and I'm using the web release, not the full. Thanks again!

auksmart wrote:Great post,

auksmart wrote:
Great post, thanks for the help! I've used this a few times now for Tomcat 6. It's even nicer now that we don't have to use snapshots and beta jars, less worry it will break. My reason for using Tomcat 6 vs Glassfish 3.01, memory consumption. I have a small app, and my dev server has just over a gig of ram. After startup, using 'top' (I know, not very scientific) with it running on Glassfish 3.01 it consumes about 27% of the ram. Start the admin app and we're almost at 50%. The same app on Tomcat 6 uses 5%. I also find tomcat serves the pages faster. I'm sure there are a few other things I could turn off on Glassfish, but I've already turned off a lot, and I'm using the web release, not the full. Thanks again!

Hello All, one the big problem connected with JSF 2.0 and need more information, it is performance and memory use in server side.
And question is JSF only for corporate sites or we can use it for development social networks?
How much memory will use each component of JSF and how we can improve it(clean). I know we must use less SessionScoped beans and more RequestScoped ...
Please write big article about JSF performance and memory use.....

Kind Regards,

I have been hunting around

I have been hunting around for a "proper" App server which could host my JSF2 (Facelets/A4J/RichFaces) application without my hassle and configuration. I tried out GF V3 but it keeps spilling out long stacktrace info complaining about non-supported ELs,etc....JBoss had some weird results too. Lastly, I decided to try out the simplest yet most reliable(and my favorite) Tomact.....JSF2 worked fine with Tomcat 6.0.20 release with out any configuration and no additional effort....Tomcat Rocks!!
www.thetechallies.com

Why go for Tomcat, you ask...

There is one good reason for getting a useful subset of JEE6 Web Profile on Tomcat 6, namely that Tomcat may already be the accepted web container for projects, and the sheer bureaucratic obstacles in the process of having a full JEE 6 application server replace Tomcat can be very large. A much better approach is to have Tomcat support the facilities we need with JSF 2.0 applications (thanks for the clarification of the EL library page being broken, it still is) so the choice of when to upgrade (and even, if) is ours driven by our own needs, instead of technology saying "You _MUST_ upgrade now". Given that requirement many will postpone the upgrade. Just the same as has happened with generics in Java because it _required_ upgrading to Java 5 JVM. This blog entry has been very helpful. Your efforts are appreciated! /Thorbjørn

JBoss-EL saves the day

I have found that javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL isn't always good enough. What ALWAYS fixes the problems I run into with JSF 2.0 and the EL that comes with Tomcat 6 is JBoss EL. Just add this to web.xml: <context-param> <param-name>com.sun.faces.expressionFactory</param-name> <param-value>org.jboss.el.ExpressionFactoryImpl</param-value> </context-param> And add this to your Maven2 pom.xml: <dependency> <groupId>org.jboss.seam</groupId> <artifactId>jboss-el</artifactId> <version>2.0.0.GA</version> <exclusions> <exclusion> <groupId>javax.el</groupId> <artifactId>el-api</artifactId> </exclusion> </exclusions> </dependency> Oh, and you also need to add http://repository.jboss.org/maven2 as a Maven 2 repository in your pom.xml. And you should be good to go with JSF 2.0 and Tomcat 6 regarding EL.

One other reason to use the new EL with Tomcat 6

I found that with Tomcat 6.0.24 and the EL that it includes, if you set javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL in web.xml to make it convert empty strings to nulls, it doesn't work. Or even if you create a Converter and manually convert empty strings to nulls, when it calls the setter in your bean, it will be the empty string regardless. It does work if you use the updated EL. One reason you might want to use this is so that you can use @NotNull for checking for required fields.

Maven 2 can help

Hi to all, I had a similar need - to find which exactly jar files I would need. Here is a blog post how to run JSF 2.0 with Maven 2 plugins for Glassfish v3, Jetty and Tomcat and another one showing CRUD application with JSF 2.0, Spring 3 and Spring Security 3 on Google Application Engine I hope this is useful...

loosing touch...

Too bad that I can't any love with crashfish v3 either. The complexity of building distributed apps is kinda getting out of hand I think. The java app servers are straining too hard to be all things to all people and now you can't even run the latest version of java server faces on tomcat anymore without a phd in computer science. I can't get the new version of crashfish to do anything but throw a mile long list of exceptions.

Then you should do a pair

Then you should do a pair programming with Dr. Cay Horstmann :) (so you have both a phd and no exception list).

EL JARs

Hello Cay,

thanks for the informative post.

The EL JARs can be found in (non-snapshot) version 2.2 in the official java.net Maven repository:

http://download.java.net/maven/2/javax/el/el-api/2.2/
http://download.java.net/maven/2/org/glassfish/web/el-impl/2.2/

I also wrote about this in my post Running JSF 2 on embedded Jetty.

Gunnar

EL JARs conflicting with jasper

When I add EL JARs to WEB-INF\lib I get exception:
javax.servlet.ServletException: java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/index_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:275)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
root cause
java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/index_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature org.apache.jsp.index_jsp._jspInit(index_jsp.java:22)
org.apache.jasper.runtime.HttpJspBase.init(HttpJspBase.java:52)
org.apache.jasper.servlet.JspServletWrapper.getServlet(JspServletWrapper.java:159)
org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:329)
org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342)
org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267)
javax.servlet.http.HttpServlet.service(HttpServlet.java:717)

It's conflict with el-api.jar in Tomcat lib directory. But without this Jasper and JSP doesn't work on server.
Can You help with this?

EL JARs conflicting with jasper (my solution)

You need to remove el-api.jar from tomcat lib dir and include el-api-2.2.jar and el-impl-2.2.jar there. Be carefully to not have the new el-api in your project WEB-INF/LIB You also need to create an empty beans.xml inside WEB-INF dir or you will get in trouble. Weld needs this file.

Pain of Tomcat?

....I think you have that the wrong way around. What do you gain from the pain of trying to deploy Glassfish? And when you finally struggle to get it to work on Glassfish, how likely is it to work on another app server like JBOSS? Well, not very....just some hassles here and a hassle there and a tweak of some app server specific deployment descriptor there...and it might run. The devil is always in the details for all this J2EE stuff...it always looks so nice and easy until you really try to use it.

Nowadays, the devil is in the details with Tomcat

@alski: I wrote this blog because I was painlessly running JSF 2 code on GlassFish and JBoss, while my coauthor got stack traces from hell when using Tomcat. I agree that there was a time when it was easier to use Tomcat for a JSF app. But the world has changed. Nowadays, both GlassFish and JBoss do a good job supporting the latest Java EE specs out of the box, and Tomcat is playing catchup. Today, it's Tomcat that looks so nice and easy until you really try to use it :-)

Re: Pain of Tomcat

And when you finally struggle to get it to work on Glassfish what struggles do you see when you try to make it work on glassfish? The war file has no Glassfish-specific file.
how likely is it to work on another app server like JBOSS? if jboss is jee 6 compliant then it definitely works on jboss.