Hitachi

VisiBroker Version 5 Borland(R) Enterprise Server VisiBroker(R) デベロッパーズガイド


19.3.2 サンプル:client_server

〈この項の構成〉

(1) サンプルの目的

このサンプルでは,コードを変更しないで,既存のCORBAアプリケーションにポータブルインタセプタを追加する簡単な方法を実際に説明します。ポータブルインタセプタはクライアント側およびサーバ側の両方のどのアプリケーションにも追加できます。これは,ランタイム時に設定する指定のオプションやプロパティで,関連するアプリケーションを再実行することによって行えます。

使用するクライアントおよびサーバアプリケーションは,$VBROKERDIR/examples/vbe/basic/bank_agent(UNIX)または%VBROKERDIR%\examples\vbe\basic\bank_agent(Windows)にあるアプリケーションと類似しています。サンプル全体は抜粋であり,ポータブルインタセプタはランタイム構成時に追加されています。その理由は,VisiBrokerのインタセプタを熟知している開発者にVisiBrokerのインタセプタとOMG固有ポータブルインタセプタ間のコーディングを早く行える方法を提供するためです。

(2) コードの説明

(a) 必須パッケージのインポート

ポータブルインタセプタインタフェースを使用するには,関連パッケージまたはヘッダファイルが組み込まれている必要があります。Java ORBで,DuplicateNameやInvalidNameのようなポータブルインタセプタの例外を使用している場合,org.omg.PortableInterceptor.ORBInitInfoPackageはオプションであることに注意してください。

コードサンプル19-25 ポータブルインタセプタを使用する際の必須ヘッダファイル(C++)
#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"
コードサンプル19-26 ポータブルインタセプタを使用する際の必須パッケージ(Java)
import org.omg.PortableInterceptor.*;
import org.omg.PortableInterceptor.ORBInitInfoPackage.*;

まずクライアント側で,リクエストインタセプタの各部分の書き方について詳細に説明します。クライアント側のリクエストインタセプタをロードするには,インタフェースをインプリメントするクラスであるORBInitializerをインプリメントする必要があります。また,これは初期化を考慮するとサーバ側のリクエストインタセプタにも該当します。

次にこれをインプリメントするコードを示します。

コードサンプル19-27 クライアントリクエストインタセプタをロードするためのORBInitializerの正しい継承
C++の場合
class SampleClientLoader :
   public PortableInterceptor::ORBInitializer
Javaの場合
public class SampleClientLoader extends 
   org.omg.CORBA.LocalObject implements ORBInitializer
コードサンプル19-28 サーバリクエストインタセプタをロードするためのORBInitializerの正しい継承
C++の場合
class SampleServerLoader :
   public PortableInterceptor::ORBInitializer
Javaの場合
public class SampleServerLoader extends
   org.omg.CORBA.LocalObject implements ORBInitializer

インタフェースをインプリメントするオブジェクトであるORBInitializerそれぞれもLocalObjectオブジェクトから継承される必要があることに注意してください。これが必要である理由は,ORBInitializerのIDL定義がキーワードであるlocalを使用するためです。IDLキーワードlocalの詳細については,「25. valuetypeの使用」を参照してください。

ORBの初期化時に,各リクエストインタセプタはpre_init()インタフェースのインプリメンテーションによって追加されています。このインタフェース内では,クライアントリクエストインタセプタは,add_client_request_interceptor()メソッドによって追加されています。関連するクライアントリクエストインタセプタ自身をORBに追加する前に,そのインタセプタが実体化される必要があります。

コードサンプル19-29 クライアント側リクエストインタセプタの初期化およびORBへの登録
C++の場合
public:
   void pre_init(PortableInterceptor::ORBInitInfo_ptr
    _info){
      SampleClientInterceptor *interceptor =
                                  new SampleClientInterceptor;
         try {
            _info->add_client_request_interceptor(interceptor);
            . . .
Javaの場合
public void pre_init(ORBInitInfo info){
   try {
      info.add_client_request_interceptor(new 
                                    SampleClientInterceptor());
      . . .

OMG規格に従って,必須アプリケーションはregister_orb_initializerメソッドによってそれぞれのインタセプタを登録します。詳細については「19.3.2(2)(f) クライアントおよびサーバアプリケーションの開発」を参照してください。VisiBrokerには,このようなインタセプタの別のオプションの登録方法,(DLLによる登録など)があります。この登録方法を使用すると,アプリケーションはコードをまったく変更する必要がなく,その実行方法だけを変更すれば済むという利点があります。実行時の拡張オプションによって,インタセプタが登録され実行されます。オプションはVisiBroker 4.xインタセプタであるvbroker.orb.dynamicLibs=<DLL filename>と同様です。ここで,<DLL filename>はダイナミックリンクライブラリのファイル名であり,拡張子は,UNIXの場合は.so,.sl,.aなどで,Windowsの場合は.dllです。一つ以上のDLLファイルをロードするには,次のように各ファイル名をコンマ(,)で区切ります。

  • vbroker.orb.dynamicLibs=a.so,b.so,c.so(UNIX)

  • vbroker.orb.dynamicLibs=a.dll,b.dll,c.dll(Windows)

動的にインタセプタをロードするには,VISInitインタフェースが使用されます。これはVisiBroker 4.xインタセプタで使用されるものと同様です。詳細については「20. VisiBroker 4.xインタセプタの使用」を参照してください。ORB_initのインプリメンテーションでは,各インタセプタローダの登録は同様に行われます。

コードサンプル19-30 DLLのロードによるクライアント側のORBInitializerの登録(C++)
void ORB_init(int& argc,char* const* argv,CORBA::ORB_ptr orb)
{
   if(_bind_interceptors_installed)return;
 
   SampleClientLoader *client =new SampleClientLoader();
   PortableInterceptor::register_orb_initializer(client);
 
   . . .

クライアント側インタセプタローダの完全なインプリメンテーションを次に示します。

コードサンプル19-31 クライアント側インタセプタローダの完全なインプリメンテーション(C++)
//SampleClientLoader.C
 
#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"
 
#include "SampleClientInterceptor.h"
 
#if !defined(DLL_COMPILE )
#include "vinit.h"
#include "corba.h"
#endif
 
//USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS
 
class SampleClientLoader :
   public PortableInterceptor::ORBInitializer
{
private:
   short int _interceptors_installed;
 
   #if defined(DLL_COMPILE )
   static SampleClientLoader _instance;
   #endif
 
public:
   SampleClientLoader(){
      _interceptors_installed =0;
   }
 
   void pre_init(PortableInterceptor::ORBInitInfo_ptr _info){
      if(_interceptors_installed)return;
 
      cout <<"=====>SampleClientLoader:Installing ..."<<endl;
 
      SampleClientInterceptor *interceptor =
                                 new SampleClientInterceptor;
 
      try {
            _info->add_client_request_interceptor(interceptor);
 
            _interceptors_installed =1;
            cout <<"=====>SampleClientLoader:Interceptors loaded."
                 <<endl;
      }
      catch(PortableInterceptor::ORBInitInfo::DuplicateName &e){
         cout <<"=====>SampleClientLoader:"
              <<e.name <<"already installed!"<<endl;
      }
      catch(...){
         cout <<"=====>SampleClientLoader:other exception occurred!"
              <<endl;
         }
      }
 
      void post_init(PortableInterceptor::ORBInitInfo_ptr _info){
   }
};
 
#if defined(DLL_COMPILE )
 
class VisiClientLoader :VISInit
 
{
private:
      static VisiClientLoader _instance;
      short int _bind_interceptors_installed;
 
public:
   VisiClientLoader():VISInit(1){
   _bind_interceptors_installed =0;
   }
 
   void ORB_init(int&argc,char*const*argv,CORBA::ORB_ptr orb){
      if(_bind_interceptors_installed)return;
 
      try {
            SampleClientLoader *client =new SampleClientLoader();
            PortableInterceptor::register_orb_initializer(client);
 
            _bind_interceptors_installed =1;
      }
 
      catch(const CORBA::Exception&e)
      {
         cerr <<e <<endl;
      }
   }
};
 
//static instance
VisiClientLoader VisiClientLoader::_instance;
 
#endif
コードサンプル19-32 クライアント側インタセプタローダの完全なインプリメンテーション(Java):SampleClientLoader.java
//SampleClientLoader.java
 
import org.omg.PortableInterceptor.*;
import org.omg.PortableInterceptor.ORBInitInfoPackage.*;
 
public class SampleClientLoader extends org.omg.CORBA.LocalObject
implements ORBInitializer
{
   public void pre_init(ORBInitInfo info){
      try {
         System.out.println("=====>SampleClientLoader:
                                                   Installing ...");
         info.add_client_request_interceptor
                                       (new SampleClientInterceptor());
         System.out.println("=====>SampleClientLoader:Interceptors
                                                             loaded.");
      }
      catch(DuplicateName dn){
         System.out.println("=====>SampleClientLoader:"+dn.name
                                                +"already installed.");
      }
      catch(Exception e){
         e.printStackTrace();
         throw new org.omg.CORBA.INITIALIZE(e.toString());
     }
   }
 
      public void post_init(ORBInitInfo info){
         //We do not do anything here.
      }
}

(b) サーバ側インタセプタでのORBInitializerのインプリメント

この段階では,クライアントリクエストインタセプタはすでに正しく実体化され,追加されているはずです。これ以降のコードサンプルは例外処理と結果表示だけを提供します。同様に,サーバ側のサーバリクエストインタセプタにも同じことが行われます。ただし,add_server_request_interceptor()メソッドを使用して関連サーバリクエストインタセプタをORBに追加することが異なります。

コードサンプル19-33 サーバ側リクエストインタセプタの初期化およびORBへの登録
C++の場合
public:
   void pre_init(PortableInterceptor::ORBInitInfo_ptr
    _info){
      SampleServerInterceptor *interceptor =
                                  new SampleServerInterceptor;
      try {
         _info->add_server_request_interceptor(interceptor);
         . . .
Javaの場合
public void pre_init(ORBInitInfo info){
   try {
      info.add_server_request_interceptor(
                                new SampleServerInterceptor());
      . . .

これは,サーバ側ORBInitializerクラスのDLLインプリメンテーションによるロードにも同様に適用されます。

コードサンプル19-34 DLLによってロードされるサーバ側リクエストORBInitializer(C++)
void ORB_init(int& argc,char* const* argv,CORBA::ORB_ptr orb)
{
   if(_poa_interceptors_installed)return;
   SampleServerLoader *server =new SampleServerLoader();
   PortableInterceptor::register_orb_initializer(server);
   . . .

サーバ側インタセプタローダの完全なインプリメンテーションを次に示します。

コードサンプル19-35 サーバ側インタセプタローダの完全なインプリメンテーション(C++)
//SampleServerLoader.C
 
#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"
 
#if defined(DLL_COMPILE )
#include "vinit.h"
#include "corba.h"
#endif
 
#include "SampleServerInterceptor.h"
 
//USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS
 
class SampleServerLoader :
   public PortableInterceptor::ORBInitializer
{
private:
   short int _interceptors_installed;
 
public:
   SampleServerLoader(){
      _interceptors_installed =0;
   }
 
   void pre_init(PortableInterceptor::ORBInitInfo_ptr _info){
       if(_interceptors_installed)return;
 
       cout <<"=====>SampleServerLoader:Installing ..."<<endl;
 
       SampleServerInterceptor *interceptor =
                             new SampleServerInterceptor();
 
       try {
         _info->add_server_request_interceptor(interceptor);
 
         _interceptors_installed =1;
         cout <<"=====>SampleServerLoader:Interceptors loaded."
              <<endl;
       }
       catch(PortableInterceptor::ORBInitInfo::DuplicateName &e){
         cout <<"=====>SampleServerLoader:"
           <<e.name <<"already installed!"<<endl;
       }
       catch(...){
         cout <<"=====>SampleServerLoader:other exception occurred!"
           <<endl;
     }
   }
void post_init(PortableInterceptor::ORBInitInfo_ptr _info){}
};
 
 
#if defined(DLL_COMPILE )
class VisiServerLoader :VISInit
{
private:
   static VisiServerLoader _instance;
   short int _poa_interceptors_installed;
 
public:
   VisiServerLoader():VISInit(1){
   _poa_interceptors_installed =0;
}
void ORB_init(int& argc,char* const* argv,CORBA::ORB_ptr orb){
      if(_poa_interceptors_installed)return;
      try {
            SampleServerLoader *server =new SampleServerLoader();
            PortableInterceptor::register_orb_initializer(server);
            _poa_interceptors_installed =1;
      }
   catch(const CORBA::Exception&e)
      {
      cerr <<e <<endl;
      }
   }
};
//static instance
VisiServerLoader VisiServerLoader::_instance;
 
#endif
コードサンプル19-36 サーバ側インタセプタローダの完全なインプリメンテーション(Java):SampleServerLoader.java
//SampleServerLoader.java
 
import org.omg.PortableInterceptor.*;
import org.omg.PortableInterceptor.ORBInitInfoPackage.*;
 
public class SampleServerLoader extends org.omg.CORBA.LocalObject
implements ORBInitializer
 
{
   public void pre_init(ORBInitInfo info){
      try {
         info.add_server_request_interceptor(new
                  SampleServerInterceptor());
         System.out.println("=====>SampleServerLoader:
                  Interceptors loaded");
      }
      catch(DuplicateName dn){
         System.out.println("Interceptor:
                              "+dn.name +"already installed.");
      }
      catch(Exception e){
         e.printStackTrace();
         throw new org.omg.CORBA.INITIALIZE(e.toString());
      }
   }
   public void post_init(ORBInitInfo info){
      //We do not do anything here.
   }
}

(c) クライアント側およびサーバ側リクエストインタセプタでのRequestInterceptorのインプリメント

クライアント側またはサーバ側のリクエストインタセプタのインプリメンテーション時に,その両方に共通の別の二つのインタフェースをインプリメントする必要があります。それは,name()とdestroy()です。リクエストや応答でロードおよび呼び出しを行うインタセプタを正しく識別するためにORBに名前を提供するので,name()は重要です。CORBAの仕様に従うと,インタセプタはアノニマスでもかまいません。つまり,名前属性として空の文字列でもかまいません。このサンプルでは,SampleClientInterceptorという名前がクライアント側インタセプタに,SampleServerInterceptorという名前がサーバ側インタセプタに割り当てられています。

コードサンプル19-37 インタフェース属性,read-only属性名のインプリメンテーション
C++の場合
public:
   char *name(void){
      return _name;
}
Javaの場合
public String name(){
   return _name;
}

(d) クライアントでのClientRequestInterceptorのインプリメント

クライアントリクエストインタセプタでは,リクエストインタセプタが正しく動作するためにClientRequestInterceptorインタフェースをインプリメントする必要があります。クラスがインタフェースをインプリメントする場合,インプリメンテーションに関係なく五つのリクエストインタセプタメソッドがインプリメントされます。これにはsend_request()メソッド,send_poll()メソッド,receive_reply()メソッド,receive_exception()メソッド,およびreceive_other()メソッドがあります。さらに,事前にリクエストインタセプタのインタフェースをインプリメントしておくことが必要です。クライアント側のインタセプタでは,そのイベントに関して次のリクエストインタセプトポイントが起動されます。

  • send_request

    インタセプトポイントを提供し,インタセプタがリクエスト情報を照会して,リクエストがサーバに送信される前にサービスコンテキストを修正できるようにします。

コードサンプル19-38 public void send_request(ClientRequestInfo ri)インタフェースのインプリメンテーション
C++の場合
void send_request(PortableInterceptor::ClientRequestInfo_ptr ri){
   . . .
Javaの場合
public void send_request(ClientRequestInfo ri)
                                          throws ForwardRequest {
   . . .
コードサンプル19-39 void send_poll(ClientRequestInfo ri)インタフェースのインプリメンテーション
  • send_poll

    インタセプトポイントを提供し,TII(時間非依存呼び出し)ポーリング取得応答シーケンス時に情報をインタセプタが照会できるようにします。

C++の場合
void send_poll(PortableInterceptor::ClientRequestInfo_ptr ri){
   . . .
Javaの場合
public void send_poll(ClientRequestInfo ri){
   . . .
コードサンプル19-40 void receive_reply(ClientRequestInfo ri)インタフェースのインプリメンテーション
  • receive_reply

    インタセプトポイントを提供し,応答がサーバから戻されてから,制御がクライアントに戻る前にインタセプタがその応答に関する情報を照会できるようにします。

C++の場合
void receive_reply(PortableInterceptor::ClientRequestInfo_ptr
                                                           ri){
   . . .
Javaの場合
public void receive_reply(ClientRequestInfo ri){
   . . .
コードサンプル19-41 void receive_exception(ClientRequestInfo ri)インタフェースのインプリメンテーション
  • receive_exception

    インタセプトポイントを提供し,例外がクライアントに発生する前にインタセプタがその例外の情報を照会できるようにします。

C++の場合
void receive_exception
               (PortableInterceptor::ClientRequestInfo_ptr ri){
   . . .
Javaの場合
public void receive_exception(ClientRequestInfo ri)
                                        throws ForwardRequest {
   . . .
  • receive_other

    インタセプトポイントを提供し,リクエスト結果が正常応答または例外以外の結果になった場合に,インタセプタが利用可能な情報を照会できるようにします。例えば,リクエストの結果がリトライ(例: LOCATION_FORWARDステータスのGIOP応答を受信)になる場合です。非同期呼び出しの場合は,リクエストのあとにすぐに応答は行われませんが,制御はクライアントに戻り,終了インタセプトポイントが呼び出されます。

コードサンプル19-42 void receive_other(ClientRequestInfo ri)インタフェースのインプリメンテーション
C++の場合
void receive_other(PortableInterceptor::ClientRequestInfo_ptr
                                                          ri){
   . . .
Javaの場合
public void receive_other(ClientRequestInfo ri)
                                          throws ForwardRequest {
   . . .

クライアント側リクエストインタセプタの完全なインプリメンテーションを次に示します。

コードサンプル19-43 クライアント側リクエストインタセプタの完全なインプリメンテーション(C++)
//SampleClientInterceptor.h
 
#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"
 
//USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS
 
class SampleClientInterceptor :
   public PortableInterceptor::ClientRequestInterceptor
{
private:
   char *_name;
 
   void init(char *name){
      _name =new char [strlen(name)+1 ];
      strcpy(_name,name);
   }
 
public:
   SampleClientInterceptor(char *name){
      init(name);
   }
 
   SampleClientInterceptor(){
      init("SampleClientInterceptor");
   }
 
char *name(void){
   return _name;
}
 
void destroy(void){
   //do nothing here
 
   cout <<"=====>SampleServerLoader:Interceptors unloaded"<<endl;
}
 
/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void preinvoke_premarshal(CORBA::Object_ptr target,
*                           const char*operation,
*                           IOP::ServiceContextList&servicecontexts,
*                           VISClosure&closure)=0;
*/
void send_request(PortableInterceptor::ClientRequestInfo_ptr ri){
   cout <<"=====>SampleClientInterceptor id "<<ri->request_id()
      <<"send_request =>"<<ri->operation()
      <<":Target ="<<ri->target()
      <<endl;
}
 
/**
* There is no equivalent interface for VisiBroker 4.x
* ClientRequestInterceptor.
*/
 
void send_poll(PortableInterceptor::ClientRequestInfo_ptr ri){
   cout <<"=====>SampleClientInterceptor id "<<ri->request_id()
      <<"send_poll =>"<<ri->operation()
      <<":Target ="<<ri->target()
      <<endl;
}
 
/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void postinvoke(CORBA::Object_ptr target,
*                 const IOP::ServiceContextList&service_contexts,
*                 CORBA_MarshalInBuffer&payload,
*                 CORBA::Environment_ptr env,
*                 VISClosure&closure)=0;
*
* with env not holding any exception value.
*/
void receive_reply(PortableInterceptor::ClientRequestInfo_ptr ri){
   cout <<"=====>SampleClientInterceptor id "<<ri->request_id()
      <<"receive_reply =>"<<ri->operation()
      <<endl;
}
 
/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void postinvoke(CORBA::Object_ptr target,
*                 const IOP::ServiceContextList&service_contexts,
*                 CORBA_MarshalInBuffer&payload,
*                 CORBA::Environment_ptr env,
*                 VISClosure&closure)=0;
*
* with env holding the exception value.
*/
void receive_exception(PortableInterceptor::ClientRequestInfo_ptr
                                                              ri){
   cout <<"=====>SampleClientInterceptor id "<<ri->request_id()
      <<"receive_exception =>"<<ri->operation()
      <<":Exception ="<<ri->received_exception()
      <<endl;
}
 
/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void postinvoke(CORBA::Object_ptr target,
*                 const IOP::ServiceContextList&service_contexts,
*                 CORBA_MarshalInBuffer&payload,
*                 CORBA::Environment_ptr env,
*                 VISClosure&closure)=0;
*
* with env holding the exception value.
*/
void receive_other(PortableInterceptor::ClientRequestInfo_ptr ri){
   cout <<"=====>SampleClientInterceptor id "<<ri->request_id()
      <<"receive_other =>"<<ri->operation()
      <<":Exception ="<<ri->received_exception()
      <<",Reply Status ="<<
     getReplyStatus(ri->reply_status())
     <<endl;
   }
 
protected:
   char *getReplyStatus(CORBA::Short status){
      if(status ==PortableInterceptor::SUCCESSFUL)
            return "SUCCESSFUL";
      else if(status ==PortableInterceptor::SYSTEM_EXCEPTION)
            return "SYSTEM_EXCEPTION";
      else if(status ==PortableInterceptor::USER_EXCEPTION)
            return "USER_EXCEPTION";
      else if(status ==PortableInterceptor::LOCATION_FORWARD)
            return "LOCATION_FORWARD";
      else if(status ==PortableInterceptor::TRANSPORT_RETRY)
            return "TRANSPORT_RETRY";
      else
            return "invalid reply status id";
      }
};
コードサンプル19-44 クライアント側リクエストインタセプタの完全なインプリメンテーション(Java):SampleClientInterceptor.java
//SampleClientInterceptor.java
 
import org.omg.PortableInterceptor.*;
import org.omg.Dynamic.*;
 
public class SampleClientInterceptor extends org.omg.CORBA.LocalObject
implements ClientRequestInterceptor {
 
   public SampleClientInterceptor(){
      this("SampleClientInterceptor");
}
 
public SampleClientInterceptor(String name){
_name =name;
}
private String _name =null;
/**
* InterceptorOperations implementation
*/
public String name(){
   return _name;
}
 
public void destroy(){
   System.out.println("=====>SampleServerLoader:Interceptors unloaded");
}
 
/**
* ClientRequestInterceptor implementation
*/
 
/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* public void preinvoke_premarshal(org.omg.CORBA.Object target,
      String operation,
*   ServiceContextListHolder service_contexts_holder,Closure
    closure);
*/
 
public void send_request(ClientRequestInfo ri)throws ForwardRequest {
   System.out.println("=====>SampleClientInterceptor id "+
      ri.request_id()+
           "send_request =>"+ri.operation()+
           ":target ="+ri.target());
}
 
/**
* There is no equivalent interface for VisiBroker 4.x
* ClientRequestInterceptor.
*/
 
public void send_poll(ClientRequestInfo ri){
   System.out.println("=====>SampleClientInterceptor id "+
      ri.request_id()+
           "send_poll => " + ri.operation() +
           " : target = " + ri.target());
}
 
/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* public void postinvoke(org.omg.CORBA.Object target,
*   ServiceContext[ ] service__contexts,InputStream payload,
*   org.omg.CORBA.Environment env,Closure closure);
*
* with env not holding any exception value.
*/
public void receive_reply(ClientRequestInfo ri){
   System.out.println("=====>SampleClientInterceptor id " +
     ri.request_id() +
           " receive_reply => " + ri.operation());
}
 
/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* public void postinvoke(org.omg.CORBA.Object target,
*   ServiceContext[ ] service__contexts,InputStream payload,
*   org.omg.CORBA.Environment env,Closure closure);
*
* with env holding the exception value.
*/
public void receive_exception(ClientRequestInfo ri)throws ForwardRequest {
   System.out.println("=====>SampleClientInterceptor id "+
      ri.request_id() +
            " receive_exception => " + ri.operation() +
            ": exception = " + ri.received_exception());
}
/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* public void postinvoke(org.omg.CORBA.Object target,
*   ServiceContext[ ] service__contexts,InputStream payload,
*   org.omg.CORBA.Environment env,Closure closure);
*
* with env holding the exception value.
*/
public void receive_other(ClientRequestInfo ri) throws ForwardRequest {
   System.out.println("=====> SampleClientInterceptor id "+
      ri.request_id() +
           " receive_reply => " + ri.operation() +
           ": exception = " + ri.received_exception() +
           ", reply status = " + getReplyStatus(ri));
}
protected String getReplyStatus(RequestInfo ri){
   switch(ri.reply_status()){
      case SUCCESSFUL.value:
         return "SUCCESSFUL";
      case SYSTEM_EXCEPTION.value:
         return "SYSTEM_EXCEPTION";
      case USER_EXCEPTION.value:
         return "USER_EXCEPTION";
      case LOCATION_FORWARD.value:
         return "LOCATION_FORWARD";
      case TRANSPORT_RETRY.value:
         return "TRANSPORT_RETRY";
      default:
         return "invalid reply status id";
      }
   }
}

(e) サーバでのServerRequestInterceptorのインプリメント

サーバリクエストインタセプタでは,リクエストインタセプタが正しく動作するためにServerRequestInterceptorインタフェースをインプリメントする必要があります。サーバ側インタセプタでは,各イベントに関して次のリクエストインタセプトポイントが起動されます。

  • receive_request_service_contexts

    インタセプトポイントを提供し,インタセプタが入力リクエストからサービスコンテキスト情報を取得し,それをPortableInterceptor::Currentのスロットに転送できるようにします。このインタセプトポイントはサーバントマネージャの前に呼び出されます。

コードサンプル19-45 void receive_request_service_contexts (ServerRequestInfo ri)インタフェースのインプリメンテーション
C++の場合
void receive_request_service_contexts
                (PortableInterceptor::ServerRequestInfo_ptr
                                                        ri){
   . . .
Javaの場合
public void receive_request_service_contexts
       (ServerRequestInfo ri) throws ForwardRequest{
   . . .
  • receive_request

    インタセプトポイントを提供し,使用できるすべての情報(オペレーションパラメタなど)をインタセプタが照会できるようにします。

コードサンプル19-46 void receive_request (ServerRequestInfo ri)インタフェースのインプリメンテーション
C++の場合
void receive_request(PortableInterceptor::ServerRequestInfo_ptr
                                                           ri){
   . . .
Javaの場合
public void receive_request(ServerRequestInfo ri)
                                         throws ForwardRequest {
   . . .
  • send_reply

    インタセプトポイントを提供し,ターゲットオペレーションが呼び出されたあと,応答がクライアントに戻される前にインタセプタが応答情報を照会し,応答サービスコンテキストを修正できるようにします。

コードサンプル19-47 void send_reply (ServerRequestInfo ri)インタフェースのインプリメンテーション
C++の場合
void send_reply(PortableInterceptor::ServerRequestInfo_ptr
                                                      ri){
   . . .
Javaの場合
public void send_reply(ServerRequestInfo ri){
   . . .
  • send_exception

    インタセプトポイントを提供し,例外がクライアントで発生する前にインタセプタが例外情報を照会し,応答サービスコンテキストを修正できるようにします。

コードサンプル19-48 void send_exception (ServerRequestInfo ri)インタフェースのインプリメンテーション
C++の場合
void send_exception(PortableInterceptor::ServerRequestInfo_ptr 
                                                          ri) {
   . . .
Javaの場合
public void send_exception(ServerRequestInfo ri)throws 
                                                ForwardRequest {
   . . .
  • send_other

    インタセプトポイントを提供し,リクエスト結果が正常応答または例外以外の結果になった場合に,インタセプタが利用可能な情報を照会できるようにします。例えば,リクエストの結果がリトライ(例: LOCATION_FORWARDステータスのGIOP応答を受信)する場合です。非同期呼び出しの場合は,リクエストのあとにすぐに応答は行われませんが,制御はクライアントに戻り,終了インタセプトポイントが呼び出されます。

コードサンプル19-49 void send_other (ServerRequestInfo ri)インタフェースのインプリメンテーション
C++の場合
void send_other(PortableInterceptor::ServerRequestInfo_ptr
                                                        ri){
   . . .
Javaの場合
public void send_other(ServerRequestInfo ri)throws
                                     ForwardRequest {
   . . .

すべてのインタセプトポイントによって,クライアントおよびサーバは異なる種類の情報を呼び出しの異なるポイントで取得できます。サンプルでは,このような情報はデバッグの形式で画面に表示されています。

サーバ側リクエストインタセプタの完全なインプリメンテーションを次に示します。

コードサンプル19-50 サーバ側リクエストインタセプタの完全なインプリメンテーション(C++):SampleServerInterceptor.cpp
// SampleServerInterceptor.h
 
#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"
 
//USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS
 
class SampleServerInterceptor :
   public PortableInterceptor::ServerRequestInterceptor
{
private:
   char *_name;
 
   void init(char *name){
      _name =new char [strlen(name)+1 ];
      strcpy(_name,name);
}
 
public:
   SampleServerInterceptor(char *name){
      init(name);
   }
 
   SampleServerInterceptor(){
      init("SampleServerInterceptor");
   }
 
   char *name(void){
      return _name;
}
 
   void destroy(void){
      //do nothing here
      cout <<"=====>SampleServerLoader:Interceptors unloaded"<<endl;
   }
 
/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void preinvoke_premarshal(CORBA::Object_ptr target,
*                           const char*operation,
*                           IOP::ServiceContextList&servicecontexts,
*                           VISClosure&closure)=0;
*/
void
receive_request_service_contexts(PortableInterceptor::
   ServerRequestInfo_ptr ri){
         cout <<"=====>SampleServerInterceptor id "<<ri->request_id()
         <<"receive_request_service_contexts =>"<<ri->operation()
         <<endl;
}
 
/**
* There is no equivalent interface for VisiBroker 4.x
* SeverRequestInterceptor.
*/
void receive_request(PortableInterceptor::ServerRequestInfo_ptr
                                                              ri)
{
   cout <<"=====>SampleServerInterceptor id "<<ri->request_id()
      <<"receive_request =>"<<ri->operation()
      <<":Object ID ="<<ri->object_id()
      <<",Adapter ID ="<<ri->adapter_id()
      <<endl;
}
 
/**
* There is no equivalent interface for VisiBroker 4.x
* SeverRequestInterceptor.
*/
void send_reply(PortableInterceptor::ServerRequestInfo_ptr ri){
   cout <<"=====>SampleServerInterceptor id "<<ri->request_id()
      <<"send_reply =>"<<ri->operation()
      <<endl;
}
 
/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* virtual void postinvoke_premarshal(CORBA::Object_ptr _target,
*                      IOP::ServiceContextList&_service_contexts,
*                                    CORBA::Environment_ptr _env,
*                                    VISClosure&_closure)=0;
*
*with env holding the exception value.
*/
void send_exception(PortableInterceptor::ServerRequestInfo_ptr
                                                              ri){
   cout << "=====> SampleServerInterceptor id " << ri->request_id()
        << " send_exception => " << ri ->operation()
        << " :Exception = " << ri ->sending_exception()
        << " ,Reply status = " << getReplyStatus(ri->reply_status())
        <<endl;
}
 
/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* virtual void postinvoke_premarshal(CORBA::Object_ptr _target,
*                                    IOP::ServiceContextList&_service_contexts,
*                                    CORBA::Environment_ptr _env,
*                                    VISClosure&_closure)=0;
*
* with env holding the exception value.
*/
void send_other(PortableInterceptor::ServerRequestInfo_ptr ri){
   cout <<"=====>SampleServerInterceptor id "<<ri->request_id()
      <<"send_other =>"<<ri->operation()
      <<":Exception ="<<ri->sending_exception()
      <<",Reply Status ="<<getReplyStatus(ri->reply_status())
      <<endl;
}
 
protected:
   char *getReplyStatus(CORBA::Short status){
      if(status ==PortableInterceptor::SUCCESSFUL)
         return "SUCCESSFUL";
            else if(status ==PortableInterceptor::SYSTEM_EXCEPTION)
         return "SYSTEM_EXCEPTION";
            else if(status ==PortableInterceptor::USER_EXCEPTION)
         return "USER_EXCEPTION";
            else if(status ==PortableInterceptor::LOCATION_FORWARD)
         return "LOCATION_FORWARD";
            else if(status ==PortableInterceptor::TRANSPORT_RETRY)
         return "TRANSPORT_RETRY";
            else
         return "invalid reply status id";
      }
};
コードサンプル19-51 サーバ側リクエストインタセプタの完全なインプリメンテーション(Java):SampleServerInterceptor.java
// SampleServerInterceptor.java
 
import org.omg.PortableInterceptor.*;
import org.omg.Dynamic.*;
import java.io.PrintStream;
 
public class SampleServerInterceptor extends org.omg.CORBA.LocalObject
implements ServerRequestInterceptor {
 
   private String _name =null;
 
   public SampleServerInterceptor(){
      this("SampleServerInterceptor");
   }
 
   public SampleServerInterceptor(String name){
      _name =name;
   }
/**
* InterceptorOperations implementation
*/
public String name() {
      return _name;
}
 
public void destroy(){
   System.out.println("=====>SampleServerLoader:Interceptors unloaded");
}
 
/**
* ServerRequestInterceptor implementation
*/
 
/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* public void preinvoke(org.omg.CORBA.Object target,
*   String operation,
*   ServiceContext[ ] service__contexts,InputStream payload,
*   Closure closure);
*/
 
public void receive_request_service_contexts(ServerRequestInfo ri)
      throws ForwardRequest {
   System.out.println("=====>SampleServerInterceptor id " + 
           ri.request_id() +
           " receive_request_service_contexts => " + ri.operation());
}
 
/**
* There is no equivalent interface for VisiBroker 4.x
* SeverRequestInterceptor.
*/
public void receive_request(ServerRequestInfo ri)
      throws ForwardRequest {
   System.out.println("=====>SampleServerInterceptor id "
            + ri.request_id() +
            " receive_request => " + ri.operation() +
            ": object id = " + ri.object_id() +
            ", adapter_id = " + ri.adapter_id());
}
 
/**
* There is no equivalent interface for VisiBroker 4.x
* SeverRequestInterceptor.
*/
public void send_reply(ServerRequestInfo ri){
   System.out.println("=====> SampleServerInterceptor id " + 
            ri.request_id() +
            " send_reply => " + ri.operation());
}
 
/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* public void postinvoke_premarshal(org.omg.CORBA.Object target,
* ServiceContextListHolder service_contexts_holder,
* org.omg.CORBA.Environment env,Closure closure);
*
*with env holding the exception value.
*/
public void send_exception(ServerRequestInfo ri)
      throws ForwardRequest {
   System.out.println("=====>SampleServerInterceptor id " + 
            ri.request_id() +
            " send_exception => " + ri.operation() +
            ": exception = " + ri.sending_exception() +
            ", reply status = " + getReplyStatus(ri));
}
 
/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* public void postinvoke_premarshal(org.omg.CORBA.Object target,
*   ServiceContextListHolder service_contexts_holder,
*   org.omg.CORBA.Environment env,Closure closure);
*
* with env holding the exception value.
*/
public void send_other(ServerRequestInfo ri)throws ForwardRequest {
      System.out.print("=====>SampleServerInterceptor id "+ 
            ri.request_id() +
            " send_other =>" + ri.operation() +
            ": exception = " + ri.sending_exception() +
            ", reply status = " + getReplyStatus(ri));
}
      protected String getReplyStatus(RequestInfo ri){
         switch(ri.reply_status()){
            case SUCCESSFUL.value:
               return "SUCCESSFUL";
            case SYSTEM_EXCEPTION.value:
               return "SYSTEM_EXCEPTION";
            case USER_EXCEPTION.value:
               return "USER_EXCEPTION";
            case LOCATION_FORWARD.value:
               return "LOCATION_FORWARD";
            case TRANSPORT_RETRY.value:
               return "TRANSPORT_RETRY";
            default:
               return "invalid reply status id";
         }
      }
}

(f) クライアントおよびサーバアプリケーションの開発

インタセプタクラスを書き込んだあと,このクラスをそれぞれクライアントおよびサーバアプリケーションに登録する必要があります。

  • C++の場合

    C++では,クライアントとサーバはPortableInterceptor::register_orb_initializer(<class name>)メソッドによって,それぞれのORBInitializerクラスを登録します。

    ここで,<class name>は登録するクラスの名前です。サンプルでは,DLL(動的リンクライブラリ)としてインタセプタクラスを登録する別の方法も説明します。この方法の利点は,アプリケーションがコードを変更する必要がなく,実行方法だけを変更すればいいということです。「19.3.2(4) クライアントおよびサーバアプリケーションの実行または配置」を参照してください。これはVisiBrokerの適切な登録方法であることに注意してください。OMGに完全に準拠するには,次に示す方法は使用しないでください。

    DLLとしてインタセプタクラスをロードすること(すなわち,VisiBrokerの適切なメソッドを使用すること)を選択したら,クライアントおよびサーバアプリケーションに拡張コードを追加する必要はありません。サンプルでは,DLLコンパイルとリンク付けが指定されていないと,コードの部分がマクロによる適切な状態ではないことがわかります。

    クライアントアプリケーションの完全なインプリメンテーションを次に示します。

    コードサンプル19-52 クライアントアプリケーションの完全なインプリメンテーション(C++)
    //Client.C
     
    #include "Bank_c.hh"
     
    //USE_STD_NS is a define setup by VisiBroker to use the std namespace
    USE_STD_NS
     
    #if !defined(DLL_COMPILE )
    #include "SampleClientLoader.C"
    #endif
     
    int main(int argc, char* const* argv)
    {
       try {
          // Instantiate the Loader *before* the orb initialization
          // if chose not to use DLL method of loading
          #if !defined(DLL_COMPILE )
          SampleClientLoader* loader = new SampleClientLoader;
          PortableInterceptor::register_orb_initializer(loader);
          #endif
     
          // Initialize the ORB.
          CORBA::ORB_var orb =CORBA::ORB_init(argc,argv);
     
          // Get the manager Id
          PortableServer::ObjectId_var managerId =
                   PortableServer::string_to_ObjectId("BankManager");
     
          // Locate an account manager.Give the full POA name and the 
          // servant ID.
          Bank::AccountManager_var manager =
                  Bank::AccountManager::_bind("/bank_agent_poa"
                                                        ,managerId);
     
          // use argv [1 ] as the account name,,or a default.
          const char*name =argc >1 ?argv [1 ] ::"Jack B.Quick";
     
          // Request the account manager to open a named account.
          Bank::Account_var account =manager->open(name);
     
          // Get the balance of the account.
          CORBA::Float balance =account->balance();
     
          // Print out the balance.
          cout <<"The balance in "<<name <<"'s account is $"<<balance
                <<endl;
       }
       catch(const CORBA::Exception&e){
       cerr <<e <<endl;
       return 1;
       }
       return 0;
    }

    サーバアプリケーションの完全なインプリメンテーションを次に示します。

    コードサンプル19-53 サーバアプリケーションの完全なインプリメンテーション(C++)
    // Server.C
     
    #include "BankImpl.h"
     
    // USE_STD_NS is a define setup by VisiBroker to use the std namespace
    USE_STD_NS
     
    #if !defined(DLL_COMPILE )
    #include "SampleServerLoader.C"
    #endif
     
    int main(int argc,char*const*argv)
    {
       try {
           // Instantiate an interceptor loader before initializing
           // the orb:
           #if !defined(DLL_COMPILE )
           SampleServerLoader*loader = new SampleServerLoader();
           PortableInterceptor::register_orb_initializer(loader);
           #endif
     
           // Initialize the ORB.
           CORBA::ORB_var orb = CORBA::ORB_init(argc,argv);
     
           // get a reference to the rootPOA
           CORBA::Object_var obj = orb->
                                     resolve_initial_references("RootPOA");
           PortableServer::POA_var rootPOA =
                                     PortableServer::POA::_narrow(obj);
     
           CORBA::PolicyList policies;
           policies.length(1);
           policies [(CORBA::ULong)0 ] = rootPOA->
                      create_lifespan_policy( PortableServer::PERSISTENT );
     
           // get the POA Manager
           PortableServer::POAManager_var poa_manager =
                                                  rootPOA->the_POAManager();
     
           // Create myPOA with the right policies
           PortableServer::POA_var myPOA =
                                    rootPOA->create_POA("bank_agent_poa",
                                                             poa_manager,
                                                             policies);
     
           // Create the servant
           AccountManagerImpl managerServant;
     
           // Decide on the ID for the servant
           PortableServer::ObjectId_var managerId =
                       PortableServer::string_to_ObjectId("BankManager");
     
           // Activate the servant with the ID on myPOA
           myPOA->activate_object_with_id(managerId,&managerServant);
     
           // Activate the POA Manager
           poa_manager->activate();
     
           CORBA::Object_var reference =
           myPOA->servant_to_reference(&managerServant);
           cout <<reference <<"is ready"<<endl;
     
           // Wait for incoming requests
           orb->run();
       }
       catch(const CORBA::Exception&e){
          cerr <<e <<endl;
          return 1;
       }
       return 0;
    }
  • Javaの場合

    Javaでは,OMG規格のregister_orb_initializerのマッピングに従います。すなわち,このクラスをJava ORBプロパティによって登録します。サンプルでは,クライアントおよびサーバアプリケーションは実際には,プロパティファイルから,org.omg.PortableInterceptor.ORBInitializerClass.<Service>(<Service>はorg.omg.PortableInterceptor.ORBInitializerをインプリメントするクラスの文字列名です)プロパティがあるclient.propertiesおよびserver.propertiesを読み取ります。この場合は,SampleClientLoaderおよびSampleServerLoaderという二つのクラスです。

    また,ファイルからプロパティを読み取らないで,アプリケーションを書き込むことを選択する場合,コマンドラインオプションを使用することもできます。これには,アプリケーションを次のように実行する必要があります。

    vbj -Dorg.omg.PortableInterceptor.ORBInitializerClass.
        SampleClientLoader = SampleClientLoaderClient
    vbj -Dorg.omg.PortableInterceptor.ORBInitializerClass.
        SampleServerLoader = SampleServerLoaderServer

    クライアントアプリケーションの完全なインプリメンテーションを次に示します。

    コードサンプル19-54 クライアントアプリケーションの完全なインプリメンテーション(Java):Client.java
    // Client.java
     
    import org.omg.PortableServer.*;
     
    import java.util.Properties;
    import java.io.FileInputStream;
     
    public class Client {
     
       private static Properties property =null;
     
       public static void main(String [ ] args){
          try {
             property = new Properties();
             property.load(new FileInputStream("client.properties"));
     
          // Initialize the ORB.
          org.omg.CORBA.ORB orb=org.omg.CORBA.ORB.init(args,property);
          // Get the manager Id
          byte[ ] AccountManagerId="BankManager".getBytes();
          // Locate an account manager.Give the full POA name and
          // the servant ID.
          Bank.AccountManager manager =
             Bank.AccountManagerHelper.bind(orb,
                "/bank_client_server_poa", AccountManagerId);
          // use args [0 ]as the account name,or a default.
          String name =null;
          name =args.length >0 ?args [0 ] :"Jack B.Quick";
          // Request the account manager to open a named account.
          Bank.Account account =manager.open(name);
          // Get the balance of the account.
          float balance =account.balance();
          // Print out the balance.
          System.out.println("The balance in "+name +"'s account is $"+
             balance);
          }
          catch(Exception e){
          e.printStackTrace();
          }
      }
    }

    サーバアプリケーションの完全なインプリメンテーションを次に示します。

    コードサンプル19-55 サーバアプリケーションの完全なインプリメンテーション(Java):Server.java
    // Server.java
     
    import org.omg.PortableServer.*;
    import java.util.Properties;
    import java.io.FileInputStream;
     
    public class Server {
     
       private static Properties property = null;
     
       public static void main(String[ ] args)){
          try {
             property =new Properties();
             property.load(new FileInputStream("server.properties"));
     
             // Initialize the ORB.
             org.omg.CORBA.ORB orb = 
                                org.omg.CORBA.ORB.init(args,property);
             // get a reference to the rootPOA
             POA rootPOA =POAHelper.narrow(orb.resolve_initial_references
                                                              ("RootPOA"));
     
             // Create policies for our persistent POA
             org.omg.CORBA.Policy[ ] policies =={
                 rootPOA.create_lifespan_policy(
                             LifespanPolicyValue.PERSISTENT)
             };
     
             // Create myPOA with the right policies
             POA myPOA =rootPOA.create_POA("bank_client_server_poa",
                              rootPOA.the_POAManager(),policies );
     
             // Create Account servants
             AccountManagerImpl managerServant =
                                             new AccountManagerImpl();
             byte[ ] managerId == "BankManager".getBytes();
             myPOA.activate_object_with_id(managerId,managerServant);
             rootPOA.the_POAManager().activate();
     
             // Announce Servants are ready
             System.out.println(myPOA.servant_to_reference
                                        (managerServant) + "is ready.");
             //Wait for incoming requests
             orb.run();
          }
          catch (Exception e){
          e.printStackTrace();
         }
       }
    }

(3) コンパイルの手順

(4) クライアントおよびサーバアプリケーションの実行または配置