中級
LiveCycle ESには、プログラミング的な手法でFlexのグラフコントロール(ColumnChartコントロールなど)にデータを挿入し、プロセスデータを視覚的に提示する方法が用意されています。LiveCycle ESプロセスはデータソースからデータを取得し、これをXMLデータとしてFlexベースのクライアントアプリケーションに返すことができます。クライアントアプリケーションでは、次の図に示すColumnChartコントロールなどのコントロール要素を用いて、データを表示することができます(図1参照)。
ここではクライアントアプリケーションによって、LiveCycle ESプロセスへのリクエストが発信される点に注目してください。このプロセスはリレーショナルデータベースからデータを抽出し、これをXMLドキュメントとともにクライアントアプリケーションへと返します。クライアントアプリケーションは構文解析を行った後、ColumnChartコントロール内に当該データを表示します。仮に、あるIT部署において、担当者別に案件の処理数を集計するようなクライアントアプリケーションがあったとします。この場合、次の図に示すように、ColumnChartコントロールには担当者別の案件処理数が示されます(図2参照)。
この記事では、MySQLデータソースのemployeeDataがデータソースとして用いられていると想定して、解説を進めることにします。このデータソースには、employeeTotalsという名のテーブルがあり、担当者ごとの案件処理数(closedCasesの列)が記録されています。employeeTotalsテーブル内のデータは、以下のとおりです。
| emp_id |
emp_name |
closedCases |
|---|---|---|
1 |
Tony Blue |
20 |
2 |
Alex Pink |
20 |
3 |
Steve White |
25 |
4 |
Karen Black |
35 |
closedCasesフィールドのデータは、前出の棒グラフの値と一致している点に注目してください。例えば、Karen Blackの案件処理数は棒グラフ上でも35を示しています。次のXMLは、LiveCycle ESプロセスからFlexベースのクライアントアプリケーションに送信されるデータの例を示したものです。
<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>
メモ:プロセスの作成方法について詳しくは、LiveCycle Workbench ESヘルプを参照してください。
GetFlexDataプロセスで行われる処理・操作は、以下のとおりです。
| 処理・操作 | 解説 |
|---|---|
1 |
メモ:この記事で紹介するFlexクライアントアプリケーションは、プロセス変数の |
2 |
メモ:この記事ではカスタムコンポーネントを作成するアプリケーションロジックを紹介しています。読者の方々は、コンポーネントの作成方法に精通していることが推奨されます。(詳しくは、LiveCycle ESでのプログラミングの「はじめてのコンポーネント作成」を参照してください。) |
ではこの記事をフォローするために、ここでemployeeDataという名のMySQLデータベースとemployeeTotalsという名のテーブルを作成してください。employeeTotalsテーブルには前出の表に示したレコードを配置します。employeeTotalsテーブルのフィールド名としては、emp_id、emp_nameおよびclosedCasesを使用するようにします。なお、MySQLデータベースはLiveCycle ESと同じホストにデプロイされたものを使用するようにしてください。(詳しくは、Getting Started with MySQL*を参照してください。)
メモ:ここではLiveCycle ESの標準コンポーネントが利用できるため、カスタムのコントロールを作成しなければならないわけではありません。カスタムコントロールは、いったんデータベースにクエリーをかけ、その後、Flexベースのクライアントアプリケーションに渡すXMLデータを作成するために用いられます。カスタムコンポーネントの作成方法について詳しくは、
LiveCycle ESプロセスのデータを利用して、Flexベースのクライアントアプリケーション上のcolumnChartコントロールにデータを供給するには、以下の手順に従います。
GetEmployeeDataという名の操作・処理が含まれた、カスタムコンポーネントを作成します。この操作によって、MySQLデータソースからデータが抽出されるとともに、XMLデータがダイナミックに生成され、データベースから抽出されたデータがXMLデータ内に配置されます。GetFlexDataという名のLiveCycle ESプロセスを作成します。GetFlexDataプロセスを呼び出します。このXMLデータはColumnChartコントロールの表示に用いられます。ここでは、MySQLデータベースにクエリーをかけ、そのクエリー結果を含むXMLデータを生成するカスタムコンポーネントを作成します。まず、EclipseでJavaプロジェクトを作成します。サポート対象のEclipseは、3.2.1以降のバージョンです。他のJavaプロジェクト同様、Javaのビジネスロジックが依存するJARファイルをプロジェクトのクラスパスに追加します。Eclipseプロジェクトを作成し、名前をDatabaseComponentに設定します。プロジェクトのクラスパスに、mysql-connector-java-3.1.14-bin.jarファイルを追加します。
データベースコンポーネントのアプリケーションロジックを作成するには、以下の手順に従います。
つまるところ、サービス実装はPOJO(Plain Old Java Object)で行います。このPOJOは、当該サービスの処理操作(パブリックメソッド)、入力値、戻り値を定義したJavaインターフェイスを作成することで開発できます。このJavaインターフェイス内で定義されたパブリックメソッドが、サービスによって公開される処理操作になります。
この節で開発するデータベースコンポーネントは、GetEmployeeDataという処理操作を公開します。この処理操作はorg.w3c.dom.Document型のオブジェクトを返します。次のコードサンプルは、データベースコンポーネントに属するインターフェイスを示したものです。このインターフェイスはcom.adobe.flexdata.DatabaseComponentパッケージ内に配置されている点に注目してください。
サンプル:DatabaseComponentインターフェイスの定義
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();
}
ここでは、DatabaseComponentインターフェイスを実装するためのサービス実装クラスを作成します。このサービス実装は以下の制約を満たす必要があります。
当該処理の呼び出し時に実行されるビジネスロジックは、それぞれ適切なメソッド内に定義されている必要があります。例えば、GetEmployeeDataメソッドであれば、データベースにクエリーをかけ、そして、その結果を含むXMLデータを作成するJavaアプリケーションロジックが含まれている必要があります。
サンプル:DatabaseComponentImplクラスの定義
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;
}
}
ここでは、LiveCycle ESにコンポーネントをデプロイするためのコンポーネントXMLファイルを作成します。コンポーネントXMLファイルはコンポーネントごとに存在し、各コンポーネントについてのメタデータを提供します。コンポーネントXMLファイルを利用すれば、各自の要件に合うようにコンポーネントをカスタマイズすることもできます。例えば、プロセスを開発するWorkbench ESユーザーが所定のコンポーネントを見つけやすくするために、特定のアイコンを指定しておくといったことが可能です。コンポーネントXMLファイルのスキーマについて詳しくは、LiveCycle ESでのプログラミングの「コンポーネントXML要素」を参照してください。
サンプル:データベースコンポーネント用のコンポーネントXMLファイルの定義
<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>
ここでは、コンポーネントをLiveCycle ESにデプロイし、プロセスの開発時にWorkbench ESから使用できるようにします。LiveCycle ESにコンポーネントをデプロイするには、まずEclipseプロジェクトをJARファイルにパッケージ化します。この際、JARファイルには必ずmysql-connector-java-3.1.14-bin.jarファイルを含めるようにします。component.xmlファイルおよび外部JARファイルは、JARファイルのルートに配置しておく必要があります。
ここでは、開発したコンポーネント内のJavaアプリケーションロジックの実行に必要なJARファイルだけを含めることが推奨されます。com.adobe.idp.Documentオブジェクトを使用するためには、adobe-livecycle-client.jarファイルがプロジェクトのクラスパスに含まれている必要がありますが、このファイルをJARファイルに含める必要はありません。このタイプはLiveCycle ESサービスコンテナーの一部にあたります。
メモ:データベースコンポーネントはadobe-dbSample-dsc.jarという名のJARファイルにパッケージ化するようにします。いったんデータベースコンポーネントをJARファイルにパッケージ化すると、当該CLASSファイルはコンポーネントJARファイルの一部にもなります。このCLASSファイルなしには、当該コンポーネントは機能しません。
データベースコンポーネントのデプロイ方法
メモ:データベースコンポーネントのデプロイは、LiveCycle ES APIを利用してプログラミング的に行うことも可能です。(詳しくは、LiveCycle ESでのプログラミングの「プログラミング的手法を用いたコンポーネントのデプロイ」を参照してください。)
ここではXMLデータを返すカスタムコンポーネントを使用する、GetFlexDataという名のLiveCycle ESプロセスを作成します。このプロセスは短命のプロセス、つまりLiveCycle ESがプロセスのインスタンス記録を作成しないものであっても構いません。短命のプロセスの場合、たとえFlexクライアントアプリケーションが当該プロセスを呼び出しても、記録が作成されません。プロセスが作成できたら、忘れずにこれを有効化するようにします。プロセスの作成方法および有効化方法について詳しくは、
メモ:GetFlexDataプロセスの解説は、本記事の冒頭に記載されています。(
次に、GetFlexDataプロセスを呼び出し、データをColumnChartコントロールに表示するためのFlexベースのクライアントアプリケーションを作成します。GetFlexDataプロセスの呼び出しには、LiveCycle Remotingを使用します。詳しくは、LiveCycle ESでのプログラミングの「LiveCycle Remotingを用いたLiveCycle ESの呼び出し」を参照してください。
GetFlexDataプロセスは、以下の手順で呼び出すことができます。
[インストールディレクトリー]\Adobe\LiveCycle8.2\LiveCycle_ES_SDK\misc\DataServices\Client-Libraries
[インストールディレクトリー]は、LiveCycle ESがインストールされているディレクトリーのことです。
mx:RemoteObjectインスタンスを作成します。このmx:RemoteObjectインスタンスからは、必ずGetFlexDataプロセスを参照するようにしておきます。<mx:RemoteObject id="GetEmpData" destination="GetFlexData" result="resultHandler(event);">
<mx:method name="invoke" result="handleEmployeeReturn(event)"/>
</mx:RemoteObject>
ChannelSetインスタンスを作成し、これをmx:RemoteObjectインスタンスに関連付けます。var cs:ChannelSet= new ChannelSet();
cs.addChannel(new AMFChannel("remoting-amf", "http://" + serverPort + "/remoting/messagebroker/amf"));
GetEmpData.setCredentials("administrator", "password");
GetEmpData.channelSet = cs;
mx:RemoteObjectインスタンスの呼び出しメソッドをコールして、GetFlexDataプロセスを呼び出します。返り値がXMLオブジェクトに正しく配置されることを確認します。次のサンプルコードは、GetFlexDataプロセスを呼び出すActionScriptコードが含まれたMXMLファイルです。(myChartという名の)チャートコントロールのデータソースには、employeeTotalsという名が付いている点に注意してください。このデータソースはArrayCollectionの1インスタンスです。
サンプル:GetFlexDataプロセスを呼び出すActionScriptコードが含まれたMXMLファイル
<?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>
LiveCycle ESを呼び出すアプリケーションの作成方法について詳しくは、LiveCycle ESでのプログラミングを参照してください。