J2EE コネクター・アーキテクチャー (JCA) は、多くのアプリケーション・コンテナーと今日の企業情報システム (EIS) との間の接続に関する問題解決に寄与する Java の技術です。JCA 1.5 仕様では、インバウンド通信モデルとして定義されていて、そのことによって EIS は EJB アプリケーションに対してすべての通信を始めることができます。このメカニズムではインバウンド・リソース・アダプターがエンタープライズ Java Bean を呼び出すことになります。
概略
この文章では EJB アプリケーションをデプロイして、JCA アダプターからインバウンド・イベントを受け取ることができるようにする方法を説明します。最初に、スタンドアロンのリソース・アダプターをデプロイする Geronimo 固有のプラン記述だけではなく、インバウンド通信モデルに付随するリソース・アダプターの重要な部分を説明します。その後、EIS によって実行されるエンタープライズ・アプリケーションのインバウンド通信メカニズムを説明します。
リソース・アダプター
このセクションで説明するコードは、デプロイされるリソース・アダプターの一部分です。多くの部分は Geronimo 固有ではありませんが、このセクションの最後では Geronimo コンテナーへリソース・アダプターをデプロイする方法を示します。
JCA 1.5 仕様では、インバウンド・アダプターはカスタマイズされたメッセージ・フォーマットのサポートが可能です。したがって、メッセージ駆動 Bean (MDB) がインバウンド・リソース・アダプターによって定義されたどんなインターフェースでも実装できます。以前の JCA 仕様では、Java メッセージ・サービス (JMS) のメッセージに javax.jms.MessageListener インターフェースを実装した MDB を必要とするようなインバウンド通信のメカニズムでした。JCA 1.5 では、どのようなインターフェースの定義でも MDB としてインバウンド・リクエストを扱えるようになりました。
インターフェースの定義
この例では、com.sample.connector.EventListener インターフェースが定義されています。このインターフェースはどのような MDB にも実装でき、この MDB はインバウンド・リソース・アダプターによって呼び出されるようになります。
package com.sample.connector; import java.util.List; import javax.resource.ResourceException; /** * An interface allowing Events to be Handled. Message-driven Beans implement * this interface, in order to receive inbound-events from our EIS via the JCA adapter. */ public interface EventListener { /** * Method to be called when a Event is handled. * * @param eventName the name of the event * @param paramList the parameters sent to the event * * @throws ResourceException if an error occurs */ void handleEvent(String eventName, List paramList) throws ResourceException; }
ActivationSpec の実装
インバウンド・リソース・アダプターは javax.resource.spi.ActivationSpec インターフェースを実装しています。インターフェース自身にはメソッドはありませんが、このインターフェースを実装するクラスは、
- JavaBean でなければなりません。getter と setter メソッドを bean のフィールドに用意してください。
- シリアライズ可能でなければなりません。
API ドキュメントによれば、「ActivationSpec 実装は、メッセージのエンド・ポイントに関する情報をアクティベーションの構成情報として持つことになります」。今回の場合では、メッセージのエンド・ポイントは今回のエンタープライズ・アプリケーション内にある MDB です。今回の ActivationSpec を実装したクラスは com.sample.connector.EventActivationSpec です。今回の例での ActivationSpec は通信を開始するために必要なすべてのデータを持っているので、リモートの EIS システム用にアプリケーション・コンテナーに読み込むことができます(マシン名、通信ポート、ユーザー名、ユーザーのパスワード、イベント・パターン)。
/* * EventActivationSpec.java */ package com.sample.connector; import java.io.Serializable; import javax.resource.spi.ActivationSpec; import javax.resource.spi.InvalidPropertyException; import javax.resource.spi.ResourceAdapter; /** * Implementation of the <code>ActivationSpec</code> interface, which allows EIS Events * to be exposed to message-drive beans. This <code>ActivationSpec</code> is used to * support inbound connection from our EIS to a message-driven bean. This will open * an EIS connection and use its event mechanism provided by the EIS-specific connection * class. The connection to the EIS will be held open while the application containing * the message-driven bean is available. */ public class EventActivationSpec implements ActivationSpec, Serializable { private ResourceAdapter resourceAdapter; private String serverName; private Integer portNumber; private String userName; private String password; private String eventPatterns;//A comma-delimeted string of patterns /** * Creates a new instance of the EventActivationSpec class. */ public EventActivationSpec() { } /** * No validation is performed */ public void validate() throws InvalidPropertyException { } //javadoc inherited public ResourceAdapter getResourceAdapter() { return resourceAdapter; } //javadoc inherited public void setResourceAdapter(ResourceAdapter resourceAdapter) { this.resourceAdapter = resourceAdapter; } /** * Getter method for the ServerName attribute. This allows the server name * to be defined against a Connection pool * * @return a <code>String</code> containing the server name value */ public String getServerName() { return serverName; } /** * Setter method for the ServerName attribute. This allows the server name to be * defined against a connection pool/. * * @param serverName the <code>String</code> that will be defined against this attribute */ public void setServerName(String serverName) { this.serverName = serverName; } /** * Getter method for the PortNumber attribute. This allows the port number * to be defined against a Connection pool * * @return a <code>Integer</code> containing the server port value */ public Integer getPortNumber() { return portNumber; } /** * Setter method for the PortNumber attribute. This allows the server port to be * defined against a connection pool/. * * @param portNumber the <code>Integer</code> that will be defined against this attribute */ public void setPortNumber(Integer portNumber) { this.portNumber = portNumber; } /** * Getter method for the UserName attribute. This allows the user name * to be defined against a Connection pool * * @return a <code>String</code> containing the user name value */ public String getUserName() { return userName; } /** * Setter method for the UserName attribute. This allows the user name to be * defined against a connection pool/. * * @param userName the <code>String</code> that will be defined against this attribute */ public void setUserName(String userName) { this.userName = userName; } /** * Getter method for the Password attribute. This allows the password * to be defined against a Connection pool * * @return a <code>String</code> containing the password value */ public String getPassword() { return password; } /** * Setter method for the Password attribute. This allows the password to be * defined against a connection pool/. * * @param password the <code>String</code> that will be defined against this attribute */ public void setPassword(String password) { this.password = password; } /** * Returns the event patterns that will be used when subscribing to Events. This string can contain * comma-delimited value, in order to subscribe to multiple Events. * * @return a <code>String</code> containing the event patterns that will be subscribed */ public String getEventPatterns() { return eventPatterns; } /** * Defines the event patterns that will be subscribed to by the message-driven beans. The value can * contain comma-delimited patterns, such that multiple events can be subscribed to in the single bean. * * @param eventPatterns a <code>String</code> containing the single pattern or comma-delimited patterns */ public void setEventPatterns(String eventPatterns) { this.eventPatterns = eventPatterns; } }
一般的なデプロイメント記述
JCA デプロイメント記述 (ra.xml) には、アダプターを ActivationSpec を実装したインターフェースに結びつけるためのセクションがあります。これが必要なのは、アダプターによって呼び出される MDB に定義されたプロパティをアプリケーション・コンテナーに伝えるためです。
<?xml version="1.0" encoding="UTF-8"?> <connector xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd" version="1.5"> <display-name>EIS Connector</display-name> <vendor-name>My Component</vendor-name> <eis-type>My Remote Server</eis-type> <resourceadapter-version>1.0</resourceadapter-version> <resourceadapter> <resourceadapter-class>com.sample.connector.MyResourceAdapter</resourceadapter-class> <!-- snip --> <inbound-resourceadapter> <messageadapter> <messagelistener> <messagelistener-type>com.sample.connector.EventListener</messagelistener-type> <activationspec> <activationspec-class>com.sample.connector.EventActivationSpec</activationspec-class> <required-config-property> <config-property-name>ServerName</config-property-name> </required-config-property> <required-config-property> <config-property-name>PortNumber</config-property-name> </required-config-property> <required-config-property> <config-property-name>UserName</config-property-name> </required-config-property> <required-config-property> <config-property-name>Password</config-property-name> </required-config-property> <required-config-property> <config-property-name>EventPatterns</config-property-name> </required-config-property> </activationspec> </messagelistener> </inbound-resourceadapter> <security-permission> <description>Permissions allowed to the EIS Connector</description> <security-permission-spec/> </security-permission> </resourceadapter> </connector>
ActivationSpec が実装されると、リソース・アダプターの endpointActivation メソッドが更新されます。MDB が環境にデプロイされた際に、アプリケーション・コンテナーはこのメソッドをリソース・アダプター上で呼び出します。このことによって、インバウンド・アダプターは通信を開始することができるようになります。このメソッドのシグネチャーは次のとおりです。
public void endpointActivation(MessageEndpointFactory endpointFactory, ActivationSpec spec) throws ResourceException
endpointFactory によって MDB の新しいインスタンスを作成できるようになり、spec は必要なすべてのプロパティを含んでいる ActivationSpec の実装になります。このメソッドを実装することで、 EIS を利用するメカニズムによるメッセージのサポートが可能になります。通常、リソース・アダプターは javax.resource.spi.work.Work インターフェースの実装が定義されていて、新しいスレッドを作ることなくインバウンド・リクエストを処理するようになります。
同じように重要なことは endpointDeactivation メソッドの実装です。エンド・ポイントが活性化された時に作成されたすべてのリソースを、アダプターから開放することができるようになります。
Geronimo のデプロイメント記述
最後に、Geronimo 固有の仕様の詳細です。Geronimo デプロイメント記述はインバウンド・リソース・アダプターの仕様が定義されているセクションです。
<?xml version="1.0" encoding="UTF-8"?> <connector xmlns="http://geronimo.apache.org/xml/ns/j2ee/connector-1.2"> <dep:environment xmlns:dep="http://geronimo.apache.org/xml/ns/deployment-1.2"> <dep:moduleId> <dep:groupId>com.sample</dep:groupId> <dep:artifactId>myConnector</dep:artifactId> <dep:version>1.0</dep:version> <dep:type>rar</dep:type> </dep:moduleId> <dep:dependencies/> <dep:hidden-classes/> <dep:non-overridable-classes/> </dep:environment> <resourceadapter> <resourceadapter-instance> <resourceadapter-name>MyInboundEvents</resourceadapter-name> <workmanager> <gbean-link>DefaultWorkManager</gbean-link> </workmanager> </resourceadapter-instance> </resourceadapter> </connector>
上記デプロイメント・プランによってアダプターの RAR ファイルをデプロイすると、MyInboundEvents という名前のインバウンド・アダプターがひとつ作られます。
EJB アプリケーション
ここまで、Geronimo サーバーのインスタンスにリソース・アダプターを定義し、デプロイしてきました。では、リモートの EIS からメッセージを受信した時にインバウンド・リソース・アダプターによって呼び出されるメッセージ駆動 Bean を持っている EJB アプリケーションを作成し、デプロイします。
この例では、メッセージ駆動 Bean はリソース・アダプターで定義された EventListener インターフェースを実装しています。
package com.sample.eventDemo.message; import com.sample.connector.EventListener; import java.util.List; import javax.ejb.ActivationConfigProperty; import javax.ejb.MessageDriven; import javax.resource.ResourceException; /** * Message-driven Bean, listening for Events */ @MessageDriven( name="EventBean", messageListenerInterface=EventListener.class, activationConfig={ @ActivationConfigProperty(propertyName="ServerName",propertyValue="fozzie"), @ActivationConfigProperty(propertyName="PortNumber",propertyValue="40100"), @ActivationConfigProperty(propertyName="UserName",propertyValue="user"), @ActivationConfigProperty(propertyName="Password",propertyValue="pwd"), @ActivationConfigProperty(propertyName="EventPatterns",propertyValue="myPattern") } ) public class EventBean implements EventListener { /** * Method that will be called by the inbound Event handler */ public void handleEvent(String eventName, List paramList) throws ResourceException { System.out.println("In MDB: " + eventName + " with params " + paramList.toString()); } }
この bean は多くのことをするわけではないのが実行されることは見せられます。ActivationConfigProperty アノテーションを利用してインバウンド・リソース・アダプターに必要とされるプロパティを定義します。これらの値は対応する ActivateSpec(今回では EventActivationSpec)向けに定義され、リソースアダプターの endpointActivation メソッドへ渡します。
Geronimo のデプロイメント記述
最後に、MDB と、リソース・アダプターを Geronimo コネクターにデプロイした時に定義したインバウンド・リソース・アダプターの MyInboundEvents とを結びつけます。これは EJB の Geronimo デプロイメント記述である openejb-jar.xml によって行います。
<?xml version="1.0" encoding="UTF-8"?> <openejb-jar xmlns="http://www.openejb.org/xml/ns/openejb-jar-2.1" xmlns:naming="http://geronimo.apache.org/xml/ns/naming-1.1" xmlns:security="http://geronimo.apache.org/xml/ns/security-1.1" xmlns:sys="http://geronimo.apache.org/xml/ns/deployment-1.2"> <sys:environment> <sys:moduleId> <sys:groupId>com.sample.connectorDemo</sys:groupId> <sys:artifactId>SampleEventHandler</sys:artifactId> <sys:version>1.1</sys:version> <sys:type>car</sys:type> </sys:moduleId> <sys:dependencies> <sys:dependency> <sys:groupId>com.sample</sys:groupId> <sys:artifactId>myConnector</sys:artifactId> <sys:version>1.0</sys:version> <sys:type>rar</sys:type> </sys:dependency> </sys:dependencies> <sys:hidden-classes/> <sys:non-overridable-classes/> </sys:environment> <enterprise-beans> <message-driven> <ejb-name>EventBean</ejb-name> <resource-adapter> <resource-link>MyInboundEvents</resource-link> </resource-adapter> </message-driven> </enterprise-beans> </openejb-jar>
このファイルでは、EventBean と MyInboundEvents アダプターとを結びつけています。