My favorites | Sign in
Project Logo
                
Search
for
Updated Jul 18, 2008 by anirudhsasikumar
Labels: Featured, Phase-Implementation
WalkingTourFxStrutsMailReaderApp  
A Walking Tour of the FxStruts MailReader Demonstration Application.

Introduction

This article is related to "A Walking Tour of the Struts MailReader Demonstration Application" distributed along with the Struts MailReader application which can be used to understand Struts and the premise of the MailReader application. Here, we attempt to guide you on the Flex application made using FxStruts that has the exact same functionality as the Struts MailReader application and has been developed without making any changes to the original backend Action class code. The only changes in the backend are to struts-config.xml and addition of new JSPs.

The FxStruts MailReader web application should be deployed to your local workstation so that you can easily follow this article.

If the struts-config.xml file distributed along with the app is replaced with the contents of struts-config-jsp.xml, you will get the HTML UI that ships with Struts.

Before we go any further, a quote from MigratingExistingStrutsAppToFlex:

 An important thing to keep in mind is that the Flex application is
 the one going to be in control and is going to treat the Struts
 backend as a service. All the control redirection done on the Struts
 side only affects what data the Flex side receives.

Details

Flex Application Architecture

Our Flex MailReader application uses Cairngorm. Cairngorm is an Model-View-Controller architecture used in Flex and the use of it in this application is to signify an important concept that there is MVC on the backend Java side (via Struts) and MVC on the client Flex side via Cairngorm.

An important distinction that Flex apps have when compared to normal HTML apps is that there are no multiple pages in an Flex app. This may take quite some time getting used to when you are from the HTML world. In Flex, you have multiple components and you can show them to the user in any number of ways (by fading in and out, by nesting them, etc.). Technically, we are on a single page throughout the lifetime of a Flex application and what the Flex app shows to the user is totally up to the application developer.

In our application's case, we have a login view component that also doubles as a registration component, a subscriptions view component and a profile view component. Each component uses some interesting Flex concepts like VBox/HBox based layout, advanced constraint based layout, states, etc.

There's also an interesting bit of addition to the normal Cairngorm architecture in this application. The view "Mediators" borrowed from PureMVC. Each view has a Mediator class that can listen for event notifications from the model and update only that particular view component. This was added to plug the inadequacy of having to use Data Binding all the time for notification of change in the Model.

Working of our App

The application begins at the welcome action. Our Welcome action maps to FxStrutsMailreader.jsp which is the HTML page generated by Flex Builder and shows our Flex application.

        <action
                path="/Welcome"
                forward="/FxStrutsMailReader.jsp"/>

Once the application is initialized, the first Cairngorm Command it dispatches is ResourceCommand. This uses ResourceDelegate which in turn uses HTTPAMFService defined in Services.mxml to hit Resources.do. There is no explicit action mapping for Resources, so the wildcard mapping will come into play and Resources.jsp will get executed.

Resources.jsp has multiple fx:message tags that pick up all the strings being used from the property file based on the selected locale and output them as separate AMF objects. ResourceDelegate sets HTTPAMFService's numObjects property to match the number of fx:message tags in Resources.jsp.

The login view of our Flex application has a combobox which allows the user to change the language. This results in a hit to Locale.do to change the locale and Resources.do to re-fetch the appropriate strings.

The login view also has a "Sign Up" button that resizes the login panel into a "Registration" panel.

On clicking the "Sign in" button, SubmitLogon.do is hit with the username and password by LoginDelegate via MailLoginCommand:

service.send({username: user, password: pass })

To adapt SubmitLogon.do to Flex, we change the mapping so that it goes to different JSPs on success and failure. On success, logon_success.jsp returns boolean value true. On failure, logon_fail.jsp returns false along with the error details. Both the JSPs use bean:define to define a bean and fx:write to output it. "errors" attribute is set to true so that error messages from validation are nested into the result object.

        <action
                path="/SubmitLogon"
                type="org.apache.struts.apps.mailreader.actions.LogonAction"
                name="LogonForm"
                scope="request"
                cancellable="true"
                validate="true"
		input="Failure">

            <forward
                    name="Success"
                    path="/logon_success.jsp"/>

            <forward
                    name="Failure"
                    path="/logon_fail.jsp"/>
        </action>

Originally, this is how the action mapping for SubmitLogon looked like:

        <action
                path="/SubmitLogon"
                type="org.apache.struts.apps.mailreader.actions.LogonAction"
                name="LogonForm"
                scope="request"
                cancellable="true"
                validate="true"
                input="Logon">
            <forward
                    name="Success"
                    path="/MainMenu.do"/>
        </action>

For an example on the handling of the result of an fx:write tag with errors attribute set to true, look at ResourcesCommand.as's result() function:

if ( event.result is Object && event.result.hasOwnProperty("errors") )
{
    model.notifyView(MailModelLocator.MODEL_RESOURCES_GET_FAILED, event.result.errors);
}
else if ( event.result is ArrayCollection )
{
//...
}

On successful login, our view fades in and then shows a grid view of all the subscriptions. This grid is populated by hitting EditRegistration.do which in turn passes control to RegistrationAMF.jsp (original mapping was to Registration.jsp).

RegistrationAMF.jsp outputs the Java object of type org.apache.struts.apps.mailreader.dao.impl.memory.MemoryUser which has a subscriptions array with objects of the type org.apache.struts.apps.mailreader.dao.impl.AbstractSubscription. MemoryUser maps to the actionscript class UserVO on the Flex side and AbstractSubscription maps to SubscriptionVO actionscript class.

This mapping can be done use the RemoteClass metadata tag in actionscript tag or by setting the serverType and returnType property of HTTPAMFService (which essentially does the same thing).

For example, this is how the UserVO class looks like:

package com.adobe.mailreader.vo
{
    [RemoteClass(alias="org.apache.struts.apps.mailreader.dao.impl.AbstractSubscription")]
    public class SubscriptionVO
    {
        public var host:String;
        public var autoConnect:Boolean;
        public var username:String;
        public var password:String;
        public var type:String;
        public var token:String;
        public function SubscriptionVO()
        {
            
            
        }
        
    }
}

Now, a user can edit a subscription by selecting the item in the grid and hitting on the edit button. A Flex popup will appear containing the subscription information in editable form.

Subscription creation, deletion and editing is managed by SubscriptionCreateEditCommand.as. This is a complex process as it involves transaction tokens which enforce that the create / edit / delete confirmation page has to be visited before the page that actually performs the operation. Here, the token attribute of fx:write is set to true so that the transaction token is nested within the result object.

The mapping change in struts-config.xml is simply to change the forward path of BaseAction to new JSPs:

        <action path="//BaseAction"
                input="Input"
                type="org.apache.struts.apps.mailreader.actions.{1}Action"
                name="{1}Form"
                scope="request">
	  <!-- change 2 nodes below for fxstruts -->
            <forward
                    name="Success"
                    path="/{1}AMF.jsp"/>
            <forward
                    name="Input"
                    path="/{1}_FailAMF.jsp"/>
        </action>

Now you should be able to get the hang of the mapping changes to make.

First we hit the (Edit/Create)Subscription.do and we get the transaction token nested within it. We save it and send this token back when we make the next hit to SaveSubscription.do.

SubscripionCreateEditCommand.as:

if ( !actionState )
{
    if ( event.result is Object && event.result.hasOwnProperty("result") && 
         event.result.hasOwnProperty("org.apache.struts.taglib.html.TOKEN")  )
    {
        /* save token, perform the actual operation */
        model.transactionToken = event.result["org.apache.struts.taglib.html.TOKEN"];
        performAction(new SubscriptionCreateEditDelegate(this), voData);
        actionState = true;
        return;
    }
}

actionState is set to true once the token is received from the confirmation page. Then we hit the actual page by prepending org.apache.struts.taglib.html.TOKEN and it's token value before all the other parameters in the send() call.

Whenever an error message is received from Struts, a small notification box shows the error message. While there are many ways to subtly display error messages in Flex, the recommended way would be to set the errorString property of !UIComponent in question so that the errors appear in the standard way that Flex validators show them.

The above described approach is repeated for handling the creation and editing Registration details like profile name, from address, etc.



Sign in to add a comment
Hosted by Google Code