omniORBだと
try{ CORBAのソース } catch(CORBA::SystemExeption& ex){ cerr << ex._name << endl; }
でtry文内のExceptionの種類がわかる
Exeptionの吐きかたが
Orbixとは違うので要注意
_out型にマッピングされるので、
毎度おなじみの_var型を使って領域を確保する。
あとはほとんど下に書いてあるのと同じなので、
めんどくさいから書かない。
注意としては、下と同様にポインタ演算で要素にアクセスするということ。
最近CORBAのキモさに対して快感を覚えてきた。
機関銃をぶっぱなす女子高生の如く・・・
Sequence型の配列を戻すような場合、
_slice*型を取り扱わなければならない。
こんなときも_var型
変数が活躍する。
(_var型は領域の解放を自動でおこなう)
ただし、[]演算子がオーバーロードされてないないので、
[]演算子を使いたいのであれば、
[]演算子を自分でオーバーロードして使ってほしい
デフォルトのままでやるならポインタ演算のお勉強が必要
以下に例を書いておく。
IDL
typedef DblSequence DblSequence3[3]; DblSequence3 returnDblSeq2(in DblSequence seq);C++
CorbaServerClient::DblSequence3_slice* CorbaServerClient::CorbaServer_impl::returnDblSeq2(const CorbaServerClient::DblSequence& seq){ CorbaServerClient::DblSequence3_slice* seq3_ptr; CorbaServerClient::DblSequence3_var seq3_var; seq3_var = DblSequence3_alloc(); for(int i=0; i<3; i++){ (*(seq3_var + i)).length(seq.length()); for(int j=0; j<seq.length(); j++){ (*(seq3_var + i))[j] = seq[j]; } } seq3_ptr = seq3_var._retn(); return seq3_ptr; }
idlで関数の戻り値の前にonewayキーワードを付ければ良い。
ただし、戻り値はvoid型で引数はinパラメータのみ
という制限がつく
oneway void server_method(in short param);
Sequence型をoutパラメータに指定してしまうと、
omniidlがSequence_out型
(typedef Sequncen& Sequence_out)
としてマッピングしてしまう。
こいつがとっても厄介。
ポインタの常識がCORBAには通じない。
CORBAのお約束どおりに書いてあげないと領域確保に失敗して、
セグメンテーションエラーやメモリリークが発生する。
DynamicsSimulator_impl.cppのおかげでなんとかお約束がわかった。
CORBAの資料ってスクネエなあ。
なんとかならんものかなあ。
わかったこととしては、
CORBAのメモリ管理は
_var型に任せてしまった方がよいということ。
Orbixの本には、
まるでなんとかの一つ覚え?と言いたくなるほどに
しつこく、_var型に任せろ
と書いてある。
神の意思には従うのが上策であろう。
ちなみにグーグル先生に聞いたところ、
F士通のIDLのマニュアルには、
基本データ型以外のシーケンス型は非対応
なんていう嘘が書いてある。
でも以下の用に、
独自に定義した構造体型のシーケンス型でも
ちゃんとデータのやりとりができる。
やっぱり富士痛はなんというか・・・。
ただ、一瞬それを信じて希望を失いかけた人間がいるというのも
また事実。
富士痛よりもN岡先生のソースを信じる方がベターだとよくわかった。
struct Gait{ double x; double y; double z; double sstime; double dstime; }; typedef sequence<Gait> GaitSequence; void getGait2(out GaitSequence gait_seq);
void SwissRanger_impl::getGait2(OpenHRP::GaitSequence_out gait_seq_out){ GaitSequence_var gait_var = new GaitSequence; gait_var->length(gaitv.size()); if(gaitv.size() > 0){ for(int i=0; i<(int)gaitv.size(); i++){ gait_var[i].x = gaitv[i].x; gait_var[i].y = gaitv[i].y; gait_var[i].z = gaitv[i].z; gait_var[i].sstime = gaitv[i].sstime; gait_var[i].dstime = gaitv[i].dstime; } } gait_seq_out = gait_var._retn(); }
SwissRanger_var sr; void SwissRangerClient::getGait2(std::vector<OpenHRP::Gait>& gait_v){ OpenHRP::GaitSequence_var gait_var; sr->getGait2(gait_var); gait_v.resize((int)gait_var->length()); for(int i=0; i<(int)gait_v.size(); i++){ gait_v[i].x = gait_var[i].x; gait_v[i].y = gait_var[i].y; gait_v[i].z = gait_var[i].z; gait_v[i].sstime = gait_var[i].sstime; gait_v[i].dstime = gait_var[i].dstime; } }
ちなみにスケルトンクラスを継承したクラスの定義と実装(_impl.h _impl.cpp)
はアップデートしていた。
スケルトンクラスはアブストラクトなので、
継承先の派生クラスでオーバーライドしてある。
ゆえに、_impl.hで
アップデート後のIDLで
定義された関数の実装が書かれてしまっている。
なのにもかかわらず、IDLがアップデートされていないため、
idlコンパイラにより吐かれるスケルトンクラスに
オーバーライドもとの関数の
宣言がされていない
ということは、追加された関数は、派生クラス独自のメンバ関数となるわけで、
( _impl.h内で定義される)
クライアントから、その追加された関数を呼び出せるわけがない。
だから、クライアントからその関数を叩いてもサーバー側はなんにも反応しない
考えてみれば当たり前だが、
コピーをめんどくさがったためにはまってしまった。
ただ頭の中を整理するのには役立った.
corbaのサーバにはFactory Classがあるものとないものがある。
FactoryClass?は シミュレーションごとに呼び出す必要があるものに使う。
Factoryクラス と サーバクラスは、 クラスとそのインスタンス に対応づけるとわかりやすい。
シミュレーションごとに呼び出す必要がないもの、 すなわち、シミュレーションのときに一回呼び出すだけで済むもの にはFactoryクラスは必要ない。
Factoryクラスがあるサーバ (Contoroller, DynamicsSimulator?, CollisionDetecter?) では、 まずFactoryクラスのインスタンスを作って、 そのインスタンスからサーバのインスタンスを作る。
Factoryクラスの必要ないサーバ (ModelLoader?) では、 直接サーバのインスタンスを作る。
SwissRangerサーバは後者であろうと思われるので、 Factoryは使っていない。(すぐに使うことができるようにしてある)
SwissRangerClient* src;
として、
SwissRangerData test; test = src->getSwissRangerData();
とすると
CORBA::SystemException
が発生する。
そこで、
SwissRangerData test = src->getSwissRangerData();
とすると、 例外が発生しなくなる。
もしかするとではあるが、 CORBA IDLで定義された型はみんな参照型っぽい性質をもっているのかもしれない。