By: Derek Berube, Wildstar Technologies, LLC.
Last Update: September 29, 2014
This tutorial will guide users through the process of developing and deploying a JavaServer Faces 2.1 application on the 1.9.12 version of Google's App Engine for Java using the 2.1.29 version of Oracle's implementation of the specification. The application built out in the course of writing this tutorial is available from http://jsf21template.wildstartech.com/. The source code is available from the jsf21template Google Code project.
The complete Eclipse project is contained in the jsf21template.zip archive which is accessible from the following URL:
One of the key features of the JavaServer Faces 2.1 specification is the ability to use annotations to define managed beans rather than using the faces-config.xml. While the annotations provided by JSF 2.1 are fantastic, you may consider taking advantage of the capabilities offered by the Contexts and Dependency Injection (JSR-299) (CDI) framework (the JSR was referred to as "Web Beans" prior to January 26, 2009). CDI provides similarly named @ApplicationScoped, @SessionScoped, @RequestScoped annotations (part of the javax.enterprise.context package) but uses a @Named annotation in favor of the JSF 2.0 @ManagedBean annotation. CDI also introduces the @ConversationScoped annotation which is familiar to Seam aficionados and provides a variable-length scope that can span requests but isn't as long-lived as either the Session or Application scope. If you are interested in incorporating the CDI framework into your App Engine project, have a look a the "Configuring JBoss Weld to Run with JavaServer Faces on the Google App Engine" after completing this tutorial (currently in a draft state).
In order to build a JavaServer Faces 2.1 application and have it run on the Google App Engine platform, you will need to have the following software downloaded and installed locally.
You can download the Google AppEngine SDK v1.9.12 and install it locally on your system; however, this tutorial is written from the Eclipse perspective using the Google Plugin for Eclipse.
The following steps will guide you through the process of importing the files which provide support for the new Unified Expression Language. Prior to completing this step, you should have downloaded version 2.3.1 of the Seam 2 framework. Once you uncompress the jboss-seam-2.3.1.Final.zip archive, the el-api.jar , jboss-el-api_2.2_spec.jar, and jboss-el.jar files are located in the lib folder.
The following steps will guide you through the process of importing the files which provide support for the second release candidate of Oracle's implementation of the JSF 2.1 specification.
Edit the appengine-web.xml file found in the WEB-INF directory of the project to allow the web application to store data in the session created for clients visiting our site. Add the <sessions-enabled>true</sessions-enabled> line as shown below. Add the <threadsafe>true</threadsafe> setting to instruct the App Engine runtime environment to allow a single Instance to service multiple requests concurrently.
NOTE: We have set the enabled HTTP sessions in this web application by setting the <sessions-enabled> property to true. Experiments configuring App Engine to transfer session data from memcache to the datastore asynchronously to reduce request latency using the <async-session-persistence> parameter to true cause Task queue quotas to become exhausted. For the time being it is recommended the <async-session-persistence> property be set to false. For more information, please refer to the Enabling Sessions section of the Java Application Configuration document.
Do not forget to modify the contents of the <application></application> tag to reflect the name of your App Engine project. Save the changes to the appengine-web.xml file and close it.
The com.sun.faces.enableThreading context parameter is set in the event you use the "Development" value for the javax.faces.PROJECT_STAGE context parameter. As indicated in the comments, setting com.sun.faces.enableThreading equal to false instructs the Mojarra implementation of the JSF 2.1 API to NOT attempt to use threads as this is not allowed by the Google App Engine platform (as described in the "Sandbox" section of the "Java Servlet Environment" article on the Google App Engine documentation site.
If your web project does not already contain an index.html file in the war directory, then skip to the "Creating index.jsp" sub-section. If there is already an index.html, continue with the "Renaming index.html to index.jsp and Modifying Its Contents" section which follows.
A Google AppEngine web project will create an index.html file as the default file for your web application. In the section above, we specified a change to the <welcome-file-list> configuration parameter which instructs the AppEngine's runtime environment to look for the following default pages in the specified order:
As such, we we will rename the AppEngine's default index.html file to index.jsp. We will ensure that the browser's "back" button will continue to function properly by following the guidelines prescribed in the "Avoid Redirects" section of Yahoo!'s "Best Practices for Speeding Up Your Web Site" document. The index.jsp file will be configured to send a redirect to the browser rather than leverage an <meta http-equiv="Refresh" content="0,welcome.jsf"/> tag in the <head> of an HTML document.
Please skip to the "Add JavaServer Faces Library to Java Build Path" section.
The default welcome page for our web application will be a JSP page entitled index.jsp and we will ensure that the browser's "back" button will continue to function properly by following the guidelines prescribed in the "Avoid Redirects" section of Yahoo!'s "Best Practices for Speeding Up Your Web Site" document. The index.jsp file will be configured to send a redirect to the browser rather than leverage an <meta http-equiv="Refresh" content="0,welcome.jsf"/> tag in the <head> of an HTML document.
To successfully run the reference implementation of the 2.1 version of the JavaServer Faces API on the Google App Engine platform, we are going to have to modify one of the classes that ship with the API. Before we do that, we are going to need to add the JavaServer Faces API to the Java Build Path of our project so we do not encounter any compilation errors.
Any time the Google App Engine framework detects a change in the HTTP session, that information is written out to the datastore. This works very well for immutable objects; however, it becomes more challenging when dealing with mutable objects as the GAE framework has no way of knowing when a field inside an object stored in the HTTP session is changed. A Stack Overflow question entitled "Session lost in Google App Engine using JSF" outlines a great strategy using a JSF PhaseListener to store the current date/time in the HTTP session at the end of each Phase.
The following process will guide you through the steps necessary to create this PhaseListener.
The getPhaseId() method returns PhaseId.ANY_PHASE which tells the JSF framework the beforePhase and afterPhase methods of the listener should be called for each phase of the JavaServer Faces lifecycle. The beforePhase method of this class does nothing; however, the afterPhase method will:
Unfortunately, the JSF 2.1 API does not provide an annotation to declare a PhaseListener programmatically, so we are going to have to create a faces-config.xml configuration file.
Now that you have completed the requisite configuration steps, you are ready to launch your first JSF application running on the App Engine platform.
The following articles provide additional information on JavaServer Faces technology.