最終更新日: 4/25/2002
注: このドキュメントは、高度な知識を持つ CORBA 開発者を対象としています。
Java CORBA Object Request Broker (ORB) は、フック (遮断点) を提供し、ORB サービスはこのフックを使って ORB の通常の実行の流れを遮断することができます。これらの「ポータブルインタセプタ」は、追加の ORB の動作をプラグインするためのメカニズムと、クライアントとサーバー間の通信を変更することによって ORB の動作を変更するためのメカニズムを提供します。このあとの例では、ポータブルインタセプタのさまざまな使い方について説明します。
ポータブルインタセプタのサポートは、CORBA 仕様に最近追加された重要な機能です。RequestInterceptor を使用すると、ORB が仲介する任意の呼び出しを遮断するポータブル ORB フックを簡単に記述して接続することができます。IORInterceptor を使用すると、CORBA オブジェクト参照に注釈を付けるためのコードを記述できます。
このドキュメントを読む前に、ポータブルインタセプタの仕様 (ptc/2001-03-04) をお読みになることを強くお勧めします。
このドキュメントでは、次のようなトピックについて説明します。
ORBInitializers
の登録
現在、登録できるインタセプタには次の 3 つの型があります。それぞれの例についてはこのあとの例で説明します。
IORInterceptor
場合によっては、クライアント上の ORB サービス実装を正しく機能させるために、ポータブル ORB サービスの実装で、サーバーまたはオブジェクトの ORB サービス関連機能を説明する情報をオブジェクト参照に追加する必要があります。この処理は、IORInterceptor インタフェースと IORInfo インタフェースによってサポートされます。IOR インタセプタは、Interoperable Object Reference (IOR) のプロファイル内にタグ付きコンポーネントを確立するために使います。
IOR インタセプタの例は、このあとに説明する例の AServiceIORInterceptor.java ファイルに示します。
ClientRequestInterceptor
要求インタセプタは、特定の地点で ORB を介して要求/応答シーケンスの流れを遮断し、サービスが要求情報を照会したり、クライアントとサーバーとの間でやりとりされるサービスコンテキストを操作したりできるよう設計されています。要求インタセプタの主な使用目的は、ORB サービスがクライアントとサーバーとの間でコンテキスト情報を転送できるようにすることです。
ClientRequestInterceptor
は、クライアント側の ORB の要求や応答シーケンスの流れを遮断します。
ClientRequestInterceptor の例は、このあとに説明する例の LoggingServiceClientInterceptor.java ファイルに示します。
ServerRequestInterceptor
ServerRequestInterceptor
は、サーバー側の ORB の要求や応答シーケンスの流れを遮断します。
ServerRequestInterceptor の例は、このあとに説明する例の LoggingServiceServerInterceptor.java ファイルに示します。
ORBInitializers
の登録 ORBInitializer
インタフェースを利用すると、インタセプタの登録と ORB の初期化が簡単になります。
インタセプタは、ORB サービスが ORB 処理にアクセスして、事実上 ORB の一部になるための手段となるよう意図されています。インタセプタは ORB の一部であるため、ORB.init
が ORB を返すときは、インタセプタの登録が完了しています。ORB.init
への呼び出しで返されたあとは、インタセプタはその ORB に登録できません。
ORBInitializers
は、Java ORB プロパティーを経由して登録されます。インタセプタの登録は、ORBInitializer
インタフェースを実装する関連付けられている ORBInitializer
オブジェクトを登録する方法で行われます。ORB は、初期化しているときに、登録されている各 ORBInitializer
を呼び出し、そのインタセプタの登録に使用される ORBInitInfo
オブジェクトをそれに渡します。
プロパティー名は、次の形式をとります。
org.omg.PortableInterceptor.ORBInitializerClass.<Service>
<Service>
は、次のプロパティーを実装するクラスの文字列名です。
org.omg.PortableInterceptor.ORBInitializer名前の競合を防ぐため、逆方向の DNS 命名規則が使用されます。たとえば、
Example
社に初期化子が 3 つある場合、次のプロパティーを定義できます。
org.omg.PortableInterceptor.ORBInitializerClass.com.example.Init1
org.omg.PortableInterceptor.ORBInitializerClass.com.example.Init2
org.omg.PortableInterceptor.ORBInitializerClass.com.example.Init3
注: ORBInitializerClass
プロパティーに値を関連付けても、すべて無視されます。
ORB.init の実行中は、org.omg.PortableInterceptor.ORBInitializerClass
で始まるこれらの ORB プロパティーが収集され、各プロパティーの <Service>
部分が取り出され、クラス名に <Service>
文字列を使用してオブジェクトがインスタンス化され、そのオブジェクトに対して pre_init
と post_init
の各メソッドが呼び出されます。例外が発生しても、ORB はそれを無視して、処理を続行します。
orb_id
を指定して ORB.init
を呼び出す) ことは避けてください。ORB の初期化中に登録が行われるため、この状態にあるかぎり、この ORB の呼び出し結果は保証されません。PortableInterceptor::Current オブジェクト (これ以降 PICurrent と呼ぶ) は、ポータブルインタセプタが、スレッドのコンテキスト情報を要求コンテキストに転送するために使用する Current オブジェクトです。ポータブルインタセプタは、PICurrent を常に使用する必要はありませんが、インタセプタの遮断点で、クライアントのスレッドコンテキストの情報が必要な場合は、PICurrent を使用してその情報を伝播することができます。PICurrent を使用すると、ORB のスレッドモデルにかかわらず移植性のあるサービスコードを記述できます。
注: PICurrent は通常、CORBA のクライアントコードまたはサーバーコードから直接使用されることはありません。一般には、このあと説明する AService というインタセプタの例で紹介されているように、インタセプタベースのサービス実装により使用されます。
PICurrent は、呼び出しを行う前に、ORB::resolve_initial_references (PICurrent) の呼び出しによって取得されます。スレッドスコープから要求スコープに移動した PICurrent のデータは、遮断点の内部から、RequestInfo オブジェクトに対する get_slot オペレーションを介して利用できます。PICurrent は引き続き resolve_initial_references を介して取得できますが、それはインタセプタのスレッドスコープの PICurrent となります。
スレッドスコープの PICurrent (TSC) は、スレッドのコンテキスト内に存在する PICurrent です。要求スコープの PICurrent (RSC) は、要求に関連付けられている PICurrent です。クライアント側では、要求の開始時に、スレッドスコープの PICurrent が、スレッドコンテキストから要求スコープの PICurrent に論理的にコピーされ、ClientRequestInfo オブジェクトに接続されます。サーバー側では、要求スコープの PICurrent が ServerRequestInfo に接続されてから、要求の処理が行われます。要求スコープの PICurrent は、receive_request_service_contexts 遮断点のリストが処理されたあとに、スレッドスコープの PICurrent に論理的にコピーされます。PICurrent のスコープの詳細については、『Updated Interceptors specification』の「21.4.4.5 Flow of PICurrent between Scopes」を参照してください。
ここでは、ロギングサービスアプリケーションの例について説明します。このアプリケーションのサンプルコードは、複雑かつ「特殊なケース」を扱うため、非常に複雑になっています。このサンプルアプリケーションでは次のシナリオを扱います。
注: 次の例では、コードを簡単に試してセットアップできるように、ORBInitializer を明示的に登録しています。一般的にはこのような処理は行いません。通常、この情報は、アプリケーションの起動時に -D プロパティーとして Java 仮想マシンに渡されます。この方法を使うと、サービス (たとえばロギングサービス) が存在するかどうか、あるいはアプリケーションが明示的に使用するサービス (たとえば AService インタフェース) がインタセプタとして実装されるかどうかという事実にアプリケーションが束縛されなくなります。
ロギングサービスの例を紹介する目的は、遮断点内から発信呼び出し (つまり、CORBA 参照に対する呼び出し) を行うときに無限再帰を回避する方法を説明することです。これは、あらゆるケースを網羅しようとすると、かなり複雑になることがあります。
「空の」サービスの例を紹介する目的は、コンテキスト情報をクライアントとサーバーの間でやり取りするサービスの実装方法を説明することです。
典型的なインタセプタベースのサービスでは、コンテキスト情報をクライアントとサーバーの間でやり取りします。AService の例は、この情報がクライアントのスレッドからクライアントのインタセプタに流れ、ワイヤーを経由してサーバーのインタセプタに入り、サーバントのスレッドに届くというフローや、その逆のフローについて説明するものです。
サービスがインタセプタを使用して実装されているということを、クライアントとサーバントがどちらも意識しないという点が重要です。そのどちらも、ローカルオブジェクト参照 (この例では aService 参照) を介してサービスと対話しているだけです。
AService の説明図
AService の説明図にある各ステップについての説明は次のとおりです。
1.a. aService.begin() は、PICurrent に予約済みのスロットに、サービスのコンテキスト情報を設定します。
サービスによっては、遮断点内から別の CORBA オブジェクト参照に対する呼び出しを行う必要があります。遮断点内から発信呼び出しを行うときには、無限再帰を回避するための処置をとる必要があります。それらの発信呼び出しが遮断点を経由するからです。LoggingService の例では、このケースについて説明します。
LoggingService の例は、クライアントプログラムに登録された ClientRequestInterceptors と、サーバープログラムに登録された ServerRequestInterceptors とで構成されます。これらのインタセプタは、クライアントおよびサーバーから LoggingService の実装に情報を送信します。LoggingService の実装は、その情報をログに記録します。
ただし、LoggingService の実装はそれ自体が CORBA サーバーであるので、ロガーに対する呼び出しはログに記録しないようにする必要があります。次の図は、無限再帰を回避するためにとるべき処置を示しています。
次の図では、インタセプタ内から外部のロガーを呼び出すという、再帰を回避するべきもっとも単純なケースを示します。ここで説明する手順は、クライアント ORB に ClientRequestInterceptors だけを含み、サーバー ORB に ServerRequestInterceptors だけを含み、LoggingService がクライアント ORB とサーバー ORB の両方に対して外部にあるというケースに役立ちます。
LoggingService の説明図
LoggingService の説明図にある各ステップについて、次に説明します。
次の図は、クライアントによって呼び出される参照と同じ ORB に LoggingService があるというケースを示しています。一般に、特定のオブジェクト参照が、その ORB によってホストされているほかのオブジェクトと同じ場所にないということを識別するのは不可能です。したがって、あらゆるケースを網羅するために、さらに処置をとる必要があります。
この図は、サーバー側だけを示したものです。クライアント側の手順は、前の図にある手順と同じです。
LoggingServiceColocated の説明図
LoggingServiceColocated の説明図にある各ステップについて、次に説明します。
ステップ 13 の後、ステップ 3 で残っている元の要求が処理されることになります。
この例で説明した内容の要点は、クライアントインタセプタとサーバーインタセプタの両方を、発信呼び出しを示す PICurrent スロットおよびサービスコンテキストと一緒に使用する必要があるということです。
再帰を回避するもっと簡単な方法として、発信呼び出しの参照先を、ロギングインタセプタが登録されていない別の ORB に関連付けるという方法があります。こうすれば、発信呼び出しがインタセプタに入っていくことがありません。
これは簡単な解決方法に思えますが、一般にインタセプタは、起動時に VM に渡すプロパティーによって登録されます。そうすると、その VM 内で作成されるすべての ORB はすべてのインタセプタを含んでいることになるため、この方法はうまくいきません。
この方法がうまくいくようにするには、ORB.init の際にクライアントコード内でインタセプタを明示的に登録します。しかし、そのような方法でインタセプタベースのサービスを登録することは一般的でないため、推奨されていません。
これまでに紹介した図で説明されているコードが、次のファイルに含まれています。これらの例をコンパイルして実行する方法は、コードの後に記載します。この例に含まれるファイルは次のとおりです。
serviceexample.idl
LoggingServiceClientORBInitializer.java
LoggingServiceClientInterceptor.java
LoggingServiceServerORBInitializer.java
LoggingServiceServerInterceptor.java
LoggingServiceImpl.java
AServiceORBInitializer.java
AServiceImpl.java
AServiceInterceptor.java
AServiceIORInterceptor.java
ArbitaryObjectImpl.java
Client.java
ColocatedServers.java
serviceexample.idl
このファイルは、インタフェース定義言語 (IDL) ファイルで、呼び出しの対象となる任意のオブジェクトの定義と、その任意のオブジェクトに対する呼び出しを実行する 2 つのサービスを含んでいます。
// serviceexample.idl // Copyright and License module pi { module serviceexample { // Create some arbitrary object to call. Those calls // will be serviced by the service implemented using interceptors. exception ArbitraryObjectException { string reason; }; interface ArbitraryObject { string arbitraryOperation1 ( in string a1 ); oneway void arbitraryOperation2 ( in long a1 ); void arbitraryOperation3 ( in string a1 ) raises (ArbitraryObjectException); }; // This would typically be in a file separate from the "ArbitraryObject" // and probably unknown to it. interface LoggingService { void log ( in string a1 ); }; // This would also typically be in a file of its own. // IMPORTANT: the interface should be a local object to avoid // unnecessary overhead. /*local*/ interface AService { void begin(); void end(); void verify(); }; // Tagged component for adding to an IOR to indicate that // the AService must be in effect when invocations are made // on the object containing this tagged component. // Note: we explicitly declare the tag type rather than using // the IOP typedef (commented out) to simplify compiling this // example (i.e., to avoid includes and make include path directives). //const IOP::ComponentId TAG_ASERVICE_COMPONENT = 2345; const unsigned long TAG_ASERVICE_COMPONENT = 2345; struct ASERVICE_COMPONENT { boolean requiresAService; }; }; // module serviceexample }; // module pi
LoggingServiceClientORBInitializer.java
このファイルでは、オブジェクトのクライアントによって使用されるロギングサービスインタセプタを作成して登録します。
// LoggingServiceClientORBInitializer.java // Copyright and License package pi.serviceexample; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.PortableInterceptor.Current; import org.omg.PortableInterceptor.CurrentHelper; import org.omg.PortableInterceptor.ORBInitInfo; public class LoggingServiceClientORBInitializer extends org.omg.CORBA.LocalObject implements org.omg.PortableInterceptor.ORBInitializer { public void pre_init(ORBInitInfo info) { } public void post_init(ORBInitInfo info) { try { // Get a reference to the LoggingService object. NamingContext nameService = NamingContextHelper.narrow( info.resolve_initial_references("NameService")); NameComponent path[] = { new NameComponent("LoggingService", "") }; LoggingService loggingService = LoggingServiceHelper.narrow(nameService.resolve(path)); // Get a reference to TSC PICurrent. Current piCurrent = CurrentHelper.narrow( info.resolve_initial_references("PICurrent")); // Allocate a slot id to use for the interceptor to indicate // that it is making an outcall. This is used to avoid // infinite recursion. int outCallIndicatorSlotId = info.allocate_slot_id(); // Create (with the above data) and register the client // side interceptor. LoggingServiceClientInterceptor interceptor = new LoggingServiceClientInterceptor(loggingService, piCurrent, outCallIndicatorSlotId); info.add_client_request_interceptor(interceptor); } catch (Throwable t) { System.out.println("Exception handling not shown."); } } }
LoggingServiceClientInterceptor.java
このインタセプタは、クライアント側の遮断点をログに記録します。次のコードは、インタセプタ内からほかのオブジェクトの呼び出しを実行する方法と、それらの「発信」呼び出しでの無限回帰を回避する方法を示しています。
// LoggingServiceClientInterceptor.java // Copyright and License package pi.serviceexample; import org.omg.CORBA.Any; import org.omg.CORBA.ORB; import org.omg.CORBA.TCKind; import org.omg.IOP.ServiceContext; import org.omg.PortableInterceptor.ClientRequestInterceptor; import org.omg.PortableInterceptor.ClientRequestInfo; import org.omg.PortableInterceptor.Current; import org.omg.PortableInterceptor.InvalidSlot; public class LoggingServiceClientInterceptor extends org.omg.CORBA.LocalObject implements ClientRequestInterceptor { private LoggingService loggingService; private Current piCurrent; private int outCallIndicatorSlotId; public LoggingServiceClientInterceptor(LoggingService loggingService, Current piCurrent, int outCallIndicatorSlotId) { this.loggingService = loggingService; this.piCurrent = piCurrent; this.outCallIndicatorSlotId = outCallIndicatorSlotId; } // // Interceptor operations // public String name() { return "LoggingServiceClientInterceptor"; } public void destroy() { } // // ClientRequestInterceptor operations // public void send_request(ClientRequestInfo ri) { log(ri, "send_request"); } public void send_poll(ClientRequestInfo ri) { log(ri, "send_poll"); } public void receive_reply(ClientRequestInfo ri) { log(ri, "receive_reply"); } public void receive_exception(ClientRequestInfo ri) { log(ri, "receive_exception"); } public void receive_other(ClientRequestInfo ri) { log(ri, "receive_other"); } // // Utilities. // public void log(ClientRequestInfo ri, String point) { // IMPORTANT: Always set the TSC out call indicator in case // other interceptors make outcalls for this request. // Otherwise the outcall will not be set for the other interceptor's // outcall resulting in infinite recursion. Any indicator = ORB.init().create_any(); indicator.insert_boolean(true); try { piCurrent.set_slot(outCallIndicatorSlotId, indicator); } catch (InvalidSlot e) { } try { indicator = ri.get_slot(outCallIndicatorSlotId); // If the RSC out call slot is not set then log this invocation. // If it is set that indicates the interceptor is servicing the // invocation of loggingService itself. In that case do // nothing (to avoid infinite recursion). if (indicator.type().kind().equals(TCKind.tk_null)) { loggingService.log(ri.operation() + " " + point); } } catch (InvalidSlot e) { System.out.println("Exception handling not shown."); } } }
LoggingServiceServerORBInitializer.java
// LoggingServiceServerORBInitializer.java // Copyright and License package pi.serviceexample; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.PortableInterceptor.Current; import org.omg.PortableInterceptor.CurrentHelper; import org.omg.PortableInterceptor.ORBInitInfo; public class LoggingServiceServerORBInitializer extends org.omg.CORBA.LocalObject implements org.omg.PortableInterceptor.ORBInitializer { public void pre_init(ORBInitInfo info) { } public void post_init(ORBInitInfo info) { try { // Create and register the logging service interceptor. // Give that interceptor references to the NameService and // PICurrent to avoid further lookups (i.e., optimization). // More importantly, allocate and give the interceptor // a slot id which is will use to tell itself not to // log calls that the interceptor makes to the logging process. NamingContext nameService = NamingContextHelper.narrow( info.resolve_initial_references("NameService")); Current piCurrent = CurrentHelper.narrow( info.resolve_initial_references("PICurrent")); int outCallIndicatorSlotId = info.allocate_slot_id(); LoggingServiceServerInterceptor interceptor = new LoggingServiceServerInterceptor(nameService, piCurrent, outCallIndicatorSlotId); info.add_client_request_interceptor(interceptor); info.add_server_request_interceptor(interceptor); } catch (Throwable t) { System.out.println("Exception handling not shown."); } } }
LoggingServiceServerInterceptor.java
このインタセプタは、サーバー側の遮断点をログに記録しますが、ClientRequestInterceptor および ServerRequestInterceptor の両方として実装されます。これは、LoggingServiceServerORBInitializer.java の説明で触れたようなケースでの無限回帰を回避するために、「発信呼び出し」サービスコンテキストのデータの一部を (発信呼び出しスロットに加えて) 設定する必要があることを説明するためです。
// LoggingServiceServerInterceptor.java // Copyright and License package pi.serviceexample; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.CORBA.Any; import org.omg.CORBA.BAD_PARAM; import org.omg.CORBA.ORB; import org.omg.CORBA.TCKind; import org.omg.IOP.ServiceContext; import org.omg.PortableInterceptor.ClientRequestInterceptor; import org.omg.PortableInterceptor.ClientRequestInfo; import org.omg.PortableInterceptor.Current; import org.omg.PortableInterceptor.InvalidSlot; import org.omg.PortableInterceptor.ServerRequestInterceptor; import org.omg.PortableInterceptor.ServerRequestInfo; public class LoggingServiceServerInterceptor extends org.omg.CORBA.LocalObject implements ClientRequestInterceptor, ServerRequestInterceptor { private NamingContext nameService; private LoggingService loggingService; private Current piCurrent; private int outCallIndicatorSlotId; private static final int serviceContextId = 100001; private static final byte[] serviceContextData = {1}; // Returns a reference to the logging process. private LoggingService loggingService() { if (loggingService == null) { NameComponent path[] = { new NameComponent("LoggingService", "") }; try { loggingService = LoggingServiceHelper.narrow(nameService.resolve(path)); } catch (Throwable t) { System.out.println("Exception handling not shown."); } } return loggingService; } public LoggingServiceServerInterceptor(NamingContext nameService, Current piCurrent, int outCallIndicatorSlotId) { this.nameService = nameService; this.piCurrent = piCurrent; this.outCallIndicatorSlotId = outCallIndicatorSlotId; } // // Interceptor operations // public String name() { return "LoggingServiceServerInterceptor"; } public void destroy() { } // // ClientRequestInterceptor operations // public void send_request(ClientRequestInfo ri) { // If the server interceptor sets the recursion slot then // put in the service context so the server doesn't make // the call again in the case where the server side interceptor // is colocated in the same ORB as the object being invoked. try { Any indicator = ri.get_slot(outCallIndicatorSlotId); if (indicator.type().kind().equals(TCKind.tk_boolean)) { ServiceContext serviceContext = new ServiceContext(serviceContextId, serviceContextData); ri.add_request_service_context(serviceContext, false); } } catch (InvalidSlot e) { System.out.println("Exception handling not shown."); } } public void send_poll(ClientRequestInfo ri) { } public void receive_reply(ClientRequestInfo ri) { } public void receive_exception(ClientRequestInfo ri) { } public void receive_other(ClientRequestInfo ri) { } // // ServerRequestInterceptor operations // public void receive_request_service_contexts(ServerRequestInfo ri) { log(ri, "receive_request_service_contexts"); } public void receive_request(ServerRequestInfo ri) { log(ri, "receive_request"); } public void send_reply(ServerRequestInfo ri) { log(ri, "send_reply"); } public void send_exception(ServerRequestInfo ri) { log(ri, "send_exception"); } public void send_other(ServerRequestInfo ri) { log(ri, "send_other"); } // // Utilities. // public void log(ServerRequestInfo ri, String point) { // This is only relevant for the colocated example. // Do not attempt to log until the logging service object // has been bound in naming. Otherwise the attempt to call // rebind on naming will call log which will fail. if (! ColocatedServers.colocatedBootstrapDone) { return; } // IMPORTANT: // The conditional logging of the invocation is only necessary // if there is a chance that the object being invoked is colocated // in the same ORB as this interceptor. Otherwise the outcall to // the logging service can be made unconditionally. // Always set the recursion slot. Any indicator = ORB.init().create_any(); indicator.insert_boolean(true); try { piCurrent.set_slot(outCallIndicatorSlotId, indicator); } catch (InvalidSlot e) { System.out.println("Exception handling not shown."); } // Make the out call if you have not already done so. try { // Only the presence of the service context counts. // The data is ignored. ri.get_request_service_context(serviceContextId); } catch (BAD_PARAM e) { // Recursion indicator not set so make the call. loggingService().log(ri.operation() + " " + point); } } }
LoggingServiceImpl.java
// // Copyright and License package pi.serviceexample; import org.omg.CORBA.ORB; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.PortableServer.POAHelper; import java.util.Properties; class LoggingServiceImpl extends LoggingServicePOA { public static ORB orb; // // The IDL operations. // public void log(String a1) { System.out.println(a1); } // // The server. // public static void main(String[] av) { try { if (orb == null) { orb = ORB.init(av, null); } POA rootPOA = POAHelper.narrow( orb.resolve_initial_references("RootPOA")); rootPOA.the_POAManager().activate(); byte[] objectId = rootPOA.activate_object(new LoggingServiceImpl()); org.omg.CORBA.Object ref = rootPOA.id_to_reference(objectId); NamingContext nameService = NamingContextHelper.narrow( orb.resolve_initial_references("NameService")); NameComponent path[] = { new NameComponent("LoggingService", "") }; nameService.rebind(path, ref); // Only relevant for colocated example. ColocatedServers.colocatedBootstrapDone = true; System.out.println("LoggingService ready."); orb.run(); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } System.exit(0); } }
AServiceORBInitializer.java
// AServiceORBInitializer.java // Copyright and License package pi.serviceexample; import org.omg.IOP.Codec; import org.omg.IOP.CodecFactory; import org.omg.IOP.CodecFactoryHelper; import org.omg.IOP.Encoding; import org.omg.PortableInterceptor.Current; import org.omg.PortableInterceptor.CurrentHelper; import org.omg.PortableInterceptor.ORBInitInfo; public class AServiceORBInitializer extends org.omg.CORBA.LocalObject implements org.omg.PortableInterceptor.ORBInitializer { private AServiceImpl aServiceImpl; private AServiceInterceptor aServiceInterceptor; public void pre_init(ORBInitInfo info) { try { int id = info.allocate_slot_id(); aServiceInterceptor = new AServiceInterceptor(id); info.add_client_request_interceptor(aServiceInterceptor); info.add_server_request_interceptor(aServiceInterceptor); // Create and register a reference to the service to be // used by client code. aServiceImpl = new AServiceImpl(id); info.register_initial_reference("AService", aServiceImpl); } catch (Throwable t) { System.out.println("Exception handling not shown."); } } public void post_init(ORBInitInfo info) { try { Current piCurrent = CurrentHelper.narrow( info.resolve_initial_references("PICurrent")); aServiceImpl.setPICurrent(piCurrent); CodecFactory codecFactory = CodecFactoryHelper.narrow( info.resolve_initial_references("CodecFactory")); Encoding encoding = new Encoding((short)0, (byte)1, (byte)2); Codec codec = codecFactory.create_codec(encoding); aServiceInterceptor.setCodec(codec); AServiceIORInterceptor aServiceIORInterceptor = new AServiceIORInterceptor(codec); info.add_ior_interceptor(aServiceIORInterceptor); } catch (Throwable t) { System.out.println("Exception handling not shown."); } } }
AServiceImpl.java
// // Copyright and License package pi.serviceexample; import org.omg.CORBA.Any; import org.omg.CORBA.TCKind; import org.omg.CORBA.LocalObject; import org.omg.CORBA.ORB; import org.omg.PortableInterceptor.Current; import org.omg.PortableInterceptor.InvalidSlot; class AServiceImpl extends LocalObject implements AService { private int slotId; private int currentServiceId = 0; private Current piCurrent; private Any NOT_IN_EFFECT; public AServiceImpl(int slotId) { this.slotId = slotId; NOT_IN_EFFECT = ORB.init().create_any(); } // Package protected so the AService ORBInitializer can access this // non-IDL defined method. void setPICurrent(Current piCurrent) { this.piCurrent = piCurrent; } public void begin() { Any any = ORB.init().create_any(); any.insert_long(++currentServiceId); setSlot(any); } public void end() { setSlot(NOT_IN_EFFECT); } public void verify() { try { Any any = piCurrent.get_slot(slotId); if (any.type().kind().equals(TCKind.tk_long)) { System.out.println("Service present: " + any.extract_long()); } else { System.out.println("Service not present"); } } catch (InvalidSlot e) { System.out.println("Exception handling not shown."); } } // Synchronized because two threads in the same ORB could be // sharing this object. synchronized private void setSlot(Any any) { try { piCurrent.set_slot(slotId, any); } catch (InvalidSlot e) { System.out.println("Exception handling not shown."); } } }
AServiceInterceptor.java
このインタセプタは、クライアント側の AService 情報をサービス側に渡すための準備を行います。
クライアント側では、AService.begin() が呼び出されると、send_request(ri) ポイントが RSC スロット内のサービス ID を確認します。この場合、これはサービス ID の値を org.omg.CORBA.ServiceContext に挿入し、そのサービスコンテキストを呼び出しで渡されるデータに追加します。
サーバー側では、receive_request_service_context(ri) が、そのサービスコンテキストの存在を確認します。存在している場合、これは ServiceContext からサービス ID 値を抽出し、RSC スロットをその値に設定します。サーバントの実行中は、RSC スロットの値を TSC スロット内で使用できます。
// AServiceInterceptor.java // Copyright and License package pi.serviceexample; import org.omg.CORBA.Any; import org.omg.CORBA.BAD_PARAM; import org.omg.CORBA.ORB; import org.omg.CORBA.TCKind; import org.omg.IOP.Codec; import org.omg.IOP.CodecPackage.FormatMismatch; import org.omg.IOP.CodecPackage.TypeMismatch; import org.omg.IOP.ServiceContext; import org.omg.IOP.TaggedComponent; import org.omg.PortableInterceptor.ClientRequestInterceptor; import org.omg.PortableInterceptor.ClientRequestInfo; import org.omg.PortableInterceptor.InvalidSlot; import org.omg.PortableInterceptor.ServerRequestInterceptor; import org.omg.PortableInterceptor.ServerRequestInfo; public class AServiceInterceptor extends org.omg.CORBA.LocalObject implements ClientRequestInterceptor, ServerRequestInterceptor { private int slotId; private Codec codec; private static final int serviceContextId = 1234; public AServiceInterceptor(int slotId) { this.slotId = slotId; } void setCodec(Codec codec) { this.codec = codec; } // // Interceptor operations // public String name() { return "AServiceInterceptor"; } public void destroy() { } // // ClientRequestInterceptor operations // public void send_request(ClientRequestInfo ri) { // // See if the target object contains an ASERVICE_COMPONENT. // try { TaggedComponent taggedComponent = ri.get_effective_component(TAG_ASERVICE_COMPONENT.value); Any sAny = null; try { sAny = codec.decode_value(taggedComponent.component_data, ASERVICE_COMPONENTHelper.type()); } catch (TypeMismatch e) { System.out.println("Exception handling not shown."); } catch (FormatMismatch e) { System.out.println("Exception handling not shown."); } ASERVICE_COMPONENT aServiceComponent = ASERVICE_COMPONENTHelper.extract(sAny); // // Only send the service context if the target object requires it. // if (aServiceComponent.requiresAService) { try { Any any = ri.get_slot(slotId); if (any.type().kind().equals(TCKind.tk_long)) { int serviceId = any.extract_long(); byte[] serviceContextData = { // Little endian to make it // easier to see in debugger. (byte)((serviceId >>> 0) & 0xFF), (byte)((serviceId >>> 8) & 0xFF), (byte)((serviceId >>> 16) & 0xFF), (byte)((serviceId >>> 24) & 0xFF) }; ri.add_request_service_context( new ServiceContext(serviceContextId, serviceContextData), false); } } catch (InvalidSlot e) { System.out.println("Exception handling not shown."); } } } catch (BAD_PARAM e) { // If it is not present, do nothing. ; } } public void send_poll(ClientRequestInfo ri) { } public void receive_reply(ClientRequestInfo ri) { } public void receive_exception(ClientRequestInfo ri) { } public void receive_other(ClientRequestInfo ri) { } // // ServerRequestInterceptor operations // public void receive_request_service_contexts(ServerRequestInfo ri) { try { ServiceContext serviceContext = ri.get_request_service_context(serviceContextId); byte[] data = serviceContext.context_data; int b1, b2, b3, b4; b4 = (data[0] << 0) & 0x000000FF; b3 = (data[1] << 8) & 0x0000FF00; b2 = (data[2] << 16) & 0x00FF0000; b1 = (data[3] << 24) & 0xFF000000; int serviceId = (b1 | b2 | b3 | b4); Any any = ORB.init().create_any(); any.insert_long(serviceId); ri.set_slot(slotId, any); } catch (BAD_PARAM e) { // Not present means service is not in effect. // Do nothing. ; } catch (InvalidSlot e) { System.out.println("Exception handling not shown."); } } public void receive_request(ServerRequestInfo ri) { } public void send_reply(ServerRequestInfo ri) { } public void send_exception(ServerRequestInfo ri) { } public void send_other(ServerRequestInfo ri) { } }
AServiceIORInterceptor.java
// AServiceIORInterceptor.java // Copyright and License package pi.serviceexample; import org.omg.CORBA.Any; import org.omg.CORBA.LocalObject; import org.omg.CORBA.ORB; import org.omg.IOP.TaggedComponent; import org.omg.IOP.Codec; import org.omg.IOP.CodecPackage.InvalidTypeForEncoding; import org.omg.PortableInterceptor.IORInfo; import org.omg.PortableInterceptor.IORInterceptor; public class AServiceIORInterceptor extends org.omg.CORBA.LocalObject implements IORInterceptor { private Codec codec; public AServiceIORInterceptor(Codec codec) { this.codec = codec; } // // Interceptor operations // public String name() { return "AServiceInterceptor"; } public void destroy() { } // // IOR Interceptor operations // public void establish_components(IORInfo info) { // // Note: typically, rather than just inserting a tagged component // this interceptor would check info.get_effective_policy(int) // to determine if a tagged component reflecting that policy // should be added to the IOR. That is not shown in this example. // ASERVICE_COMPONENT aServiceComponent = new ASERVICE_COMPONENT(true); Any any = ORB.init().create_any(); ASERVICE_COMPONENTHelper.insert(any, aServiceComponent); byte[] value = null; try { value = codec.encode_value(any); } catch (InvalidTypeForEncoding e) { System.out.println("Exception handling not shown."); } TaggedComponent taggedComponent = new TaggedComponent(TAG_ASERVICE_COMPONENT.value, value); info.add_ior_component(taggedComponent); } }
ArbitaryObjectImpl.java
このファイルは、ArbitraryObject IDL インタフェースのサーバーおよび実装です。この IDL インタフェースオペレーションの実装では、クライアントからサーバントへの AService.begin() を使用したエンドツーエンドデータの受け渡しを説明するために、AServiceImpl.verify() メソッドを明示的に呼び出しています。
// ArbitaryObjectImpl.java // Copyright and License package pi.serviceexample; import org.omg.CORBA.ORB; import org.omg.CORBA.ORBPackage.InvalidName; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.PortableServer.POAHelper; import java.util.Properties; class ArbitraryObjectImpl extends ArbitraryObjectPOA { public static ORB orb; private AService aService; // // The IDL operations. // public String arbitraryOperation1(String a1) { verifyService(); return "I got this from the client: " + a1; } public void arbitraryOperation2 (int a1) { verifyService(); } public void arbitraryOperation3(String a1) throws ArbitraryObjectException { verifyService(); if (a1.equals("throw exception")) { throw new ArbitraryObjectException("because you told me to"); } } private void verifyService() { getAService().verify(); } private AService getAService() { // Only look up the service once, then cache it. if (aService == null) { try { aService = AServiceHelper.narrow( orb.resolve_initial_references("AService")); } catch (InvalidName e) { System.out.println("Exception handling not shown."); } } return aService; } // // The server. // public static void main(String[] av) { try { if (orb == null) { Properties props = new Properties(); props.put("org.omg.PortableInterceptor.ORBInitializerClass." + "pi.serviceexample.AServiceORBInitializer", ""); props.put("org.omg.PortableInterceptor.ORBInitializerClass." + "pi.serviceexample.LoggingServiceServerORBInitializer", ""); orb = ORB.init(av, props); } POA rootPOA = POAHelper.narrow( orb.resolve_initial_references("RootPOA")); // Create a POA so the IOR interceptor executes. POA childPOA = rootPOA.create_POA("childPOA", null, null); childPOA.the_POAManager().activate(); byte[] objectId = childPOA.activate_object(new ArbitraryObjectImpl()); org.omg.CORBA.Object ref = childPOA.id_to_reference(objectId); NamingContext nameService = NamingContextHelper.narrow( orb.resolve_initial_references("NameService")); NameComponent path[] = { new NameComponent("ArbitraryObject", "") }; nameService.rebind(path, ref); System.out.println("ArbitaryObject ready."); orb.run(); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } System.exit(0); } }
Client.java
これは、ArbitraryObject に対するメソッドを呼び出すクライアントです。このクライアントは、AService のコンテキストの内部と外部で、それらの呼び出しをいくつか実行します。クライアントは、ロギングインタセプタの存在を認識しません。ただし、前の例のように LoggingServerClientORBInitializer を明示的に登録します。
// Client.java // Copyright and License package pi.serviceexample; import org.omg.CORBA.ORB; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import java.util.Properties; public class Client { public static void main(String av[]) { try { Properties props = new Properties(); props.put("org.omg.PortableInterceptor.ORBInitializerClass." + "pi.serviceexample.AServiceORBInitializer", ""); props.put("org.omg.PortableInterceptor.ORBInitializerClass." + "pi.serviceexample.LoggingServiceClientORBInitializer", ""); ORB orb = ORB.init(av, props); // // The client obtains a reference to a service. // The client does not know the service is implemented // using interceptors. // AService aService = AServiceHelper.narrow( orb.resolve_initial_references("AService")); // // The client obtains a reference to some object that // it will invoke. // NamingContext nameService = NamingContextHelper.narrow( orb.resolve_initial_references("NameService")); NameComponent arbitraryObjectPath[] = { new NameComponent("ArbitraryObject", "") }; ArbitraryObject arbitraryObject = ArbitraryObjectHelper.narrow(nameService.resolve(arbitraryObjectPath)); // // The client begins the service so that invocations of // any object will be done with that service in effect. // aService.begin(); arbitraryObject.arbitraryOperation1("one"); arbitraryObject.arbitraryOperation2(2); // // The client ends the service so that further invocations // of any object will not be done with that service in effect. // aService.end(); // This invocation is not serviced by aService since // it is outside the begin/end. arbitraryObject.arbitraryOperation3("just return"); aService.begin(); try { arbitraryObject.arbitraryOperation3("throw exception"); throw new RuntimeException("should not see this"); } catch (ArbitraryObjectException e) { // Expected in this example, so do nothing. } aService.end(); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } System.out.println("Client done."); System.exit(0); } }
ColocatedServers.java
このファイルは、ArbitraryObject および LoggingService の両方を同一の ORB 内で実行するサーバーです。つまり、これらのオブジェクトは「同じ場所に置かれています」。
このサーバーは、LoggingServiceServerInterceptor 内のコードを試すために、このような方法で作成されています。このコードは、インタセプタが、同じ ORB 内に置かれている複数のオブジェクトに対する呼び出しを実行するときに、無限回帰を回避するために追加の処理を実行する必要があることを示しています。
// ColocatedServers.java // Copyright and License package pi.serviceexample; import org.omg.CORBA.ORB; import java.util.Properties; public class ColocatedServers { public static ORB orb; public static boolean colocatedBootstrapDone = false; public static void main (String[] av) { try { // // Share an ORB between objects servers. // Properties props = new Properties(); props.put("org.omg.PortableInterceptor.ORBInitializerClass." + "pi.serviceexample.AServiceORBInitializer", ""); props.put("org.omg.PortableInterceptor.ORBInitializerClass." + "pi.serviceexample.LoggingServiceServerORBInitializer", ""); ORB orb = ORB.init(av, props); ArbitraryObjectImpl.orb = orb; LoggingServiceImpl.orb = orb; // // Start both object servers. // ServerThread ServerThread = new ServerThread(av); ServerThread.start(); ArbitraryObjectImpl.main(av); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } } } class ServerThread extends Thread { String[] av; ServerThread (String[] av) { this.av = av; } public void run () { LoggingServiceImpl.main(av); } }
ロギングの例とサービスの例が含まれているこれらのコード例は、次のような Makefile を使用してコンパイルおよび実行することができます。
# Makefile for the Example Files # Copyright and License JAVA_HOME=/path_to_J2SE_installation CLASSPATH=. JAVAC=$(JAVA_HOME)/bin/javac JAVA=$(JAVA_HOME)/bin/java ORB_INITIAL_PORT=1050 IDLJ=$(JAVA_HOME)/bin/idlj IDLJ_FLAGS=-fall -td $(CLASSPATH) -verbose ORBD=${JAVA_HOME}/bin/orbd -ORBInitialPort ${ORB_INITIAL_PORT} build: $(IDLJ) $(IDLJ_FLAGS) serviceexample.idl $(JAVAC) -d $(CLASSPATH) *.java $(JAVAC) pi/serviceexample/*.java runorbd: $(ORBD) runloggingservice: $(JAVA) -classpath $(CLASSPATH) pi.serviceexample.LoggingServiceImpl \ -ORBInitialPort ${ORB_INITIAL_PORT} runarbitraryobject: $(JAVA) -classpath $(CLASSPATH) pi.serviceexample.ArbitraryObjectImpl \ -ORBInitialPort ${ORB_INITIAL_PORT} runcolocatedservers: $(JAVA) -classpath $(CLASSPATH) pi.serviceexample.ColocatedServers \ -ORBInitialPort ${ORB_INITIAL_PORT} runclient: $(JAVA) -classpath $(CLASSPATH) pi.serviceexample.Client \ -ORBInitialPort ${ORB_INITIAL_PORT} clean: rm -rf pi rm -rf orb.db # Order of steps: # Build: clean build # Remote: runorbd runloggingservice runarbitraryobjectimpl runclient # Colocated: runorbd runcolocatedservers runclient
次に、上記の Makefile を使用して Solaris オペレーティングシステム上でこの例をビルドし、実行するための手順を紹介します。ここで紹介するコマンドを、コマンドプロンプトから実行してください。%
記号は、記載されているコマンドをコマンドプロンプトから実行するべきであることを示すために使用しています。
このステップの後、次のような出力が表示されます。
resolve send_request resolve receive_reply arbitraryOperation1 send_request Service present: 1 arbitraryOperation1 receive_reply arbitraryOperation2 send_request Service present: 1 arbitraryOperation2 receive_other arbitraryOperation3 send_request Service not present arbitraryOperation3 receive_reply arbitraryOperation3 send_request Service present: 2 arbitraryOperation3 receive_exception Client done.
このステップの後、次のような出力が表示されます。
[1] Running make runorbd & [2]- Running make runloggingservice & [3]+ Running make runarbitraryobject &
このステップの後、次のような出力が表示されます。
log receive_request_service_contexts log receive_request resolve send_request log send_reply log receive_request_service_contexts log receive_request resolve receive_reply log send_reply log receive_request_service_contexts log receive_request arbitraryOperation1 send_request log send_reply arbitraryOperation1 receive_request_service_contexts arbitraryOperation1 receive_request Service present: 1 arbitraryOperation1 send_reply log receive_request_service_contexts log receive_request arbitraryOperation1 receive_reply log send_reply log receive_request_service_contexts log receive_request arbitraryOperation2 send_request log send_reply arbitraryOperation2 receive_request_service_contexts arbitraryOperation2 receive_request log receive_request_service_contexts Service present: 1 arbitraryOperation2 send_reply log receive_request arbitraryOperation2 receive_other log send_reply log receive_request_service_contexts log receive_request arbitraryOperation3 send_request log send_reply arbitraryOperation3 receive_request_service_contexts arbitraryOperation3 receive_request Service not present arbitraryOperation3 send_reply log receive_request_service_contexts log receive_request arbitraryOperation3 receive_reply log send_reply log receive_request_service_contexts log receive_request arbitraryOperation3 send_request log send_reply arbitraryOperation3 receive_request_service_contexts arbitraryOperation3 receive_request Service present: 2 arbitraryOperation3 send_exception log receive_request_service_contexts log receive_request arbitraryOperation3 receive_exception log send_reply Client done.
このステップの後、次のような出力が表示されます。
[1]- Running make runorbd & [4]+ Running make runcolocatedservers &
ORBInitInfo