CrnpClient.java のコンテンツ
/*
* CrnpClient.java
* ================
*
* 解析についての注意:
*
* このプログラムは、Sun Java Architecture for XML Processing (JAXP) API を
* 使用しています。API ドキュメントや利用についての情報は、
* http://java.sun.com/xml/jaxp/index.html を参照してください。
*
* このプログラムは、Java 1.3.1 以降を対象に作成されています。
*
* プログラムの概要:
*
* このプログラムのメインスレッドは、CrnpClient オブジェクトを作成し、
* ユーザーがデモを終了するのを待機し、CrnpClient オブジェクトで
* shutdown を呼び出し、最後にプログラムを終了します。
*
* CrnpClient コンストラクタは、EventReceptionThread オブジェクトを作成し、
* (コマンド行で指定されたホストとポートを使用して) CRNP サーバーに対して
* 接続を開き、(コマンド行の指定にもとづいて) 登録メッセージを作成し、登録
* メッセージを送信し、応答の読み取りと解析を行います。
*
* EventReceptionThread は、このプログラムが動作するマシンのホスト名と
* コマンド行に指定されるポートにバインドされる待機ソケットを作成します。
* EventReceptionThread は、イベントコールバックの着信を待機し、受信した
* ソケットストリームから XML ドキュメントを構築し、これを CrnpClient
* オブジェクトに返して処理を行わせます。
*
* CrnpClient 内のshutdown メソッドは、単に登録解除用の
* (REMOVE_CLIENT) SC_CALLBACK_REG メッセージを crnp サーバーへ送信
* するだけです。
*
* エラー処理についての注意: 説明を簡潔にするため、このプログラムはほとんどの
* エラーに対して単に終了するだけですが、実際のアプリケーションではさまざまな
* 方法でエラー処理がなされます (適宜再試行するなど)。
*/
// JAXP パッケージ
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
import org.w3c.dom.*;
// 標準パッケージ
import java.net.*;
import java.io.*;
import java.util.*;
/*
* クラス CrnpClient
* -----------------
* 上記のファイルヘッダーコメントを参照。
*/
class CrnpClient
{
/*
* main
* ----
* 実行のエントリポイント main は、コマンド行引数の数を
* 検証し、すべての作業を行う CrnpClient インスタンスを
* 作成する。
*/
public static void main(String []args)
{
InetAddress regIp = null;
int regPort = 0, localPort = 0;
/* コマンド行引数の数を検証する */
if (args.length < 4) {
System.out.println(
"Usage: java CrnpClient crnpHost crnpPort "
+ "localPort (-ac | -ae | -re) "
+ "[(M | A | RG=name | R=name) [...]]");
System.exit(1);
}
/*
* コマンド行には crnp サーバーの IP とポート、
* 待機するローカルポート、登録タイプを示す
* 引数が入る。
*/
try {
regIp = InetAddress.getByName(args[0]);
regPort = (new Integer(args[1])).intValue();
localPort = (new Integer(args[2])).intValue();
} catch (UnknownHostException e) {
System.out.println(e);
System.exit(1);
}
// CrnpClient を作成する。
CrnpClient client = new CrnpClient(regIp, regPort, localPort,
args);
// ユーザーがプログラムを終了したくなるまで待機する。
System.out.println("Hit return to terminate demo...");
// ユーザーが何か入力するまで読み取りはブロックする。
try {
System.in.read();
} catch (IOException e) {
System.out.println(e.toString());
}
// クライアントを停止する。
client.shutdown();
System.exit(0);
}
/*
* ======================
* public メソッド
* ======================
*/
/*
* CrnpClient コンストラクタ
* -----------------------
* crnp サーバーとの通信方法を知るためにコマンド行引数を解析
* し、イベント受信スレッドを作成し、このスレッドの実行を開始
* し、XML DocumentBuilderFactory オブジェクトを作成し、
* 最後に crnp サーバーにコールバックの登録を行う。
*/
public CrnpClient(InetAddress regIpIn, int regPortIn, int localPortIn,
String []clArgs)
{
try {
regIp = regIpIn;
regPort = regPortIn;
localPort = localPortIn;
regs = clArgs;
/*
* xml 処理用のドキュメントビルダー
* ファクトリを設定する。
*/
setupXmlProcessing();
/*
* ServerSocket を作成してこれをローカル IP と
* ポートにバインドする EventReception を作成する。
*/
createEvtRecepThr();
/*
* crnp サーバーに登録する。
*/
registerCallbacks();
} catch (Exception e) {
System.out.println(e.toString());
System.exit(1);
}
}
/*
* processEvent
* ---------------
* CrnpClient (イベントコールバックを受信する際に
* EventReceptionThread によって使用される) にコールバックする。
*/
public void processEvent(Event event)
{
/*
* ここでは、説明の都合上、単純にイベントを System.out
* に出力。実際のアプリケーションでは、通常、イベント
* をなんらかの方法で使用する。
*/
event.print(System.out);
}
/*
* shutdown
* -------------
* CRNP サーバーに対する登録を解除する。
*/
public void shutdown()
{
try {
/* サーバーに登録解除メッセージを送信する */
unregister();
} catch (Exception e) {
System.out.println(e);
System.exit(1);
}
}
/*
* ======================
* private ヘルパーメソッド
* ======================
*/
/*
* setupXmlProcessing
* --------------------
* xml 応答と xml イベントを解析するためにドキュメント
* ビルダーファクトリを作成する。
*/
private void setupXmlProcessing() throws Exception
{
dbf = DocumentBuilderFactory.newInstance();
// わざわざ検証する必要はない。
dbf.setValidating(false);
dbf.setExpandEntityReferences(false);
// コメントと空白文字は無視したい。
dbf.setIgnoringComments(true);
dbf.setIgnoringElementContentWhitespace(true);
// CDATA セクションを TEXT ノードに結合する。
dbf.setCoalescing(true);
}
/*
* createEvtRecepThr
* -------------------
* 新しい EventReceptionThread オブジェクトを作成し、待機
* ソケットがバインドされる IP とポートを保存し、スレッドの
* 実行を開始する。
*/
private void createEvtRecepThr() throws Exception
{
/* スレッドオブジェクトを作成する */
evtThr = new EventReceptionThread(this);
/*
* イベント配信コールバックを待機し始めるために
* スレッドの実行を開始する。
*/
evtThr.start();
}
/*
* registerCallbacks
* ------------------
* crnp サーバーに対するソケット接続を作成し、
* イベント登録メッセージを送信する。
*/
private void registerCallbacks() throws Exception
{
System.out.println("About to register");
/*
* crnp サーバーの登録 IP / ポートに接続されたソケット
* を作成し、登録情報を送信する。
*/
Socket sock = new Socket(regIp, regPort);
String xmlStr = createRegistrationString();
PrintStream ps = new PrintStream(sock.getOutputStream());
ps.print(xmlStr);
/*
* 応答を読み取る。
*/
readRegistrationReply(sock.getInputStream());
/*
* ソケット接続を閉じる。
*/
sock.close();
}
/*
* unregister
* ----------
* registerCallbacks の場合と同様に、crnp サーバーに対する
* ソケット接続を作成し、登録解除メッセージを送信し、
* サーバーからの応答を待機し、ソケットを閉じる。
*/
private void unregister() throws Exception
{
System.out.println("About to unregister");
/*
* crnp サーバーの登録 IP / ポートに接続された
* ソケットを作成し、登録解除情報を送信する。
*/
Socket sock = new Socket(regIp, regPort);
String xmlStr = createUnregistrationString();
PrintStream ps = new PrintStream(sock.getOutputStream());
ps.print(xmlStr);
/*
* 応答を読み取る。
*/
readRegistrationReply(sock.getInputStream());
/*
* ソケット接続を閉じる。
*/
sock.close();
}
/*
* createRegistrationString
* ------------------
* このプログラムのコマンド行引数にもとづいて CallbackReg
* オブジェクトを作成し、CallbackReg オブジェクトから XML
* 文字列を取得する。
*/
private String createRegistrationString() throws Exception
{
/*
* 実際のCallbackReg クラスを作成し、ポートを設定する。
*/
CallbackReg cbReg = new CallbackReg();
cbReg.setPort("" + localPort);
// 登録タイプを設定する
if (regs[3].equals("-ac")) {
cbReg.setRegType(CallbackReg.ADD_CLIENT);
} else if (regs[3].equals("-ae")) {
cbReg.setRegType(CallbackReg.ADD_EVENTS);
} else if (regs[3].equals("-re")) {
cbReg.setRegType(CallbackReg.REMOVE_EVENTS);
} else {
System.out.println("Invalid reg type: " + regs[3]);
System.exit(1);
}
// イベントを追加する。
for (int i = 4; i < regs.length; i++) {
if (regs[i].equals("M")) {
cbReg.addRegEvent(createMembershipEvent());
} else if (regs[i].equals("A")) {
cbReg.addRegEvent(createAllEvent());
} else if (regs[i].substring(0,2).equals("RG")) {
cbReg.addRegEvent(createRgEvent(regs[i].substring(3)));
} else if (regs[i].substring(0,1).equals("R")) {
cbReg.addRegEvent(createREvent(regs[i].substring(2)));
}
}
String xmlStr = cbReg.convertToXml();
System.out.println(xmlStr);
return (xmlStr);
}
/*
* createAllEvent
* ----------------
* クラス EC_Cluster を使用して (サブクラスは使用しない)
* XML 登録イベントを作成する。
*/
private Event createAllEvent()
{
Event allEvent = new Event();
allEvent.setClass("EC_Cluster");
return (allEvent);
}
/*
* createMembershipEvent
* ----------------------
* クラス EC_Cluster、サブクラス ESC_cluster_memberhip を
* 使用して XML 登録イベントを作成する。
*/
private Event createMembershipEvent()
{
Event membershipEvent = new Event();
membershipEvent.setClass("EC_Cluster");
membershipEvent.setSubclass("ESC_cluster_membership");
return (membershipEvent);
}
/*
* createRgEvent
* ----------------
* クラス EC_Cluster、サブクラス ESC_cluster_rg_state、
* および "rg_name" nvpair (入力パラメタにもとづく) を
* 1 つ使用して XML 登録イベントを作成する。
*/
private Event createRgEvent(String rgname)
{
/*
* rgname リソースグループ用の
* リソースグループ状態変更イベントを作成する。
* このイベントタイプには、どのリソースグループに興味
* があるのかを示すため、名前 / 値ペア (nvpair) を指定
* する。
*/
/*
* イベントオブジェクトを作成し、クラスとサブクラスを設定する。
*/
Event rgStateEvent = new Event();
rgStateEvent.setClass("EC_Cluster");
rgStateEvent.setSubclass("ESC_cluster_rg_state");
/*
* nvpair オブジェクトを作成し、これをこのイベントに追加する。
*/
NVPair rgNvpair = new NVPair();
rgNvpair.setName("rg_name");
rgNvpair.setValue(rgname);
rgStateEvent.addNvpair(rgNvpair);
return (rgStateEvent);
}
/*
* createREvent
* ----------------
* クラス EC_Cluster、サブクラス ESC_cluster_rg_state、
* および "rg_name" nvpair (入力パラメタにもとづく) を
* 1 つ使用して XML 登録イベントを作成する。
*/
private Event createREvent(String rname)
{
/*
* rgname リソースグループ用の
* リソースグループ状態変更イベントを作成する。
* があるのかを示すため、名前 / 値ペア (nvpair) を指定
* する。
*/
Event rStateEvent = new Event();
rStateEvent.setClass("EC_Cluster");
rStateEvent.setSubclass("ESC_cluster_r_state");
NVPair rNvpair = new NVPair();
rNvpair.setName("r_name");
rNvpair.setValue(rname);
rStateEvent.addNvpair(rNvpair);
return (rStateEvent);
}
/*
* createUnregistrationString
* ------------------
* REMOVE_CLIENT CallbackReg オブジェクトを作成し、
* CallbackReg オブジェクトから XML 文字列を取得する。
*/
private String createUnregistrationString() throws Exception
{
/*
* CallbackReg オブジェクトを作成する。
*/
CallbackReg cbReg = new CallbackReg();
cbReg.setPort("" + localPort);
cbReg.setRegType(CallbackReg.REMOVE_CLIENT);
/*
* 登録を OutputStream に整列化する。
*/
String xmlStr = cbReg.convertToXml();
// デバッグのために文字列を出力する。
System.out.println(xmlStr);
return (xmlStr);
}
/*
* readRegistrationReply
* ------------------------
* xml を解析してドキュメントにし、このドキュメントから
* RegReply オブジェクトを構築し、RegReply オブジェクトを
* 出力する。実際のアプリケーションでは、通常、RegReply
* オブジェクトの status_code にもとづいて処理をする。
*/
private void readRegistrationReply(InputStream stream)
throws Exception
{
// ドキュメントビルダーを作成する。
DocumentBuilder db = dbf.newDocumentBuilder();
//
// 解析前に ErrorHandler を設定する。
// ここではデフォルトハンドラを使用。
//
db.setErrorHandler(new DefaultHandler());
// 入力ファイルを解析する。
Document doc = db.parse(stream);
RegReply reply = new RegReply(doc);
reply.print(System.out);
}
/* private 指定のメンバー変数 */
private InetAddress regIp;
private int regPort;
private EventReceptionThread evtThr;
private String regs[];
/* public 指定のメンバー変数 */
public int localPort;
public DocumentBuilderFactory dbf;
}
/*
* クラス EventReceptionThread
* ----------------------------
* 上記のファイルヘッダーコメントを参照。
*/
class EventReceptionThread extends Thread
{
/*
* EventReceptionThread コンストラクタ
* ----------------------------------
* ローカルホスト名とワイルドカードポートにバインドされる
* 新しい ServerSocket を作成する。
*/
public EventReceptionThread(CrnpClient clientIn) throws IOException
{
/*
* イベントの取得時に再度呼び返すことができるように、
* クライアントに対する参照を保持する。
*/
client = clientIn;
/*
* バインドする IP を指定する。これは、ローカル
* ホスト IP である。このマシンに複数のパブリック
* インタフェースが構成されている場合は、
* InetAddress.getLocalHost によって検出される
* ものをどれでも使用する。
*
*/
listeningSock = new ServerSocket(client.localPort, 50,
InetAddress.getLocalHost());
System.out.println(listeningSock);
}
/*
* run
* ---
* Thread.Start メソッドによって呼び出される。
*
* ServerSocket で着信接続を待機し、永続的にループする。
*
* 各着信接続が受け入れられる際に xml ストリームから
* Event オブジェクトが作成される。続いてこのオブジェクト
* が CrnpClient オブジェクトに返されて処理される。
*/
public void run()
{
/*
* Loop forever.
*/
try {
//
// CrnpClient 内のドキュメントビルダーファクトリを
// 使用してドキュメントビルダーを作成する。
//
DocumentBuilder db = client.dbf.newDocumentBuilder();
//
// 解析前に ErrorHandler を設定する。
// ここではデフォルトハンドラを使用。
//
db.setErrorHandler(new DefaultHandler());
while(true) {
/* サーバーからのコールバックを待機 */
Socket sock = listeningSock.accept();
// 入力ファイルを解析する。
Document doc = db.parse(sock.getInputStream());
Event event = new Event(doc);
client.processEvent(event);
/* ソケットを閉じる */
sock.close();
}
// 到達不能
} catch (Exception e) {
System.out.println(e);
System.exit(1);
}
}
/* private 指定のメンバー変数 */
private ServerSocket listeningSock;
private CrnpClient client;
}
/*
* クラス NVPair
* -----------
* このクラスは名前 / 値ペア (両方とも文字列) を格納する。
* このクラスは、そのメンバーから NVPAIR XML メッセージを構築し、
* NVPAIR XML 要素を解析してそのメンバーにすることができる。
*
* NVPAIR の形式仕様では複数の値が許可されているが、ここでは
* 単純に値は 1 つだけという前提を下す。
*/
class NVPair
{
/*
* 2 つのコンストラクタ: 最初のコンストラクタは空の NVPair を
* 作成する。2 つ目は NVPAIR XML 要素から NVPair を作成する。
*/
public NVPair()
{
name = value = null;
}
public NVPair(Element elem)
{
retrieveValues(elem);
}
/*
* Public 指定のセッター。
*/
public void setName(String nameIn)
{
name = nameIn;
}
public void setValue(String valueIn)
{
value = valueIn;
}
/*
* 1 行で名前と値を出力する。
*/
public void print(PrintStream out)
{
out.println("NAME=" + name + " VALUE=" + value);
}
/*
* createXmlElement
* ------------------
* メンバー変数から NVPAIR XML 要素を作成する。
* この要素を作成できるように、ドキュメントをパラメタとして
* 受け付ける。
*/
public Element createXmlElement(Document doc)
{
// 要素を作成する。
Element nvpair = (Element)
doc.createElement("NVPAIR");
//
// 名前を追加する。実際の名前は別の
// CDATA セクションであることに注意。
//
Element eName = doc.createElement("NAME");
Node nameData = doc.createCDATASection(name);
eName.appendChild(nameData);
nvpair.appendChild(eName);
//
// 値を追加する。実際の値は別の
// CDATA セクションであることに注意。
//
Element eValue = doc.createElement("VALUE");
Node valueData = doc.createCDATASection(value);
eValue.appendChild(valueData);
nvpair.appendChild(eValue);
return (nvpair);
}
/*
* retrieveValues
* ----------------
* XML 要素を解析して名前と値を取得する。
*/
private void retrieveValues(Element elem)
{
Node n;
NodeList nl;
//
// NAME 要素を検出する。
//
nl = elem.getElementsByTagName("NAME");
if (nl.getLength() != 1) {
System.out.println("Error in parsing: can't find "
+ "NAME node.");
return;
}
//
// TEXT セクションを取得する。
//
n = nl.item(0).getFirstChild();
if (n == null || n.getNodeType() != Node.TEXT_NODE) {
System.out.println("Error in parsing: can't find "
+ "TEXT section.");
return;
}
// 値を取得する。
name = n.getNodeValue();
//
// ここで値要素を取得する。
//
nl = elem.getElementsByTagName("VALUE");
if (nl.getLength() != 1) {
System.out.println("Error in parsing: can't find "
+ "VALUE node.");
return;
}
//
// TEXT セクションを取得する。
//
n = nl.item(0).getFirstChild();
if (n == null || n.getNodeType() != Node.TEXT_NODE) {
System.out.println("Error in parsing: can't find "
+ "TEXT section.");
return;
}
// 値を取得する。
value = n.getNodeValue();
}
/*
* Public 指定のアクセッサ
*/
public String getName()
{
return (name);
}
public String getValue()
{
return (value);
}
// Private 指定のメンバー変数
private String name, value;
}
/*
* クラス Event
* -----------
* このクラスは、クラス、サブクラス、ベンダー、パブリッシャー、名前 /
* 値ペアのリストから成るイベントを格納する。このクラスでは、そのメンバー
* から SC_EVENT_REG XML 要素を作成し、この要素を解析してそのメンバーに
* することができる。次の非対称性に注意: SC_EVENT 要素を解析するが、
* 作成するのは SC_EVENT_REG 要素である。これは、SC_EVENT_REG 要素が
* 登録メッセージ (これは作成の必要がある) 内で使用され、SC_EVENT 要素
* がイベント配信 (これは解析の必要がある) 内で使用されるためである。
* 違いは、SC_EVENT_REG 要素にはベンダーとパブリッシャーがないことだけ
* である。
*/
class Event
{
/*
* 2 つのコンストラクタ: 最初のコンストラクタは空のイベントを
* 作成し、2 つ目は SC_EVENT XML ドキュメントからイベントを
* 作成する。
*/
public Event()
{
regClass = regSubclass = null;
nvpairs = new Vector();
}
public Event(Document doc)
{
nvpairs = new Vector();
//
// デバッグで使用できるようにドキュメントを文字列に
// 変換して出力する。
//
DOMSource domSource = new DOMSource(doc);
StringWriter strWrite = new StringWriter();
StreamResult streamResult = new StreamResult(strWrite);
TransformerFactory tf = TransformerFactory.newInstance();
try {
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, streamResult);
} catch (TransformerException e) {
System.out.println(e.toString());
return;
}
System.out.println(strWrite.toString());
// 実際に解析する。
retrieveValues(doc);
}
/*
* Public 指定のセッター。
*/
public void setClass(String classIn)
{
regClass = classIn;
}
public void setSubclass(String subclassIn)
{
regSubclass = subclassIn;
}
public void addNvpair(NVPair nvpair)
{
nvpairs.add(nvpair);
}
/*
* createXmlElement
* ------------------
* メンバー変数から SC_EVENT_REG XML 要素を作成する。
* この要素を作成できるように、ドキュメントをパラメタとして
* 受け付ける。NVPair createXmlElement 機能を使用。
*/
public Element createXmlElement(Document doc)
{
Element event = (Element)
doc.createElement("SC_EVENT_REG");
event.setAttribute("CLASS", regClass);
if (regSubclass != null) {
event.setAttribute("SUBCLASS", regSubclass);
}
for (int i = 0; i < nvpairs.size(); i++) {
NVPair tempNv = (NVPair)
(nvpairs.elementAt(i));
event.appendChild(tempNv.createXmlElement(doc));
}
return (event);
}
/*
* メンバー変数を複数行に出力する。
*/
public void print(PrintStream out)
{
out.println("\tCLASS=" + regClass);
out.println("\tSUBCLASS=" + regSubclass);
out.println("\tVENDOR=" + vendor);
out.println("\tPUBLISHER=" + publisher);
for (int i = 0; i < nvpairs.size(); i++) {
NVPair tempNv = (NVPair)
(nvpairs.elementAt(i));
out.print("\t\t");
tempNv.print(out);
}
}
/*
* retrieveValues
* ----------------
* XML ドキュメントを解析し、クラス、サブクラス、ベンダー、
* パブリッシャー、および nvpair を取得する。
*/
private void retrieveValues(Document doc)
{
Node n;
NodeList nl;
//
// SC_EVENT 要素を検出する。
//
nl = doc.getElementsByTagName("SC_EVENT");
if (nl.getLength() != 1) {
System.out.println("Error in parsing: can't find "
+ "SC_EVENT node.");
return;
}
n = nl.item(0);
//
// CLASS、SUBCLASS、VENDOR、および PUBLISHER
// 属性の値を取得する。
//
regClass = ((Element)n).getAttribute("CLASS");
regSubclass = ((Element)n).getAttribute("SUBCLASS");
publisher = ((Element)n).getAttribute("PUBLISHER");
vendor = ((Element)n).getAttribute("VENDOR");
//
// すべての nv ペアを取得する。
//
for (Node child = n.getFirstChild(); child != null;
child = child.getNextSibling())
{
nvpairs.add(new NVPair((Element)child));
}
}
/*
* Public 指定のアクセッサメソッド。
*/
public String getRegClass()
{
return (regClass);
}
public String getSubclass()
{
return (regSubclass);
}
public String getVendor()
{
return (vendor);
}
public String getPublisher()
{
return (publisher);
}
public Vector getNvpairs()
{
return (nvpairs);
}
// Private 指定のメンバー変数
private String regClass, regSubclass;
private Vector nvpairs;
private String vendor, publisher;
}
/*
* クラス CallbackReg
* -----------
* このクラスは、ポートと登録タイプ (どちらも文字列)、およびイベントリストを
* 格納する。このクラスは、そのメンバーから SC_CALLBACK_REG XML メッセージ
* を作成できる。
*
* SC_CALLBACK_REG メッセージを解析する必要があるのは CRNP サーバー
* だけであるため、このクラスで SC_CALLBACK_REG メッセージを解析でき
* なくてもよい。
*/
class CallbackReg
{
// setRegType メソッドに便利な定義
public static final int ADD_CLIENT = 0;
public static final int ADD_EVENTS = 1;
public static final int REMOVE_EVENTS = 2;
public static final int REMOVE_CLIENT = 3;
public CallbackReg()
{
port = null;
regType = null;
regEvents = new Vector();
}
/*
* Public 指定のセッター。
*/
public void setPort(String portIn)
{
port = portIn;
}
public void setRegType(int regTypeIn)
{
switch (regTypeIn) {
case ADD_CLIENT:
regType = "ADD_CLIENT";
break;
case ADD_EVENTS:
regType = "ADD_EVENTS";
break;
case REMOVE_CLIENT:
regType = "REMOVE_CLIENT";
break;
case REMOVE_EVENTS:
regType = "REMOVE_EVENTS";
break;
default:
System.out.println("Error, invalid regType " +
regTypeIn);
regType = "ADD_CLIENT";
break;
}
}
public void addRegEvent(Event regEvent)
{
regEvents.add(regEvent);
}
/*
* convertToXml
* ------------------
* メンバー変数から SC_CALLBACK_REG XML ドキュメントを構築する。
* Event createXmlElement 機能を使用。
*/
public String convertToXml()
{
Document document = null;
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.newDocument();
} catch (ParserConfigurationException pce) {
// 指定したオプションを持つパーサーを構築できない。
pce.printStackTrace();
System.exit(1);
}
Element root = (Element) document.createElement("SC_CALLBACK_REG");
root.setAttribute("VERSION", "1.0");
root.setAttribute("PORT", port);
root.setAttribute("REG_TYPE", regType);
for (int i = 0; i < regEvents.size(); i++) {
Event tempEvent = (Event)
(regEvents.elementAt(i));
root.appendChild(tempEvent.createXmlElement(document));
}
document.appendChild(root);
//
// ここでドキュメントを文字列に変換する。
//
DOMSource domSource = new DOMSource(document);
StringWriter strWrite = new StringWriter();
StreamResult streamResult = new StreamResult(strWrite);
TransformerFactory tf = TransformerFactory.newInstance();
try {
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, streamResult);
} catch (TransformerException e) {
System.out.println(e.toString());
return ("");
}
return (strWrite.toString());
}
// private 指定のメンバー変数
private String port;
private String regType;
private Vector regEvents;
}
/*
* クラス RegReply
* -----------
* このクラスは、status_code と status_msg (どちらも文字列) を格納する。
* このクラスは、SC_REPLY XML 要素を解析し、そのメンバーにできる。
*/
class RegReply
{
/*
* 1 つのコンストラクタが XML ドキュメントを受け入れて解析を行う。
*/
public RegReply(Document doc)
{
//
// ここでドキュメントを文字列に変換する。
//
DOMSource domSource = new DOMSource(doc);
StringWriter strWrite = new StringWriter();
StreamResult streamResult = new StreamResult(strWrite);
TransformerFactory tf = TransformerFactory.newInstance();
try {
Transformer transformer = tf.newTransformer();
transformer.transform(domSource, streamResult);
} catch (TransformerException e) {
System.out.println(e.toString());
return;
}
System.out.println(strWrite.toString());
retrieveValues(doc);
}
/*
* Public 指定のアクセッサ
*/
public String getStatusCode()
{
return (statusCode);
}
public String getStatusMsg()
{
return (statusMsg);
}
/*
* 1 行で情報を出力する。
*/
public void print(PrintStream out)
{
out.println(statusCode + ": " +
(statusMsg != null ? statusMsg : ""));
}
/*
* retrieveValues
* ----------------
* XML ドキュメントを解析し、statusCode と statusMsg を取得する。
*/
private void retrieveValues(Document doc)
{
Node n;
NodeList nl;
//
// SC_REPLY 要素を検出する。
//
nl = doc.getElementsByTagName("SC_REPLY");
if (nl.getLength() != 1) {
System.out.println("Error in parsing: can't find "
+ "SC_REPLY node.");
return;
}
n = nl.item(0);
// STATUS_CODE 属性の値を取得する。
statusCode = ((Element)n).getAttribute("STATUS_CODE");
//
// SC_STATUS_MSG 要素を検出する。
//
nl = ((Element)n).getElementsByTagName("SC_STATUS_MSG");
if (nl.getLength() != 1) {
System.out.println("Error in parsing: can't find "
+ "SC_STATUS_MSG node.");
return;
}
//
// TEXT セクションが存在する場合は、それを取得する。
//
n = nl.item(0).getFirstChild();
if (n == null || n.getNodeType() != Node.TEXT_NODE) {
// Not an error if there isn't one, so we
// just silently return.
return;
}
// 値を取得する。
statusMsg = n.getNodeValue();
}
// private 指定のメンバー変数。
private String statusCode;
private String statusMsg;
}