Why?
Because you want to write a Flex application that requires that the server be able to push data to the client, you want a highly scalable server so you decided on the Google App Engine, when provided with the option of Python versus Java you found Java more accessible, and Eclipse is an easy way to link it all together.
- Flex – used for the graphical user interface
- BlazeDS – used for Flex to Server remote objects and provides the ability for the server to push data to the Flex client
- Google App Engine – used for hosting the server portion of the application
- Java – the language used for constructing the server potion of the application
- Eclipse – an easy way to build, manage, write code, and deploy
There are lots of other options though, in general with Flex you are aiming for a way to deal with remote objects and/or server data push + some way to persist data on a server that ties to some language + some IDE. This is just one of many possible configurations with an emphasis on relatively free parts.
It is also apparently difficult to get all of things working together, so I thought it would help for others if I shared the steps.
In this example I basically combined the two following projects into one to use the Google App Engine to show basic remote objects and messaging:
- http://learn.adobe.com/wiki/display/Flex/Creating+a+BlazeDS+messaging+application+in+Flex+Builder
- http://www.flexlive.net/?p=92
If you want more details into the how remote objects and messaging works see those examples.
Requirements
- Eclipse - http://www.eclipse.org/europa/ (FREE)
- Google App Engine Developer Account - http://appengine.google.com/ (FREE)
- Install the Google App Engine Java plug-in for Eclipse - http://code.google.com/appengine/docs/java/tools/eclipse.html (FREE)
- Flex Builder plug-in for Eclipse - http://www.adobe.com/products/flex/features/flex_builder/ ($$$)
- The BlazeDS Binary Distribution- http://opensource.adobe.com/wiki/display/blazeds/Release+Builds (FREE)
1. Creating the Server
1.1 Press the “New Web Application” button in the Eclipse toolbar
1.2 In the “New Web Application Project” window specify a project name, the package, and for the rest use the default settings then press the “Finish” button.
1.3 If you are like me and already run another server on port 8080, then you need to change the project settings to use a different port. You can do this by opening the debug menu and selecting “Open Debug Dialog…”
1.4 Specify a new port to be used and save these settings.
2. Adding BlazeDS to the Server
2.1 Assuming you have obtained the BlazeDS WAR file, unzip it using some ZIP program
2.2 Open the BlazeDS web.xml file and copy the mappings into the web.xml in your Google test project.
The web.xml file is located in MyGoogleServer/war/WEB-INF
The resulting web.xml file should look like the following:
<?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>
<!-- Default page to serve -->
<welcome-file-list>
<welcome-file>MyGoogleServer.html</welcome-file>
</welcome-file-list>
<!-- Servlets -->
<servlet>
<servlet-name>greetServlet</servlet-name>
<servlet-class>com.example.myproject.server.GreetingServiceImpl</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>greetServlet</servlet-name>
<url-pattern>/mygoogleserver/greet</url-pattern>
</servlet-mapping>
<!-- Begin BlazeDS Stuff -->
<!-- Http Flex Session attribute and binding listener support -->
<listener>
<listener-class>flex.messaging.HttpFlexSession</listener-class>
</listener>
<!-- 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>MessageBrokerServlet</servlet-name>
<url-pattern>/messagebroker/*</url-pattern>
</servlet-mapping>
</web-app>
2.3 Copy the BlazeDS flex directory into MyGoogleServer/war/WEB-INF
2.4 Open the services-config.xml file and change the three instances of {server.name}:{server.port}/{context.root} to your server name, which in the case of this example is localhost:9000. When you deploy this thing to Google you will of course need to change it.
2.5 Open the appengine-web.xml file and add the node <sessions-enabled>true</sessions-enabled>
2.6 Copy all of the JAR file in the BlaseDS lib directory to your lib directory, which in this example is MyGoogleServer/war/WEB-INF/lib
Before copy:
After copy:
2.7 If your server will be at a different location than your client, then you need to create a crossdomain.xml file to grant the client access.
In this case I like to share, so I am granting the entire internet access to the web services here. Normally you wouldn’t want to do this for reasons that should be obvious:
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-access-from domain="*" />
</cross-domain-policy>
3. Creating server-side logic
3.1 Create a class that will be used as a remote object that will just return “Hello”
package com.example.myproject.hello;
public class Hello {
public String sayHello() {
return "Hello World";
}
}
3.2 Open the remoting-config.xml file and add the following node to map the Hello remote object:
<destination id="Hello">
<properties>
<source>com.example.myproject.hello.Hello</source>
</properties>
</destination>
3.3 Open the messaging-config.xml file and add the following node to be able to use the chat variable for messaging:
<destination id="chat"/>
4. Creating the Flex client
4.1 Run the Google Server project
4.2 From the File menu create a new Flex Project
4.3 Specify the project name and set it to be a J2EE application server and don’t use WTP.
4.4 Uncheck the box to use the default LiceCycle Data services server and specify the location of the war directory of the Google Server project, and change the URL to reflect the the location of the server. Since I am planning on running the client on a different machine than the server, specify the Output folder to be bin-debug.
4.5 Specify the output folder URL to match the location on your local test server.
4.6 Run two instance of the Flex application, and notice how the sayHello button tests the Hello.java class, and you can use the Send B button to send message back and forth the the “chat” variable.
4.7 The Flex Code
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="consumer.subscribe()">
<mx:RemoteObject id="blazeService" fault="faultHandler(event)" source="hello.Hello" destination="Hello">
<mx:method name="sayHello" result="resultHandler(event)" />
</mx:RemoteObject>
<mx:Consumer id="consumer" destination="chat" message="messageHandler(event.message)"/>
<mx:Producer id="producer" destination="chat"/>
<mx:Script>
<![CDATA[
import mx.rpc.events.ResultEvent;
import mx.rpc.events.FaultEvent;
import mx.messaging.messages.AsyncMessage;
import mx.messaging.messages.IMessage;
private function send():void{
var message:IMessage = new AsyncMessage();
message.body.chatMessage = msg.text;
producer.send(message);
msg.text = "";
}
private function messageHandler(message:IMessage):void{
log.text += message.body.chatMessage + "\n";
}
private function faultHandler(fault:FaultEvent):void {
result_text.text = "code:\n" + fault.fault.faultCode + "\n\nMessage:\n" + fault.fault.faultString + "\n\nDetail:\n" + fault.fault.faultDetail;
}
private function resultHandler(evt:ResultEvent):void {
result_text.text = evt.message.body.toString();
}
]]>
</mx:Script>
<mx:Button x="10" y="132" label="sayHello" width="79" click="blazeService.getOperation('sayHello').send();"/>
<mx:TextArea x="10" y="27" width="319" height="100" id="result_text"/>
<mx:Panel title="Chat" width="100%" height="100%">
<mx:TextArea id="log" width="100%" height="100%"/>
<mx:ControlBar>
<mx:TextInput id="msg" width="100%" enter="send()"/>
<mx:Button label="Send B" click="send()"/>
</mx:ControlBar>
</mx:Panel>
</mx:Application>
5. Last Thoughts
I haven’t tried it, but apparently if you want to get remoting-only BlazeDS to work you have to do the following hack: http://martinzoldano.blogspot.com/2009/04/appengine-adobe-blazeds-fix.html