Created

2 March 2009

LiveCycle ES provides the means to programmatically populate a Flex graph control, such as a Column chart control, that lets you view a visual representation of process data. A LiveCycle ES process can retrieve data from a data source and return XML data to a Flex-based client application. The client application can display data in a control, such as a Column chart control, as shown in the following illustration (see Figure 1).

Notice that a client application makes a request to a LiveCycle ES process. The process retrieves data from a relational database and returns it within an XML document to the client application. The client application parses the data and displays it in a Column chart control. For example, assume that the client application tracks the number of cases that employees within an IT department fix and close. A Column chart control displays the number of cases that each employee closes, as shown in the following illustration (see Figure 2).

For the purposes of this development article, assume that a MySQL data source named employeeData is used. This data source contains a table named employeeTotals, which tracks the number of customer cases that an employee closes (tracked in a field named closedCases). The following table shows the data located within the employeeTotals table.

emp_id

emp_name

closedCases

1

Tony Blue

20

2

Alex Pink

20

3

Steve White

25

4

Karen Black

35

Notice that the closedCases field matches the data specified in the Column control shown in the previous illustration. For example, Karen Black has closed 35 cases, which is shown in the Column control. The following XML represents the data that is sent from the LiveCycle ES process to the Flex-based client application.

<root> <Record> <Name>Tony Blue</Name> <Count>20</Count> </Record> <Record> <Name>Alex Pink</Name> <Count>30</Count> </Record> <Record> <Name>Steve White</Name> <Count>25</Count> </Record> <Record> <Name>Karen Black</Name> <Count>35</Count> </Record> </root>

GetFlexData process

The following illustration (see Figure 3) shows the short-lived GetFlexData process that retrieves data from the employeeTotals table and returns XML data. (The previous XML data is an example of data returned by the process.)

Note: For information about creating processes, see LiveCycle Workbench ES Help.

The following table describes the operations in the GetFlexData process.

Operation Description

1

Represents the SetValue operation and creates an output process variable of type XML named outXMLData. This process variable is the output for the process.

Note: In the Flex client application that is referenced in this document, the outXMLData process variable is referenced.

2

Represents a custom component that contains an operation named GetEmployeeData. This operation queries the employeeTotals table to retrieve results of the closedCases field and then dynamically creates an XML data source. The database is queried using Java classes located in the java.sql.* package and the XML data source is created using Java classes in the org.w3c.dom.* package.

The GetEmployeeData operation populates the outXMLData process variable with XML data.

Note: Although this document shows the application logic that creates the custom component, it is recommended that you are familiar with creating components. (See "Creating Your First Component" in Programming with LiveCycle ES.)

To follow along with this development article, create both a MySQL database named employeeData and a table named employeeTotals. Populate the employeeTotals table with the four records shown in the previous table. Make sure that the field names of the employeeTotals table are: emp_id, emp_name, and closedCases. Use the MySQL database that is deployed on the same host as LiveCycle ES. (See Getting Started with MySQL.)

Note: It is not necessary to create a custom control as you can use components available with LiveCycle ES. A custom control is used to query the database and then create XML data that is passed to the Flex-based client application. For information about creating custom components, see "Creating Your First Component" in Programming with LiveCycle ES.

Summary of steps

To populate a Column chart control located in a Flex-based client application using LiveCycle ES process data, perform the following steps:

  1. Create a custom component that contains an operation named GetEmployeeData. This operation retrieves data from the MySQL data source, dynamically creates XML data, and places the data retrieved from the database within XML data.
  2. Create a LiveCycle ES process named GetFlexData that returns XML data created by the custom component.
  3. Create a Flex-based client application that contains a Column chart control. This application uses LiveCycle Remoting to invoke the GetFlexData process to retrieve XML data. The XML data is used to populate the Column chart control.

Creating a custom component that creates XML data

Create a custom component that queries the MySQL database and constructs XML data that contains the query results. The first step is to create an Eclipse Java project. The version of Eclipse that is supported is 3.2.1 or later. Like other Java projects, add JAR files that your Java business logic depends on to your project's class path. Create an Eclipse project and name it DatabaseComponent. Add the mysql-connector-java-3.1.14-bin.jar file to your project's class path.

To create application logic for your database component, perform the following tasks:

  1. Define the service interface.
  2. Define the service implementation.

Defining the service interface

A service implementation is essentially a Plain Old Java Object (POJO) that you can develop by creating a Java interface that defines the service's operations (public methods), input values, and return values. The public methods that are defined within the Java interface become operations that are exposed by the service.

The database component developed in this section exposes an operation named GetEmployeeData. This operation returns an object of type org.w3c.dom.Document. The following example shows the interface that belongs to the database component. Notice that this interface is located within the com.adobe.flexdata.DatabaseComponent package.

Example: Defining the DatabaseComponent interface

package com.adobe.flexdata.DatabaseComponent; import java.sql.*; import java.sql.DriverManager.*; import java.sql.*; import java.sql.DriverManager.*; public interface DatabaseComponent { public org.w3c.dom.Document GetEmployeeData(); }

Defining the service implementation

Create a service implementation class that implements the DatabaseComponent interface. A service implementation must conform to the following restrictions:

  • The implementation class must have a public no-argument constructor.
  • The service implementation class must be stateless.
  • Input parameters, output parameters, and exceptions must be serializable.

Business logic that is executed when an operation is invoked must be specified in the corresponding method. For example, the GetEmployeeData method must contain Java application logic that queries the database and creates XML data that contains the results.

Example: Defining the DatabaseComponentImpl class

package com.adobe.flexdata.DatabaseComponent; import java.sql.*; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Element; public class DatabaseComponentImpl implements DatabaseComponent { //This method builds an XML data source from //results queried from jdbc:mysql://localhost:3306/employeeData public org.w3c.dom.Document GetEmployeeData() { //Create an org.w3c.dom.Document object org.w3c.dom.Document document = null; //Create a String array that contains all employees String[] allEmployees = new String[5]; allEmployees[0]="Tony Blue"; allEmployees[1]="Alex Pink"; allEmployees[2]="Steve White"; allEmployees[3]="Karen Black"; try{ // Specify an URL to MySQL and // Create a connection to the database Class.forName("com.mysql.jdbc.Driver"); String url = "jdbc:mysql://localhost:3306/employeeData"; Connection con = DriverManager.getConnection(url,"root", "root"); // Get a statement object // This object is used to pass SQL statements to the database Statement st = con.createStatement(); String tonyTotals = GetEmpCount(st,allEmployees[0]); String alexTotals = GetEmpCount(st,allEmployees[1]); String steveTotals = GetEmpCount(st,allEmployees[2]); String karenTotals = GetEmpCount(st,allEmployees[3]); //Build the XML data //Create DocumentBuilderFactory and DocumentBuilder objects DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); //Create a new Document object document = builder.newDocument(); //Create the root element and append it to the XML DOM Element root = (Element)document.createElement("root"); document.appendChild(root); //Create a rec element Element rec = (Element)document.createElement("Record"); root.appendChild(rec); Element Name = (Element)document.createElement("Name"); Element Count = (Element)document.createElement("Count"); //Create section for Tony Blue's Totals Name.appendChild(document.createTextNode(allEmployees[0])); Count.appendChild(document.createTextNode(tonyTotals)); rec.appendChild(Name); rec.appendChild(Count); //Create section for Alex Pink's Totals Element rec1 = (Element)document.createElement("Record"); root.appendChild(rec1); Element Name2 = (Element)document.createElement("Name"); Element Count2 = (Element)document.createElement("Count"); Name2.appendChild(document.createTextNode(allEmployees[1])); Count2.appendChild(document.createTextNode(alexTotals)); rec1.appendChild(Name2); rec1.appendChild(Count2); //Create section for Steve White's Totals Element rec2 = (Element)document.createElement("Record"); root.appendChild(rec2); Element Name3 = (Element)document.createElement("Name"); Element Count3 = (Element)document.createElement("Count"); Name3.appendChild(document.createTextNode(allEmployees[2])); Count3.appendChild(document.createTextNode(steveTotals)); rec2.appendChild(Name3); rec2.appendChild(Count3); //Create section for Karen Black's Totals Element rec3 = (Element)document.createElement("Record"); root.appendChild(rec3); Element Name4 = (Element)document.createElement("Name"); Element Count4 = (Element)document.createElement("Count"); Name4.appendChild(document.createTextNode(allEmployees[3])); Count4.appendChild(document.createTextNode(karenTotals)); rec3.appendChild(Name4); rec3.appendChild(Count4); //Return the XML data that return document; } catch (Exception ee) { ee.printStackTrace(); } return null; } //Return the closedCases field value from the employeeTotals table private String GetEmpCount(java.sql.Statement st,String name) { String mt = ""; try{ //Get the single value from the closedCases field ResultSet rs = st.executeQuery("SELECT closedCases FROM employeeTotals where emp_name = '"+name+"'"); while(rs.next()) mt = rs.getString("closedCases"); } catch (Exception ee) { ee.printStackTrace(); } return mt; } }

Creating the component XML file for the database component

Create a component XML file to deploy a component to LiveCycle ES. A component XML file exists for each component and provides metadata about the component. You can use the component XML file to customize your component to meet your requirements. For example, you can specify an icon that is visible to Workbench ES users who build processes by using the component. For information about the schema of a component XML file, see "Component XML Elements" in Programming with LiveCycle ES.

Example: Defining the component XML file for the database component

<component xmlns="http://adobe.com/idp/dsc/component/document"> <!-- Unique id identifying this component --> <component-id>com.adobe.flexdata.DatabaseComponent</component-id> <!-- Version --> <version>1.0</version> <class-path>mysql-connector-java-3.1.14-bin.jar</class-path> <!-- Start of the Service definition --> <services> <!-- Unique name for service descriptor. The value is used as the default name for deployed services --> <service name="FlexDatabaseComponent"> <!-- service implementation class definition --> <implementation-class>com.adobe.flexdata.DatabaseComponent.DatabaseComponentImpl</implementation-class> <!-- automatically deploys the service and starts it after installation --> <auto-deploy service-id="FlexDatabaseComponent" /> <operations> <operation name="GetEmployeeData"> <output-parameter name="outXMLValue" title="outXMLValue" type="org.w3c.dom.Document"> </output-parameter> <faults> <fault name="Exception" type="java.lang.Exception"/> </faults> </operation> </operations> </service> </services> </component>

Deploying your component

Deploy the component to LiveCycle ES so that you can use it within Workbench ES to build processes. To deploy the component to LiveCycle ES, package your Eclipse project into a JAR file. Ensure that the mysql-connector-java-3.1.14-bin.jar file is included in the JAR file. The component.xml file and external JAR file must be located at the root of the JAR file.

It is recommended that you include only the JAR files that are required to execute the Java application logic located in your component. Although the adobe-livecycle-client.jar file must be in your project's class path to use a com.adobe.idp.Document object, it is not necessary to include this file in the JAR file. This type is part of the LiveCycle ES service container.

Note: Package the database component into a JAR file named adobe-dbSample-dsc.jar. After the database component is packaged into a JAR file, the corresponding CLASS files will also be part of the component JAR file. Without the CLASS files, the component does not work.

To deploy the database component:

  1. Start LiveCycle Workbench ES.
  2. Log in to Workbench ES.
  3. Select Window > Show Views > Components. This action adds the Components view to Workbench ES.
  4. Right-click the Components icon and select Install Component.
  5. Select the adobe-dbSample-dsc.jar file through the file browser and click Open.
  6. Select Service Descriptors, and then right-click DatabaseComponent and select Activate Service.
  7. Right-click DatabaseComponent and select Start Component. A green arrow appears next to the name if it succeeds. Notice that DatabaseComponent is automatically deployed and has a green arrow next to it if it succeeds.

Note: You can also deploy the database component programmatically by using the LiveCycle ES API. (See "Programmatically Deploying Components" in Programming with LiveCycle ES.

Creating a LiveCycle Process that uses the custom component

Create a LiveCycle ES process named GetFlexData that uses the custom component that returns XML data. The process can be a short-lived process, meaning that LiveCycle ES does not create a process instance record. That is, when a Flex client application invokes the process, a record is not created. After the process is created, ensure that you activate it. For information about creating and activating processes, see LiveCycle Workbench ES Help.

Note: The introduction section of this article describes the GetFlexData process. (See GetFlexData process.)

Creating a Flex-based client application

Create a Flex-based client application that invokes the GetFlexData process and display the data in a Column chart control. To invoke the GetFlexData process, use LiveCycle Remoting. For information, see "Invoking LiveCycle ES Using LiveCycle Remoting" in Programming with LiveCycle ES.

You can invoke the GetFlexData process by performing the following steps:

  1. Create a Flex-based project and add the adobe-remoting-provider.swc file to your class path. This SWC file is located in the following location:

    [install_directory]\Adobe\LiveCycle8.2\LiveCycle_ES_SDK\misc\DataServices\Client-Libraries

    where [install_directory] is the directory where LiveCycle ES is installed.

  2. Create a mx:RemoteObject instance through either ActionScript or MXML. Ensure that this mx:RemoteObject instance references the GetFlexData process:
<mx:RemoteObject id="GetEmpData" destination="GetFlexData" result="resultHandler(event);"> <mx:method name="invoke" result="handleEmployeeReturn(event)"/> </mx:RemoteObject>
  1. Create a ChannelSet instance to communicate with LiveCycle ES, and associate it with the mx:RemoteObject instance:
var cs:ChannelSet= new ChannelSet(); cs.addChannel(new AMFChannel("remoting-amf", "http://" + serverPort + "/remoting/messagebroker/amf")); GetEmpData.setCredentials("administrator", "password"); GetEmpData.channelSet = cs;
  1. Invoke the GetFlexData process by calling the mx:RemoteObject instance's invoke method. Ensure that the return value populates an XML object.

The following code example is a MXML file that contains Action Script code that invokes the GetFlexData process. Notice that the data source that populates the chart control (named myChart) is named employeeTotals. This data source is an ArrayCollection instance.

Example: A MXML file that contains Action Script code that invokes the GetFlexData process

<?xml version="1.0"?> <!-- Simple example to demonstrate the ColumnChart controls. --> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns="*" creationComplete="SetupColumnChart();"> <mx:Script><![CDATA[ import mx.formatters.NumberFormatter; import flash.net.FileReference; import flash.net.URLRequest; import flash.events.Event; import flash.events.DataEvent; import mx.messaging.ChannelSet; import mx.messaging.channels.AMFChannel; import mx.rpc.events.ResultEvent; import mx.collections.ArrayCollection; import mx.rpc.AsyncToken; [Bindable] public var employeeTotals:ArrayCollection = new ArrayCollection(); private function SetupColumnChart():void { var cs:ChannelSet= new ChannelSet(); cs.addChannel(new AMFChannel("remoting-amf", "http://localhost:8080/remoting/messagebroker/amf")); GetEmpData.setCredentials("administrator", "password"); GetEmpData.channelSet = cs; // Invoke the EncryptDocument process var token:AsyncToken; token = GetEmpData.invoke(); token.name = name; } public function handleEmployeeReturn(event:ResultEvent):void { // var token:AsyncToken = event.token; var res:Object = event.result; var myXML:XML = res["outXMLData"] as XML; //WE need to create application logic to retrieve the values from the //returned XML data var myList:XMLList = myXML.children(); var ee:String ="" ; var index:int = 0 ; var index2:int = 0; var employeeName:String =""; var countRecs:String = ""; for each (var element:XML in myList) { //trace(element.name()); index=index+1; //Drill down into the XML further var myList2:XMLList = element.children(); for each (var element:XML in myList2) { //THis is where the repeating elements are if (element.name() == "Name") { employeeName = element.toString(); } if (element.name() == "Count") { countRecs = element.toString(); var intNum:int = int(countRecs); //Populate the datasource employeeTotals.addItem({Employee: employeeName, Closed_Cases: intNum}); } } } } private function resultHandler(event:ResultEvent):void { // Do anything else here. } ]]> </mx:Script> <mx:RemoteObject id="GetEmpData" destination="GetFlexData" result="resultHandler(event);"> <mx:method name="invoke" result="handleEmployeeReturn(event)"/> </mx:RemoteObject> <mx:Panel title="Column Chart"> <mx:ColumnChart id="myChart" dataProvider="{employeeTotals}" showDataTips="true"> <mx:horizontalAxis> <mx:CategoryAxis dataProvider="{employeeTotals}" categoryField="Employee" /> </mx:horizontalAxis> <mx:series> <mx:ColumnSeries xField="Employee" yField="Closed_Cases" displayName="Closed Cases" /> </mx:series> </mx:ColumnChart> <mx:Legend dataProvider="{myChart}"/> </mx:Panel> </mx:Application>

Where to go from here

For more information about creating applications that invoke LiveCycle ES, see Programming with LiveCycle ES.