许多Web2.0应用程序都需要一种机制来在彼此之间传递和交换消息。在大部分开发环境中,程序员一般都会选择消息队列(Message Queue,MQ)来作为消息交互的底层技术支持。
EGL是EnterpriseGeneration Language(企业生成语言)的英文缩写,这是一种面向业务的第四代语言。利用EGL可以快速开发和部署Java、COBOL以及Web2.0应用程序。EGL的集成开发环境有IBM Rational Business Developer(RBD)和Eclipse EGL Development Tools(EDT)。读者可以通过访问http://www-01.ibm.com/software/awdtools/developer/business/index.html来了解和下载RBD的试用版。
在这篇文章中,我们会介绍一种新的可用于EGL语言中的消息传递机制,它使用WebShpere MQ Bridge for HTTP作为传输介质,通过HTTP协议来传递消息。
1. WebShpere MQ Bridge for HTTP的介绍
WebShpere MQ Bridge for HTTP使得客户端应用程序可以互相交换消息,这些客户端程序可以是基于不同的平台或语言,只需要通过HTTP协议,而对WebSphereMQ的客户端不作要求。
图1WebShpere MQ Bridge for HTTP的架构
如图1所示,WebSphereMQ Bridge for由一个J2EE Servlet组成,它通过一个资源适配器来连接到WebSphere MQ。该J2EE Servlet具备处理三种不同类型的HTTP请求的能力:POST、GET和DELETE。
读者如果想获取更多关于WebSphereMQ Bridge for HTTP的资料,可以访问http://www-01.ibm.com/software/integration/wmq/httpbridge/。
2. 联合EGL和WebShpereMQ Bridge for HTTP
图2所示的框架描述的是我们提出的一种解决方案,它允许EGL语言通过HTTP协议来访问和交换外部消息,以及在Web2.0应用程序内部通过EGL的消息总线(InfoBus)来传递内部消息。
图2EGL消息传递的解决方案
在该解决方案的例子中,我们定义了两个消息实体:事件(Event)和聊天(Chat)。事件是指在HTTP客户端中发生的实时事件,而聊天则指用户在分布式环境中互相交谈的机制。在该解决方案中,它们的工作机制是一样的,我们假设这样一种应用场景:
Web2.0应用程序的用户“Tom”在他的主页上发布了一条状态:Hello EGL,然后EGL的Rich UI Handler将该消息发布到消息总线上。在消息总线上,我们已经订阅了和发布一致的主题,并且具有一个回调函数用于处理接受到的消息。当消息到达消息总线时,回调函数开始被调用,然后EventScanner将通过HTTP协议该消息投递到WebShpere MQ Bridge for HTTP。而WebShpere MQ Bridge for HTTP紧接着将该消息传递到相应的消息队列。
另一个Web2.0用户“Paul”已经登陆了他的主页。EventScanner每隔一秒种将通过HTTP协议,用“拉”的模式来获取消息。当Tom发布的消息“HelloEGL”到达时,就会被投递到消息总线上,然后EGL Rich UI Handler就会将该消息展示在Paul的主页上。
1. 设置WebShpere MQ Bridge for HTTP环境
首先在WebSphereApplication Server中创建一个带有WebSphere MQ messaging provider的连接工厂(Connection Factory)。想获取更多关于如何安装和配置WebShpere MQ Bridge for HTTP,读者可以访问http://www-01.ibm.com/support/docview.wss?rs=171&uid=swg24016142&loc=en_US&cs=utf-8?=en&wv=1来下载最新的安装指南和安装包。
在部署完WebShpereMQ Bridge for HTTP以后,启动WebSphere MQ Explorer,打开“MQ Explorer-Navigator”视图,创建一个队列管理器(QueueManager),命名为“HTTPQM”。如图3和图4所示。
保留其他参数为默认值,然后完成该向导,队列管理器“HTTPQM”就创建成功了。 最后,创建如图5和图6所示的本地队列(LocalQueue)。
图5创建本地消息队列a
图6创建本地消息队列b
2. 用EGL开发Web2.0应用程序
在这个章节中,我们用EGL语言和RBD集成开发环境来开发一个叫做“RBD Team Hub”的Web2.0应用程序,如图7所示。请注意在这篇文章中我们不会说明这个Web应用的所有组件,而是仅关心消息传递的模块,因为这个模块提供了重要的底层消息支持,其他的功能都是在这基础上开发的,这是我们描述的重点。
以下是消息传递组件的一些EGL代码片段:
library EventScannerLib type BasicLibrary{}
oldMessage string = "";
sendmessage string = "";
function scan()
Infobus.subscribe("com.ibm.egl.hub.event.send", callback);
new Job{runFunction = getMessage}.repeat(1000);
end
function callback(name string in, data any in)
sendmessage = data as string;
serv IRest{@RestBinding{}};
call serv.invokeDelete("http://localhost:9080/mq/msg/queue/EVENTDELETE",
sendmessage) returning to invokeDeleteCallback
onException handlerExcep;
end
function getMessage()
serv IRest{@RestBinding{}};
call serv.invokeGet("http://localhost:9080/mq/msg/queue/EVENTGET")
returning to invokeGetCallback onException handlerExcep;
end
function invokeGetCallback(message string in)
if(message != oldMessage)
Infobus.publish("com.ibm.egl.hub.event.recieve", message);
end
oldMessage = message;
end
function invokeDeleteCallback(message string in)
serv IRest{@RestBinding{}};
call serv.invokePost("http://localhost:9080/mq/msg/queue/EVENTPOST",
sendmessage) returning to invokePostCallback
onException handlerExcep;
end
function invokePostCallback(sendMesage string in)
// TODO
end
function handlerExcep(e AnyException in)
// TODO
end
end
library ChatScannerLib type BasicLibrary{}
oldMessage string = "";
function scan()
Infobus.subscribe("com.ibm.egl.hub.chat.send", callback);
new Job{runFunction = getMessage}.repeat(1000);
end
function callback(name string in, data any in)
sendmessage string = data as string;
destInternetId string = clip(sendMessage[21 : 40]);
atIndex int = strLib.indexOf(destInternetId, "@");
destQueue string = destInternetId[1 : atIndex - 1];
serv IRest{@RestBinding{}};
call serv.invokePost("http://localhost:9080/mq/msg/queue/" +
destQueue, sendmessage) returning to invokePostCallback
onException handlerExcep;
end
function getMessage()
myInternet string = RbdMemberScannerLib.myInternetId;
atIndex int = strLib.indexOf(myInternet, "@");
myQueue string = myInternet[1 : atIndex - 1];
msg string;
serv IRest{@RestBinding{}};
call serv.invokeDelete("http://localhost:9080/mq/msg/queue/" +
myQueue, msg) returning to invokeDeleteCallback
onException handlerExcep;
end
function invokeDeleteCallback(message string in)
if(message != oldMessage && message != "")
srcInternetId string = clip(message[1 : 20]);
destInternetId string = clip(message[21 : 40]);
rbdMember RbdMember = RbdMemberScannerLib.getRbdMemeberByInternet(srcInternetId);
if(rbdMember != null)
ChatDialogLib.setUserName(rbdMember.name);
ChatDialogLib.setPhoto(rbdMember.photo);
end
messageBody string = clip(message[41 : strLib.characterLen(message)]);
chatHistory string = rbdMember.chatHistory + rbdMember.internetid +
": " + messageBody + "
";
RbdMemberScannerLib.setChatHistory(destInternetId, chatHistory);
ChatDialogLib.setChatHistory(rbdMember.chatHistory);
ChatDialogLib.showChat();
end
end
function invokePostCallback(sendMesage string in)
// TODO
end
function handlerExcep(e AnyException in)
// TODO
end
end
和消息相关的消息总线主题如表1所示:
Topic |
Publisher |
Subscriber |
com.ibm.egl.hub.event.send |
UserDetail |
EventScannerLib |
com.ibm.egl.hub.event.recieve |
EventScannerLib |
WorkBench |
com.ibm.egl.hub.chat.send |
ChatDialogLib |
ChatScannerLib |
表1消息总线主题
样例
为了使该样例能够成功运行,我们建议读者下载该样例并运行。首先利用可视化编辑器(Visual Editor)来打开MainHandler.egl,或者将该应用程序项目部署到应用服务器上,然后在外部浏览器中运行。
需要说明一下在该样例中的用户名列表,读者可以任意选择其中的一个用户名登录应用程序,相应的密码都是“password”。如图8所示.
图8登录对话框
点击“Login”按钮,系统会通过dedicatedservice来校验用户名和密码,一旦授权通过,就会进入用户主页面。
在这个场景中,假设有两个用户在使用该应用程序:Tom和Paul。让我们来看一下事件(Event)和聊天(Chat)组件是如何工作的。
如图9所示,用户“Tom”发布了一条最新的状态“Hello EGL!”,然后我们在Paul的主页上的消息面板上看到了这条最新状态“Tom PublishedLatest Status:Hello EGL!”
用户“Tom”在好友列表中通过点击“Paul”的头像,发起聊天会话,这样两用户之间可以在弹出的对话框中进行即时交谈。图10所示的是Tom与Paul之间的聊天消息历史。
EGL支持许多和其他遗留系统之间通讯的方式,如数据库、消息队列、服务提供者,等等。用户可以使用SOAP/RESTful服务来消耗或提供Web服务,从而构建基于SOA的Web2.0应用。企业服务总线(EnterpriseService Bus,ESB)和消息队列(MessageQueue,MQ)都可以被快速集成到EGL应用程序中,甚至不用写一行代码。
简而言之,EGL具有灵活且高扩展性的机制,来允许用户在Web2.0应用程序中来定义自己的框架或解决方案。