(2017-05) 現代の環境でコンパイルできるよう, 更新した。10年ぶり、か。
CORBAでのクラス継承を試す。
Java の CORBAモジュール java.corba
は、Java SE 11 (2018年9月リリース) で削除された。JEP 320: Remove the Java EE and CORBA Modules
代替としては, JacORB ぐらい。
インタフェイス
Counter
/ ReverseCounter
インタフェイスのオブジェクトに対して, RPCで呼び出す.
interface Counter {
readonly attribute short value;
void incr();
void decr();
string name();
};
interface ReverseCounter: Counter {
};
ReverseCounter
はincr()
で減算し,decr()
で加算するようにする.
omniORB (C++)
次の環境;
- Fedora 25 Linux
- omniORB 4.2.1
- gcc 6.3.1
サーバ
まず、オブジェクトを実装する。POA_インタフェイス名 から継承する。
C++
- class CounterImpl: public virtual POA_Counter,
- public virtual PortableServer::RefCountServantBase
- {
- protected:
- short count_;
- public:
- CounterImpl(): count_(0) { }
- virtual ~CounterImpl() { }
-
- virtual CORBA::Short value(){ return count_; }
- virtual void incr() { count_++; }
- virtual void decr() { count_--; }
- virtual char* name() { return CORBA::string_dup("通常Counter"); }
- protected:
- CounterImpl(short v): count_(v) { }
- };
-
-
-
-
-
- class ReverseCounterImpl: public virtual POA_ReverseCounter,
- public virtual PortableServer::RefCountServantBase,
- public virtual CounterImpl
- {
- typedef CounterImpl super;
- public:
- ReverseCounterImpl(): super(1000) { }
- virtual ~ReverseCounterImpl() { }
-
- virtual void incr() { count_--; }
- virtual void decr() { count_++; }
- virtual char* name() { return CORBA::string_dup("Reverse(逆進)Counter"); }
- };
CORBA::Object_var
で受けて, _narrow()
で目的のクラスにダウンキャストする。
インタフェイス名_var とインタフェイス名_ptr がある. _varはスコープから抜けるときに解放され, _ptr はそうではない。
実装クラスからインタフェイスクラスを得るには, _this()
を呼び出す。
サーバ側では, クライアントからオブジェクトを探せるように, 次の二つのいずれかの方法を採る;
- name service にオブジェクトを登録する. クライアントでは名前で検索する.
- ファイルに, オブジェクトを
object_to_string()
したものを書き出す. この文字列は, Interoperable Object Reference (IOR) と呼ばれ, サーバのプロセスなどの情報が含まれる。
C++
- int main(int argc, char* argv[])
- {
-
- CORBA::ORB_var orb = CORBA::ORB_init(argc, argv, "omniORB4");
-
- CORBA::Object_var obj;
-
- #ifdef USE_NAME_SERVICE
- CosNaming::NamingContext_var rootContext;
-
-
- obj = orb->resolve_initial_references("NameService");
- rootContext = CosNaming::NamingContext::_narrow(obj);
- if( CORBA::is_nil(rootContext) ) {
- cerr << "Failed to narrow the root naming context." << endl;
- return 1;
- }
- #endif
-
- try {
-
- obj = orb->resolve_initial_references("RootPOA");
- PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(obj);
-
-
-
-
- CounterImpl* myCounter = new CounterImpl();
- ReverseCounterImpl* myReverseCounter = new ReverseCounterImpl();
-
-
-
- PortableServer::ObjectId_var myCounter_iid
- = rootPOA->activate_object(myCounter);
- PortableServer::ObjectId_var myReverseCounter_iid
- = rootPOA->activate_object(myReverseCounter);
-
- #ifdef USE_NAME_SERVICE
- bindObjectToName(orb, rootContext, myCounter->_this(), COUNTER_NAME);
- bindObjectToName(orb, rootContext, myReverseCounter->_this(), REVERSE_NAME);
- #else
-
-
- FILE* fp = fopen(IOR_FILE, "w");
- if (!fp) {
- perror("ior-file open failed");
- return 1;
- }
- CORBA::String_var sior;
- sior = orb->object_to_string(myCounter->_this());
- fprintf(fp, "%s\n", (const char*) sior);
- sior = orb->object_to_string(myReverseCounter->_this());
- fprintf(fp, "%s\n", (const char*) sior);
- fclose(fp);
- #endif
-
-
-
- PortableServer::POAManager_var poaMgr = rootPOA->the_POAManager();
- poaMgr->activate();
-
-
- printf("ready.\n");
- orb->run();
-
- rootPOA->destroy(true, true);
- delete myCounter;
- delete myReverseCounter;
-
- #ifndef USE_NAME_SERVICE
- remove(IOR_FILE);
- #endif
- }
- catch(CORBA::SystemException&) {
- cerr << "Caught CORBA::SystemException." << endl;
- }
- catch(CORBA::Exception&) {
- cerr << "Caught CORBA::Exception." << endl;
- }
- catch(omniORB::fatalException& fe) {
- cerr << "Caught omniORB::fatalException:" << endl;
- cerr << " file: " << fe.file() << endl;
- cerr << " line: " << fe.line() << endl;
- cerr << " mesg: " << fe.errmsg() << endl;
- }
- catch(...) {
- cerr << "Caught unknown exception." << endl;
- }
-
- orb->destroy();
-
- return 0;
- }
クライアント
インタフェイス名_ptr を使って、各メソッドを呼び出す.
C++
-
- void do_test(Counter_ptr counter)
- {
- CORBA::String_var name = counter->name();
- printf("name = %s\n", name.in());
-
- int i;
- printf("incr(): ");
- for (i = 0; i < 5; i++) {
- counter->incr();
- printf(" %d", counter->value());
- }
- printf(".\n");
-
- printf("decr(): ");
- for (i = 0; i < 3; i++) {
- counter->decr();
- printf(" %d", counter->value());
- }
- printf(".\n");
- }
ほんで, main
関数. オブジェクトへの参照は CORBA::Object_var
C++
- int main(int argc, char* argv[])
- {
-
- CORBA::ORB_var orb = CORBA::ORB_init(argc, argv, "omniORB4");
-
- CORBA::Object_var obj;
-
- #ifdef USE_NAME_SERVICE
- CosNaming::NamingContext_var rootContext;
-
-
- obj = orb->resolve_initial_references("NameService");
- rootContext = CosNaming::NamingContext::_narrow(obj);
- if( CORBA::is_nil(rootContext) ) {
- cerr << "Failed to narrow the root naming context." << endl;
- return 1;
- }
- #endif
-
- try {
- #ifdef USE_NAME_SERVICE
- CORBA::Object_var obj_nc = getObjectReference(orb, rootContext,
- COUNTER_NAME);
- CORBA::Object_var obj_rc = getObjectReference(orb, rootContext,
- REVERSE_NAME);
- #else
- FILE* fp = fopen(IOR_FILE, "r");
- if (!fp) {
- perror("file open");
- return 1;
- }
- CORBA::Object_var obj_nc = orb->string_to_object(read_line(fp));
- CORBA::Object_var obj_rc = orb->string_to_object(read_line(fp));
- fclose(fp);
- if (!obj_nc || !obj_rc) {
- printf("ior error.\n");
- return 1;
- }
- #endif
-
- Counter_var nc = Counter::_narrow(obj_nc);
- ReverseCounter_var rc = ReverseCounter::_narrow(obj_rc);
- if (CORBA::is_nil(nc) || CORBA::is_nil(rc)) {
- printf("cannot invoke on a nil object\n");
- return 1;
- }
-
- do_test(nc);
- do_test(rc);
- }
- catch (CORBA::SystemException&) {
- cerr << "Caught CORBA::SystemException." << endl;
- }
- catch (CORBA::Exception& e) {
- cerr << "Caught CORBA::Exception." << endl;
- }
- catch (...) {
- printf("unknown exception.\n");
- }
-
- orb->destroy();
-
- return 0;
- }
実行方法
name serviceを使う場合は, あらかじめ root ユーザで name server を起動しておく。
# omniNames -always
/var/omninames/ 以下にデータを書き込む。
omniORB は, /etc/omniORB.cfg ファイルの設定を見るので, name service を使う場合でも, プログラムの起動時にポート番号などを与える必要はない。
$ ./server
ready.
$ ./client
name = 通常Counter
incr(): 1 2 3 4 5.
decr(): 4 3 2.
name = Reverse(逆進)Counter
incr(): 999 998 997 996 995.
decr(): 996 997 998.
Java
Java SE 8.
サーバ
Javaは多重継承がないので, CounterImpl
を継承できない。同じコードでも再度定義する。
Java
- class CounterImpl extends CounterPOA
- {
- protected short count_;
-
- public CounterImpl() { super(); count_ = 0; }
-
- public short value() { return count_; }
- public void incr() { count_++; }
- public void decr() { count_--; }
- public String name() { return "Counter"; }
- };
-
-
- class ReverseCounterImpl extends ReverseCounterPOA
- {
- protected short count_;
-
- public ReverseCounterImpl() { super(); count_ = 1000; }
-
- public short value() { return count_; }
- public void incr() { count_--; }
- public void decr() { count_++; }
- public String name() { return "ReverseCounter"; }
- };
main
メソッド. 流れは C++版と同じ.
Java
-
- class Server
- {
- public static void main(String[] args) {
- try {
- ORB orb = ORB.init(args, null);
-
-
- POA rootPOA = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
- rootPOA.the_POAManager().activate();
-
-
-
-
-
-
- CounterPOATie ncTie
- = new CounterPOATie(new CounterImpl(), rootPOA);
- ReverseCounterPOATie rcTie
- = new ReverseCounterPOATie(new ReverseCounterImpl(),
- rootPOA);
-
-
- Counter ncRef = ncTie._this(orb);
- ReverseCounter rcRef = rcTie._this(orb);
-
- if (Config.USE_NAME_SERVICE) {
- org.omg.CORBA.Object nameRef
- = orb.resolve_initial_references("NameService");
- NamingContext naming = NamingContextHelper.narrow(nameRef);
-
-
- NameComponent nc = new NameComponent(Config.COUNTER_NAME,
- "Object");
- NameComponent[] pathNC = { nc };
- naming.rebind(pathNC, ncRef);
-
- NameComponent rc = new NameComponent(Config.REV_COUNTER_NAME,
- "Object");
- NameComponent[] pathRC = { rc };
- naming.rebind(pathRC, rcRef);
- }
- else {
-
- FileWriter out = new FileWriter("../counter.ior");
-
-
-
- String ncIOR = orb.object_to_string(ncRef);
- String rcIOR = orb.object_to_string(rcRef);
- out.write(ncIOR + "\n");
- out.write(rcIOR + "\n");
- out.close();
- }
-
-
- orb.run();
-
-
-
-
-
- }
- catch (Exception e) {
- e.printStackTrace(System.err);
- }
- }
- };
クライアント
こちらも, C++と同じ流れ。
Java
-
- class Client
- {
- public static void main(String[] args) {
- try {
- ORB orb = ORB.init(args, null);
-
- org.omg.CORBA.Object ncRef;
- org.omg.CORBA.Object rcRef;
-
- if (Config.USE_NAME_SERVICE) {
- org.omg.CORBA.Object nameRef
- = orb.resolve_initial_references("NameService");
- NamingContext naming = NamingContextHelper.narrow(nameRef);
-
- NameComponent nc = new NameComponent(Config.COUNTER_NAME,
- "Object");
- NameComponent[] pathNC = { nc };
- ncRef = naming.resolve(pathNC);
-
- NameComponent rc = new NameComponent(Config.REV_COUNTER_NAME,
- "Object");
- NameComponent[] pathRC = { rc };
- rcRef = naming.resolve(pathRC);
- }
- else {
-
- BufferedReader in = new BufferedReader(
- new FileReader("../counter.ior"));
- String ncIOR = in.readLine();
- String rcIOR = in.readLine();
-
- ncRef = orb.string_to_object(ncIOR);
- rcRef = orb.string_to_object(rcIOR);
- }
-
- Counter[] counter = new Counter[2];
- counter[0] = CounterHelper.narrow(ncRef);
- counter[1] = ReverseCounterHelper.narrow(rcRef);
-
- for (int k = 0; k < 2; k++) {
- System.out.println(counter[k].name());
-
- for (int i = 0; i < 10; i++) {
- counter[k].incr();
- System.out.print(" " + counter[k].value());
- }
- System.out.println(".");
-
- for (int i = 0; i < 5; i++) {
- counter[k].decr();
- System.out.print(" " + counter[k].value());
- }
- System.out.println(".");
- }
- }
- catch (Exception e) {
- e.printStackTrace(System.err);
- }
- }
- };
実行方法
name serviceを使う場合は, name server のホスト名, ポート番号を引数で与える. IORをファイルでやりとりする場合は、オプションを何も与えなくても大丈夫。
次の例は, omniORB の name server を使う場合。
$ java Server -ORBInitialPort 2809 -ORBInitialHost lolhost
$ java Client -ORBInitialPort 2809 -ORBInitialHost localhost
IORファイルを使う場合, name service を使う場合のいずれでも、omniORB / Java 間で当然, メソッドの呼び出しができる。
gtk3クライアント
次の環境;
- gtk3 3.22.15
- glade 3.20.0
ORBit2 はすでに廃れているので, omniORBを使う。
ウィンドウは, glade3 で, GtkBuilder形式で作る。
本体 (C++).
C++
- #include "../../config.h"
-
- #include <gtk/gtk.h>
- #include "support.h"
- #include "gtk2sample.h"
- #include "../misc.h"
-
- CounterSet csets[2];
-
-
- GtkBuilder* builder;
-
- int main(int argc, char* argv[])
- {
- GtkWindow* window1;
-
- #ifdef ENABLE_NLS
- bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
- textdomain (GETTEXT_PACKAGE);
- #endif
-
- gtk_init(&argc, &argv);
- add_pixmap_directory (PACKAGE_DATA_DIR "/" PACKAGE "/pixmaps");
-
- CORBA::ORB_var orb = CORBA::ORB_init(argc, argv, "omniORB4");
-
- #ifdef USE_NAME_SERVICE
- CORBA::Object_var obj;
- obj = orb->resolve_initial_references("NameService");
- CosNaming::NamingContext_var rootContext =
- CosNaming::NamingContext::_narrow(obj);
- if ( !rootContext ) {
- printf("resolve NameService failed.\n");
- return 1;
- }
-
- CosNaming::Name name;
- name.length(1);
- name[0].id = CORBA::string_dup(COUNTER_NAME);
- name[0].kind = "Object";
- obj = rootContext->resolve(name);
- csets[0].counter = Counter::_narrow(obj);
-
- name.length(1);
- name[0].id = CORBA::string_dup(REVERSE_NAME);
- name[0].kind = "Object";
- obj = rootContext->resolve(name);
- csets[1].counter = ReverseCounter::_narrow(obj);
- #else
- FILE* fp = fopen(IOR_FILE, "r");
- if (!fp) {
- perror("file open");
- return 1;
- }
-
-
- csets[0].counter = Counter::_narrow(orb->string_to_object(read_line(fp)));
- csets[1].counter = ReverseCounter::_narrow(orb->string_to_object(read_line(fp)));
- fclose(fp);
- #endif
-
- if (CORBA::is_nil(csets[0].counter) || CORBA::is_nil(csets[1].counter)) {
- printf("ior error.\n");
- return 1;
- }
-
-
-
-
-
-
- builder = gtk_builder_new();
- GError* error = nullptr;
-
- gtk_builder_add_from_file(builder, "gtk3-window.ui", &error);
- g_assert_no_error(error);
-
-
- gtk_builder_connect_signals(builder, nullptr);
-
- window1 = GTK_WINDOW( gtk_builder_get_object(builder, "window1") );
- gtk_widget_show_all( GTK_WIDGET(window1) );
-
- gtk_main ();
-
-
- Counter_Helper::release(csets[0].counter);
- Counter_Helper::release(csets[1].counter);
-
- return 0;
- }
実行結果
昔の
Linux版はgtk+(GUI)クライアントも実装してみた。
C++の場合は多重継承を使って実装する。plain Cだと(C++ならコンパイラが自動でやってくれる)vtableを手で書く。Javaは多重継承が使えないので,TIE(委譲)モデルで実装する。
IORを文字列にして渡すというヘボい方法なら,JDK 1.2をサーバーにしたとき以外はどの組み合わせでも問題なく接続できる。
\クライアント サーバー\ | Linux | Windows
|
omniORB | mico | ORBacus | ORBit | omniORB | JDK 1.2
|
omniORB on Linux | ○ | ○ | ○ | (未) | ○ | ○
|
mico on Linux (注1) | ○ | ○ | ○ | ○ | ○ | ○
|
ORBacus on Linux | ○ | ○ | ○ | (未) | ○ | ○
|
ORBit on Linux | (未) | ○ | (未) | ○ | ○ | ○
|
omniORB on Windows | ○ | ○ | ○ | ○ | ○ | ○
|
JDK 1.2 on Windows | × (注2) | × (注3) | × (注3) | × (注3) | ○ | ○
|
注1: micoをサーバーにするとき,BOAではなくPOAを使う必要あり。BOAではクライアント側がBAD_OPERATION例外を発生する
注2: CORBA/COMM_FAILURE例外
注3: ハングアップ?
ネームサービスを介してオブジェクトをやり取りするのは,ORBの組み合わせによって上手くいったりいかなかったりして,2000年1月現在では難しい。
- 2000.11.19
- ORBit, mico, omniORB, JavaによるCounter/ReverseCounterリモートオブジェクトの相互接続のテスト
- 2000.01.03
- gtk+クライアント
- 1999.05.16
- ORBit
- 1999.04.23
- mico
ソースコードをまとめたもの: