[技術講座]
金融や電気通信、防衛や宇宙開発などの様々な分野のシステムに CORBA が適用されています。 また、最近では、リアルタイム性が要求される組み込みの分野にも使われるようになってきています。 このような広範囲な分野に適用されるのは、CORBA が異機種間の相互運用性や拡張性、パフォーマンス等に優れているといった特徴を持っているからです。
CORBA とは、一言で説明すると、「分散オブジェクト技術の一つであり、異機種分散環境システムにおけるネットワークインフラ を構築するための仕様である」ということができます。 つまり、CORBA はプログラミング言語非依存、プラットフォーム非依存、ネットワークプロトコル非依存という強力な基盤をアプリケーション開発者に提供します。
しかし、広範囲な機能性を提供できる一方で、問題も抱えています。 CORBA は異機種分散環境におけるシステムインテグレーションに重点をおいてきた技術であり、インテグレーションの観点から見たときの最重要で不可欠なインフラ部分を標準化してきました。しかし、アプリケーション開発の観点からみると、インフラとアプリケーション間とのギャップは大きく、 CORBA を用いて高度なアプリケーションを開発するには、ある程度のスキルが要求されることになってしまいます。
本記事では、そのギャップを解消し、アプリケーション開発の効率を向上させることが可能な CORBA Component Model ( CCM )について解説します。 CCM は、2002 年にリリースが予定されている CORBA 3.0 の主要な機能となっています。
本記事は、CORBA についてある程度の知識を有している読者を対象としています。もし、CORBA についてまだ良く知らない方は、本記事の最後に CORBA を理解するための参考書を記載しましたのでご活用ください。
CCM はサーバサイドのコンポーネントモデルであり、 CORBA のアーキテクチャ上にコンポーネント環境を構築するための仕様です。コンポーネントとは、一般的に「再利用可能なソフトウェアの単位」であると言われていますが、厳密には、以下の4つの要件を満たすものをコンポーネントと呼ぶようです [6]。 CCM も以下の要件を満たしたコンポーネントを実現することを目指しています。
自己完備性/自己記述性
|
独立した機能単体として存在し、 宣言的にインターフェースが定義されている。また、動作や操作に 標準的な方法が定められており、そのためのメカニズムが明確に定義されている。 |
動的な機能追加、変更が可能
|
コンポーネントの外部からプロパティやイベントなどの設定、変更ができる。また、そのための標準的な方法が与えられている。 |
インターフェースの透明性
|
インターフェース定義に基づいて、バイナリレベルでの連携方法が与えられている。 |
他のコンポーネントとの疎結合の支援
|
他のコンポーネント との直接的な通信経路を持たず、コンテナやアセンブリ環境などのフレームワークを介して接続される。 |
サーバサイドのコンポーネントモデルの一つとして Sun の EJB ( Enterprise Java Beans ) があります。図 1-a と 図 1-b はそれぞれ CCM のアーキテクチャと EJB のアーキテクチャをあらわしたものですが、 この図からわかるように CCM は EJB のコンポーネントモデルに強く影響を受けています。事実、CCM の仕様を Java 言語にマッピングしたものが EJB として位置付けられています。
図 1-a: CCM のアーキテクチャ
|
図 1-b: EJB のアーキテクチャ
|
EJB の Enterprise Bean が CCM の CORBA コンポーネントに、EJB コンテナが CCM のコンテナに対応しています。コンテナはコンポーネントを実行させる論理的な環境であり、コンテナ上にコンポーネントが配置されます。そして、コンテナはコンポーネントに対してトランザクション管理やセキュリティ、永続化といった機能を提供します。従来の CORBA の開発では、ORB の初期化や POA による分散オブジェクトの管理、ネーミングサービスへの登録などのアプリケーション開発毎に共通であった処理をアプリケーション開発者が実装する必要がありました。CCM におけるコンテナはそれらの煩雑な処理もすべて提供するので、アプリケーション開発者はその作業から開放されることになります。従って、アプリケーション開発者は、コンポーネントが持つべきビジネスロジックの実装にのみ集中することが可能になります。
また、CCM では EJB と同じくアプリケーション開発者にフレームワークを提供します。CCM のフレームワークにはデザインパターンが適用されているので、CCM のフレームワークで開発することにより、デザインパターンを用いた開発を強制的に行うことになります。例えば、コンポーネントのライフサイクルを Home インターフェースを通して管理するというフレームワークは、必然的に Abstract Factory パターンを使用することになります。
当然、CCM は EJB と類似している点が多いのですが、異なる点もあります。一番の大きな違いは、EJB が Java をベースとした技術であるのに対して CCM は CORBA をベースとした技術であるということです。従って、CCM は、CORBA がもつ言語非依存やプラットフォーム非依存などの強力な特徴を受け継ぐため、レガシーシステムとの連携において非常に効果を発揮します。例えば、EJB の場合、EJB 自体が将来的にレガシーシステムとなったときに、EJB をインテグレーションの対象として考慮する必要があります。しかし、CCM によって作成されたシステムであれば、CORBA によって将来的にも接続性が保証されるため、そのような対象として考慮する必要がないことになります。 また、CCM は EJB との連携に関してブリッジを用いた変換を行う仕様が採用されています。これによって、CCM 仕様のクライアントは、サーバのコンポーネントが EJB であるか CCM であるかといったことを気にせずに透過的にアクセスすることが可能となっています。
また、CCM は OMG で標準化されている技術であるので、MOF ( Meta Object Facility ) のプロファイルとしてメタモデルが厳密に定義されています。従って、UML 等の OMG の他の仕様とのモデルの交換が簡単に行えます。EJB の仕様では、メタモデルはそれほど厳密に定義されていないので、UML 等とモデルの交換を行う場合は多少困難を要します。
さらに、CCM ではコンポーネント間の接続においてかなり厳密なフレームワークが取り入れられています。従って、CCM で開発することによって、複数のコンポーネントを組み合わせてアプリケーションを構築するということが EJB よりも簡単に行えます。
次の章では、CCM のコンポーネントがもつこれらの特徴について説明します。
図 2 は CCM で扱うコンポーネントの外観を示しています。コンポーネントは、5 つの Ports を持っています。 Ports とは、コンポーネントの特徴を外部に公開するための特殊なインターフェースであり、 図に示されている Facet, Receptacle, Event Source, Event Sink, Attribute のことを表しています。これら Ports を適切に宣言することによって、様々な機能や特徴を外部に公開したコンポーネントを作成することができます。
図 2:コンポーネントの外観
|
Facet, Receptacle, Event Source, Event Sink, Attribute のそれぞれが提供する機能を以下の表に示します。
Facet
|
コンポーネントのインターフェースを外部に公開することを示します。クライアントは、公開されたインターフェースをイントロスペクションによって獲得し、インターフェースがもつメソッドを呼び出すことができます。 |
Receptacle
|
他のコンポーネントがもつインターフェースを接続できることを示します。Receptacle のタイプとしては、一つのインターフェースを接続できる Simplex Receptacle と複数のインターフェースを同じ Receptacle に接続できる Multiplex Receptacle が存在します。 |
Event Source
|
特定のイベントを発行することを示します。イベント通知のタイプとしては、1対多の通知ができる Publisher と同時にひとつしか通知できない Emitter が存在します。 |
Event Sink
|
特定のイベントを受け取ることを示します。 |
Attribute
|
コンポーネントが持つ属性を示します。通常の CORBA オブジェクトの属性と同じ意味を持っています。 |
Facet で提供されたコンポーネントのインターフェースは他の Receptacle として宣言されているコンポーネントのインターフェースに接続することを可能します。この Facet と Receptacle の対は、コンポーネント間に同期的な通信手段を提供します。また、Event Sink として特定のイベントを受け取ることを宣言したコンポーネントに対しては、特定のイベントを発行する Event Source を持ったコンポーネントを接続することを可能にします。CCM では、Event Sink と Event Source 間のイベント通知に Publisher / Subscriber モデル[10] が採用されており、これによってコンポーネント間に非同期的な通信手段を提供します。
このように CCM では、コンポーネントという単位によって、外部に提供するインターフェースと外部に要求するインターフェースが何であるかを明示的に表現するという視点を採用しています。これによって、コンポーネントの設計者はよりコンポーネント間の連携に重点を置いた設計が行えるようになります。
コンポーネントに対して明確に定義されたこれらのインターフェースは、コンポーネント間の相互接続性を容易にします。これらの相互接続は、コンポーネントをコンテナに配置するときにデプロイメントツールを用いて行われます。そして、これらの接続に関する情報は、XML ベースのファイル形式として保存されます。
CCM でコンポーネントを定義する場合は、併せて Home インターフェースも定義します。Home インターフェースは、コンポーネントのライフサイクルを管理するためのファクトリのような機能として動作するインターフェースです。CCM におけるクライアントは直接、コンテナ上にコンポーネントのインスタンスを作成することはできません。クライアントはコンポーネントを管理する Home インターフェースを通じて、コンポーネントのインスタンスを作成したり、存在するインスタンスを検索したりします。
さて、上述しているように CCM では Ports および Home と呼ばれる新たなインターフェース定義を導入していますが、これは従来の CORBA で出来ないことを新しく定義しているわけではありません。繰り返しになりますが、CORBA は異機種分散環境の相互運用性を考慮した技術であるため、CCM で作成したコンポーネントが従来の CORBA で作成されたクライアントからも同じ CORBA オブジェクトとしてアクセスできる必要があります。従って、CCM ではコンポーネントを CORBA オブジェクトとしてアクセスできることを可能にするために、拡張された IDL ( Interface Definition Language ) を従来の CORBA と等価な IDL (Equivalent IDL) に変換することを行っています。
次の章では、CCM で拡張された IDL がどのように Equivalent IDL にマッピングされるかについて解説します。
IDL はインターフェースを実装から分離して定義することが可能な言語です。IDL は プラットフォーム、プログラミング言語、ネットワークプロトコル、オブジェクトモデルに依存しないという特徴をもっており、これが CORBA で異機種分散環境のシステムを構築できるということを可能にしています。 例えば、以下のように IDL では interface キーワードを用いて、CORBA オブジェクトが提供するサービスを定義します。
interface Hello{ void sayHello(); };
この IDL では、引数と戻り値を持たない sayHello オペレーションを持った Hello という名前の CORBA オブジェクトを宣言したことになります。
CCM ではコンポーネントを宣言するために、CORBA の IDL に対して新しく以下のキーワードを追加しました。
component
|
consumes
|
emits
|
eventtype
|
finder
|
getraises
|
home
|
import
|
multiple
|
primarykey
|
provides
|
publishes
|
setraises
|
typeid
|
typeprefix
|
uses
|
以下では、新しく追加されたキーワードを用いて、コンポーネントをどのように宣言するのかを一部サンプルを交えながら説明します。
4-1. コンポーネントの宣言
CCM のコンポーネントは、拡張 IDL において component キーワードを用いて以下の構文に従って宣言されます。
component <component_name> [ : <base_name> ] [ supports <interface_name> [, <interface_name>] * ] { <attribute declaration> *; <port declaration> *; };
<component_name> は宣言するコンポーネントの名前を記述します。オプション的な宣言として、 コンポーネントは一つのコンポーネント( <base_name> )を継承することができます。また、同時に いくつかの IDL で定義したインターフェース( <interface_name> )を持つこともできます。 コンポーネントの本体には、コンポーネントの属性( <attribute declaration> ) や Ports ( <port declaration> )を宣言します。
例えば、以下のように Hello インターフェースをもった HelloWorld コンポーネントを宣言することができます。
component HelloWorld supports Hello { attribute string message; };
interface HelloWorld : Hello, Components::CCMObject { attribute string message; };
変換された IDL を見ると、HelloWorld コンポーネントが従来の CORBA オブジェクトと同じように interface で宣言されているのが分ります。但し、コンポーネントは、
Components::CCMObject インターフェースを継承したインターフェースとして宣言されることになります。 Components::CCMObject
インターフェースは、イントロスペクションやPorts を動的にハンドリングするための手段を提供します。
4-2. Ports の宣言
上記の例で attribute キーワードを用いてコンポーネントの属性を宣言したように、同様な記述方法でコンポーネントの本体に Ports を宣言することができます。以下では、それぞれの Ports の宣言方法について示しています。
Facet はコンポーネントのインターフェースを外部に公開することを表します。これは既存の CORBA オブジェクトをコンポーネント化したい場合に利用できます。Facet は 拡張 IDL において provides キーワードを用いて以下の構文で宣言します。
provides <interface_type> <name>;
これは、次のような Equivalent IDL 宣言に変換されます。
<interface_type> provide_<name>();
provide_<name> オペレーションを用いて、コンポーネントが公開するインターフェース( <interface_type> )にアクセスすることができます。コンポーネントの本体に複数の provides 文を記述することで、複数の Facet を公開することもできます。
Receptacle はコンポーネントが他のコンポーネントのインターフェースを使うことを明示的に表します。 Receptacle は拡張 IDL において uses キーワードを用いて以下の構文で宣言します。
uses [multiple] <interface_type> <name>;
multiple キーワードをオプションとして追加すると Multiplex Receptacle として宣言することになります。
Simplex Receptacle として宣言した場合は、次のような Equivalent IDL 宣言に変換されます。 なお、例外にあたる raises 句は記載していません。
void connect_<name>( in <name> conxm ); <interface_type> disconnect_<name>(); <interface_type> get_connection_<name>();
struct <name>Connction{ <interface_type> objref; Components::Cookie ck; }; typedef sequence <<name>Connection> <name>Connections; Components::Cookie connect_<name> ( in <name> conxm ); <interface_type> disconnect_<name>(); <name>Connections get_connections_<name>();
Event Source と Event Sink の間で非同期的にイベントをやり取りするには、やり取りするイベントを宣言する必要があります。イベントは、拡張 IDL において eventtype キーワードを用いて以下のように宣言します。
eventtype <name> { ... };
これは、次のような Equivalent IDL 宣言に変換されます。
valuetype <name> : Components::EventBase{ ... }; interface <name>Consumer : Components::EventConsumerBase{ void push( in <name> ev ); };
イベントを宣言すると、イベント名をもったコンシューマインターフェース( <name>Consumer )が生成されます。このコンシューマインターフェースがもつ push オペレーションを呼ぶことでイベントを通知することができます。イベントを受け取りたいコンポーネントは、このコンシューマインターフェースを実装する必要があります。
Publisher タイプの Event Source は 1 対 多 のイベント通知を可能にします。Publisher タイプでは、拡張 IDL において publishes キーワードを用いて以下の構文で宣言します。
publishes <event_type> <name>;
<event_type> には eventtype キーワードで宣言したイベント名を記述します。
これは、次のような Equivalent IDL 宣言に変換されます。 なお、例外にあたる raises 句は記載していません。
Component::Cookie subscribe_<name>( in <event_type>Consumer consumer ); <event_type>Consumer unsubscribe_<name>( in Components::Cookie ck );
Emitter タイプの Event Source は一度に一つのコンポーネントに対して通知を行います。Emitter タイプでは、拡張 IDL において emits キーワードを用いて以下の構文で宣言します。
emits <event_type> <name>;
これは、次のような Equivalent IDL 宣言に変換されます。 なお、例外にあたる raises 句は記載していません。
void connect_<name>( in <event_type>Consumer consumer ); <event_type>Consumer disconnect_<name>();
Event Sink は特定のイベントを受け取ることを表します。Event Sink は拡張 IDL において consumers キーワードを用いて以下の構文で宣言します。
consumers <event_type> <name>;
<event_type> にはeventtype キーワードで宣言したイベントを記述します。
これは、次のような Equivalent IDL 宣言に変換されます。
<event_type>Consumer get_consumer_<name>();
コンポーネントに対してイベントを通知する場合は、get_consume_<name> オペレーションを用いてコンシューマを取得します。
Home インターフェースはコンポーネントのインスタンスのライフサイクルを管理します。管理対象のコンポーネントの Home インターフェースを宣言するには、拡張 IDL において home キーワードを用います。
例えば、上記 HelloWorld コンポーネントに対する Home インターフェースは以下のように宣言することができます。 manages の後に、管理対象となるコンポーネント HelloWorld を指定します。
home HelloHome manages HelloWorld { attribute string initial_message; };
Home インターフェースにはコンポーネントのインスタンスを一意に特定するためのプライマリキーを持つものと持たないものの 2 種類が存在します。どちらの種類の Home インターフェースを利用するかは、コンポーネントのライフサイクルと深く関係しています。 上記の例は、プライマリキーを持たない Home インターフェースとして宣言したものです。
プライマリキーを持たない上記の Home インターフェースは、次のような Equivalent IDL 宣言に変換されます。
interface HelloHomeImplicit : Components::CCMHome { HelloWorld create(); }; interface HelloHomeExplicit : Components::KeylessCCMHome { attribute string initial_message; }; interface HelloHome : HelloHomeImplicit, HelloHomeExplicit{};
Components::CCMHome を継承した HelloHomeImplicit インターフェースと Components::KeylessCCMHome を継承した HelloHomeExplicit インターフェースが生成されます。 拡張 IDL で宣言された HelloHome インターフェースはこれらの 2 つのインターフェースを継承した形式に変換されます。 HelloHomeExplicit インターフェースには、設計者が宣言したオペレーションや属性( この例では、initial_message )がマッピングされます。 また、HelloHomeImplicit インターフェースには create オペレーションが定義されており、これがコンポーネントの生成に利用されます。
本記事では、 CCM で扱われるコンポーネントに焦点を当て、どのように拡張 IDL で定義するのかについて解説を行いました。CCM の仕様では、コンポーネントのライフサイクルとして、コンポーネントの作成・実装、コンポーネントの接続・結合、コンポーネントの分散配置、コンポーネントの実行といった 4 段階のステップがあり、それぞれコンポーネントモデル、パッケージングモデル、分散配置モデル、コンテナモデルとして仕様が規定されています。今回はコンポーネントモデルの一部について取り上げたということになります。次回は、CCM でどのようにコンポーネントを実装するのか、CCM を実装した製品を用いて、その開発の流れを EJB の開発と対比させながら解説したいと思います。
参考までに現在利用可能ないくつかの CCM の実装製品 [12],[13],[14],[15] を参考資料 ・ URLに記載しています。
CORBA について理解したい方は、CORBA 準拠の ORB 製品を実際に使用してみることをお奨めします。CORBA 準拠の ORB 製品のリストは、 OMG ジャパンのサイトに掲載されています。ORB 製品に付属するサンプルを実行し、ソースコードを確認することで、CORBA の通信のメカニズムが理解し易くなるでしょう。
以下の図書は Java を用いて解説を行っていますが、 Java を良く知らない方でも CORBA についてある程度、理解が得られると思います。
また、さらに CORBA について理解を深めたい方は次の図書を読むことをお奨めします。
© 2002 OGIS-RI Co., Ltd. |
|