OracleでXMLを活用する
XSQLプログラミング入門

最終回 アクションハンドラーを作成する

XSQLでは、あらかじめ決められたタグを利用してプログラミングを行うだけでなく、独自のカスタムなタグを作ることができる。カスタムタグが利用されると、それに関連されたアクションハンドラーが呼び出される。ここでは、そのカスタムタグとアクションハンドラーの作成について説明しよう。

小山尚彦、Chienowa.comチーム
日本オラクル株式会社
2000/7/20

     XSQLアクションハンドラー作成の基本

 XSQLの連載は今回で最終回です。前回ではXSQLの標準タグについて説明しました。今回は、標準では用意されないXSQLタグを処理するため、Javaによるカスタムアクションハンドラーの作成方法について説明します。アクションハンドラーを定義することで、既存の処理にはなかった新しい処理をXSQLに追加することが可能になるわけです。

 まずはJavaによるアクションハンドラーを作成する際の基本について説明しましょう。下のファイルは、サンプルとしてsrc/oracle/xml/xsql/actionの中にはいっている、ExampleCurrentDBDateHandlerというアクションハンドラーの例です。

ExampleCurrentDBDateHandlerの例

pakcage com.test
import oracle.xml.xsql.*;
import org.w3c.dom.*;
import java.sql.*;

public class ExampleCurrentDBDateHandler extends
     XSQLActionHandlerImpl {


String statement = null;
ResultSet rs = null;
Statement s = null;


public void init(XSQLPageRequest xsqlpagerequest, Element element) {
  super.init(xsqlpagerequest, element);
}


public void handleAction( Node rootNode ) throws SQLException {
  statement = "select to_char(sysdate,
      'dd-Mon-yyyy hh24:mi:ss') from dual";
  if (!requiredConnectionProvided(rootNode)) {
  return;
}


try {
  s = getPageRequest().getJDBCConnection()
       .createStatement();
  rs = s.executeQuery(statement);
  String curDate = "";
  if (rs.next()) {
    curDate = rs.getString(1);
  }
  addResultElement(rootNode,"Current-Date",curDate);
  rs.close();
  s.close();
}
  catch (SQLException exs) {
    this.reportErrorIncludingStatement(rootNode,statement,
         exs.getMessage());
    rs.close();
    s.close();
  }
}
}

注目点すべきは4つあります。アクションハンドラーの作成では、この4点がポイントです。

インポートするクラス群
1行目と2行目で、以下のクラスをインポートしています。
oracle.xml.xsql.*
org.w3c.dom.*

XSQLActionHandlerImplの継承
クラスの宣言のところでXSQLActionHandlerImplをextend(継承)しています。

initによる初期化
initメソッドが特に必要になる場合というのはありません。というのも、次のhandleActionメソッドですべてできてしまうからです。しかし、initでactionエレメントからの入力などを処理して、handleActionをすっきりさせるのもよいかもしれません。

handleActionによる実際の処理
handleAction(Node rootNode)の中で、実際の処理を記述します。

     アクションハンドラーを呼び出すには?

 まずは、手っ取り早く実際にこのアクションハンドラーをコンパイル、インストールして、呼び出す方法を説明しましょう。

  1. ActionHandlerファイルを作る(例えばcom.test.ExampleCurrentDBDateHandler)
  2. javacでコンパイルしてclassを生成します。
  3. jar -cvf <jarfilename>.jar com/でjarファイルを生成します。
  4. jarファイルをservletエンジンのクラスパスに入れます。Servletエンジンのマニュアルを参照してください。
  5. xsqlファイルから<xsql:action handler="com.test.ExampleCurrentDBDateHandler">タグで呼び出します
  6. (この操作はオプションです)上記5の代わりにハンドラーをlib/XSQLConfig.xmlで新たなXSQLタグとしてマクロ定義しても構いません。するといちいちハンドラー名を記述する手間が省けます。 ただし登録できるタグ数は10までです。 具体的には次のように記述します。

XSQLタグとアクションハンドラーの定義

<?xml version="1.0" ?>
<XSQLConfig>
……中略……

<actiondefs>
  <action>
    <elementname>current-date</elementname>
    <handlerclass>
      com.test.ExampleCurrentDBDateHandler
    </handlerclass>
  </action>
</actiondefs>
</XSQLConfig>

 このように記述することで、先ほどの長い表記<xsql:action handler="com.test.ExampleCurrentDBDateHandler">を<xsql:current-date>タグで呼び出すことができます。

 万が一作成したアクションハンドラーが設計したように動かないときはデバッグが必要になります。 その際は、handleAction(Node rootNode)メソッド内で

addResultElement(rootNode, "CHECK", “メッセージの内容");

を「メッセージの内容」と書かれた部分に適材適所な情報を各所に埋め込んであげることでデバッグがやりやすくなるはずです。

     アクションハンドラーに値を渡す方法

 通常は、アクションハンドラーになんらかのデータやXML文書を渡し、処理された結果を受け取ることになります。その方法について説明します。

 理屈は最小限にして、実際にサンプルを見ながら説明していきましょう。アクションハンドラーに値を渡すにはさまざまな方法がありますここでは下記の6つの方法を紹介します。

  1. action elementのattributeを読み込む
  2. action elementの内容を読み込む
  3. action elementの子エレメントの内容を読み込む
  4. HTTPで渡された引数を受け取る
  5. HTTPで渡された引数をHttpRequestを通じて受け取る
  6. 外部XMLファイルから読み取る。

 まず、アクションハンドラーは以下のXML文書から呼び出すとしましょう。

アクションハンドラーを呼び出すXML文書例

<xsql:action handler="com.chienowa.TestAction"
    deptid="{@dept_id}">
  ドットコム事業開発部
  <location>
    <building>ニューオータニガーデンコート</building>
    <floor>14F</floor>
    <region>SE</region>
  </location>
  <manager>
    <id>50</id>
    <name>高橋敦子</name>
  </manager>
</xsql:action>

■action elementのattributeを読み込む方法

 action elementとは、実際にアクションハンドラーを呼び出しているところ。<xsql:acrion…>のタグを指します。

 このaction elementのattributeを読み込むには、以下のようなアクションハンドラーを定義します。

action elementのattributeを読み込む方法

public void handleAction(Node rootNode) {
  //actionのエレメント<xsql:action   handler="com.chienowa.TestAction">をとる
  Element actionElement = getActionElement();
  // attribute名deptidにdept_idリクエストパラメターを代入する
  String deptid = getAttributeAllowingParam("deptid",
    actionElement);
}

このアクションハンドラーを、次のようなXML文書で呼び出すとしましょう。

<xsql:action handler="com.test.TestAction"
     deptid="{@dept_id}">

アクションハンドラーで、上記の変数の値を取得できます。 例えば、上記の場合dept_idという引数で0115と渡されていたとしますとString deptidには0115が入ります。

■action elementの内容を読み込む

 こんどはaction elementの内容を読み込むアクションハンドラーの定義です。

action elementの内容を読み込む方法

public void handleAction(Node rootNode)
{
  //actionのエレメント
  //<xsql:action handler="com.test.TestAction">をとる
  Element actionElement = getActionElement();
  // actionElementの内容をとる
  String content = getElementContent(actionElement);
}

これで、最初に例にあげたアクションハンドラーを呼び出すXML文書の中の、action elementの内容である

ドットコム事業開発部

を取得できます。

■action elementの子エレメントの内容を読み込む

 例えば、以下のXML文書の“ニューオータニガーデンコート”を取得したいと思います。

<location>
  <building>ニューオータニガーデンコート</building>
</location>

 このときのアクションハンドラーは以下になります。

上記の「ニューオータニガーデンコート」を読み込む

public void handleAction(Node rootNode) {

  Element actionElement = getActionElement();
  //actionのエレメント
  //<xsql:action handler="com.chienowa.TestAction">をとる

  Element elLocation = getElementByName("location", actionElement);
  // 同じく<location>タグをとる
  Element elBuilding = getElementByName("building", elLocation);
  // <building>タグ
  String building = getTextNode(elBuilding);
  //ここでgetTextNodeメソッドを呼び<bulding>タグのコンテンツを取得

}

 ここでgetTextNode(Element)というメソッドが出てまいりましたが、これは標準のActionHandlerImplのメソッドではありませんので別途下記のように用意してください。

Private String getTextNode( Element source ) {
  StringBuffer buffer = new StringBuffer();
  NodeList nodes = source.getChildNodes();
  int size = nodes.getLength();
  for ( int i = 0 ; i < size ; i++ ) {
    Node node = nodes.item(i);
    if ( node.getNodeType() == Node.TEXT_NODE ) {
      Text text = (Text)node;
    buffer.append( text.getData() );
    }
  }
  String result = new String( buffer );
  return( result );
}

 多少の制限はありますが、もう少し簡単にElementの値をとってくることがXSQLUtilのAPIとして用意されています。 例えば次のようなXSQLファイルがあったとします。

<?xml version='1.0' encoding="Shift_JIS"?>
<page xmlns:xsql="urn:oracle-xsql">

<xsql:action handler="com.test.ReadTreeAction">
  <CHIENOWA>こんにちわ
    <TEST>てすとです</TEST>
  </CHIENOWA>
</xsql:action>

ここで呼ばれているcom.test.ReadTreeActionのhandleActionメソッドは次のようになっています。

public void handleAction(Node node) {

  Element actionElement = getActionElement();

  String s1=XSQLUtil.valueOf(actionElement, "CHIENOWA");
  String s2=XSQLUtil.valueOf(actionElement, "CHIENOWA/TEST");

  addResultElement(node, "CHECK", s1);
  addResultElement(node, "CHECK", s2);

}

このときの出力は

<?xml version="1.0" encoding="Shift_JIS" ?>
<page xsql-timing="2">
  <CHECK>こんにちわ てすとです</CHECK>
  <CHECK>てすとです</CHECK>
</page>

 という形式なります。これでお分かりのように、この方法で取り出すと子孫エレメントの内容も連結してしまいます。そのため、エレメントがすべてアクションエレメントの子エレメントであった場合のみ有功な方法となります。

■HTTPで渡された引数を受け取る

 HTTPで渡された引数を受け取って処理する場合には、以下のアクションハンドラーを定義すれば可能になります。

HTTPで渡された引数を受け取るアクションハンドラー

public void handleAction(Node rootNode) {

  XSQLPageRequest xsqlpagerequest = getPageRequest();
  String v_mailaddress = new String(
  (xsqlpagerequest.getParameter("p_mailaddress")
  ).getBytes("8859_1") , "JISAutoDetect" );
}

 これでp_mailaddressパラメターをv_mailaddressに収めることができます。

■HTTPで渡された引数を、HttpRequestを通じて受け取る

 同様に、今度はHttpRequestを通じて引数を受け取るアクションハンドラーです。

HTTPで渡された引数を、HttpRequestを通じて受け取る

public void handleAction(Node rootNode) {
  XSQLPageRequest xsqlpagerequest = getPageRequest();
  XSQLServletPageRequest request = (XSQLServletPageRequest)
    xsqlpagerequest;
  HttpServletRequest req = request.getHttpServletRequest();
  String v_mailaddress[] =   req.getParameterValues("p_mailaddress");
}

 先ほどの方法ではできなかった、Arrayになっているparameterも、HttpRequestを通じてv_mailaddress[ ]に渡すことができます。

■外部XMLファイルから読み取る。

 ここでは以下のChienowa.xmlというxmlファイルの中にある<SMTP-SERVER>の内容を取得したいと思います。 このファイルの置き場所は、xsql/libディレクトリかまたはアクションハンドラーとおなじjarファイル内のトップディレクトリに置くかどちらでもかまいません。

Chienowa.xmlの内容

<?xml version="1.0" encoding="Shift_JIS"?>
<Chienowa>
  <SMTP-SERVER>sendmail1.jp.oracle.com</SMTP-SERVER>
</Chienowa>

XMLファイルを読み込むアクションハンドラー

public void handleAction(Node rootNode) {
  org.w3c.Document document = null;
  try{
    java.io.InputStream inputstream =     
        getClass().getResouceAsStream("/Chienowa.xml");
    if(inputstream == null) {
      throw new Exceptioin(null);
    }
    BufferedInputStream bis = new     
    BufferedInputStream(inputstream);
    document = XSQLParserHelper.parse(bis, null,     
        xsqlpagerequest.getErrorWriter());
    bis.close();
  } catch (Exception ex) {
    reportError(rootNode, ex.getMessage());
  }//下準備終了

  String s1 = XSQLUtil.valueOf(document, "/Chienowa/SMTP-  
      SERVER");
}

 これで“s1”というString変数に“sendmail1.jp.oracle.com”という文字列が入ります。この方法を使って汎用性の高いアクションハンドラーを作ることが可能です。

 

 目次 

 1ページ

 XSQLアクションハンドラー作成の基本
 アクションハンドラーを呼び出すには?
 アクションハンドラーに値を渡す方法
   action elementのattributeを読み込む
   action elementの内容を読み込む
   action elementの子エレメントの内容を読み込む
   HTTPで渡された引数を受け取る
   HTTPで渡された引数をHttpRequestを通じて受け取る
   外部XMLファイルから読み取る

 2ページ
 アクションハンドラからの出力を得る方法
 アクションハンドラー内でのデータベースとの接続
 エラーリポート(例外処理)
   HreportErrorを利用する
   reportErrorIncludingStatementを利用する
   reportFatalErrorを利用する
 

「連載 XSQLプログラミング入門」


XML & SOA フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

HTML5+UX 記事ランキング

本日月間