/* | |
* Licensed to the Apache Software Foundation (ASF) under one | |
* or more contributor license agreements. See the NOTICE file | |
* distributed with this work for additional information | |
* regarding copyright ownership. The ASF licenses this file | |
* to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
package org.apache.click.extras.gae; | |
import javax.servlet.ServletContextEvent; | |
import javax.servlet.ServletContextListener; | |
/** | |
* Provides <a href="http://code.google.com/appengine/docs/java/overview.html" class="external" target="_blank">Google App Engine</a> | |
* (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. | |
* | |
* <h3>Configuration</h3> | |
* | |
* To deploy Click applications to GAE, you need to set the | |
* <tt>GoogleAppEngineListener</tt> listener in your <tt>web.xml</tt>: | |
* | |
* <pre class="codeHtml"> | |
* <?xml version="1.0" encoding="utf-8"?> | |
* <web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5"> | |
* | |
* <listener> | |
* <listener-class><span class="red">org.apache.click.extras.gae.GoogleAppEngineListener</span></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> </pre> | |
* | |
* You also need to configure GAE to exclude <tt>*.htm</tt> files from being | |
* served as static resources. Also you should enable <tt>http-session</tt> | |
* support. You set these changes in the GAE file <tt>war/WEB-INF/appengine-web.xml</tt>: | |
* | |
* <pre class="codeHtml"> | |
* <?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 --> | |
* <<span class="blue">sessions-enabled</span>><span class="red">true</span></<span class="blue">sessions-enabled</span>> | |
* | |
* <!-- Exclude *.htm files from being served as static files by GAE, | |
* because the *.htm extension is mapped to ClickServlet. --> | |
* <static-files> | |
* <<span class="blue">exclude</span> path="<span class="red">**.htm</span>" /> | |
* </static-files> | |
* | |
* </appengine-web-app> </pre> | |
* | |
* <h3>Performance Filter</h3> | |
* | |
* If you use Click's {@link org.apache.click.extras.filter.PerformanceFilter} | |
* you should also exclude the following static files from GAE, so that | |
* PerformanceFilter can set their <tt>expiry headers</tt>: | |
* <tt>*.css</tt>, <tt>*.js</tt>, <tt>*.png</tt> and <tt>*.gif</tt>. For example: | |
* | |
* <pre class="codeHtml"> | |
* <?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> | |
* <<span class="blue">exclude</span> path="<span class="red">**.htm</span>" /> | |
* <<span class="blue">exclude</span> path="<span class="red">**.css</span>" /> | |
* <<span class="blue">exclude</span> path="<span class="red">**.js</span>" /> | |
* <<span class="blue">exclude</span> path="<span class="red">**.png</span>" /> | |
* <<span class="blue">exclude</span> path="<span class="red">**.gif</span>" /> | |
* </static-files> | |
* | |
* </appengine-web-app> </pre> | |
* | |
* <h3>File Uploads</h3> | |
* | |
* GAE does not allow web application to write to files on disk. This poses a | |
* problem for the {@link org.apache.click.control.FileField} control that | |
* depends on <a class="external" target="_blank" href="http://commons.apache.org/fileupload/">Commons FileUpload</a> | |
* which stores uploaded files on disk. To work around this limitation Click | |
* provides the {@link MemoryFileUploadService} which stores uploaded files in | |
* memory. | |
* <p/> | |
* Below is an example configuration of a {@link MemoryFileUploadService}: | |
* | |
* <pre class="prettyprint"> | |
* <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> </pre> | |
* | |
* <h2>Limitations</h2> | |
* | |
* <h3>Page Automapping</h3> | |
* GAE does not always adhere to the Servlet specification. One of the areas that affects | |
* Click directly is the <a href="../../../../../../user-guide/html/ch05s02.html#application-automapping">automatic mapping</a> | |
* of Page templates to page classes. GAE does not implement the ServletContext | |
* method <tt>getResourcePaths("/")</tt>. 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. | |
* <p/> | |
* Fortunately GAE does work properly for resources under subfolders of the web-app root. | |
* For example if the folders <span class="blue">/path</span> or <span class="blue">/paths</span> | |
* exists under the web-app root, calling <tt>getResourcePaths("/path")</tt> or | |
* <tt>getResourcePaths("/paths")</tt> will return the set of resources contained | |
* under these folders. | |
* <p/> | |
* Taking advantage of the fact that GAE supports subfolders, Click | |
* provides automapping support to GAE applications with a slight caveat: Page | |
* templates <b>must</b> be placed under the folders <span class="blue">/path</span> | |
* or <span class="blue">/paths</span> of the web-app root. Click explicitly | |
* maps these two folders if it is running on GAE, other subfolders are not supported. | |
* <p/> | |
* <b>Please note:</b> manual mapping works as expected. | |
* <p/> | |
* Below is an automapping example for the folder <span class="blue">/page</span> | |
* (note the page template <tt>index.htm</tt> is not placed under the folder | |
* <tt>/page</tt>, and has to be mapped manually): | |
* | |
* <pre class="codeConfig"> | |
* /index.htm | |
* <span class="blue">/page</span>/search.htm | |
* <span class="blue">/page</span>/customer/customer-edit.htm | |
* <span class="blue">/page</span>/customer/customer-search.htm </pre> | |
* | |
* The Page classes are placed under the <span class="blue">page</span> package: | |
* | |
* <pre class="codeConfig"> | |
* com.mycorp<span class="blue">.page</span>.IndexPage.java | |
* com.mycorp<span class="blue">.page</span>.SearchPage.java | |
* com.mycorp<span class="blue">.page</span>.customer.CustomerEditPage.java | |
* com.mycorp<span class="blue">.page</span>.customer.CustomerSearchPage.java </pre> | |
* | |
* Lastly define the <tt>click.xml</tt> to automatically map page templates | |
* and classes under the package <tt>com.mycorp</tt>: | |
* | |
* <pre class="prettyprint"> | |
* <click-app> | |
* | |
* <pages package="com.mycorp"> | |
* <page path="/index.htm" classname="page.IndexPage"/> | |
* </pages> | |
* | |
* <mode value="production"/> | |
* | |
* </click-app> </pre> | |
* | |
* <b>Please note:</b> automapping will work in a GAE <tt>development</tt> environment | |
* but not when hosted on the server. GAE uses the Jetty server for local development | |
* which properly implements <tt>getResourcePaths("/")</tt>. | |
* <p/> | |
* <b>Also note:</b> 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. | |
* | |
* <h3>Deployment limitation</h3> | |
* | |
* On application startup, Click automatically deploys all its JavaScript, CSS | |
* and image resources to the "<tt>/click</tt>" folder in the root directory of | |
* the webapp. Since GAE doesn't allow writing to disk, Click cannot | |
* automatically deploy its resources. | |
* <p/> | |
* Please see the user-guide section, | |
* <a href="../../../../../../user-guide/html/ch05s03.html#deploying-restricted-env">Deploying resources in a restricted environment</a>, | |
* for various solutions. | |
*/ | |
public class GoogleAppEngineListener implements ServletContextListener { | |
/** | |
* Creates a default GoogleAppEngineListener. | |
*/ | |
public GoogleAppEngineListener() { | |
} | |
/** | |
* This method does nothing. | |
* | |
* @param servletContextEvent the event class for notifications about | |
* changes to the servlet context | |
*/ | |
public void contextDestroyed(ServletContextEvent servletContextEvent) { | |
} | |
/** | |
* This method does nothing. | |
* | |
* @param servletContextEvent the event class for notifications about | |
* changes to the servlet context | |
*/ | |
public void contextInitialized(ServletContextEvent servletContextEvent) { | |
} | |
} |