Showing posts with label flexdevelopment. Show all posts
Showing posts with label flexdevelopment. Show all posts

Adobe Flex as front end for J2EE application presentation

I did a presentation on how you can use Adobe Flex as front end of J2EE application Flex in Portal. This is good start if your a J2EE developer and want to learn what is flex, how you can integrate it in J2EE, what are your options,.. There are some slides which are specific to Portlet and WebSPhere Portal specifically

These are the sample applications that i built during preparation of this presentation

Developing Adobe Flex chat client

Together the Adobe Flex framework and BlazeDS framework provide infrastructure to create messaging/chat type of application. You can use the infrastructure to either create one to one or broadcast type of application.

I wanted to try this feature so i built a simple broadcast application, in which there will be one chat destination and multiple clients and connect to it and publish and subscribe messages from it. You can download that application from here

First download the BlazeDS application and use it for creating a new J2EE application.

Then open the messaging-config.xml, which has messaging related configuration required for BlazeDS and add a destination element in it like this

<?xml version="1.0" encoding="UTF-8"?>
<service id="message-service"
class="flex.messaging.services.MessageService">

<adapters>
<adapter-definition id="actionscript"
class="flex.messaging.services.messaging.adapters.ActionScriptAdapter"
default="true" />
<!-- <adapter-definition id="jms"
class="flex.messaging.services.messaging.adapters.JMSAdapter"/> -->
</adapters>

<default-channels>
<channel ref="my-polling-amf"/>
</default-channels>

<destination id="chat"/>
</service>


The chat destination will be used by flex application for both publishing and subscribing messages

Next create a ChatClient.mxml file like this


<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955"
minHeight="600" creationComplete="consumer.subscribe()">
<fx:Declarations>

<mx:Consumer id="consumer" destination="chat" message="messageHandler(event.message)"/>
<mx:Producer id="producer" destination="chat"/>

</fx:Declarations>
<fx:Script>
<![CDATA[
import mx.messaging.messages.AsyncMessage;
import mx.messaging.messages.IMessage;

private function send():void{
var message:IMessage = new AsyncMessage();
message.body.chatMessage = msg.text;
producer.send(message);
msg.text = "";
}
private function messageHandler(message:IMessage):void{
log.text += message.body.chatMessage + "\n";
}
]]>
</fx:Script>
<mx:Panel title="Chat" width="100%" height="100%">
<mx:TextArea id="log" width="100%" height="100%"/>
<mx:ControlBar>
<mx:TextInput id="msg" width="100%" enter="send()"/>
<mx:Button label="Send B" click="send()"/>
</mx:ControlBar>
</mx:Panel>
</s:Application>


I am using declarative message handling, the mx:Consumer element declares that your interested in chat destination its messageHandler() method will get whenever there is a new message chat destination.

The mx:Producer element is used for publishing messages to the destination, i am calling its send() method to publish the text to the desination

Reading query string inside the Flex Portlet

I made some changes in the Getting Query String of portal URL from inside the portlet code to use Flex on the client side. Now Flex is used for UI on the client side. You can download the sample code for portlet from here



The Portlet code remains the same, except one change, now i am forwarding control to query.jsp which is including Flex object on page using code like this


<%@page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1" session="false"%>
<%@taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>
<portlet:defineObjects />
<script type="text/javascript">

function getQueryString(){
console.log("Returning getQueryString");
return "<%=renderRequest.getAttribute("queryString")%>";
}

</script>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
id="HelloWorld" width="500px" height="500px"
codebase="http://fpdownload.macromedia.com/get/flashplayer/current/swflash.cab">
<param name="movie"
value='<%=renderResponse.encodeURL(renderRequest.getContextPath()
+ "/FlashQueryString.swf")%>' />
<param name="quality" value="high" />
<param name="bgcolor" value="#869ca7" />
<param name="allowScriptAccess" value="sameDomain" />
<embed src="<%=renderResponse.encodeURL(renderRequest.getContextPath() + "/FlashQueryString.swf")%>"
quality="high" bgcolor="#869ca7" width="500px" height="500px"
name="HelloWorld" align="middle" play="true" loop="false"
quality="high" allowScriptAccess="sameDomain"
type="application/x-shockwave-flash"
pluginspage="http://www.adobe.com/go/getflashplayer">
</embed> </object>


Also i have getQueryString function that returns the query string set by the Portlet code as request attribute.

My Flex code is very simple

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955"
minHeight="600" creationComplete="init()">
<fx:Script>
<![CDATA[
public function init():void{
if(ExternalInterface.available){
var queryString = ExternalInterface.call("getQueryString");
queryStringText.text = queryString;
}
}

]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Panel x="5" y="10" width="284" height="172" title="Query String Demo">
<s:TextArea x="10" y="44" width="220" height="54" id="queryStringText" />
<s:Label x="10" y="10" text="Query String" width="167" height="30"/>
</s:Panel>
</s:Application>


In the creationComplete() method of the Flex code i am calling getQueryString JavaScript method and setting value returned by it inside the text area for display

Flex and WebServices Portlet

If you follow this blog regularly you might have noticed that i am experimenting with how to use Flex in Portlet, which seems to be getting popular option. I started by creating simple Contact table in the database and then demonstrated how you can use Flex for adding and displaying records in the table. So far i have demonstrated how to use


In this last part i am going to demonstrate how you can use the Web Service in the Portlet from Flex application. The basic idea is that the Portlet will return HTML that loads Flex object from the doView() method but once that is done, the Flex will talk directly to the Web Service which is part of Same Portlet .war file directly without going through portlet



You can download the sample code for this blog from here



First i did create a simple WebServicesContactPortlet portlet like this

public class WebServicesContactPortlet extends javax.portlet.GenericPortlet {
public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
System.out.println("Entering WebServicesContactPortlet.doView()");
response.setContentType(request.getResponseContentType());
getPortletContext().getRequestDispatcher("/index.jsp").include(request, response);

}
}


In this portlet i am forwarding control to index.jsp for generating markup of the view mode. The index.jsp includes WSDataExchange.swf, this is how my Flex source looks like

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955"
minHeight="600" creationComplete="initLogging()">
<fx:Script>
<![CDATA[
import com.webspherenotes.flex.Contact;
import mx.controls.Alert;
import mx.logging.LogEventLevel;
import mx.logging.targets.TraceTarget;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.soap.WebService;
import mx.utils.ObjectUtil;
private function initLogging():void {
trace("Entering initLogging");
var logTarget:TraceTarget = new TraceTarget();
logTarget.level = LogEventLevel.ALL;
contactList.getContactList.send();
trace("Exiting initLogging");
}
public function getContactList_result(event:ResultEvent):void{
trace("Inside getContactList_result");
dgEmployees.dataProvider = event.result;
trace("ContactList result" + event.result);
}
public function faultHandler(event:FaultEvent):void{
trace("Inside getContactList_fault");
}
public function addContact():void{
trace("Entering addContact")
var mycontact:Contact = new Contact();
mycontact.firstName =txtFirstName.text;
mycontact.lastName = txtLastName.text;
mycontact.email = txtEmail.text;
contactList.insertContact.send(mycontact);
contactList.getContactList.send();
}
public function insertContact_result(event:ResultEvent):void{
trace("Entering insertContact_result");
}
]]>
</fx:Script>
<fx:Declarations>
<mx:WebService id="contactList"
wsdl="http://localhost:10040/wpcert/wscontactportlet/services/ContactDAOImpl/wsdl/ContactDAOImpl.wsdl">
<mx:operation name="getContactList"
resultFormat="object"
result="getContactList_result(event);"
fault="faultHandler(event);" />
<mx:operation name="insertContact"
resultFormat="object"
result="insertContact_result(event);"
fault="faultHandler(event);" />
</mx:WebService>

</fx:Declarations>
<mx:Panel x="0" y="0" width="500" height="410" layout="absolute"
title="Simple WebService Example">
<mx:DataGrid x="10" y="174" width="460" enabled="true" editable="false"
id="dgEmployees">
<mx:columns>
<mx:DataGridColumn headerText="First Name" dataField="firstName"/>
<mx:DataGridColumn headerText="Last Name" dataField="lastName"/>
<mx:DataGridColumn headerText="Email" dataField="email"/>
</mx:columns>
</mx:DataGrid>
<mx:Button x="190" y="121" label="Add Employee" id="getPerson" click="addContact()" />
<mx:Label x="110" y="12" text="First Name"/>
<mx:TextInput x="189" y="10" id="txtFirstName" />
<mx:Label x="110" y="50" text="Last Name"/>
<mx:TextInput x="189" y="48" id="txtLastName" />
<mx:Label x="110" y="84" text="E-mail"/>
<mx:TextInput x="189" y="82" id="txtEmail" />
<mx:Label x="10" y="148" text="Employees:"/>
</mx:Panel>
</s:Application>


The mx:WebService mxml element is pointing to the ContactDAOImpl web services which is part of my portlet and the two mx:operation declare that i want to use the getContactList and insertContact operation of ContactDaoImpl web service.

On the load of the swf file it calls initLogging() and in that method i am calling contactList.getContactList.send(), this results in getContactList operation of contactList service being called and once the results of the web service is available i get control in the getContactList_result method and i am using that method to assign results of websevice as dgEmployees.dataProvider

When it comes to calling web service with complex object first i have to create object of Contact which is defined as ActionScript class like this in my code

package com.webspherenotes.flex
{
[Bindable]
[RemoteClass(alias="com.webspherenotes.flex.dao.Contact")]
public class Contact
{
private var _firstName:String;
private var _lastName:String;
private var _email:String;
public function Contact()
{
}
public function get email():String
{
return _email;
}
public function set email(value:String):void
{
_email = value;
}
public function get lastName():String
{
return _lastName;
}
public function set lastName(value:String):void
{
_lastName = value;
}
public function get firstName():String
{
return _firstName;
}
public function set firstName(value:String):void
{
_firstName = value;
}
}
}


When i call contactList.insertContact.send(mycontact);, the ActionScript takes care of converting the object of Contact class into XML and passing it as argument to insertContact

For generating WebService i did copy my ContactDaoImpl in my portlet, and used RAD's generate Web Service feature to generate a web service to expose that Java Object. This is how my WebService Contact Portlet looks like

Flex Youtube Demo portlet

I built a sampleYoutube Demo Portlet using Simple Youtube FLex application




This portlet is very simple, all that it does is forward control to a JSP which includes Flex object from Simple Youtube FLex application and thent he

Simple Youtube Flex application

I wanted to build a simple Flex application for working with Youtube API, most of the blogs that i found on the internet talk about how to use as3-youtube-data-api for building that type of application, so i tried to build Flex application using that library but could not get it working, so i decided to build a simple demo application that makes use of Youtube API without any library

My Sample application lets you search for video first and then when you double click on a video, it will display that video below the search result for display



This the source code of my sample Youtube Flex application

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"
backgroundColor="0x000000" viewSourceURL="srcview/index.html" >
<mx:Script>
<![CDATA[
import com.adobe.serialization.json.JSON;
import mx.collections.ArrayCollection;
import mx.collections.XMLListCollection;
import mx.controls.dataGridClasses.DataGridColumn;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
[Bindable]
protected var dp:ArrayCollection;
protected function onResult(event:ResultEvent):void{
var feed:Object = JSON.decode(event.result as String).feed;
dp = new ArrayCollection(feed.entry);
}
protected function onFault(event:FaultEvent):void{
trace("Fault: " + event.fault.faultString);
}
protected function dgLabelFunction(row:Object,column:DataGridColumn):String{
if (column.dataField=="title")
return row.title.$t;
else if (column.dataField=="content")
return row.content.$t;
else return row.published.$t;
}
protected function getURL():String{
trace("Entering getURL()");
var videoUrlStr:String = dg.selectedItem.link[0].href;
var startingIndex:int = videoUrlStr.indexOf("?v=") +3;
var endingIndex = videoUrlStr.indexOf("&feature");
var tokenLength:int = endingIndex - startingIndex;
var v:String = videoUrlStr.substr(startingIndex, tokenLength);
var videoUrl = "http://www.youtube.com/v/" + v;
return videoUrl;
}
private function displayYouTube(videoUrl:String):void{
trace("Changing value of URL " + videoUrl);
swfloader.source = videoUrl;
}
]]>
</mx:Script>
<mx:HTTPService id="youTubeService" url="http://gdata.youtube.com/feeds/api/videos"
resultFormat="text" result="onResult(event)" fault="onFault(event)">
<mx:request>
<q>{searchTxt.text}</q>
<alt>json</alt>
</mx:request>
</mx:HTTPService>

<mx:HBox top="10" left="10">
<mx:Label text="Search YouTube:" color="0xFFFFFF"/>
<mx:TextInput id="searchTxt" enter="youTubeService.send()"/>
<mx:Button label="Go!" click="youTubeService.send()"/>
<mx:Label id="msg" text="Double click result to open video" visible="false"/>
</mx:HBox>
<mx:HBox width="100%" top="40" left="10" color="#000000">
<mx:DataGrid id="dg" width="620" height="220" doubleClickEnabled="true"
dataProvider="{dp}" doubleClick="displayYouTube(getURL())">
<mx:columns>
<mx:DataGridColumn dataField="title" labelFunction="dgLabelFunction"
headerText="Title" width="150"/>
<mx:DataGridColumn dataField="content" labelFunction="dgLabelFunction"
headerText="Content" width="200" />
<mx:DataGridColumn dataField="published" labelFunction="dgLabelFunction"
headerText="Published" width="150"/>
</mx:columns>
</mx:DataGrid>
</mx:HBox>
<mx:SWFLoader x="10" y="268" source="" id="swfloader"
autoLoad="true" scaleContent="true"/>
</mx:Application>


In my Sample application i have a mx:HTTPService pointing to http://gdata.youtube.com/feeds/api/videos, when you enter some text in the search box and click on GO it makes a HTTP request to the Http Service by making HTTP GET call to http://gdata.youtube.com/feeds/api/videos?alt=json&q=cricket, in this value of q is cricket because thats my search criteria.

The response is a JSON feed cricket video. I am decoding the feed and displaying it in the spreadsheet format using this code

protected function onResult(event:ResultEvent):void{
var feed:Object = JSON.decode(event.result as String).feed;
dp = new ArrayCollection(feed.entry);
}


Every row in the spread sheet has displayYouTube() has event listener for double click, when you double click on any row in the spread sheet i am building a URL to that video and assiging it as value of source for SWFLoader that is part of the mxml.

protected function getURL():String{
trace("Entering getURL()");
var videoUrlStr:String = dg.selectedItem.link[0].href;
var startingIndex:int = videoUrlStr.indexOf("?v=") +3;
var endingIndex = videoUrlStr.indexOf("&feature");
var tokenLength:int = endingIndex - startingIndex;
var v:String = videoUrlStr.substr(startingIndex, tokenLength);
var videoUrl = "http://www.youtube.com/v/" + v;
return videoUrl;
}
private function displayYouTube(videoUrl:String):void{
trace("Changing value of URL " + videoUrl);
swfloader.source = videoUrl;
}


When you click on any of the video it will build a URL like http://www.youtube.com/v/q9ew_nITQWY and set it as value of SWFLoader source attribute.

Flex Flickr Demo Portlet

I built a sample portlet using Simple Flickr Flex Application to demonstrate how to use Flex. You can download this portlet from here, it will work in any JSR 168 or JSR 286 compliant portlet container




Its a very simple portlet all that it does is forward control to a JSP that includes Flicker Flex object and then the actual business logic is inside Flex

Simple Flickr Flex application

I wanted to build a simple Flex application that would get photos from the Flickr Service, but most of the tutorials that i found on the web they build a very complicated full fledged application, so i built this simple application, which gets the recently added photos from Flex and displays them in simple layout. This demo application covers basic pattern for using Flickr service from Flex and once you get basics you should be able to modify it for adding other calls.



I am using As3FlickrLib library for building my code,

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955"
minHeight="600" creationComplete="init()">
<fx:Script>
<![CDATA[
import adobe.utils.CustomActions;
import com.adobe.webapis.flickr.AuthPerm;
import com.adobe.webapis.flickr.FlickrService;
import com.adobe.webapis.flickr.PagedPhotoList;
import com.adobe.webapis.flickr.Photo;
import com.adobe.webapis.flickr.events.FlickrResultEvent;
import mx.collections.ArrayCollection;
import mx.collections.ArrayList;
import mx.logging.Log;
import mx.logging.LogEventLevel;
import mx.logging.targets.TraceTarget;
public var flickr:FlickrService = new FlickrService("ReplaceWithYourFlickerKey");
private function initLogging():void {
var logTarget:TraceTarget = new TraceTarget();
logTarget.level = LogEventLevel.ALL;
Log.addTarget(logTarget);
}
public function init():void{
initLogging();
trace("After enabling logging");
flickr.secret=""ReplaceWithYourFlickerSecret"";
flickr.addEventListener (FlickrResultEvent.AUTH_GET_FROB, onGetFrob);
flickr.auth.getFrob();
}
public function onGetFrob (event : FlickrResultEvent) : void{
if (event.success){
var frob : String = event.data.frob as String;
var authURL : String = flickr.getLoginURL (frob, AuthPerm.READ);
flickr.addEventListener(FlickrResultEvent.PHOTOS_GET_RECENT,showRecent);
flickr.photos.getRecent();

}
}
public function showRecent(e:Object):void{
trace("Inside showPhotoDetail "+ e)
var photoList:PagedPhotoList = e.data.photos;
trace("Paged Photo List "+ photoList);
var photos:ArrayList = new ArrayList();
for( var i = 1 ; i < 40 ; i++){
var photo:Photo = photoList.photos[i];
var photoUrl:String ='http://static.flickr.com/' +
photo.server+ '/' + photo.id + '_' + photo.secret + '_t.jpg';
trace(photoUrl);
photos.addItem(photoUrl);
}
imageDisplay.dataProvider = photos;
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<s:Panel x="0" y="0" width="600" height="500" title="Flickr Demo">
<s:List id="imageDisplay" width="530"
height="400" x="0" y="0">
<s:layout>
<s:TileLayout requestedColumnCount="5" requestedRowCount="8"
horizontalGap="2" verticalGap="2"/>
</s:layout>
<s:itemRenderer>
<fx:Component>
<mx:Image source="{data}"
height="100" width="100" />
</fx:Component>
</s:itemRenderer>
</s:List>
</s:Panel>
</s:Application>


In order to use Flickr Service you will need a Flickr API key, you can get it from here , once you have it, you can replace the ReplaceWithYourFlickerKey in sample code with your key and ReplaceWithYourFlickerSecret in sample code with your secret.

Before you start using FlickrService you will have to authenticate with the service, you can do that by using following code

public var flickr:FlickrService = new FlickrService("ReplaceWithYourFlickerKey");
flickr.secret="ReplaceWithYourFlickerSecret";
flickr.addEventListener (FlickrResultEvent.AUTH_GET_FROB, onGetFrob);
flickr.auth.getFrob();


Create object of FlickrService by passing your developer key, then set the secret property equal to value of secret you got from Flickr, Once that is done add a event listener for FlickrResultEvent.AUTH_GET_FROB and call the flickr.auth.getFrob(), this will result in Authentication call being made to Flickr Service, with your key and secret and the response will return a frob value like this

Request
http://api.flickr.com/services/rest/?api_key=yourkey&method=flickr.auth.getFrob&api_sig=secretinencodedformat&
Response
<?xml version="1.0" encoding="utf-8" ?>
<rsp stat="ok">
<frob>72157623957288592-f1571eccb125f756-29961</frob>
</rsp>


After you get response for the frob, you can start making the actual calls to get data from service, in my case i wanted to keep this application very simple so i am making call to get all the recent additions to flickr and displaying it using this code

public function onGetFrob (event : FlickrResultEvent) : void{
if (event.success){
var frob : String = event.data.frob as String;
var authURL : String = flickr.getLoginURL (frob, AuthPerm.READ);
flickr.addEventListener(FlickrResultEvent.PHOTOS_GET_RECENT,showRecent);
flickr.photos.getRecent();

}
}
public function showRecent(e:Object):void{
trace("Inside showPhotoDetail "+ e)
var photoList:PagedPhotoList = e.data.photos;
trace("Paged Photo List "+ photoList);
var photos:ArrayList = new ArrayList();
for( var i = 1 ; i < 40 ; i++){
var photo:Photo = photoList.photos[i];
var photoUrl:String ='http://static.flickr.com/' +
photo.server+ '/' + photo.id + '_' + photo.secret + '_t.jpg';
trace(photoUrl);
photos.addItem(photoUrl);
}
imageDisplay.dataProvider = photos;
}


As you can see after getting authentication i am attaching event listener for FlickrResultEvent.PHOTOS_GET_RECENT event and then making call to get flickr.photos.getRecent() recent photos, This results in following HTTP request to flickr service

http://api.flickr.com/services/rest/?api_key=apikey&method=flickr.photos.getRecent&extras=&per_page=100&page=1&


And response is XML feed with information about recently added photos like this

<?xml version="1.0" encoding="utf-8" ?>
<rsp stat="ok">
<photos page="1" pages="10" perpage="100" total="1000">
<photo id="4563046917" owner="19673208@N08" secret="2e8188f6e7" server="4052"
farm="5" title="DSCN0379" ispublic="1" isfriend="0" isfamily="0" />
<photo id="4563047015" owner="8867627@N07" secret="16e4c986a6" server="3375"
farm="4" title="red blossom" ispublic="1" isfriend="0" isfamily="0" />


I am iterating through the feed and creating URLs to the photos.

Note: If you want to call any other method of FlickrService you can find the corresponding Event name and method name and use them to call the service

BlazeDS Contact Portlet

I wanted to learn how to i can use BlazeDS technology in portlet so i built a sample Contact Management application, This application has BlazeDSContactPortlet, which is used for returning a JSP that includes Flex from doView() method but once the Flex application is loaded it will directly communicate to MessageBrokerServlet inside the portlet, which is disadvantage of using BlazeDS in portlet application, you wont have portlet context in any other calls



You can download the sample code for this article from here


The BlazeDS application is nothing but a Servlet that you can add to your portlet application along with set of jars and you should be able to use it for communicating to Flex

  1. First download the blazeds.war and copy all the jars from its WEB-INF/lib to your WEB-INF/lib folder
  2. Then add HttpFlexSession listener and MessageBrokerServlet servlet to your web.xml like this

    <listener>
    <listener-class>flex.messaging.HttpFlexSession</listener-class>
    </listener>
    <servlet>
    <servlet-name>MessageBrokerServlet</servlet-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>


  3. The copy flex folder from the blazeds.war to your WEB-INF folder and change services-config.xml file so that value of my-amf channel points to the MessageBrokerServlet in your environment.

    <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
    <endpoint url="http://localhost:10040/wpcert/PA_BlazeDSContact/messagebroker/amf"
    class="flex.messaging.endpoints.AMFEndpoint"/>
    </channel-definition>

    The value of url will change based on your environment, in my case base URL of the server is http://localhost:10040 and the web application that has the MessageBrokerServlet is available at http://localhost:10040/wpcert/PA_BlazeDSContact, so i add /messagebroker/amf to it and that becomes value of my-amf channel url

  4. I am more interested in using BlazeDS to make calls to Java Objects in my portlet application from my Flex code, so first i declare the Java Class that should be invoked from my Flex class by adding this code to my remoting-config.xml file like this

    <destination id="contactdao">
    <properties>
    <source>com.webspherenotes.flex.dao.ContactDAOImpl</source>
    </properties>
    </destination>

    Now i can call methods of com.webspherenotes.flex.dao.ContactDAOImpl Java Class directly from my Flex code

  5. Now inside my flex code i can add this code to call methods of the ContactDAOImpl

    [Bindable]
    public var contactList:ArrayCollection;

    public var contactDAORO:RemoteObject;
    public function getContactList():void {
    contactDAORO = new RemoteObject();
    contactDAORO.destination = "contactdao";
    contactDAORO.endpoint ="http://localhost:10040/wpcert/PA_BlazeDSContact/messagebroker/amf"
    contactDAORO.addEventListener("result",getContactListHandler);
    contactDAORO.addEventListener("fault",faultHandler);
    contactDAORO.getContactList();
    }
    public function faultHandler (event:FaultEvent):void {
    Alert.show(event.fault.faultString, 'Error');
    }
    private function getContactListHandler(event:ResultEvent):void{
    contactList = event.result as ArrayCollection;
    dgEmployees.dataProvider = contactList;
    }


    <mx:DataGrid x="10" y="174" width="460" enabled="true" editable="false"
    id="dgEmployees">
    <mx:columns>
    <mx:DataGridColumn headerText="First Name" dataField="firstName"/>
    <mx:DataGridColumn headerText="Last Name" dataField="lastName"/>
    <mx:DataGridColumn headerText="Email" dataField="email"/>
    </mx:columns>
    </mx:DataGrid>

    My Flex code has dgEmployees as DataGrid , that displays list of contacts in spread sheet format.

    I am calling getContactList(), flex method on the application load, this method is creating object of RemoteObject and pointing to URL where MessageBrokerServlet in my application is listening, then i am setting value of contactDAORO.destination to contactdao, when i do that MessageBrokerServlet, will take value of destination and find out the java class from that is mapped to contactdao by reading remoting-config.xml, in our case it is pointing to com.webspherenotes.flex.dao.ContactDAOImpl, then i am setting getContactListHandler, as flex method which should be used to handle result of this call and faultHandler method for handling error cases in this flex call.

    The contactDAORO.getContactList() means i want to call the getContactList() method of ContactDAOImpl class, this method returns ArrayList of Contact objects, on the flex side i am converting that ArrayList to ArrayCollection and i have a Contact flex class that is mapped to the Contact java class. Inside the getContactList() method i am setting the list returned by Java code as dataprovider for the datagrid

  6. This is how my Action Script Contact class looks like

    package com.webspherenotes.flex
    {
    [Bindable]
    [RemoteClass(alias="com.webspherenotes.flex.dao.Contact")]
    public class Contact
    {
    private var _firstName:String;
    private var _lastName:String;
    private var _email:String;
    public function Contact()
    {
    }
    public function get email():String
    {
    return _email;
    }
    public function set email(value:String):void
    {
    _email = value;
    }
    public function get lastName():String
    {
    return _lastName;
    }
    public function set lastName(value:String):void
    {
    _lastName = value;
    }
    public function get firstName():String
    {
    return _firstName;
    }
    public function set firstName(value:String):void
    {
    _firstName = value;
    }
    }
    }


What is blazeDS

BlazeDS is a open source project, that provides some infrastructure that can be used to simplify development of J2EE backend and Flex for front end type of application

BlazeDS functionality can be divided into following three key services:

  1. The Remoting Service allows your Flex application to directly invoke methods of Java objects deployed in your application server.

  2. The Message Service provides a publish/subscribe infrastructure that allows your Flex application to publish messages and subscribe to a messaging destination, enabling the development of real-time data push and collaborative applications.

  3. The Proxy Service allows your Flex application to make cross-domain service requests in a secure and controlled manner. In other words, it allows your Flex application to access a service available on a different domain than the domain from where the application was downloaded (without having to deploy a crossdomain.xml policy file on the target domain).




If you want to build J2EE on server side and Flex for front end type of application, then you can either use JSON, XML or Flex for data exchange but using BlazeDS provides following advantages


  1. It takes care of converting Java object into Action Script object required by Flex and other way round.

  2. It is more efficient then either JSON or XML for communicating between J2EE and Flex application

Converting Action Script object to XML

The Flex and XML Portlet is sample of how you can send XML String from Java Portlet to Flex and Flex displays it in DataGrid format. In that blog i covered how to submit data entered by user in Flex application, using HTTP POST method.






I changed the Sample code so that now i am converting the data submitted by user in Flex application into XML first then submitting it using HTTP POST method. I am using As3xml library for converting Action Script object into XML.

In order to get this sample working first i had to define Flex Contact class then change the addContact() method like this

public function addContact():void{
trace("Entering useHttpService");
service = new HTTPService();
service.url = nextActionURL;
service.resultFormat = HTTPService.RESULT_FORMAT_TEXT;
service.method = "POST";
var myContact:Contact = getContact();

var myContactXML:XML= Asx3mer.instance.toXML(myContact);

var params:Object = { myContactStr: myContactXML };

service.send(params);
getContactList();
trace("Entering useHttpService");
}
public function getContact():Contact{
var myContact:Contact =new Contact();
myContact.firstName = txtFirstName.text;
myContact.lastName = txtLastName.text;
myContact.email = txtEmail.text;
return myContact;
}


First i did create a getContact() method which reads values entered by user in Flex application and returns a Contact object based on it. Then converting Contact Flex object into XML object is pretty simple all i had to do was call Asx3mer.instance.toXML(). What i liked most is about working with XML in Flex is how easy it is pretty print XML, all i had to do was print the XML object and it prints a XML like this


<com.webspherenotes.flex.Contact>
<firstName>Sachin</firstName>
<lastName>Tendulkar</lastName>
<email>sachin@mi.com</email>
</com.webspherenotes.flex.Contact>


I am submitting a form to the actionURL with this XML as value of myContactStr

Then on the server side i had to create a method which can parse the XML string into Java Object, i am using Xstream for that

public static Contact convertXMLToJava(String xmlStr){
XStream xstream = new XStream(new DomDriver());
xstream.setMode(XStream.NO_REFERENCES);
xstream.alias("com.webspherenotes.flex.Contact", Contact.class);
System.out.println("setting values of contact object");
Contact contact= (Contact)xstream.fromXML(xmlStr);
return contact;
}

Flex and XML Portlet

Before couple of days i did create a Flex and JSON portlet, that portlet is a simple portlet which sends list of contacts to flex in JSON format and then flex is displaying that data in the Grid format then i changed it so that Flex UI converts the data submitted by user in the JSON string format and submit it to portlet, the portlet is responsible for parsing JSON back to Java Object and inserting it into database.

Today i made some changes in the portlet so that portlet reads list of contacts from database, converts it into XML and sends it to Flex object and then Flex is displaying it like this using DataGrid. YOu can also insert new record in Contact table, when you do that i am passing values submitted by user separately as POST parameters




The server side code for this portlet is almost same as that of Flex and JSON portlet, with difference that i am using Xstream for converting Contact Java object into XML like this


public static String convertJavaToXML(ContactDTO contactDto){
XStream xstream = new XStream(new DomDriver());
xstream.setMode(XStream.NO_REFERENCES);
xstream.alias("contactDTO",ContactDTO.class);
xstream.alias("contact", Contact.class);

String xmlString = xstream.toXML(contactDto);

return xmlString ;
}


The client side flex code is almost same, only thing that i had to change is the method that handles response of resourceURL and converts it into dataprovider for the DataGrid like this


public function httpResult(event:ResultEvent):void {
trace("Entering httpResult");
var result:Object = event.result;
trace(" Response in string" + event.result.toString());
var xmlData:Object =new XML(event.result.toString());
nextActionURL = xmlData.actionURL;
var xmlListColl:XMLListCollection = new XMLListCollection(xmlData.contactList.children());
trace("After creating xmlListCollection " + xmlListColl);
dgEmployees.dataProvider = xmlListColl;
trace("Entering httpResult");
}


The XML object which is part of default package in Flex takes XML string as input and converts it into flex object. This is the response returned by portlet

<contactDTO>
<actionURL>/pluto/portal/Sunils Test Page/__acXMLContactPortlet0x2XMLContactPortlet!-318001599%7C0/__pmXMLContactPortlet0x2XMLContactPortlet!-318001599%7C0_view/__wsXMLContactPortlet0x2XMLContactPortlet!-318001599%7C0_normal?</actionURL>
<contactList>
<contact>
<firstName>Jiya</firstName>
<lastName>Patil</lastName>
<email>jiya@gmail.com</email>
</contact>
</contactDTO>


After converting this object into Flex you can access elements as properties of flex object Ex. you can access values of actionURL element using xmlData.actionURL.

In order to display contacts in DataGrid first i am creating a XMLListCollection object like this XMLListCollection(xmlData.contactList.children()) then setting it as value of dataProvider for the DataGrid

Creating JSON in Flex

In the Flex JSON Portlet that i blogged about yesterday, i was submitting values submitted by users for First Name, Last Name and email as form parameters, which seems natural.

Then i thought lets see if i can create a Action Script class and then convert it into JSON and submit it as JSON String to server side, so i did create my First Action Script Class like this

I used Flash Builder 4.0 for creating this class, All i had to do was to right click and say create Action Script Class and it asked me for package and class name like Java and created this class then after adding variables in it i did select each of them and said Generate Geters and setters, it marked that variable as private first and generated methods like this

package com.webspherenotes.flex
{
public class Contact
{
private var _firstName:String;
private var _lastName:String;
private var _email:String;

public function Contact()
{
}
public function get email():String
{
return _email;
}
public function set email(value:String):void
{
_email = value;
}
public function get lastName():String
{
return _lastName;
}
public function set lastName(value:String):void
{
_lastName = value;
}
public function get firstName():String
{
return _firstName;
}
public function set firstName(value:String):void
{
_firstName = value;
}
}
}


After that i thought lets create ContactDTO which will be used for submitting data from client side to server side so i created a class like this

package com.webspherenotes.flex
{
public class ContactDTO
{
private var _contact:Contact;
public function ContactDTO()
{
}
public function get contact():Contact
{
return _contact;
}
public function set contact(value:Contact):void
{
_contact = value;
}

}
}


Then i made changes in the event listener for the Add Employee button so that it creates object of Contact and ContactDTO and then makes use of JSON.encode() method to convert that object into JSON String and submitted that string as a value of myContactStr

public function addContact():void{
trace("Entering useHttpService");
service = new HTTPService();
service.url = nextActionURL;
service.resultFormat = HTTPService.RESULT_FORMAT_TEXT;
service.method = "POST";

var myContact:Contact =new Contact();
myContact.firstName = txtFirstName.text;
myContact.lastName = txtLastName.text;
myContact.email = txtEmail.text;
var myContactDTO:ContactDTO = new ContactDTO();
myContactDTO.contact = myContact;
var myContactJSONStr:String = JSON.encode(myContactDTO);

trace("Submitting MyContactStr " + myContactJSONStr);
var params:Object = { myContactStr: myContactJSONStr };
service.send(params);
getContactList();
trace("Entering useHttpService");
} }


Now when i try to add a new contact, the flex code creates a JSON string like this and submits it as form parameter

{"contact":{"firstName":"James","lastName":"bond","email":"jamesbond@mi5.com"}}


Then on the server side i am reading value of myContactStr form parameter instead of firstName, lastName and email and then using XStream to parse that string into Contact object with code like this

public static Contact convertJSONToJava(String jsonStr){
XStream xstream = new XStream(new JettisonMappedXmlDriver());
xstream.setMode(XStream.NO_REFERENCES);
xstream.alias("contact", Contact.class);
System.out.println("setting values of contact object");
Contact contact= (Contact)xstream.fromXML(jsonStr);
return contact;
}

Flex and JSON Portlet

I built a Sample Contact Management to demonstrate how you can use JSON as data exchange format for sending data from Portlet to Flex. You can download the sample code for portlet as well as Flex part

Note: After downloading sample first thing that you should do is go to Edit mode and click on Setup DB link, it will create Contact table in the hsqldb.

The Sample Contact application is Flex on the client side and on the server side it is JSR 286 compliant portlet, i am using HSQLDB for storing data and XStream for Converting Java Object to JSON. On the Flex side i am using as3corelib. There is Apache Maven 2 script that you can use for building the source code and downloading server side dependencies

I have a Contact table in database and when you access the portlet, it will query data in the Contact Table and display it in spread sheet format on the onload event. THere is a form at the top in Flex part which you can use for adding new record in the Contact table.





<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx1="library://ns.adobe.com/flex/halo"
minWidth="500" minHeight="410"
creationComplete="initLogging()"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="500" height="410">
<fx:Script>
<![CDATA[
import com.adobe.serialization.json.JSON;
import com.adobe.serialization.json.JSONDecoder;
import mx.controls.Alert;
import mx.logging.ILogger;
import mx.logging.Log;
import mx.logging.LogEventLevel;
import mx.logging.targets.TraceTarget;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;
private function initLogging():void {
trace("Entering initLogging");
var logTarget:TraceTarget = new TraceTarget();
logTarget.level = LogEventLevel.ALL;
Log.addTarget(logTarget);
getContactList();
trace("Exiting initLogging");
}
private var service:HTTPService;
public function useHttpService(url:String):void {
trace("Entering useHttpService");
service = new HTTPService();
service.url = url;
service.resultFormat = HTTPService.RESULT_FORMAT_TEXT;
service.method = "GET";
service.addEventListener("result", httpResult);
service.addEventListener("fault", httpFault);
service.send(parameters);
trace("Entering useHttpService");
}
public function httpResult(event:ResultEvent):void {
trace("Entering httpResult");
var result:Object = event.result;
var resultJSON:Object =JSON.decode(event.result.toString());
dgEmployees.dataProvider = resultJSON.contactDTO.contactList;
nextActionURL = resultJSON.contactDTO.actionURL;
trace("Entering httpResult");
}
public function httpFault(event:FaultEvent):void {
trace("Entering httpFault");
var faultstring:String = event.fault.faultString;
Alert.show(faultstring + event.fault.faultDetail + event.fault.rootCause);
trace("Entering httpFault");
}
private var nextActionURL:String;
public function getContactList():void {
var javaScriptMethodName:String = "getResourceURL";
if (ExternalInterface.available) {
var portletUrl:String = ExternalInterface.call(javaScriptMethodName);
}
trace("Resource URL " + portletUrl);
useHttpService(portletUrl);
}
public function addContact():void{
trace("Entering useHttpService");
service = new HTTPService();
service.url = nextActionURL;
service.resultFormat = HTTPService.RESULT_FORMAT_TEXT;
service.method = "POST";
var params:Object =
{ firstName: txtFirstName.text, lastName: txtLastName,email:txtEmail };
service.send(params);
getContactList();
trace("Entering useHttpService");
}

]]>
</fx:Script>
<fx:Declarations>

</fx:Declarations>
<mx:Panel x="0" y="0" width="500" height="410" layout="absolute"
title="Simple JSON Example">
<mx:DataGrid x="10" y="174" width="460" enabled="true" editable="false"
id="dgEmployees">
<mx:columns>
<mx:DataGridColumn headerText="First Name" dataField="firstName"/>
<mx:DataGridColumn headerText="Last Name" dataField="lastName"/>
<mx:DataGridColumn headerText="Email" dataField="email"/>
</mx:columns>
</mx:DataGrid>
<mx:Button x="190" y="121" label="Add Employee" id="getPerson"
click="addContact()" />
<mx:Label x="110" y="12" text="First Name"/>
<mx:TextInput x="189" y="10" id="txtFirstName" />
<mx:Label x="110" y="50" text="Last Name"/>
<mx:TextInput x="189" y="48" id="txtLastName" />
<mx:Label x="110" y="84" text="E-mail"/>
<mx:TextInput x="189" y="82" id="txtEmail" />
<mx:Label x="10" y="148" text="Employees:"/>
</mx:Panel>

</s:Application>


The Flex application has DataGrid which is used for displaying the Contact Summary, DataGrid has three DataGridColumn which are used for displaying three Contact table columns. The MXML also has three input fields where user can enter values for adding new contact.

There is quite a bit of ActionScript in this application but i already blogged about most of the pieces, lets take a look at them one by one

  • initLogging() It is used for initializing the flex logging In addition to enabling log it also does one thing, which is to call the getContactList() function

  • getContactList() This function is used for making a Resource Request from Flex application to the portlet. Now as we know we cannot hard code the Resource URL in flex application, because the URL is dynamically generated by portal. So what i am doing is making use of JavaScript function to read the ResourceURL generated by JSP page that is including Flex object and then making HTTPService call to get it. Inside getContactList(), i am calling useHttpService() function for making actual HTTP Service call

  • useHttpService() This function is making a HTTP GET call to the URL supplied as parameter and attaching the httpResult() function as a result handler and httpFault() as error handler

  • httpResult() In This sample portlet the serveResource() method is returning contactlist in JSON format, so this method is used for parsing the JSON and getting contactList object out of it. I am using JSON.decode() function provided by as3corelib to convert the response into Flex object. Once you have the flex object you can access its fields. In my sample application the JSON response string would be something like this

    {"contactDTO": {
    "actionURL": "/pluto/portal/Sunils Test Page/__acJSONContactPortlet0x2JSON0x8C
    ontact0x8Portlet!-318001599%7C0?",
    "contactList": [
    {
    "firstName": "Jiya",
    "lastName": "Patil",
    "email": "jiya@gmail.com"
    },
    }

    The JSON object has a ContactDTO object which has actionURL, which is a String and contactList which is list of Contact Objects which three fields. The JSON.decode() converts it into corresponding Flex object. Once the JSON is parsed i am assigning contactList as dataProvider for the DataGriddgEmployees.dataProvider = resultJSON.contactDTO.contactList, so flex will read the list and display in the Spread sheet format. The JSON response also has action URL field which is nothing but actionURL for this portlet, As i mentioned in How to make action or render request from the Adobe Flex post, in WPS you cannot reuse the ActionURL instead you can use it only once. So i am generating the actionURL in the portlet and passing it as part of the JSON response, when the Flex code want to make action URL it will use the ActionURL sent in the last response, inside addContact() method

  • addContact() Method is event handler for Add Employee button, it reads the values entered by user in 3 input fields and submits them using HTTP POST method to the actionURL, which will result in processAction() method of the portlet being called, where i am adding that contact to the contact table. Please note that i am ignoring output of the HTTP POST call. After that call i am calling getContactList() for getting updated contact list and displaying in the spread sheet



THe Server side code for this application is like this

public class JSONContactPortlet extends GenericPortlet {
protected void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
System.out.println("Entering JSONContactPortlet.doView()");
response.setContentType("text/html");
getPortletContext().getRequestDispatcher("/index.jsp").include(request,
response);
System.out.println("Exiting JSONContactPortlet.doView()");
}
protected void doEdit(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
System.out.println("Entering JSONContactPortlet.doEdit()");
response.setContentType("text/html");
getPortletContext().getRequestDispatcher("/setup.jsp").include(request,
response);
System.out.println("Exiting JSONContactPortlet.doEdit()");

}
public void processAction(ActionRequest request, ActionResponse response)
throws PortletException, IOException {
System.out.println("Entering JSONContactPortlet.processAction()");
ContactDAO contactDAO = new ContactDAOImpl();
if(request.getPortletMode().equals(PortletMode.EDIT)){

contactDAO.setup();
}else if(request.getPortletMode().equals(PortletMode.VIEW)){
String firstName =request.getParameter("firstName");
String lastName =request.getParameter("lastName");
String email = request.getParameter("email");
contactDAO.insertContact(new Contact(firstName,lastName,email));
}

System.out.println("Exiting JSONContactPortlet.processAction()");
}
public void serveResource(ResourceRequest request, ResourceResponse response)
throws PortletException, IOException {
System.out.println("Entering JSONContactPortlet.serveResource()");
response.setContentType("text/html");
ContactDAO contactDAO = new ContactDAOImpl();
ArrayList contactList = contactDAO.getContactList();
ContactDTO contactDTO = new ContactDTO(response.createActionURL().toString(), contactList);
response.getWriter().println(JSONHelper.convertJavaToJSON(contactDTO));
System.out.println("Exiting JSONContactPortlet.serveResource()");
}
}



  • doView() In this method i am passing control to index.jsp which generates a markup to include the swf file in the response and it also has getResourceURL
    ()
    JavaScript function that can be used for getting resource URL

  • doEdit() THis method is passing control to setup.jsp which generates action URL for setup. THe Edit mode of this portlet allows you to create Contact table in the database

  • processAction() This method can be called from either the VIEW or EDIT mode, in the VIEW mode it used for inserting a row in contact table and in the EDIT mode it is used for setup, i.e. to crate CONTACT table

  • serveResource() This method is fist getting list of contacts from ContactDAO and then using XStream to convert it into JSON string using code like this

    public static String convertJavaToJSON(Object javaObj){
    XStream xstream = new XStream(new JsonHierarchicalStreamDriver());
    xstream.setMode(XStream.NO_REFERENCES);
    xstream.alias("contactDTO",ContactDTO.class);
    xstream.alias("contact", Contact.class);
    String jsonString = xstream.toXML(javaObj);
    System.out.println(jsonString);
    return jsonString;
    }



Download the sample code of this portlet and try it.

Maven script to build Flex portlet

As you might have seen in the last few days i am working on using Flex inside the portlet and i did built quite a few portlets to demonstrate how that works.

The building and deployment was very painful, first i had to make changes in the .mxml export it as .swf from Flex builder into the WebContent folder of my portlet then export portlet with new .swf and install it on portal.

In order to simplify this process i built a mvn script which can be used to build .mxml in .swf, copy it into the WebContent folder, package the portlet and then deploy it in the pluto, this is the script that i am using.



<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

<!-- Change this to something akin to your java package structure -->
<groupId>com.webspherenotes.portlet</groupId>
<modelVersion>4.0.0</modelVersion>
<!-- Version of this app -->
<version>0.1-alpha1</version>
<!-- Base name of the war file without .war ext -->
<artifactId>HelloWorldPortlet</artifactId>
<packaging>war</packaging>
<name>${pom.artifactId}</name>
<!-- Dependency Version Properties ======================================= -->
<properties>
<pluto.version>2.0.0</pluto.version>
<portlet-api.version>2.0</portlet-api.version>
<servlet-api.version>2.4</servlet-api.version>
<jsp-api.version>2.0</jsp-api.version>
<junit.version>3.8.1</junit.version>
<pluto.home>C:/software/pluto-2.0.0</pluto.home>
<flex.home>C:/software/AdobeFlashBuilder/sdks/4.0.0</flex.home>
<flex.mxml.path>C:/flex/HelloFlex/src/HelloWorld.mxml</flex.mxml.path>
<flex.swf.name>HelloWorld.swf</flex.swf.name>
</properties>
<dependencies>
<dependency>
<groupId>javax.portlet</groupId>
<artifactId>portlet-api</artifactId>
<version>${portlet-api.version}</version>
<scope>provided</scope><!-- Prevents addition to war file -->
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>${servlet-api.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.portals.pluto</groupId>
<artifactId>pluto-util</artifactId>
<version>${pluto.version}</version>
<scope>provided</scope>
</dependency>
<!-- Any other build or deployment dependancies go here -->
</dependencies>
<build>
<finalName>${pom.name}</finalName>
<plugins>

<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>integration-test</phase>
<configuration>
<tasks>
<property environment="env"/>
<!-- This assumes that you have set a CATALINA_HOME environmental variable
<property name="pluto.home" value="C:/software/pluto-2.0.0"/>-->
<copy file="target/${pom.name}.war" todir="${pluto.home}/webapps"/>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- configure to use Java 6 to compile (change to your JDK) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<!-- configure maven-war-plugin to use updated web.xml -->
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webXml>${project.build.directory}/pluto-resources/web.xml</webXml>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.portals.pluto</groupId>
<artifactId>maven-pluto-plugin</artifactId>
<version>${pluto.version}</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<configuration>
<tasks>
<property name="FLEX_HOME" value="${flex.home}"/>
<taskdef resource="flexTasks.tasks" classpath="${FLEX_HOME}/ant/lib/flexTasks.jar"/>
<mxmlc file="${flex.mxml.path}" keep-generated-actionscript="false"
output="${project.build.directory}/${project.name}/${flex.swf.name}">
<load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/>
<source-path path-element="${FLEX_HOME}/frameworks"/>
<compiler.library-path dir="${FLEX_HOME}/frameworks" append="true">
<include name="libs" />
<include name="../bundles/{locale}" />
</compiler.library-path>
</mxmlc>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

Ant script for building Flash application

This is the ant script that i use for compiling my Flex application into .swf file


<?xml version="1.0" encoding="utf-8"?>
<project name="My App Builder" basedir=".">

<property name="FLEX_HOME" value="C:/software/AdobeFlashBuilder/sdks/4.0.0"/>
<property name="FLEX_MXML_PATH" value="C:/flex/HelloFlex/src/JSONDataExchange.mxml"/>
<property name="FLEX_SWF_PATH" value="C:/flex/HelloFlexPortlet/WebContent/HelloFlex.swf"/>

<taskdef resource="flexTasks.tasks" classpath="${FLEX_HOME}/ant/lib/flexTasks.jar"/>
<target name="main">
<mxmlc file="${FLEX_MXML_PATH}" keep-generated-actionscript="true" output="${FLEX_SWF_PATH}">
<load-config filename="${FLEX_HOME}/frameworks/flex-config.xml"/>
<source-path path-element="${FLEX_HOME}/frameworks"/>
<compiler.library-path dir="${FLEX_HOME}/frameworks" append="true">
<include name="libs" />
<include name="../bundles/{locale}" />
</compiler.library-path>
</mxmlc>
</target>
</project>


You need to have either the Adobe Flex builder or the Flex SDK installed on your machine. This script requires following three variables


  1. FLEX_HOME Location where FLEX SDK is installed on your machine. If you have Flex builder 4.0, it has both SDK 4.0 and SDK 3.5 and you can point to either of them

  2. FLEX_MXML_PATHFully qualified path of the .mxml file that has your Flex application

  3. FLEX_SWF_PATHFully qualified path of the .swf file that you want to generate. In my case i am generating the .swf file inside my Web application so that i can package it in the .war file

Creating application specific log in the Flex program

You can create application specific log in your flex application like this. In my case i am initializing myLogger in the initLogger() method at the time of document creation and once the logger is initialized we can write something at debug level by calling myLogger.debug() method.

Similar to debug there are methods to indicate log statement at different levels, same as that of log4j.


<?xml version="1.0"?>
<!-- logging/ButtonLifeCycle.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete='initLogging()'>
<mx:Script><![CDATA[
import mx.controls.Alert;
import mx.logging.ILogger;
import mx.logging.Log;
import mx.logging.LogEventLevel;
import mx.logging.targets.TraceTarget;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;

private var myLogger:ILogger;
private function initLogging():void {
var logTarget:TraceTarget = new TraceTarget();
logTarget.filters=["MyCustomClass"];
logTarget.level = LogEventLevel.ALL;
Log.addTarget(logTarget);
myLogger = Log.getLogger("MyCustomClass");
}


private function traceClick():void {
myLogger.debug("Entering traceClick");
useHttpService("http://www.google.com");
myLogger.debug("Exiting traceClick");
}

private var service:HTTPService
public function useHttpService(url:String):void {
myLogger.debug("Entering useHttpService");
service = new HTTPService();
service.url = url;
service.resultFormat = HTTPService.RESULT_FORMAT_TEXT;
service.method = "GET";
service.addEventListener("result", httpResult);
service.addEventListener("fault", httpFault);
service.send(parameters);
myLogger.debug("Entering useHttpService");
}
public function httpResult(event:ResultEvent):void {
myLogger.debug("Entering httpResult");
var result:Object = event.result;
Alert.show(event.result.toString());
myLogger.debug("Entering httpResult");
}
public function httpFault(event:FaultEvent):void {
myLogger.debug("Entering httpFault");
var faultstring:String = event.fault.faultString;
Alert.show(faultstring + event.fault.faultDetail + event.fault.rootCause);
myLogger.debug("Entering httpFault");
}
]]></mx:Script>
<mx:Button id="b1" label="Click Me" click="traceClick()" />
</mx:Application>

Enabling log Flex applicationEnable log for HTTPService in Flex application

When i started with Flex development, i was trying to make HTTP call to the portlet and i was not able to get any response so i did add this code to my Flex program to enable the log so that i can see what was going on with the HTTPService.

In order to use the Logging you will have to Enable trace in the Flex program


<?xml version="1.0"?>
<!-- logging/ButtonLifeCycle.mxml -->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete='initLogging()' >
<mx:Script><![CDATA[
import mx.controls.Alert;
import mx.logging.ILogger;
import mx.logging.Log;
import mx.logging.LogEventLevel;
import mx.logging.targets.TraceTarget;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.http.HTTPService;

private function initLogging():void {
var logTarget:TraceTarget = new TraceTarget();
logTarget.filters=["mx.rpc.*","mx.messaging.*"];
logTarget.level = LogEventLevel.ALL;
Log.addTarget(logTarget);
}

private function traceClick():void {
useHttpService("http://www.google.com");
}

private var service:HTTPService
public function useHttpService(url:String):void {
service = new HTTPService();
service.url = url;
service.resultFormat = HTTPService.RESULT_FORMAT_TEXT;
service.method = "GET";
service.addEventListener("result", httpResult);
service.addEventListener("fault", httpFault);
service.send(parameters);
}
public function httpResult(event:ResultEvent):void {
var result:Object = event.result;
Alert.show(event.result.toString());
}
public function httpFault(event:FaultEvent):void {
var faultstring:String = event.fault.faultString;
Alert.show(faultstring + event.fault.faultDetail + event.fault.rootCause);
}
]]></mx:Script>
<mx:Button id="b1" label="Click Me" click="traceClick()" />
</mx:Application>


The log is disabled by default in Flex so first i had to create initLogging() function to enable trace and then call it from createComplete() so that the log for HTTPService gets enabled. After that i could see this log in flashlog.txt when i tried making call to www.google.com from Flex application

'7671B99A-ED63-A113-A196-E28CF5762B74' producer set destination to 'DefaultHTTP'.
'direct_http_channel' channel endpoint set to http:
'7671B99A-ED63-A113-A196-E28CF5762B74' producer sending message 'D672CE47-357B-884E-07D7-E28CF5D40D82'
'direct_http_channel' channel sending message:
(mx.messaging.messages::HTTPRequestMessage)#0
body = (Object)#1
clientId = (null)
contentType = "application/x-www-form-urlencoded"
destination = "DefaultHTTP"
headers = (Object)#2
httpHeaders = (Object)#3
messageId = "D672CE47-357B-884E-07D7-E28CF5D40D82"
method = "GET"
recordHeaders = false
timestamp = 0
timeToLive = 0
url = "http://www.google.com"
'7671B99A-ED63-A113-A196-E28CF5762B74' producer connected.
'7671B99A-ED63-A113-A196-E28CF5762B74' producer acknowledge of 'D672CE47-357B-884E-07D7-E28CF5D40D82'.
Decoding HTTPService response
Processing HTTPService response message:
(mx.messaging.messages::AcknowledgeMessage)#0
body = "<!doctype html><html onmousemove="google&&google.fade&&google.fade(event)"><head><meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>Google</title><script>window.google={kEI:"upR9S5bhE4_MowTPsPWXCg",kEXPI:"17259,21965,23394,23807",kCSI:{e:"17259,21965,23394,23807",ei:"upR9S5bhE4_MowTPsPWXCg",expi:"17259,21965,23394,23807"},pageState:"#",kHL:"en",time:function(){return(new Date).getTime()},log:function(b,d,c){var a=new Image,e=google,g=e.lc,f=e.li;a.onerror=(a.onload=(a.onabort=function(){delete g[f]}));g[f]=a;c=c||"/gen_204?atyp=i&ct="+b+"&cad="+d+"&zx="+google.time();a.src=c;e.li=f+1},lc:[],li:0,j:{en:1,l:function(){},e:function(){},b:location.hash&&location.hash!="#",pl:[],mc:0,sc:0.5},Toolbelt:{}};(function(){for(var d=0,c;c=["ad","bc","p","pa","zd","ac","pc","pah","ph","sa","xx","zc","zz"][d++];)(function(a){google.j[a]=function(){google.j.pl.push([a,arguments])}})(c)})();
window.google.sn="webhp";window.google.timers={load:{t:{start:(new Date).getTime()}}};try{window.google.pt=window.gtbExternal&&window.gtbExternal.pageT();}catch(u){}window.google.jsrt_kill=1;
"
clientId = "DirectHTTPChannel0"
correlationId = "D672CE47-357B-884E-07D7-E28CF5D40D82"
destination = ""
headers = (Object)#1
DSStatusCode = 200
messageId = "3CAC4096-54F6-BF7C-EEB9-E28CF855D638"
timestamp = 0
timeToLive = 0
Warning: Ignoring 'secure' attribute in policy file from http://ad.doubleclick.net/crossdomain.xml. The 'secure' attribute is only permitted in HTTPS and socket policy files. See http://www.adobe.com/go/strict_policy_files for details.
Warning: Ignoring 'secure' attribute in policy file from http://ad.doubleclick.net/crossdomain.xml. The 'secure' attribute is only permitted in HTTPS and socket policy files. See http://www.adobe.com/go/strict_policy_files for details.
Warning: Domain www.youtube.com does not specify a meta-policy. Applying default meta-policy 'master-only'. This configuration is deprecated. See http://www.adobe.com/go/strict_policy_files to fix this problem.
Warning: Domain i3.ytimg.com does not specify a meta-policy. Applying default meta-policy 'master-only'. This configuration is deprecated. See http://www.adobe.com/go/strict_policy_files to fix this problem.
Warning: Domain i4.ytimg.com does not specify a meta-policy. Applying default meta-policy 'master-only'. This configuration is deprecated. See http://www.adobe.com/go/strict_policy_files to fix this problem.
Warning: Domain i2.ytimg.com does not specify a meta-policy. Applying default meta-policy 'master-only'. This configuration is deprecated. See http://www.adobe.com/go/strict_policy_files to fix this problem.
Warning: Domain www.youtube.com does not specify a meta-policy. Applying default meta-policy 'master-only'. This configuration is deprecated. See http://www.adobe.com/go/strict_policy_files to fix this problem.
Warning: Domain video-stats.video.google.com does not explicitly specify a meta-policy, but Content-Type of policy file http://video-stats.video.google.com/crossdomain.xml is 'text/x-cross-domain-policy'. Applying meta-policy 'by-content-type'.
Warning: Domain www.youtube.com does not specify a meta-policy. Applying default meta-policy 'master-only'. This configuration is deprecated. See http://www.adobe.com/go/strict_policy_files to fix this problem.
Warning: Domain video-stats.video.google.com does not explicitly specify a meta-policy, but Content-Type of policy file http://video-stats.video.google.com/crossdomain.xml is 'text/x-cross-domain-policy'. Applying meta-policy 'by-content-type'.

Flashbug for Flex developer

FlashBug is a very nice and useful extension of FireBug, if your serious Flash Developer



It lets you look at the flashlog.txt, policylog.txt in the console and provides ability to cleanup the log

Please note that you will have to Enable trace in the Flex program before you can use Flashbug

Enable trace in the Flex program

By default the Tracing is disabled in the flex player but you can enable it by going to C:\Documents and Settings\sunpatil\mm.cfg file and modifying value of TraceOutputFileEnabled to 1 instead of 0. Then restart your browser and execute your flex program again.


#flashlog
# Beginning with the Flash Player 9 Update, Flash Player ignores the TraceOutputFileName property.
# On Macintosh OS X, you should use colons to separate directories in the TraceOutputFileName path rather than slashes.
TraceOutputFileName=C:\Documents and Settings\<username>\Application Data\Macromedia\Flash Player\Logs\flashlog.txt # Set TraceOutputFileName to override the default name and location of the log file

ErrorReportingEnable=1 # Enables the logging of error messages. 0/1
TraceOutputFileEnable=1 # Enables trace logging. 0/1
MaxWarnings=100 # Sets the number of warnings to log before stopping.

#policyfiles
PolicyFileLog=1 # Enables policy file logging
PolicyFileLogAppend=1 # Optional; do not clear log at startup


Now open the C:\Documents and Settings\<username>\Application Data\Macromedia\Flash Player\Logs\flashlog.txt file in text editor and you should see the trace generated by your flex program. Other option is to use FlashBug which is a plugin in firebug