使用JCA inbound实现信息流入集成
来源:岁月联盟
时间:2010-08-30
2 JCA资源适配器的作用
JCA资源适配器部署在J2EE容器中,起类似于JDBC驱动的作用,一般是应用系统提供商或者第三方开发商提供的。JCA资源适配器是有特定功能的,比如针对Corba服务器或者SAP应用系统,打包成资源适配器存档文件(RAR),包括J2EE相应的jar文件以及基础类库 (如本地运行库)。 JCA资源适配器通过系统契约和J2EE容器进行交互,这些契约是一系列Java接口定义。J2EE容器和应用程序通过调用这些接口,来传播被调用的上下文信息。其中连接管理契约描述了J2EE容器在使用资源适配器的过程中,是如何建立连接、维持连接池、执行调用以及释放这些连接的。连接管理契约还可以对连接监听,对发生的事件进行响应,比如当连接丢失或者发生错误时,容器执行回调操作。JCA定义了CCI接口集,类似于使用JDBC来访问数据库,通过CCI,J2EE应用程序可以用统一的接口来访问不同的外部应用系统。当然,JCA资源适配器并不需要一定支持CCI层,资源适配器可以使用自己的API接口。3 用Inbound方式集成邮件应用
在实际集成项目中,J2EE应用程序同外部系统的交互往往是多种形式的,可能是同步的调用,也可能是异步的消息传递。JCA 1.0的规范没有定义信息输入的方式,JCA适配器只能进行Outbound单向调用,从而限制了JCA技术在EAI项目中的应用范围。JCA 1.5规范引入Inbound binding解决了这个问题。JCA采用MDB接受异步消息,同时J2EE引入了工作管理(Work)的概念,使得J2EE容器可以管理和调度工作队列,让资源适配器可以为延迟或定期执行的工作创建计时器,并允许它使用应用程序服务器的线程资源执行处理。这些特性使得J2EE架构更加灵活、有效的解决开发应用中的各种问题。 系统开发中常常会遇到需要异步输入的问题,在J2EE开发中,一般用两种方法解决,一种是使用JMS或者MDB,这样就要求外部系统也得使用JMS来发送消息,从而限制了外部系统必须是Java程序,并且必须是一直运行的。第二是容器采用定时器(Timer)定时访问外部系统。这种方式应用在JCA适配器上,用MDB来接受外部消息,就是JCA Inbound的思路。我们通过Jboss,开源应用服务器中自带的邮件资源适配器mail-ra.rar来举例说明[3],以下是inbound的JCA部署描述符:| <connector><description>JBoss JavaMail Resource Adapter</description><display-name>JavaMail Adapter</display-name> <vendor-name>JBoss, Inc</vendor-name> <eis-type>JavaMail Adapter</eis-type> <resourceadapter-version>1.0</resourceadapter-version> <resourceadapter> <resourceadapter-class>org.jboss.resource.adapter.mail.MailResourceAdapter</resourceadapter-class> <inbound-resourceadapter> <messageadapter> <messageer> <messagelistener-type>org.jboss.resource.adapter.mail.inflow.MailListener</messagelistener-type> <activationspec> <activationspec-class>org.jboss.resource.adapter.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></connector> |
这个资源适配器实现了定时查询邮件的功能,当有新邮件到来时,会有消息传递到J2EE容器中。其源码可以在Jboss源码包中connector/src/main/org/jboss/resource/adapter/mail找到。
资源适配器核心接口是MailListener,这个接口中定义了类似于MDB的onMessage方法,接受异步消息通知。MailResourceAdapter类通实现了ResourceAdapter接口,是J2EE容器和资源适配器的桥梁。MailActivationSpec类是参数集合,可以对资源适配器进行配置,描述文件说明有三个参数必须定义,分别是邮件服务器名称,邮件夹和访问协议。在mail-ra.rar资源适配器中,还有NewMsgsWorker类实现了Work, WorkListener接口,是实际工作的管理着,负责调度MailActivation类。MailActivation和MailFolder一起工作,完成对邮件服务器的访问。 MailResourceAdapter中包括四个接口方法start,stop,endpointActivation,endpointDeactivation,分别在状态改变时被容器回调,进入开始,结束,激活,暂停四个状态。在开始和激活方法中创建工作类:| public void start(BootstrapContext ctx) throws ResourceAdapterInternalException {…//获得WorkManagerWorkManager mgr = ctx.getWorkManager(); //创建NewMsgsWorkernewMsgsWorker = new NewMsgsWorker(mgr); try { //进入调度队列mgr.scheduleWork(newMsgsWorker); } catch … }public void endpointActivation(MessageEndpointFactory endpointFactory, ActivationSpec spec) throws ResourceException { //获得参数集MailActivationSpec mailSpec = (MailActivationSpec) spec; //创建MailActivationMailActivation activation = new MailActivation(this, endpointFactory, mailSpec); try { //对MailActivation监控管理newMsgsWorker.watch(activation); } catch … activations.put(spec, activation); //加入到Hashmap中 } |
NewMsgsWorker类中,run方法被WorkManager调度执行
| public void run() {while( released == false ) { try {//查看队列MailActivation ma = (MailActivation) pollQueue.take(); if( ma.isReleased() ) continue; long now = System.currentTimeMillis(); long nextTime = ma.getNextNewMsgCheckTime(); long sleepMS = nextTime - now; Thread.sleep(sleepMS); //间隔一段时间再去检查新邮件 if( released ) break; mgr.scheduleWork(ma, WorkManager.INDEFINITE, null, this); //进入调度队列 } catch …} //pollQueue队列中的Work是watch方法中加入的。public void watch(MailActivation activation) throws InterruptedException { long now = System.currentTimeMillis(); activation.updateNextNewMsgCheckTime(now); pollQueue.put(activation);} |
在MailActivation类中,run方法执行检查邮件的动作:
| public void run() {released = false;try {//MailFold为JavaMail的类,进行设置MailFolder mailFolder = new MailFolder(spec); mailFolder.open(); //检查邮件//获得新邮件数目Message[] msgs = mailFolder.getNewMessages(); for(int n = 0; released == false && n < msgs.length; n ++) { Message msg = msgs[n]; deliverMsg(msg); //逐个访问,这个方法中调用onMessage方法,可以重载自己的实现 } mailFolder.close(); }catch …} |
| public void onMessage(Message msg){ System.out.println(msg);}public void ejbCreate() {}public void ejbRemove() {} |
| <ejb-jar><enterprise-beans><message-driven><ejb-name>EchoMailMDB</ejb-name> <ejb-class>org.jboss.example.EchoMailMessageListener</ejb-class><messaging-type>org.jboss.resource.adapter.mail.inflow.MailListener</messaging-type> <activation-config> <activation-config-property> <activation-config-property-name>mailServer</activation-config-property-name> <activation-config-property-value>pop3.sohu.com</activation-config-property-value> </activation-config-property> <activation-config-property> <activation-config-property-name>mailFolder</activation-config-property-name> <activation-config-property-value>INBOX</activation-config-property-value> </activation-config-property> <activation-config-property> <activation-config-property-name>storeProtocol</activation-config-property-name> <activation-config-property-value>pop3</activation-config-property-value> </activation-config-property> <activation-config-property> <activation-config-property-name>username</activation-config-property-name> <activation-config-property-value>username</activation-config-property-value> </activation-config-property> <activation-config-property> <activation-config-property-name>password</activation-config-property-name> <activation-config-property-value>password</activation-config-property-value> </activation-config-property> </activation-config> <transaction-type>Container</transaction-type> </message-driven> </enterprise-beans>…</ejb-jar> |
打包这个MDB,并部署到Jboss中,成功后可以看到资源适配器部署成功的信息。默认的检查时间间隔是60秒,J2EE容器会检查sohu邮件服务器上的该帐户邮件,发现有新邮件就会在Jboss的控制台窗口中打印出来。如果或者用户名密码出错的话,则会给出错误:ERROR[MailActivation] Failed to execute folder check, spec=MailActivationSpec(mailServer=pop3.sohu.com, storeProtocol=pop3, mailFolder=INBOX, pollingInterval=60000, messageSelector=null, userName=username, maxMessages=1),提醒进行进一步检查修改。我们可以使用网络监视工具看到Pop3网络交互协议文本。
4
在实际的项目中,可以加入更多的功能,比如把邮件显示在门户页面上。或者在出差时,发送特定格式的邮件,由J2EE应用程序来分析内容,完成系统管理等等功能。另外,我们还可以用Inbound的方式实现文件资源适配器,对文件系统目录进行监视,如果有新的文件就进行处理,这个功能在EAI项目中很有用处。实现能够MSN,Jabber协议的即时消息资源适配器,可以利用MSN Messager,Gtalk等即时消息软件向J2EE应用服务器程序发送消息,利用这个功能可以完成的P2P协议的集成。: Sun Microsystems. J2EE Connector Architecture Specification V1.5, 2003 David Currie, “JCA 1.5, Part 3: Message inflow”, IBM UK Ltd, , 2005 Jboss JCA wiki, Jboss organization,上一篇:基于多级指引索引的高效技术