最終更新日: 2002/4/25
注: このドキュメントは、高度な知識を持つ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の例は、クライアント・プログラムに登録されたClientRequestInterceptorと、サーバー・プログラムに登録されたServerRequestInterceptorとで構成されます。これらのインタセプタは、クライアントおよびサーバーから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