Prerequisite knowledge
Working knowledge of Struts.Basic knowledge of Flex.
User level
Required products
Flash Builder (Download trial)
Sample files

Additional Requirements

Apache Struts is an incredibly popular open source framework for building Servlet/JSP based web applications on the Model-View-Controller (MVC) design paradigm. The view layer in Struts is HTML, but the isolation between the view and rest of the pieces ensures that Flex can easily replace HTML. The migration or creation of such an application with a Flex front end requires transforming the existing view layer to output XML, SOAP, or AMF.
FxStruts helps developers who are familiar with Struts to easily move to Flex by providing the glue code necessary for the transformation of the existing view layer. FxStruts is a free open source library that provides replacements for Struts (version 1.x.x) bean:write and bean:message tags. It outputs AMF or XML from any Java object with ActionErrors and transaction token support. FxStruts is present both on the Flex and Java side.
Note: Struts 2 is an entirely different framework and currently not supported by FxStruts.
Flex is a free open source framework for building expressive cross platform web applications, and it comes with tons of customizable and extensible controls. Flex is gaining momentum and many developers are learning how to develop Flex applications with a variety of back-end technologies. If you are a Java developer with some experience in Struts, and you want to get started with Flex quickly, then FxStruts will help you do that.
As a validation of FxStruts, the Struts MailReader demonstration application has been implemented in Flex (see Figure 1) using Cairngorm by only adding new JSPs and changing the struts-config.xml file on the back end. No other changes have been made to the action or validation classes.
Figure 1. MailReader demonstration application.
Figure 1. MailReader demonstration application.
In this article, I'll describe some of the JSP tags and features offered by Struts and show how these are preserved even when using Flex courtesy of FxStruts.
I'll also walk through the process of installing FxStruts and writing a simple Hello World Struts web application with a Flex front end.

Preserving Struts concepts while using Flex

Let's begin with a quick overview of a few Struts tags and concepts:
  • <bean:write/> - Takes the name and property of a Java object in a particular scope and outputs the value.
  • <bean:message/> - Takes the key in a property file and outputs its value according to the chosen locale (picking data from the correct property file).
  • <html:errors/> - If there are any ActionErrors present in any scope, output their values.
  • Transaction Token - The Action class in Struts has functions such as saveToken() and validateToken() that output a unique ID and associate it with an operation. The main aim is to define a transaction such as, "the edit page has to be visited before the save page is visited."
FxStruts adds AMF and XML serialization capability to bean:write and bean:message Struts tags. It also optionally nests the value of ActionErrors objects (if any) that would have been the output of the html:errors tag and also the value of the transaction token with the result.
XML serialization aims to format the XML so that the ActionScript object decoded from it matches the server side object. However, I strongly recommend AMF over XML due to its lightweight nature and ability to preserve types across the wire.
Note: The AMF serialization code provided by FxStruts differs from that of BlazeDS in only one aspect: read-only properties (that is, properties with only getters defined) are serialized as well.

Installing FxStruts

Follow these steps to install FxStruts:
  1. Add HTTPAMFService.swc to your Flex project's build path in Flex Builder.
    Flex currently lacks a built-in component for making normal HTTP requests and getting back AMF responses. To solve this, a Flex side component called HTTPAMFService extending from HTTPService has been developed. It differs from HTTPService in that the result is expected to be in binary AMF format and read back using a ByteArray.readObject() call.
  2. Put fxstruts.jar and fxstruts-serialization.jar in your web application's WEB-INF/lib directory.
The former is licensed under Apache Software License 2.0 and the latter under the GNU Lesser General Public License 3.0.
Now you're ready to develop your slick looking RIA with Struts.

Developing a simple Hello World application using FxStruts: Java side

Your aim is to build an application that displays the value of a Java object returned by an Action class.
This is the action defined in struts-config.xml:
<action path="/Test" type="" name="testForm" forward="success" > <forward name="success" path="/pages/Test.jsp" /> </action>
The TestForm class inherits from ActionForm and has getters and setters for the properties firstname and lastname. This is the input form to expect. If request parameters firstname and lastname are sent, a TestForm object will be created and the corresponding properties will be mapped and passed to the Action class's execute() method.
In the Action class, I perform a simple validation check and call setAttribute() passing on the input form Java object so that it is accessible from the view layer (JSP):
package; import javax.servlet.http.*; import org.apache.struts.action.*; import; public final class TestAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { ActionErrors errors = new ActionErrors(); TestForm testForm = (TestForm) form; String name = testForm.getFirstname(); request.setAttribute("test", form); // Dummy business logic: here is where you would // typically communicate with a business object if (name != null && name.length() < 3) { errors.add(ActionMessages.GLOBAL_MESSAGE, new ActionMessage("errors.minlength", "First Name", 3)); saveErrors(request,errors); return mapping.findForward(mapping.getForward()); } return mapping.findForward(mapping.getForward()); } }
In the JSP, I use fx:write to output the Java object in AMF:
<%@ page language="java" %> <%@ taglib uri="/WEB-INF/lib/fxstruts.jar" prefix="fx" %> <fx:write name="test" type="amf" errors="true" />
The errors attribute has been set to true in the fx:write tag. Any validation errors will be nested within the result object. That is, on the Flex side, event.result will be an object with an errors property and will have the actual object in a property named result.
By default, fx:write outputs AMF which is a binary format. Be careful not to place stray newlines in the JSP as this will result in a "getOutputStream() has already been called" error. You can set type to xml to output XML instead of AMF.
Now that your back end is ready, let's create the Flex application.

Developing a simple Hello World application using FxStruts: Flex side

First, create a class called TestVO that is equivalent to the TestForm Java class on the Flex side:
package { RemoteClass(alias="")] public class TestVO { public var firstname:String; public var lastname:String; public function TestVO() { } } }
The RemoteClass metadata tag signifies that the ActionScript class TestVO maps to the server side class TestForm.
Once HTTPAMFService.swc is included, you can use HTTPAMFService and point it to the URL http://localhost:8080/appname/ When the service's send() method is called, you'll get the Java object in the event.result property.
Here is the code for the Flex application:
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="/2006/mxml" xmlns:rpc="com.adobe.fxstruts.rpc.*" creationComplete="service.send({firstname:'John', lastname:'Doe'})" layout="vertical" > <mx:Script> <![CDATA[ import mx.controls.Alert; import; [Bindable] private var testobj:TestVO; private function handleResult(event:ResultEvent):void { if ( event.result is TestVO ) { testobj = event.result as TestVO; } else if ( event.result is Object && event.result.hasOwnProperty("errors") ) {"Error:" + event.result.errors); } } private function submit():void { service.send({firstname:fname.text, lastname: lname.text}); fname.text = ""; lname.text = ""; } ]]> </mx:Script> <mx:HBox> <mx:Label text="First Name: " /> <mx:TextInput id="fname" text="{testobj.firstname}" /> </mx:HBox> <mx:HBox> <mx:Label text="Last Name: " /> <mx:TextInput id="lname" text="{testobj.lastname}" /> </mx:HBox> <mx:Button label="Submit new name" click="submit()" /> <rpc:HTTPAMFService id="service" url="http://localhost:8080/fxstruts-blank/" result="handleResult(event)" /> </mx:Application>
The Flex application has a simple user interface that lets you input a first and last name and submit them to the Struts back end. If the first name has fewer than three characters, an error is set in the Action class via saveErrors(), and this is displayed in an Alert popup dialog in the Flex application. Take note of how an error case is checked for in handleResult().

Where to go from here

Thanks to FxStruts it is easy to develop a Flex application with a Struts back end or migrate an existing HTML Struts application to Flex. It has never been easier to create expressive rich experiences using Flex powered by a Struts back end.
For more information on migrating your existing Struts application to Flex, visit the Google Code Wiki.