バージョン 7.0
資料番号 GD88-6860-00
第 1 刷 (2008 年 6 月)
この版は、以下のプログラムに適用されます。
また、新しい版で明記されていない限り、以降のすべてのリリースおよびモディフィケーションに適用されます。
資料を注文する場合は、IBM 担当者または最寄りの IBM 営業所にご連絡ください。
(C) Copyright International Business Machines Corporation 2008. All rights reserved.
このセクションでは、本書「WebSphere(R) Application Server Edge Components プログラミング・ガイド」の目的、編成、および規則について説明します。
本書では、WebSphere Application Server バージョン 7.0. の Edge Components をカスタマイズするために使用できるアプリケーション・プログラミング・インターフェース (API) について説明します。 この情報は、プラグイン・アプリケーションを作成したり、その他のカスタマイズを行う プログラマーを対象としています。 ネットワーク設計者およびシステム管理者にとっても、この情報は可能なカスタマイズ・タイプの指示として役立つ場合があります。
本書をご利用の際には、使用予定の API に応じて、Java(TM) または C プログラミング言語を使用した プログラミング手順を理解している必要があります。 公開された各インターフェースで使用可能なメソッドおよび構造について文書化していますが、独自のアプリケーションの構成方法、ユーザー・システム用のコンパイル方法、および検査方法を知っている必要があります。一部のインターフェースには サンプル・コードが提供されていますが、このサンプルは独自のアプリケーションを 構成するための例としてのみ提供されています。
本書では、以下のような書体およびキー操作の規則を使用しています。
規則 | 意味 |
---|---|
太字 | グラフィカル・ユーザー・インターフェース (GUI) に関しては、太字は、メニュー、メニュー項目、 ラベル、ボタン、アイコン、およびフォルダーを示します。 また、太字にしないと周りのテキストと混同される恐れがあるコマンド名を強調するためにも 使用されます。 |
モノスペース | コマンド・プロンプトから入力する必要のあるテキストを示します。 また、モノスペースは、画面上のテキスト、コード例、およびファイルからの引用も示します。 |
イタリック | 指定する必要のある可変値を示します (例: fileName に ファイルの名前を指定します)。 イタリックは、強調表示および書名の表示にも使用されます。 |
Ctrl-x | x がキーの名前である場合、制御文字のシーケンスを示します。例えば、 Ctrl-c は、Ctrl キーを押しながら c キーを押すという意味になります。 |
Return | Return、Enter または左矢印が表示されているキーを指します。 |
% | root 権限を必要としないコマンド用の Linux および UNIX(R) コマンド・シェル・プロンプトを示します。 |
# | root 権限を必要とするコマンド用の Linux および UNIX コマンド・シェル・プロンプトを示します。 |
C:¥ | Windows のコマンド・プロンプトを示します。 |
コマンド入力 | コマンドを「入力」または「発行」するよう指示されたときは、コマンドを入力してから Return を押します。 例えば、「ls コマンドを入力してください」という指示が出された場合には、コマンド・プロンプトに ls と入力してから Return を押すという意味になります。 |
[ ] | 構文記述内のオプション項目を囲みます。 |
{ } | 構文記述内の、項目を選択する必要があるリストを囲みます。 |
| | 構文記述の中で { } (中括弧) で囲まれた選択項目リストにある項目を区切るために使用されます。 |
... | 構文記述内の省略記号は、前の項目を 1 回以上繰り返すことができることを示します。 例にある省略記号は、簡潔にするために例から情報が省略されていることを示します。 |
アクセシビリティー機能は、運動障害または視覚障害など身体に障害を持つユーザーがソフトウェア・プロダクトを快適に使用できるようにサポートします。 WebSphere Application Server バージョン 7.0 の主なアクセシビリティー機能は次のとおりです。
IBM にお客様のご意見をお寄せください。本書または WebSphere Application Server の Edge Components に関するその他の資料についてお気付きの点がありましたら、次のようにしてください。
本書では、WebSphere Application Server の Edge Components のために提供されるアプリケーション・プログラム・インターフェース (API) について説明します。 (WebSphere Application Server の Edge Components には、Caching Proxy と Load Balancer が含まれます。) 管理者は提供されるいくつかのインターフェースを使用して 環境をカスタマイズしたり、Edge Components 相互間の対話方法を変更したり、 他のソフトウェア・システムと対話できるようにしたりすることができます。
重要: Caching Proxy は、すべての Edge Components 環境で使用可能です。ただし、以下の例外があります。
本書の API はいくつかのカテゴリーを扱っています。
Caching Proxy の処理シーケンスにはいくつかのインターフェースが書き込まれていて、カスタム処理を追加したり標準処理の代わりに使用したりできます。実行できるカスタマイズには、以下のようなタスクの変更および拡大が含まれます。
カスタム・アプリケーション・プログラムは、Caching Proxy プラグインとも呼ばれ、プロキシー・サーバーの処理シーケンス中の、事前に定義されたポイントで呼び出されます。
Caching Proxy API は、特定のシステム機能を実装するために使用されています。 例えば、プロキシー・サーバーの LDAP サポートはプラグインとして実装されます。
Caching Proxy API では、インターフェースについて詳しく説明します。これには、プラグイン・プログラムを使用するようにプロキシー・サーバーを構成するためのステップが含まれます。
ユーザー独自の advisor を作成することによって、Load Balancer をカスタマイズできます。 advisor はサーバー上で実際のロード測定を実行します。 カスタム advisor があれば、ロードを測定するためのシステムに 関連する、自分で用意したメソッドを使用することができます。 これは特に、カスタマイズ済みまたは所有 Web サーバー・システムがある場合に重要です。
カスタム advisor では、カスタム advisor の作成および使用の詳細について説明します。 これには、advisor のサンプル・コードも含まれます。
上記の API のサンプル・コードは、Edge Components CD-ROM の samples ディレクトリーに入っています。 追加のコード・サンプルを WebSphere Application Server Web サイト www.ibm.com/software/webservers/appserv/ から入手できます。
このセクションでは、Caching Proxy アプリケーション・プログラミング・インターフェース (API) の概念、 利点、および仕組みについて説明します。
重要: Caching Proxy は、すべての Edge Components 環境で使用可能です。ただし、以下の例外があります。
この API は Caching Proxy へのインターフェースであり、これを使用してプロキシー・サーバーの基本機能を拡張することができます。 拡張機能またはプラグインを作成し、次の例を含むカスタマイズされた処理を実行できます。
Caching Proxy API には、以下の利点があります。
Caching Proxy プラグイン・プログラムを作成する前に、プロキシー・サーバーがどのように機能するのかを理解しておく必要があります。 プロキシー・サーバーの振る舞いは、いくつかの別個の処理ステップに分けることができます。 これらのそれぞれのステップで、API を使用して独自にカスタマイズした機能を使用することが可能です。 例えば、 ある処理をクライアント要求の読み取り後、他の処理を行う前に行う、あるいは特殊ルーチンを認証時に実行してから、 要求ファイルの送信後に再度行うなどを決めます。
事前定義機能のライブラリーには API が備わっています。 ご使用のプラグイン・プログラムは、プロキシー・サーバー・プロセス (例えば、要求の操作、要求ヘッダーの読み取りまたは書き込み、あるいはプロキシー・サーバーのログへの書き込みなど) と対話するために事前定義 API 関数を呼び出すことができます。 これらの関数を、ご自分で作成したプラグイン関数と混同しないでください。プラグイン関数は、プロキシー・サーバーによって呼び出されます。 事前定義関数については、事前定義関数およびマクロで説明しています。
サーバー構成ファイル内の対応する Caching Proxy API ディレクティブを使用して 適切なステップでプラグイン関数を呼び出すように、プロキシー・サーバーに対して指示します。 これらのディレクティブについては、API ステップの Caching Proxy 構成ディレクティブで説明します。
本書には、次の内容が含まれています。
以下のコンポーネントと手順を使用して独自の Caching Proxy プラグイン・プログラムを作成することができます。
プロキシー・サーバーの基本操作は、そのフェーズでサーバーが実行する処理のタイプに基づいて、いくつかのステップに分けることができます。 各ステップには、プログラムの指定された部分を実行できる接続点があります。Caching Proxy 構成ファイル (ibmproxy.conf) に API ディレクティブを追加することによって、特定のステップで呼び出すプラグイン関数を指定します。 そのステップに複数のディレクティブを組み込むことによって、特定のプロセス・ステップで 複数のプラグイン関数を呼び出すことができます。
いくつかのステップはサーバー要求プロセスの一部です。 つまり、プロキシー・サーバーは、要求を処理するたびにこれらのステップを実行します。 その他のステップは要求処理とは無関係に実行されます。 つまり、要求が処理されているかどうかにかかわらず、 サーバーはこれらのステップを実行します。
コンパイルされたプログラムは、オペレーティング・システムに応じて、 いずれかの共用オブジェクト (例えば、DLL または .so ファイル) に入っています。 サーバーは、その要求プロセス・ステップを進めながら、いずれかの関数が要求の 処理を終えたことを示すまでは、各ステップに関連付けられたプラグイン関数を呼び出します。 特定のステップのプラグイン関数が複数ある場合は、これらの関数は構成ファイル内に あるディレクティブの順序で呼び出されます。
要求がプラグイン関数によって処理されない (そのステップに関する Caching Proxy API ディレクティブを 組み込まなかったか、そのステップのプラグイン関数が HTTP_NOACTION を戻した) 場合には、サーバーはそのステップのためのデフォルト・アクションを実行します。
注 : これは、Service ステップを除くすべてのステップにあてはまります。Service ステップにはデフォルト・アクションはありません。
図 1 は、プロキシー・サーバー・プロセスのステップを表し、要求処理に関連するステップの処理順序を定義しています。
図 1. プロキシー・サーバー・プロセスにおけるステップのフローチャート
この図の中の 4 つのステップは、クライアント要求の処理とは無関係に実行されます。 これらのステップは、プロキシー・サーバーの実行および保守に関連しています。 これらのステップには以下が含まれます。
以下のリストは、図 1 に示した各ステップの目的を示しています。必ずしもすべてのステップが特定の要求で呼び出されるわけではありません。
要求が読み込まれた後、まだ何も実行されないうちに処理を実行します。
このステップで要求が処理されたことを示す標識 (HTTP_OK) が戻された場合には、 サーバーは要求プロセスの他のステップをバイパスし、Transmogrifier、Log、および PostExit ステップだけを実行します。
保管されたセキュリティー・トークンを使用して保護、ACL、およびその他のアクセス制御用の 物理パスを検査し、基本認証に必要な WWW 認証ヘッダーを生成します。 独自のプラグイン関数を作成してこのステップを置き換える場合は、これらのヘッダーを 自分で生成しなければなりません。
詳しくは、認証および許可を参照してください。
セキュリティー・トークンのデコード、検査、および保管を行います。
詳しくは、認証および許可を参照してください。
許可およびオブジェクト検索後に (ただし要求が満たされる前に) 処理を実行します。
このステップで要求が処理されたことを示す標識 (HTTP_OK) が戻された場合には、 サーバーは要求プロセスの他のステップをバイパスし、Transmogrifier、Log、および PostExit ステップだけを実行します。
AIX(R) システムでは、プラグイン関数をリストするエクスポート・ファイル (例えば libmyapp.exp) が必要であり、Caching Proxy API インポート・ファイル libhttpdapi.exp とリンクする必要があります。
Linux、HP-UX、および Solaris システムでは、libhttpdapi および libc ライブラリーと リンクする必要があります。
Windows(R) システムでは、プラグイン関数をリストするモジュール定義ファイル (.def) が必要であり、HTTPDAPI.LIB とリンクする必要があります。
関数定義に HTAPI.h を組み込み、HTTPD_LINKAGE マクロを使用します。このマクロを使用すると、すべての関数で必ず同じ呼び出し規則を使用できます。
以下のコンパイル・コマンドおよびリンク・コマンドを、ガイドラインとして使用します。
cc_r -c -qdbxextra -qcpluscmt foo.c
cc_r -bM:SRE -bnoentry -o libfoo.so foo.o -bI:libhttpdapi.exp -bE:foo.exp
(このコマンドは、読みやすくするために 2 行にわたって示されています。)
cc -Ae -c +Z +DAportable
aCC +Z -mt -c +DAportable
gcc -c foo.c
ld -G -Bsymbolic -o libfoo.so foo.o -lhttpdapi -lc
cc -mt -Bsymbolic -c foo.c
cc -mt -Bsymbolic -G -o libfoo.so foo.o -lhttpdapi -lc
cl /c /MD /DWIN32 foo.c
link httpdapi.lib foo.obj /def:foo.def /out:foo.dll /dll
エクスポートを指定するには、以下のいずれかの方法を使用します。
定義済み要求処理ステップ用に独自のプログラム関数を作成する場合は、プラグイン関数プロトタイプに示した構文に従ってください。
各ユーザー関数では、実行されたアクションを示す値が 戻りコード・パラメーターに使用される必要があります。
Caching Proxy ステップごとの関数プロトタイプは、使用する形式を示し、それらが実行できる処理のタイプを記述します。 関数名は事前定義されないので、注意してください。関数には固有の名前を指定する必要がありますが、 命名規則は自由に決めることができます。 わかりやすくするため、本書では、サーバーの処理ステップに関連する名前を使用しています。
各プラグイン関数で、特定の事前定義 API 関数が有効です。 すべてのステップで無効な事前定義関数もあります。 以下の事前定義 API 関数は、これらのどのプラグイン関数からでも呼び出すことができます。
その他の有効または無効な API 関数については、関数のプロトタイプの説明に 示されています。
関数に送られる handle パラメーターの値は、 最初の引数として事前定義関数に渡すことができます。 事前定義された API 関数については、事前定義関数およびマクロで説明しています。
void HTTPD_LINKAGE ServerInitFunction ( unsigned char *handle, unsigned long *major_version, unsigned long *minor_version, long *return_code )
このステップに定義された関数は、サーバー初期化の間のモジュールのロード時に一度呼び出されます。初期化を行うことができるのはいずれかの要求が受け入れられる前です。
すべてのサーバー初期化関数が呼び出されますが、このステップの関数から エラー戻りコードが戻されると、サーバーはエラー・コードを戻した関数と 同じモジュールで構成された他のすべての関数を無視します。 (つまり、エラーを戻した関数と同じ共用オブジェクトに入っている 関数はどれも呼び出されません。)
バージョン・パラメーターにはプロキシー・サーバーのバージョン番号が含まれます。バージョン・パラメーターは Caching Proxy によって提供されます。
void HTTPD_LINKAGE PreExitFunction ( unsigned char *handle, long *return_code )
このステップに定義された関数は、要求が読み取られた後、処理が行われる前に それぞれの要求ごとに呼び出されます。 このステップのプラグインを使用することにより、クライアントの要求が Caching Proxy によって処理される前に、この要求にアクセスできます。
preExit 関数の有効な戻りコードは次のとおりです。
その他の戻りコードは使用しないでください。
この関数が HTTP_OK を戻した場合、プロキシー・サーバーは、その要求が処理されたものと想定します。 それ以降のすべての要求処理ステップはバイパスされ、応答ステップ (Transmogrifier、 Log、および PostExit) のみが実行されます。
void HTTPD_LINKAGE MidnightFunction ( unsigned char *handle, long *return_code )
このステップで定義された関数は毎日、真夜中に実行されます。要求コンテキストは含まれていません。 例えば、この関数はログを分析する子プロセスを起動するために使用できます。 (このステップで処理が長引くと、ロギングの妨げになる可能性があることに注意してください。)
void HTTPD_LINKAGE AuthenticationFunction ( unsigned char *handle, long *return_code )
このステップで定義された関数は、要求の認証方式に基づいて要求ごとに呼び出されます。 この関数は、要求とともに送信されるセキュリティー・トークンの検査を カスタマイズするために使用できます。
void HTTPD_LINKAGE NameTransFunction ( unsigned char *handle, long *return_code )
このステップで定義された関数は、要求ごとに呼び出されます。 テンプレートと一致する要求のみについてプラグイン関数が呼び出されるようにしたい場合は、 URL テンプレートを構成ファイル・ディレクティブに指定します。 Name Translation ステップは要求が処理される前に実行され、URL を ファイル名などのオブジェクトにマッピングするためのメカニズムを提供します。
void HTTPD_LINKAGE AuthorizationFunction ( unsigned char *handle, long *return_code )
このステップで定義された関数は、要求ごとに呼び出されます。 テンプレートと一致する要求のみについてプラグイン関数が呼び出されるようにしたい場合は、 URL テンプレートを構成ファイル・ディレクティブに指定します。 Authorization ステップは要求が処理される前に実行され、 識別されたオブジェクトをクライアントに戻すことができるかどうかを 検査するために使用できます。基本認証を行う場合は、必要な WWW 認証ヘッダーを生成しなければなりません。
void HTTPD_LINKAGE ObjTypeFunction ( unsigned char *handle, long *return_code )
このステップで定義された関数は、要求ごとに呼び出されます。 テンプレートと一致する要求のみについてプラグイン関数が呼び出されるようにしたい場合は、 URL テンプレートを構成ファイル・ディレクティブに指定します。 Object Type ステップは要求が処理される前に実行され、 オブジェクトが存在するかどうかを調べてオブジェクトの型定義を行うために使用できます。
void HTTPD_LINKAGE PostAuthFunction ( unsigned char *handle, long *return_code )
このステップで定義された関数は、要求を許可してから処理が起こるまえに呼び出されます。 この関数が HTTP_OK を戻した場合、プロキシー・サーバーは、その要求が処理されたものと想定します。 それ以降のすべての要求ステップはバイパスされ、応答ステップ (Transmogrifier、 Log、および PostExit) のみが実行されます。
void HTTPD_LINKAGE ServiceFunction ( unsigned char *handle, long *return_code )
このステップで定義された関数は、要求ごとに呼び出されます。 テンプレートと一致する要求のみについてプラグイン関数が呼び出されるようにしたい場合は、 URL テンプレートを構成ファイル・ディレクティブに指定します。 Service ステップは、要求が PreExit または PostAuthorization ステップで 満たされなかった場合に、この要求を満たします。
このステップ中は、サーバー事前定義関数はすべて有効です。
URL ではなく HTTP メソッドに基づいて実行する Service 関数を構成するための情報については、「WebSphere Application Server Caching Proxy 管理ガイド」の Enable ディレクティブの項を参照してください。
このステップには、以下の 4 つの関数をインプリメントしなければなりません。 (使用する関数名は、以下で使用されているものと同じでなくてもかまいません。)
void * HTTPD_LINKAGE openFunction ( unsigned char *handle, long *return_code )
open 関数は、このストリームのデータの処理に必要な 初期化 (バッファー割り振りなど) を実行します。 HTTP_OK 以外の戻りコードが戻されると、このフィルターは打ち切りになります (write 関数も close 関数も呼び出されません)。 関数は void ポインターを戻すことができるので、構造にスペースを割り振り、後続の関数の correlator パラメーターで戻されるポインターをもつことができます。
void HTTPD_LINKAGE writeFunction ( unsigned char *handle, unsigned char *data, /* response data sent by the origin server */ unsigned long *length, /* length of response data */ void *correlator, /* pointer returned by the 'open' function */ long *return_code )
write 関数はデータを処理し、新規または変更データを指定して サーバーの事前定義 HTTPD_write() 関数を呼び出すことができます。 プラグイン側では、渡されたバッファーを解放しないでください。 また、サーバーが受け取ったバッファーを解放することもありません。
write 関数の有効範囲でデータを変更しないようにする場合は、open、 write、または close 関数の有効範囲で HTTPD_write() 関数を呼び出して、 クライアントへの応答に対してデータを渡す必要があります。 correlator 引数は データ・バッファーを指すポインターで、open ルーチンで戻されたものです。
void HTTPD_LINKAGE closeFunction ( unsigned char *handle, void *correlator, long *return_code )
close 関数は、このストリームのデータの処理を完了するために必要な クリーンアップ・アクション (correlator バッファーのフラッシュや解放など) を行います。 correlator 引数は データ・バッファーを指すポインターで、open ルーチンで戻されたものです。
void HTTPD_LINKAGE errorFunction ( unsigned char *handle, void *correlator, long *return_code )
error 関数により、エラー・ページが送信される前に、バッファー内にあるデータの フラッシュまたは解放 (あるいはその両方) などのクリーンアップ・アクションを 行うことができるようになります。 この時点で、エラー・ページを 処理するために open、write、および close 関数が呼び出されます。correlator 引数は データ・バッファーを指すポインターで、open ルーチンで戻されたものです。
注 :
void HTTPD_LINKAGE GCAdvisorFunction ( unsigned char *handle, long *return_code )
このステップで定義された関数は、ガーベッジ・コレクションの際、キャッシュ内のファイルごとに呼び出されます。この関数によって、保持するファイルと廃棄するファイルの決定に 影響を与えることができます。 詳細については、GC_* 変数を参照してください。
void HTTPD_LINKAGE ProxyAdvisorFunction ( unsigned char *handle, long *return_code )
このステップで定義された関数は、各プロキシー要求のサービス時に呼び出されます。 例えば、USE_PROXY 変数を設定するために使用することができます。
void HTTPD_LINKAGE LogFunction ( unsigned char *handle, long *return_code )
このステップで定義された関数は、要求が処理され、クライアントへの通信が クローズされた後で、それぞれの要求ごとに呼び出されます。 テンプレートと一致する要求のみについてプラグイン関数が呼び出されるようにしたい場合は、 URL テンプレートを構成ファイル・ディレクティブに指定します。 この関数は、要求処理の成否に関係なく呼び出されます。 ログ・プラグインにデフォルトのログ・メカニズムを変更させたくない場合は、戻りコードを HTTP_OK ではなく HTTP_NOACTION に設定します。
void HTTPD_LINKAGE ErrorFunction ( unsigned char *handle, long *return_code )
このステップで定義された関数は、失敗した要求ごとに呼び出されます。 テンプレートと一致する、失敗した要求のみについてプラグイン関数が呼び出されるようにしたい場合は、 URL テンプレートを構成ファイル・ディレクティブに指定します。 Error ステップを使用して、エラー応答をカスタマイズできます。
void HTTPD_LINKAGE PostExitFunction ( unsigned char *handle, long *return_code )
このステップで定義された関数は、要求の成否に関係なく、 要求ごとに呼び出されます。 このステップを使用して、要求を処理するプラグインによって割り振られたリソースに対して クリーンアップ・タスクを行うことができます。
void HTTPD_LINKAGE ServerTermFunction ( unsigned char *handle, long *return_code )
このステップで定義された関数は、サーバーが正常にシャットダウンしたときに呼び出されます。 これにより、サーバー初期化ステップの際に割り振られたリソースをクリーンアップすることができます。このステップでは、いずれの HTTP_* 関数も呼び出さないでください (呼び出しの結果は保証できません)。構成ファイルに Server Termination 用の複数の Caching Proxy API ディレクティブがある場合は、それらがすべて呼び出されます。
これらの戻りコードは、World Wide Web Consortium によって公開されている HTTP 1.1 仕様書 (www.w3.org/pub/WWW/Protocols/) の RFC 2616 に準拠しています。
プラグイン関数は、以下のいずれかの値を戻す必要があります。
表 2. Caching Proxy API 関数の HTTP 戻りコード
値 | 戻りコード |
0 | HTTP_NOACTION |
100 | HTTP_CONTINUE |
101 | HTTP_SWITCHING_PROTOCOLS |
200 | HTTP_OK |
201 | HTTP_CREATED |
202 | HTTP_ACCEPTED |
203 | HTTP_NON_AUTHORITATIVE |
204 | HTTP_NO_CONTENT |
205 | HTTP_RESET_CONTENT |
206 | HTTP_PARTIAL_CONTENT |
300 | HTTP_MULTIPLE_CHOICES |
301 | HTTP_MOVED_PERMANENTLY |
302 | HTTP_MOVED_TEMPORARILY |
302 | HTTP_FOUND |
303 | HTTP_SEE_OTHER |
304 | HTTP_NOT_MODIFIED |
305 | HTTP_USE_PROXY |
307 | HTTP_TEMPORARY_REDIRECT |
400 | HTTP_BAD_REQUEST |
401 | HTTP_UNAUTHORIZED |
403 | HTTP_FORBIDDEN |
404 | HTTP_NOT_FOUND |
405 | HTTP_METHOD_NOT_ALLOWED |
406 | HTTP_NOT_ACCEPTABLE |
407 | HTTP_PROXY_UNAUTHORIZED |
408 | HTTP_REQUEST_TIMEOUT |
409 | HTTP_CONFLICT |
410 | HTTP_GONE |
411 | HTTP_LENGTH_REQUIRED |
412 | HTTP_PRECONDITION_FAILED |
413 | HTTP_ENTITY_TOO_LARGE |
414 | HTTP_URI_TOO_LONG |
415 | HTTP_BAD_MEDIA_TYPE |
416 | HTTP_BAD_RANGE |
417 | HTTP_EXPECTATION_FAILED |
500 | HTTP_SERVER_ERROR |
501 | HTTP_NOT_IMPLEMENTED |
502 | HTTP_BAD_GATEWAY |
503 | HTTP_SERVICE_UNAVAILABLE |
504 | HTTP_GATEWAY_TIMEOUT |
505 | HTTP_BAD_VERSION |
ユーザー独自のプラグイン関数から、サーバーの事前定義関数およびマクロを呼び出すことができます。 その事前定義された名前を使用し、以下の形式に従う必要があります。パラメーターの説明で、 i は入力パラメーターを示し、o は出力パラメーターを示し、 i/o はパラメーターが入力と出力の両方であることを示しています。
これらの関数は、要求の結果に応じて、いずれかの HTTPD 戻りコードを戻します。これらのコードは、事前定義関数およびマクロからの戻りコードで説明されています。
これらの関数を呼び出すときは、プラグインへ提供されたハンドルを最初のパラメーターとして使用します。最初の パラメーターとして使用しない場合、関数は HTTPD_PARAMETER_ERROR エラー・コードを戻します。 NULL は、有効なハンドルとしては受け入れられません。
void HTTPD_LINKAGE HTTPD_authenticate ( unsigned char *handle, /* i; handle */ long *return_code /* o; return code */ )
void HTTPD_LINKAGE HTTPD_cacheable_url ( unsigned char *handle, /* i; handle */ unsigned char *url, /* i; URL to check */ unsigned char *req_method, /* i; request method for the URL */ long *retval /* o; return code */ )
戻り値 HTTPD_SUCCESS は、URL コンテンツがキャッシュできることを示します。HTTPD_FAILURE はコンテンツがキャッシュできないことを示します。また、HTTPD_INTERNAL_ERROR もこの関数の可能な戻りコードです。
void HTTPD_LINKAGE HTTPD_close ( unsigned char *handle, /* i; handle */ long *return_code /* o; return code */ )
void HTTPD_LINKAGE HTTPD_exec ( unsigned char *handle, /* i; handle */ unsigned char *name, /* i; name of script to run */ unsigned long *name_length, /* i; length of the name */ long *return_code /* o; return code */ )
void HTTPD_LINKAGE HTTPD_extract ( unsigned char *handle, /* i; handle */ unsigned char *name, /* i; name of variable to extract */ unsigned long *name_length, /* i; length of the name */ unsigned char *value, /* o; buffer in which to put the value */ unsigned long *value_length, /* i/o; buffer size */ long *return_code /* o; return code */ )
この関数が HTTPD_BUFFER_TOO_SMALL コードを戻した場合、要求したバッファー・サイズは、抽出された値を入れるのに十分な大きさではありませんでした。この場合、 この関数はバッファーを使用せず、この値を正常に抽出するために必要な バッファー・サイズで value_length パラメーターを更新します。 少なくとも、戻された value_length と同じ大きさのバッファーを使用して抽出を再試行します。
void HTTPD_LINKAGE HTTPD_file ( unsigned char *handle, /* i; handle */ unsigned char *name, /* i; name of file to send */ unsigned long *name_length, /* i; length of the name */ long *return_code /* o; return code */ )
const unsigned char * /* o; value of variable */ HTTPD_LINKAGE httpd_getvar( unsigned char *handle, /* i; handle */ unsigned char *name, /* i; variable name */ unsigned long *n /* i; index number for the array containing the header */ )
ヘッダーが入っている配列の指標は 0 から始まります。配列で最初の項目を得るには、n に値 0 を使用します。5 番目の項目を得るには、n には値 4 を使用します。
void HTTPD_LINKAGE HTTPD_log_access ( unsigned char *handle, /* i; handle */ unsigned char *value, /* i; data to write */ unsigned long *value_length, /* i; length of the data */ long *return_code /* o; return code */ )
サーバー・アクセス・ログにパーセント記号 (%) を書き込むときに、 エスケープ記号は必要がない ことに注意してください。
void HTTPD_LINKAGE HTTPD_log_error ( unsigned char *handle, /* i; handle */ unsigned char *value, /* i; data to write */ unsigned long *value_length, /* i; length of the data */ long *return_code /* o; return code */ )
サーバー・エラー・ログにパーセント記号 (%) を書き込むときに、 エスケープ記号は必要がない ことに注意してください。
void HTTPD_LINKAGE HTTPD_log_event ( unsigned char *handle, /* i; handle */ unsigned char *value, /* i; data to write */ unsigned long *value_length, /* i; length of the data */ long *return_code /* o; return code */ )
サーバー・イベント・ログにパーセント記号 (%) を書き込むときに、 エスケープ記号は必要がない ことに注意してください。
void HTTPD_LINKAGE HTTPD_log_trace ( unsigned char *handle, /* i; handle */ unsigned char *value, /* i; data to write */ unsigned long *value_length, /* i; length of the data */ long *return_code /* o; return code */ )
サーバー・トレース・ログにパーセント記号 (%) を書き込むときに、 エスケープ記号は必要がない ことに注意してください。
void HTTPD_LINKAGE HTTPD_open ( unsigned char *handle, /* i; handle */ long *return_code /* o; return code */ )
void HTTPD_LINKAGE HTTPD_proxy ( unsigned char *handle, /* i; handle */ unsigned char *url_name, /* i; URL for the proxy request */ unsigned long *name_length, /* i; length of URL */ void *request_body, /* i; body of request */ unsigned long *body_length, /* i; length of body */ long *return_code /* o; return code */ )
void HTTPD_LINKAGE HTTPD_read ( unsigned char *handle, /* i; handle */ unsigned char *value, /* i; buffer for data */ unsigned long *value_length, /* i/o; buffer size (data length) */ long *return_code /* o; return code */ )
void HTTPD_LINKAGE HTTPD_restart ( long *return_code /* o; return code */ )
この関数で変数を作成することもできますので注意してください。作成する変数は、 変数で説明されている、 接頭部 HTTP_ および PROXY_ の規則に準拠します。 HTTP_ で始まる変数を作成した場合、この変数は、接頭部 HTTP_ なしで、 クライアントへの応答でヘッダーとして送信されます。 例えば、Location ヘッダーを設定するには、変数名 HTTP_LOCATION で HTTPD_set() を使用します。 接頭部 PROXY_ を付けて作成した変数は、コンテンツ・サーバーへの要求でヘッダーとして送信されます。 接頭部 CGI_ を付けて作成した変数は CGI プログラムに渡されます。
この関数はすべてのステップで有効です。 ただし、すべての変数がすべてのステップで有効であるとは限りません。
void HTTPD_LINKAGE HTTPD_set ( unsigned char *handle, /* i; handle */ unsigned char *name, /* i; name of value to set */ unsigned long *name_length, /* i; length of the name */ unsigned char *value, /* i; buffer with value */ unsigned long *value_length, /* i; length of value */ long *return_code /* o; return code */ )
long /* o; return code */ HTTPD_LINKAGE httpd_setvar ( unsigned char *handle, /* i; handle */ unsigned char *name, /* i; variable name */ unsigned char *value, /* i; new value */ unsigned long *addHdr /* i; add header or replace it */ )
addHdr パラメーターには、以下の 4 つの値を使用できます。
void HTTPD_LINKAGE httpd_variant_insert ( unsigned char *handle, /* i; handle */ unsigned char *URI, /* i; URI of this object */ unsigned char *dimension, /* i; dimension of variation */ unsigned char *variant, /* i; value of the variant */ unsigned char *filename, /* i; file containing the object */ long *return_code /* o; return code */ )
注 :
Mozilla 4.0 (compatible; BatBrowser 94.1.2; Bat OS)
void HTTPD_LINKAGE httpd_variant_lookup ( unsigned char *handle, /* i; handle */ unsigned char *URI, /* URI of this object */ unsigned char *dimension, /* i; dimension of variation */ unsigned char *variant, /* i; value of the variant */ long *return_code); /* o; return code */
初めてこの関数を呼び出す前にコンテンツ・タイプを設定しなかった場合、 サーバーは、CGI データ・ストリームが送信されるものと想定します。
void HTTPD_LINKAGE HTTPD_write ( unsigned char *handle, /* i; handle */ unsigned char *value, /* i; data to send */ unsigned char *value_length, /* i; length of the data */ long *return_code); /* o; return code */
サーバーは、要求が成功したかどうかに応じて、以下のいずれかの値に戻りコード・パラメーターを設定します。
値 | 状況コード | 説明 |
---|---|---|
-1 | HTTPD_UNSUPPORTED | この関数はサポートされていません。 |
0 | HTTPD_SUCCESS | この関数は正常に実行され、出力フィールドが有効です。 |
1 | HTTPD_FAILURE | 関数は失敗しました。 |
2 | HTTPD_INTERNAL_ERROR | 内部エラーを検出し、 この要求の処理を続行できません。 |
3 | HTTPD_PARAMETER_ERROR | 1 つまたは複数の無効なパラメーターが渡されました。 |
4 | HTTPD_STATE_CHECK | この関数はこのプロセス・ステップでは無効です。 |
5 | HTTPD_READ_ONLY | (これを戻すのは HTTPD_set と httpd_setvar だけです。) 変数は読み取り専用であり、プラグインによって設定できません。 |
6 | HTTPD_BUFFER_TOO_SMALL | (これを戻すのは HTTPD_set、 httpd_setvar、および HTTPD_read だけです。)指定のバッファーが小さすぎます。 |
7 | HTTPD_AUTHENTICATE_FAILED | (これを戻すのは HTTPD_authenticate だけです。) 認証は失敗しました。 詳細については、HTTP_RESPONSE および HTTP_REASON 変数を調べてください。 |
8 | HTTPD_EOF | (これを戻すのは HTTPD_read だけです。) 要求本文の終わりを示します。 |
9 | HTTPD_ABORT_REQUEST | クライアントが要求が指定する条件と一致しないエンティティー・タグを指定したために、 要求は打ち切られました。 |
10 | HTTPD_REQUEST_SERVICED | (これを戻すのは HTTPD_proxy だけです。) 呼び出した関数は この要求の応答を完了しました。 |
11 | HTTPD_RESPONSE_ALREADY_COMPLETED | その要求の応答はすでに完了しているので、 この関数は失敗しました。 |
12 | HTTPD_WRITE_ONLY | 変数は書き込み専用であり、プラグインによって読み取ることはできません。 |
要求プロセスの各ステップには構成ディレクティブがあり、これを使用して、そのステップの間に呼び出して実行したいプラグイン関数を示すことができます。 サーバーの構成ファイル (ibmproxy.conf) にそれらのディレクティブを追加するには、サーバーの構成ファイルを手操作で編集して更新するか、または Caching Proxy の「構成および管理」フォームの中の 「API 要求処理」フォームを使用します。
つまり、サーバーは、Service、NameTrans、Exec、Fail、Map、Pass、Proxy、 ProxyWAS、および Redirect の各ディレクティブを構成ファイル内に 並んでいる順序で処理します。 サーバーが URL をファイルに正常にマップすると、サーバーはこれらのディレクティブ以外の ディレクティブを読み取ったり、処理したりしません。 (Map ディレクティブは例外です。プロキシー・サーバーのマッピング・ルールの詳細については、「WebSphere Application Server Caching Proxy 管理ガイド」を参照してください。)
これらの構成ファイル・ディレクティブは、ここに明確に指定されたものを除いてスペースを入れずに、ibmproxy.conf ファイル中に 1 行で記述しなければなりません。構文例の一部では
読みやすさのために改行していますが、実際のディレクティブではそこにスペースを入れないでください。
表 4. Caching Proxy プラグインの API ディレクティブ
これらのディレクティブの変数には、以下の意味があります。
パス情報にアクセスする場合、Service ディレクティブには、関数名の後に アスタリスク (*) が必要です。
これらのディレクティブの構文など、詳細については、「WebSphere Application Server Caching Proxy 管理ガイド」を参照してください。
Caching Proxy API は、バージョン 4.6.1 までの ICAPI および GWAPI と下位互換性があります。
Caching Proxy API を使用するために、C で作成された CGI アプリケーションを移植する場合、以下のガイドラインに従います。
API プログラムの作成に際しては、リモート・クライアントおよびサーバー・システムに関する情報を提供する Caching Proxy 変数を使用することができます。
注 :
図 2. HTTP_ および PROXY_ 変数接頭部。凡例: 1--クライアント・マシン 2--Caching Proxy 3--起点サーバー
ACCEPT_RANGES BYTES CLIENT_ADDR 9.67.84.3
この変数は、PostAuthorization、PostExit、ProxyAdvisor、または Log ステップで使用できます。
http://www.anynet.com/~userk/main.htm
Mon, 01 Mar 2002 19:41:17 GMT
Mon, 01 Mar 1998 19:41:17 GMT
d:¥wwwhome¥foo
/wwwhome/foo
application/x-www-form-urlencoded
7034
NAME=Eugene+T%2E+Fox&ADDR=etfox%7Cibm.net&INTEREST=xyz
http://www.company.com/homepage
application/x-www-form-urlencoded
まず、用語を簡単に説明します。
図 3 は、プロキシー・サーバーによる認証および許可プロセスを表しています。
図 3 に示したように、サーバーの許可および認証のプロセスの最初のステップは、許可プロセスの開始です。
Caching Proxy において、認証は許可プロセスの一部であり、認証が行われるのは、許可が必要な場合に限られます。
プロキシー・サーバーは、許可を必要とする要求を処理するときに以下のステップに従います。
Caching Proxy プラグインが独自の許可プロセスを備えている場合、そのプロセスがデフォルトのサーバーの許可および認証を上書き します。 したがって、構成ファイルに許可ディレクティブがある場合には、 それらに関連するプラグイン関数は、必要な認証を処理する必要もあります。 これに使用するために、事前定義 HTTPD_authenticate() 関数が用意されています。
許可プラグインに認証を備えるには、次の 3 つの方法があります。
Authorization ステップを実行すると、それが許可プラグイン関数を実行し、 次にその許可が認証プラグイン関数を呼び出します。
Authorization ステップを実行すると、それが許可プラグイン関数を実行し、 次にその許可がデフォルト・サーバー認証を呼び出します。
Authorization ステップを実行すると、それが許可プラグイン関数と、 その許可プラグイン関数に含まれる認証を実行します。
Caching Proxy プラグインが独自の許可プロセスを備えていない場合でも、次の方法を使用して、カスタマイズされた認証を用意することができます。
Authorization ステップを実行すると、それがデフォルトのサーバー許可を実行し、 次にその許可が認証プラグイン関数を呼び出します。
以下の点に注意してください。
元の文書 (URI) が変更されたデータをキャッシュする場合は、バリアント・キャッシュを使用します。Caching Proxy は、API によって生成されたバリアントを処理します。バリアントとは、 基本文書の別バージョンです。
一般に、起点サーバーはバリアントを送信するときに、それらがバリアントであることを識別できません。Caching Proxy は、プラグインによって作成されたバリアント (例えばコード・ページ変換) のみをサポートします。プラグインが HTTP ヘッダーに入っていない基準に基づいてバリアントを作成する場合は、プラグインに PreExit または PostAuthorization ステップ関数を組み込んで疑似ヘッダーを作成して、Caching Proxy が既存のバリアントを正しく識別できるようにしなければなりません。
例えば、ブラウザーが送信する User-Agent ヘッダーの値に基づいて ユーザーが要求したデータを変更するには、Transmogrifier API プログラムを使用します。 close 関数で、変更された内容をファイルに保管するか、 またはバッファー長を指定してデータ引数としてバッファーを渡します。 その後で、バリアント・キャッシュ関数 httpd_variant_insert() および httpd_variant_lookup() を使用して、コンテンツをキャッシュに入れます。
Edge Components のインストール CD-ROM の samples ディレクトリーに提供されているサンプル・プログラムを参照して、独自の Caching Proxy API 関数の作成に役立ててください。 WebSphere Application Server Web サイト www.ibm.com/software/webservers/appserv/ に追加情報が記載されています。
このセクションでは、Load Balancer 用のカスタム advisor の作成について説明します。
advisor は、指定サーバー上のロードに関する情報を提供するために Load Balancer 内部で働くソフトウェア・エージェントです。 各標準プロトコル (HTTP、SSL、その他) ごとに異なる advisor が存在します。定期的に、Load Balancer 基本コードが advisor サイクルを実行します。このサイクルで、構成内のすべてのサーバーの状況が個別に評価されます。
Load Balancer 用の独自の advisor を作成することによって、サーバー・マシンのロードを判別する方法をカスタマイズできます。
一般に、advisor は、以下のようにロード・バランシングを可能にするために働きます。
Load Balancer に提供されている標準 advisor には、以下の機能のための advisor が含まれます。 これらの advisor に関する詳細情報は「WebSphere Application Server Load Balancer 管理ガイド」に記載されています。
標準 advisor が提供されていない所有プロトコルをサポートするには、カスタム advisor を作成しなければなりません。
カスタム advisor はクラス・ファイルとして提供される小さな Java コードであり、サーバー上のロードを判別するために Load Balancer 基本コードによって呼び出されます。 基本コードは、カスタム advisor のインスタンスの開始と停止、状況および報告書の提供、ヒストリー情報のログ・ファイルへの記録、さらに advisor 結果のマネージャー・コンポーネントへの報告など、必要なすべての管理サービスを提供します。
Load Balancer 基本コードがカスタム advisor を呼び出すと、以下のステップが実行されます。
カスタム advisor は、Load Balancer と通常 モードまたは置換 モードで対話するように設計することができます。
操作モードの選択は、カスタム advisor ファイルで、コンストラクター・メソッドのパラメーターとして指定されます。(各 advisor は設計に基づいて、上記のモードのいずれかでのみ稼動します。)
通常モードでは、カスタム advisor がサーバーとデータを交換し、基本 advisor コードが交換の時間を測定して、ロード値を計算します。その後、基本コードがこのロード値をマネージャーに報告します。成功を示す場合は値ゼロが、 またはエラーを示す場合は -1 がカスタム advisor から戻されます。
通常モードを指定するには、コンストラクター内の replace フラグを false に設定してください。
置換モードでは、基本コードはいかなる時間測定も行いません。カスタム advisor はその固有の要件に基づいて、指定された操作をすべて実行し、その後、実際のロード値を戻します。基本コードはそのロード値を受け入れ、それをそのままマネージャーに報告します。最良の結果を得るには、高速サーバーを表す 10 と低速サーバーを表す 1000 によって、ロード値を 10 から 1000 の間で正規化してください。
置換モードを指定するには、コンストラクター内の replace フラグを true に設定してください。
カスタム advisor ファイル名は ADV_name.java という形式に従わなければなりません。 ここで name は advisor のために選択する名前です。 完全な名前は大文字の接頭部 ADV_ で始まり、後続の文字がすべての小文字でなければなりません。ここで小文字を使用することにより、 advisor を実行するためのコマンドでの大/小文字の区別が不要になります。
Java の規則に従って、ファイル内で定義されるクラスの名前はファイルの名前と一致しなければなりません。
Java 言語でカスタム advisor を作成し、それを Load Balancer コードと同じレベルの Java コンパイラーでコンパイルする必要があります。ご使用のシステムにおける Java のバージョンを検査するには、install_path/java/bin ディレクトリーから以下のコマンドを実行してください。
java -fullversion
現行ディレクトリーがお客様のパスの一部ではない場合、正しいバージョン情報が確実に得られるようにするために、現行ディレクトリーから Java を実行するように指定する必要があります。 その場合、install_path/java/bin ディレクトリーから以下のコマンドを実行してください。
./java -fullversion
コンパイル時には、以下のファイルが参照されます。
コンパイル時には、クラスパス環境変数がカスタム advisor ファイルと基本クラス・ファイルの 両方を指していなければなりません。 Microsoft Windows システムの場合、サンプル・コンパイル・コマンドは次のような書式です。
install_path/java/bin/javac -classpath /opt/ibm/edge/lb/servers/lib/ibmlb.jar ADV_name.java
ただし、
コンパイルの出力は ADV_name.class などのクラス・ファイルです。advisor を開始する前に、 クラス・ファイルを install_path/servers/lib/CustomAdvisors/ ディレクトリーに コピーしてください。
カスタム advisor を実行するには、最初に advisor のクラス・ファイルを Load Balancer マシン上の lib/CustomAdvisors サブディレクトリーにコピーする必要があります。 例えば、myping というカスタム advisor の場合、ファイル・パスは、 install_path/servers/lib/CustomAdvisors/ADV_myping.class
になります。Load Balancer を構成し、そのマネージャー機能を開始し、カスタム advisor を開始するコマンドを発行します。 カスタム advisor は、次のように、その名前から ADV_ 接頭部とファイル拡張子を除いたものによって指定されます。
dscontrol advisor start myping port_number
コマンドに指定するポート番号は、advisor がターゲット・サーバーとの接続をオープンするポートです。
すべてのadvisor と同様に、カスタム advisor は、ADV_Base と呼ばれる advisor 基本クラスの機能性を拡張 します。 advisor ベースは、マネージャーの重みアルゴリズムで使用するためにロードをマネージャーに報告するなど、advisor の関数の大部分を実行します。advisor ベースはまた、ソケット接続およびクローズ操作を実行し、advisor が使用する送信および受信メソッドを提供します。advisor は、調査中のサーバー用に指定されたポートでデータを送信および受信するためだけに使用されます。advisor ベース内の TCP メソッドは、ロードを計算するために時間測閧ウれます。advisor ベースのコンストラクター内のフラグが、既存のロードを advisor から戻された新しいロードで上書きするかどうかを示します。
advisor には、以下の基本クラス・メソッドがあります。
これらの必須ルーチンに関する詳細は、このセクションで後述します。
カスタム advisor は、ネイティブ advisor または標準 advisor を検索した後に呼び出されます。 Load Balancer は、指定の advisor を標準 advisor のリストから見つけられない場合、カスタム advisor のリストを調べます。 advisor の使用に関する追加情報は「WebSphere Application Server Load Balancer 管理ガイド」に記載されています。
カスタム advisor の名前およびパスについては、以下の要件を忘れないでください。
public <advisor_name> ( String sName; String sVersion; int iDefaultPort; int iInterval; String sDefaultLogFileName; boolean replace )
void ADV_AdvisorInitialize()
このメソッドは、カスタム advisor に必要な初期化を実行するために提供されます。このメソッドが呼び出されるのは advisor 基本モジュールを開始した後です。
標準 advisor を含む多くの場合においてこのメソッドは使用されず、 そのコードを構成するのは return ステートメントだけです。 このメソッドは suppressBaseOpeningSocket メソッドを呼び出すために使用できます。 suppressBaseOpeningSocket メソッドが有効であるのは上記のメソッド内から呼び出された場合のみです。
int getLoad( int iConnectTime; ADV_Thread *caller )
以下のセクションで説明するメソッドまたは関数は、カスタム advisor から呼び出せます。これらのメソッドは advisor 基本コードによってサポートされています。
一部の関数呼び出し (例えば function_name () など) は直接に作成できますが、その他は接頭部 caller を必要とします。caller は基本 advisor インスタンスを示し、これは実行されるカスタム advisor をサポートします。
ADVLOG 関数により、カスタム advisor はテキスト・メッセージを advisor 基本ログ・ファイルに書き込むことができます。形式は次のとおりです。
void ADVLOG (int logLevel, String message)
getAdvisorName 関数は、カスタム advisor 名の接尾部部分の Java ストリングを戻します。 例えば、ADV_cdload.java という名前の advisor では、この関数は値 cdload を戻します。
この関数にはパラメーターを使用しません。
この値は advisor のインスタンス化中に変更できないことに注意してください。
getAdviseOnPort 関数は、呼び出しカスタム advisor を実行するポート番号を戻します。戻り値は Java 整数 (int) であり、この関数ではパラメーターは使用されません。
この値は advisor のインスタンス化中に変更できないことに注意してください。
getCurrentServerId 関数は、現行サーバーを一意的に表わす Java ストリングを戻します。
advisor 基本コードがすべてのサーバー・マシンを連続して照会するため、通常はカスタム advisor を呼び出すたびにこの値が変更されます。
この関数にはパラメーターを使用しません。
getCurrentClusterId 関数呼び出しは、現行クラスターを一意的に表わす Java ストリングを戻します。
advisor 基本コードがすべてのクラスターを連続して照会するため、通常はカスタム advisor を呼び出すたびにこの値が変更されます。
この関数にはパラメーターを使用しません。
getSocket 関数呼び出しは、通信のために現行サーバーに対してオープンされているソケットを表す、Java ソケットを戻します。
getInterval 関数は、advisor サイクル間の秒数である advisor 間隔を戻します。この値は、 dscontrol コマンドを使用して実行時に変更しない限り、 カスタム advisor のコンストラクターに設定されたデフォルト値と同じです。
戻り値は Java 整数 (int) です。この関数にはパラメーターを使用しません。
getLatestLoad 関数により、カスタム advisor は指定サーバー・オブジェクトの最新ロード値を獲得できます。 ロード値は、advisor 基本コードおよびマネージャー・デーモンによって内部テーブルで保守されています。
int caller.getLatestLoad (String clusterId, int port, String serverId)
3 つの引数は 1 つのサーバー・オブジェクトをともに定義します。
戻り値は整数です。
この関数呼び出しは、あるプロトコルまたはポートの動作を別のものの動作に依存させる場合に役立ちます。例えば、同一マシン上の Telnet サーバーが使用不可である場合に、特定アプリケーション・サーバーを使用不可にするカスタム advisor でこの関数呼び出しを使用する場合などです。
receive 関数は、ソケット接続から情報を入手します。
caller.receive(StringBuffer *response)
パラメーター response は、検索されたデータが置かれるストリング・バッファーです。さらに、この関数は以下の重要度のある整数値を戻します。
send 関数は、指定ポートを使用してデータのパケットをサーバーに送信するために確立したソケット接続を使用します。
caller.send(String command)
パラメーター command は、サーバーに送信するデータが入っているストリングです。この関数は、以下の重要度のある整数値を戻します。
suppressBaseOpeningSocket 関数呼び出しにより、カスタム advisor の代わりに 基本 advisor コードがサーバーへの TCP ソケットをオープンするかどうかを カスタム advisor が指定できます。 advisor が状況を判別するためにサーバーとの直接通信を使用しない場合は、このソケットをオープンする必要はありません。
この関数呼び出しを出せるのは一度だけであり、ADV_AdvisorInitialize ルーチンから出さなければなりません。
以下の例は、カスタム advisor をインプリメントできる方法を示します。
このサンプル・ソース・コードは、標準 Load Balancer HTTP advisor に類似しています。 以下のように機能します。
この advisor は通常モードで操作するので、ロード測定はソケット・オープン、送信、受信、およびクローズ操作を実行するために必要な経過時間 (ミリ秒) に基づきます。
package CustomAdvisors; import com.ibm.internet.lb.advisors.*; public class ADV_sample extends ADV_Base implements ADV_MethodInterface { static final String ADV_NAME ="Sample"; static final int ADV_DEF_ADV_ON_PORT = 80; static final int ADV_DEF_INTERVAL = 7; static final String ADV_SEND_REQUEST = "HEAD / HTTP/1.0¥r¥nAccept: */*¥r¥nUser-Agent: " + "IBM_Load_Balancer_HTTP_Advisor¥r¥n¥r¥n"; //-------- // Constructor public ADV_sample() { super(ADV_NAME, "3.0.0.0-03.31.00", ADV_DEF_ADV_ON_PORT, ADV_DEF_INTERVAL, "", false); super.setAdvisor( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { return; // usually an empty routine } //-------- // getLoad public int getLoad(int iConnectTime, ADV_Thread caller) { int iRc; int iLoad = ADV_HOST_INACCESSIBLE; // initialize to inaccessible iRc = caller.send(ADV_SEND_REQUEST); // send the HTTP request to // the server if (0 <= iRc) { // if the send is successful StringBuffer sbReceiveData = new StringBuffer(""); // allocate a buffer // for the response iRc = caller.receive(sbReceiveData); // receive the result // parse the result here if you need to if (0 <= iRc) { // if the receive is successful iLoad = 0; // return 0 for success } // (advisor's load value is ignored by } // base in normal mode) return iLoad; } }
このサンプルでは、advisor ベースによる標準ソケットのオープンの抑制を例示しています。その代わりに、この advisor は、サイド・ストリーム Java ソケットをオープンしてサーバーを照会します。 このプロシージャーは、通常のクライアント・トラフィックと異なるポートを使用して advisor 照会を listen するサーバーのために役立ちます。
この例では、サーバーはポート 11999 上で listen していて、 照会されたときに 16 進 int "4" でロード値を戻します。 このサンプルは置換モードで実行されます。 つまり、advisor コンストラクターの最終パラメーターが true に設定されて、 advisor 基本コードは経過時間ではなく戻されたロード値を使用します。
初期化ルーチンでの supressBaseOpeningSocket() に対する呼び出しに注意してください。データが送信されないときの基本ソケットの抑制は不要です。例えば、advisor がサーバーに接続できることを確認するためにソケットをオープンする場合などです。 この選択を行う前には、アプリケーションの必要性を注意深く調べてください。
package CustomAdvisors; import java.io.*; import java.net.*; import java.util.*; import java.util.Date; import com.ibm.internet.lb.advisors.*; import com.ibm.internet.lb.common.*; import com.ibm.internet.lb.server.SRV_ConfigServer; public class ADV_sidea extends ADV_Base implements ADV_MethodInterface { static final String ADV_NAME = "sidea"; static final int ADV_DEF_ADV_ON_PORT = 12345; static final int ADV_DEF_INTERVAL = 7; // create an array of bytes with the load request message static final byte[] abHealth = {(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x04}; public ADV_sidea() { super(ADV_NAME, "3.0.0.0-03.31.00", ADV_DEF_ADV_ON_PORT, ADV_DEF_INTERVAL, "", true); // replace mode parameter is true super.setAdvisor( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { suppressBaseOpeningSocket(); // tell base code not to open the // standard socket return; } //-------- // getLoad public int getLoad(int iConnectTime, ADV_Thread caller) { int iRc; int iLoad = ADV_HOST_INACCESSIBLE; // -1 int iControlPort = 11999; // port on which to communicate with the server String sServer = caller.getCurrentServerId(); // address of server to query try { socket soServer = new Socket(sServer, iControlPort); // open socket to // server DataInputStream disServer = new DataInputStream( soServer.getInputStream()); DataOutputStream dosServer = new DataOutputStream( soServer.getOutputStream()); int iRecvTimeout = 10000; // set timeout (in milliseconds) // for receiving data soServer.setSoTimeout(iRecvTimeout); dosServer.writeInt(4); // send a message to the server dosServer.flush(); iLoad = disServer.readByte(); // receive the response from the server } catch (exception e) { system.out.println("Caught exception " + e); } return iLoad; // return the load reported from the server } }
このカスタム advisor サンプルは、サーバーの 1 つのポートに対する失敗を検出する機能を説明しています。 これは、そのポートの状況と、同一サーバー・マシン上にある別のポート上で実行されている 異なるサーバー・デーモンの状況の両方に基づいています。 例えば、ポート 80 の HTTP デーモンが応答を停止する場合には、ポート 443 の SSL デーモンへのルーティング・トラフィックも停止することができます。
この advisor は、応答を送信しないサーバーは機能を停止したと見なして、ダウンのマークを付けるので、 標準 advisor よりも積極的です。標準 advisor は応答のないサーバーを非常に低速であると見なします。この advisor は HTTP ポートおよび SSL ポートのいずれかの応答がないと、両方のポートがダウンしたことを示す マークをサーバーに付けます。
このカスタム advisor を使用するには、advisor の HTTP ポート上にある インスタンスと SSL ポート上にあるインスタンスを管理者が開始します。 advisor は HTTP 用と SSL 用の 2 つの静的グローバル・ハッシュ・テーブルを検証します。各 advisor は そのサーバー・デーモンとの通信を試行し、そのハッシュ・テーブルにこのイベントの結果を保管します。 各 advisor が基本 advisor クラスに戻す値は、 その固有のサーバー・デーモンと通信する能力およびそのデーモンと通信するパートナー advisor の能力によって異なります。
以下のカスタム・メソッドが使用されます。
次のエラー条件が検出されます。
このサンプルは HTTP 用のポート 80 および SSL 用の 443 をリンクするように書かれていますが、ポートの組み合わせは任意に調整できます。
package CustomAdvisors; import java.io.*; import java.net.*; import java.util.*; import java.util.Date; import com.ibm.internet.lb.advisors.*; import com.ibm.internet.lb.common.*; import com.ibm.internet.lb.manager.*; import com.ibm.internet.lb.server.SRV_ConfigServer; //-------- // Define the table element for the hash tables used in this custom advisor class ADV_nte implements Cloneable { private String sCluster; private int iPort; private String sServer; private int iLoad; private Date dTimestamp; //-------- // constructor public ADV_nte(String sClusterIn, int iPortIn, String sServerIn, int iLoadIn) { sCluster = sClusterIn; iPort = iPortIn; sServer = sServerIn; iLoad = iLoadIn; dTimestamp = new Date(); } //-------- // check whether this element is current or expired public boolean isCurrent(ADV_twop oThis) { boolean bCurrent; int iLifetimeMs = 3 * 1000 * oThis.getInterval(); // set lifetime as // 3 advisor cycles Date dNow = new Date(); Date dExpires = new Date(dTimestamp.getTime() + iLifetimeMs); if (dNow.after(dExpires)) { bCurrent = false; } else { bCurrent = true; } return bCurrent; } //-------- // value accessor(s) public int getLoadValue() { return iLoad; } //-------- // clone (avoids corruption between threads) public synchronized Object Clone() { try { return super.clone(); } catch (cloneNotSupportedException e) { return null; } } } //-------- // define the custom advisor public class ADV_twop extends ADV_Base implements ADV_MethodInterface, ADV_AdvisorVersionInterface { static final int ADV_TWOP_PORT_HTTP = 80; static final int ADV_TWOP_PORT_SSL = 443; //-------- // define tables to hold port-specific history information static HashTable htTwopHTTP = new Hashtable(); static HashTable htTwopSSL = new Hashtable(); static final String ADV_TWOP_NAME = "twop"; static final int ADV_TWOP_DEF_ADV_ON_PORT = 80; static final int ADV_TWOP_DEF_INTERVAL = 7; static final String ADV_HTTP_REQUEST_STRING = "HEAD / HTTP/1.0¥r¥nAccept: */*¥r¥nUser-Agent: " + "IBM_LB_Custom_Advisor¥r¥n¥r¥n"; //-------- // create byte array with SSL client hello message public static final byte[] abClientHello = { (byte)0x80, (byte)0x1c, (byte)0x01, // client hello (byte)0x03, (byte)0x00, // SSL version (byte)0x00, (byte)0x03, // cipher spec len (bytes) (byte)0x00, (byte)0x00, // session ID len (bytes) (byte)0x00, (byte)0x10, // challenge data len (bytes) (byte)0x00, (byte)0x00, (byte)0x03, // cipher spec (byte)0x1A, (byte)0xFC, (byte)0xE5, (byte)Ox20, // challenge data (byte)0xFD, (byte)0x3A, (byte)0x3C, (byte)0x18, (byte)0xAB, (byte)0x67, (byte)0xB0, (byte)0x52, (byte)0xB1, (byte)0x1D, (byte)0x55, (byte)0x44, (byte)0x0D, (byte)0x0A }; //-------- // constructor public ADV_twop() { super(ADV_TWOP_NAME, VERSION, ADV_TWOP_DEF_ADV_ON_PORT, ADV_TWOP_DEF_INTERVAL, "", false); // false = load balancer times the response setAdvisor ( this ); } //-------- // ADV_AdvisorInitialize public void ADV_AdvisorInitialize() { return; } //-------- // synchronized PUT and GET access routines for the hash tables synchronized ADV_nte getNte(Hashtable ht, String sName, String sHashKey) { ADV_nte nte = (ADV_nte)(ht.get(sHashKey)); if (null != nte) { nte = (ADV_nte)nte.clone(); } return nte; } synchronized void putNte(Hashtable ht, String sName, String sHashKey, ADV_nte nte) { ht.put(sHashKey,nte); return; } //-------- // getLoadHTTP - determine HTTP load based on server response int getLoadHTTP(int iConnectTime, ADV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iRc = caller.send(ADV_HTTP_REQUEST_STRING); // send request message // to server if (0 <= iRc) { // did the request return a failure? StringBuffer sbReceiveData = new StringBuffer("") // allocate a buffer // for the response iRc = caller.receive(sbReceiveData); // get response from server if (0 <= iRc) { // did the receive return a failure? if (0 < sbReceiveData.length()) { // is data there? iLoad = SUCCESS; // ignore retrieved data and // return success code } } } return iLoad; } //-------- // getLoadSSL() - determine SSL load based on server response int getLoadSSL(int iConnectTime, ASV_Thread caller) { int iLoad = ADV_HOST_INACCESSIBLE; int iRc; CMNByteArrayWrapper cbawClientHello = new CMNByteArrayWrapper( abClientHello); Socket socket = caller.getSocket(); try { socket.getOutputStream().write(abClientHello); // Perform a receive. socket.getInputStream().read(); // If receive is successful, return load of 0. We are not concerned with // data's contents, and the load is calculated by the ADV_Thread thread. iLoad = 0; } catch (IOException e) { // Upon error, iLoad will default to it. } return iLoad; } //-------- // getLoad - merge results from the HTTP and SSL methods public int getLoad(int iConnectTime, ADV_Thread caller) { int iLoadHTTP; int iLoadSSL; int iLoad; int iRc; String sCluster = caller.getCurrentClusterId(); // current cluster address int iPort = getAdviseOnPort(); String sServer = caller.getCurrentServerId(); String sHashKey = sCluster = ":" + sServer; // hash table key if (ADV_TWOP_PORT_HTTP == iPort) { // handle an HTTP server iLoadHTTP = getLoadHTTP(iConnectTime, caller); // get the load for HTTP ADV_nte nteHTTP = newADV_nte(sCluster, iPort, sServer, iLoadHTTP); putNte(htTwopHTTP, "HTTP", sHashKey, nteHTTP); // save HTTP load // information ADV_nte nteSSL = getNte(htTwopSSL, "SSL", sHashKey); // get SSL // information if (null != nteSSL) { if (true == nteSSL.isCurrent(this)) { // check the time stamp if (ADV_HOST_INACCESSIBLE != nteSSL.getLoadValue()) { // is SSL // working? iLoad = iLoadHTTP; } else { // SSL is not working, so mark the HTTP server down iLoad= ADV_HOST_INACCESSIBLE; } } else { // SSL information is expired, so mark the // HTTP server down iLoad = ADV_HOST_INACCESSIBLE; } } else { // no load information about SSL, report // getLoadHTTP() results iLoad = iLoadHTTP; } } else if (ADV_TWOP_PORT_SSL == iPort) { // handle an SSL server iLoadSSL = getLoadSSL(iConnectTime, caller); // get load for SSL ADV_nte nteSSL = new ADV_nte(sCluster, iPort, sServer, iLoadSSL); putNte(htTwopSSL, "SSL", sHashKey, nteSSL); // save SSL load info. ADV_nte nteHTTP = getNte(htTwopHTTP, "SSL", sHashKey); // get HTTP // information if (null != nteHTTP) { if (true == nteHTTP.isCurrent(this)) { // check the timestamp if (ADV_HOST_INACCESSIBLE != nteHTTP.getLoadValue()) { // is HTTP // working? iLoad = iLoadSSL; } else { // HTTP server is not working, so mark SSL down iLoad = ADV_HOST_INACCESSIBLE; } } else { // expired information from HTTP, so mark SSL down iLoad = ADV_HOST_INACCESSIBLE; } } else { // no load information about HTTP, report // getLoadSSL() results iLoad = iLoadSSL; } } //-------- // error handler else { iLoad = ADV_HOST_INACCESSIBLE; } return iLoad; } }
WebSphere Application Server のサンプル・カスタム advisor は、install_path/servers/samples/CustomAdvisors/ ディレクトリーに入っています。 完全なコードはこの資料では掲載していません。
完全な advisor はサンプルよりわずかに複雑です。上記の StringTokenizer の例よりコンパクトな特殊化された構文解析ルーチンを追加します。
サンプル・コードのより複雑な部分は Java サーブレットにあります。 このサーブレットには、他のメソッドとともに、サーブレット仕様が必要とする init() および service() という 2 つのメソッドと、Java.lang.thread クラスが必要とする run() という 1 つのメソッドが入っています。
サーブレット・コードの関連フラグメントは、以下のようになります。
... public void init(ServletConfig config) throws ServletException { super.init(config); ... _checker = new Thread(this); _checker.start(); } public void run() { setStatus(GOOD); while (true) { if (!getKeepRunning()) return; setStatus(figureLoad()); setLastUpdate(new java.util.Date()); try { _checker.sleep(_interval * 1000); } catch (Exception ignore) { ; } } } public void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { ServletOutputStream out = null; try { out = res.getOutputStream(); } catch (Exception e) { ... } ... res.setContentType("text/x-application-LBAdvisor"); out.println(getStatusString()); out.println(getLastUpdate().toString()); out.flush(); return; } ...
アプリケーション・サーバーの既存パーツに対する標準呼び出しを使用したり、 またはカスタム advisor のサーバー側で相対するコードの新規部分を追加して、 戻されたロード値を調べてサーバー動作を変更することができます。 Java StringTokenizer クラスおよびその関連メソッドは、この調査を実行しやすくします。
通常の HTTP コマンドのコンテンツは GET /index.html HTTP/1.0 です。
このコマンドに対する通常の応答は、以下のようになります。
HTTP/1.1 200 OK Date: Mon, 20 November 2000 14:09:57 GMT Server: Apache/1.3.12 (Linux and UNIX) Content-Location: index.html.en Vary: negotiate TCN: choice Last-Modified: Fri, 20 Oct 2000 15:58:35 GMT ETag: "14f3e5-1a8-39f06bab;39f06a02" Accept-Ranges: bytes Content-Length: 424 Connection: close Content-Type: text/html Content-Language: en <!DOCTYPE HTML PUBLIC "-//w3c//DTD HTML 3.2 Final//EN"> <HTML><HEAD><TITLE>Test Page</TITLE></HEAD> <BODY><H1>Apache server</H1> <HR> <P><P>This Web server is running Apache 1.3.12. <P><HR> <P><IMG SRC="apache_pb.gif" ALT=""> </BODY></HTML>
関心のある項目 (特に HTTP 戻りコード) は先頭行に入っています。
HTTP 仕様は戻りコードを分類し、以下のように要約できます。
サーバーが戻す可能性のあるコードが正確に分かる場合は、コードをこの例ほど詳細にする必要はありません。ただし、検出する戻りコードを制限すると、プログラムの将来の柔軟性を制限することになる場合があります。
以下の例は、最小限の HTTP クライアントが入っているスタンドアロン Java プログラムです。 この例は HTTP 応答を調べるための単純な汎用パーサーを起動します。
import java.io.*; import java.util.*; import java.net.*; public class ParseTest { static final int iPort = 80; static final String sServer = "www.ibm.com"; static final String sQuery = "GET /index.html HTTP/1.0¥r¥n¥r¥n"; static final String sHTTP10 = "HTTP/1.0"; static final String sHTTP11 = "HTTP/1.1"; public static void main(String[] Arg) { String sHTTPVersion = null; String sHTTPReturnCode = null; String sResponse = null; int iRc = 0; BufferedReader brIn = null; PrintWriter psOut = null; Socket soServer= null; StringBuffer sbText = new StringBuffer(40); try { soServer = new Socket(sServer, iPort); brIn = new BufferedReader(new InputStreamReader( soServer.getInputStream())); psOut = new PrintWriter(soServer.getOutputStream()); psOut.println(sQuery); psOut.flush(); sResponse = brIn.readLine(); try { soServer.close(); } catch (Exception sc) {;} } catch (Exception swr) {;} StringTokenizer st = new StringTokenizer(sResponse, " "); if (true == st.hasMoreTokens()) { sHTTPVersion = st.nextToken(); if (sHTTPVersion.equals(sHTTP110) || sHTTPVersion.equals(sHTTP11)) { System.out.println("HTTP Version: " + sHTTPVersion); } else { System.out.println("Invalid HTTP Version: " + sHTTPVersion); } } else { System.out.println("Nothing was returned"); return; } if (true == st.hasMoreTokens()) { sHTTPReturnCode = st.nextToken(); try { iRc = Integer.parseInt(sHTTPReturnCode); } catch (NumberFormatException ne) {;} switch (iRc) { case(200): System.out.println("HTTP Response code: OK, " + iRc); break; case(400): case(401): case(402): case(403): case(404): System.out.println("HTTP Response code: Client Error, " + iRc); break; case(500): case(501): case(502): case(503): System.out.println("HTTP Response code: Server Error, " + iRc); break; default: System.out.println("HTTP Response code: Unknown, " + iRc); break; } } if (true == st.hasMoreTokens()) { while (true == st.hasMoreTokens()) { sbText.append(st.nextToken()); sbText.append(" "); } System.out.println("HTTP Response phrase: " + sbText.toString()); } } }