org.apache.click.extras.gae
Class GoogleAppEngineListener

java.lang.Object
  extended by org.apache.click.extras.gae.GoogleAppEngineListener
All Implemented Interfaces:
EventListener, ServletContextListener

public class GoogleAppEngineListener
extends Object
implements ServletContextListener

Provides Google App Engine (GAE) support for Click applications. GAE is a free Java hosting service provided by Google that allows you to quickly and easily make your Click applications available online.

Configuration

To deploy Click applications to GAE, you need to set the GoogleAppEngineListener listener in your web.xml:
 <?xml version="1.0" encoding="utf-8"?>
 <web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">

     <listener>
         <listener-class>org.apache.click.extras.gae.GoogleAppEngineListener</listener-class>
     </listener>

     <servlet>
         <servlet-name>ClickServlet</servlet-name>
         <servlet-class>org.apache.click.ClickServlet</servlet-class>
         <load-on-startup>0</load-on-startup>
     </servlet>
     <servlet-mapping>
         <servlet-name>ClickServlet</servlet-name>
         <url-pattern>*.htm</url-pattern>
     </servlet-mapping>
 </web-app> 
You also need to configure GAE to exclude *.htm files from being served as static resources. Also you should enable http-session support. You set these changes in the GAE file war/WEB-INF/appengine-web.xml:
 <?xml version="1.0" encoding="utf-8"?>
 <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
     <application>myapp</application>
     <version>1</version>

       <!-- Configure java.util.logging -->
     <system-properties>
         <property name="java.util.logging.config.file" value="WEB-INF/logging.properties"/>
     </system-properties>

     <!-- Enable HttpSession usage -->
     <sessions-enabled>true</sessions-enabled>

     <!-- Exclude *.htm files from being served as static files by GAE,
             because the *.htm extension is mapped to ClickServlet. -->
     <static-files>
         <exclude path="**.htm" />
     </static-files>

 </appengine-web-app> 

Performance Filter

If you use Click's PerformanceFilter you should also exclude the following static files from GAE, so that PerformanceFilter can set their expiry headers: *.css, *.js, *.png and *.gif. For example:
 <?xml version="1.0" encoding="utf-8"?>
 <appengine-web-app xmlns="http://appengine.google.com/ns/1.0">

     ...

     <!-- Exclude the following files from being served as static files by GAE,
             as they will be processed by Click's PerformanceFilter. -->
     <static-files>
         <exclude path="**.htm" />
         <exclude path="**.css" />
         <exclude path="**.js" />
         <exclude path="**.png" />
         <exclude path="**.gif" />
     </static-files>

 </appengine-web-app> 

File Uploads

GAE does not allow web application to write to files on disk. This poses a problem for the FileField control that depends on Commons FileUpload which stores uploaded files on disk. To work around this limitation Click provides the MemoryFileUploadService which stores uploaded files in memory.

Below is an example configuration of a MemoryFileUploadService:

 <click-app charset="UTF-8">
     <pages package="com.myapp.pages"/>
     <mode value="production"/>

     <file-upload-service classname="org.apache.click.extras.gae.MemoryFileUploadService">
         <!-- Set the total request maximum size to 10mb (10 x 1024 x 1024 = 10485760).
                 The default request upload size is unlimited. -->
         <property name="sizeMax" value="10485760"/>

         <!-- Set the maximum individual file size to 2mb (2 x 1024 x 1024 = 2097152).
             The default file upload size is unlimited. -->
         <property name="fileSizeMax" value="2097152"/>
    </file-upload-service>
 </click-app> 

Limitations

Page Automapping

GAE does not always adhere to the Servlet specification. One of the areas that affects Click directly is the automatic mapping of Page templates to page classes. GAE does not implement the ServletContext method getResourcePaths("/"). Instead of returning the resources under the web-app root, it returns an empty set. Click needs these resources to map between page templates and classes, and since GAE does not return anything, it isn't possible to perform the automapping.

Fortunately GAE does work properly for resources under subfolders of the web-app root. For example if the folders /path or /paths exists under the web-app root, calling getResourcePaths("/path") or getResourcePaths("/paths") will return the set of resources contained under these folders.

Taking advantage of the fact that GAE supports subfolders, Click provides automapping support to GAE applications with a slight caveat: Page templates must be placed under the folders /path or /paths of the web-app root. Click explicitly maps these two folders if it is running on GAE, other subfolders are not supported.

Please note: manual mapping works as expected.

Below is an automapping example for the folder /page (note the page template index.htm is not placed under the folder /page, and has to be mapped manually):

 /index.htm
 /page/search.htm
 /page/customer/customer-edit.htm
 /page/customer/customer-search.htm 
The Page classes are placed under the page package:
 com.mycorp.page.IndexPage.java
 com.mycorp.page.SearchPage.java
 com.mycorp.page.customer.CustomerEditPage.java
 com.mycorp.page.customer.CustomerSearchPage.java 
Lastly define the click.xml to automatically map page templates and classes under the package com.mycorp:
 <click-app>

   <pages package="com.mycorp">
     <page path="/index.htm" classname="page.IndexPage"/>
   </pages>

   <mode value="production"/>

 </click-app> 
Please note: automapping will work in a GAE development environment but not when hosted on the server. GAE uses the Jetty server for local development which properly implements getResourcePaths("/").

Also note: when running Click on GAE in development mode, it will appear that automapping is working when it really isn't. This is because Click uses a variety of ways to detect new page templates in development mode. So even though automapping failed, Click still serves page requests because it used an alternative way of looking up the template template. While these techniques are useful for development modes it impacts performance and is not used in production mode.

Deployment limitation

On application startup, Click automatically deploys all its JavaScript, CSS and image resources to the "/click" folder in the root directory of the webapp. Since GAE doesn't allow writing to disk, Click cannot automatically deploy its resources.

Please see the user-guide section, Deploying resources in a restricted environment, for various solutions.


Constructor Summary
GoogleAppEngineListener()
          Creates a default GoogleAppEngineListener.
 
Method Summary
 void contextDestroyed(ServletContextEvent servletContextEvent)
          This method does nothing.
 void contextInitialized(ServletContextEvent servletContextEvent)
          Sets the Ognl Runtime SecurityManager to null so as not to interfere with Google App Engine (GAE).
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

GoogleAppEngineListener

public GoogleAppEngineListener()
Creates a default GoogleAppEngineListener.

Method Detail

contextDestroyed

public void contextDestroyed(ServletContextEvent servletContextEvent)
This method does nothing.

Specified by:
contextDestroyed in interface ServletContextListener
Parameters:
servletContextEvent - the event class for notifications about changes to the servlet context

contextInitialized

public void contextInitialized(ServletContextEvent servletContextEvent)
Sets the Ognl Runtime SecurityManager to null so as not to interfere with Google App Engine (GAE). GAE provides its own strict SecurityManager which clashes with Ognl security checks.
 OgnlRuntime.setSecurityManager(null); 

Specified by:
contextInitialized in interface ServletContextListener
Parameters:
servletContextEvent - the event class for notifications about changes to the servlet context