Bonoboとは?(この節、2005.10.23更新)Bonoboに関するドキュメントは非常に少ない。Bonobo自体も何か一つのことをするのにやり方がいろいろあって、何が妥当なやり方か非常に分かりにくい。Bonoboは、GNOMEで使われているコンポーネント技術。プロセスをまたいでオブジェクトのメソッドを呼び出したり、イベントをやり取りできる。内部ではORBit2を利用してプロセス間通信を行っている。(Moniker)、などなど。Bonoboは、libbonoboとlibbonobouiライブラリからなる。GUIのコンテナとそこに埋め込まれるコントロールを作りたいときはlibbonoboとlibbonobouiの両方を使い、そうでない場合はlibbonoboだけ使う。Bonoboオブジェクトサーバ(この節、2005.10.23更新)手始めに、GUIのコントロールではないBonoboオブジェクトサーバを作ってみよう。オブジェクトサーバを作るときは、次のことをこなさないといけない。ファイルだが、名前のとおり、インターフェイスを定義する。ここではごく簡単なカウンタを定義してみる。ファイル名はcounter.idl。Bonoboオブジェクトにするインターフェイスは、Bonobo::Unknownから派生するようにする。name()を持ち,読み取り専用の属性valueを持つようにしてみる。それから、逆順カウンタも定義してみる。ファイル名はReverseCounter.idl。インターフェイスは同じにすることにして、追加のメソッドなどはない。(Makefileは後述。)実装クラスの宣言IDLファイルをIDLコンパイラに掛けただけでは、サーバー側のスケルトンしか生成されない。インターフェイスの実装は、自分でしないといけない。(インターフェイスだけではどんな動作か決まらないから当たり前。)Bonoboでは、CORBAインターフェイスの実装をglibオブジェクトとして作る。Counterインターフェイスのための実装クラスを宣言する。して、次のようにクラスを定義する。派生し、CounterImplClassはBonoboObjectClassから派生させる。BonoboObjectクラス、BonoboObjectClassクラスは、<bonobo/bonobo-object.h>で定義される。BonoboObjectClassクラスは、Bonobo::Unknownインターフェイスを実装している。して実装しなければならない。structでなければならない。CounterImplクラスでvalueを定義しておく。Bonoboのマクロで決めうちになっている。ファイルで、ReverseCounterインターフェイスの実装クラスであるReverseCounterImplクラスを定義する。cycle管理は、リファレンスカウント方式で行っている。Bonobo::Unknownインターフェイスで参照、解放メソッドが宣言されている。};};Note.Bonobo::Unknownインターフェイスは、COMのIUnknownインターフェイスと同じ意図のメソッドを持つ。(COM)クライアントからの参照が増えるときにref()し、参照が減るときにunref()する。カウントが0になると、そのオブジェクトは破棄される。Bonoboでは、BonoboObjectから派生する実装クラスと、Unknownインターフェイスから派生するインターフェイス・クラスが入り乱れる。unref()を直接呼び出してもいいが、インターフェイスクラスとBonoboObject(派生)クラスの変換をしなければならない。めんどくさくないようにヘルパ関数が用意されている。プロトタイプ宣言は次のとおり。この関数にはBonoboObjectインスタンスを引数として渡す。obj);また、インターフェイス参照を引数として渡すヘルパ関数もある。opt_ev);では、実装に入ることにしよう。必要があれば、ここでメモリの解放などを行う。class_nameと同じにする。)サーバ側でインスタンスを生成、破壊するために次の関数が必要になる。CounterImpl_class_init()は、最初のインスタンスの生成の前に呼び出される。スーパークラスのほうからクラス初期化関数が順番に呼び出されるので、自分でスーパークラスを呼び出す必要はない。ここでは、スーパークラスへのポインタの保存、メソッドの設定をしなければならない。CounterImpl_init()は、インスタンスが生成されるたびに呼び出される。この関数も、スーパークラスのほうから順番に呼び出されるので、自分でスーパークラスを呼び出す必要はない。ここでは、プロパティの初期化などを行う。counter_object_finalize()は、インスタンスのリファレンスカウントが0になって、実際に廃棄されるときに呼び出される。メモリなどインスタンスに関連する資源の解放をここで行う。スーパークラスのfinalize()は自動では呼び出されないので、自分で親クラスのfinalize()を呼び出すようにしなければならない。最後に、BONOBO_TYPE_FUNC_FULL()マクロでCORBAインターフェイスとBonoboObjectクラスを結びつける。定義されていて、'prefix'_get_type()関数を生成する。ReverseCounterのほうも同じように実装する。)サーバ(ファクトリ)Bonoboオブジェクトサーバは、Bonobo::GenericFactoryインターフェイスを実装する。ファクトリ実装は、真の目的のオブジェクトを生成する。このようになっているのは、ひとつのサーバプロセスで複数のオブジェクトを生成できるようにし、また、場合によってはオブジェクトを共有できるようにするためだ。クライアントはファクトリに対して本当の目的のオブジェクトを生成するよう要求する。ファクトリオブジェクトはオブジェクトを生成し、その参照を返す。Bonobo::GenericFactoryインターフェイスは、ただひとつのメソッドcreateObject()を持つ。};};Note.COMではIClassFactoryインターフェイスが相当する。このインターフェイスはCreateInstance()とLockServer()メソッドを持つ。実際には、BONOBO_ACTIVATION_FACTORY()マクロを使うことで、実装の手間は少なくなっている。やらないといけないのは、クライアントから要求されたIIDを確認し、適切なオブジェクトを生成し、それを返すこと。IIDを確認するは、単純に文字列比較すればいい。オブジェクトを共有しようとするときは、リファレンスカウンタを上げておくことを忘れないように。main()関数を生成し、main()関数のなかではBONOBO_FACTORY_INIT()マクロ、bonobo_generic_factory_main()関数を呼び出す。サーバの活性化(2000.11.06の日記を加筆。)オブジェクトサーバは出来たが、クライアントはどのようにして自動的にオブジェクトを提供するサーバプログラムを探し、起動するのか。そのための仕組みがbonobo-activation。頻繁に名前が変わっていて混乱する。いう名前で、GOADがオブジェクト活性化に関わっていた、らしい。私は使ったことがない。1.xはOAFに依存していた。今でも設定ファイルにOAFの名残がある。2.xになって、OAFはbonobo-activationに名前が変わった。その後、bonobo-activationは2003年8月のバージョン2.4.0を最後に、その後はlibbonoboに含まれるようになった。bonobo-activationは、サーバ情報を格納したファイルを調べることでサーバを探す。ディレクトリにそのファイルを保存する。ファイルを見てみよう。Editor"/>設定ファイルは、XMLフォーマットで、oaf_infoがルート要素になる。文字コードはUTF-8。oaf_server要素がサーバの設定で、oaf_info内に複数のサーバ設定を書ける。location属性を持つ。iidはサーバを識別する文字列。typeはサーバプログラムをどのように起動するか。factory、exe、shlibのいずれか。このサーバのtypeを確認する。動的にロードし、ファクトリオブジェクトを生成し、さらにOAFIID:GNOME_GtkHTML_Editor:3.6オブジェクトを生成するよう、ファクトリオブジェクトに要求する。oaf_attribute要素でオブジェクトサーバの属性を設定する。値が複数のときは、oaf_attribute要素のname属性で名前、type属性で型を決め、item要素でサーバの設定値を決める。値がひとつだけのときは、oaf_attribute要素のvalue属性値で設定値を定める。指定の言語で書かれたもの。指定の言語で書かれたもの。一つのオブジェクトは複数のインターフェイスを実装できる。サーバのIIDを指定して呼び出す。インターフェイスを指定して、そのインターフェイスを実装しているサーバを呼び出す方法がある。通常は、前者の方法を採る。)を持つサーバをリストアップして、ユーザに選ばせてからサーバを呼び出すので、やはり前者の方法になるだろう。Note.IIDを介してサーバを探すというやり方はWindowsのCOMと同じ。COMではCLSIDといい、その設定はレジストリに保存される。このようにすることで、インターフェイスさえ変えなければ、コンポーネントをバージョンアップなどで交換することができる。objectとの違いだが、インターフェイスをクラス指向で書けるのが大きいように思う。C++のABIを維持するのは至難の業で、現実は不可能に近い。今回のサンプルの設定ファイルは次のようになる。ファイル名はcounter.server。ファイル名はサーバ名と一致していなくてもいい。なければならないので、uuidgenコマンドで生成したuuidを使うのが望ましい。実際の運用では、単純に名前で区別しているみたい。クライアントWarning.以下の解説は、内容が古く、整理されていません。この節を更新すること。クライアントのコードを示す。argv);生のORBitではCORBA_ORB_init()を最初に呼び出すが,OAFではそれに代えてoaf_init()を呼ぶ。中は見ていないが,おそらく裏でoafdデーモンの起動などを行うのだろう。サーバーに接続する部分は次のようになる。catchException(ev);repo_ids.has()とは見るからに式のようだが,深く調べていないので,何が書けるかは分からない。サーバーを呼び出すだけなら,これで十分。