我之前写过一个 JCA 开发入门的文章,是一个 Outbound Resource Adapter 的开发。文章放在蓝点上了, 大家可以参考下。这次我想分析一个现有的 Inbound Resource Adapter 的实现。有关 Inbound 的架构, 请参考文章 JCA Oerview。
本次要分析的 Inbound Resouce Adapter 的目的是定期检查某个邮件服务器里某个目录下的邮件, 如果有新邮件就会通知相应的 MessageEndPoint。 该 RA 由 IronJacamar team 开发, 现在 trunk 下不再维护, 目前只存在 IronJacamar code branch 1.0 下。 我把该 rar 的代码完全移到了 github 下, 加上了 Maven 的支持。
https://github.com/gaol/mail-ra.git
我们先看下这个 RA 的 metadata:
<resourceadapter> <resourceadapter-class>org.jboss.jca.adapters.mail.MailResourceAdapter</resourceadapter-class> <config-property> <config-property-name>QueueSize</config-property-name> <config-property-type>java.lang.Integer</config-property-type> <config-property-value>1024</config-property-value> </config-property> <inbound-resourceadapter> <messageadapter> <messagelistener> <messagelistener-type>org.jboss.jca.adapters.mail.inflow.MailListener</messagelistener-type> <activationspec> <activationspec-class>org.jboss.jca.adapters.mail.inflow.MailActivationSpec</activationspec-class> <required-config-property> <config-property-name>mailServer</config-property-name> </required-config-property> <required-config-property> <config-property-name>mailFolder</config-property-name> </required-config-property> <required-config-property> <config-property-name>storeProtocol</config-property-name> </required-config-property> </activationspec> </messagelistener> </messageadapter> </inbound-resourceadapter> </resourceadapter>
这里定义了 resourceadapter-class 为: org.jboss.jca.adapters.mail.MailResourceAdapter, 它实现了
javax.resource.spi.ResourceAdapter 接口。 该接口定义了 RA 的生命周期方法和 MessageEndpoint 的 active 和
deactive 方法。除此以外,它还是个 Java Bean。
注意,在 Inbound Resource Adapter 里, resourceadapter-class 是必须有的, 而在 Outbound Resource Adapter 里,resourceadapter-class 可以没有, 原因是为了和 JCA 1.0 兼容, 因为在 JCA 1.0 里, 没有 Inbound 的概念。
还定义了 messagelistener-type 为: org.jboss.jca.adapters.mail.inflow.MailListener。这个是 MessageEndPoint 需要实现的接口。 当 RA 满足一定条件的时候, 调用 MailListener 里的方法。
另外还定义了 activationspec-class 为: org.jboss.jca.adapters.mail.inflow.MailActivationSpec, 这个是一个
JavaBean, 定义了 EIS 相关的配置信息。这些配置信息对应着 MDB 里的 activation-config-property. 从该配置文件可以看到: mailServer, mailFolder, storeProtocol 是必须配置的。
我们接下来写一个 MDB 来接收该 RA 的调用, 通过演示来摸清 Inbound RA 的调用流程:
package org.jboss.test.mdb; import javax.ejb.ActivationConfigProperty; import javax.ejb.MessageDriven; import javax.mail.Message; import javax.mail.MessagingException; import org.jboss.jca.adapters.mail.inflow.MailListener; @MessageDriven( name = "MailBean", messageListenerInterface = MailListener.class, activationConfig = { @ActivationConfigProperty(propertyName="mailServer", propertyValue = "pop.163.com"), @ActivationConfigProperty(propertyName="mailFolder", propertyValue = "INBOX"), @ActivationConfigProperty(propertyName="storeProtocol", propertyValue = "pop3"), @ActivationConfigProperty(propertyName="debug", propertyValue = "true"), @ActivationConfigProperty(propertyName="port", propertyValue = "110"), @ActivationConfigProperty(propertyName="userName", propertyValue = "XXXXXX"), @ActivationConfigProperty(propertyName="password", propertyValue = "XXXXXX") } ) @org.jboss.ejb3.annotation.ResourceAdapter(value = "mail-ra.rar") public class MailBean implements MailListener { public MailBean(){;} public void onMessage(Message msg) { StringBuilder sb = new StringBuilder(); try { String subject = msg.getSubject(); sb.append("Subject is: \n" + subject + "\n"); } catch (MessagingException e) { e.printStackTrace(); } System.out.println(sb.toString()); } }
其中, @ResourceAdapter(value = "mail-ra.rar") 用来指定该 MDB 与哪个 RA 相匹配。 这个 annotation 是由 jboss-ejb3 组件提供, 如果是部署到其他 App Server 下, 请参考其他 Server 的文档。 如果不使用 annotation, 那么需要在 MDB 这个 jar 里加入 jboss.xml 文件, 并配置 resource adapter 。
JBoss AS 7 使用 OSGI 的概念, 我们已经部署过 mail-ra.rar, MailListener 已经加载过, 那么我们这个 MDB 只需要是个简单的 jar 就可以了, 我们只需要在 MDB 的 jar 的的 META-INF/MANIFEST.MF 里加入:
Dependencies: deployment.mail-ra.rar
即可。 大家一定要注意 MANIFEST.MF 的格式, 最好能测试一下, 确定该条目已经起作用了(java.util.Manifest)。
注意, 目前只有 MDB 才能接收 Inbound Resource Adapter 调用。 因为每个 App Server 都支持 JMS, 每个 App Server 下都已经有了默认的 JMS 的一个 RA。因此, 如果你的 MDB 是基于 JMS 的, 就不需要再编写 RA 了。
首先我们 build mail-ra.rar 文件,
mvn package
之后部署 mail-ra.rar 到 JBoss AS 7,
bin/jboss-cli.sh --connect [localhost /] deploy ~/jca/mail-ra.rar
部署的时候 App Server 会调用 MailResourceAdapter 的 start 方法, 该方法会启动一个 NewMsgsWorker,
该 work 运行在 App Server 的线程下,并维持一个 Queue, 在 MailResourceAdapter.stop() 方法被调用之前, 该 work 会一直循环。 之后我们部署 MDB,
[localhost /] deploy ~/jca/maibean.jar
MDB 被部署的时候, App Server 会调用 MailResourceAdapter.endpointActivation(MessageEndpointFactory, ActivationSpec) 方法, 参数 MessageEndpointFactory 由 App Server 实现并创建, ActivationSpec 也是由 App Server 创建, 这里创建的 ActivationSpec 会包含 MDB 里定义的配置信息。 这个方法会创建一个 MailActivation 实例,并把它加入到 NewMsgsWorker 的 Queue 里, MailActivation 也是一个 Work, 该 Work 会调用 Java Mail 相关方法遍历邮件服务器某个目录下的邮件, 并调用 MailListener.onMessage(Message message) 方法。
FYI: Source of Mail-rar: https://github.com/gaol/mail-ra