目次


Java プログラミングで XML サービス定義を操作する

SOA の要求を満足する軽量の Java クライアントを作成する

SOA は一連のサービスを提供しますが、その一部はユーザーが利用し、その他の部分は機械が利用します。後者は実際には他のサービスであることが多く、そのため SOA は一種の再帰構造を持っています。この記事では、ISP (Internet service provider: インターネット・サービス・プロバイダー) で使われるサービスを簡単に定義する方法について説明します。このタイプのプロバイダーを使う理由は、大部分の人にとって ISP はおなじみだからです。しかし、ここで説明する概念は通信プロバイダーのみに限定されるわけではなく、あらゆる種類のサービス・プロバイダー、つまり銀行や証券仲介業、公共サービスを提供する会社などにも適用することができます。

この記事では、自社のインフラのすべて、あるいは一部を SOA で実装した ISP を考えることにします。このプロバイダーがエクスポートするサービスの 1 つが、ユーザーが自分たちのサービス・プロファイルの変更に使用できる、Web ベースの機能です。

なぜ、この記事を読む必要があるのか

この記事の執筆時点では、SOA はなおも進化を続けており、主要なソフトウェア・ベンダーの多くは SOA に対応したソリューションを開発している最中です。そのため、SOA の分野は現在、JBI (Java Business Integration) やインテリジェント・ビジネス処理 (Intelligent Event Processing)、BPEL (Business Process Execution Language) サーバーなどのさまざまな技術が複雑に混ざり合った状態にあり、SOA のメリットを活用しようとするユーザー組織が 1 つのソリューションに収束するまでに大きな投資を強いられることは十分あり得るのです。SOA によって約束されるものの 1 つが、標準に基づいた、特定ベンダーに依存しない、コンポーネント指向のコンピューティングですが、SOA をそのように複雑にしてしまうことによって、業界は誤ってベンダー・ロックインの方向に進んでしまうかもしれません。コストの高い (SOA への) マイグレーション・プロセスに入る前に、ユーザー組織が実動の SOA を使った有益な経験をすることは可能なのでしょうか。

その質問に答えるために、この記事では SOA の重要な原則のいくつかを、単純な XML といくつかの Java コードで示します。この記事は SOA の世界のすべてを網羅するのではなく、鍵となるいくつかの領域に説明を絞ります。例えば、XML のサービス定義はおそらく RSS を使って配布されると思われますが、この記事の例では配布を行う際に Java の機能を利用します。

このように焦点を絞ることによるメリットは、ユーザー組織の Java 開発者が、この考え方を利用して独自の簡単なパイロット SOA を構築できることです。そうしたパイロット・スキームを利用することによって、組織は SOA によるビジネス上のメリットを認識することができます。そのメリットとしては、ビジネス・サービスを、計算サービスやユーザーによるセルフサービス、非常に自動化されたサービス、そして応答性の高いサービスとしてモデル化できることが挙げられます。SOA へのマイグレーションは、既存のビジネス・プロセスと並行して動作するスタンドアロンのパイロット・スキームとして表された SOA へのマイグレーションと同じように実行することができます。

SOA のパイロット・スキームは、ユーザー組織が大きな投資を行わなくても実現することができます。この方法によって、SOA に対する組織特有の要求を、ベンダーによる実装と分離して記述することができます。もちろん、小さなユーザー組織であれば、SOA のパイロット・スキームを継続し、後からソフトウェア・ベンダーによる大規模な商用グレードのソリューションに移行することができます。

セルフサービスへの傾向

大部分のサービス・プロバイダーでは (特に予算の限られた ISP の場合は)、セルフサービスの機能が増え続ける傾向にあります。そのため、(ダウンロードを実行したりオンライン・ゲームをプレイしたりするために) より大きな帯域幅が必要な場合には、プロバイダーの Web サイトにログオンし、Web ページを使ってそのプロバイダーへの接続を自動的にアップグレードします。具体的な例を見てみましょう。リスト 1 は、XML ベースの単純なユーザー・サービス・プロファイルを示しています。

リスト 1. XML ベースの単純なサービスの記述n
<ServiceInstance>
<Customer>Josephine Bloggs</Customer>
<Package>Internet</Package>
<Bandwidth>1mbps</Bandwidth>
<DownloadLimit>1Gbyte</DownloadLimit>
<Uptime>95</Uptime>
</ServiceInstance>

このコードはユーザーの XML サービス・モデルを示しています。このモデルには下記が含まれています。

  • サービス・インスタンス
  • 顧客の名前
  • サービス・パッケージの名前
  • 割り当てられる帯域幅の大きさ
  • 1 カ月間に許容されるダウンロード量
  • プロバイダーによるアップタイムの保証

当然のことですが、サービスの定義はここに挙げたものよりも、もっと複雑にすることができます。この他にも詳細な定義としては、顧客の住所、請求明細、往復遅延時間、暗号化、提供されるサービスの詳細などがあります。重要なことは、リスト 1 のような詳細に Web からアクセスできるようにするプロバイダーが増えているということです。その理由の一部には、コストとサポート・コールの回数を減らそうとしているということがあります。興味深いことに、そうした Web ベースのサービスによって、最先端を行くプロバイダーであるという印象を与えることができます。これは双方にとって好都合です。顧客は自分たちのサービス・データに非常にアクセスしやすくなり、一方プロバイダーは手間のかからないパッケージを販売できるからです。許可されたユーザーは、リスト 1 に示すサービス・パラメーターの一部 (例えば割り当てられた帯域幅など) を変更することができます。すると、そのユーザーの月額利用料は、その変更に応じて変更 (増額あるいは減額) されます。

つまりリスト 1 のコードは、XML ベースのサービス・モデルの基本です。ユーザーは単純にオンライン・フォームとやり取りし、書き込み可能なサービス要素 (例えば帯域幅) を変更します。オンライン・フォームを通して行われた変更は記録され、ユーザーのプロファイルによって影響されるバックエンドのサービスに反映されます。これは、セルフサービスを実装するための非常に標準的な方法です。

しかしここでは、別の、もっと疎結合のセルフサービスの可能性について学びます。このセルフサービスでは、ユーザーはリスト 1 の XML コンテンツをネットワークで転送することでデータを変更することができます。このシナリオで転送される XML データは、デスクトップ・コンピューターやノートブック・コンピューター、さらにはリソースの制限された携帯電話などの機器で実行する Java クライアントによってローカルで変更され、そしてネットワーク・サービス・プロバイダーに返送されます。こうした機構は基本的な HTML のページ・モデルを超えており、SOA の考え方が必要になります。

サービスを定義する XML 文書を Java 技術を使ってクライアントに転送する

Java 技術は XML データを操作するための非常に強力なツールをいくつか提供しています (囲み記事「Java 技術と XML」を参照)。指定されたデータ・セットを XML ベースで表現したものとしてリスト 1を考えると、他の方法でこれを表現することができます。リスト 1 の基礎となっている生データは、通常はデータベースに保存されます。では、そのデータを XML としてパッケージするためにはどうすればよいのでしょう。

リスト 2 は、この記事で提供する Java ファイルの 1 つ、encodeXML.java というファイルからの抜粋です。(このファイルや関連のファイルは「ダウンロード」セクションからダウンロードすることができます。) encodeXML.java クラスは XMLEncoder クラスのオブジェクトをインスタンス化します。見るとわかるように、このオブジェクトは次に、xmldata.xml というファイルをカレント・ディレクトリーに作成します。次のステップは、このファイルに XML のデータ値を挿入することです。そのためには writeObject() メソッドを繰り返し呼び出します (これもリスト 2 に示されています)。当然ですが、実動環境では、リスト 2 のハードコーディングされたテキスト・ストリングには、データベースなどの永続ストアの中にあるものを利用します。いずれにせよ、この方法で XML データ・ファイルを容易に作成できることがわかるはずです。

リスト 2. XML フォーマットでのデータのエンコーディング
XMLEncoder e = new XMLEncoder(
new BufferedOutputStream(
new FileOutputStream("xmldata.xml")));
e.writeObject("Josephine Bloggs");
e.writeObject("Internet");
e.writeObject("1mbps");
e.writeObject("Gbyte");
e.writeObject("295");
e.close();

リスト 2 のプログラムを実行すると、このプログラムの実行ディレクトリーに xmldata.xml というファイルが現れます。リスト 3 は、この新たに作成されるファイルの内容を示しています。

リスト 3. 生成される XML データ
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.5.0_06" class="java.beans.XMLDecoder">
<string>Josephine Bloggs</string>
<string>Internet</string>
<string>1mbps</string> 
<string>Gbyte</string> 
<string>295</string>
</java>

今度はリスト 3 のファイルを、待機しているクライアントにネットワークを介して転送します。これは Java 技術を使えば簡単です。リスト 4 は単純な例を示しています。

リスト 4. ネットワークでファイルを転送する
byte[] bytes = new byte[BUFFER_SIZE];
FileInputStream inputFile = null;
try
{
File file = new File("xmldata.xml");
if (file.exists())
{
inputFile = new FileInputStream(file);
int ch = inputFile.read(bytes, 0, BUFFER_SIZE);
while (ch != -1)
{
output.write(bytes, 0, ch);
ch = inputFile.read(bytes, 0, BUFFER_SIZE);
}
}

リスト 4 のコードは、長さが BUFFER_SIZE のバッファーを作成します。定数 BUFFER_SIZE の値は 1024 以上です。入力ファイル (xmldata.xml) の内容は、inputFile.read() メソッドを呼び出すとバッファーに読み込まれます。ファイルのデータはバッファーされると、output.write() メソッドによって OutputStream オブジェクトのソケットに書き込まれます。この最後のステップによって、待機しているクライアントにネットワークを介してデータが送信されます。これほどわずかのコードに、これほどの力を秘めているのです。

次に、受信される XML データを処理するクライアントを作成する必要があります。

受信 Java クライアントが (XML ファイルではなく) XML コンテンツを取得する

クライアントはどのように XML データを受信するのでしょう。この場合も、Java 技術を使えば簡単です。データはソケット・オブジェクトを通して受信されます。リスト 5 に示すコードは、受信データを受け取り、そのデータを ArrayList クラスのオブジェクトに渡します。

ここでクライアントは、受信されるデータ項目の数に関連する 2 つの重要な問題を解決しなければなりません。これは疎結合のシナリオなので、クライアントはサービス・プロファイル (つまりリスト 1 のコード) の中に XML のデータ項目がいくつあるかを知らない、と考える必要があります。そのため、正確な数のデータ項目を受信し、処理するための何らかの方法を見つけなければなりません。そして次の問題 (最初の問題ほど難しくありません) は、処理されたデータを保存するための方法です。リスト 5 は、見るとわかるように、この両方の問題を解決します。

リスト 5. 埋め込まれた XML データを抽出する
XMLDecoder d = new XMLDecoder(input);
try
{
while (true)
ArrayList<Object[]> rowList = new ArrayList<Object[]>();
{
String dataItem = (String)d.readObject();
System.out.println("XML decoded data: " + dataItem);
rowList.add(dataItem);
}
}
}
catch (Exception exc)
{
if (exc instanceof ArrayIndexOutOfBoundsException)
{
// No more records to process
System.out.println("Parsed all XML records - " +
	"threw exception. Number of rows: " + rowList.size());
}
}

d.close();

受信されるはずのデータ項目の数を、無限ループ while (true) によって判断することができます。このコードは最後のデータ項目が受信されるまでループし、最後のデータ項目が受信された時点で例外 (ArrayIndexOutOfBoundsException) がスローされます。想定されるデータ項目の数をクライアントが既に知っている場合以外は、この例外機構を使う必要があります。

InputStream オブジェクトから取得される XML データは ArrayList クラスのオブジェクトに保存されます。このクラスは、こうしたアプリケーションには非常に便利です。ArrayList のオブジェクトを定義すると、このオブジェクトは、基礎となるリストのサイズと常に一致する特定の容量を持ちます。要素が追加されると、この ArrayList オブジェクトの容量は自動的に拡張されます。そのため、配列の境界を越えてしまうことを心配する必要がありません。その処理は自動的に行われるのです。

この時点で、クライアントはリスト 1 のデータのコピーを持っています。クライアントは今や帯域幅要素を、必要な値に変更することができます。次に、クライアントからサーバーへという、逆のファイル転送プロセスが行われます。XML ファイルをサーバーからクライアントに移動することで、クライアントは実質的にそのサービスを利用したことになります。更新されたデータはサーバーに返送され、トランザクションが完了します。もちろん、その時にはサービス・プロバイダーは受信されるデータを検証する必要があり、また必要な帯域幅の変更を行う必要があります。

ここで説明したスキームは、XML ファイルと、ネットワークを介したファイル転送で始まります。クライアントはストリームとしてファイル・データを受信し、それを構文解析してメモリー常駐のオブジェクトにします。次にクライアントはこの後者のオブジェクトに変更を加え、そして今度は手順を逆にし、そのオブジェクトをサーバーに返送します。

さらに進めたサービスの可能性として、XML データ・ファイルを変更せずにそのままサーバーからクライアントに転送するサービスも考えられます。この場合クライアントは、何らかの形式のファイル転送プロトコル (FTP など) を使って、そのファイルの完全なコピーを取得します。ファイル転送は標準的な技術なので詳細は省略しますが、クライアントはリスト 1 のサービス・プロファイル・データのファイルのコピーをダウンロードします。この時点で、クライアントはこのファイルを構文解析して変更し、サーバーに返送する必要があります。このスキームはどのように動作するのでしょう。

XML ファイル・ベースの Java 機構はいかがでしょう

クライアントは今や、サービス・プロファイルのディスク・コピーを持っています。このファイルを構文解析して XML データを抽出しなければなりません。驚いたことに、この作業は、(特にファイルが大きい場合には) 少し難しいのです。重要なことは、適切な構文解析ツールを使うということです。ここでは dom4j を使用します。dom4j を利用すると、XML データを構文解析して Java オブジェクトにすることができます。dom4j の代わりに SAX (Simple API for XML) ベースのパーサーを使うこともできますが、SAX は下位レベルの技術です。ここから先の説明でわかるように、dom4j ツールは、ほとんど手間をかけずに使うことができます。リスト 6 は、この記事で提供されているファイル ProcessEventXml.java の抜粋ですが、dom4j を使ってファイルを構文解析するために必要な主な要素を示しています。

リスト 6. dom4j で XML データを処理する
try
{
handler.treeWalk(handler.parse(new File(argv[0])));
}
catch (Throwable t)
{
t.printStackTrace();
}
}

public Document parse(File url)
throws DocumentException
{
SAXReader reader = new SAXReader();
Document document = reader.read(url);
return document;
}

public void treeWalk(Document document)
throws Exception
{
treeWalk(document.getRootElement());
}

基本的に、parse()treeWalk() という 2 つのメソッドが必要です。このクラスをコンパイルしたものを実行すると、リスト 7 に示す出力が得られます。このコードを皆さん自身で実行しようとする場合には、必ず dom4j のコピーをダウンロードしてインストールし、そしてクラスパスに追加してください。(後者のステップは、単純に適切な JAR ファイルを CLASSPATH 変数に追加するだけです。) 次に、ProcessEventXml.java ファイルをコンパイルし、次のコマンドを使ってこのプログラムを実行します。

java ProcessEventXml ServiceDefinition.xml
リスト 7. dom4j を使って XML ファイルを処理する
java ProcessEventXml ServiceDefinition.xml
Josephine Bloggs Internet 1mbps 1Gbyte 95

これを見るとわかるように、ほとんど手間をかけずに XML データが整然と表示されています。面倒な作業は dom4j によって処理されています。実際は、作業の大部分は treeWalk() メソッドの中で行われます (このメソッドは、ファイルの最後に達するまで呼び出されない再帰メソッドです)。ここでは dom4j の機能の 1 つである、メモリー内処理を見ることができます。ただしこの方法を、非常に大きな XML ファイルに対して使うことは (特に Java 機器が小さい場合には) 不適切な場合があることに注意してください。しかし、この記事の例では XML データ・セットは小さいため、何も問題はないはずです。

これで、ファイル・ベースのクライアントは正常に XML データにアクセスできるようになりました。クライアントは必要に応じてデータを変更することができ、また新しい XML ファイルを作成することができます。そして、作成された XML ファイルをサーバーに返送して処理させることができます。先ほどと同じく、クライアントはサービスを利用しています。

まとめ

Java 技術は、SOA の設計や実装の問題に対してカスタムのソリューションを提供することができます。単純な、XML ファイル・ベースのサービス・プロファイルを使うことによって、クライアントのデータをネットワーク上で容易に移動させることができます。クライアントはこのデータを表示して変更することができ、そしてそのデータを使ってサービスを更新することができます。この記事で取り上げたサービスは ISP のサービスですが、どのようなプロバイダーも、この方法を使うことができます。

そうした、クライアント・サービスによるアクセスの重要な要素がワークフローです。SOA に対応した商用のソリューションは、BPEL を使ってこのワークフローを提供する傾向があります。SOA のパイロット・スキームでは、例えば JMS (Java Message Service) の API (application program interface) など、単純なメッセージング・スキームを使うことができます。この記事の導入部で触れたように、この方法のメリットは、商用の SOA ソリューションへのマイグレーションに必要な大きな投資を行う前に、実動の SOA を組織が経験できることです。

ワークフローのサポートの他に、この記事では考慮しなかった、もう 1 つの重要な問題がセキュリティーです。もしクライアント・ユーザーが彼らのサービス・プロファイルを変更するのであれば、その基礎となるデータを保護することが重要です。この場合にも、Java 技術はさまざまなオプションを提供することができます。

また、XML のサービス・プロファイル・データをファイルとして表現する、もっと粒度の大きい方法を採用することもできます。この場合、クライアントは何らかのスキームを使ってこれらのファイルをローカルのストレージに転送します。このファイルのデータは、dom4j を使って構文解析し、変更することができます。ここでも、Java 技術は単純さと強力さを併せ持つツールを提供します。これらの方法を使うことによって、どのような規模や機能を持つ Java クライアントも、SOA の実装に完全に参加することができます。


ダウンロード可能なリソース


関連トピック

  • XML-RPC で C++ アプリケーションを Web サービス対応可能にする」(Karthik Subbian と Ramakrishnan Kannan の共著、developerWorks、2006年6月) を読んでください。C++ のメソッドをサービスとして公開するための手順を、順を追って解説しています。
  • 無料の百科事典 Wikipedia が Web フィード・フォーマット、RSS を紹介しています。
  • XML および関連技術において IBM 認証開発者になる方法については、IBM XML certification を参照してください。
  • XML と XPath、そして XSLT を Java プラットフォームで処理でき、また DOM と SAX、そして JAXP を完全にサポートするオープン・ソースのライブラリー・ツール、 dom4j をダウンロードしてください。
static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Java technology, SOA and web services
ArticleID=260623
ArticleTitle=Java プログラミングで XML サービス定義を操作する
publish-date=09112007