Apache | WS |
WebServices - AxisAxis 開発者ガイド
バージョン 1.2
目次
はじめにこのガイドは Axis のコード開発に関連するトピックのコレクションです。 一般的なガイドライン
開発環境Axis の開発には以下のパッケージが必要です。
Axis jar ファイルは xml-axis/java/build/lib にビルドされています。以下に私がコードを開発する時に使用している CLASSPATH の例を示します。 G:\xerces\xerces-1_4_2\xerces.jar G:\junit3.7\junit.jar G:\xml-axis\java\build\lib\commons-discovery.jar G:\xml-axis\java\build\lib\commons-logging.jar G:\xml-axis\java\build\lib\wsdl4j.jar G:\xml-axis\java\build\lib\axis.jar G:\xml-axis\java\build\lib\log4j-1.2.8.jar G:\xml-axis\java\build\classes もし proxy サーバ経由でインターネットにアクセスしているのであれば、Axis テストが同じ動作を行うために環境変数を設定する必要があります。例えば ANT_OPTS を以下のように設定します。 -Dhttp.proxyHost=proxy.somewhere.com -Dhttp.proxyPort=80 -Dhttp.nonProxyHosts="localhost" プラグイン可能なコンポーネントAxis アーキテクチャガイドはプラグイン可能なコンポーネントの要件について説明しています。 発見Axis 特有のコンポーネントは以下の形式で作成する必要があります。 org.apache.axis.components.<コンポーネント型>.<ファクトリクラス名> 例えば、org.apache.axis.components.logger.LogFactory はロガーコンポーネント/サービスのためのファクトリ、あるいは発見機構です。 The org.apache.axis.components.image パッケージは、ファクトリと、Axis によって利用される様々な画像ツールの補助クラス、の両方の実例を示しています。これは、外部ツールを利用したプラグイン可能なコンポーネントの見本で、Axis の最小限の要件を満たすために、Axis を包んでいる、制限されたインターフェースのみを提供する '薄い' ラッパの背後に隔離されています。これにより今後の設計者や実装者は、これらのツールに対する Axis 特有の要件の明確な理解を得ることができます。 ロギング/トレーシングAxis のロギングとトレーシングは Jakarta Commons [英語] プロジェクトの Logging コンポーネント、つまり Jakarta Commons Logging (JCL) SPI に基づいています。JCL は、Log4J [英語]、Avalon LogKit [英語]、JDK 1.4 を含むその他のロギングツール用に、薄いラッパと共に Log インターフェースを提供しています。このインターフェースは Log4J と LogKit に密接にマッピングします。 ロガー SPI の利用Java クラスから JCL SPI を利用するには、以下の重要な文を入れてください。 import org.apache.commons.logging.Log; import org.apache.axis.components.logger.LogFactory; それぞれのクラス定義で、以下のように log 属性を宣言し、初期化してください。 public class CLASS { private static Log log = LogFactory.getLog(CLASS.class); ... 優先順位に対応するメソッドを呼ぶことにより、メッセージは log のような ロガーにログ出力されます。Log インターフェースは、ログ/トレースメッセージをログに書き込むのに利用する以下のメソッドを定義しています。 log.fatal(Object message); log.fatal(Object message, Throwable t); log.error(Object message); log.error(Object message, Throwable t); log.warn(Object message); log.warn(Object message, Throwable t); log.info(Object message); log.info(Object message, Throwable t); log.debug(Object message); log.debug(Object message, Throwable t); log.trace(Object message); log.trace(Object message, Throwable t); これらのメソッドのセマンティックスは最終的には Log インターフェースの実装によって定義されていますが、メッセージの重要度は上記リストに示されたような順序にすることが求められています。 ロギングメソッドに加え、以下のメソッドも提供されています。 log.isFatalEnabled(); log.isErrorEnabled(); log.isWarnEnabled(); log.isInfoEnabled(); log.isDebugEnabled(); log.isTraceEnabled(); これらは一般的に、ロギングのサポートがある時のみ実行する必要のあるコードと、一般的な場合 (ロギングが無効時) に望ましくない実行時オーバヘッドを導入するコードとを守るために利用されます。 ガイドラインメッセージプロパティログメッセージが内容と重要度の点で適切であるか確かめることは重要です。以下のガイドラインが提案されています。
ロガーの設定Jakarta Commons Logging (JCL) SPI は設定により異なるロギングツールキットを利用することができます。JCL が利用するロガーを設定する方法は Axis システム統合ガイドをご覧下さい。 JCL の動作設定は、最終的には利用しているロギングツールキットに依存します。JCL SPI (と、それ故に Axis) は (CLASSPATH の中で) 利用可能であれば、デフォルトで Log4J [英語] を利用します。 Log4JLog4J [英語] は Axis の推奨する/デフォルトのロガーなので、開発者の開発のためにここでいくつかの詳細を紹介します。 システムプロパティとプロパティファイルの両方、あるいは片方を利用して Log4J を設定します。
Axis サーブレットクエリー文字列プラグインorg.apache.axis.transport.http.AxisServlet クラスから派生する全てのサーブレットは、多数の標準クエリー文字列 (?list、?method、?wsdl) をサポートします。これらの標準クエリー文字列はWebサービスから情報を提供したり、Webサービスの操作を実行したりします (例えば、?method はWebサービス上のメソッドを呼び出すのに利用され、?wsdl はWebサービスの WSDL ドキュメントを取得するのに利用されます)。Axis サーブレットはこれら3つのクエリー文字列だけに制限しているわけではなく、開発者は org.apache.axis.transport.http.QSHandler インターフェースを実装することで自分用の "プラグイン" を生成することができます。このインターフェースには実装しなければならない1つのメソッドがあり、このメソッドは以下のシグネチャを持ちます。 public void invoke (MessageContext msgContext) throws AxisFault; org.apache.axis.MessageContext インスタンスは、その getProperty メソッドでアクセス可能な多数の有用なオブジェクト (Axis エンジンインスタンスや HTTP サーブレットオブジェクト等) を開発者に提供しています。以下の定数は、Axis サーブレットがクエリー文字列プラグインを呼び出すことによって提供される様々なオブジェクトを取得するのに利用することができます。
出力の同じ基本情報とメソッドを開発者が利用できるという点において、クエリー文字列プラグイン開発は普通のサーブレット開発に大変似ています。以下は、システム時計の値を単に表示するクエリー文字列プラグインの例です (簡潔にするために、import 文は省略しています)。 public class QSClockHandler implements QSHandler { public void invoke (MessageContext msgContext) throws AxisFault { PrintWriter out = (PrintWriter) msgContext.getProperty (HTTPConstants.PLUGIN_WRITER); HttpServletResponse response = (HttpServletResponse) msgContext.getProperty (HTTPConstants.MC_HTTP_SERVLETRESPONSE); response.setContentType ("text/html"); out.println ("<HTML><BODY><H1>" + System.currentTimeMillis() + "</H1></BODY></HTML>"); } } クエリー文字列プラグインクラスを作成したら、Axis サーバを、それを呼び出すクエリー文字列を認識するように設定する必要があります。Axis サーバ設定ファイルの HTTP トランスポート節の設定方法に関する情報は Axis リファレンスガイド内のデプロイ (WSDD) リファレンス節をご覧下さい。 設定プロパティAxis は内部設定の主要ポイントとしてシステムプロパティを利用することをやめる過程にいます。System.getProperty() を呼ぶことを避け、替わりに AxisProperties.getProperty を呼んでください。AxisProperties.getProperty は System.getProperty を呼び、(最終的には) その他の設定情報源に問い合わせを行います。 このアクセスの中央ポイントを利用することにより、グローバル設定システムを、単一の JVM 上で複数の Axis エンジンをよりサポートするように再設計することができます。 例外処理Axis 例外処理に関するガイドラインは例外処理のベストプラクティスに基づいています。これらのガイドラインには Axis 特有の詳細がありますが、基本的には全てのプロジェクトに適用できます。これらのガイドラインは2つの理由でここに含まれました。1つめは、Apache/Jakarta ガイドラインのどこにも書かれていなかった (あるいは見つからなかった) からです。2つめは、これらのガイドに順守することはエンタープライズ用のミドルウェアにとって重大であると考えられるからです。 これらのガイドラインは基本的にプログラミング言語から独立しています。これらは経験に基づいていますが、何年も前に無邪気 (?) な人を開眼させたという適切な功績は Scott Meyers による More Effective C++ に与えられるべきです。 最後に、これらはガイドラインです。これらのガイドラインには必ず例外があります。その場合、その例外が "コードの中にコメントがある" という形式でログが取られている状態で (これらのガイドラインごとに) 質問してください。
コンパイルと実行xml-axis/java/build.xml ファイルは、アプリケーションをビルドしてテストを実行するために ant が利用する主要な 'make' ファイルです。build.xml は ant のビルドの targetを定義しています。より詳細な情報については build.xml ファイルをお読みください。ここにいくつかの有用な target を挙げます。
ソースコードをコンパイルするには次のように実行します。 cd xml-axis/java ant compile Tテストを実行するには次のように実行します。 cd xml-axis/java ant functional-tests 注意: これらのテストはポート8080でサーバを起動します。もしこのポートが、あなたの (Tomcatのような) Webアプリケーションサーバが利用するポートと衝突する場合、どちらかのポートを変えるか、テストを実行するときにあたなのWebアプリケーションサーバを停止する必要があります。 新しいコードをチェックする前に、ant functional-tests と ant all-tests を実行してください。 国際化ソースコードに変更を加えて、テキスト (エラーメッセージやデバッグ情報) を生成するようにした場合、そのテキストが確実に正しく変換されるために以下のガイドラインに従う必要があります。 開発者ガイドライン
例以下の文について考えてください。 if (operationName == null) throw new AxisFault( "No operation name specified" ); org/apache/axis/i18n/resource.properties にエントリーを追加します。 noOperation=No operation name specified. そしてそれを読み込むようにコードを変更します。 if (operationName == null) throw new AxisFault(Messages.getMessage("noOperation")); インターフェースAxis はプロパティファイルとメッセージ文字列にアクセスするために標準 Java 国際化クラス java.util.ResourceBundle を利用し、変数を利用して文字列の書式を整えるために java.text.MessageFormat を利用します。Axis は ResourceBundle クラスと MessageFormat クラスの両方を管理する単一のクラス org.apache.axis.i18n.Messages を提供しています。Messages のメソッドは以下の通りです。 public static java.util.ResourceBundle getResourceBundle(); public static String getMessage(String key) throws java.util.MissingResourceException; public static String getMessage(String key, String var) throws java.util.MissingResourceException; public static String getMessage(String key, String var1, String var2) throws java.util.MissingResourceException; public static String getMessage(String key, String[] vars) throws java.util.MissingResourceException; Axis プログラマは Messages.getResourceBundle() 呼び出し経由で直接リソースバンドルを扱うことができますが、2つの理由から、代わりに getMessage() メソッドを利用すべきです。
getMessage メソッド変数のないメッセージであれば myMsg00=This is a string. 単に次のように呼びます。 Messages.getMessage("myMsg00"); 変数付きのメッセージであれば、X が0から始まる変数の名前を表す、文法 "{X}" を利用します。例えば、 myMsg00=My {0} is {1}. であれば、次のように呼び、 Messages.getMessage("myMsg00","name", "Russell"); その結果の文字列は "My name is Russell." になります。 getMessage の String 配列バージョンも呼ぶことができます。 Messages.getMessage("myMsg00", new String[] {"name", "Russell"}); 本当に必要なのは getMessage の String 配列バージョンだけですが、大部分のメッセージは0個か1個か2個の変数を持つので、String 配列バージョンの複雑さを避けるための利便性として、そのほかの getMessage メソッドが提供されています。 もしリソースが見つからなければ getMessage メソッドは MissingResourceException をスローすることに注意してください。また、引数より多くの {X} エントリーがあれば ParseException をスローします。これらの例外は RuntimeException の例外なので、呼び出し側は明示的にそれらをキャッチする必要はありません。 リソースバンドルプロパティファイルは org/apache/axis/i18n/resource.properties です。 メッセージファイルの拡張一般的に、Axis 内では全てのメッセージは org.apache.axis.i18n.resource.properties にあります。Axis への統合や、Axis のサードパーティ拡張のために、このファイルを修正することなくメッセージを拡張する機構があります。詳細については統合ガイドをご覧下さい。 テストケースの追加テスト構造とサンプル構造もご覧下さい。 編集者注釈: テストの追加の合理化と簡素化のさらなる努力が必要です。また、テストが増えるに従って、テストの分類を考慮に入れる必要もあります。 Axis に変更を加えたのであれば、その変更を利用するテストを追加してください。理由は以下の通りです。
いくつかの一般的な原則を挙げます。
テストをビルドする1つの方法は、既存のテストを "カットアンドペースト" し、あなたのニーズを満たすようにテストを修正することです。このアプローチは異なる種類のテストが増えるにつれてより複雑になってきます。 参考になる "wsdl のない" 良いテストは test/saaj です。 WSDL テストの作成私が sequence テストを作成するために利用したステップを紹介します。このテストは wsdl ファイルからコードを生成し、シーケンスの検証テストを実行します。
テスト構造テストとサンプルの再設計ドキュメントはここにあります。 [英語] Axis 1.0, RC1 以降、"コンポーネント化された" テスト構造に移行しました。1つの高レベルの大きな再帰関数を持つ代わりに、test/** ツリーと samples/** ツリーの葉レベルに小さくて単純な "コンポーネント" である build.xml ファイルがあります。 これらの "コンポーネント" ファイルは共通のレイアウトを持っています。それらの主要な target は以下の通りです。
"サンプル" であるテスト xml ファイルは test/templateTest にあります。 ソースコードチェックを追加するAxis ビルドは、メッセージを発行する際に国際化された文字列を利用しているかといった、特定の規約に従っているか確かめるために、ソースディレクトリ (java/src) 内のファイルに対して一定の自動化されたチェックを実行します。 規約を正規表現マッチに変形できるのであれば、java/test/utils/TestSrcContent.java を更新することでビルド時にそれを強制することができます。 必要なことは、static な FileNameContentPattern 配列にパターンを追加するだけです。各パターンは3つのパラメータを持っています。
正規表現表記の適度な要約は Jakarta ORO javadocs [英語] で提供されています。 JUnit と AxisWebサービスを呼び出す Axis クライアントの JUnit テストを実行しようとすると、必ず以下の例外を得ることになるでしょう。 java.lang.ExceptionInInitializerError at org.apache.axis.client.Service.<init>(Service.java:108) ... Caused by: org.apache.commons.logging.LogConfigurationException: ... org.apache.commons.logging.impl.Jdk14Logger does not implement Log at org.apache.commons.logging.impl.LogFactoryImpl.newInstance (LogFactoryImpl.java:555) ... 実際には、Jdk14Logger は Log を実装しています。これは JUnit のクラスローディングの問題です。JUnit のグラフィカルな TestRunner には、ユーザが "Run" ボタンを押すたびに修正されたクラスを動的にリロードする機能があります。これによりユーザは修正のたびに TestRunner を再起動する必要がなくなります。このために JUnit は自身のクラスローダ junit.runner.TestCaseClassLoader を利用します。JUnit 3.8.1 現在、TestCaseClassLoader とシステムクラスローダ間で、どのクラスに対してどちらのローダが実行されたか、あるいはどちらのローダでロードすべきかという混乱が生じます。 この問題を回避するのに2つの方法があります。
ディレクトリパスを保持しながらこのファイルを他の場所、例えば deployDir にコピーします。ですからコピーされたプロパティファイルのパスは deployDir/junit/runner/excluded.properties になります。このファイルの最後に余分なエントリを追加します。 excluded.9=org.apache.* あなたのクラスパスを修正して、deployDir が junit.jar の前に来るようにします。これによりデフォルトではなく修正した excluded.properties が利用されます。(クラスパスに excluded.properties 自身へのパスを追加しないで下さい。) この修正により commons-logging 例外を防ぐことができます。しかし、他のクラスローディング問題が出てくるかもしれません。例えば以下のようなものです。 Dec 10, 2002 7:16:16 PM org.apache.axis.encoding.ser.BeanPropertyTarget set SEVERE: Could not convert [Lfoo.bar.Child; to bean field 'childrenAsArray', type [Lfoo.bar.Child; Dec 10, 2002 7:16:16 PM org.apache.axis.client.Call invoke SEVERE: Exception: java.lang.IllegalArgumentException: argument type mismatch at org.apache.axis.encoding.ser.BeanPropertyTarget.set (BeanPropertyTarget.java:182) at org.apache.axis.encoding.DeserializerImpl.valueComplete (DeserializerImpl.java:284) ... この場合、あなたには選択肢はなく、動的クラス再ロードをあきらめて -noloading 引数を利用します。 Axis Webサービスの JUnit テストに関してもう1つ注意があります。Webサービスとして公開するコンポーネントをローカルで JUnit テストを実行したとします。一連のテストを初期化するために "Run" ボタンを押します。各テスト間で、全てのデータ構造は再初期化されます。あなたのテストは長い緑色のバーを生成します。これはいいでしょう。 次に、Axis Webアプリケーションと共にあなたのWebサービスが実行されているアプリケーションサーバに接続する Axis クライアントに対して JUnit テストを実行するとします。各テスト間で、JUnit はあなたのクライアントを自動的に再初期化します。 サーバ側のデータ構造が問題となります。各テストの終わりでサーバのデータをチェックしていて (するべきです)、一度に2つ以上のテストを実行すると、2つめ以降のテストが失敗します。なぜなら、現在のテストのみに基づいた新鮮なデータではなく、以前のテストに基づいた累積したデータを Axis サーバ上で生成しているからです。 これは、各テストにおいてあなたのWebサービスを手動で最初期化しなくてはいけないことを意味しています。これを達成する1つの方法は、あなたのWebサービスインターフェースに最初期化操作を加えることです。そして各テストの最初で、クライアントがその操作を呼ぶようにします。 ファンクションテストを監視するために tcpmon を利用するfunctional-tests (あるいは all-tests) の実行時にメッセージを監視する簡単な方法を紹介します。 8080ポートをリッスンし、異なるポートにフォワードする tcpmon を起動します。 java org.apache.axis.utils.tcpmon 8080 localhost 8011 SimpleAxisServer にポートをフォワードし、失敗が発生しても functional-tests を続けるように指示してテストを実行します。 ant functional-tests -Dtest.functional.SimpleAxisPort=8011 -Dtest.functional.fail=no すべてのテストの SOAP メッセージは tcpmon ウィンドウに現れるはずです。 tcpmon は Axis ユーザガイドで詳細に説明されています。 ファンクションテストを監視するために SOAP Monitor を利用する(Tomcat のような) Webアプリケーションサーバを利用してWebアプリケーションとして実行しているコードをデバッグする際に、SOAP リクエストメッセージと SOAP レスポンスメッセージを見るために SOAP Monitor ユーティリティを利用することもできます。 ウェブブラウザウィンドウ内で SOAP Monitor アプレットをロードして SOAP Monitor ユーティリティを立ち上げてください。 http://localhost:<port>/axis/SOAPMonitor テストを実行するに従って、SOAP メッセージが SOAP Monitor ウィンドウに現れます。 SOAP Monitor は Axis ユーザガイドで詳細に説明されています。 単一のファンクションテストを実行するあるウィンドウでサーバを起動します。 java org.apache.axis.transport.http.SimpleAxisServer -p 8080 別のウィンドウでまずテストを行うサービスをデプロイします。 java org.apache.axis.client.AdminClient deploy.wsdd 次にテストを指定して JUnit ユーザインターフェースを立ち上げます。例えば、マルチスレッドのテストケースを実行するには以下のようにします。 java junit.swingui.TestRunner -noloading test.wsdl.multithread.MultithreadTestCase デバッギングデバッグ出力を行うこの節では Axis のデフォルトのロガーである Log4J の説明をします。Log4J の追加的な情報はロギング/トレーシング節をご覧下さい。
一時出力の出力Axis は多くのオープンソースのWebアプリケーションやその他のWebアプリケーションでの利用を目標としているので、善良な市民である必要があります。System.out.println や System.err.println を利用して出力を書き出すことは避けるべきです。 開発者はシステムをデバッグしたり分析したりする際に System.out.println を利用する傾向があります。もしこれを行うのであれば、System.out.println と System.err.println の回避を強制する util/TestSrcContent テストを無効にする必要があります。また、そのコードをチェックインして戻す前にあなたの文を削除する必要が出てきます。 別の方法として、デバッグ文 log.debug("適度に簡潔で意味のあるメッセージ") を導入することを強くお勧めします。デバッグメッセージが問題の理解に今役立つのであれば、将来あなたと仲間にとってもまた役立つかもしれません。 JAX-RPC 互換性テストの実行仕様と同様に、JAX-RPC には JAX-RPC エキスパートグループのメンバ (とその他の人達?) が手に入れることのできる Technology Compatibility Kit (TCK) があります。 このキットは zip ファイルで提供されているので、自分の好きなディレクトリに unzip する必要があります。インストールの説明は docs ディレクトリ内にある JAX-RPC リリースノートドキュメントにあります。ウェブブラウザを利用して doc ディレクトリ内の index.html ファイルを開くと、キットで提供されている全てのドキュメントのリストを見ることができます。 このキットには、互換性テストを実行するのに利用される JavaTest テストハーネスが含まれていることに注意してください。 これらのテストの実行に関する情報がさらに必要であれば、ここに追加してください。 |