View on GitHub

Devendra's Log

Integrating Flash and Java

This is a short tutorial on integrating Flash and Java using Web Services and Flash Remoting. We start by constructing a short example for each approach and then point out the advantages and limitations of the approach. We will not be entering into much detail on how to configure the tools used in this tutorial - leaving that as an exercise for the reader. We do however link to sites where you can download these tools and seek help on configuring them.

Publish a Java web service using Apache Axis

Let us begin by publishing a simple web service using Apache Axis. The example we will use in this section is a simple use case for creating a new customer with a name and address information. We will represent the customer using a Customer class shown below. The class follows the JavaBeans syntax for specifying getters and setters to expose private attributes. Only those attributes that have getters and setters will be serialized or de-serialized by Axis. The class would also need a default no arguments constructor if it had a constructor with arguments.

package flashjava;

public class Customer {
    private int id;
    private String firstName;
    private String lastName;
    private String street;
    private String city;
    private String state;
    private String country;
    private String zip;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getCity() {
        return city;
    }
    public void setCity(String city) {
        this.city = city;
    }
    public String getCountry() {
        return country;
    }
    public void setCountry(String country) {
        this.country = country;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
    public String getStreet() {
        return street;
    }
    public void setStreet(String street) {
        this.street = street;
    }
    public String getZip() {
        return zip;
    }
    public void setZip(String zip) {
        this.zip = zip;
    }
}

Next, let us construct a class called ServiceFacade that contains a method called createCustomer which receives a Customer instance. To keep our example simple we just echo back the Customer instance to the caller.

package flashjava;

public class ServiceFacade {
    private static int seq = 0; 
    public Customer createCustomer(Customer customer) {
        customer.setId(++seq);
        return customer;
    }
}

Next, we will expose the ServiceFacade class to Flash using Apache Axis. We assume you have a J2EE web module with Apache Axis configured in Apache Tomcat. We will use a wsdd file - as shown below - to publish our simple web service using Axis. The service element in the wsdd file tells Axis that we are publishing a new web service called flashjava, the class providing the service is ServiceFacade and that all methods in the class should be exposed. The beanMapping element within the service element tells Axis that we want to publish a new custom type called Customer and the Java class it maps to is flashjava.Customer.

<?xml version="1.0" encoding="UTF-8"?>
<deployment 
    xmlns="http://xml.apache.org/axis/wsdd/" 
    xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
    <globalConfiguration>
        <parameter name="adminPassword" value="admin"/>
        <parameter name="attachments.Directory" value="C:\eclipse\workspace\flashjava\WebContent\WEB-INF\attachments"/>
        <parameter name="attachments.implementation" value="org.apache.axis.attachments.AttachmentsImpl"/>
        <parameter name="sendXsiTypes" value="true"/>
        <parameter name="sendMultiRefs" value="true"/>
        <parameter name="sendXMLDeclaration" value="true"/>
        <parameter name="axis.sendMinimizedElements" value="true"/>
        <requestFlow>
            <handler type="java:org.apache.axis.handlers.JWSHandler">
                <parameter name="scope" value="session"/>
            </handler>
            <handler type="java:org.apache.axis.handlers.JWSHandler">
                <parameter name="scope" value="request"/>
                <parameter name="extension" value=".jwr"/>
            </handler>
        </requestFlow>
    </globalConfiguration>
    <handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/>
    <handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/>
    <handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>
    <service name="flashjava" provider="java:RPC">
        <parameter name="allowedRoles" value="*"/>
        <parameter name="allowedMethods" value="*"/>
        <parameter name="className" value="flashjava.ServiceFacade"/>
        <beanMapping languageSpecificType="java:flashjava.Customer" qname="ns1:Customer" 
            xmlns:ns1="urn:BeanService"/>
    </service>
    <service name="AdminService" provider="java:MSG">
        <parameter name="allowedMethods" value="AdminService"/>
        <parameter name="enableRemoteAdmin" value="false"/>
        <parameter name="className" value="org.apache.axis.utils.Admin"/>
        <namespace>http://xml.apache.org/axis/wsdd/</namespace>
    </service>
    <service name="Version" provider="java:RPC">
        <parameter name="allowedMethods" value="getVersion"/>
        <parameter name="className" value="org.apache.axis.Version"/>
    </service>
    <transport name="http">
        <requestFlow>
            <handler type="URLMapper"/>
            <handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/>
        </requestFlow>
    </transport>
    <transport name="local">
        <responseFlow>
            <handler type="LocalResponder"/>
        </responseFlow>
    </transport>
</deployment>

To publish the web service using AdminClient, we issue the following command:

java org.apache.axis.client.AdminClient -sflashjava/services/AdminService -p 8080 publish.wsdd

You can also use the publish target of the Ant script build.xml, provided with the source code of this tutorial, to publish the web service. Access the URL http://localhost/flashjava/services/ to verify that the flashjava web service is listed by Axis. We have used a web application context called flashjava in the call to AdminClient and in the URL.

Consume the web service in Flash

We will now create a Flash client to consume the web service we published in the previous section. We will use Flash MX Professional 2004 to create a simple user interface to input information about a customer, as shown below.

Flash user interface to consume the Java web service

The OK button event handler code that invokes the web service is shown below. To be able to compile the SWF the Flash document must have the WebServiceConnector in the library. Just drop a WebServiceConnector component onto a frame and delete it and Flash will add the component to the document library.

on (click) {
    import mx.services.*;
    var customer:Customer = new Customer();
    customer.id = 0;
    customer.firstName = _root.txtFirstName.text;
    customer.lastName = _root.txtLastName.text;
    customer.street = _root.txtStreet.text;
    customer.city = _root.txtCity.text;
    customer.state = _root.txtState.text;
    customer.country = _root.txtCountry.text;
    executeCreateCustomer(customer);

    function executeCreateCustomer(customer:Customer) {
        var ws:WebService = new WebService
            ("http://localhost:8080/flashjava/services/flashjava?wsdl");
        ws.onFault = function(fault) {
            trace("onFault")
        };
        ws.onLoad = function(wsdl) {
            trace ("onLoad");
        };
        var pendingResult = ws.createCustomer(customer);
        pendingResult.onResult = function(obj) {
            trace("onResult");
            trace(obj.id);
            _root.txtID.text = obj.id;
        }
    }
}

To test the Flash interface, just enter any values in the form fields and hit OK. If the service call goes through, the application will update the ID field with a positive integer value.

Advantages and Limitations of SOAP

Flash Remoting - discussed in the following section - overcomes most of the limitations of the SOAP implementation in Flash.

Publish a Java class using OpenAMF

OpenAMF is an open source Flash remoting framework that can be used to expose Java classes to Flash using Flash remoting. Flash remoting uses a native format for serializing and de-serializing Flash objects which results in much better performance as compared to calling SOAP based web services.

Next, we will publish the ServiceFacade class using OpenAMF. To configure OpenAMF copy the libraries - jar files - from the OpenAMF distribution to the lib folder of your web module. Then, create an xml file called openamf-config.xml with the configuration shown below and place it in the WEB-INF folder of your web module.

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <invoker>
        <name>Java</name>
        <class>org.openamf.invoker.JavaServiceInvoker</class>
    </invoker>

    <!-- Custom object mapping -->
    <custom-class-mapping>
        <java-class>flashjava.Customer</java-class>
        <custom-class>Customer</custom-class>
    </custom-class-mapping>

    <!-- Required  for AdvancedGateway -->
    <service>
        <name>flashjava</name>
        <service-location>flashjava.ServiceFacade</service-location>
        <invoker-ref>Java</invoker-ref>
        <method>
            <name>createCustomer</name>
            <parameter>
                <type>*</type>
            </parameter>
        </method>
    </service>
</config>

The web module configuration file - web.xml - also needs to be modified to publish the OpenAMF flash remoting gateway. The configuration required is shown below.

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
    <display-name>flashjava</display-name>

    <!-- Axis -->
    <servlet>
        <display-name>Apache-Axis Servlet</display-name>
        <servlet-name>AxisServlet</servlet-name>
        <servlet-class>
            org.apache.axis.transport.http.AxisServlet
        </servlet-class>
    </servlet>

    <servlet>
        <display-name>Axis Admin Servlet</display-name>
        <servlet-name>AdminServlet</servlet-name>
        <servlet-class>
            org.apache.axis.transport.http.AdminServlet
        </servlet-class>
        <load-on-startup>100</load-on-startup>
    </servlet>

    <!-- Flash Remoting Gateway -->
    <servlet>
        <description>AdvancedGateway</description>
        <display-name>AdvancedGateway</display-name>
        <servlet-name>AdvancedGateway</servlet-name>
        <servlet-class>org.openamf.AdvancedGateway</servlet-class>
        <init-param>
            <description>Location of the OpenAMF config file.</description>
            <param-name>OPENAMF_CONFIG</param-name>
            <param-value>/WEB-INF/openamf-config.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Axis -->
    <servlet-mapping>
        <servlet-name>AxisServlet</servlet-name>
        <url-pattern>/servlet/AxisServlet</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>AxisServlet</servlet-name>
        <url-pattern>/services/*</url-pattern>
    </servlet-mapping>

    <!-- Flash Remoting Gateway -->
    <servlet-mapping>
        <servlet-name>AdvancedGateway</servlet-name>
        <url-pattern>/gateway</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
</web-app>

This wraps up the configuration of the flash remoting gateway.

Use Flash Remoting to interact with the Java class

Let us now create a Flash client to interact with the remoting gateway we set up in the previous section. The Flash client is similar to the example used in the section on web services, the only difference being the code in the OK button event handler. The event handler code shown below uses Flash remoting to call the ServiceFacade class instead of the SOAP web service. You may need to install ActionScript APIs to invoke Flash remoting services.

on (click) {
    #include "NetServices.as"
     // Flash Remoting object mapping
    Object.registerClass( "Customer" , Customer );
    // Call the service
    var customer:Customer = new Customer();
    customer.id = 0;
    customer.firstName = _root.txtFirstName.text;
    customer.lastName = _root.txtLastName.text;
    customer.street = _root.txtStreet.text;
    customer.city = _root.txtCity.text;
    customer.state = _root.txtState.text;
    customer.country = _root.txtCountry.text;
    executeCreateCustomer(customer, this);
    createCustomer_Result = function (obj) {
        trace("Result");
        _root.txtID.text = obj.id;
    }
    createCustomer_Status = function (obj) {
        trace("Status");
    }

    function executeCreateCustomer(customer:Customer, caller) {
        NetServices.setDefaultGatewayUrl
            ("http://localhost:8080/flashjava/gateway");
        var gatewayConnection = NetServices.createGatewayConnection();
        var service = gatewayConnection.getService("flashjava", caller);
        service.createCustomer(customer);
    }
}

The following points should help you overcome any potential problems when using OpenAMF:

Advantages and Limitations of Flash Remoting

The only disadvantage of Flash remoting is that it is not a universal standard like SOAP. This limits its use when consuming existing SOAP based web services, unless you consume the web service on the server and expose it as a flash remoting service.