Connecting GAE/J and Flex through BlazeDS

I remember back in late 2008, a friend of mine talked to me about that cool new service: Google App Engine. The fact that this friend of mine was using it to host and execute Python script made me think that Python was the only supported language for that cool new service. Not being too interested in using Python, I let it go and kind of forget about it. Recently, the company I work for, decided to migrate their communication platform to a Google-based service using Gmail. Talking to our IT people here, I discover that they are trying to migrate some in-house services that were originally developed to support another platform we’re using to manage files and assets, they were going to deploy a new version of it using Google App Engine and try to link that service with the Gmail service. When I asked them who coded in Python, he replied “But, nobody. It’s all Java-based”. From that point on, I started fooling around with it and, I must say that I’m pretty impressed with it so far.

Even though it’s got a pretty limited support for frameworks like Spring and Seam, and doesn’t offer any kind of relational database system, there are still things that work very well. It also supports JVM-based languages like JRuby. Refer to http://groups.google.com/group/google-appengine-java/web/will-it-play-in-app-engine for a complete list of supported stuff.

This page will be covering from creating the project in Eclipse to deploying it to Google App Engine.

First off, we need the software. Here’s a list of softwares and plugins you will need:

The reason why I chose Eclipse 3.4 is for Flex Builder support. The current plug-in for Eclipse doesn’t support Galileo. There are some workarounds, if you really want to use Eclipse 3.5 but for the sake of this example, we’ll stick to Ganymede.

First off, you’ll notice that after installing the Google App Engine plugin for Eclipse, a new toolbar appeared on your toolbar. It should look like this:

After all your softwares are installed and configured, let’s start with creating our application on the Google App Engine. Navigate to: http://appengine.google.com

After logging in or registering, you should be presented with a page with a list of all your applications. Click on the “Create an Application” button at the bottom of the list. You will then be presented with another page that should look like this:

Once your app has a name and a title, feel free to tweak the settings to your liking and click “Save”.

Now, on to developing our application!

Click on the left icon on the new Google toolbar in Eclipse, the blue “g” with a star next to it.

Fill in all your information, you don’t have to use the same settings I did. Once you are done, click “Finish” to return to Eclipse.

Before we go any further, we need to decompress the BlazeDS package we downloaded earlier. Extract the files into a directory somewhere in your user folder.

Now, you should see all your files on the File Explorer to the left. Expand your files and navigate to the “war” directory. Right-click on the WEB-INF directory and select “New -> Folder” and call it “flex”. Right-click on the newly created flex directory and select “import”. Fom this dialog, expand the “General” section and select the “File System” option. In this next dialog, click on the Browse button and navigate to the directory where you extracted the BlazeDS archive. Within that directory, go to “tomcat/webapps/blazeds/WEB-INF” and click Choose. You should see the WEB-INF directory appear in the left list. Expand the directory and check the “flex” and “lib” directories. When done, click “Finish” to return to Eclipse.

Now all the libraries for BlazeDS and basic configuration files are imported to your project.

You will need to get a copy of the modified flex-messaging-core.jar file created by Martin Zoldano. You can request a copy at http://martinzoldano.blogspot.com/2009/04/appengine-adobe-blazeds-fix.html. Simply post in the comments that you would like to have the fixed JAR and he usually replies very fast with the file attached to an email. Once you have the file, copy it to your war/WEB-INF/lib directory.

Now, we need to add the Flex part of the application to the project. To do so, right-click on the project (top folder) and select “Flex Project Nature -> Add Flex Project Nature”. You should be presented with the following screen:

Adjust your projects settings accordingly and click Next to proceed.

On this next dialog, set your Root Folder to your WAR directory within your project and set your Google App Engine site in the Root URL. Make sure there are no trailing slashes and that the Context Root is empty. You can enter a value there if you want to specify a different context for your Flex servlets. For this example, I’ll leave it blank. Normally, the Output Folder has the project name appended to it, once again, this is not necessary. For my example, I set my output folder to the root of my site so it’ll be set directly into my WAR directory. Click “Finish” when done.

A few more settings need to be done to the application, as the Google App Engine has no idea where to deploy the files. Right-click on the project and select Properties. In the list, expand Google and click on App Engine. You should see a text field saying “Application ID”. That’s the name of your application, whatever goes before “.appspot.com”. In my case, it’s “mydevcentral”. Here’s a screenshot:

Now we’re ready to configure our application. As all of you J2EE developers out there, you all know that you have to write twice as much XML stuff as you need to write code to get an app to work. Google App Engine is no exception. Let’s start with the web.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>

    <display-name>BlazeDS</display-name>
    <description>BlazeDS Application</description>

    <!-- Http Flex Session attribute and binding listener support -->
    <listener>
        <listener-class>flex.messaging.HttpFlexSession</listener-class>
    </listener>

	<!-- Servlets -->
	<servlet>
		<servlet-name>greetServlet</servlet-name>
		<servlet-class>com.mydevcentral.server.GreetingServiceImpl</servlet-class>
	</servlet>

    <!-- MessageBroker Servlet -->
    <servlet>
        <servlet-name>MessageBrokerServlet</servlet-name>
        <display-name>MessageBrokerServlet</display-name>
        <servlet-class>flex.messaging.MessageBrokerServlet</servlet-class>
        <init-param>
            <param-name>services.configuration.file</param-name>
            <param-value>/WEB-INF/flex/services-config.xml</param-value>
       </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

  <servlet-mapping>
    <servlet-name>greetServlet</servlet-name>
    <url-pattern>/my_gae_test/greet</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
  	<servlet-name>MessageBrokerServlet</servlet-name>
  	<url-pattern>/messagebroker/*</url-pattern>
  </servlet-mapping>

  <!-- Default page to serve -->
  <welcome-file-list>
    <welcome-file>My_GAE_Test.html</welcome-file>
  </welcome-file-list>

</web-app>

In order for this application to work on Google App Engine, there are some other tweaks that we need to make. For example, we need to enable the session. To do so, modify your app-engine.xml file in war/WEB-INF to look like this:

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

	<!-- Configure java.util.logging -->
	<system-properties>
		<property name="java.util.logging.config.file" value="WEB-INF/logging.properties">
	</system-properties>
	<sessions-enabled>true</sessions-enabled>
</appengine-web-app>

Now that we have enabled our sessions, we need to modify our Flex configurations. Let’s start with war/WEB-INF/flex/services-config.xml. You can pretty much leave the file intact. All we need to do is to set the application to non-manageable. To do so, make this section of the file look like the following:

    <system>
       	<manageable>false</manageable>
        <redeploy>
            <enabled>false</enabled>
            <!--
            <watch-interval>20</watch-interval>
            <watch-file>{context.root}/WEB-INF/flex/services-config.xml</watch-file>
            <watch-file>{context.root}/WEB-INF/flex/proxy-config.xml</watch-file>
            <watch-file>{context.root}/WEB-INF/flex/remoting-config.xml</watch-file>
            <watch-file>{context.root}/WEB-INF/flex/messaging-config.xml</watch-file>
            <watch-file>{context.root}/WEB-INF/flex/data-management-config.xml</watch-file>
            <touch-file>{context.root}/WEB-INF/web.xml</touch-file>
             -->
        </redeploy>
    </system>

Alright! One more thing. We need to configure our AMF destination. To do that, we’ll open war/WEB-INF/flex/remoting-config.xml. Here are my configurations:

<?xml version="1.0" encoding="UTF-8"?>
<service id="remoting-service"
    class="flex.messaging.services.RemotingService">

    <adapters>
        <adapter-definition id="java-object" class="flex.messaging.services.remoting.adapters.JavaAdapter" default="true"/>
    </adapters>

    <default-channels>
        <channel ref="my-amf">
    </default-channels>

    <destination id="amfbackend">
    	<properties>
    		<source>com.mydevcentral.amf.AMFBackend</source>
    	</properties>
    </destination>

</service>

We should be done with the XML configurations. On to the programming part!

First off, let’s create a new package in the “src” directory. Right-click on the “src” directory and select “New -> Package”. I called mine “com.mydevcentral.amf”. Feel free to adjust that to your liking. In this directory, we’ll create our Java class. Right-click on the newly created package, com.mydevcentral.amf, and select “New -> Class”. Call your class “AMFBackend” and make sure you implement the java.io.Serializable interface. Click on “Generate Comments” and “Inherited Abstract Methods”. Click Finish when done. Here is my class:

package com.mydevcentral.amf;

import java.util.logging.Logger;

public class AMFBackend {

	private static final Logger log = Logger.getAnonymousLogger();

	public String test()
	{
		log.info("The 'test()' service was called.");
		return "Test!";
	}
}

* Note that I use java.util.Logger. You don’t have to do it, but I always like to know if my Flex app actually reaches the server. That’s a nice way of “tracing” a message in the Java stack’s log.

We now have a fully functional Java class, ready to be called through AMF! On to the Flex part.

When you added the Flex project nature to your Google project, Flex Builder created a “main.mxml” file by default. Open that file and let’s add some code in there.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
	<mx:Script>
		<![CDATA[
			import mx.rpc.events.FaultEvent;
			import mx.rpc.events.ResultEvent;

			private function resultHandler(evt:ResultEvent):void
			{
				trace(evt.message);
			}

			private function faultHandler(evt:FaultEvent):void
			{
				trace(evt.message);
			}

			private function init():void
			{
				remoteObject.test();
			}
		]]>
	</mx:Script>
	<mx:RemoteObject id="remoteObject" destination="amfbackend" result="resultHandler(event)" fault="faultHandler(event)" />
</mx:Application>

You should be presented with a blank .mxml file containing only a <mx:Application> tag. To communicate with our Java back end, we need a Remote Object. Let’s add the Remote Object between our <mx:Application> tags. Let’s give it the id “remoteObject” and the destination that we declared in our remoting-config.xml file, in this case, “amfbackend”. We’ll specify the “result” and “fault” callbacks as well, and make them trace the message of the event.

We want the application to contact our AMF back end as soon as the application is done loading. To do so, add a property to the <mx:Application>, creationComplete=”init()”. That will call the init() method, with no parameter, as soon as the application creation is complete. To support that property, we need to declare the function. Create a <mx:Script> tag between the <mx:Application> tags. Flex Builder will automatically add the <[!CDATA[ tags to it. Create your init() method and make it call the “test()” method of the remoteObject object. Flex should send the request to the Java back end through the amfbackend channel. The request will then be processed by the source class declared in that channel’s properties. In this case, the method simply returns a string saying “Test!”.

Once all this code is written, go ahead and build the project. It is important that the whole project is built before sending it to Google App Engine. That includes the Java classes and the Flex application. To make sure that the application is getting compiled properly, make sure that you find a “main.swf” and a “main.html” file in your war directory. You might have to refresh your directory.

If Eclipse gives you an error on the project level saying that the “html-template” is missing, go ahead and right-click on the error message in the Problems tab and select “Regenerate html-template”. Build again and you should have all the supporting files in the war directory.

When all this is looking good, go ahead and click on the right icon of the Google App Engine toolbar (the Jet engine icon). You should be shown the following dialog:

Enter your login and password and hit deploy.

Voila! You can now select your Flex file and select Debug as a Flex Application. Flex Builder should open a new browser, pointing at the appspot.com url you configured for your project. If all is good, you should see a trace in your Eclipse console that looks like this:

[SWF] /main.swf - 872,234 bytes after decompression
(mx.messaging.messages::AcknowledgeMessage)#0
  body = "Test!"
  clientId = "A08B0627-9090-C4B1-5B2C-FC78F1FA5422"
  correlationId = "BF1A21CF-1589-314B-3E10-B301A2DF7939"
  destination = (null)
  headers = (Object)#1
  messageId = "A08B0ABB-70FF-81E8-48B1-56392C115CDC"
  timestamp = 1261428692135
  timeToLive = 0

Thanks for reading!

Feel free to comment and share the page!

Simon

4 Comments

  1. […] Connecting GAE/J and Flex through BlazeDS « Zend Framework 2.0 […]

  2. Marcel says:

    Hi, I followed your demo step by step. I received the enhanced jar from Martin. I have Eclipse Indigo (3.7) and Flashbuilder 4.5.1. No matter what I do I do not get the result I want. Is it possible for you to make an export of your project so I can import it? Cheers!

  3. sgermain says:

    I would recommend that you try BlazeDS 4. This tutorial/demo was for BlazeDS 3 and a lot of the issues with GAE/J are fixed in 4. Also, even though BlazeDS might not be the official release, the beta is surprisingly stable.

    As for the demo project, I’ll have to dig to see if I can find it.

    Cheers!

  4. Yunus says:

    I had the similiar exrineepce when I ported a j2me app from another phone to 3650 (t-mobile not attws). Try to do this:Before you send a request, set the User-Agent, Content-Length etc. like this: conn = (HttpConnection)Connector.open(serverURL); conn.setRequestProperty( User-Agent , Profile/MIDP-1.0 Configuration/CLDC-1.0 ); conn.setRequestProperty( Content-Language , en-US ); conn.setRequestProperty( Connection , close ); conn.setRequestMethod(HttpConnection.POST); conn.setRequestProperty( Content-Length , Integer.toString( msgByte.length ) ); os = conn.openOutputStream(); If this can not fix your problem, install the HttpTest to your phone (it comes with Java Wireless Toolkit). If it works, read the http codes.

Leave a Reply

*