Google App Engine + JSF 2 example

In this tutorial, we will show you how to develop and deploy a JSF 2.0 web application in Google App Engine (GAE) environment.

Tools and technologies used :

  1. JDK 1.6
  2. Eclipse 3.7 + Google Plugin for Eclipse
  3. Google App Engine Java SDK 1.6.3.1
  4. JSF 2.1.7
Note
This example is going to reuse this JSF 2.0 hello world example, modify it and merge it with this GAE + Java example.

1. New Web Application Project

In Eclipse, create a new Web Application project, named as “JSFGoogleAppEngine“.

generate a new web application GAE project

“Google Plugin for Eclipse” will generate a sample of GAE project structure.

2. JSF 2 Dependencies

To use JSF 2 in GAE, you need following jars

  1. jsf-api-2.1.7.jar
  2. jsf-impl-2.1.7.jar
  3. el-ri-1.0.jar

Copy and put it in “war/WEB-INF/lib” folder.

gae jsf2 dependency libraries

Right click on project folder, select “Properties“. Select “Java Build Path” -> “Libraries” tab, click “Add Jars” button and select above jars.

gae jsf2 java build path
Note
You need to put this el-ri-1.0.jar, otherwise, you will hit error message – Unable to instantiate ExpressionFactory ‘com.sun.el.ExpressionFactoryImpl’.

3. JSF Managed bean

3.1 Delete plugin generated JSFGoogleAppEngineServlet.java, you don’t need this.

3.2 Create a managed bean.

File : src/com/mkyong/HelloBean.java


package com.mkyong;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

import java.io.Serializable;

@ManagedBean
@SessionScoped
public class HelloBean implements Serializable {

	private static final long serialVersionUID = 1L;

	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

3.3 Create a new WebConfiguration.java.

JSF 2 is using “javax.naming.InitialContext” that’s not support in GAE.

To solve this, you need to get a copy of the JSF’s source code, clone the WebConfiguration.java, comment methods that are using “javax.naming.InitialContext” class, put it in “src/com/sun/faces/comfig/WebConfiguration.java“. Now, your newly created WebConfiguration.java class will overload the original WebConfiguration.java.

I don’t think GAE team will white-list this jar, just hope JSF’s team can fix this in future release.

4. JSF Pages

4.1 Create hello.xhtml page, accept a user input and pass it to helloBean.

File : war/hello.xhtml


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html">

<h:head>
	<title>GAE + JSF</title>
</h:head>
<h:body>
	<h1>Google App Engine + JSF 2.0 example - hello.xhtml</h1>
	<h:form>
		<h:inputText value="#{helloBean.name}"></h:inputText>
		<h:commandButton value="Welcome Me" action="welcome"></h:commandButton>
	</h:form>
</h:body>
</html>

4.2 Create welcome.xhtml page, display the user input from hellobean.

File : war/welcome.xhtml


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html">

<h:head>
	<title>GAE + JSF</title>
</h:head>
<h:body bgcolor="white">
	<h1>Google App Engine + JSF 2.0 example - welcome.xhtml</h1>
	<h2>Welcome #{helloBean.name}</h2>
</h:body>
</html>

4.3 Delete the plugin generated index.html file, you don’t need this.

5. web.xml

Update web.xml, integrate JSF 2.

File : web.xml


<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">

	<display-name>JavaServerFaces</display-name>

	<!-- GAE 1.6.3 cannot handle server side (JSF default) state management. -->
	<context-param>
		<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
		<param-value>client</param-value>
	</context-param>


	<!-- Change to "Production" when you are ready to deploy -->
	<context-param>
		<param-name>javax.faces.PROJECT_STAGE</param-name>
		<param-value>Development</param-value>
	</context-param>

	<!-- Welcome page -->
	<welcome-file-list>
		<welcome-file>faces/hello.xhtml</welcome-file>
	</welcome-file-list>

	<!-- JSF mapping -->
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- Map these files with JSF -->
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>/faces/*</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.jsf</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.faces</url-pattern>
	</servlet-mapping>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>*.xhtml</url-pattern>
	</servlet-mapping>

</web-app>
Note
GAE do not support server side state management, so, you need to define “javax.faces.STATE_SAVING_METHOD” to “client“, to avoid of this “View /hello.xhtml could not be restored” error message in GAE production environment.

6. Enable Session in GAE

Update appengine-web.xml, enable session support, JSF need this.

File : appengine-web.xml


<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <application></application>
  <version>1</version>

	<sessions-enabled>true</sessions-enabled>

</appengine-web-app>

7. Directory Structure

Review final directory structure.

final directory structure

8. Run on Local

Right click on the project, run as “Web Application”.

URL : http://localhost:8888/hello.jsf

local output

Click on the button.

local output

10. Deploy on GAE

Update appengine-web.xml file, add your App Engine application ID.

File : appengine-web.xml


<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
  <application>mkyong-jsf2gae</application>
  <version>1</version>

	<sessions-enabled>true</sessions-enabled>

</appengine-web-app>

Select project, click on Google icon, “Deploy to App Engine“.

deploy on GAE

URL : http://mkyong-jsf2gae.appspot.com/hello.jsf

gae production output

Download Source Code

Due to large file size, all JSF and GAE jars are excluded.

Download – JSF2-GoogleAppEngine-Example.zip (42 KB)

References

  1. JSF and GAE compatible issues
  2. JSF 2 configuration on Google App
  3. Google App Engine with JSF 2 + CDI
  4. Getting start with Google App and JSF
  5. JSF 2.0 hello world example
  6. Oracle : JavaServer Faces development tutorial

About the Author

author image
mkyong
Founder of Mkyong.com, love Java and open source stuff. Follow him on Twitter, or befriend him on Facebook or Google Plus. If you like my tutorials, consider make a donation to these charities.

Comments

avatar
26 Comment threads
7 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
26 Comment authors
ChesarekaraujoAloka ZaBéla Bodaremo Recent comment authors
newest oldest most voted
Chesare
Guest
Chesare

Thank you very much , very good publication

karaujo
Guest
karaujo

Did you tried call ws with cliente certificate on Java AppEngine?

Aloka Za
Guest
Aloka Za

Thanks for this tuto, but i hava one question : how navigation-rules works with this config?, there is no faces-config.xml???

Béla Boda
Guest
Béla Boda

Thanks for Your efforts :)

remo
Guest
remo

it works!!, thank you very much!!!!!

Vladimir
Guest
Vladimir

Hi,
I tried to run this example but it doesn’t work. Can anyone help me?

My problem is (maybe):

Caused by: com.google.apphosting.utils.config.AppEngineConfigException: Invalid appengine-web.xml(C:\Users\user\workspace\JSFGoogleAppEngine\war\WEB-INF/appengine-web.xml) – appengine-web.xml does not contain a element.
See http://code.google.com/appengine/docs/java/config/appconfig.html#Using_Concurrent_Requests for more information.

trackback
Running JSF 2 on Google App Engine.

[…] I searched around a bit and hit this post from http://www.mkyong.com: JSF 2 + Google App Engine (GAE) […]

Kasper R. Thomsen
Guest
Kasper R. Thomsen

Hey – absolutely great tutorial even though it’s a year old ;-)

I tried to add the newest JSF jars, but this didn’t seem to work, so after going back to version 2.1.7 everything worked.

However my content assist doesn’t work inside the xhtml files. Did you run into this problem by any chance and perhaps have a solution for this problem?

This is only a problem when combining JSF and GAE – it’s working nicely in standard JSF projects.

I’m really bad at remembering the different tags, so I’d appreciate if my content assist would work ;-)

Sanyog Barve
Guest
Sanyog Barve

Hi Kasper R. Thomsen,

I am struggling with the setup from quite long time.

Just to bother you, can you please share your test project with all jar’s and code on GDrive etc.

Thanks in advance.

Kasper R. Thomsen
Guest
Kasper R. Thomsen

Hi Sanyog,

Here it is – https://bitbucket.org/darwind/jsf-2-on-gae/overview – just pull the zip file or clone the repo.

Sanyog Barve
Guest
Sanyog Barve

Hi Kasper R. Thomsen, Thanks for the help. Little more help is required from your side. I am still getting the same error while running the application.Can you please help me with this, unable to google this too. PFA Console Log. SEVERE: Critical error during deployment: com.sun.faces.config.ConfigurationException: java.util.concurrent.ExecutionException: javax.faces.FacesException: java.net.URISyntaxException: Illegal character in opaque part at index 29: jar:file:/D:/Software/Eclipse Workspace/JsfOnGae/war/WEB-INF/lib/jsf-impl-2.1.7.jar!/META-INF/mojarra_ext.taglib.xml ————————————————————————— 16 May, 2013 8:10:15 AM com.google.apphosting.utils.jetty.JettyLogger info INFO: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger 16 May, 2013 8:10:15 AM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml INFO: Successfully processed D:\Software\Eclipse Workspace\JsfOnGae\war\WEB-INF/appengine-web.xml 16 May, 2013 8:10:15 AM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml INFO: Successfully processed D:\Software\Eclipse Workspace\JsfOnGae\war\WEB-INF/web.xml 16 May,… Read more »

Sanyog Barve
Guest
Sanyog Barve

Hi,

Please ignore, error resolved. Thanks

Carl C
Guest
Carl C

What was the resolution, please?

Sanyog Barve
Guest
Sanyog Barve

Dear Sir, Getting this error while running the application. java.lang.NoClassDefFoundError: com/sun/faces/context/ApplicationMap Log for reference – 5 May, 2013 6:56:07 PM com.google.apphosting.utils.jetty.JettyLogger info INFO: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger 5 May, 2013 6:56:07 PM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml INFO: Successfully processed D:\Software\Eclipse Workspace\jsfgwt\war\WEB-INF/appengine-web.xml 5 May, 2013 6:56:07 PM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml INFO: Successfully processed D:\Software\Eclipse Workspace\jsfgwt\war\WEB-INF/web.xml 5 May, 2013 6:56:08 PM com.google.apphosting.utils.jetty.JettyLogger warn WARNING: failed com.google.appengine.tools.development.DevAppEngineWebAppContext@13d1402{/,D:\Software\Eclipse Workspace\jsfgwt\war}: java.lang.NoClassDefFoundError: com/sun/faces/context/ApplicationMap 5 May, 2013 6:56:08 PM com.google.apphosting.utils.jetty.JettyLogger warn WARNING: failed JettyContainerService$ApiProxyHandler@a1aa85: java.lang.NoClassDefFoundError: com/sun/faces/context/ApplicationMap 5 May, 2013 6:56:08 PM com.google.apphosting.utils.jetty.JettyLogger warn WARNING: Error starting handlers java.lang.NoClassDefFoundError: com/sun/faces/context/ApplicationMap at com.sun.faces.config.InitFacesContext$ServletContextAdapter.getApplicationMap(InitFacesContext.java:297) at com.sun.faces.util.Util.getApplicationMap(Util.java:144) at com.sun.faces.util.Util.getPatternCache(Util.java:160) at com.sun.faces.util.Util.split(Util.java:629) at com.sun.faces.config.WebConfiguration.getOptionValue(WebConfiguration.java:290)… Read more »

Klaus
Guest
Klaus

Thanks for this tutorial – works great!
I’ve just one minor issue left after following it:

http://localhost:8888/hello.jsf looks perfect,
but
http://localhost:8888/hello.xhtml doesn’t interpret the facelets. According to the servlet-mappings (from your code above) both should work, right? Trying around I get all file-extensions working, but not .xhtml .

Oh, just got the idea about trying it out at http://mkyong-jsf2gae.appspot.com/hello.xhtml – same problem there.
Any ideas?

But anyway, even thoug my preferred file ending is .xhtml I’m fine going for anything else. Big thanks for this example!

Klaus
Guest
Klaus

Found the answer in http://stackoverflow.com/questions/10668117/google-app-engine-jsf-facelets-why-not-xhtml-as-a-url-pattern

Following is required in the appengine-web.xml for .xhtml-files to be not interpreted as static content:

<static-files>
    <exclude path="/**.xhtml" />
</static-files>
Krasen
Guest
Krasen

those with javax.faces-2.1.7.jar or higher have to gate javax.faces source and from there to get the WebConfiguration.java and package path. Mine is com.sun.faces.config. So i comment these two methods and also comment their usage. It was only to rows

cheg3
Guest
cheg3

I would like to know if this works with latest versions of gae and jsf. Thanks.

James
Guest
James

i am getting this error when i click the welcome me button “Unable to find matching navigation case with from-view-id ‘/hello.xhtml’ for action ‘welcome’ with outcome ‘welcome”
please help me

GC
Guest
GC

where do I find el-ri-1.0.jar

Andre
Guest
Andre

Hello! great tutorial!

I’m facing a issue when I go Run As > Web Application (localhost), its the following exception:

Jan 9, 2013 12:43:08 AM com.google.apphosting.utils.jetty.JettyLogger info
INFO: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger
Jan 9, 2013 12:43:08 AM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml
INFO: Successfully processed C:\workarea\workspaces\olecram\teste\war\WEB-INF/appengine-web.xml
Jan 9, 2013 12:43:08 AM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml
INFO: Successfully processed C:\workarea\workspaces\olecram\teste\war\WEB-INF/web.xml
Jan 9, 2013 12:43:11 AM com.google.apphosting.utils.jetty.JettyLogger warn
WARNING: EXCEPTION
java.lang.ClassNotFoundException: com.google.api.server.spi.SystemServiceServlet
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at com.google.appengine.tools.development.IsolatedAppClassLoader.loadClass(IsolatedAppClassLoader.java:176)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)

seems to be related with SDK I’m using… appengine-java-sdk-1.6.3.1

Why its happening? =/

thanks
André

David
Guest
David

Hi mkyong

I’m new to JSF on GAE and I followed your great tutorial step by step by simply reproducing what you have done. It works perfectly in local using Eclipse, but It doesn’t work on GAE as you can see at http://primaprovadavide.appspot.com/hello.jsf.

When the “welcome me” button is pressed, when the page “welcome” is shown the bean misses its value.
Please can you give me an opinion in what could be wrong?

Thanks in advance
David

trackback
Google App Engine + JSF 2 give the error | Jisku.com - Developers Network

[…] I am using this linkfor google app engine with jsf so i am getting this error when i run the on eclipse so give the desire solution link is http://www.mkyong.com/google-app-engine/google-app-engine-jsf-2-example/ […]

Shilendra
Guest
Shilendra

I am using this link for google app engine with jsf so i am getting this error when i run the on eclipse so give the desire solution Error is java.lang.ClassNotFoundException: javax.faces.webapp.FacesServlet at java.net.URLClassLoader$1.run(URLClassLoader.java:366) at java.net.URLClassLoader$1.run(URLClassLoader.java:355) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:423) at com.google.appengine.tools.development.IsolatedAppClassLoader.loadClass (IsolatedAppClassLoader.java:207) at java.lang.ClassLoader.loadClass(ClassLoader.java:356) at org.mortbay.util.Loader.loadClass(Loader.java:91) at org.mortbay.util.Loader.loadClass(Loader.java:71) at org.mortbay.jetty.servlet.Holder.doStart(Holder.java:73) at org.mortbay.jetty.servlet.ServletHolder.doStart(ServletHolder.java:242) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.servlet.ServletHandler.initialize(ServletHandler.java:685) at org.mortbay.jetty.servlet.Context.startContext(Context.java:140) at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250) at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517) at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130) at org.mortbay.jetty.Server.doStart(Server.java:224) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at com.google.appengine.tools.development.JettyContainerService.startContainer (JettyContainerService.java:197) at com.google.appengine.tools.development.AbstractContainerService.startup (AbstractContainerService.java:241) at com.google.appengine.tools.development.DevAppServerImpl.start (DevAppServerImpl.java:148) at com.google.appengine.tools.development.DevAppServerMain$StartAction.apply (DevAppServerMain.java:310) at com.google.appengine.tools.util.Parser$ParseResult.applyArgs(Parser.java:48) at com.google.appengine.tools.development.DevAppServerMain. (DevAppServerMain.java:249) at com.google.appengine.tools.development.DevAppServerMain.main (DevAppServerMain.java:225)… Read more »

Sujay
Guest
Sujay

Thanks for the tutorial Mkyong. I am new to jsf and as yet I have not figured out which part of the code handled the “welcome” action generated by the ‘Welcome Me” button to change the page to welcome.xhtml. Would you be able to clarify that?

raskanskyz
Guest
raskanskyz

Thanks a lot for ALL your tuts, they are very helpful!!
one short question, after following this tut i was able to run the project on localhost, but after trying to deploy it on Google App Engine i get error 500:
http://raskanskyjsftest.appspot.com/

am I the only one facing this problem?

Keith
Guest
Keith

Thanks for the tutorial but when i run on the server, it got failure because it requires the tag in the appengine-web.xml so I added it in. The page was loaded but the text box and button didn’t get render

I am using jsf-api and jsf-impl 2.1.9 from com.sun. so is there any something wrong will my configuration

p.m.verma
Guest
p.m.verma

Thanks a lot for your tutorial..
would u please to upload (google apps engine + jsf 2.0 + Spring bean) example that contains CRUD Operation.

thank you very much.

Rene
Guest
Rene

Great, please add support to jpa to this project…thanks advance

EHarpham
Guest
EHarpham

Hi thanks for the great amount of resources on your site. I followed this tutorial however I am using app engine 1.6.5, JDK 1.7 and the javax.faces-2.1.7.jar. I get the following error: //... WARNING: Error starting handlers java.lang.VerifyError: Expecting a stackmap frame at branch target 36 in method com.sun.faces.config.WebConfiguration.getServletContextName()Ljava/lang/String; at offset 10 at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Unknown Source) at com.google.appengine.tools.development.agent.runtime.RuntimeHelper.checkRestricted(RuntimeHelper.java:69) at com.google.appengine.tools.development.agent.runtime.Runtime.checkRestricted(Runtime.java:64) at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:163) at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:548) at org.mortbay.jetty.servlet.Context.startContext(Context.java:136) at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1250) at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517) at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:467) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130) at org.mortbay.jetty.Server.doStart(Server.java:224) at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50) at com.google.appengine.tools.development.JettyContainerService.startContainer(JettyContainerService.java:196) at com.google.appengine.tools.development.AbstractContainerService.startup(AbstractContainerService.java:239) at com.google.appengine.tools.development.DevAppServerImpl.start(DevAppServerImpl.java:146) at com.google.appengine.tools.development.gwt.AppEngineLauncher.start(AppEngineLauncher.java:97) at com.google.gwt.dev.DevMode.doStartUpServer(DevMode.java:509) at com.google.gwt.dev.DevModeBase.startUp(DevModeBase.java:1068) at com.google.gwt.dev.DevModeBase.run(DevModeBase.java:811)… Read more »

Spidi
Guest
Spidi

Great job!

Brumla
Guest
Brumla

Many thanks for this tutorial!