目次


Apache Geronimo、JMSを使いイベントドリブンフレームワーク構築する

Javaリフレクションを使ってイベント・タイプを定義する

Comments

リアルタイムで発生する変化やイベントに即座に応答できることは、エンタープライズ・フレームワークにとって重要な要求です。この記事では、リアルタイムの刺激に対してアプリケーションやサービスが効果的に応答できるように、またアーキテクチャーの仮想レイヤーにまたがってイベントを送受信できるようにするための機能として、Apache Geronimoフレームワークの中に具体化されている技術や機構を紹介します。

動的なワークフロー・システムや統合システムは、開発者が通常のシーケンシャルな処理方法を使って設計や構築を行おうとすると、障害に突き当たります。従って、もっと適切な、イベントを意識する手法やツールが強く求められるようになりました。SOAとイベント・ドリブン・プログラミングは、この複雑な課題を解決しようとしています。

SOAは、疎結合の開発モデルとランタイム環境を構築することを目的としています。SOAでは、サービス・プロバイダーとサービス・コンシューマーが動的なコンポーネント対話動作を通して作業を行い、SOAモデルの持つ柔軟性や強力さを活用した対話動作モデルを構築します。イベント・ドリブンの対話動作モデルは、動的なイベントやシグナルに対して、通常の同期機構よりもタイムリーに応答することができます。その理由の一端は、SOAの中でのイベント・ドリブン・プログラミングが、分散システムが本来的に必要とするものと同じ特性(特殊化、モジュラー性、適用性など)を備えているためです。

イベント・ドリブン・アーキテクチャー

Gartner Groupは2003年に、システムやサービス、アプリケーションなどの設計構築のための方法論として、EDA(event-driven architecture)を紹介しました。EDAでは、疎結合されたイベント・レシーバーの間でイベントをルーティングします。イベント・ドリブン・システムは、『イベント・プロデューサー』と『イベント・レシーバー』で構成されます。イベント・プロデューサーは、『イベント・チャネル』に対してイベントを公開し、イベント・チャネルはそのイベントを、サブスクライブ・イベント・レシーバーに配布します。イベント・チャネルは、プロデューサーがイベントを公開すると、それをレシーバーに転送します。レシーバーが利用できない場合には、イベント・チャネルはイベントを保存し、後でレシーバーが利用できるようになると、そのイベントをレシーバーに転送します。このプロセスは、『保存と転送(store and forward)』と言われます。

EDAでは、2つ以上の実体の間における対話動作の手段として、メッセージングの概念を利用しています。対話動作は、何らかのビジネス・ドメイン・イベントに対応するシグナル、あるいはメッセージを発行することによって開始されます。対象となる各イベントに対する全サブスクライバーは、イベントが発生すると通知を受けます。そうすると、サブスクライバーはイベントに対して何らかの動作を行います。

EDAは、次のような特徴を持っています。

  • 関連付けの分離(decoupled associations): イベント・パブリッシャーとイベント・サブスクライバーは、お互いの存在を事前に知っている必要がありません。
  • 多対多の対話動作(Many-to-many interactions): 1つ以上のイベントが、1つ以上のサブスクライバーに影響を与えます。
  • イベント・ベースのコントロール・フロー: アプリケーションはイベントが発生した時に応答するため、アプリケーション・フローは、より自然になります。
  • 非同期メッセージング: ビジネス・ロジックは、イベントと並行して発生することができます。

EDAを利用してアプリケーションやシステムを構築すると、応答性を高めることができます。これは、イベント・ドリブン・システムの設計そのものが、予測不可能で変化する環境に対して適用性が高い構成となっているためです。

イベント・ドリブンの設計開発の利点

イベント・ドリブンのプログラミングには多くの利点がありますが、その一部として下記を挙げることができます。

  • 分散システムの開発や維持管理に関わる複雑さを減少させることができます。
  • アプリケーションやサービスの構築やコンフィギュレーションが、より容易に、安価になります。
  • ソースコードやコンポーネントの再利用が促進されるため、バグが減少し、アジャイルな開発やデプロイメントを実現することができます。

イベント・ドリブンの設計開発による短期的な利点としては、カスタム化が迅速に、容易に行えることです。また長期的な利点としては、システムの状態が、より正確になることです。

EDAとSOAを組み合わせる

EDAでは、変更リクエストがないかをクライアントがポーリングするシーケンシャル型システムやプロシージャー型のシステムとは異なり、システムやコンポーネントが、イベントの発生に合わせて動的に、リアルタイムで応答することができます。EDAは、長期間実行する処理機能を導入することによって、SOAを補完しています。つまり、イベント・コンシューマーはイベントが発生した時にイベントを受信するのであり、また疎結合のサービスを呼び出してタイムリーで正確なデータを顧客に提供できることから、ビジネスにとっても有利になります。

EDAでは、システムが効果的に応答し、動作できるように、物理層やアーキテクチャーの仮想レイヤーを含めたSOAの全セグメントにまたがってイベントを送信することができます。図1は、アーキテクチャー・スタックのレイヤーにまたがってイベントが伝搬される様子を示しています。

図1. 仮想レイヤーにまたがる伝搬
Event flow across architecture stack
Event flow across architecture stack

ここから分かる通り、イベントは、アプリケーションやビジネス、コンポーネント、プラットフォーム、あるいはシステム・レイヤーにおける、どのような変化の結果としても発生します。技術的な観点から言うと、ビジネス・イベントは本質的に、例えばシステム・イベントやコンポーネント・イベントよりも上位レベルと見なされます。

イベントの原因、つまり『イベント因果関係(event causality)』は、そのイベントを理解する上で重要な要因です。イベント因果関係は、『水平因果関係(horizontal causality)』と『垂直因果関係(vertical causality)』に分解することができます。水平因果関係は、イベント・パブリッシャーがイベント・レシーバーと同じレイヤー(アーキテクチャーの仮想レイヤー)に存在する場合に発生します。垂直因果関係は、イベント・パブリッシャーがイベント・レシーバーとは異なるレイヤーに存在する場合に発生します。

EDAとイベント・キュー

イベント・ドリブン・プログラミングは、イベント・プロデューサーとイベント・コンシューマーとの間の分離という概念を元に構成されています。言い換えると、イベント・コンシューマーは、どこで、なぜイベントが発生しているのかには関知せず、イベントが発生した場合に自分が呼び出されることに関心を持つのです。イベント・プロデューサーとイベント・コンシューマーを分離するシステムやアプリケーションは、通常はイベント・ディスパッチャー、つまり『チャネル』に依存します。このチャネルには、イベント・プロデューサーとイベント・ハンドラーとの間の仲介者として動作する、イベント・キューが含まれています。

図2は、プロデューサーやコンシューマー、イベント・チャネル、そしてトピック、つまり『キュー』の関係を示しています。

図2. イベント・チャネル
Event queue
Event queue

イベント・キューの役割は、プロデューサーから受信したイベントを保存し、各コンシューマーが利用可能となったら、こうしたイベントを(通常はイベントが受信された順に)コンシューマーに対して送信することです。

イベント・キューとトピック

大部分のイベント・ドリブン・システムでは、MOM(Message-Oriented Middleware)フレームワークのような、事前構築されたイベント・キュー技術に依存しています。MOMは、メッセージ・キューに基づく非同期メッセージング・モデル・フレームワークです。

MOMフレームワークの主な利点は、無期限にメッセージを保存でき、コンシューマーがそれらを受信できるようになったらコンシューマーにルーティングできることです。MOMシステムは、下記のメッセージング・モデルで動作します。

  • ポイント・ツー・ポイント・モデル: このモデルは『キュー』として知られるメッセージ・リポジトリーに基づいており、メッセージは、1つ以上のプロデューサーから1つのコンシューマーに送信されます。
  • パブリッシュ/サブスクライブ・モデル: このモデルは『トピック』として知られるメッセージ・リポジトリーに基づいており、メッセージは、1つ以上のプロデューサーから1つ以上のサブスクライブ・コンシューマーに公開されます。

図3は、1つのパブリッシャー、1つのイベント・チャネル、1つのトピック、そして与えられたメッセージ・タイプをサブスクライブする複数コンシューマー、という間で行われる対話動作を示しています。

図3. パブリッシャーとサブスクライバー、イベント・チャネル、トピックの間での対話動作
Interactions
Interactions

JMS(Java Message Service)フレームワークは、MOMモデルに対するJava API(application program interface)の抽象化です。

EDAでJMSを使用する

Java技術は、Javaプログラムがメッセージを作成、送信、受信し、そして読むための共通な方法として、JMSを提供しています。JMSは、大部分のメッセージング・システムに見られる共通概念や意味体系の、インターフェースとクラスの抽象化フレームワークです。

メッセージ・プロデューサーとコンシューマーは、JMSインターフェースを通して、メッセージをポイント・ツー・ポイント・モデル、あるいはパブリッシュ/サブスクライブ・モデルで送受信します。下記のリストは、JMSの中の主なコンポーネントを示しています。

  • ConnectionFactory: JMSコネクションを作成するために使用されるオブジェクト
  • Connection: JMSシステムへのコネクション
  • Destination: メッセージ・トピックあるいはメッセージ・キューいずれかの抽象化
  • Session: メッセージを送受信するためのコンテキスト
  • MessageProducer: セッションが作成し、また宛先(destination)にメッセージを送信するために使用されるコンポーネント
  • MessageConsumer: セッションが作成し、また宛先からメッセージを受信するために使用されるコンポーネント

GeronimoとJMSを使った単純なイベント・フレームワーク

Apache Geronimoには、Active MQというオープンソースのメッセージング・プロバイダーが同梱されています。Active MQはJMSをサポートしています。つまり、Geronimoフレームワークに基づくアプリケーションの構築に、JMSのメッセージング機能を利用することができます。

これから先のセクションでは、GeronimoとActive MQ、そしてJMSの概念や意味体系を使って構築された単純なイベント・フレームワークを定義します。これらのセクションで定義するイベント・フレームワークは、イベント・チャネルとイベント・パブリッシャー、そしてイベント・レシーバーから構成されます。イベント・チャネルは、イベント・レシーバーの登録/登録解除と、イベント・パブリッシャーからイベント・レシーバーに非同期でイベント・メッセージをルーティングすることに責任を持ちます。このフレームワークが持つユニークな概念として、イベント・チャネルがフィルター機能とルーティング機能を持っており、イベント・オブジェクトが実装するJavaクラスのタイプやインターフェースに基づいて、適当なレシーバーにメッセージを渡せることが挙げられます。

クラス/インターフェース階層構造を使用してイベントをフィルターし、ルーティングする

通常のメッセージング・システムでは、メッセージ・サブスクライバーが、自分たちが受信するイベントのタイプをドット区切り文字列(例えば『travel.flights.seats』あるいは『travel.lodging.rates』など)で定義することができます。この記事で説明するイベント・フレームワークでも、サブスクライバーは特定タイプのイベントをサブスクライブできますが、そのイベント・タイプはJavaのクラスとインターフェースの階層構造で定義されます。

このイベント・フレームワークは、図4に示すクラス階層構造のようなドット区切りメッセージ型の階層構造を表します。

図4. イベント・アプリケーションのクラス関係
Event application class relationships
Event application class relationships

Eventインターフェースが表現するイベントをサブスクライブするイベント・レシーバーは、この図に基づいて、全イベントを受信します。一方、FlightEventインターフェースが表現するイベントをサブスクライブするイベント・レシーバーは、そのインターフェース、あるいはFlightDelayedクラスまたはSeatAvailableクラスに基づくイベントのみを受信します。この設計によって、イベント・レシーバーは、複数のイベント・タイプを同時にサブスクライブすることができます。例えばイベント・レシーバーは、イベント・チャネルのsubscribe() メソッドをEvent.classというパラメーターを付けて呼び出すことによって、全てのイベントをサブスクライブすることができます。もし新しいイベント・タイプが追加された場合には、それらが公開されると、イベント・レシーバーは自動的にそれらの受信を開始します。

イベント・チャネルは、イベント・レシーバーがサブスクライブするイベント・インターフェースのうちの、最も具体的なサブタイプを判断することでイベント階層構造を処理します。例えば、リスト1に示すFlightDelayedクラスは、FlightEventインターフェースを実装しています。従ってイベント・チャネルは、まずFlightDelayedクラスのサブスクライバーを探し、次にFlightEventインターフェースを探し、と続け、クラス/インターフェースの階層構造を上にたどって行きます。

リスト1. FlightDelayedクラス
class TravelEvent extends Event {}
class FlightEvent extends TravelEvent {}
class LodgingEvent extends TravelEvent {}

public class FlightDelayed
implements FlightEvent
{
private String message = "";

public FlightDelayed()
{
}

public FlightDelayed(String message)
{
this.message = message;
}

public String getMessage()
{
return message;
}

public void setMessage(String message)
{
this.message = message;
}
}

イベント・チャネル

『イベント・チャネル』はイベント・パブリッシャーがイベントを公開するために使用するコンポーネントであり、またイベント・レシーバーがイベントのサブスクライブや受信に使用するコンポーネントでもあります。単純なイベント・チャネルに対するインターフェースをリスト2に示します。

リスト2. 単純なイベント・チャネルに対するインターフェース
public interface Channel
{
void start();

void stop();

void publish(final Event event);

void subscribe(final Receiver receiver,
final Class eventClass);

void unsubscribe(final Receiver receiver,
final Class eventClass);
}

subscribe() メソッドとunsubscribe() メソッドは、Class型のパラメーターを必要とすることに注意してください。イベント・チャネルはこれを使用して、レシーバーがサブスクライブ、あるいはサブスクライブ中止するイベントのタイプを判定します。

イベント発生を検出しようとイベント・レシーバーがポーリングするのを防ぐために、イベント・レシーバーはReceiverインターフェースのreceive() メソッドを通して呼び出されます。イベントがイベント・チャネルに公開された場合には、どのサブスクライバーがイベントを受信すべきかを判断するために、Javaリフレクションが使われます。次に、こうしたオブジェクトに対してreceive() メソッドが呼び出されます。リスト3は、単純なイベント・レシーバーを示しています。

リスト3. 単純なイベント・レシーバーの実装
public class EventReceiver
implements Receiver
{
private static final transient Log log =
LogFactory.getLog(EventReceiver.class);

private String id = "";

public EventReceiver()
{
}

public EventReceiver(String id)
{
this.id = id;
}

public void setId(String id)
{
this.id = id;
}

public String getId()
{
return id;
}

public void receive(final Event event)
{
log.info("EventReceiver [" + id
+ "] received event [" + event.getMessage() + "]");
}
}

リスト4はイベント・チャネルからの抜粋です。

リスト4. イベント・チャネルの実装
public class EventChannel
implements Channel
{
private static final String TOPIC_NAME =
"java:comp/env/EventTopic";

private static final String MQ_URL = "tcp://localhost:61616";

private HashMap subscribers = new HashMap();
private TopicConnectionFactory factory = null;
private Topic eventTopic = null;
private TopicConnection topicConn = null;
private TopicSession topicSess = null;
private TopicSubscriber topicSubscriber = null;
private TopicPublisher topicPublisher = null;
private EventConsumer eventConsumer = null;

private void handleEvent(Event event)
{
final Set received = new HashSet();

for (Class eventClass = event.getClass();
Event.class.isAssignableFrom(eventClass);
eventClass = eventClass.getSuperclass())
{
ArrayList receiverList = new ArrayList();
getReceiversForEvent(getEventLeafInterface(eventClass),
 receiverList);
Receiver[] receivers = new Receiver[receiverList.size()];
receiverList.toArray(receivers);
for (int i = 0; i < receivers.length; i++)
{
invokeOnce(received, receivers[i], event);
}
}
}

private void invokeOnce(Set received,
Receiver receiver,
Event event)
{
received.add(receiver);
receiver.receive(event);
}

private Class getEventLeafInterface(Class cls)
{
Class retVal = null;

if (Event.class.isAssignableFrom(cls))
{
retVal = cls;
if (cls.isInterface())
{
return retVal;
}
}

Class[] interfaces = cls.getInterfaces();
if (interfaces != null)
{
for (int i = 0; i < interfaces.length; i++)
{
if (Event.class.isAssignableFrom(interfaces[i]))
{
retVal = interfaces[i];
break;
}
retVal = getEventLeafInterface(interfaces[i]);
}
}

return retVal;
}

public void start()
{
try
{
factory = new ActiveMQConnectionFactory(MQ_URL);
topicConn = factory.createTopicConnection();
topicSess =
topicConn.createTopicSession(false,
           Session.AUTO_ACKNOWLEDGE);
eventTopic = topicSess.createTopic(TOPIC_NAME);
topicSubscriber = topicSess.createSubscriber(eventTopic);
topicPublisher = topicSess.createPublisher(eventTopic);

eventConsumer = new EventConsumer(this);
Thread consumerThread = new Thread(eventConsumer);
consumerThread.setDaemon(false);
consumerThread.start();
}
catch (Exception e)
{
e.printStackTrace();
}
}

public void stop()
{
// close topic connections, sessions, consumers, etc.
}

public void publish(final Event event)
{
try
{
ObjectMessage eventMessage = topicSess.createObjectMessage();
eventMessage.setObject(event);

topicPublisher.publish(eventMessage);
}
catch (Exception e)
{
e.printStackTrace();
}
}

public void subscribe(final Receiver receiver,
final Class eventClass)
{
ArrayList receiverList = null;

Class leafCls = getEventLeafInterface(eventClass);

if (subscribers.get(leafCls) == null)
{
receiverList = new ArrayList();
subscribers.put(leafCls, receiverList);
}
else
{
receiverList = (ArrayList) subscribers.get(leafCls);
}

if (receiverList.indexOf(receiver) < 0)
{
receiverList.add(receiver);
}
}

public void unsubscribe(final Receiver receiver,
final Class eventClass)
{
Class leafCls = getEventLeafInterface(eventClass);
if (subscribers.get(leafCls) != null)
{
ArrayList receiverList = (ArrayList) subscribers.get(leafCls);
receiverList.remove(receiverList);
}
}
}

注意: EventChannelクラスの完全なソースコードは、この記事の最後にあるダウンロード可能なリソースセクションからダウンロードすることができます。

リスト5は、イベント・コンシューマーの実装からの抜粋です。

リスト5. イベント・コンシューマーの実装
class EventConsumer
implements Runnable, ExceptionListener
{
private boolean running = false;
private boolean stopped = true;
private EventChannel eventChannel = null;

private EventConsumer(EventChannel eventChannel)
{
this.eventChannel = eventChannel;
}

public void run()
{
log.info("Event Consumer started");

// Create a Topic Connection, Session, and a MessageConsumer for the Topic
// loop until stopped and distribute events to the event channel
// using the handleEvent method  
eventChannel.handleEvent(event);

stopped = true;

log.info("Event Consumer stopped");
}

public void shutdown()
{
running = false;

while (stopped == false)
{
Thread.yield();
}
}
}

注意: EventConsumerクラスの完全なソースコードは、この記事の最後にあるダウンロード可能なリソースセクションからダウンロードすることができます。

Geronimoの中でイベント・フレームワークをデプロイし、実行する

イベント・フレームワークは、Geronimoの中にデプロイされたWebアプリケーションを使用して、各イベント・タイプをテストします。このWebアプリケーションは、イベント・フレームワークの他に、1つのHTMLフォーム(イベント・メッセージを入力します)と、1つのサーブレット(HTTPリクエストを受信し、その内容をイベント・チャネルにディスパッチします)から構成されています。

このHTMLフォーム(図5)は単純に、3つのタイプのイベント・メッセージを、ディスパッッチを行うサーブレットに送ります。

図5. Webアプリケーションの起動画面
Web application Start screen

ディスパッチを行うサーブレットは、イベント・チャネル・オブジェクトと3つのサンプル・イベント・レシーバーをインスタンス化します。次にイベント・レシーバーは、与えられたイベントをサブスクライブし、サーブレットはこれらイベントをイベント・チャネル・オブジェクトに公開します。リスト6は、このサーブレットを示しています。

リスト6. ディスパッッチ・サーブレットの実装
public class SenderServlet extends HttpServlet
{
private EventChannel eventChannel = null;
private EventReceiver allTravelEventReceiver = null;
private EventReceiver flightEventReceiver = null;
private EventReceiver lodgingEventReceiver = null;

public void init()
throws ServletException
{
super.init();

eventChannel = new EventChannel();
eventChannel.start();

// create event receivers
allTravelEventReceiver =
new EventReceiver("allTravelEventReceiver");
flightEventReceiver =
new EventReceiver("flightEventReceiver");
lodgingEventReceiver =
new EventReceiver("lodgingEventReceiver");

// subscribe to all Travel events
eventChannel.subscribe(allTravelEventReceiver,
 TravelEvent.class);

// subscribe to Flight events
eventChannel.subscribe(flightEventReceiver,
 FlightEvent.class);

// subscribe to Lodging events
eventChannel.subscribe(lodgingEventReceiver,
 LodgingEvent.class);
}

public void destroy()
{
super.destroy();

// unsubscribe all event receivers and stop the event channel
}

public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException
{
// respond with input form
}

public void doPost(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException
{
String txtMsg = req.getParameter("txtMsg");
if (txtMsg != null && txtMsg.length() > 0)
{
String flightDelayed = req.getParameter("FlightDelayed");
String rateIncreased = req.getParameter("RateIncreased");
String seatAvailable = req.getParameter("SeatAvailable");

if (flightDelayed != null)
{
// send a Flight event
eventChannel.publish(new FlightDelayed(txtMsg));
}
else if (rateIncreased != null)
{
// send a Lodging event
eventChannel.publish(new RateIncreased(txtMsg));
}
else if (seatAvailable != null)
{
// send a Flight event
eventChannel.publish(new SeatAvailable(txtMsg));
}
}

doGet(req, res);
}
}

注意: SenderServletクラスの完全なソースコードは、この記事の最後にあるダウンロード可能なリソースセクションからダウンロードすることができます。

図6は、イベント・ディスパッチ・サーブレットによって呼び出された場合の、イベント・フレームワークに対するアプリケーション・フローを示しています。

図6. イベントWebアプリケーションのシーケンス
Sequences for event Web application
Sequences for event Web application

アプリケーションをデプロイする

Webアプリケーションとイベント・フレームワークのためのクラスは、GERONIMO_HOME/deployディレクトリーの.warファイルの中にパッケージされています。.warファイルが作成され、デプロイ・ディレクトリーにコピーされると、Geronimoは起動時にそれを自動的にデプロイします。デプロイ・ディレクトリーに置かれたアプリケーションはホット・ロードされるため、変更が加えられた場合には、Geronimoは実行時にそのアプリケーションを再ロードすることができます。これはアプリケーションのデバッグに便利です。

アプリケーションを実行する

Geronimoアプリケーション・サーバーの起動は、GERONIMO_HOME/binディレクトリーの中にある起動スクリプト(startup.batまたはstartup.sh)を使って行います。Geronimoの起動スクリプトが呼び出されると、Geronimoのコンソール・ウィンドウが現れます。イベント・フレームワークのWebアプリケーションがデプロイされると、起動時のGeronimoコンソール・ウィンドウにリスト7のようなラインが表示され、Webアプリケーションが無事起動したことを確認できます。

リスト7. 無事起動したWebアプリケーション
00:12:33,921 INFO  [EventChannel] Starting EventChannel...
00:12:33,937 INFO  [EventChannel] Creating topic connection...
00:12:35,062 INFO  [EventChannel] EventChannel started
00:12:35,062 INFO  [EventChannel] Event Consumer started
00:12:35,093 INFO  [SenderServlet] AllTravelEventReceiver
[com.jeffhanson.eda.EventReceiver@f84033]
00:12:35,093 INFO  [SenderServlet] FlightEventReceiver
[com.jeffhanson.eda.EventReceiver@3ee73b]
00:12:35,093 INFO  [SenderServlet] LodgingEventReceiver
[com.jeffhanson.eda.EventReceiver@16127f4]

イベントがサーブレットに送られると、サーブレットはそれをイベント・チャネルに公開します。もし、Flight 2365 to Detroit will be delayed 15 minutesというテキストを含んだFlight-Delayedメッセージがサーブレットに送られると、Geronimoのコンソール・ウィンドウにはリスト8のような表示が現れます。

リスト8. 成功したイベント公開
00:12:53,718 INFO  [SenderServlet] >>>>>
00:12:53,718 INFO  [SenderServlet] >>>>>
00:12:53,734 INFO  [EventChannel] Publishing event
  [com.jeffhanson.eda.events.business.FlightDelayed@863854]
00:12:53,859 INFO  [EventReceiver] EventReceiver [flightEventReceiver]
  received event [Flight 2365 to Detroit will be delayed 15 minutes]
00:12:53,859 INFO  [EventReceiver] EventReceiver [allTravelEventReceiver]
  received event [Flight 2365 to Detroit will be delayed 15 minutes]

まとめ

リアルタイムの変化やイベントにタイムリーに応答する、効果的なイベント・ドリブン・ソフトウェア・システムの設計は複雑です。Javaリフレクションを使用した効果的なイベント・ドリブン対話動作フレームワークとSOAを組み合わせることによって、複雑さを減少させ、柔軟性を向上することができます。Geronimoプラットフォームには、強力なイベント・ドリブン対話動作フレームワークを構築するために、JMSプロバイダーなど様々なAPIやツールが用意されています。

直線的なエンタープライズ・プログラミングからサービス指向の設計に移行することには大きな利点があり、これはSOAモデルにも当てはまります。ビジネス・サービスの成果を得るためにシステムをリファクタリングすれば、サービスやコンポーネントのためのモジュラーなフレームワークが生まれるはずです。そして、サービス・インフラの対話動作モデルがアジャイルで拡張性が高ければ、様々なアプリケーションに合わせて、こうしたコンポーネントを再利用することができます。SOAとEDA、そしてApache Geronimoの組み合わせは、強力で効果的なソフトウェア・インフラ構築の基礎と言うことができます。


ダウンロード可能なリソース


関連トピック


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Open source, Java technology
ArticleID=232567
ArticleTitle=Apache Geronimo、JMSを使いイベントドリブンフレームワーク構築する
publish-date=06272006