All entries for Thursday 20 March 2008

March 20, 2008

Using BlazeDS to invoke server side Java classes from client side Flex Flash applications

Today I have been experimenting with BlazeDS, a J2EE based framework that simplifies the task of building client server web applications with a Flex/Flash client and a Java server. BlazeDS allows for data to be exchanged between client and server using the very efficient AMF3 binary format. It includes messaging and web services proxying. But of most immediate use for me is the ability to access server side Java classes (value objects and methods) from a Flex/Flash app. This will replace the JSON based communications in a database app that I recently built. Here are some notes on what I have learned today.
Firstly, I must acknowledge this very useful explanation from Ashier's blog. 

A BlazeDS project is simply a standard web application, with a few additional features. In this case I have created a Tomcat application in Eclipse. You can see the various components in this image of the Eclipse resource navigator:  

Tomcat project

The additional elements within the web app are:
  1. The flex directory in WEB-INF, containing the BlazeDS configuration files for this application, with the required service configurations (for example, making Java classes available to Flash).
  2. Various jar library files in the lib directory. 
  3. The flash application (swf and html files) generated from the Flex 3.0 project.
  4. Some configuration settings added to the web.xml file.

To get it all set up, I followed these steps:

1. Create the Tomcat project in Eclipse.

2. Add the jar files.

3. Add the flex directory with template config files.

4. Modify the web.xml file so that BlazeDS requests are handled.

We need to add the listener...

<listener>
<listener-class>flex.messaging.HttpFlexSession</listener-class>
</listener>

And a message broker 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>
<welcome-file-list>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
</welcome-file-list>

5. Create a new Flex 3.0 project.

Use settings like this:

Project settings 1

Note that I have set it to use LiveCycle Data Services (now known as BlazeDS) and a J2EE application server. In the next screen, the location and url of the web app must be specified. Note how I have set the output folder of the Flex application to be the root of the web application, so that when I run the Flex app it is built and deployed directly into the web app.

Project settings 2

6. Write and build a class in the Eclipse web app project.

I created a class called Hello in the package hello. To start with it contains two simple methods. One method is called sayHello, and returns a string. The other method is multiiply(int i, int j). This method returns the value of i * j.

7. Make that class and its methods available to the Flex application via BlazeDS.

The following 'destination' needs to be set up in the remoting-config.xml: 

<destination id="Hello">
<properties>
<source>hello.Hello</source>
</properties>
</destination>

The source maps to the Hello class in the hello package.

I also pared-down the services-config.xml file so that only the remoting service is being used (as suggested by Ashier):

<services>
<service-include file-path="remoting-config.xml" />
</services>

8. Add a RemoteObject to my MXML application file in Flex 3.0.

This points to the class that I have created and registered with BlazeDS. See how the source points to the Hello class in the hello package. Also see how the RemoteObject has its own id. We use that to referece it and call its methods.

<mx:RemoteObject id="blazeService" fault="faultHandler(event)" source="hello.Hello" destination="Hello">
<mx:method name="sayHello" result="resultHandler(event)" />
<mx:method name="multiply" result="resultHandler(event)" />
</mx:RemoteObject>

Notice how I have registered the two methods, and specified a resultHandler method (in this case the same handler, as it just displays the string that is returned in a text box).

9. Call one of the methods, and handle the result.

I have a button that, when pressed, calls a method that calls the multiply method on the RemoteObject...

blazeService.multiply(i, j);

This method executes asynchronously on the server, in the class Hello. The values of i and j are passed to the Java method. The result is receieved bythe specified result handler method in the action script:

private function resultHandler(evt:ResultEvent):void {
result_text.text = evt.message.body.toString();
}

In this case, I simply get the single string that is returned, and display it in a text box.

Alternatively, I could get a series of arguments, an ArrayCollection, an Object. I can also create a value object class in the Flex app, mirroring a class in the Java. This class may then be passed back and forth in the method call (i'll document this in another article).