Showing posts with label Adobe Flex. Show all posts
Showing posts with label Adobe Flex. Show all posts

Sunday, February 08, 2009

Adobe Air: Getting Started

I wanted to create this post because I needed a reference to where I am at with Adobe Air/Flex. Plus Vladimir Vivien said I needed to blog about what I have been doing. So here is what I have been doing:

I have mostly been creating Flex form based applications with datagrids that rely on RESTful Web services mostly running on Groovy/Grails but I have also created an Air application that communicates with TIBCO EMS. I want to go over the TIBCO integrated Air app, I call systemStatus. Basically, systemStatus makes an HTTP request to a URL like http://host:port/systemStatus and a TIBCO HTTP Receiver listens and responds after executing some processes on the ESB. The TIBCO project includes processes that execute some simple tasks, like queries on databases, and the results are accumulated and mapped to a pre-defined schema. The response is an XML document that looks something like this:

...
<resources>
    <resource>
        <name>Production Oracle</name>
        <type>database</type>
        <vendor>Oracle</vendor>
        <status>offline</status>
        <instance>server 1</instance>
    </resource>
.
.
.
</resources>
...


The XML is pretty simple, but it does what I need it to do. It basically gives us some META data and a status for each of the resources, like databases, which are dependencies of the deployed TIBCO projects. I am going to stay away from the details pertaining to the TIBCO application but if you need some help setting up something like this, just contact me.

Next we turn to the Air/Flex application. The Air application is made up of only a few major components: <mx:HTTPService>, <mx:Panel>, <mx:TextInput>, <mx:DataGrid> and <mx:Button>. At the simplest level, the <mx:HTTPService> makes the call to the TIBCO service and the <mx:DataGrid> handles and displays the XML results. I have added the <mx:TextInput> component so the app can be configured to point to different TIBCO environments running the deployed systemStatus TIBCO application that provides the XML results. Here is the meat of the Air application:

...
<mx:HTTPService id="systemStatusService" result="r_Handler(event)" resultFormat="e4x" fault="f_Handler(event)" url="http://{serverName}" />

<mx:Panel title="systemStatus" height="100%" width="100%" paddingTop="10" paddingLeft="10" paddingRight="10">

<mx:ControlBar horizontalAlign="left">
<mx:Label text="Server:Port"/>
<mx:TextInput id="serverNameInput" enter="setServerName()"/>
</mx:ControlBar>

<mx:Label text="Systems:"/>

<mx:DataGrid id="systemDG" width="100%" height="80%"
dataProvider="{systemStatusService.lastResult.resource}"
editable="true">
<mx:columns>
<mx:DataGridColumn dataField="vendor" headerText="Vendor" editable="false"/>
<mx:DataGridColumn dataField="name" headerText="Name" editable="false"/>
<mx:DataGridColumn dataField="instance" headerText="Instance" editable="false"/>
<mx:DataGridColumn dataField="type" headerText="Type" editable="false"/>
<mx:DataGridColumn dataField="status" headerText="Status" editable="false"/>
</mx:columns>
</mx:DataGrid>

<mx:ControlBar horizontalAlign="left">
<mx:Button id="refresh"
label="Refresh"
rollOver="refresh_rollOver(event);"
rollOut="refresh_rollOut(event);"
click="refresh_clickHandler();"/>
</mx:ControlBar>

</mx:Panel>
...


Here is a screen shot of the Air application:



The refresh button will initiate another request to the TIBCO service and if anything has changed, the XML results will reflect the changes and the <mx:DataGrid> will be updated.

This is a pretty simple idea, but it demonstrates how we can take one technology and combine it with other tools and technologies to create useful applications to make life easier.

Download the code:
systemStatus.zip

Sunday, October 19, 2008

Editable Flex Datagrid and Grails

I have been really digging into Flex lately and I have been complimenting Flex's incredibly nice UI capabilities with services written on Grails. I am extremely impressed with Flex and Grails really helps me get things up and running very quickly (you already know this if you are using Grails). Let's look at a quick example of where I am using one domain class and a few simple Grails actions in a controller in order to provide search and editing capabilities to a simple Flex application based on a datagrid.

The Grails domain class, Item.groovy:

...
class Item {

    String name
    String brand
    String line
}
...

The Grails controller class ItemController.groovy:

...
class ItemController {

    def search = {
        if(!params.max) {
            params.max = 100
        }
        if(!params.name) {
            params.name = ""
        }

        def itemList = Item.findAllByNameLike("$params.name%",[max:params.max])

        render(contentType:"text/xml") {
            items {
                for(i in itemList) {
                    item {
                        id(i.id)
                        name(i.name)
                        brand(i.brand)
                        line(i.line)
                    }
                }
            }
        }
    }

    def save = {
        if(params.id) {
            def item = Item.get(params.id)

            if(item) {
                item.properties = params
                if(!item.hasErrors() && item.save()) {
                    render ""
                }
                else {
                    render ""
                }
            }
        }
    }
}
...


I also added this to the conf/BootStrap.groovy so I would have some data to work with once I started up the Grails applicaiton. The code below creates 1,000 items during start-up:

...
def init = { servletContext ->

    (1..1000).each {
        new Item(name: "Item $it", brand: "My Brand", line: "My Line").save()
    }
}
...

I mostly worked with only 1,000 items, but I increased this up to 100,000 items to put it through some tests and it worked very nicely.

Now let's dive right into the MXML. Here is the entire itemlist.mxml file:

...
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml">

<mx:Script>
<![CDATA[

import mx.controls.Alert;
import mx.events.DataGridEvent;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;

[Bindable]
private var itemId:String;

[Bindable]
private var itemName:String;

[Bindable]
private var itemBrand:String;

[Bindable]
private var itemLine:String;

private function sendItemData(event:DataGridEvent):void
{
var myEditor:TextInput = TextInput(event.currentTarget.itemEditorInstance);
itemName = myEditor.text;

itemId = event.currentTarget.editedItemRenderer.data["id"];
itemBrand = event.currentTarget.editedItemRenderer.data["brand"];
itemLine = event.currentTarget.editedItemRenderer.data["line"];

itemSaveService.send();
}

protected function filterList():void
{
itemSearchService.send();
}

private function fault_Handler(event:FaultEvent):void
{
Alert.show(event.fault.message, "Could not load items.");
}
]]>
</mx:Script>

<mx:HTTPService
id="itemSaveService"
method="POST"
url="http://localhost:8080/itemlist/item/save"
resultFormat="e4x"
fault="fault_Handler(event);"
showBusyCursor="true">
<mx:request xmlns="">
<id>{itemId}</id>
<name>{itemName}</name>
<brand>{itemBrand}</brand>
<line>{itemLine}</line>
</mx:request>
</mx:HTTPService>

<mx:HTTPService
id="itemSearchService"
method="GET"
url="http://localhost:8080/itemlist/item/search"
resultFormat="e4x"
fault="fault_Handler(event);"
showBusyCursor="true">
<mx:request xmlns="">
<name>{searchBox.text}</name>
</mx:request>
</mx:HTTPService>

<mx:Panel title="Item List" height="100%" width="100%" paddingTop="10" paddingLeft="10" paddingRight="10">

<mx:Label text="Search:"/><mx:TextInput id="searchBox" enter="filterList();"/>

<mx:DataGrid id="dg" width="100%" height="50%" rowCount="5"
dataProvider="{itemSearchService.lastResult.item}"
editable="true"
itemEditEnd="sendItemData(event);">
<mx:columns>
<mx:DataGridColumn dataField="id" headerText="Id" editable="false"/>
<mx:DataGridColumn dataField="name" headerText="Name"/>
<mx:DataGridColumn dataField="brand" headerText="Brand" editable="false"/>
<mx:DataGridColumn dataField="line" headerText="Line" editable="false"/>
</mx:columns>
</mx:DataGrid>

</mx:Panel>
</mx:Application>
...

Now that all of the code is out on the table, we can start to dissect what is happening with the Flex UI.

When the application starts up:




Once we type in "Item " and press enter:




When we click on a value under the "Name" column in our datagrid:




We have 2 HTTPService's setup to send requests back to our Grails controller at http://localhost:8080/itemlist/item/save and http://localhost:8080/itemlist/item/search. The first service call will send all the item data to the ItemController's save action and the second one will send our search box's text to the ItemController's search action. We have ActionScript functions that handle the "Enter" key press event on the search box and we also have a function that will be called after the datagrid field has been edited.

Most of the code is pretty self explanatory but if you have any questions, feel free to contact me. Also, Marcel Overdijk has some great posts on Grails and Flex that can really help out when you get stuck.