Sunday, March 1, 2009

GWT and Google App Engine - How to develop!

So I have developed an application in GWT using the GXT library which is currently connecting to a Restful WebService through Tomcat and using JPA to access my MySQL Database. I recently had a disk failure on this system, and so have become acutely aware of the possibility at some point I might want to have my application hosted.

I was looking at the Google App Engine, and wanted to experiment with it. The problem is, there are blogs talking about putting your GWT application onto a GAE app, but how do you develop the app on your local box and communicate with either a local or remote GAE application? You can develop the GAE in eclipse and run it locally, but there is currently no way to embed GAE apps in your hosted mode browser for GWT. As well, by default the GWT app sandbox does not allow you connect to a site outside of the site hosting the GWT app. My requirements were simple:
  1. Develop a GAE application in Eclipse and run the server locally.
  2. Continue to develop my GWT Application in eclipse connecting to my existing server.
  3. Be able to connect my GWT Application to a GAE application, with the intent to later deploy it on that application (therefore request url should remain the same).
  4. (Optionally) - "replace" a web-service running on my server with a GAE application service.

The way to do this, is to insert a redirect filter in the embedded tomcat run within the GWTShell to send any requests matching a particular syntax to the GAE application. This actually worked surprisingly well. The filter I am using was one I found after a quick search, I came across the HttpRedirectFilter. This didn't take much at all to configure and voila I am off to the races. The general strategy here, is you can use this redirect filter to forward requests to the GAE application while in development. Upon compilation of your GWT application you can bundle it with the GAE application (see Configuring Eclipse on Windows to Use With Google App Engine) and deploy this to Google. In my case, I can still have features hosted locally and as I convert a Restful Resource to GAE I can use the Redirect Filter to redirect the request to GAE. Once everything is converted, I can stop supporting my Jersey-based application and use the pure GAE app. At this point, I am purely in the evaluation stage of GAE, but it was a non-starter if I was not going to be able to concurrently develop a GWT and GAE applications together. This method gives me this ability to experiment with this. As well, you could concievably use this technique to develop a pure GAE application, by just providing the redirect filter in your web.xml configuration.

As an example of the redirectfilter.xml I am using, I configured a new fictious resource testpy to be redirected to my helloworld GAE application on port 9998 on my local machine. Since I had to read the source code provided in the HttpRequestFilter to get this to work, I figured I would show what my file looks like:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE redirect-filter PUBLIC "-//zlatkovic.com//DTD RedirectFilter 2.0//EN" "http://www.zlatkovic.com/dtd/redirect-filter-2.0.dtd">
<redirect-filter>

 <redirect match="/StampWeb/resources/testpy$" target="http://localhost:9998/helloworld" remote-address="127.0.0.1/255.0.0.0"/>
 
</redirect-filter>


My web.xml configuration look like the following (Note: I am currenly filtering everything, but you could easily configure it just for the resources that are on the GAE application):

   <filter>
        <filter-name>HttpRedirectFilter</filter-name>
        <filter-class>com.zlatkovic.servlet.RedirectFilter</filter-class>
        <init-param>
         <param-name>configFile</param-name>
         <param-value>/WEB-INF/redirectfilter.xml</param-value>
        </init-param>
        <init-param>
         <param-name>reloadConfig</param-name>
         <param-value>true</param-value>
        </init-param>
        <init-param>
         <param-name>logRedirects</param-name>
         <param-value>true</param-value>
        </init-param>
   </filter>
   <filter-mapping>
     <filter-name>HttpRedirectFilter</filter-name>
     <url-pattern>/*</url-pattern>
   </filter-mapping>

No comments: