ページの先頭行へ戻る
Interstage Application Server アプリケーション作成ガイド(CORBAサービス編)

G.3.2 C++言語の開発

G.3.2.1 Basic Object Adapter : BOA

  動的スケルトンインタフェース(DSI)のサーバアプリケーションは、初期化処理部とサーバアプリケーションが実装するゲートウェイから構成されます。初期化処理部では、以下に示す処理を行います。



G.3.2.1.1 初期化

  CORBAの初期化メソッドCORBA::ORB_init()を呼び出し、初期化処理を行います。結果として、ORBのオブジェクトリファレンスが返されます。このオブジェクトリファレンスは、以降で呼び出すORBインタフェースを使用する場合に指定します。
  また、基本オブジェクトアダプタの初期化処理を行います。


G.3.2.1.2 ゲートウェイの登録

  サーバアプリケーションが実装するゲートウェイをORBに対して通知します。このため、以下の手順で処理を行います。

  1. CORBA::ORB::resolve_initial_references()によりインプリメンテーションリポジトリのオブジェクトリファレンスを取り出します。メソッドのパラメタとしてCORBA_ORB_ObjectId_ImplementationRepositoryを指定します。

  2. サーバアプリケーションのImplementationRepオブジェクトのオブジェクトリファレンスを求めるため、FJ::ImplementationRep::lookup_id()を発行します。

  3. サーバアプリケーションが実装するゲートウェイを登録するために、CORBA::BOA::set_impl_dsi()を発行します。

  boa->set_impl_dsi(
      boa, 
      *env, 
      (CORBA_DynamicImplementationRoutine_cpp)dsi ); 

G.3.2.1.3 サーバの活性化

  サーバアプリケーションの初期化が完了すると、ORBに対してその旨を通知します。ORBは、この命令が発行された時点で、クライアントからの要求をサーバアプリケーションに伝えます。


G.3.2.1.4 ゲートウェイの処理

  ゲートウェイでは、以下に示す処理を行います。

ゲートウェイの実装例を以下に示します。

  static void
  dsi(
      CORBA::Object_ptr          obj, 
      CORBA::ServerRequest_ptr   request, 
      CORBA::Environment         &ev ) 
  {
      CORBA::RepositoryId dsi_op_name; 

      try {
          // (1) メソッドの解析
          dsi_op_name = request->op_name( ev ); 
          if( strcmp( dsi_op_name, "calculate" ) == 0 ) {
              method_calculate( request ); 
          }
          CORBA::string_free( dsi_op_name ); 
      }
      // (5) 例外情報の設定
      catch ( ODdemo::calculator::ZEROPARAM &_zeroparam ) {
          CORBA::Any *_any = new CORBA::Any( _tc_ODdemo_calculator_ZEROPARAM, &_zeroparam );
          request->exception( _any, ev );
      }
      catch ( CORBA::Exception e ){
          // 例外発生時の処理を記述してください。
          // 復帰情報あるいは例外情報を設定してください
      }
      return; 
  }

  void
  method_calculate( CORBA::ServerRequest_ptr request )
  throw( CORBA::Exception ) 
  {
      try {
          // (2) パラメタの組立て
          // パラメタリストの生成
          CORBA::NVList_ptr    arg_list;
          orb->create_list( 2, arg_list, *env ); 

          CORBA::Any p1, p2;

          CORBA::Long l;

          // パラメタ情報の登録
          l = 0;
          p1 <<= l;
          arg_list->add_value(
                              "a",
                              p1,
                              CORBA::ARG_IN,
                              *env );
          p2 <<= l;
          arg_list->add_value(
                              "b",
                              p2,
                              CORBA::ARG_IN,
                              *env );

          // (3) パラメタの解析
          request->params(
                         arg_list,
                         *env );

          CORBA::NamedValue_ptr	nvp1, nvp2;

          nvp1 = arg_list->item(0,*env);
          nvp2 = arg_list->item(1,*env);

          CORBA::Any *r1, *r2;
          r1 = nvp1->value(*env);
          r2 = nvp2->value(*env);

          CORBA::Long a,b; 
           (*r1) >>= a;
           (*r2) >>= b;
          cout << " a = [" << a << "] b = [" << b << "]" << endl;

          if ( b == 0 ){
              ODdemo::calculator::ZEROPARAM excep = ODdemo::calculator::ZEROPARAM();
              throw( excep );
          }

          // (4) 復帰情報の設定
          ODdemo::calculator::result *res =
              new ODdemo::calculator::result();
          res->add_result = a+b;
          res->subtract_result = a-b;
          res->multiple_result = a*b;
          res->divide_result = (CORBA::Float)a/b;

          CORBA::Any *tmp_any = new CORBA::Any;
          tmp_any->replace( _tc_ODdemo_calculator_result, 
                               (void *)res, CORBA_TRUE );
          request->result( tmp_any, *env );
      }
      catch ( ODdemo::calculator::ZEROPARAM &_zeroparam ) {
          throw( _zeroparam );
      }
      catch( CORBA::Exception e ) {
          throw( e );
      }
  }

(1)メソッドの解析

  CORBA::ServerRequest::op_name()を発行して、メソッド名の解析を行います。


(2)パラメタの組立て

(3)パラメタの解析

  CORBA::ServerRequest::params()を発行して、パラメタの解析を行います。この結果、アプリケーションに渡すパラメタ値が取得されます。


(4)復帰情報の設定

  CORBA::ServerRequest::result()を発行して、復帰情報の設定を行います。


(5)例外情報の設定

  CORBA::ServerRequest::exception()を発行して、例外情報の設定を行います。


G.3.2.1.5 サーバの非活性化

  サーバアプリケーションは、利用者等からの停止要求を受けた場合、クライアントからの要求を以降受け付けない旨をORBに対して通知します。ORBはこの通知を受けて、クライアントからの処理要求をサーバアプリケーションに伝えず、クライアントに例外を返します。


G.3.2.2 Portable Object Adpter : POA

  動的スケルトンインタフェース(DSI)のサーバアプリケーションは、初期化処理部とインタフェースの実装部分から構成されます。初期化処理部では、以下に示す処理を行います。以下の説明では、ServantオブジェクトをDefault Servantとして扱っています。



G.3.2.2.1 初期化

  初期化処理として以下の処理を行います。

G.3.2.2.2 ゲートウェイの登録

  ゲートウェイを実装したServantオブジェクトを生成し、Default Servantとして子POAに登録します。これによりクライアントからの要求に対して、Servant内に記述したinvoke()メソッドが起動されます。


G.3.2.2.3 サーバの活性化

  Servantオブジェクトを設定したPOAに関連付けられたPOAManagerのインスタンスに対しactivate()メソッドを発行します。


G.3.2.2.4 ゲートウェイの処理

  ゲートウェイでは、以下に示す処理を行います。

  ゲートウェイの実装例を以下に示します。


【ゲートウェイ実装例】

class DSIServant : public virtual PortableServer::DynamicImplementation
{
public:
    DSIServant(){ _rep_id = "IDL:ODdemo/calculator:1.0"; };
    ~DSIServant(){};

    CORBA::Boolean invoke(
        CORBA::ServerRequest_ptr sr,
        CORBA::Environment &env )
    {
        try{
            // (1)メソッド名の取得
            char *_name = sr->op_name();
            //メソッド名の解析
            if( !strcmp( _name, "calculate" )){
                // (2)パラメタリストの設定
                //パラメタリストの作成
                CORBA::NVList_ptr _list = NULL;
                orb->create_list( 2, _list );

                //パラメタ情報の登録
                CORBA::Any _p1, _p2;
                _p1 <<= (CORBA::Long)0;
                _p2 <<= (CORBA::Long)0;

                _list->add_value( "a", _p1, CORBA::ARG_IN );
                _list->add_value( "b", _p2, CORBA::ARG_IN );

                // (3)パラメタの解析
                sr->params(_list);
                CORBA::Long _param1, _param2;
                *(_list->item(0)->value()) >>= _param1;
                *(_list->item(1)->value()) >>= _param2;

                //処理部の起動
                UserServant *_sv = new UserServant();
                ODdemo::calculator::result *_result = _sv->calculate( _param1, _param2, env );

                // (4)復帰情報の設定
                CORBA::Any *_res = new CORBA::Any();
                _res->replace( _tc_ODdemo_calculator_result, (void*)_result, CORBA_TRUE );
                sr->result(_res);

                _sv->servant_delete();
            }
            CORBA::string_free(_name);

        } catch( ODdemo::calculator::ZEROPARAM *_zeroparam ) {
            // (5) 例外情報の設定
            env.exception(_zeroparam);
            CORBA::Any *_any = new CORBA::Any( _tc_ODdemo_calculator_ZEROPARAM, _zeroparam );
            sr->exception( _any, env );
            return true;
        } catch( CORBA::Exception e ) {
            // 例外発生時の処理を記述してください。
            // 復帰情報あるいは例外情報を設定してください
        }

        return true;
    };

    // (6)実装が必要なメソッド
    CORBA::RepositoryId _primary_interface(
        const PortableServer::ObjectId &oid,
        PortableServer::POA_ptr poa,
        CORBA::Environment&  env )
    {
        return _rep_id;
    };

private:
    CORBA::RepositoryId _rep_id;
};

//処理部
class UserServant : public virtual PortableServer::ServantBase
{
public:
    UserServant(){};
    ~UserServant(){};

    ODdemo::calculator::result    *calculate(
        CORBA::Long a,
        CORBA::Long b,
        CORBA::Environment &env )
        throw( CORBA::Exception )
    {
        if( b == 0 ){
            throw new ODdemo::calculator::ZEROPARAM();
        }
        ODdemo::calculator::result *_result =
            new ODdemo::calculator::result();
        _result->add_result = a + b;
        _result->subtract_result = a - b;
        _result->multiple_result = a * b;
        _result->divide_result = (CORBA::Float)(a / b);
        return _result;
    }
};

  ゲートウェイを実装するServantオブジェクトは、PortableServer::DynamicImplementationを継承するものとして作成します。また、クライアントからのリクエストに対して起動されるメソッドとしてinvoke()メソッドを実装します。起動の際、invoke()の引数としてServerRequestクラスのオブジェクト(上記例ではreq)が渡されます。
  処理部では、ゲートウェイを実装するServantオブジェクト内で、そのServantに対してservant_delete()を発行するために、PortableServer::ServantBaseクラスを継承します。


【ゲートウェイServantの必須メソッド(1)

  CORBA::boolean invoke( CORBA::ServerRequest_ptr req )

(1)メソッドの取得と解析

  渡されたServerRequestクラスに登録されているオペレーション名をCORBA::ServerRequest::op_name()メソッドにより取得します。


(2)パラメタの組立て

(3)パラメタの解析

  生成したNVListオブジェクトを引数として、CORBA::ServerRequest::params()メソッドを呼び出します。この結果、アプリケーションに渡すパラメタ値が取得されます。


(4)復帰情報の設定

  CORBA::ServerRequest::result()メソッドを発行して復帰情報の設定を行います。


(5)例外情報の設定

  CORBA::ServerRequest::exception()メソッドを発行し例外情報の設定を行います。


(6)その他実装が必要なメソッド

  ゲートウェイを実装するServantは、OMG規約上_primary_interface()メソッドを実装しておく必要があります。上記の例のように、PortableServer::POAクラスのオブジェクト、PortableServer::ObjectIdオブジェクトを引数とし、インタフェースリポジトリID相当の文字列("IDL:xxx:1.0")を戻り値とする形式で実装します。引数の値をメソッド内部で扱う必要は特にありません。


【ゲートウェイServantの必須メソッド(2)

    virtual CORBA::RepositoryId  _primary_interface(
                                    const PortableServer::ObjectId& oid, );
                                    PortableServer::POA_ptr         poa,
                                    CORBA::Environment& = CORBA::Environment())
                                 throw( CORBA::Exception ) = 0;

G.3.2.2.5 DSI使用時の注意点

  POAでDSIを使用する場合は、RTTIをサポートするC++コンパイラを使用してください。

【Visual C++の場合】
  「プロジェクトの設定」で、RTTIを使用するようにします。

【Makefileでnmakeを使用する場合】
  /GRオプションを追加してください。


G.3.2.3 パラメタの獲得/解放

  動的スケルトンインタフェースを使用して動的にパラメタを作成する方法について説明します。
  パラメタはCORBA::NVList::add_value()を使用して設定します。


inパラメタ

  クライアントアプリケーションからinパラメタを受け取る場合、パラメタ領域の獲得/解放を行う必要はありません。add_value()は以下のように指定します。

  CORBA::Any        p1( ((*params)[0])->type, &i, CORBA_TRUE ); 
  arg_list->add_value(
        name,                        /* IDLで指定したパラメタの名前を設定します */
        p1,                          /* inで使用する値を設定したAny型を設定します */
        CORBA::ARG_IN,               /* CORBA::ARG_INを設定します */
        *env );

outパラメタ

  サーバアプリケーションの処理結果をoutパラメタで渡す場合、データ域獲得関数(CORBA::long_alloc()等)で領域を獲得し、そのポインタをadd_value()の第2パラメタに指定します。

  CORBA::Any        *p2 = new CORBA::Any( ((*params)[1])->type, &i, CORBA_TRUE ); 
  arg_list->add_value(
        name,                        /* IDLで指定したパラメタの名前を設定します */
        *p2,                         /* outの値を設定するAny型を設定します */
        CORBA::ARG_OUT,              /* CORBA::ARG_OUTを設定します */
        *env );

  獲得した領域は、CORBAサービス内でリクエスト復帰後に解放されます。


inoutパラメタ

  クライアントアプリケーションからinoutパラメタを受け取る場合、パラメタ領域の獲得/解放を行う必要はありません。add_value()は以下のように指定します。

  CORBA::Any        *p3 = new CORBA::Any(( (*params)[2])->type, &i, CORBA_TRUE ); 
  arg_list->add_value(
        name,                        /* IDLで指定したパラメタの名前を設定します */
        *p3,                         /* inoutの値を設定するAny型を設定します */
        CORBA::ARG_INOUT,            /* CORBA::ARG_INOUTを設定します */
        *env );

  サーバアプリケーションの処理結果をinoutでクライアントアプリケーションに渡す場合、以下のようにします。

  固定長データの場合

  CORBA::ServerRequest::params()で通知されたパラメタ領域に値を設定します。

  可変長データの場合

  CORBA::ServerRequest::params()で通知されたパラメタ領域を、CORBA::free()でいったん解放した後、データ域獲得関数(CORBA::string_alloc()等)で領域を獲得し、そのポインタを再設定します。新しいデータをその領域に設定します。

  inoutパラメタとして使用した領域は、リクエスト復帰後にスケルトンで解放されます。


復帰パラメタ

  サーバアプリケーションの処理結果を復帰パラメタ渡す場合、データ域獲得関数(CORBA::long_alloc()等)で領域を獲得します。