https://blogs.oracle.com/WebLogicServer/entry/new_ejb_3_2_feature
WebLogic Server 12.2.1は、Java EE7仕様に完全に互換性をもつ実装です。このリリースのWebLogic ServerにおけるEJBコンテナでの大きな改善点の一つに、MDB(メッセージ駆動型Bean)がメソッド無しでリスナーインターフェースを実装できる点があります。このようなno-methodリスナーインタフェースを使用する場合、すべてのstaticではないBeanクラス(およびjava.lang.Object以外のBeanクラスのスーパークラス)のパブリックメソッドは、メッセージ・リスナー・メソッドとして公開されます。
それでは、ステップバイステップでサンプルを開発してみましょう。e-Commerceのwebサイトは、製品が売買されると、その売買イベントをJMS Queue、buyQueueとsellQueueそれぞれに送信するものとします。コネクタは、キューをリスニングし、MDBの非静的パブリック・メソッドを実行して、永続ストアにイベントのレコードを書き込みます。
1. Define a no-methods message listener interface
今回のサンプルでは、メッセージ・リスナー・インターフェースのNoMethodsListenerIntfにはメソッドがありません。List 1 - No-methods message listener interface
public NoMethodsListenerIntf { }
2. Now define the bean class
MDBのクラスには、productBoughtとproductSoldという、二つの非静的パブリックメソッドがあります。そのため、両方ともメッセージリスナーメソッドとして公開されています。コネクタがsellQueueから製品販売イベントを取得すると、MDBのproductSoldを呼び出します。製品購入イベントでも同様です。コネクタが実行すべきターゲット・メソッドであることを示すよう、productSoldメソッドとproductBoughtメソッドに対して@EventMonitorで注釈を付けます。これらの2つのメソッドは、データベースまたは他の永続ストアにレコードを永続化します。ほかにも非静的パブリック・メソッドを定義することができますが、どれををコネクタが実行するのかはコネクタ次第です。
List 2 - Message-Driven BeanEventMonitor注釈を以下のように設定します。
@MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "resourceAdapterJndiName", propertyValue = "eis/TradeEventConnector") }) public class TradeEventProcessingMDB implements NoMethodsListenerIntf { @EventMonitor(type = "Retailer") public void productSold(long retailerUUID, long productId) { System.out.println("Retailer [" + retailerUUID + "], product [" + productId + "] has been sold!"); // persist to database } @EventMonitor(type = "Customer") public void productBought(long customerId, long productId) { System.out.println("Customer [" + customerId + "] has bought product [" + productId + "]!"); // persist to database } }
List 3 - EventMonitor annotationこのMDBをWebLogic Serverにデプロイする際、EJBコンテナはこのMDBがEJB 3.2互換のMDBであることを検知します。resourceAdapterJndiNameの値を指定し忘れていると、WebLogic Serverが適切なコネクタリソースを見つけようとします。例えば、(現在のアプリケーションスコープ、もしくはサーバ全体のグローバルスコープでアクセス可能なコネクタのうち)同じno-methodメッセージリスナーインターフェースのサポートを宣言しているコネクタを見つけようとします。
@Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface EventMonitor { public String type(); }
適切なコネクタが見つかり、MDBと紐付けられた場合、コネクタはBeanクラス定義を読み取り、分析することができます。
3. Developing a connector that is used to associate with message-driven bean
コネクタアプリケーションでは、MessageEndpointFactoryのgetEndpointClass()メソッドを使ってBeanクラス定義を取得し、@EventMonitorで注釈が付いている場合にはすべてのメソッドを検査します。その後、javax.jms.MessageListenerをBeanクラスのターゲットメソッドを使って作成し、イベント・キューで待機します。List 4 - trade event connector関連づけられたコネクタのアクティベーション・スペックを以下のように定義します。
@Connector( description = "This is a sample resource adapter", eisType = "Trade Event Connector", vendorName = "Oracle WLS", version = "1.0") public class TradeEventConnector implements ResourceAdapter, Serializable { // jms related resources ...... private static final String CALLBACK_METHOD_TYPE_RETAILER = "Retailer"; private static final String CALLBACK_METHOD_TYPE_CUSTOMER = "Customer"; @Override public void endpointActivation(MessageEndpointFactory mef, ActivationSpec activationSpec) throws ResourceException { try { Class<?> beanClass = mef.getEndpointClass(); // retrieve bean class definition ...... jmsContextForSellingEvent = ...; // create jms context jmsContextForBuyingEvent = ...; jmsConsumerForSellingEvent = jmsContextForSellingEvent.createConsumer(sellingEventQueue); jmsConsumerForBuyingEvent = jmsContextForBuyingEvent.createConsumer(buyingEventQueue); jmsConsumerForSellingEvent.setMessageListener(createTradeEventListener(mef, beanClass, CALLBACK_METHOD_TYPE_RETAILER)); jmsConsumerForBuyingEvent.setMessageListener(createTradeEventListener(mef, beanClass, CALLBACK_METHOD_TYPE_CUSTOMER)); jmsContextForSellingEvent.start(); jmsContextForBuyingEvent.start(); } catch (Exception e) { throw new ResourceException(e); } } private MessageListener createTradeEventListener(MessageEndpointFactory mef, Class<?> beanClass, String callbackType) { for (Method m : beanClass.getMethods()) { if (m.isAnnotationPresent(EventMonitor.class)) { EventMonitor eventMonitorAnno = m.getAnnotation(EventMonitor.class); if (callbackType.equals(eventMonitorAnno.type())) { return new JmsMessageEventListener(mef, m); } } } return null; } @Override public void endpointDeactivation(MessageEndpointFactory mef, ActivationSpec spec) { // deactivate connector } ...... }
List 5 - the activation spec
@Activation( messageListeners = {NoMethodsListenerIntf.class} ) public class TradeEventSpec implements ActivationSpec, Serializable { ...... }
4. Developing a message listener to listen on the event queue.
メッセージリスナのonMessage()が呼び出されると、MessageEndpointFactoryを使ってメッセージエンドポイントを作成し、このメッセージエンドポイントのターゲットメソッドを呼び出します。List 6 - jms message listener
public class JmsMessageEventListener implements MessageListener { private MessageEndpointFactory endpointFactory; private Method targetMethod; public JmsMessageEventListener(MessageEndpointFactory mef, Method executeTargetMethod) { this.endpointFactory = mef; this.targetMethod = executeTargetMethod; } @Override public void onMessage(Message message) { MessageEndpoint endpoint = null; String msgText = null; try { if (message instanceof TextMessage) { msgText = ((TextMessage) message).getText(); } else { msgText = message.toString(); } long uid = Long.parseLong(msgText.substring(0, msgText.indexOf(","))); long pid = Long.parseLong(msgText.substring(msgText.indexOf(",") + 1)); endpoint = endpointFactory.createEndpoint(null); endpoint.beforeDelivery(targetMethod); targetMethod.invoke(endpoint, new Object[]{uid, pid}); endpoint.afterDelivery(); } catch (Exception e) { // log exception System.err.println("Error when processing message: " + e.getMessage()); } finally { if (endpoint != null) { endpoint.release(); } } } }
5. Verify the application
イベントの構文は、カンマで区切られた2個の数字、例えば328365,87265で構成されているものとします。前者の数字は、顧客や小売店のIDで、後者の数字は、製品IDです。そのようなイベントをイベントキューに送信すると、MDBがそのイベントを永続化することがわかるでしょう。We assume that the syntax of the event is composed
0 件のコメント:
コメントを投稿