WebOTX Manual V11.1 (第6版) 目次を表示 |
> java -Dorg.omg.CORBA.ORBClass=jp.co.nec.orb.OSPORB -Dorg.omg.CORBA.ORBSingletonClass=jp.co.nec.orb.OSPORBSingleton <APのクラス名>
: : java.util.Properties props = new java.util.Properties(); props.setProperty("org.omg.CORBA.ORBClass", "jp.co.nec.orb.OSPORB"); props.setProperty("org.omg.CORBA.ORBSingletonClass", "jp.co.nec.orb.OSPORBSingleton"); ORB orb = ORB.init(args, props); : :
org.omg.CORBA.ORBClass=jp.co.nec.orb.OSPORB org.omg.CORBA.ORBSingletonClass=jp.co.nec.orb.OSPORBSingleton
org.omg.CORBA.ORBClass=jp.co.nec.orb.OSPORB org.omg.CORBA.ORBSingletonClass=jp.co.nec.orb.OSPORBSingleton
int main (int argc, char **argv) { CORBA::ORB_var orb = CORBA::ORB_init(argc, argv, "", env); CORBA::Object_var obj = orb->resolve_initial_references("NameService", env); CosNaming::NamingContext_var nmctx = CosNaming::NamingContext::_narrow(obj); ... }
CORBA::ORB_ptr orb = ...; // CORBA::ORB疑似オブジェクト用 CORBA::Environment env; // プロセス単位でタイムアウト値を1秒に設定する orb->__process_request_timeout(1L, env); // クライアント用 orb->__server_request_timeout(1L, env); // サーバ用 // スレッド単位でタイムアウト値を1秒に設定する orb->__request_timeout(1L, env);関数呼び出しを行ってから応答が返るまでの間に、設定した時間が過ぎてしまったときは、CORBA::NO_RESPONSEシステム例外が返ります。 タイムアウトの設定には優先順位が付けられています。同時に複数の設定がされていたときは、より優先度の高い設定が有効になります。設定の優先順位については [ 関連製品 > Object Broker C++ > 構築・運用 > 環境設定 ] および、各関数の説明を参照してください。
フックの種類 | 値 |
---|---|
クライアントがサーバにリクエストメッセージを送信する直前のフック | CLNT_PRE_SEND |
サーバがリクエストメッセージを受け取った直後のフック | SERV_AFT_RECV |
サーバがリプライメッセージを送信する直前のフック | SERV_PRE_SEND |
クライアントがサーバからのリプライメッセージを受け取った直後のフック | CLNT_AFT_RECV |
void func(Ob_MesBuf&, CORBA::Request_ptr, CORBA::Environment&);b.とc.に挿入できるユーザ定義関数インタフェースはつぎのとおりです。
void func(Ob_MesBuf&, CORBA::Environment&);フックオブジェクトには複数の関数が登録でき、関数は登録された順番に呼び出されます。また、フックオブジェクトも複数作成することができ、作られた順番にすべてのオブジェクトに登録されている関数が呼び出されます。関数はフックオブジェクトのライフタイムの間だけ登録されています。
// クライアントがリクエストを送信する前に呼び出すフック void clnt_pre_send_hook(Ob_MesBuf& mb, CORBA::Request_ptr req, CORBA::Environment& env) { // メッセージバッファの内容をpacket.logファイルに出力する mb.dump("packet.log"); // リクエストメッセージに対するリプライメッセージをクライアントで // 作成し、サーバメソッドを呼ばないようにする ... // リプライメッセージは、Ob_MesBuf& CORBA::Request::__reply()に // 書き込む IIOP::MessageHeader ihead; ihead.flags = (CORBA::Octet)((Obi_my_byteorder()&1)|(ihead.flags&~1)); //リプライメッセージを表す ihead.message_type = IIOP::Reply; //GIOPマイナーバージョン1の場合 ihead.GIOP_version.minor = 1; CORBA::Ulong* message_size_addr = 0; if(!(ihead._encode(req->__reply(), message_size_addr))) { //error処理 } if(!(req->__reply().begin_encode_message(message_size_addr))) { //error処理 } IIOP::ReplyHeader rhead; //rhead.service_context *必要ならServiceContextを設定 rhead.request_id = リクエストメッセージのrequest_idと同じ値を設定 //通常のリプライ(エラーなし)の場合 rhead.reply_status = IIOP::NO_EXCEPTION; rhead._encode(req->__reply()); CORBA::Long nRet; ... req->__reply() <<= nRet; ... //戻り値等のencode終了後に呼ぶ req->__reply().end_encode_message(); //サーバメソッドを呼ばないようにする req->__not_call(); } // クライアントがリプライを受信した後に呼び出すフック void clnt_aft_recv_hook(Ob_MesBuf& mb, CORBA::Request_ptr req, CORBA::Environment& env) { // clnt_pre_send_hookで作ったリプライメッセージの内容を // packet.logファイルに出力する req->__reply().dump("packet.log"); // __not_call()にしてあるときはreq->__reply()の返り値を // デコードするので、req->__reply()をmbにコピーする必要はない } main() { ... Ob_MesBufHook hook(CLNT_PRE_SEND); hook <<= clnt_pre_send_hook; Ob_MesBufHook hook2(CLNT_AFT_RECV); hook2 <<= clnt_aft_recv_hook; ... }サーバ側のフックも同様の手順で登録できます。
フックの種類 | 値 |
---|---|
メソッドインプリメンテーション呼びだし前のフック | OB_"INTERFACE"_PRE_"METHOD" |
メソッドインプリメンテーション呼びだし後のフック | OB_"INTERFACE"_AFT_"METHOD" |
引数 | タイプ | 意味 |
---|---|---|
第一引数 | インタフェース_ptr型 | オブジェクトへのポインタ |
第二引数 | オペレーションのリターン型 | リターン値 |
それ以降 | オペレーションの引数型 | 引数 |
最後の引数 | CORBA::Environment& | 例外 |
/* IDL */ interface MyIntf { string myop(in long l); }; /* C++ */ void hook_func(MyIntf_ptr& o, char* ret, CORBA::ULong l, CORBA::Environment& env) { ... } // OB_MYINTF_PRE_MYOPはmyop()を呼び出す前のフックに対する値。 // 呼び出し後はOB_MYINTF_AFT_MYOP。 main() { ... Ob_MyIntfHook hook(OB_MYINTF_PRE_MYOP); hook <<= (Ob_ProcAddr)hook_func; ... }
void func(CORBA::Environment&);サーバを終了させるメソッドの例を示します。動作の概要は以下のとおりです。
// IDL interface MyIntf { ... void exit(string mesg); }; // C++ void server_exit(CORBA::Environment& env) { exit(0); } void MyIntf::exit(const char* mesg, CORBA::Environment& env) { ... if (strcmp(mesg, "exit") == 0) { Ob_SentHook hook(server_exit); } ... }
void func(CORBA::Object_ptr&, CORBA::Environment&);登録の仕方を例で示します。
void change_object(CORBA::Object_ptr& o, CORBA::Environment& env) { // 新たにオブジェクトをセットする前に、 // 渡って来たオブジェクトをリリースする CORBA::release(o); o = ... //オブジェクトをセットする } main() { ... Ob_SvrHook hook; hook <<= change_object; ... }
void myhook(Ob_SvrCon* con, CORBA::Environment&) { // ここに切断されたときの処理を記述します。}切断時のフック関数はOb_SvrSocketClosedHook型のオブジェクトを作成することで登録されます。Ob_SvrSocketClosedHookのコンストラクタの引数は上記のフック関数へのポインタです。登録は検出したい切断が発生するまでに行っておきます。
main() { CORBA::ORB_var orb = CORBA::ORB_init(...); ... Ob_SvrSocketClosedHook hobj(myhook); }次に、クライアントから呼ばれるオペレーション内で、そのオペレーションを呼び出したクライアントが切断されたときのフック関数の設定を行います。フックを呼び出す設定には、Ob_SvrCon::need_closed_hook関数を使います。この設定を行った場合だけ、クライアントとの接続が切断されたときに、上記フック関数が呼ばれるようになります。need_closed_hook関数を呼ばない場合あるいは、0を引数として呼び出した場合は、フック関数は呼ばれません。
AAA::op1(..., CORBA::Environment& env) { Ob_SvrCon* con = env.__connection(); if (con) { // フック関数を呼ぶか呼ばないかのフラグ設定 con->need_closed_hook(1); } ... }
CORBA::ORB_ptr orbobj = CORBA::ORB_init(...); // リポジトリオブジェクトのオブジェクトリファレンスを得る CORBA::Object_var ir_in_obj = orbobj->resolve_initial_references("InterfaceRepository", env);ここで得られたオブジェクトリファレンスはCORBA::Object型なのでこのままでは使えません。CORBA::Repository::_narrow()を使って型を変換します。
CORBA::Repository_var repository = CORBA::Repository::_narrow(ir_in_obj);
interface myintf { void op(in short i); };このデータをインタフェースリポジトリから取り出す例を以下に示します。なお、例外処理や複数のインタフェースやオペレーションが含まれていた場合の考慮などは省略します。
// C++ #include <orb.h> #include <stdio.h> // 引数モード別 static char* opemode[] = { "in", "out", "inout", 0 }; // 型別 static char* tckind[] = { "null", "void", "short", "long", "ushort", "ulong", "float", "double", "boolean", "char", "octet", "any", "TypeCode", "Principal", "object", "struct", "union", "enum", "string", "sequence", "array", "typedef", "exception", "longlong", "ulonglong", "longdouble", "wchar", "wstring", "fixed", 0 }; void main(int argc, char** argv) { CORBA::Environment env; // 初期化 CORBA::ORB_var orbobj = CORBA::ORB_init(argc, argv, "", env); // リポジトリオブジェクトの取り出し CORBA::Object_var ir_in_obj = orbobj->resolve_initial_references("InterfaceRepository", env); CORBA::Repository_var repository = CORBA::Repository::_narrow(ir_in_obj); // リポジトリオブジェクトからInterfaceDefオブジェクトだけを取り出す // CORBA::dk_Interface : 取り出すのはインタフェースのみ // 1 : 継承されたオブジェクトは含まない // -1L : 数量制限なし CORBA::Container::DescriptionSeq_ptr descseq = repository->describe_contents(CORBA::dk_Interface, 1, -1L, env); // シーケンスの最初のオブジェクトをnarrowする CORBA::InterfaceDef_var intfobj = CORBA::InterfaceDef::_narrow((*descseq)[(CORBA::ULong)0].contained_object); // インタフェース情報を取り出す CORBA::InterfaceDef::FullInterfaceDescription_ptr intfdesc = intfobj->describe_interface(env); // インタフェース名 printf("interface %s {\n", intfdesc->name); // オペレーションのシーケンスから1つ取り出す CORBA::OperationDescription opedesc = intfdesc->operations[(CORBA::ULong)0]; // オペレーションのモード if(opedesc.mode == CORBA::OP_ONEWAY) printf("\toneway "); else printf("\t "); // オペレーションの戻り値の型 printf("%s ", tckind[opedesc.result->kind(env)]); // オペレーション名 printf("%s(", opedesc.name); // パラメータのシーケンスから1つ取り出す CORBA::ParameterDescription paradesc = opedesc.parameters[(CORBA::ULong)0]; // オペレーションの引数のモード printf("%s ", opemode[paradesc.mode]); // オペレーションの引数 printf("%s %s);\n", tckind[paradesc.type->kind(env)], paradesc.name); printf("};\n"); }CORBA::Container::describe_contents()は、そのオブジェクトが内包しているオブジェクトの一覧をCORBA::Container::DescriptionSeqへのポインタで返します。上記の例ではInterfaceDefに限定して検索をしています。
struct CORBA::Container::Description { CORBA::Contained contained_object; // 内包されたオブジェクト CORBA::DefinitionKind kind; // 内包されたオブジェクトの種類 CORBA::Any value; // 内包されたオブジェクトが持つ // 型情報 };contained_objectにはInterfaceDefオブジェクトが入っています。そこで、CORBA::InterfaceDef::describe_interface()を使って、そのCORBA::InterfaceDefオブジェクトが内包しているオペレーションのリストを取り出します。オペレーションのリストはCORBA::InterfaceDef::FullInterfaceDescriptionへのポインタとして返されます。
struct CORBA::InterfaceDef::FullInterfaceDescription { Obi_String name; // インタフェース名 Obi_String id; // リポジトリID Obi_String defined_in; // インタフェースを包含している // ContainerのリポジトリID Obi_String version; // バージョン CORBA::OpDescriptionSeq operations; // オペレーションのシーケンス CORBA::AttrDescriptionSeq attributes; // 属性のシーケンス CORBA::RepositoryIdSeq base_interfaces; // 基底インタフェースの // シーケンス CORBA::TypeCode type; // タイプコード };さらに、operationsから目的のオペレーションの型情報を取り出します。
struct CORBA::OperationDescription { Obi_String name; // オペレーション名 Obi_String id; // リポジトリID Obi_String defined_in; // オペレーションを包含している // ContainerのリポジトリID Obi_String version; // バージョン CORBA::TypeCode result;; // 戻り値の型を表すタイプコード CORBA::OperationMode mode; // オペレーションのモード // CORBA::OP_NORMAL:双方向呼び出し // CORBA::OP_ONEWAY:単方向呼び出し CORBA::ContextIdSeq context; // コンテキスト名のシーケンス CORBA::ParDescriptionSeq parameters; // パラメータのシーケンス CORBA::ExcDescriptionSeq exceptions; // ユーザ定義例外のシーケンスparametersからパラメータ情報を取り出します。
struct CORBA::ParameterDescription { CORBA::Identifier name; // 引数の名前 CORBA::TypeCode type; // 引数の型を表すタイプコード CORBA::IDLType type_def; // 引数の型を表すオブジェクト CORBA::ParameterMode mode; // 引数のモード // CORBA::PARAM_IN :in引数 // CORBA::PARAM_OUT :out引数 // CORBA::PARAM_INOUT:inout引数 };CORBA::OperationDescription構造体のメンバexceptionsがヌル・ポインタでなければ、exceptionsからユーザ定義例外情報を取り出します。
struct CORBA::ExceptionDescription { CORBA::Identifier name; //例外名 CORBA::RepositoryId id; ; //リポジトリID CORBA::RepositoryId defined_in; // この例外を返すオペレーションのリポジトリID CORBA::VersionSpec version; // バージョン CORBA::TypeCode type; //この例外を示すタイプコード };これらのインタフェース情報により、DIIによる呼び出しに必要なパラメータを組み立てることができます。
CORBA::Environment env; ... CORBA::Object_var obj = ...; // 何らかの手段でオブジェクトリファレンスを取得 // インタフェースリポジトリを使った検索を許可する orb->__use_IR(1, env); // インタフェースを定義しているオブジェクトの取得 CORBA::InterfaceDef_var intfobj = obj->_get_interface(env); // インタフェース情報を取り出す CORBA::InterfaceDef::FullInterfaceDescription_var intfdesc = intfobj->describe_interface(env);intfdescにはオブジェクトリファレンスが指し示すオブジェクトのすべてのインタフェース情報が入っています。この中から、目的のオペレーションを選びます。
CORBA::ULong count = intfdesc->operations.length(); CORBA::ULong i; CORBA::OperationDescription opedesc; for(i=0; i<count; i++) { // オペレーションのシーケンスから1つ取り出す opedesc = intfdesc->operations[i]; // オペレーション名が一致するものを探す(仮に"myop"を探すことにします) if(strcmp(opedesc.name, "myop") == 0) break; }名前が一致するオペレーションを取得できたら、CORBA::Requestオブジェクトを作成します。引数には、オペレーション名を渡します。
CORBA::Request_var req = obj->_request(opedesc.name, env);作成したCORBA::Requestオブジェクトに戻り値の型をCORBA::TypeCode_ptr型で指定します。
req->set_return_type(opedesc.result, env);オペレーションの引数を登録します。引数にはin, out, inoutの3種類があり、それぞれ別の関数が用意されています。引数はadd_XXX_arg()(XXXは引数の種類によって異なる)を呼び出すたびに引数リストの後ろへ追加されます。add_XXX_arg()関数は、CORBA::Anyへの参照を返します。そして、返されたCORBA::Anyに引数を挿入します。各型のanyへの挿入の方法は、「C++マッピング」の「any」を参照してください
count = opedesc.parameters.length(); CORBA::ParameterDescription paradesc; CORBA::Any value; for(i=0; i<count; i++) { // パラメータのシーケンスから1つ取り出す paradesc = opedesc.parameters[i]; // パラメータの設定 switch(paradesc.mode){ case CORBA::PARAM_IN: switch(paradesc.type->kind()){ case CORBA::tk_short: CORBA::Short in_param = ...; req->add_in_arg(paradesc.name, env) <<= in_param; break; ... } break; case CORBA::PARAM_INOUT: switch(paradesc.type->kind()){ case CORBA::tk_short: CORBA::Short inout_param = ...; req->add_inout_arg(paradesc.name, env) <<= inout_param; break; ... } break; default: switch(paradesc.type->kind()){ case CORBA::tk_short: CORBA::Short out_param = 0; // dummy req->add_out_arg(paradesc.name, env) <<= out_param; break; ... } break; } }引数の組み立てが終わったら、サーバの呼び出しを行います。サーバの呼び出し方には単方向のものと双方向の2種類があります。これらはIDL定義をしたときに決まっています。呼び出しをするときには、以下のようにこれらの違いを調べ、呼び出し方にあった方法を使う必要があります。
if(opedesc.mode == CORBA::OP_ONEWAY) req->send_oneway(env); //単方向呼び出しのとき else{ CORBA::Status status = req->invoke(env); // 双方向呼び出しのとき }双方向呼び出しで、かつ、戻り値を持っていた場合は、戻り値を取得する必要があります。戻り値は、CORBA::Any型で取得します。anyから各型へ取り出す方法は、「C++マッピング」の「any」を参照してください。
if(opedesc.result->kind() != CORBA::tk_void){ switch(opedesc.result->kind()) { case CORBA::tk_short: CORBA::Short result; req->return_value(env) >>= result; break; ... } }
namespace PortableServer { class DynamicImplementation : public virtual PortableServer::ServantBase { //実装オブジェクトのオペレーションを呼び出す virtual void invoke(CORBA::ServerRequest_ptr, CORBA::Environment&); virtual CORBA::RepositoryId _primary_interface( const PortableServer::ObjectId&, PortableServer::POA_ptr, CORBA::Environment& ); }; };
// IDL interface MyInterface { MyType2 MyOperation(in MyType arg); }; // C++ class MyDynamicImpl : public PortableServer::DynamicImplementation { public: MyDynamicImpl() { // 必要ならばメンバの領域の割り当て、初期化を行います } ~MyDynamicImpl() { // 必要ならばメンバの領域の解放を行います } virtual void invoke( CORBA::ServerRequest_ptr, CORBA::Environment& ); virtual CORBA::RepositoryId _primary_interface( const PortableServer::ObjectId&, PortableServer::POA_ptr, CORBA::Environment& ); MyType2 MyOperation(MyType&, CORBA::Environment&); // 呼び出されるオペレーション };
// IDL interface MyInterface { MyType2 MyOperation(in MyType arg); }; // C++ void MyDynamicImpl::invoke(CORBA::ServerRequest_ptr sr, CORBA::Environment&) { try { // どのオペレーションが呼ばれたか調べる const char* op_name = sr->operation(); if (strcmp(op_name, "MyOperation") == 0) { MyType arg; MyType2 ret; //引数のデコードに必要な情報をセットする CORBA::NVList_ptr param; CORBA::NamedValue_ptr np = param->add(CORBA::ARG_IN); CORBA::Any* ap = np->value(); *ap <<= arg; //引数をデコードする sr->arguments(param); // IN引数を取り出す arg = *(MyType*)param->item(0)->value()->value(); //オペレーションを呼び出す ret = MyOperation(arg); //戻り値をsrにセットする CORBA::Any* result = new CORBA::Any; *result <<= ret; sr->set_result(*result); } } catch (CORBA::NO_MEMORY& e) { // CORBA::NO_MEMORY例外のとき //エラー処理または例外をsrにセットする // CORBA::NO_MEMORY例外をsrにセットする場合 CORBA::Any* exc = new CORBA::Any(CORBA::_tc_NO_MEMORY, new CORBA::NO_MEMORY(e), 1); sr->set_exception(*exc); } catch (CORBA::Exception& e) { // その他の例外のとき //エラー処理または例外をsrにセットする } }次に、DSIサーバントのインスタンスが複数あり、インスタンスにより処理を切り換える場合の例を以下に示します。
// IDL interface MyInterface { MyType2 MyOperation(in MyType arg); }; // C++ class MyDynamicImpl : public PortableServer::DynamicImplementation { public: ... virtual void invoke( CORBA::ServerRequest_ptr, CORBA::Environment& ); MyType2 MyOperation1(MyType&, CORBA::Environment&); // 呼び出されるオペレーション MyType2 MyOperation2(MyType&, CORBA::Environment&); // 呼び出されるオペレーション ... }; main(...) { CORBA::ORB_ptr orb = CORBA::ORB_init(...); PortableServer::POA_ptr rootPOA = ... // ルートPOAを取得 CORBA::PolicyList plist; plist.length(1); plist[0] = rootPOA->create_id_assignment_policy(PortableServer::USER_ID); PortableServer::POA_ptr poa = rootPOA->create_POA("myPOA", PortableServer::POAManager::_nil(), plist); // 文字列をオブジェクトIDに変換 PortableServer::ObjectId_var oid1 = PortableServer::string_to_ObjectId("myimpl1"); PortableServer::ObjectId_var oid2 = PortableServer::string_to_ObjectId("myimpl2"); MyDynamicImpl* impl1 = ... // MyOperation1を呼び出すインスタンスを作成 MyDynamicImpl* impl2 = ... // MyOperation2を呼び出すインスタンスを作成 // サーバントを活性化 poa->activate_object_with_id(oid1, impl1); poa->activate_object_with_id(oid2, impl2); ... } void MyDynamicImpl::invoke(CORBA::ServerRequest_ptr sr, CORBA::Environment&) { try { CORBA::ORB_var orb = CORBA::ORB_init(...); CORBA::Object_var curobj = orb->resolve_initial_references("POACurrent"); PortableServer::Current_var cur = PortableServer::Current::_narrow(curobj); CORBA::Object_var obj = _this(); PortableServer::POA_var poa = cur->get_POA(); PortableServer::ObjectId_var oid = poa->reference_to_id(obj); CORBA::String_var impl_id = ProtableServer::ObjectId_to_string(*oid); //どのオペレーションが呼ばれたか調べる const char* op_name = sr->operation(); if (strcmp(op_name, "MyOperation") == 0) { MyType arg; MyType2 ret; //引数のデコードに必要な情報をセットする CORBA::NVList_ptr param; CORBA::NamedValue_ptr np = param->add(CORBA::ARG_IN); CORBA::Any* ap = np->value(); *ap <<= arg; //引数をデコードする sr->arguments(param); // IN引数を取り出す arg = *(MyType*)param->item(0)->value()->value(); // impl_idにより呼び出すオペレーションを切り換える if (strcmp(impl_id, "myimpl1") == 0) { ret = MyOperation1(arg); } else { ret = MyOperation2(arg); } //戻り値をsrにセットする CORBA::Any* result = new CORBA::Any; *result <<= ret; sr->set_result(*result); } } catch (CORBA::Exception& e) { // その他の例外のとき //エラー処理または例外をsrにセットする } }
// IDL interface MyInterface { MyType2 MyOperation(in MyType arg); }; interface MyInterface2 { MyType2 MyOperation2(in MyType arg); }; // C++ main(...) { CORBA::ORB_ptr orb = CORBA::ORB_init(...); PortableServer::POA_ptr rootPOA = ... // ルートPOAを取得 CORBA::PolicyList plist; plist.length(1); plist[0] = rootPOA->create_id_assignment_policy(PortableServer::USER_ID); PortableServer::POA_ptr poa = rootPOA->create_POA("myPOA", PortableServer::POAManager::_nil(), plist); PortableServer::ObjectId_var oid1 = PortableServer::string_to_ObjectId("myintf1"); PortableServer::ObjectId_var oid2 = PortableServer::string_to_ObjectId("myintf2"); MyDynamicImpl* impl1 = ... // MyInterfaceをあつかうインスタンスを作成 MyDynamicImpl* impl2 = ... // MyInterface2をあつかうインスタンスを作成 // サーバントを活性化 poa->activate_object_with_id(oid1, impl1); poa->activate_object_with_id(oid2, impl2); ... } CORBA::RepositoryId MyDynamicImpl::_primary_interface(const PortableServer::ObjectId& oid, PortableServer::POA_ptr poa, CORBA::Environment&) { // オブジェクトIDを文字列に変換 CORBA::String_var str = PortableServer::ObjectId_to_string(oid); // 呼び出されたオブジェクトに対応したサーバントを調べる if (strcmp(str, "intf1") == 0) { // サーバントがimpl1のとき return CORBA::string_dup("IDL:MyInterface:1.0"); } else { // それ以外のとき return CORBA::string_dup("IDL:MyInterface2:1.0"); } }
orbobj->__reuse_socket(0, env);として共有を解除します。この呼び出しを行うと、ORBの通信を行うたびにコネクションを作ります。
// IDL interface A {}; interface B {}; interface C : A, B {}; interface D : C {};CのInterfaceDefでオブジェクトリファレンスを生成し、各_narrowに渡すと、次に示す結果となります。
// a.idl interface A {}; // b.idl #include "a.idl" interface B : A { string op2(); }; // c.idl #include "a.idl" interface C { A op(); };サーバ内の'Cの実装クラス'::op()オペレーションは、次のように、Bオブジェクトリファレンスを返すとします。
A_ptr 'Cの実装クラス'::op(CORBA::Environment& env) { B_ptr o = ...; return A::_duplicate(o, env); }実装オブジェクトがBであれば、クライアント側のスタブオブジェクトはBProxyとなりますので、クライアント側にもbcmn.oが必要になります。
// serv.idl interface A { void func(in any arg); };そして、次のような型のIDL定義から生成されたスタブをリンクしているクライアントが、サーバを呼び出したとします。
// clnt.idl struct st { long l1; long l2; }; // C++ client code A_ptr o = ...; CORBA::Environment env; st arg; arg.l1 = 1234; arg.l2 = 5678; CORBA::Any aarg; aarg <<= arg; o->func(aarg, env);clntcmn.oをリンクして作ったサーバのfuncオペレーションは、次のことができます。
void 'Aの実装クラス'::func(const CORBA::Any& arg, CORBA::Environment&) { st* p; arg >>= p; CORBA::Long a = p->l1; CORBA::Long b = p->l2; ... }しかし、clntcmn.oをリンクしないで作ったサーバは、st型を扱うことができないので、上記の方法で構造体のメンバをアクセスすることができません。このように、直接扱うことのできない型のデータが入っているanyをanonymous anyと呼びます。
void 'Aの実装クラス'::func(const CORBA::Any& arg, CORBA::Environment&) { // argにはstが入っていることを前提としています Ob_MesBuf mb; mb.from_any_value(arg.value()); CORBA::Long a, b; mb >>= a; mb >>= b; ... }上記の例は、構造体なので、mbから各要素を順番に取り出しています。
// C++ CORBA::StructMemberSeq members; members.length(2); members[0].name = CORBA::string_dup("l1"); // l1メンバのメンバ名 members[0].type = CORBA::_tc_Long; // l1メンバのタイプコード members[1].name = CORBA::string_dup("l2"); // l2メンバのメンバ名 members[1].type = CORBA::_tc_Long; // l2メンバのタイプコード CORBA::Object_var orbobj = ...; // CORBA::ORB_initより CORBA::Environment env; CORBA::TypeCode_var tc = orbobj->create_struct_tc("IDL:st:1.0", "st", members, env);第2引数にはanonymousなデータ型のポインタを渡します。WebOTX Object Brokerでは、anonymousなデータはOb_MesBufオブジェクトを使って作成します。たとえば、上記のst型のときには次のように作成します。
// C++ CORBA::Long l1, l2; l1 = 1234; l2 = 5678; Ob_MesBuf mb; mb <<= l1; mb <<= l2;このようにそれぞれ作成したタイプコードとanonymousデータを次のようにanyに渡します。
CORBA::Any any(tc, mb.to_any_value(), 1);あるいは
any.replace(tc, mb.to_any_value(), 1);これらの関数の第二引数にOb_MesBufオブジェクトで作成したデータ以外のものを渡すと、コンストラクタは値をセットしません。replace関数は例外を返します。
// C++ Ob_MesBuf mb; // エンコード用オブジェクトを生成 CORBA::Long l = 1000; mb <<= l; // lをエンコードする
// C++ Ob_MesBuf mb(128); // デコード用オブジェクトを生成 CORBA::Long l; mb >>= l; // CORBA::Long型をデコードする
// IDL struct st { long l; string s; }; enum en { ee1, ee2, ee3 }; // C++ void encode_sample1() { st data1; en data2; data1.l = 1234; data1.s = CORBA::string_dup("abcdefg"); data2 = ee2; Ob_MesBuf mb; // 1. エンコード用コンストラクタ // IDL定義した型は、Ob_MesBuf型に対してoperator<<=が使えるようになる mb <<= data1; // 2. mb <<= data2; ... }初期化処理関数と終了処理関数を使う方法 初期化処理関数と終了処理関数を使ってエンコード用に指定する方法を、次のencode_sample2()関数の例を使って説明します。
// IDL struct st { long l; string s; }; enum en { ee1, ee2, ee3 }; // C++ void encode_sample2(Ob_MesBuf& mb) { st data1; en data2; data1.l = 1234; data1.s = CORBA::string_dup("abcdefg"); data2 = ee2; CORBA::ULong length; // 1. ここからエンコード用として使用することを宣言します mb.begin_encode_message(&length); mb <<= data1; mb <<= data2; // 2. これでエンコード用としての使用を終了することを宣言します mb.end_encode_message(); ... }mbが内部的に管理するバッファのカレントポインタからエンコード用として使用することを宣言します。このときの引数の領域には、end_encode_message()関数を呼び出したとき、使用バッファ長が書き込まれます。この領域は必ず指定してください。
// IDL struct st { long l; string s; }; enum en { ee1, ee2, ee3 }; // C++ void decode_sample1() { char* buffer = ....; // エンコードされたデータの入っているバッファ // バッファ長は1024バイトだとする Ob_MesBuf mb(1024); // 1. デコード用コンストラクタ mb.buf_copy(buffer, 1024); // 2. bufferからデータをコピーする mb.reset(); // 3. カレントポインタを先頭に戻します st data1; en data2; // IDL定義した型は、Ob_MesBuf型に対してoperator>>=が使えるようになる mb >>= data1; // 4. mb >>= data2; ... }Ob_MesBufのインスタンスを生成します。デコード用のインスタンスはバッファ長を指定するコンストラクタを使って生成します。
// IDL struct st { long l; string s; }; enum en { ee1, ee2, ee3 }; // C++ void decode_sample2(Ob_MesBuf& mb) { // mbにはすでにデコードしたいデータが入っているとする mb.begin_decode_message(100, 0); // 1. st data1; en data2; mb >>= data1; mb >>= data2; mb.end_decode_message(); // 2. ... }ここからデコード用として使うことを宣言します。このときの第一引数にはデコードするバイト数を指定しますが、この値は内部的には使っていません。第二引数にはデコードを実行するマシンのバイトオーダを指定します。これを動的に求めるには次の関数が便利です。
CORBA::Boolean my_byteorder() { const CORBA::Boolean big_endian = 0; const CORBA::Boolean little_endian = 1; long l = 1; if ((*(char *)&l) == l) { return little_endian; } else { return big_endian; } }
// IDL struct st { long l; string s; }; enum en { ee1, ee2, ee3 }; // C++ void encode_sample3() { st data1; en data2; data1.l = 1234; data1.s = CORBA::string_dup("abcdefg"); data2 = ee2; Ob_MesBuf mb; CORBA::ULong length; // 1. ここからencapsulationすることを宣言します mb.begin_encode_encapsulation(&length); mb <<= data1; mb <<= data2; // 2. これでencapsulationを終了することを宣言します mb.end_encode_encapsulation(); // encapsulationしたものをsequence<octet>型にコピーしたいとします // IDL定義で typedef sequence<octet> encap;と宣言したとします encap encap_data; // 3. encap_dataの要素の領域をlength分確保します encap_data.length(length); // 4. mbからencap_dataにコピーします mb.buf_copy_to(&encap_data[0], length); ... }mbをencapsulation用として使うことを宣言します。このときの引数の領域には、end_encode_encapsulation()関数内で使用バッファ長が書き込まれます。この領域は必ず指定してください。また、encapsulationに必要なバイトオーダの情報は、実行したマシンの値が自動的に入ります。
// IDL struct st { long l; string s; }; enum en { ee1, ee2, ee3 }; // C++ void decode_sample3(Ob_MesBuf& mb) { // mbにはすでにデコードしたいデータが入っているとする mb.begin_decode_encapsulation(100); // 1. st data1; en data2; mb >>= data1; mb >>= data2; mb.end_decode_message(); // 2. ... }ここからencapsulationされているデータをデコードすることを宣言します。このときの引数はencapsulationされているデータサイズを指定しますが、この値は内部的には使っていません。
Ob_MesBuf mb; // エンコード用オブジェクトの生成 mb <<= (CORBA::Long)100; // データのエンコード CORBA::ULong len = mb.used_size(); // Byte長を得る CORBA::Octet* buffer = new CORBA::Octet[len]; mb.buf_copy_to(buffer, len); // bufferにエンコードデータをコピーする
#define SSL_PORT_NUMBER ... int main(int argc, char** argv) { ... orb = CORBA::ORB_init(argc, argv, "ObjectSpinner"); orb->__use_ssl(SSL_PORT_NUMBER); ... Ob_ssl_initialize(); ... }起動時の引数で指定する場合 SSLポート番号を起動時の引数で指定する場合、以下のようにします。
<apName> -ORBSSLPort=port_num環境変数で指定する場合 SSLポート番号を環境変数で指定する場合、以下の設定名を使用します。 設定方法の詳細に関しては、 [リファレンス > 設定 > Object Broker C++における環境設定] を参照してください。 "ImplName"SSLPort SSLポート番号を指定します。 ※ "ImplName"はインプリメンテーション名を表します。 ※ポート番号には1以上の値を使用してください。 ※システムによっては、一定の範囲の値が予約されている場合があります。
#define KEY_ID "..." int main(int argc, char** argv) { ... orb = CORBA::ORB_init(argc, argv, "ObjectSpinner"); orb->__server_cert_key(KEY_ID); ... Ob_ssl_initialize(); ... }クライアントの鍵IDを指定する場合
#define KEY_ID "..." int main(int argc, char** argv) { ... orb = CORBA::ORB_init(argc, argv, "ObjectSpinner"); orb->__client_cert_key(KEY_ID); ... Ob_ssl_initialize(); ... }起動時の引数で指定する場合 鍵IDを起動時の引数で指定する場合、以下のようにします。 サーバの鍵IDを指定する場合
<apName> -ORBServerCertKey=KeyIDクライアントの鍵IDを指定する場合
<apName> -ORBClientCertKey=KeyID環境変数で指定する場合 鍵IDを環境変数で指定する場合、以下の設定名を使用します。 設定方法の詳細に関しては、 [リファレンス > 設定 > Object Broker C++における環境設定] を参照してください。 "ImplName"ServerCertKey サーバの鍵IDを指定します ClientCertKey クライアントの鍵IDを指定します ※ "ImplName"はインプリメンテーション名を表します。
int main(int argc, char** argv) { ... orb = CORBA::ORB_init(argc, argv, "ObjectSpinner"); orb->__cert_request((CORBA::Boolean)1); ... Ob_ssl_initialize(); ... }起動時の引数で指定する場合 クライアント証明書要求を起動時の引数で指定する場合、以下のようにします。
<apName> -ORBCertRequest環境変数で指定する場合 クライアント証明書要求を環境変数で指定する場合、以下の設定名を使用します。 設定方法の詳細に関しては、 [リファレンス > 設定 > Object Broker C++における環境設定] を参照してください。 "ImplName"CertRequest "on"を指定するとクライアント証明書を要求します
int main(int argc, char** argv) { ... orb = CORBA::ORB_init(argc, argv, "ObjectSpinner"); orb->__accept_mode(Ob_AcceptSSLPortOnly); ... Ob_ssl_initialize(); ... }SSLポートと非SSLポートの両方への接続を受付ける場合
int main(int argc, char** argv) { ... orb = CORBA::ORB_init(argc, argv, "ObjectSpinner"); orb->__accept_mode(Ob_AcceptBothPort); ... Ob_ssl_initialize(); ... }起動時の引数で指定する場合 アクセプトモードを起動時の引数で指定することは出来ません。 環境変数で指定する場合 アクセプトモードを環境変数で指定することはできません。
名前空間の構造
// C++ CORBA::ORB_ptr orbobj = CORBA::ORB_init(...); // 名前サービスのルートコンテキストを得る CORBA::Object_ptr nmsv_in_obj = orbobj->resolve_initial_references("NameService", env);ここで得られたオブジェクトリファレンスはorg.omg.CORBA.Object型なのでこのままでは使えません。
// C++ CosNaming::NamingContext_ptr nmsv_root_ctx = CosNaming::NamingContext::_narrow(nmsv_in_obj);
// C++ CosNaming::Name myname; myname.length(1); myname[0].id = (const char*)"myobject"; myname[0].kind = (const char*)""; CORBA::Object_ptr myobj; nmsv_root_ctx->bind(myname, myobj, env);名前コンテキストの登録はbind_contextまたはrebind_contextにより行います。使い方はbindやrebindとほとんど同じです。
// C++ CosNaming::Name myname; myname.length(1); myname[0].id = (const char*)"mycontext"; myname[0].kind = (const char*)""; // 名前コンテキストの生成 CosNaming::NamingContext_var myctx = nmsv_root_ctx->new_context(env); // 名前の登録 nmsv_root_ctx->bind_context(myname, myctx, env);上記の例では名前コンテキストの生成と名前の登録を別々に行っていますが、この2つを同時に行うbind_new_contextというオペレーションもあります。
// C++ CosNaming::Name myname; myname.length(1); myname[0].id = (const char*)"mycontext"; myname[0].kind = (const char*)""; // 名前コンテキストの生成と名前の登録 CosNaming::NamingContext_var myctx = nmsv_root_ctx->bind_new_context(myname, env);rebindやrebind_contextは、すでに同じ名前が存在したときに新しいオブジェクトと入れ替わってしまい、もとのオブジェクトとの関連付けは失われてしまうので注意が必要です。bind, bind_contextでは、同じ名前が存在した場合は例外が発生します。上記の例では名前階層が1段だけでしたが、複数段を指定することが可能です。複数段を指定するときは、途中の名前コンテキストは実在していなければなりません。また、名前サービスではファイルシステムの"../"に相当する指定はできません。 例) nmsv_root_ctxの配下に"mycontext"と命名された名前コンテキストがあるものとします。
// C++ CosNaming::Name n; n.length(2); // 名前の作成 n[0].id = (const char *)"mycontext"; n[0].kind = (const char *)""; n[1].id = (const char *)"new_context"; n[1].kind = (const char *)""; CosNaming::NamingContext_var myctx2 = nmsv_root_ctx->bind_new_context(n, env);以下に名前コンテキストctx1, ctx2が同一のオブジェクトobjを指す例を示します。
例) // C++ // 変数の定義 CosNaming::NamingContext_var root1, root2, ctx1, ctx2; CosNaming::Name n11, n12, n21, n22; CORBA::Object_var obj; CORBA::Environment env; // 基点になる名前コンテキストとターゲットになるオブジェクトの初期化 root1 = ...; root2 = ...; obj = ...; // 名前コンテキストの作成 n11.length(1); n11[0].id = (const char *)"alpha"; n11[0].kind = (const char *)""; ctx1 = root1->bind_new_context(n11, env); n12.length(1); n12[0].id = (const char *)"beta"; n12[0].kind = (const char *)""; ctx2 = root2->bind_new_context(n12, env); // 2つの名前コンテキストが同一のオブジェクトをbindする n21.length(1); n21[0].id = (const char *)"nameX"; n21[0].kind = (const char *)""; ctx1->bind(n21, obj, env); n22.length(1); n22[0].id = (const char *)"name1"; n22[0].kind = (const char *)""; ctx2->bind(n22, obj, env);何らかの手段でオブジェクトリファレンスを獲得することにより、別のサーバで動作している名前サービスのコンテキストをbind_contextで異なる名前サービスにつなぐこともできます。この操作はリモートファイルシステムのマウントにたとえることができます。別の名前サービスの一部をあたかも同一の名前サービスの名前空間の一部のように扱うことができます。
CosNaming::Name myname; myname.length(1); myname[0].id = (const char*)"myobject"; myname[0].kind = (const char*)""; CORBA::Object_ptr myobj = nmsv_root_ctx->resolve(myname, env);
例) // C++ CORBA::Environment env; CosNaming::NamingContext_var ctx1 = ... // ctx1に10個の名前を登録しておく。 ... CosNaming::BindingList_var bl; CosNaming::BindingIterator_var bi; // 1つだけblに取り出して、残りはbiから参照することにした ctx1->list(1L, bl, bi, env); printf("id : %s\nkind : %s\n", bl[0].binding_name[0].id, bl[0].binding_name[0].kind); // biから1つだけ取り出す CosNaming::Binding_var b; bi->next_one(b, env); printf("id : %s\nkind : %s\n", b->binding_name[0].id, b->binding_name[0].kind); // biから5つまとめて取り出す bi->next_n(5L, bl, env); for(int i = 0; i < 5; i++){ printf("id : %s\nkind : %s\n", bl[i].binding_name[0].id, bl[i].binding_name[0].kind); } // biの削除 bi->destroy(env);
プッシュモデル
プルモデル
イベントチャネル
複雑な使い方
// C++によるコーディング例 CORBA_ORB_ptr orb = CORBA_ORB_init(...); orb->__implementation_name("eventchimpl"); orb->__server_path_name("サーバ上でのeventsv.exeまたはeventsvのパス名"); CORBA::Object_var obj = orb->resolve_initial_references("RootPOA"); PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(obj); // LifespanPolicyとしてPERSISTENTをもつPOAを作成 CORBA::PolicyList plist; plist.length(1); plist[0] = rootPOA->create_lifespan_policy(PortableServer::PERSISTENT); PortableServer::POA_var poa = rootPOA->create_POA("MyPOA", PortableServer::POAManager::_nil(), plist); CORBA::Object_var eventch_obj = poa->create_reference("IDL:omg.org/CosEventChannelAdmin/EventChannel:1.0"); char *objstr = orb->object_to_string(eventch_obj); // これをJavaアプリケーションに渡す