Skip navigation
ANNOUNCEMENT: community.oracle.com is currently Read only due to planned upgrade until 29-Sep-2020 9:30 AM Pacific Time. Any changes made during Read only mode will be lost and will need to be re-entered when the application is back read/write.

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 andweb.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 andjsf-impl.jar into the WEB-INF/libdirectory.

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 theWEB-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 fileartifacts/weld/weld-servlet.jar toWEB-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, andall JARs in the lib directory toWEB-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.

Java EE 6 has three different ways of defining “beans” that are “managed” in one way or another. Here is a quick recap.

JSR 314

JSF 2.0 introduced annotations to avoid the tedium of declaring managed beans in faces-config.xml:

@javax.faces.bean.ManagedBean(name="user")
@javax.faces.bean.SessionScoped
public class UserBean implements Serializable {
   ...
}

That's certainly nicer than

<managed-bean> 
   <managed-bean-name>user</managed-bean-name>
   <managed-bean-class>com.corejsf.UserBean</managed-bean-class> 
   <managed-bean-scope>session</managed-bean-scope> 
</managed-bean>

There is a second annotation for a rudimentary dependency injection mechanism:

public class EditBean {
   @javax.faces.bean.ManagedProperty(value="#{user}")
   private UserBean currentUser;
}

When an EditBean instance is constructed, the value expression #{user} is evaluated, and the result is passed to the setCurrentUser method (which you must also supply)

(It is a bit odd that the @ManagedPropertyannotation is applied to a field when in fact the property setter is invoked. That is not how injection works elsewhere in Java EE. Let's not dwell on this oddity.)

JSR 316

There is an annotation@javax.annotation.ManagedBean, defined by JSR 316, that attempts to generalize JSF managed beans for use elsewhere in Java EE. There isn't much there. You can use the@PostConstruct and @PreDestroyannotations. You can use @Resource for injecting EE resources. You can use interceptors. For example, if you define

@javax.annotation.ManagedBean("user") public class UserBean ...

then you can construct an instance by making a JNDI lookup forjava:module/user. But there is no interaction with an expression language, and there is no notion of scopes. So, perhaps this kind of managed bean isn't going to see a lot of love.

JSR 299

In an EE 6 container, you can use JSR 299 “contexts and dependency injection” (CDI), like this:

@javax.inject.Named("user")
@javax.enterprise.context.SessionScoped
public class UserBean implements Serializable {
   ...
}

Now you refer to the bean as #{user} in JSF, just like you would with JSF managed beans.

If you try this out, remember to put an emptybeans.xml into web/WEB-INF to trigger the CDI implementation. This works today with GlassFish v3.

What is the advantage? Well, first off,@Named("user") is shorter than@ManagedBean(name="user"), so you are doing your part alleviating the global pixel shortage.

The advocates of CDI will tell you that they offer facilities for managing beans that go far beyond what JSF has to offer, and that is certainly true. For example, injection works with types, not EL expressions. You would use

@Inject private UserBean currentUser;

Then the CDI implementation automatically injects theUserBean of the appropriate scope. You use annotations (which you define) to control this process, such as

@Inject @LoggedIn private UserBean currentUser;

I won't go into detail here. See the documentationof Weld, the CDI reference implementation, which is very well written. For a quick intro, check out this blog by Roger Kitain.

http://weblogs.java.net/blog/cayhorstmann/archive/conversation.png

Dependency injection is all good and well, but here is a more immediate “selling point” for a JSF programmer. CDI supports the usual request, session, and application scope, but it also provides a conversation scope, a scope whose lifetime is controlled by the application. That's a sorely needed feature to deal with two separate problems: session bloat and multiple browser windows. Again, the Weld documentation describes this quite nicely.

Now What?

So, should we ditch @javax.faces.bean.ManagedBeanbefore too many people get used to it? If you deploy in an EE 6 container, then there is really no reason to use@ManagedBean. Just use @Named and start using CDI—it's there, so why not take advantage of it? If you use Tomcat or another servlet runner, you can also get CDI by adding the Weld implementation to your web app. According to a recent conversation on the jsr-314-open mailing list (which, sadly,doesn't seem to be archived), Spring 3.0 supports @Namedas well, so that seems to be the way to go for consistent examples.

On the flip side, IDE support isn't quite there yet (see this bug—please vote for it), and there will always be some people who will want to use Tomcat without any additional libraries.

Why do I care? We have a very short window for replacing all@ManagedBean with @Named before the 3rd edition of Core JSF goes to print, and I wonder whether we should do it. Please comment! (But please, no flame wars on JSF or CDI—there is a better forum for those :-))

For the upcoming semester, I want to run a learning management system into which I can integrate an experimental feature for evaluating student programs. It needs to be open source so that I can modify it. I was first going to go with Sakai, which is based on Java, butjust about everyone else is going to Moodle, and there are reasons for that.

The problem is, Moodle is written in PHP, and I am not a LAMP guy. I run Java, PostgreSQL, OpenSolaris, and GlassFish. (Thanks Sun for donating the server!) What's a JPOG guy going to do?

In this blog, I show three ways of running a PHP application on GlassFish. These all work with GlassFish and Moodle.

Quercus

Quercus is an implementation of PHP in Java. An interpreted version is free and open source, and a faster version can be licensed by those who feel the need for speed (which I do not). The Quercus folks will tell you that this is a more secure and scalable way of running PHP applications, which seems entirely plausible, provided, of course, that they did a good job with the PHP implementation.

I had my doubts, but Moodle is listed as a supported application and indeed, it worked like a charm.

Installation couldn't be simpler.

Download Moodle and Quercus:

wget http://download.moodle.org/download.php/direct/stable19/moodle-weekly-19.tgz
wget http://caucho.com/download/quercus-4.0.2.war

Unzip somewhere, superimposing the Quercus and Moodle trees, so that the Moodle tree wins out with index.php.

cd /somewhere
mkdir moodle
cd moodle
unzip ~/quercus-4.0.2.war 
tar xvfz ~/moodle-1.9.7.tgz 
mv moodle/* .
rmdir moodle

Do the other things you need to do for Moodle: create amoodledata directory somewhere and make amoodle database with PostgreSQL (or, if you prefer, MySQL).

Deploy, using directory deployment. That way, you can keep making changes to the Moodle PHP files, which is the modus operandi when adding themes or plugins.

asadmin deploy /somewhere/moodle

(This is with GlassFish v3.)

Now point your browser to http://server:8080/moodleand run the Moodle setup process.

There are ominous warnings about missing xml-rpc and ssl libraries, but they haven't caused me any problems yet. Overall, this is very impressive and the simplest way of getting going for a non-PHP person.

Update 2010-05-16: Actually, I did run into issues with Quercus later and didn't have the time to resolve them. I then switched to the PHP/Java Bridge described below, and that held up without problems for the entire semester.

PHP/Java Bridge

The PHP/Java Bridge connects a JVM and a native PHP implementation. I tried this on Ubuntu Linux where I needed to installphp5-common, php5-cli,php5-cgi, and php-pear. (Don't installphp5—it shleps with it all of Apache, and the point of all this is not to install Apache.)

The installation procedure is similar. Download the latest PHP/Java Bridge binary from here. Download Moodle. Extract them into the same directory. Then you need to edit WEB/web-inf.xml and change thephp_include_java parameter from the defaultOn to Off, like this:

<init-param>
   <param-name>php_include_java</param-name>
   <param-value>Off</param-value>
</init-param>

(Thanks to Peter from the project mailing list for this tip!)

Again, run

asadmin deploy /somewhere/moodle

and point your browser tohttp://server:8080/moodle.

The advantage of using the bridge is that you are using genuine PHP, so there isn't any potential incompatibility issue. (The Quercus people will tell you that this is also a disadvantage—PHP is more prone to attacks than Java, and it is not all that fast.)

It is worth noting that both with Quercus and the PHP/Java Bridge, you can make Java calls from PHP code, which can come in handy if you want to extend the capabilities of your PHP program without the indignity of having to code in PHP.

jFastCGI

jFastCGI is another mechanism for making a servlet container serve PHP pages. I am guessing that it has a bit less overhead than the PHP/Java Bridge. It didn't work out of the box for me on Linux, but one of the developers, Barry van Someren, sent me a patch that worked. Here is how you can build it yourself.

Check out the latest code from SourceForge and build it. Curiously, the Ant script assumes that you have the servlet library on the global class path:

cd ~
svn co https://jfastcgi.svn.sourceforge.net/svnroot/jfastcgi/trunk jfastcgi 
export CLASSPATH=.:/path/to/glassfishv3/glassfish/modules/javax.servlet.jar
cd jfastcgi/ant
ant

Now unzip Moodle somewhere and turn it into a web application like this:

mkdir -p /somewhere/moodle/WEB-INF/lib
cp ../dist/jFastCGI.jar /somewhere/moodle/WEB-INF/lib
cp ../lib/*.jar /somewhere/moodle/WEB-INF/lib

Make a file /somewhere/moodle/WEB-INF/web.xml with the contents

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
  <servlet>
     <servlet-name>FastCGI</servlet-name>
     <servlet-class>net.jr.fastcgi.FastCGIServlet</servlet-class>
     <init-param>
        <param-name>server-address</param-name>
        <param-value>localhost:6667</param-value>
     </init-param>
  </servlet>
  <servlet-mapping>
     <servlet-name>FastCGI</servlet-name> 
      <url-pattern>*.php</url-pattern>
  </servlet-mapping>
</web-app>

Run

php-cgi -b6667

(The docs recommend port 6666, but for some reason, that is taken on my machine.)

Deploy the directory to GlassFish, and it works.

Summary

I am a Java guy and build my applications with JSF and JPA. But there is no denying that there is a lot of PHP code out there that does useful stuff. If you need to host a PHP app with your Java apps, you don't have to drink the LAMP Kool-Aid. There are multiple ways of making this work with GlassFish, which gave me the courage to go with one of them and use the others as a fallback.