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.

No comments: