WebServices - Axis

Axis システム統合ガイド

バージョン 1.2
フィードバック: axis-dev@ws.apache.org

目次

はじめに

このガイドの主な目的は、Axis を既存のWebアプリケーションサーバ、例えば Tomcat や WebSphere、に統合する方法を紹介することです。Axis にはそのような統合に必要なプラグイン可能な API が数多くあります。

有用な背景知識についてはアーキテクチャガイドで得られます。

プラグイン可能な API

以下は、Axis をWebアプリケーションサーバに統合するためのプラグイン可能なポイントです。最初の小節では、一般のプラグイン可能なコンポーネントのいくつかを解説しています。残りの小節で、その他のコンポーネントについて詳しく解説しています。

コンポーネント

この節では、様々なコンポーネントの特殊化を Axis にプラグインする方法全般について解説しています。

General Strategy

プラグイン可能なコンポーネントのデフォルトの動作を上書きするには以下のことを行います。

  • コンポーネントインターフェースの実装を開発します
  • サービス定義ファイルを作成する (推奨) か、システムプロパティを設定することによって、Axis に実装クラスを定義します。
    • 推奨: サービス定義ファイルを作成するには以下のことを行います。
      • サービス定義ファイルの名前は、サービスが実装/拡張するインターフェース/抽象クラスに由来します。
        /META-INF/services/<コンポーネントパッケージ>.<インターフェース名>
      • サービス定義ファイルに、実装クラスの完全修飾名の1行を追加します
    • 以下のようにシステムプロパティを設定します。
      • システムプロパティの名前はインターフェースの名前になります。
      • システムプロパティの値は実装の名前になります。
      • 省略可能なシステムプロパティの名前 (下の表にあります) も利用することができます。
      • システムプロパティを設定することは、特に J2EE やその他のアプリケーションホスティング環境ではお勧めできません。なぜならそれにより全てのアプリケーションに渡って命令を出すことになるからです。これは適切な行為かどうか分かりません。もしこれを行うのであれば、ウェブアプリケーションの実行時に行うべきではありません。
  • 実装クラスと、もし利用するのであればサービス定義ファイルを JAR ファイルに入れ、クラスローダ (CLASSPATH) から取り出せる場所に置きます。
例 1

Java コンパイラのデフォルトの動作を上書きするには以下のことを行います。

  • Compiler インターフェースの実装は既に Jikes コンパイラに提供されています。
  • 以下の行をサービス定義ファイルに追加します。
    /META-INF/services/org.apache.axis.components.compiler.Compiler
  • Add the following line to the service definition file:
    org.apache.axis.components.compiler.Jikes
  • org.apache.axis.components.compiler.Jikes は Axis にパッケージ化されているので、しなくてはいけないことは、サービス定義ファイルがクラスローダからロードできることを確かめることだけです。
例 2

リソースを適切に配置すること、あるいはロードすることが許されていない環境や、ある動作を特定の実装に強制させる必要がある環境において、SocketFactory のデフォルトの動作を上書きするには以下のことを行います。

  • SocketFactory インターフェースの実装を提供します。例えば次のようになります。your.package.YourSocketFactory
  • 次の名前をもつシステムプロパティに
    org.apache.axis.components.net.SocketFactory
    次の値を設定します。
    your.package.YourSocketFactory

    これは以下の JVM コマンドラインを利用して行うことができます。
    -Dorg.apache.axis.components.net.SocketFactory=your.package.YourSocketFactory
  • 実装クラスがクラスローダによってロードできるか確かめてください。
リファレンス

(コンポーネント/パッケージ: org.apache.axis.components.*)

コンポーネントパッケージ ファクトリ インターフェース 省略可能なシステムプロパティ デフォルトの実装
compiler CompilerFactory getCompiler() Compiler axis.Compiler Javac
image ImageIOFactory getImageIO() ImageIO axis.ImageIO MerlinIO, JimiIO, JDK13IO
jms JMSVendorAdapterFactory getJMSVendorAdapter() JMSVendorAdapter JNDIVendorAdapter
net SocketFactoryFactory getFactory() SocketFactory axis.socketFactory DefaultSocketFactory
net SocketFactoryFactory getSecureFactory() SecureSocketFactory axis.socketSecureFactory JSSESocketFactory

ロギング/トレーシング

Axis のロギングとトレーシングは Jakarta Commons [英語] プロジェクトの Logging コンポーネント、つまり Jakarta Commons Logging (JCL) SPI に基づいています。JCL は、Log4J [英語]、Avalon LogKit [英語]、JDK 1.4 を含むその他のロギングツール用に、薄いラッパと共に Log インターフェースを提供しています。このインターフェースは Log4J と LogKit に密接にマッピングします。

正当化/原理

プラグイン可能なロギング/トレース機構により、Axis はロギング/トレースメッセージをホストであるWebアプリケーションサーバのロギング機構に流すことができます。単一の設定/制御を持った中央ロギング機構は、Webアプリケーションサーバに統合される多数のミドルウェアコンポーネントのそれぞれのための個別のロギング機構よりも優れています。

統合

他のロガーとの統合に最低限必要なことは、org.apache.commons.logging.Log インターフェースの実装を提供することです。さらに、ロガーに接続するため、またはロガーをインスタンス化するための特定の要件を満たすために、org.apache.commons.logging.LogFactory インターフェースの実装も提供します。

  • org.apache.commons.logging.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.isFatalEnabled();
      log.isErrorEnabled();
      log.isWarnEnabled();
      log.isInfoEnabled();
      log.isDebugEnabled();
      log.isTraceEnabled();

    これらのメソッドのセマンティックスには、メッセージの重要度が最高から最低へと順序付けられている、というのがあります。

    • fatal - コンソールとシステムログにログを書き込むものとする。
    • error - コンソールとシステムログにログを書き込むものとする。
    • warn - コンソールとシステムログにログを書き込むものとする。
    • info - コンソールとシステムログにログを書き込むものとする。
    • debug - 可能であればシステムログにログを書き込む。
    • trace - 可能であればシステムログにログを書き込む。
  • org.apache.commons.logging.LogFactory

    必要に応じて、org.apache.commons.logging.LogFactory インターフェースのデフォルトの実装を上書きすることができます。これにより JDK 1.3 Service Provider 発見処理は、アプリケーションの必要に応じて指定した LogFactory を設置したり作成したりすることができるようになります。詳細については LogFactoryImpl.java の Javadoc をご覧下さい。

機構
  • ライフサイクル

    JCL LogFactory 実装は、ロギングツールキットへの接続/切断、あるいはロギングツールキットのインスタンス化/初期化/破棄のいずれかに対する責任があることを前提とするべきです。

  • 例外処理

    JCL Log インターフェースは処理すべき例外を1つも指定していません。この実装はいかなる例外も catch する必要があります。

  • 複数スレッド

    JCL Log と LogFactory 実装は、ロギングツールキットが必要としている同期化を全て満足するようにしなければなりません。

ロガー設定
  • Log

    JCL によって提供されるデフォルトの LogFactory は、プロパティ org.apache.commons.logging.Log を設定することにより org.apache.commons.logging.Log インターフェースの特定の実装をインスタンス化するように設定することができます。このプロパティはシステムプロパティか、CLASSPATH に存在している必要がある commons-logging.properties ファイルによって指定することができます。

  • プラグインされていない場合のデフォルトのロガー

    Jakarta Commons Logging SPI はシステムプロパティ org.apache.commons.logging.Log によって指定された org.apache.commons.logging.Log インターフェースの実装を利用します。もしこのプロパティが指定されていない場合、あるいはそのクラスが利用できない場合、JCL は CLASSPATH 中で、以下のツールキットを望ましい順に検索することによって、デフォルトのロギングツールキットにアクセスします。

    • Log4J [英語]
    • JDK 1.4
    • JCL SimpleLog

設定

Axis が利用する内部データモデルは、Axis 特有のデータモデルである Web Services Deployment Descriptor (WSDD) に基づいています。Axis は初期時は org.apache.axis.EngineConfiguration のインスタンスから、サービスの WSDD 情報を取得します。

EngineConfiguration は org.apache.axis.EngineConfigurationFactory インターフェースの実装によって提供されます。これは現在のところクライアント設定とサーバ設定を返すメソッドを提供しています。

ここでは EngineConfigurationFactory の実装クラスを定義する方法に焦点を合わせます。

  • 正当化/原理

    Axis の一般的な利用においてはデフォルトの動作で十分ですが、Axis を既存のアプリケーションサーバに統合するには別のデプロイモデルが必要とされます。EngineConfigurationFactory のカスタマイズされた実装は、ホストデプロイモデルから Axis 内部デプロイモデルにマッピングします。

  • 機構

    設定情報を手に入れるため、また Axis を初期化するために利用される、関連する一連の説明は以下の通りです。

    EngineConfigurationFactory factory = EngineConfigurationFactoryFinder(someContext);
    EngineCongfiguration config = factory.getClientEngineConfig();
    AxisClient = new AxisClient(config);

    詳細は様々です (サーバ対クライアント、他のファクトリが関わっているかどうか等)。とにかくポイントは、統合コードは EngineConfigurationFactoryFinder(someContext) を呼ぶ責任があり、その結果を確実に Axis に渡すということです。someContext は、利用される適切な EngineConfigurationFactory の実装 (もしあれば) をファクトリファインダが設置する方法、の鍵となります。

    EngineConfigurationFactoryFinder は以下のように機能します。

    • org.apache.axis.EngineConfigurationFactory を実装するクラスのリストを以下の順で取得します
      • システムプロパティ axis.EngineConfigFactory の値。
      • システムプロパティ org.apache.axis.EngineConfigurationFactory の値。
      • META-INF/services/org.apache.axis.EngineConfigurationFactory という名前の全てのリソースを設置します。そのようなリソースの各行は、そのインターフェースを実装するクラスの名前を識別します ('#' のコメントから、最終行まで)。
      • org.apache.axis.configuration.EngineConfigurationFactoryServlet
      • org.apache.axis.configuration.EngineConfigurationFactoryDefault
    • EngineConfigurationFactory を実装するクラスは以下のメソッドを提供することが求められています。
      public static EngineConfigurationFactory newFactory(Object)
      このメソッドはパラメータとして someContext を渡されて呼ばれます。
    • newFactory メソッドは someContext パラメータをチェックすることが求められています。このチェックは、someContext がクラスにとって意味があるのか (最低限、それが求められている型やクラスであるか検証します) を決めるため、さらには、全体的な実行環境を検査するために行われます。もし EngineConfigurationFactory が必要とする情報をその環境が提供できるのであれば、newFactory() はそのファクトリのインスタンスを返します。さもなければ newFactory() は null を返さなければなりません。
    • EngineConfigurationFactoryFinder はそれが手に入れる null でない最初のファクトリを返します。
  • デフォルトの動作

    上記で説明したように、デフォルトの動作は実装クラスのリストの最後の2つの要素によって提供されます。

    • org.apache.axis.configuration.EngineConfigurationFactoryServlet

      newFactory(obj) が呼ばれます。もし obj instanceof javax.servlet.ServletContext が true であれば、このクラスのインスタンスが返されます。

      デフォルトの Servlet ファクトリはサーバとして機能することが想定されています (クライアントとしてでは、間違って現在の作業ディレクトリから WSDD ファイル client-config.wsdd をロードしようとします)。

      デフォルトの Servlet ファクトリはWebアプリケーションリソースである /WEB-INF/server-config.wsdd をオープンします (このファイル名はシステムプロパティ axis.ServerConfigFile により変更することができます。)。

      • もしこのファイルがアクセス可能なファイルとして存在している (すなわち JAR/WAR ファイルではない) のであれば、それをファイルとしてオープンします。もし変更が Admin ツールにより許されていて、Admin ツールにより変更が行われたら、変更が保存されます。
      • それがファイルとして存在しなければ、リソースストリームとしてアクセスを試みます (getResourceAsStream)。これは JAR/WAR ファイル内容に対して機能します。
      • もしリソースが単純に利用できなければ、それをファイルとして作成しようと試みます。
      • 上記全ての試みが失敗したら、最後の試みとして、org.apache.axis.server.server-config.wsdd にデータストリームとしてアクセスします。
    • org.apache.axis.configuration.EngineConfigurationFactoryDefault

      newFactory(obj) が呼ばれます。もし obj が null であればこのクラスのインスタンスが返されます。デフォルトではないファクトリを必要とするのであれば null でない obj を与えてください。

      デフォルトのファクトリは必要に応じて WSDD ファイル client-config.wsdd あるいは server-config.wsddを現在の作業ディレクトリからロードします。これらのファイル名はそれぞれシステムプロパティ axis.ClientConfigFileaxis.ServerConfigFile により変わる可能性があります。

ハンドラ

ハンドラに関する現在の情報は アーキテクチャガイド をご覧下さい。

国際化

Axis は次の2つ両方を提供することにより国際化をサポートしています。1つめは Axis で利用される文字列のプロパティファイルです。2つめは、内部の Axis メッセージへのアクセスと、既存の Axis コードに基づく統合コードから利用できるメッセージの拡張とを容易にする拡張メカニズムです。

変換
  • 正当化/原理

    英語以外の言語を使う人に Axis を気に入ってもらうために、Axis で利用される文字列を変換する機構を提供しています。Axis ではいかなる変換も提供せず、単に、変換を行う人が簡単に変換をプラグインできる方法を提供しています。

  • 機構

    Axis は英語メッセージを org.apache.axis.i18n.resource.properties (ソースツリーの中では、このファイル名は xml-axis/java/src/org/apache/axis/i18n/resource.properties です) という名前の Java リソースで提供しています。

    Axis は Java 国際化機構を利用しています。それは、プロパティファイルで支えられている java.util.ResourceBundle と、パラメータをメッセージテキストに置換する java.text.MessageFormat クラスです。

    • java.util.ResourceBundle はプログラムで提供されたキーを利用して、プロパティファイルからメッセージテキストを取り出します。メッセージリソースファイルの中のエントリーは <key>=<message> という形式です。
    • java.text.MessageFormat はメッセージテキスト中の目印のついた変数を置換します。目印は、X が0から始まる変数の数を表す "{X}" という文法を利用します。

    例: myMsg00=My {0} is {1}.

    変換は、対象言語のために Axis が提供するプロパティファイルの別のバージョンの作成を必要とします。java.utils.ResourceBundle の JavaDoc は、異なるロケールに対する異なるプロパティファイルを識別する方法の詳細を扱っています。

    Axis の国際化ツールの利用に関する詳細は開発者ガイドをご覧下さい

  • デフォルトの動作

    デフォルトの動作 (つまり指定されたロケールの変換ファイルが存在しない場合に何が起こるかを意味しています) は英語のプロパティファイルに戻されることです。このファイルが存在しなければ (何かが著しくおかしくない限り起こりえませんが) Axis は英語の理由メッセージ付きの例外を投げます。

メッセージファイルの拡張

Axis は、Axis に基づくコードが Axis メッセージキーと同様に、拡張コードに対して唯一の新しいメッセージキーを利用できる、メッセージファイル拡張機構を提供しています。

  • 正当化/原理

    Axis は様々な Axis エンティティに対してプラグイン可能なインターフェース (EngineConfigurationFactory、プロバイダ、ハンドラを含む) を提供しています。また、Axis はこれらのエンティティに対して様々な実装も提供しています。この実装の Axis ソースコードを、エンドユーザの独自のニーズを満たす拡張やカスタマイズを開発するための出発点として利用すると便利です。

  • 手順

    Axis メッセージファイルを拡張するには以下のことを行います。

    • Axis ソースファイル java/src/org/apache/axis/i18n/Messages.java をあなたの project/package、ここでは my/project/package/path/Messages.javaとします、にコピーします。
      • コピーしたファイルの package 宣言に正しいパッケージ名を設定します。
      • プライベート属性 projectName"my.project" に設定します。これはあなたのプロジェクトで共通のパッケージ名の一部です。projectName はコピーした Message パッケージ名と同じかその接頭辞である必要があります。
    • my/project/package/path/resource.properties ファイルを生成します。このファイルに新しいメッセージのキー/値の組を追加します。
    • Axis ソースファイルをあなたのプロジェクトにコピーしたら、import org.apache.axis.i18n.Messages 文を import my.project.package.path.Messages に変更します。
    • 開発者ガイドで述べられているように、新しいメッセージにアクセスするには Message クラスで提供されているメソッドを使用します。
  • 動作
    • ローカル検索

      Messages は自身のパッケージ (Messages) の中にある resources.properties リソース内で キーの値を検索し始めます。

    • 階層検索

      もし Messages がキーもリソースファイルも見つけられなければ、見つけるまでパッケージ階層を上っていきます。階層の頂点、つまりその上は検索しない場所、は projectName 属性で定義します (先ほど設定しました)。

    • デフォルトの動作

      もしパッケージ階層でキーが見つけられなければ、デフォルトリソースが利用されます。デフォルトの動作はあなたの拡張ディレクトリにコピーした Messages クラスの parent 属性で決定されます。

      変更していない限り、デフォルトの動作 (新しいプロパティファイル内でキーが定義されていない時になにが起こるかを意味しています) は、Axis プロパティファイル (org.apache.axis.i18n.resource.properties) に戻ることです。

パフォーマンスモニタリング

Axis は今のところ特定のパフォーマンスモニタリングプラグインを持っていません。

エンコーディング

Axis は今のところエンコーディングプラグインを持っていません。

WSDL パーサとコード生成器フレームワーク

WSDL2Java は WSDL から Java 加工物を生成するための Axis のツールです。このツールには拡張性があります。もし Axis のユーザが Axis を拡張させたいのであれば、生成された加工物も拡張、あるいは変更する必要があります。例えば、もし Axis が、Axis のデプロイモデルと異なる既存のデプロイモデルを持つ製品に挿入されたら、その製品の WSDL2Java バージョンは Axis の deploy.wsdd と異なるデプロイメントディスクリプタを生成する必要があります。

これ以降はフレームワークの説明に移ります。もし代わりに examples [リンク切れ] の泥の中に飛び込めば、それらから多くのことを学べるでしょう。その後ここに戻ってくれば流血場面の詳しい描写を知ることができます。

WSDL2Java は3部から構成されています。

  1. シンボルテーブル
  2. パーサフロントエンドと生成器フレームワーク
  3. コード生成器バックエンド (WSDL2Java 自身)
シンボルテーブル

org.apache.axis.wsdl.symbolTable にあるシンボルテーブルは、WSDL ドキュメントからの全てのシンボル、つまり WSDL 構造自身 (portType、binding 等) からのシンボルと、WSDL が参照する XML スキーマ型の両方を持っています。

注意: ここにたくさんの説明が必要です。

シンボルテーブルは拡張可能ではありませんが、動的変数構造を利用してシンボルテーブルにフィールドを追加することはできます

  • 動的変数キーには定数オブジェクトが必要です。例: public static final String MY_KEY = "my key";
  • その変数の値を GeneratorFactory.generatorPass に設定します: entry.setDynamicVar(MY_KEY, myValue);
  • 生成器内の変数の値を取得します: Object myValue = entry.getDynamicVar(MY_KEY);
パーサフロントエンドと生成器フレームワーク

パーサフロントエンドと生成器フレームワークは in org.apache.axis.wsdl.gen にあります。パーサフロントエンドは2つのファイルから構成されています。

  • Parser
    public class Parser {
      public Parser();
      public boolean isDebug();
      public void setDebug(boolean);
      public boolean isImports();
      public void setImports(boolean);
      public boolean isVerbose();
      public void setVerbose(boolean);
      public long getTimeout();
      public void setTimeout(long);
      public java.lang.String getUsername();
      public void setUsername(java.lang.String);
      public java.lang.String getPassword();
      public void setPassword(java.lang.String);
      public GeneratorFactory getFactory();
      public void setFactory(GeneratorFactory);
      public org.apache.axis.wsdl.symbolTable.SymbolTable getSymbolTable();
      public javax.wsdl.Definition getCurrentDefinition();
      public java.lang.String getWSDLURI();
      public void run(String wsdl) throws java.lang.Exception;
      public void run(String context, org.w3c.dom.Document wsdlDoc)
        throws java.io.IOException, javax.wsdl.WSDLException;
    }

    このクラスの基本的な動作は単純です。Parser をインスタンス化して実行するだけです。

    Parser parser = new Parser();
    parser.run("myfile.wsdl");

    パーサにはアクセッサメソッドを持った様々なオプションがあります。

    • debug - デフォルトは false - WSDL ファイルのパース後にシンボルテーブルをダンプする
    • imports - デフォルトは true - インポートファイルを訪れるかどうか
    • verbose - デフォルトは false - パース中にそれぞれのファイルをリストアップする
    • timeout - デフォルトは 45 - パースを停止する前に待つ秒数
    • username - デフォルトなし - protected URI のために必要
    • password - デフォルトなし - protected URI のために必要

    パーサのその他のメソッド

    • get/setFactory - このパーサの GeneratorFactory を取得、あるいは設定する - 詳細については下をご覧下さい。デフォルトの生成器ファクトリは NoopFactory で、これはなにも生成しません。
    • getSymbolTable - 一度 run メソッドが呼ばれると、シンボルテーブルが住みつき、クエリーすることができるようになります。
    • getCurrentDefinition - 一度 run メソッドが呼ばれると、パーサは与えられた wsdl ファイルを表す Definition オブジェクトを持つようになります。Definition は WSDL4J オブジェクトです。
    • getWSDLURI - 文字列を引数に取る run メソッドが一度呼ばれると、パーサは WSDL ファイルの場所を示す文字列を持つようになります。その他の run メソッド - run(String context, Document wsdlDoc) - は wsdl ファイルの場所を提供しないことに注意してください。この run メソッドが使用されると getWSDLURI は null になります。
    • 2つの run メソッドがあります。1つめは上で示した通り、WSDL ファイルの場所を表す URI 文字列を引数に取るメソッドです。もしすでに WSDL ファイルを XML Document にパースしているのであれば、コンテキストと WSDL Document を引数に取る2つめのメソッドを使用することができます。

    このクラスの拡張は ...

    注意: この言葉を続けてください ...

  • WSDL2

    Parser は、WSDL パーサ内の、プログラムに従ったインターフェースです。WSDL2 は WSDL パーサのためのコマンドラインツールです。WSDL2 はコマンドラインから Parser を呼ぶための拡張可能なフレームワークを提供しています。WSDL2 の拡張は WSDL2Java、WSDL2Lisp、WSDL2XXX のように WSDL2 で始まるので WSDL2 という名前がつけられました。

    public class WSDL2 {
      protected WSDL2();
      protected Parser createParser();
      protected Parser getParser();
      protected void addOptions(org.apache.axis.utils.CLOptionDescriptor[]);
      protected void parseOption(org.apache.axis.utils.CLOption);
      protected void validateOptions();
      protected void printUsage();
      protected void run(String[]);
      public static void main(String[]);
    }

    優れたコマンドラインツールと同じように、WSDL2 には main メソッドがあります。しかしながら、いくつかのコマンドラインツールと違い、WSDL2 のメソッドは static ではありません。static メソッドには拡張性がありません。static メソッドを呼ぶ替わりに、WSDL2 の main メソッドは自身のインスタンスを生成し、そのインスタンスのメソッドを呼びます。これらのメソッドはある動作パターンに従います。main メソッドはとても単純です。

    public static void main(String[] args) {
      WSDL2 wsdl2 = new WSDL2();
      wsdl2.run(args);
    }

    WSDL2 のコンストラクタは createParser を呼び、Parser や Parser の拡張を構築します。

    run は以下のものを呼びます。

    • parseOption。各コマンドラインオプションをパースし、適切な Parser アクセッサを呼びます。例えばこのメソッドが --verbose をパースした際は parser.setVerbose(true) を呼びます。
    • validateOptions。全てのオプション値に一貫性があるか確かめます。
    • printUsage。このツールの使い方が間違っていた場合。
    • parser.run(args);

    もし拡張されたものに追加されたオプションがあれば、run を呼ぶ前に addOptions を呼ぶことが求められています。それにより拡張されたものは必要に応じて getParser、addOptions、run を呼びます。拡張されたものは必要に応じて createParser、parseOption、validateOptions、printUsage を上書きします。

    生成器フレームワークは2つのファイルから構成されます。

    • Generator

      Generator インターフェースはとても単純です。単に generate メソッドを定義しています。

      public interface Generator
      {
        public void generate() throws java.io.IOException;
      }
    • GeneratorFactory
      public interface GeneratorFactory
      {
        public void generatorPass(javax.wsdl.Definition, SymbolTable);
        public Generator getGenerator(javax.wsdl.Message, SymbolTable);
        public Generator getGenerator(javax.wsdl.PortType, SymbolTable);
        public Generator getGenerator(javax.wsdl.Binding, SymbolTable);
        public Generator getGenerator(javax.wsdl.Service, SymbolTable);
        public Generator getGenerator(TypeEntry, SymbolTable);
        public Generator getGenerator(javax.wsdl.Definition, SymbolTable);
        public void setBaseTypeMapping(BaseTypeMapping);
        public BaseTypeMapping getBaseTypeMapping();
      }

      GeneratorFactory インターフェースは生成器を取得するためにパーサが利用するメソッドを定義しています。WSDL 構造それぞれ (message、portType 等 - これらは WSDL4J のクラスである javax.xml.Message、javax.xml.PortType 等に依存していることに注意してください) の生成器、スキーマ型の生成器、WSDL Definition 自身の生成器が必要です。この最後の生成器は前述のカテゴリに収まらないものを生成するのに利用されます。

      getGeneratorMethod に加え、GeneratorFactory は generatorPass メソッドを定義しています。このメソッドはファクトリ実装に、実際の生成が始まる前に前処理を行うためにシンボルテーブルを歩き回る機会を与えます。

      基本型マッピングのアクセッサも定義されています。これらは QName を与えられたターゲットマッピング内の基本型に変換するのに利用されます。

    Parser、WSDL2、Generator、GeneratorFactory に加え、org.apache.axis.wsdl.gen パッケージもいくつかの操作のないクラス、NoopGenerator と NoopFactory を持っています。NoopGenerator は、全ての WSDL 構造に対して加工物を生成する必要がない拡張にとって便利なクラスです。例えば、WSDL2Java は message に対して何も生成しませんので、message ファクトリの getGenerator(Message, SymbolTable) メソッドは NoopGenerator を返します。NoopFactory は全ての getGenerator メソッドに対して NoopGenerator を返します。Parser のデフォルトのファクトリは NoopFactory です。

コード生成器バックエンド

WSDL2Java バックエンド生成器の要点は org.apache.axis.wsdl.toJava にあります。Emitter は Parser を拡張しています。org.apache.axis.wsdl.WSDL2Java は WSDL2 を拡張しています。JavaGeneratorFactory は GeneratorFactory を実装しています。様々な JavaXXXWriter クラスは Generator インターフェースを実装しています。

注意: ここにもっと説明が必要...

WSDL フレームワーク拡張例

上記全てはいくぶん複雑に聞こえます。実際複雑ですが、それはあたなの拡張が複雑であるべきだということを意味していません。

例 1 - WSDL2Java の簡単な拡張 - 付加的な加工物

このフレームワークの最も簡単な拡張は、WSDL2Java が既に生成したもの全てと、さらに何か新しいものを生成する拡張です。例1はそのような拡張です。余分な加工物は、サービスの port をリストアップする、各サービスのファイルです。これを作成する理由はありませんが、簡単でよい例となるでしょう。この例の完全な実装については samples/integrationGuide/example1 をご覧下さい。

  • まず最初に新しい加工物を書き出す writer を作成する必要があります。この新しいクラスは org.apache.axis.wsdl.toJava.JavaWriter を拡張します。JavaWriter はその拡張に対して動作を指示します。JavaWriter は writeFileHeader と writeFileBody を呼びます。この例ではファイルヘッダを気にしないので、writeFileHeader は操作のないメソッドです。writeFileBody がこの writer の実際の作業を行います。
    public class MyListPortsWriter extends JavaWriter {
      private Service service;
      public MyListPortsWriter(
          Emitter emitter,
          ServiceEntry sEntry,
          SymbolTable symbolTable) {
        super(emitter,
              new QName(
                sEntry.getQName().getNamespaceURI(),
                sEntry.getQName().getLocalPart() + "Lst"),
              "",
              "lst",
              "Generating service port list file",
              "service list");
        this.service = sEntry.getService();
      }
      protected void writeFileHeader() throws IOException {
      }
      protected void writeFileBody() throws IOException {
        Map portMap = service.getPorts();
        Iterator portIterator = portMap.values().iterator();
    
        while (portIterator.hasNext()) {
          Port p = (Port) portIterator.next();
          pw.println(p.getName());
        }
        pw.close();
      }
    }
  • 次に main プログラムが必要です。この main プログラムは WSDL2Java を拡張することによって、WSDL2Java の全ての機能を利用することができます。このツールは主に3つのことを行います。
    • 自身をインスタンス化します。
    • WSDL service の生成器のリストに MyListPortsWriter を追加します。
    • run メソッドを呼びます。

    これで全てです。基本ツールが残りの作業全てを行ってくれます。

    public class MyWSDL2Java extends WSDL2Java {
    
      public static void main(String args[]) {
        MyWSDL2Java myWSDL2Java = new MyWSDL2Java();
    
        JavaGeneratorFactory factory =
            (JavaGeneratorFactory) myWSDL2Java.getParser().getFactory();
        factory.addGenerator(Service.class, MyListPortsWriter.class);
    
        myWSDL2Java.run(args);
      }
    }
例 2 - それほど簡単ではない WSDL2Java の拡張 - 加工物の変更

この例では deploy.wsdd を mydeploy.useless に置き換えます。簡単に言うと、mydeploy.useless は少々役に立ちません。これを有用にするのは読者の課題にしておきます。この例の完全な実装は samples/integrationGuide/example2 をご覧下さい。

  • まず、以下に mydeploy.useless の writer を示します。この新しいクラスは org.apache.axis.wsdl.toJava.JavaWriter を拡張しています。JavaWriter はその拡張に対して動作を指示します。JavaWriter は writeFileHeader と writeFileBody を呼びます。この例ではファイルヘッダを気にしないので、writeFileHeader は操作のないメソッドです。writeFileBody がこの writer の実際の作業を行います。writeFileBody は単に、ユーザの入力に依存するちょっとした歌を書き出します。

    generate メソッドも上書きしたことに注意してください。パーサは常に generate を呼びますが、これはサーバ側の加工物なので、サーバ側の加工物を生成していない (言い換えれば、コマンドラインオプションで --serverSide オプションを指定しない) 限り、それを生成したくはありません。

    public class MyDeployWriter extends JavaWriter {
      public MyDeployWriter(Emitter emitter, Definition definition,
          SymbolTable symbolTable) {
        super(emitter,
              new QName(definition.getTargetNamespace(), "deploy"),
              "",
              "useless",
              "Generating deploy.useless", "deploy");
      }
      public void generate() throws IOException {
        if (emitter.isServerSide()) {
          super.generate();
        }
      }
      protected void writeFileHeader() throws IOException {
      }
      protected void writeFileBody() throws IOException {
        MyEmitter myEmitter = (MyEmitter) emitter;
        if (myEmitter.getSong() == MyEmitter.RUM) {
          pw.println("Yo!  Ho!  Ho!  And a bottle of rum.");
        }
        else if (myEmitter.getSong() == MyEmitter.WORK) {
          pw.println("Hi ho!  Hi ho!  It's off to work we go.");
        }
        else {
          pw.println("Feelings...  Nothing more than feelings...");
        }
        pw.close();
      }
    }
  • 前回の例で行ったように単に WSDL2Java に追加するのではなく、WSDL2Java が生成するものを変更しているので、addGenerator を呼ぶのは十分ではありません。WSDL2Java が生成するものを変更するには、生成器ファクトリを作成して自分の生成器を提供する必要があります。WSDL2Java の加工物のほとんどを持ち続けたいので単純に WSDL2Java のファクトリ - JavaGeneratorFactory - を拡張し、addDefinitionGenerators メソッドを上書きします。
    public class MyGeneratorFactory extends JavaGeneratorFactory {
      protected void addDefinitionGenerators() {
        // WSDL2Java's JavaDefinitionWriter
        addGenerator(Definition.class, JavaDefinitionWriter.class);
    
        // our DeployWriter
        addGenerator(Definition.class, MyDeployWriter.class);
    
        // WSDL2Java's JavaUndeployWriter
        addGenerator(Definition.class, JavaUndeployWriter.class);
      }
    }
  • ここで私達のツールに API を書く必要があります。オプション - song - を追加したので、プログラムに従った API - Parser の拡張 (実際この場合は Emitter です。なぜなら私達は WSDL2Java を拡張していて、Emitter は WSDL2Java パーサの拡張だからです。) - とコマンドライン API の両方を必要としています。

    ここにプログラムに従った API を示します。Emitter に song アクセッサを追加しています。さらにコントラクタ内で、ファクトリが出力器について、そして出力器がファクトリについて識別するようにしています。

    public class MyEmitter extends Emitter {
      public static final int RUM  = 0;
      public static final int WORK = 1;
      private int song = -1;
    
      public MyEmitter() {
        MyGeneratorFactory factory = new MyGeneratorFactory();
        setFactory(factory);
        factory.setEmitter(this);
      }
      public int getSong() {
        return song;
      }
      public void setSong(int song) {
        this.song = song;
      }
    }

    そしてここにコマンドライン API を示します。これは前の例の main プログラムに比べて多少複雑ですが、たった2つの余分なことしかしません。

    1. 新しいコマンドラインオプション --song rum|work を受け付けます (新たな仕事の内、これが一番大きな塊です)。
    2. Parser の新しいサブクラスを作成します。
    public class WSDL2Useless extends WSDL2Java {
      protected static final int SONG_OPT = 'g';
      protected static final CLOptionDescriptor[] options
        = new CLOptionDescriptor[]{
            new CLOptionDescriptor("song",
                CLOptionDescriptor.ARGUMENT_REQUIRED,
                SONG_OPT,
                "Choose a song for deploy.useless:  work or rum")
      };
    
      public WSDL2Useless() {
        addOptions(options);
      }
      protected Parser createParser() {
        return new MyEmitter();
      }
      protected void parseOption(CLOption option) {
        if (option.getId() == SONG_OPT) {
          String arg = option.getArgument();
          if (arg.equals("rum")) {
            ((MyEmitter) parser).setSong(MyEmitter.RUM);
          }
          else if (arg.equals("work")) {
            ((MyEmitter) parser).setSong(MyEmitter.WORK);
          }
        }
        else {
          super.parseOption(option);
        }
      }
      public static void main(String args[]) {
        WSDL2Useless useless = new WSDL2Useless();
    
        useless.run(args);
      }
    }

    これについて1メソッドずつ見ていきましょう。

    • コンストラクタ - このコンストラクタは新しいオプション --song rum|work を追加します。(このオプションの省略版は "-g" です。いくぶん奇妙な省略ですが、"-s" は --serverSide の省略で、"-S" は --skeletonDeploy の省略です。残念。それで異なる文字を選んだのです。)
    • createParser - 親クラスが私達の Parser 拡張を得られる方法を提供しなくてはいけません。
    • parseOption - このメソッドは私達の新しいオプションを処理します。もし与えられたオプションが私達のものでなければ、この仕事を super.parseOption にさせます。
    • main - 実際にはこの main は最初の例の main よりも簡単です。最初の main は生成器のリストに私達の生成器を追加する必要がありました。この例ではファクトリが既にそれを行ったので、この main ですることは自身をインスタンス化して自身を run させるだけです。

クライアント SSL

デフォルトのプラグイン可能なセキュリティソケットファクトリモジュール (プラグイン可能 API をご覧下さい) は JSSE セキュリティを利用します。あなたの実行時環境への JSSE のインストール、登録、設定に関する詳細は JSSE ドキュメントをご覧下さい。