- 浏览: 122021 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
ze_nana:
那楼主去哪个行业了?
怀念曾经的日子 -
誓言无声:
...
我的90后学生的一篇检查 -
lvwenwen:
不错,楼主要是能上传能跑的工程就更好了,楼主加油!
JMS(Java Massage Service)与MDB(Massage Driver Bean) -
lvff1314:
楼主的爬虫是自己用socket写的还是用的开源框架啊,可否跟大 ...
《说说做网站的事》我朋友写的关于自己开发一个网站的经验帖 -
MVC2008MVC:
感觉自己玩玩还行
《说说做网站的事》我朋友写的关于自己开发一个网站的经验帖
Jboss ESB简介及开发实例.
作者:岳乡成
一、Jboss ESB的简介
1、 什么是ESB。
ESB的全称是Enterprise Service Bus,即企业服务总线。ESB是过去消息中间件的发展,ESB采用了“总线”这样一种模式来管理和简化应用之间的集成拓扑结构,以广为接受的开放标准为基础来支持应用之间在消息、事件和服务的级别上动态的互连互通。
ESB是一种在松散耦合的服务和应用之间标准的集成方式。它可以作用于:
①面向服务的架构 - 分布式的应用由可重用的服务组成。
②面向消息的架构 - 应用之间通过ESB发送和接受消息。
③事件驱动的架构 - 应用之间异步地产生和接收消息。
用一句比较通俗的话来描述ESB:ESB就是在SOA架构中实现服务间智能化集成与管理的中介。
2、 ESB和SOA之间的关系。
介绍ESB就不得不提到SOA的概念,那么什么是SOA呐?
简单的说,SOA(service-oriented architecture)是面向服务的体系结构,是一类分布式系统的体系结构。这类系统是将异构平台上应用程序的不同功能部件(称为服务)通过这些服务之间定义良好的接口和规范按松耦合方式整合在一起,即将多个现有的应用软件通过网络将其整合成一个新系统。
多应用的整合不但是跨平台的,而且应该是松耦合的,也就是说,被整合的应用自身仍保持其自主,如香港政府已回归中国,但保持一国二制。
新增设的业务功能,应允许适应变化,即随需应变。
如何做到跨平台、松耦合,除使用方和服务方外,另有中介方,提供驻册登记和查询。现在社会的劳务市场和职业介绍所等都起这样作用。即先查询、梆定、然后调用。
在SOA的体系结构中,简单的可以分为如下几个角色:
①服务使用者:服务使用者是一个应用程序、一个软件模块或需要一个服务的另一个服务。它发起对注册中心中的服务的查询,通过传输绑定服务,并且执行服务功能。服务使用者根据接口契约来执行服务。
②服务提供者:服务提供者是一个可通过网络寻址的实体,它接受和执行来自使用者的请求。它将自己的服务和接口契约发布到服务注册中心,以便服务使用者可以发现和访问该服务。
③服务注册中心:服务注册中心是服务发现的支持者。它包含一个可用服务的存储库,并允许感兴趣的服务使用者查找服务提供者接口。
SOA体系结构中的操作
①发布:为了使服务可访问,需要发布服务描述以使服务使用者可以发现和调用它。
②发现:服务请求者定位服务,方法是查询服务注册中心来找到满足其标准的服务。
③绑定和调用:在检索完服务描述之后,服务使用者继续根据服务描述中的信息来调用服务。
SOA的优点如下:
①利用现有的资产。
方法是将这些现有的资产包装成提供企业功能的服务。组织可以继续从现有的资源中获取价值,而不必重新从头开始构建。
②更易于集成和管理复杂性。
将基础设施和实现发生的改变所带来的影响降到最低限度。因为复杂性是隔离的。当更多的企业一起协作提供价值链时,这会变得更加重要。
那么ESB和SOA有什么关系呐?
ESB同SOA之间的关系:ESB是逻辑上与SOA 所遵循的基本原则保持一致的服务集成基础架构,它提供了服务管理的方法和在分布式异构环境中进行服务交互的功能。
可以这样说,ESB是特定环境下(SOA架构中)实施EAI的方式:首先,在ESB系统中,被集成的对象被明确定义为服务,而不是传统EAI中各种各样的中间件平台,这样就极大简化了在集成异构性上的考虑,因为不管有怎样的应用底层实现,只要是SOA架构中的服务,它就一定是基于标准的。
其次,ESB明确强调消息(Message)处理在集成过程中的作用,这里的消息指的是应用环境中被集成对象之间的沟通。以往传统的EAI实施中碰到的最大的问题就是被集成者都有自己的方言,即各自的消息格式。作为基础架构的EAI系统,必须能够对系统范畴内的任何一种消息进行解析。传统的EAI系统中的消息处理大多是被动的,消息的处理需要各自中间件的私有方式支持,例如API的方式。因此尽管消息处理本身很重要,但消息的直接处理不会是传统EAI系统的核心。ESB系统由于集成对象统一到服务,消息在应用服务之间传递时格式是标准的,直接面向消息的处理方式成为可能。如果ESB能够在底层支持现有的各种通讯协议,那么对消息的处理就完全不考虑底层的传输细节,而直接通过消息的标准格式定义来进行。这样,在ESB中,对消息的处理就会成为ESB的核心,因为通过消息处理来集成服务是最简单可行的方式。这也是ESB中总线(Bus)功能的体现。其实,总线的概念并不新鲜,传统的EAI系统中,也曾经提出过信息总线的概念,通过某种中间件平台,如CORBA来连接企业信息孤岛,但是,ESB的概念不仅仅是提供消息交互的通道,更重要的是提供服务的智能化集成基础架构。
最后,事件驱动成为ESB的重要特征。通常服务之间传递的消息有两种形式,一种是调用(Call),即请求/回应方式,这是常见的同步模式。还有一种我们称之为单路消息(One-way),它的目的往往是触发异步的事件,发送者不需要马上得到回复。考虑到有些应用服务是长时间运行的,因此,这种异步服务之间的消息交互也是ESB必须支持的。除此之外,ESB的很多功能都可以利用这种机制来实现,例如,SOA中服务的性能监控等基础架构功能,需要通过ESB来提供数据,当服务的请求通过ESB中转的时候,ESB很容易通过事件驱动机制向SOA的基础架构服务传递信息。
3、 Jboss ESB的主要特征和功能
①Jboos esb 4.2主要的特性包括:
支持普通的通知框架。支持的Transports包括JMS (JBossMQ, JBoss Messaging, Oracle AQ and MQSeries), email, 数据库或文件系统. 推荐的缺省 JMS 实现是JBoss Messaging 1.2.0GA.
jBPM 集成.
支持WS-BPEL.
支持Web Services.
使用特定的ESB 服务器改进部署和配置.
支持Groovy.
trailblazer 例子.
许多quickstart 例子.
支持使用Smooks or XSLT转数据 .
支持交互步骤松耦合的侦听器和动作模型.
使用Drools或者 XPath 基于内容的路由.
支持JAX-R和jUDDI注册 .
提供允许non-ESB traffic与ESB进行集成的网关.
图形化的配置编辑器.
高性能和可靠性(大型保险公司3年的使用).
②什么时候使用Jboos ESB
下面的图表说明JBossESB可以被使用的具体例子。虽然这些例子在参与者间使用非互操作的JMS实现特殊的交互,但原理是相同的。
下面的这张图表显示了在两个系统间简单的文件发送,而没有使用消息队列管理。
下一个图表说明了在与上图相同的环境下如何通过注入实现转换。
下面的几个例子,我们使用了消息队列系统(例如,一个JMS实现)。
下面这幅图表显示了在相同环境下的转换和排队。
JBossESB能被用在多种情况下。举一个例子,下面的图显示了ESB利用文件系统进行基本数据转换。
最后的场景又是一个使用了转换和排队的例子。
3. JBossESB的核心
JbossESB建立在三个核心的体系结构组件上:
• 消息监听器和消息过滤器代码。消息监听器监听消息(例如,JMS上的Queue/Topic,或文件系统),并路由。然后引导消息到处理管道。消息过滤器则过滤消息,并将消息路由到另一个消息端点。
• 数据转换使用Smooks转换处理器。
• 一个基于路由服务的目录。
• 一个消息存储库, 用来存储在ESB上交换的消息/事件。
一个典型的JBossESB部署如下图。
二、Jboss ESB的详细介绍。
1、总述
JBossESB是JBoss推出的ESB的实现,也是JBoss的SOA产品的基础.首先大家对于ESB的定义有很多的不同,我个人更喜欢把ESB看作是系统集成的一个平台. JBossESB是一个基于消息的中间件(Message Oriented). 在这篇文章中,我们只是看待ESB中的一个很基础部份,也就是怎么从Endpoint A发送信息给ESB的服务S1,然后再有S1发送信息到Endpoint B去调用服务。还有一些关于Router(路由),Data Transformation(数据转换)功能点的介绍,比较基础要详细了解JbossESB的各种功能请详细参考相关的文档。
我们就假设一个简单的系统集成场景来开始阐述JBossESB的设计和概念。
A系统(Endpoint A) – Message -> ESB -> – Message --> B系统 (Endpoint B)
所以,如果简单的对于JBossESB定义的话,我们可以定义以下三个概念:
Message Listener (接收“inbound” message)
Message Filter (发送 "outbound” message)
Message (消息对象)
JBossESB 是一个面向服务(Service Oriented)的架构,所以在ESB内部的要么是一个Service, 要么是一个Message. 这里的Service就是指具有实现业务逻辑的服务,也可以是一个实现路由(Router),或者数据转化(Transformation)的服务. 就拿上面的这个例子,系统A发送一个Message给 ESB的一个服务,我们假设叫做S1, 那么S1收到Message后,做一些处理,转到S2的服务,S2再把处理后的结果发送给系统B. 这样就实现了A和B之间通过ESB的通信.
System A -> message -> S1 -> S2 ->.... -> message -> System B
那么在ESB内部是怎么去表达一个服务呢?这里引入了EndpointReference的概念,简称EPR. 有了服务之后,服务之间是通过什么样的传输层(比如JMS, FTP, HTTP)来通信呢? 所以ESB的内部也引入了Courier的API, 来统一抽象传输层. 刚我们也看到了,ESB的内部无非就是一系列的服务, 但是我们怎么来保存/注册这些服务的呢? JBossESB是使用jUDDI来注册和保存这些服务元数据的。
2、 JBossESB的几个重要概念
在要了解和运行JBossESB之前,我们最好了解下JBossESB中比较重要的几个概念。
①Message (消息)
ESB内部所交流/传递的都是消息,所以可见这个消息格式的重要性. 在JBossESB中, 定义了一个Message的对象,它是有以下几个部分构成的。
(1). Header (用来存放From, To, Reply-to等Addressing的信息).
(2). Body (存放信息主体)
(3). Attachment (用来存放附件等)
(4). Properties
(5). Context (主要是存放一些类似事务的信息等)
目前在Body里面一般来说存放两种格式的数据,一个是串行化数据(Serialized Object ),另外一个是XML文件,比如常见 的SOAP的payload. 在ESB中,还有两个定义,一个叫ESB-aware Message, 我们上面所讲的Message就是ESB-aware Message, 正如名字说讲的,它是属于ESB内部的Message对象. 还有个叫 ESB unaware Message,也就是说他同样也是一个message,比如SOAP Message,但是如果把soap message直接让ESB来处理,是处理不了的,所以呢? 经常的在Listener 监听的端口会有个Adapter (在JBossESB里叫做Gateway)来负责把ESB-unaware message 转成 ESB-aware message。
②Service (服务)
ESB的内部服务是用EPR来映射的. ESB的内部服务可以是任何的一个服务,比如说一个FTP的服务,一个基于文件系统的服务等等, 那么这个时候我们就需要用EPR来对这个服务进行描述.在EPR这个类里,主要是描述了这个服务的URI,以及所必须的一些元数据. 目前在JBossESB中提供的EPR有: FileEPR,EmailEPR,FTPEPR, HibernateEPR等等. 我们在注册服务的时候,是将EPR的信息注册到UDDI的容器里, 但不仅仅是EPR, 还有一些辅助信息,比如定义服务的category-name, service-name. 这些将在后面继续介绍。
③Listeners, Gateway
Listener的作用是负责监听端口,一般来说,客户端是发送消息到Listener,然后有Listener把消息传递给ESB, 我们可以把Listener看做是inbound router. 在JBossESB中,我们是叫GatewayListener, 它一般来说做两件事情.
监听Message.
ESB-unaware message和 ESB-aware message的互转.
目前ESB支持的Gateway有: JMSGatewayListener, JBossRemotingGatewayListener, FileGatewayListener等等. 在MessageComposer这个类里的compose/decompose方法来负责ESB-unaware信息和ESB-aware信息的转化。
public interface MessageComposer<T> {
/**
* Set the composer's configuration
*/
public void setConfiguration(ConfigTree config) throws ConfigurationException;
/**
* Compose an ESB "aware" message from the supplied message payload.
* Implementations need to construct and populate an ESB Message from the
* messagePayload instance.
*/
public Message compose(T messagePayload) throws MessageDeliverException;
/**
* Decompose an ESB "aware" message, extracting and returning the message payload.
*/
public Object decompose(Message message, T originalInputMessagePayload) throws MessageDeliverException;
}
④Couriers
Courier的作用就是负责传输,正如以下接口所显示:
public interface Courier extends DeliverOnlyCourier
{
Public Boolean deliver(Message message) throwsCourierException,MalformedEPRException;
}
目前实现的Transport有:JmsCourier, InVMCourier, HibernateCourier, FileCourier等传输层,在ESB内部是通过EPR来跟Courier进行关联的。
⑤Actions
在JBossESB中,我们可以把ActionProcessingPipeline类看作是Message Filter, 每个Message都会经过 ActionProcessingPipeline的处理. 里面有这么个方法:
public boolean process(final Message message)
而actionProcessingPipeline又是由Action (ActionPipelineProcessor)来组成的. 我们可以把Action看成是Interceptor, 由它来实现具体的业务逻辑,可以是路由,又或者数据转化功能等等. 如果你用JBossESB的话,那么Action是一个非常重要的部分,我们来看下它所定义的接口。
一般来说自定义的Action把具体的业务逻辑放在Process的方法里,当然了,你也可以定义相对应的Exception处理方法,通过实现processException.在ESB代码中,自定义的Action可以用继承AbstractActionPipelineProcessor 或者 AbstractActionLifecycle。
⑥Meta-data and Filters
在有些情况下,你需要一些全局的Interceptor,我们之前说的Action,可以理解成是每个service的interceptor,但是如果我需要使用log来记录一个消息在各个service之间传输的日志, 又或者想记录消息进入某个service的时间和退出的时间. 那么在JBoss ESB中就有Filter的概念. 如果你要实现自己的Filter,需要继承InputOputFilter类。
public class InputOutputFilter
{
/**
* Called as the message flows towards the transport.
*/
public Message onOutput (Message msg, Map<String, Object> params) throws CourierException
{
return msg;
}
/**
* Called immediately after the message is received from the transport.
*/
public Message onInput (Message msg, Map<String, Object> params) throws CourierException
{
return msg;
}
}
写完自己的Filter后,你需要在$JBossESB/server/config (e.g. default)/deploy/jbossesb.sar/jbossesb-properties.xml里面增加filter. 需要注意的是,在这里配置的filter是对所有的esb包都起作用,是个全局的变量.
onInput方法总是在从传输层获取到Message后,第一步所做的工作;类似的, onOutput是给传输层传递前所做的最后一步工作. 你可以在TwoWayCourierImpl中看到这段代码的调用。
⑦ServiceInvoker
对于客户端调用来说,EPR, Courier等都太底层了.所以如果对此进行了封装. 我们对每个service加以service-category和service-name的属性. 所以如果你想发送一个ESB的内部Message,你只需要知道目标service的service-category和service-name,然后就可以调用ServiceInvoker来调用服务. 不需要去使用Courier等底层的API, 另外用ServiceInvoker还可以支持fail-over等特性.
public class ServiceInvoker {
public ServiceInvoker(String serviceCategory, String serviceName) throws MessageDeliverException {
this(new Service(serviceCategory, serviceName));
}
public Message deliverSync(Message message, long timeoutMillis) throws MessageDeliverException, RegistryException, FaultMessageException
public void deliverAsync(Message message) throws MessageDeliverException
}
3、 Jboss ESB一个简单示例。
为了更好的来解释JBossESB, 最好的一个方法就是试下JBossESB自带的例子,这里我们先以helloworld_action的例子来讲解.
①安装和运行JBossESB sample
到这里,你已经成功的运行了helloworld_action的例子
1 从JBossESB网站下载 jbossesb-server-4.4.GA.zip
2 解压jbossesb-server-4.4.GA.zip, 假设到/var/local/jbossesb-sever4.4. 下面以$jbossesb来替代.
3 在$jbossesb中,运行 bin/run.sh 来启动ESB server
4 另外打开一个窗口,到$jbossesb/samples/quickstarts/helloworld_actions, 运行: ant deploy
5. 再运行: ant runtest
6. 回到JBoss ESB server的控制台上,应该可以看到以下的输出:.
7. INFO [STDOUT] [Hello World Action].
8. INFO [STDOUT]
9. &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
10. INFO [STDOUT] Body: Hello World Action
11. INFO [STDOUT] &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
12. INFO [STDOUT] ConsoleNotifier 2008/09/26 06:35:39.643<
13. BEFORE**
14. Hello World Action
15. AFTER**
16. >
②分析helloworld_action例子
<1>在看jboss-esb.xml的配置时候,我们应该分成两个部份. providers和services.
a. providers
首先是<providers>,它是有一系列的<provider>组成, 目前有jms-provider, fs-provider, ftp-provider等等. 然后我们在provider里面定义这个.esb文件里面service所定义的listener所需要的bus, Bus可以简单理解成消息传送所需要的传输层. 正如以下所显示的,我们定义了两个Bus,一个是给Gateway的Listener用,另外一个是给ESB-aware Message传输所需要的传输层.
<providers>
<jms-provider name="JBossMQ" connection-factory="ConnectionFactory">
<jms-bus busid="quickstartGwChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/quickstart_helloworld_action_Request"
/>
</jms-bus>
<jms-bus busid="quickstartEsbChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/B"
/>
</jms-bus>
</jms-provider>
</providers>
虽然在这边写的是JBossMQ, 但是对于JBoss ESB server来说,是默认使用JBoss Messaging的; 如果是把JBoss ESB安装在JBoss AS 4.x的服务器, 那么就是用JBoss MQ, 因为JBoss AS 4.x默认是使用JBoss MQ.
b. services
第二部份就是定义services的部份, 在这里定义了当前这个esb包所提供的services. 每个service又是由 <listener> 和 <actions>组成的.
<services>
<service category="HelloWorld_ActionESB"
name="SimpleListener"
description="Hello World" >
<listeners>
<jms-listener name="JMS-Gateway"
busidref="quickstartGwChannel"
is-gateway="true"
/>
<jms-listener name="JMS-ESBListener"
busidref="quickstartEsbChannel"
/>
</listeners>
<actions mep="OneWay">
<action name="action2"
class="org.jboss.soa.esb.actions.SystemPrintln"
/>
<action name="displayAction"
class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction"
process="displayMessage">
<property name="exceptionMethod" value="exceptionHandler"/>
</action>
<action name="playAction"
class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction"
process="playWithMessage">
<property name="exceptionMethod" value="exceptionHandler"/>
</action>
</actions>
</service>
</services>
在listener里,我们通过 busidref来关联到我们定义在provider里面的bus. 在这里,我们定义了两个listener. 其中一个是做为Gateway,只负责从外界获取到JMS的消息,然后转成ESB内部所需要的Message. 而另外一个listener是用来这个Message在services内部之间通讯的通道. 所以对于每个service来说,一定要至少定义一个listener来作为内部Message传输用.
这里的action是对消息(Message)处理的地方.
<2> MyJMSListenerAction
正如我们在上面看到的,我们在jboss-esb.xml中定义了action,我们看下MyJMSListenerAction.
public class MyJMSListenerAction extends AbstractActionLifecycle
{
protected ConfigTree _config;
public MyJMSListenerAction(ConfigTree config) { _config = config; }
public Message playWithMessage(Message message) throws Exception {
Body msgBody = message.getBody();
String contents = msgBody.get().toString();
StringBuffer sb = new StringBuffer();
sb.append("\nBEFORE**\n");
sb.append(contents);
sb.append("\nAFTER**\n");
msgBody.add(sb.toString());
return message;
}
}
我们只是截取其中的一部分来说明,一般来说每个Action都要继承AbstractActionLifecycle类,然后输入/输出参数都必须是ESB的Message. 方法名可以随便定义. 你只需要在jboss-esb.xml的action的process属性中写相对应的方法名就可以. 如果不写,默认是process方法.
这里的ConfigTree是个很重要的属性,我们很经常的会在Action配置其他的信息,那么 所有的信息都可以通过ConfigTree来获取到.比如说在某个Action中配置静态路由信息等等.也正是由于Action中你可以随意的配置你自己的信息,增加了很多的灵活性和扩展性.
<3> esb文件目录结构
我们先看下部署在server下的.esb包的文件目录,一般是包括以下些东西.
/META-INF/jboss-esb.xml
/META-INF/deployment.xml 在这里定义对其他包或者服务的依赖,或者配置classloader.
jbm-queue-service.xml (optional) 这里是定义启动所需要的Queue
**.jar (optional) 放些所需要的第三方包
所需要的些classes文件
3、客户端调用服务
目前在JBossESB中,一般有两种方式来调用service. 一种是通过Gateway listener, 另外一种是直接通过ServiceInvoker的API来调用.
①通过Gateway来调用服务
回到我们的例子,我们通过JMS Gateway来访问ESB的服务.
public class SendJMSMessage {
public void setupConnection() throws JMSException, NamingException
{
InitialContext iniCtx = new InitialContext();
Object tmp = iniCtx.lookup("ConnectionFactory");
QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
conn = qcf.createQueueConnection();
que = (Queue) iniCtx.lookup("queue/quickstart_helloworld_action_Request");
session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
conn.start();
System.out.println("Connection Started");
}
public void sendAMessage(String msg) throws JMSException {
QueueSender send = session.createSender(que);
ObjectMessage tm = session.createObjectMessage(msg);
tm.setStringProperty(StoreMessageToFile.PROPERTY_JBESB_FILENAME, "HelloWorldActionTest.log");
send.send(tm);
send.close();
}
public static void main(String args[]) throws Exception
{
SendJMSMessage sm = new SendJMSMessage();
sm.setupConnection();
sm.sendAMessage(args[0]);
sm.stop();
}
}
应该说,这是一个很普通发送JMS消息送到一个指定的Queue. 注意,我这里并没有全部拷贝这个SendJMSMessage类. 只是拷贝出重要的部分.(如果想要看完整的,请参考helloworld_action例子下面的代码)
②利用ServiceInvoker直接发送ESB Message
在helloworld_action例子中,没有直接SendESBMessage的客户端来调用,但是我们可以看下helloworld的sample下面的,因为是一样的.
public class SendEsbMessage
{
public static void main(String args[]) throws Exception
{
// Setting the ConnectionFactory such that it will use scout
System.setProperty("javax.xml.registry.ConnectionFactoryClass","org.apache.ws.scout.registry.ConnectionFactoryImpl");
if (args.length < 3)
{
System.out.println("Usage SendEsbMessage <category> <name> <text to send>");
}
Message esbMessage = MessageFactory.getInstance().getMessage();
esbMessage.getBody().add(args[2]);
new ServiceInvoker(args[0], args[1]).deliverAsync(esbMessage);
}
}
正如我们之前所说的,客户端用ServiceInvokerAPI大大简化了调用服务的过程. 我们在jboss-esb.xml中看到每个service都会有service-category和service-name的属性. 在ServiceInvoker中,用户只需要提供这两个属性,就能调用到ESB的服务,当然了,还需要juddi.properties文件. 这也是为什么我们的 sample下面一般会有这个文件.
ServiceInvoker的使用
ServiceInvoker是个相当重要的API,应该说在ESB service之间服务的互相调用,就是用ServiceInvoker来完成的. 因为ServiceInvoker对Courier等进行了一层的抽象封装. 所以用ServiceInvoker来调用服务,是可以支持fail-over等高级特性的.
4、小结
我们结合之前的概念,来看下这个例子的调用过程. 这里我们假设是通过JMS Gateway来调用ESB服务的.
(1). 从JMS Gateway listener接收到JMS Message.然后把JMS message 转成 ESB Message.
(2). 使用ServiceInvoker API发送 ESB Message到指定的service.
(3). ESBAwareListener接收到ESB Mesage后,找到对应的service,把Message提交给ActionProcessingPipeline来处理.
我们这里讲述了一个简单的调用oneway服务的一个过程.
三、 Jboss ESB的功能点及实例介绍
1、简单的测试通过Jboss ESB服务器进行消息转发的实例
(1)消费者端的代码(即要访问Jboss ESB服务器端的代码,访问者端的代码)
该类的路径在VSS上是:
Jboss ESB实例\实例1\book\src\org\jboss\seam\example\booking
package org.jboss.seam.example.booking;
import java.util.Hashtable;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.jboss.soa.esb.message.format.MessageFactory;
import org.jboss.soa.esb.message.format.MessageType;
import org.apache.log4j.Logger;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.format.MessageFactory;
import org.jboss.soa.esb.message.format.MessageType;
import org.jboss.soa.esb.client.ServiceInvoker;
public class TestESB {
QueueConnection conn;
QueueSession session;
Queue que;
private ServiceInvoker serviceInvoker;
@SuppressWarnings("unchecked")
public void setupConnection() throws JMSException, NamingException
{
Hashtable properties1 = new Hashtable();
properties1.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
properties1.put(Context.URL_PKG_PREFIXES,
"org.jboss.naming:org.jnp.interfaces");
properties1.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
InitialContext iniCtx = new InitialContext(properties1);
Object tmp = iniCtx.lookup("ConnectionFactory");
QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
conn = qcf.createQueueConnection();
que = (Queue) iniCtx.lookup("queue/esb-tb-bankRequestQueue");//("queue/esb-tb-bankRequestQueue");//("queue/quickstart_helloworld_action_Request");
session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
conn.start();
System.out.println("Connection Started");
}
public void stop() throws JMSException
{
conn.stop();
session.close();
conn.close();
}
public void sendAMessage(String msg) throws JMSException {
QueueSender send = session.createSender(que);
ObjectMessage tm = session.createObjectMessage(msg);
send.send(tm);
send.close();
}
public static void main(String args[]) throws Exception
{
TestESB sm = new TestESB();
sm.setupConnection();
sm.sendAMessage("yuexiangcheng");
sm.stop();
}
这是一个带有main()函数的主方法,目的就是为了测试。
properties1.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099"); 这句代码中的IP地址,表示Jboss ESB服务器的IP地址。
iniCtx.lookup("queue/esb-tb-bankRequestQueue"); 这句代码中的
queue/esb-tb-bankRequestQueue表示Jboss ESB服务器上暴露的服务接口。
(2)Jboss ESB服务器端的代码。
该实例的代码在VSS的路径是:
Jboss ESB实例\实例1\HelloESB
Jboss ESB服务器上主要的代码有两部分。
①jboss-esb.xml
代码如下:
<?xml version="1.0"?>
<jbossesb
xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd">
<providers>
<jms-provider name="JBossMQ" connection-factory="ConnectionFactory">
<jms-bus busid="quickstartGwChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/quickstart_helloworld_action_Request"
/>
</jms-bus>
<jms-bus busid="quickstartEsbChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/B"
/>
</jms-bus>
<!--加被岳乡成 -->
<jms-bus busid="creditAgencyRequest">
<jms-message-filter dest-type="QUEUE" dest-name="queue/esb-tb-creditAgencyQueue" />
</jms-bus>
<jms-bus busid="bankResponseGateway">
<jms-message-filter dest-type="QUEUE" dest-name="queue/esb-tb-bankGatewayResponseQueue"/>
</jms-bus>
<jms-bus busid="bankResponseListener">
<jms-message-filter dest-type="QUEUE" dest-name="queue/esb-tb-bankResponseQueue"/>
</jms-bus>
</jms-provider>
</providers>
<services>
<service category="HelloWorld_ActionESB"
name="SimpleListener"
description="Hello World" >
<listeners>
<jms-listener name="JMS-Gateway"
busidref="quickstartGwChannel"
is-gateway="true"
/>
<jms-listener name="JMS-ESBListener"
busidref="quickstartEsbChannel"
/>
</listeners>
<actions mep="OneWay">
<action name="action2"
class="org.jboss.soa.esb.actions.SystemPrintln"
/>
<action name="displayAction"
class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction"
process="displayMessage">
<property name="exceptionMethod" value="exceptionHandler"/>
</action>
<action name="playAction"
class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction"
process="playWithMessage">
<property name="exceptionMethod" value="exceptionHandler"/>
</action>
<action name="notificationAction"
class="org.jboss.soa.esb.actions.Notifier">
<property name="okMethod" value="notifyOK" />
<property name="notification-details">
<NotificationList type="OK">
<target class="NotifyConsole" />
<target class="NotifyQueues">
<messageProp name="quickstart" value="hello_world_action" />
<queue jndiName="queue/quickstart_helloworld_action_Response"/>
</target>
</NotificationList>
</property>
</action>
</actions>
</service>
<!--加被岳乡成 -->
<service category="tbCreditAGency" name="creditagency" description="Credit Agency Service">
<listeners>
<jms-listener name="trailblazer-jmscreditagency"
busidref="creditAgencyRequest"
maxThreads="1"/>
</listeners>
<actions>
<action class="org.jboss.soa.esb.samples.quickstart.testbyyuexiangcheng.CreditAgencyActions"
process="processCreditRequest" name="fido">
</action>
</actions>
</service>
<service category="tbJmsbank" name="jmsbankreplies" description="Trailblazer Bank Reply Service">
<listeners>
<jms-listener name="trailblazer-jmsbank"
busidref="bankResponseGateway"
maxThreads="1"
is-gateway="true"/>
<jms-listener name="trailblazer-jmsbankreplies"
busidref="bankResponseListener"
maxThreads="1"/>
</listeners>
<actions>
<action class="org.jboss.soa.esb.samples.quickstart.testbyyuexiangcheng.BankResponseActions"
process="processResponseFromJMSBank" name="pepe"/>
</actions>
</service>
</services>
</jbossesb>
上面红色部分表示Jboss ESB服务器上暴露的上面要调用的服务的接口的过程。
当通道接收到消息时,就会被拦截,就会转到上面绿色区域定义的类中去处理。
②Action类
该类的代码在VSS上的路径为:
Jboss ESB实例\实例1\HelloESB\src\org\jboss\soa\esb\samples\quickstart\testbyyuexiangcheng
package org.jboss.soa.esb.samples.quickstart.testbyyuexiangcheng;
import java.util.Random;
import org.apache.log4j.Logger;
import org.jboss.soa.esb.actions.AbstractActionLifecycle;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.format.MessageFactory;
import org.jboss.soa.esb.message.format.MessageType;
import org.jboss.soa.esb.util.Util;
public class CreditAgencyActions extends AbstractActionLifecycle {
protected ConfigTree _config;
private static Logger _logger = Logger.getLogger(CreditAgencyActions.class);
public CreditAgencyActions(ConfigTree config) { _config = config; }
public Message noOperation(Message message) { return message; }
public Message processCreditRequest(Message message) throws Exception{
_logger.debug("message received: " + Util.serialize(message) );
String csvData = (String) message.getBody().get();
_logger.debug("csv data received: " + csvData);
//generate a random score between 1 and 10
Random rand = new Random();
int n = 10;
int score = rand.nextInt(n+1);
//send back the reply
Message replyMessage = MessageFactory.getInstance().getMessage(MessageType.JBOSS_XML);
_logger.info("CreditAgency sending back a credit score of " + score);
replyMessage.getBody().add(Integer.toString(score));
return replyMessage;
}
public Message debugMessage(Message message) throws Exception{
_logger.debug("message received in processCreditRequest with message: " + Util.serialize(message));
return message;
}
}
2、 读取外部文档的数据,发送到Jboss ESB服务器上并且进行数据转换。
该实例的工程在VSS上的路径是:
Jboss ESB实例\实例2\James
该实例主要要注意三点:
①在工程中要提供一个要读取的文件,比如该实例中的SampleOrder.csv文件。
该文件在VSS上的路径为:
Jboss ESB实例\实例2\James\src\test
当然Jboss ESB还可以读取多种类型的文件,比如.xml文档等。
②调用者端的代码
该类在VSS的路径如下:
Jboss ESB实例\实例2\James\src\test
package test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Hashtable;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.jboss.soa.esb.util.FileUtil;
public class testCvsMassage {
QueueConnection conn;
QueueSession session;
Queue que;
public void setupConnection() throws JMSException, NamingException
{
Hashtable properties1 = new Hashtable();
properties1.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
properties1.put(Context.URL_PKG_PREFIXES,
"org.jboss.naming:org.jnp.interfaces");
properties1.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
// InitialContext iniCtx = new InitialContext(properties1);
// Object tmp = iniCtx.lookup("ConnectionFactory");
// QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
// conn = qcf.createQueueConnection();
// que = (Queue) iniCtx.lookup("queue/esb-tb-bankRequestQueue");//("queue/esb-tb-bankRequestQueue");//("queue/quickstart_helloworld_action_Request");
// session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
// conn.start();
// System.out.println("Connection Started");
InitialContext iniCtx = new InitialContext(properties1);
Object tmp = iniCtx.lookup("ConnectionFactory");
QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
conn = qcf.createQueueConnection();
que = (Queue) iniCtx.lookup("queue/quickstart_transform_CSV2XML_gw");
session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
conn.start();
System.out.println("Connection Started");
}
public void stop() throws JMSException
{
conn.stop();
session.close();
conn.close();
}
public void sendAMessage(String fileName) throws JMSException, FileNotFoundException, IOException {
QueueSender send = session.createSender(que);
ObjectMessage tm;
File file = new File(fileName);
if(!file.exists()) {
throw new IllegalArgumentException("Input message file [" + file.getAbsolutePath() + "] not found.");
}
String message = FileUtil.readTextFile(file);
tm = session.createObjectMessage(message);
tm.setStringProperty("jbesbfilename", "transformedmessageCSV2XML.log");
send.send(tm);
send.close();
System.out.println("*** Switch back to the ESB Java console now to see '" + fileName + "' before and after the transformation...");
}
public static void main(String args[]) throws Exception
{
testCvsMassage sm = new testCvsMassage();
sm.setupConnection();
sm.sendAMessage("SampleOrder.csv");
sm.stop();
}
}
上面的这句代码sm.sendAMessage("SampleOrder.csv");表示读取SampleOrder.csv文件中的内容。
③Jboss ESB端的代码
该代码在VSS上的路径为:
Jboss ESB实例\实例2\HelloESB\src\META-INF
Ⅰ、jboss-esb.xml
<?xml version="1.0"?>
<jbossesb
xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd">
<providers>
<jms-provider name="JBossMQ" connection-factory="ConnectionFactory">
<jms-bus busid="quickstartGwChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/quickstart_helloworld_action_Request"
/>
</jms-bus>
<jms-bus busid="quickstartEsbChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/B"
/>
</jms-bus>
<!--加被岳乡成 -->
<jms-bus busid="creditAgencyRequest">
<jms-message-filter dest-type="QUEUE" dest-name="queue/esb-tb-creditAgencyQueue" />
</jms-bus>
<jms-bus busid="bankResponseGateway">
<jms-message-filter dest-type="QUEUE" dest-name="queue/esb-tb-bankGatewayResponseQueue"/>
</jms-bus>
<jms-bus busid="bankResponseListener">
<jms-message-filter dest-type="QUEUE" dest-name="queue/esb-tb-bankResponseQueue"/>
</jms-bus>
<!--加被岳乡成 -->
<jms-bus busid="quickstartCSVGwChannel">
<jms-message-filter dest-type="QUEUE" dest-name="queue/quickstart_transform_CSV2XML_gw" />
</jms-bus>
<jms-bus busid="quickstartCSVEsbChannel">
<jms-message-filter dest-type="QUEUE" dest-name="queue/quickstart_transform_CSV2XML_esb" />
</jms-bus>
</jms-provider>
</providers>
<services>
<service category="HelloWorld_ActionESB"
name="SimpleListener"
description="Hello World" >
<listeners>
<jms-listener name="JMS-Gateway"
busidref="quickstartGwChannel"
is-gateway="true"
/>
<jms-listener name="JMS-ESBListener"
busidref="quickstartEsbChannel"
/>
</listeners>
<actions mep="OneWay">
<action name="action2"
class="org.jboss.soa.esb.actions.SystemPrintln"
/>
<action name="displayAction"
class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction"
process="displayMessage">
<property name="exceptionMethod" value="exceptionHandler"/>
</action>
<action name="playAction"
class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction"
process="playWithMessage">
<property name="exceptionMethod" value="exceptionHandler"/>
</action>
<action name="notificationAction"
class="org.jboss.soa.esb.actions.Notifier">
<property name="okMethod" value="notifyOK" />
<property name="notification-details">
<NotificationList type="OK">
<target class="NotifyConsole" />
<target class="NotifyQueues">
<messageProp name="quickstart" value="hello_world_action" />
<queue jndiName="queue/quickstart_helloworld_action_Response"/>
</target>
</NotificationList>
</property>
</action>
</actions>
</service>
<!--加被岳乡成 -->
<service category="tbCreditAGency" name="creditagency" description="Credit Agency Service">
<listeners>
<jms-listener name="trailblazer-jmscreditagency"
busidref="creditAgencyRequest"
maxThreads="1"/>
</listeners>
<actions>
<action class="org.jboss.soa.esb.samples.quickstart.testbyyuexiangcheng.CreditAgencyActions"
process="processCreditRequest" name="fido">
</action>
</actions>
</service>
<service category="tbJmsbank" name="jmsbankreplies" description="Trailblazer Bank Reply Service">
<listeners>
<jms-listener name="trailblazer-jmsbank"
busidref="bankResponseGateway"
maxThreads="1"
is-gateway="true"/>
<jms-listener name="trailblazer-jmsbankreplies"
busidref="bankResponseListener"
maxThreads="1"/>
</listeners>
<actions>
<action class="org.jboss.soa.esb.samples.quickstart.testbyyuexiangcheng.BankResponseActions"
process="processResponseFromJMSBank" name="pepe"/>
</actions>
</service>
<!--加被岳乡成 -->
<service category="QuickstartTransformCSV" name="SimpleListener" description="Hello World">
<listeners>
<jms-listener name="CSVJMS-Gateway" busidref="quickstartCSVGwChannel" is-gateway="true"/>
<jms-listener name="CSVquickstart" busidref="quickstartCSVEsbChannel"/>
</listeners>
<actions mep="OneWay">
<!--
Note that with this quickstart, the transformation is broken into 2 transforms; CSV to XML
and XML to XML. These 2 transformations could easly be merged into a single transform, saving
on XML processing.
-->
<action name="print-before" class="org.jboss.soa.esb.actions.SystemPrintln">
<property name="message" value="[transform_CSV2Smooks_Intermediate_format] Message before CVS to XML transformation" />
</action>
<!--
Transform 1: Source CSV to Canonical XML...
-->
<action name="transform-from-csv" class="org.jboss.soa.esb.smooks.SmooksAction">
<property name="smooksConfig" value="/smooks-res.xml" />
<property name="messageProfile" value="source-csv" />
</action>
<action name="print-after-csv-tranform" class="org.jboss.soa.esb.actions.SystemPrintln">
<property name="message" value="[transform_CSV2Smooks_Intermediate_format] Message after CVS to XML transformation" />
</action>
<!--
Transform 2: Canonical XML to target XML...
-->
<action name="transform-to-xml" class="org.jboss.soa.esb.smooks.SmooksAction">
<property name="smooksConfig" value="/smooks-res.xml" />
<property name="messageProfile" value="canonical-xml" />
</action>
<action name="print-after-xml-transform" class="org.jboss.soa.esb.actions.SystemPrintln">
<property name="message" value=">>>> Message after Smooks intermediate xml -> target xml : " />
</action>
</actions>
</service>
</services>
</jbossesb>
上面绿色区域的代码表示Jboss ESB服务器把.cvs文件转换为.xml文件的过程。
<action name="transform-from-csv" class="org.jboss.soa.esb.smooks.SmooksAction">这句代码中的class="org.jboss.soa.esb.smooks.SmooksAction"是Jboss ESB提供的。
Jboss ESB提供了好多关于数据转换的例子,请详细参考。
3、 基于内容的路由
关于内容的路由,我在这里就不详细说了,请详细参考:
jbossesb-4.4.GA\samples\quickstarts下的
4、 Jboss ESB的业务流
关于Jboss ESB的业务流,我在这里也不详细说了,请详细参考:
jbossesb-4.4.GA\samples\quickstarts下的
5、 以JMS为消息在Jboss ESB上的一个应用。
该实例的源码在VSS上的路径是:
SOA\ JMS在Jboss ESB中的应用
这个实例包括三个部分<1>Jboss ESB服务器端(192.168.1.101 esb文件夹下的工程)。<2>服务消费者端(192.168.1.111文件夹下的工程)。<3>服务提供者端(192.168.1.121文件夹下的工程)。
①Jboss ESB服务器端
Ⅰ、Jboss-esb.xml文件
该文件在VSS上的路径为:
JMS在Jboss ESB中的应用\192.168.1.101 esb\Medicare_esb\src\META-INF
<?xml version = "1.0" encoding = "UTF-8"?>
<jbossesb xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd" parameterReloadSecs="5">
<providers>
<jms-provider name="JBossMQ" connection-factory="ConnectionFactory">
<jms-bus busid="quickstartGwChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/quickstart_transform_pojo_gw"
/>
</jms-bus>
<jms-bus busid="quickstartEsbChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/quickstart_transform_pojo_esb"
/>
</jms-bus>
</jms-provider>
</providers>
<services>
<service
category="MyTransformationServicesESB"
name="MyFirstTransformationServiceESB"
description="ESB: Takes XML in and produces a POJO">
<listeners>
<jms-listener name="JMS-Gateway"
busidref="quickstartGwChannel"
is-gateway="true"
/>
<jms-listener name="jmsTransformer"
busidref="quickstartEsbChannel"
/>
</listeners>
<actions mep="OneWay">
<action name="displayBeforeTransformer"
class="org.jboss.soa.esb.samples.medicare.MyJMSListenerAction"
process="displayMessage"
/>
<action name="returnToSender"
class="org.jboss.soa.esb.samples.medicare.MyJMSListenerAction" process="sendResponse" />
<!--
<action name="receiveMsg"
class="org.jboss.soa.esb.samples.medicare.ReceiveMessage" process="displayMessage" />
<action name="receiveMsg"
class="org.jboss.soa.esb.samples.medicare.ReceiveMessage" process="sendResponse" />
-->
</actions>
</service>
</services>
</jbossesb>
Ⅱ、 在Jboss ESB服务器上的Action
在VSS上的路径为:
JMS在Jboss ESB中的应用\192.168.1.101 esb\Medicare_esb\src\org\jboss\soa\esb\samples\medicare
这个文件夹下的内容就是消息的拦截器,负责对消息的拦截。详细内容请查看相关的代码。
②消费者端的代码。
该工程在VSS上的路径为:
JMS在Jboss ESB中的应用\192.168.1.121
相关的代码请详细参考该工程。
③提供者端的代码。
该工程在VSS上的路径为:
JMS在Jboss ESB中的应用\192.168.1.111
相关的代码请详细参考该工程。
6、 以Web Service为基础在Jboss ESB上的一个应用。
该工程在VSS上的路径为:
SOA\SOA(V1.2)
这个实例也包括三个部分<1>Jboss ESB服务器端(Esb Service(192.168.1.101)文件夹下的工程)。<2>服务消费者端(Request endpoint(192.168.1.112)文件夹下的工程)。<3>服务提供者端(Respose endpoint(192.168.1.111)文件夹下的工程)。
服务消费者端和服务提供者端我已经在另一个文档中《Web Service简介及开发实例》中做了详细的介绍。
现在我只简单的讨论一下再Jboss ESB服务器端的代码。
①先看Jboss-esb.xml文件
该文件在VSS上的路径为:
SOA(V1.2)\Esb Service(192.168.1.101)\WebService\src\META-INF
<?xml version = "1.0" encoding = "UTF-8"?>
<jbossesb
xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd"
parameterReloadSecs="5">
<providers>
<jms-provider name="JBossMQ" connection-factory="ConnectionFactory">
<jms-bus busid="quickstartGwChannel">
<jms-message-filter dest-type="QUEUE" dest-name="queue/quickstart_webservice_producer_gw"/>
</jms-bus>
<jms-bus busid="quickstartEsbChannel">
<jms-message-filter dest-type="QUEUE" dest-name="queue/quickstart_webservice_producer_esb"/>
</jms-bus>
</jms-provider>
<jbr-provider name="JBR-Http" protocol="http" >
<jbr-bus busid="Http-1" port="8765" />
</jbr-provider>
<jbr-provider name="JBR-Socket" protocol="socket" host="localhost">
<jbr-bus busid="Socket-1" port="8888" />
</jbr-provider>
</providers>
<services>
<service category="MyServiceCategory" name="MyWSProducerService" description="WS Frontend speaks natively to the ESB">
<listeners>
<jms-listener name="JMS-Gateway" busidref="quickstartGwChannel" is-gateway="true"/>
<jbr-listener name="Http-Gateway" busidref="Http-1" is-gateway="true"/>
<jbr-listener name="Socket-Gateway" busidref="Socket-1" is-gateway="true"/>
<jms-listener name="JMS-ESBListener" busidref="quickstartEsbChannel"/>
</listeners>
<actions>
<action name="print-before" class="org.jboss.soa.esb.actions.SystemPrintln">
<property name="message"
value="[Quickstart_webservice_producer] BEFORE invoking jbossws endpoint"/>
</action>
<action name="JBossWSAdapter" class="org.jboss.soa.esb.actions.soap.SOAPProcessor">
<property name="jbossws-endpoint" value="GoodbyeWorldWS"/>
</action>
<action name="print-after" class="org.jboss.soa.esb.actions.SystemPrintln">
<property name="message"
value="[Quickstart_webservice_producer] AFTER invoking jbossws endpoint"/>
</action>
<action name="testStore" class="org.jboss.soa.esb.actions.TestMessageStore"/>
</actions>
</service>
</services>
</jbossesb>
②Jboss ESB服务器上的Action类,代码如下:
该类在VSS上的路径为:
SOA(V1.2)\EsbService(192.168.1.101)\WebService\src\org\jboss\soa\esb\samples\quickstart\webserviceproducer\webservice
代码如下:
package org.jboss.soa.esb.samples.quickstart.webserviceproducer.webservice;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.stream.StreamResult;
/**
* @author
*/
@WebService(name = "GoodbyeWorldWS", targetNamespace="http://webservice_producer/goodbyeworld")
public class GoodbyeWorldWS {
public static final String INDEXOFOBJECTSTART = "<Hotel>";
public static final String INDEXOFOBJECTEND = "</Hotel>";
public static final int OBJECTSTARTFLAGLENGTH = INDEXOFOBJECTSTART.length();
public static final int OBJECTENDFLAGLENGTH = INDEXOFOBJECTEND.length();
@WebMethod
@WebResult(name="ListHotel")
public String sayGoodbye(@WebParam(name="message") String message){
try {
//传送参数需要创建Name
SOAPFactory soapFactory = SOAPFactory.newInstance();
//Next, create the actual message
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message1 = messageFactory.createMessage();
//Create objects for the message parts
SOAPPart soapPart = message1.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
//Populate the body
//Create the main element and namespace
SOAPElement bodyElement =
body.addChildElement(envelope.createName("getHotelObject" ,
"serch",
"http://tower/ehr_DEV"));
bodyElement.setEncodingStyle(SOAPConstants.URI_NS_SOAP_ENCODING);
//传送参数新建一个Name对象
Name name = soapFactory.createName("arg0");
SOAPElement symbol = bodyElement.addChildElement(name);
symbol.addTextNode(message);
//Add content
//Save the message
message1.saveChanges();
//Send the message and get a reply
//Set the destination
//Send the message
List<String> destinationList = readTxtFile("D:/webServiceConfig.txt");
String resultString = getResultString(destinationList,message1);
if("".equals(resultString)){
return "";
}else{
return resultString;
}
} catch(Exception e) {
System.out.println(e.getMessage());
}
return "";
}
public static List<String> readTxtFile(String fileName){
String read;
FileReader fileread;
List<String> l = new ArrayList<String>();
try {
fileread = new FileReader(fileName);
BufferedReader bufread = new BufferedReader(fileread);
try {
while ((read = bufread.readLine()) != null) {
l.add(read);
}
} catch (IOException e) {
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return l;
}
public static String getResultString(List<String> destinationList,SOAPMessage message){
try {
String resultString = "";
for(int i = 0;i<destinationList.size();i++){
String destination = destinationList.get(i);
SOAPConnectionFactory soapConnFactory = SOAPConnectionFactory.newInstance();
SOAPConnection connection = soapConnFactory.createConnection();
SOAPMessage reply = connection.call(message, destination);
String stringBady = getSOAPMessageStringBady(reply);
resultString = resultString + stringBady;
connection.close();
}
return resultString;
} catch (UnsupportedOperationException e) {
e.printStackTrace();
} catch (SOAPException e) {
e.printStackTrace();
}
return "";
}
public static String getSOAPMessageStringBady(SOAPMessage reply) {
try {
String sb = "";
Source source = reply.getSOAPPart().getContent();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
ByteArrayOutputStream myOutStr = new ByteArrayOutputStream();
StreamResult res = new StreamResult();
res.setOutputStream(myOutStr);
transformer.transform(source,res);
String temp = myOutStr.toString().trim();
int indexOfObjectStart = temp.indexOf(INDEXOFOBJECTSTART);
if(indexOfObjectStart==-1){
return sb;
}else{
int indexOfObjectEnd = temp.lastIndexOf(INDEXOFOBJECTEND);
sb = temp.substring(indexOfObjectStart,indexOfObjectEnd+OBJECTENDFLAGLENGTH);
return sb;
}
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerFactoryConfigurationError e) {
e.printStackTrace();
} catch (SOAPException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}
return "";
}
}
哦 好的 我原来用 AXIS 它是用DataHandler 来封装文件的 不过 1.4 版本 时还需要写 wsd文件
作者:岳乡成
一、Jboss ESB的简介
1、 什么是ESB。
ESB的全称是Enterprise Service Bus,即企业服务总线。ESB是过去消息中间件的发展,ESB采用了“总线”这样一种模式来管理和简化应用之间的集成拓扑结构,以广为接受的开放标准为基础来支持应用之间在消息、事件和服务的级别上动态的互连互通。
ESB是一种在松散耦合的服务和应用之间标准的集成方式。它可以作用于:
①面向服务的架构 - 分布式的应用由可重用的服务组成。
②面向消息的架构 - 应用之间通过ESB发送和接受消息。
③事件驱动的架构 - 应用之间异步地产生和接收消息。
用一句比较通俗的话来描述ESB:ESB就是在SOA架构中实现服务间智能化集成与管理的中介。
2、 ESB和SOA之间的关系。
介绍ESB就不得不提到SOA的概念,那么什么是SOA呐?
简单的说,SOA(service-oriented architecture)是面向服务的体系结构,是一类分布式系统的体系结构。这类系统是将异构平台上应用程序的不同功能部件(称为服务)通过这些服务之间定义良好的接口和规范按松耦合方式整合在一起,即将多个现有的应用软件通过网络将其整合成一个新系统。
多应用的整合不但是跨平台的,而且应该是松耦合的,也就是说,被整合的应用自身仍保持其自主,如香港政府已回归中国,但保持一国二制。
新增设的业务功能,应允许适应变化,即随需应变。
如何做到跨平台、松耦合,除使用方和服务方外,另有中介方,提供驻册登记和查询。现在社会的劳务市场和职业介绍所等都起这样作用。即先查询、梆定、然后调用。
在SOA的体系结构中,简单的可以分为如下几个角色:
①服务使用者:服务使用者是一个应用程序、一个软件模块或需要一个服务的另一个服务。它发起对注册中心中的服务的查询,通过传输绑定服务,并且执行服务功能。服务使用者根据接口契约来执行服务。
②服务提供者:服务提供者是一个可通过网络寻址的实体,它接受和执行来自使用者的请求。它将自己的服务和接口契约发布到服务注册中心,以便服务使用者可以发现和访问该服务。
③服务注册中心:服务注册中心是服务发现的支持者。它包含一个可用服务的存储库,并允许感兴趣的服务使用者查找服务提供者接口。
SOA体系结构中的操作
①发布:为了使服务可访问,需要发布服务描述以使服务使用者可以发现和调用它。
②发现:服务请求者定位服务,方法是查询服务注册中心来找到满足其标准的服务。
③绑定和调用:在检索完服务描述之后,服务使用者继续根据服务描述中的信息来调用服务。
SOA的优点如下:
①利用现有的资产。
方法是将这些现有的资产包装成提供企业功能的服务。组织可以继续从现有的资源中获取价值,而不必重新从头开始构建。
②更易于集成和管理复杂性。
将基础设施和实现发生的改变所带来的影响降到最低限度。因为复杂性是隔离的。当更多的企业一起协作提供价值链时,这会变得更加重要。
那么ESB和SOA有什么关系呐?
ESB同SOA之间的关系:ESB是逻辑上与SOA 所遵循的基本原则保持一致的服务集成基础架构,它提供了服务管理的方法和在分布式异构环境中进行服务交互的功能。
可以这样说,ESB是特定环境下(SOA架构中)实施EAI的方式:首先,在ESB系统中,被集成的对象被明确定义为服务,而不是传统EAI中各种各样的中间件平台,这样就极大简化了在集成异构性上的考虑,因为不管有怎样的应用底层实现,只要是SOA架构中的服务,它就一定是基于标准的。
其次,ESB明确强调消息(Message)处理在集成过程中的作用,这里的消息指的是应用环境中被集成对象之间的沟通。以往传统的EAI实施中碰到的最大的问题就是被集成者都有自己的方言,即各自的消息格式。作为基础架构的EAI系统,必须能够对系统范畴内的任何一种消息进行解析。传统的EAI系统中的消息处理大多是被动的,消息的处理需要各自中间件的私有方式支持,例如API的方式。因此尽管消息处理本身很重要,但消息的直接处理不会是传统EAI系统的核心。ESB系统由于集成对象统一到服务,消息在应用服务之间传递时格式是标准的,直接面向消息的处理方式成为可能。如果ESB能够在底层支持现有的各种通讯协议,那么对消息的处理就完全不考虑底层的传输细节,而直接通过消息的标准格式定义来进行。这样,在ESB中,对消息的处理就会成为ESB的核心,因为通过消息处理来集成服务是最简单可行的方式。这也是ESB中总线(Bus)功能的体现。其实,总线的概念并不新鲜,传统的EAI系统中,也曾经提出过信息总线的概念,通过某种中间件平台,如CORBA来连接企业信息孤岛,但是,ESB的概念不仅仅是提供消息交互的通道,更重要的是提供服务的智能化集成基础架构。
最后,事件驱动成为ESB的重要特征。通常服务之间传递的消息有两种形式,一种是调用(Call),即请求/回应方式,这是常见的同步模式。还有一种我们称之为单路消息(One-way),它的目的往往是触发异步的事件,发送者不需要马上得到回复。考虑到有些应用服务是长时间运行的,因此,这种异步服务之间的消息交互也是ESB必须支持的。除此之外,ESB的很多功能都可以利用这种机制来实现,例如,SOA中服务的性能监控等基础架构功能,需要通过ESB来提供数据,当服务的请求通过ESB中转的时候,ESB很容易通过事件驱动机制向SOA的基础架构服务传递信息。
3、 Jboss ESB的主要特征和功能
①Jboos esb 4.2主要的特性包括:
支持普通的通知框架。支持的Transports包括JMS (JBossMQ, JBoss Messaging, Oracle AQ and MQSeries), email, 数据库或文件系统. 推荐的缺省 JMS 实现是JBoss Messaging 1.2.0GA.
jBPM 集成.
支持WS-BPEL.
支持Web Services.
使用特定的ESB 服务器改进部署和配置.
支持Groovy.
trailblazer 例子.
许多quickstart 例子.
支持使用Smooks or XSLT转数据 .
支持交互步骤松耦合的侦听器和动作模型.
使用Drools或者 XPath 基于内容的路由.
支持JAX-R和jUDDI注册 .
提供允许non-ESB traffic与ESB进行集成的网关.
图形化的配置编辑器.
高性能和可靠性(大型保险公司3年的使用).
②什么时候使用Jboos ESB
下面的图表说明JBossESB可以被使用的具体例子。虽然这些例子在参与者间使用非互操作的JMS实现特殊的交互,但原理是相同的。
下面的这张图表显示了在两个系统间简单的文件发送,而没有使用消息队列管理。
下一个图表说明了在与上图相同的环境下如何通过注入实现转换。
下面的几个例子,我们使用了消息队列系统(例如,一个JMS实现)。
下面这幅图表显示了在相同环境下的转换和排队。
JBossESB能被用在多种情况下。举一个例子,下面的图显示了ESB利用文件系统进行基本数据转换。
最后的场景又是一个使用了转换和排队的例子。
3. JBossESB的核心
JbossESB建立在三个核心的体系结构组件上:
• 消息监听器和消息过滤器代码。消息监听器监听消息(例如,JMS上的Queue/Topic,或文件系统),并路由。然后引导消息到处理管道。消息过滤器则过滤消息,并将消息路由到另一个消息端点。
• 数据转换使用Smooks转换处理器。
• 一个基于路由服务的目录。
• 一个消息存储库, 用来存储在ESB上交换的消息/事件。
一个典型的JBossESB部署如下图。
二、Jboss ESB的详细介绍。
1、总述
JBossESB是JBoss推出的ESB的实现,也是JBoss的SOA产品的基础.首先大家对于ESB的定义有很多的不同,我个人更喜欢把ESB看作是系统集成的一个平台. JBossESB是一个基于消息的中间件(Message Oriented). 在这篇文章中,我们只是看待ESB中的一个很基础部份,也就是怎么从Endpoint A发送信息给ESB的服务S1,然后再有S1发送信息到Endpoint B去调用服务。还有一些关于Router(路由),Data Transformation(数据转换)功能点的介绍,比较基础要详细了解JbossESB的各种功能请详细参考相关的文档。
我们就假设一个简单的系统集成场景来开始阐述JBossESB的设计和概念。
A系统(Endpoint A) – Message -> ESB -> – Message --> B系统 (Endpoint B)
所以,如果简单的对于JBossESB定义的话,我们可以定义以下三个概念:
Message Listener (接收“inbound” message)
Message Filter (发送 "outbound” message)
Message (消息对象)
JBossESB 是一个面向服务(Service Oriented)的架构,所以在ESB内部的要么是一个Service, 要么是一个Message. 这里的Service就是指具有实现业务逻辑的服务,也可以是一个实现路由(Router),或者数据转化(Transformation)的服务. 就拿上面的这个例子,系统A发送一个Message给 ESB的一个服务,我们假设叫做S1, 那么S1收到Message后,做一些处理,转到S2的服务,S2再把处理后的结果发送给系统B. 这样就实现了A和B之间通过ESB的通信.
System A -> message -> S1 -> S2 ->.... -> message -> System B
那么在ESB内部是怎么去表达一个服务呢?这里引入了EndpointReference的概念,简称EPR. 有了服务之后,服务之间是通过什么样的传输层(比如JMS, FTP, HTTP)来通信呢? 所以ESB的内部也引入了Courier的API, 来统一抽象传输层. 刚我们也看到了,ESB的内部无非就是一系列的服务, 但是我们怎么来保存/注册这些服务的呢? JBossESB是使用jUDDI来注册和保存这些服务元数据的。
2、 JBossESB的几个重要概念
在要了解和运行JBossESB之前,我们最好了解下JBossESB中比较重要的几个概念。
①Message (消息)
ESB内部所交流/传递的都是消息,所以可见这个消息格式的重要性. 在JBossESB中, 定义了一个Message的对象,它是有以下几个部分构成的。
(1). Header (用来存放From, To, Reply-to等Addressing的信息).
(2). Body (存放信息主体)
(3). Attachment (用来存放附件等)
(4). Properties
(5). Context (主要是存放一些类似事务的信息等)
目前在Body里面一般来说存放两种格式的数据,一个是串行化数据(Serialized Object ),另外一个是XML文件,比如常见 的SOAP的payload. 在ESB中,还有两个定义,一个叫ESB-aware Message, 我们上面所讲的Message就是ESB-aware Message, 正如名字说讲的,它是属于ESB内部的Message对象. 还有个叫 ESB unaware Message,也就是说他同样也是一个message,比如SOAP Message,但是如果把soap message直接让ESB来处理,是处理不了的,所以呢? 经常的在Listener 监听的端口会有个Adapter (在JBossESB里叫做Gateway)来负责把ESB-unaware message 转成 ESB-aware message。
②Service (服务)
ESB的内部服务是用EPR来映射的. ESB的内部服务可以是任何的一个服务,比如说一个FTP的服务,一个基于文件系统的服务等等, 那么这个时候我们就需要用EPR来对这个服务进行描述.在EPR这个类里,主要是描述了这个服务的URI,以及所必须的一些元数据. 目前在JBossESB中提供的EPR有: FileEPR,EmailEPR,FTPEPR, HibernateEPR等等. 我们在注册服务的时候,是将EPR的信息注册到UDDI的容器里, 但不仅仅是EPR, 还有一些辅助信息,比如定义服务的category-name, service-name. 这些将在后面继续介绍。
③Listeners, Gateway
Listener的作用是负责监听端口,一般来说,客户端是发送消息到Listener,然后有Listener把消息传递给ESB, 我们可以把Listener看做是inbound router. 在JBossESB中,我们是叫GatewayListener, 它一般来说做两件事情.
监听Message.
ESB-unaware message和 ESB-aware message的互转.
目前ESB支持的Gateway有: JMSGatewayListener, JBossRemotingGatewayListener, FileGatewayListener等等. 在MessageComposer这个类里的compose/decompose方法来负责ESB-unaware信息和ESB-aware信息的转化。
public interface MessageComposer<T> {
/**
* Set the composer's configuration
*/
public void setConfiguration(ConfigTree config) throws ConfigurationException;
/**
* Compose an ESB "aware" message from the supplied message payload.
* Implementations need to construct and populate an ESB Message from the
* messagePayload instance.
*/
public Message compose(T messagePayload) throws MessageDeliverException;
/**
* Decompose an ESB "aware" message, extracting and returning the message payload.
*/
public Object decompose(Message message, T originalInputMessagePayload) throws MessageDeliverException;
}
④Couriers
Courier的作用就是负责传输,正如以下接口所显示:
public interface Courier extends DeliverOnlyCourier
{
Public Boolean deliver(Message message) throwsCourierException,MalformedEPRException;
}
目前实现的Transport有:JmsCourier, InVMCourier, HibernateCourier, FileCourier等传输层,在ESB内部是通过EPR来跟Courier进行关联的。
⑤Actions
在JBossESB中,我们可以把ActionProcessingPipeline类看作是Message Filter, 每个Message都会经过 ActionProcessingPipeline的处理. 里面有这么个方法:
public boolean process(final Message message)
而actionProcessingPipeline又是由Action (ActionPipelineProcessor)来组成的. 我们可以把Action看成是Interceptor, 由它来实现具体的业务逻辑,可以是路由,又或者数据转化功能等等. 如果你用JBossESB的话,那么Action是一个非常重要的部分,我们来看下它所定义的接口。
一般来说自定义的Action把具体的业务逻辑放在Process的方法里,当然了,你也可以定义相对应的Exception处理方法,通过实现processException.在ESB代码中,自定义的Action可以用继承AbstractActionPipelineProcessor 或者 AbstractActionLifecycle。
⑥Meta-data and Filters
在有些情况下,你需要一些全局的Interceptor,我们之前说的Action,可以理解成是每个service的interceptor,但是如果我需要使用log来记录一个消息在各个service之间传输的日志, 又或者想记录消息进入某个service的时间和退出的时间. 那么在JBoss ESB中就有Filter的概念. 如果你要实现自己的Filter,需要继承InputOputFilter类。
public class InputOutputFilter
{
/**
* Called as the message flows towards the transport.
*/
public Message onOutput (Message msg, Map<String, Object> params) throws CourierException
{
return msg;
}
/**
* Called immediately after the message is received from the transport.
*/
public Message onInput (Message msg, Map<String, Object> params) throws CourierException
{
return msg;
}
}
写完自己的Filter后,你需要在$JBossESB/server/config (e.g. default)/deploy/jbossesb.sar/jbossesb-properties.xml里面增加filter. 需要注意的是,在这里配置的filter是对所有的esb包都起作用,是个全局的变量.
onInput方法总是在从传输层获取到Message后,第一步所做的工作;类似的, onOutput是给传输层传递前所做的最后一步工作. 你可以在TwoWayCourierImpl中看到这段代码的调用。
⑦ServiceInvoker
对于客户端调用来说,EPR, Courier等都太底层了.所以如果对此进行了封装. 我们对每个service加以service-category和service-name的属性. 所以如果你想发送一个ESB的内部Message,你只需要知道目标service的service-category和service-name,然后就可以调用ServiceInvoker来调用服务. 不需要去使用Courier等底层的API, 另外用ServiceInvoker还可以支持fail-over等特性.
public class ServiceInvoker {
public ServiceInvoker(String serviceCategory, String serviceName) throws MessageDeliverException {
this(new Service(serviceCategory, serviceName));
}
public Message deliverSync(Message message, long timeoutMillis) throws MessageDeliverException, RegistryException, FaultMessageException
public void deliverAsync(Message message) throws MessageDeliverException
}
3、 Jboss ESB一个简单示例。
为了更好的来解释JBossESB, 最好的一个方法就是试下JBossESB自带的例子,这里我们先以helloworld_action的例子来讲解.
①安装和运行JBossESB sample
到这里,你已经成功的运行了helloworld_action的例子
1 从JBossESB网站下载 jbossesb-server-4.4.GA.zip
2 解压jbossesb-server-4.4.GA.zip, 假设到/var/local/jbossesb-sever4.4. 下面以$jbossesb来替代.
3 在$jbossesb中,运行 bin/run.sh 来启动ESB server
4 另外打开一个窗口,到$jbossesb/samples/quickstarts/helloworld_actions, 运行: ant deploy
5. 再运行: ant runtest
6. 回到JBoss ESB server的控制台上,应该可以看到以下的输出:.
7. INFO [STDOUT] [Hello World Action].
8. INFO [STDOUT]
9. &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
10. INFO [STDOUT] Body: Hello World Action
11. INFO [STDOUT] &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
12. INFO [STDOUT] ConsoleNotifier 2008/09/26 06:35:39.643<
13. BEFORE**
14. Hello World Action
15. AFTER**
16. >
②分析helloworld_action例子
<1>在看jboss-esb.xml的配置时候,我们应该分成两个部份. providers和services.
a. providers
首先是<providers>,它是有一系列的<provider>组成, 目前有jms-provider, fs-provider, ftp-provider等等. 然后我们在provider里面定义这个.esb文件里面service所定义的listener所需要的bus, Bus可以简单理解成消息传送所需要的传输层. 正如以下所显示的,我们定义了两个Bus,一个是给Gateway的Listener用,另外一个是给ESB-aware Message传输所需要的传输层.
<providers>
<jms-provider name="JBossMQ" connection-factory="ConnectionFactory">
<jms-bus busid="quickstartGwChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/quickstart_helloworld_action_Request"
/>
</jms-bus>
<jms-bus busid="quickstartEsbChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/B"
/>
</jms-bus>
</jms-provider>
</providers>
虽然在这边写的是JBossMQ, 但是对于JBoss ESB server来说,是默认使用JBoss Messaging的; 如果是把JBoss ESB安装在JBoss AS 4.x的服务器, 那么就是用JBoss MQ, 因为JBoss AS 4.x默认是使用JBoss MQ.
b. services
第二部份就是定义services的部份, 在这里定义了当前这个esb包所提供的services. 每个service又是由 <listener> 和 <actions>组成的.
<services>
<service category="HelloWorld_ActionESB"
name="SimpleListener"
description="Hello World" >
<listeners>
<jms-listener name="JMS-Gateway"
busidref="quickstartGwChannel"
is-gateway="true"
/>
<jms-listener name="JMS-ESBListener"
busidref="quickstartEsbChannel"
/>
</listeners>
<actions mep="OneWay">
<action name="action2"
class="org.jboss.soa.esb.actions.SystemPrintln"
/>
<action name="displayAction"
class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction"
process="displayMessage">
<property name="exceptionMethod" value="exceptionHandler"/>
</action>
<action name="playAction"
class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction"
process="playWithMessage">
<property name="exceptionMethod" value="exceptionHandler"/>
</action>
</actions>
</service>
</services>
在listener里,我们通过 busidref来关联到我们定义在provider里面的bus. 在这里,我们定义了两个listener. 其中一个是做为Gateway,只负责从外界获取到JMS的消息,然后转成ESB内部所需要的Message. 而另外一个listener是用来这个Message在services内部之间通讯的通道. 所以对于每个service来说,一定要至少定义一个listener来作为内部Message传输用.
这里的action是对消息(Message)处理的地方.
<2> MyJMSListenerAction
正如我们在上面看到的,我们在jboss-esb.xml中定义了action,我们看下MyJMSListenerAction.
public class MyJMSListenerAction extends AbstractActionLifecycle
{
protected ConfigTree _config;
public MyJMSListenerAction(ConfigTree config) { _config = config; }
public Message playWithMessage(Message message) throws Exception {
Body msgBody = message.getBody();
String contents = msgBody.get().toString();
StringBuffer sb = new StringBuffer();
sb.append("\nBEFORE**\n");
sb.append(contents);
sb.append("\nAFTER**\n");
msgBody.add(sb.toString());
return message;
}
}
我们只是截取其中的一部分来说明,一般来说每个Action都要继承AbstractActionLifecycle类,然后输入/输出参数都必须是ESB的Message. 方法名可以随便定义. 你只需要在jboss-esb.xml的action的process属性中写相对应的方法名就可以. 如果不写,默认是process方法.
这里的ConfigTree是个很重要的属性,我们很经常的会在Action配置其他的信息,那么 所有的信息都可以通过ConfigTree来获取到.比如说在某个Action中配置静态路由信息等等.也正是由于Action中你可以随意的配置你自己的信息,增加了很多的灵活性和扩展性.
<3> esb文件目录结构
我们先看下部署在server下的.esb包的文件目录,一般是包括以下些东西.
/META-INF/jboss-esb.xml
/META-INF/deployment.xml 在这里定义对其他包或者服务的依赖,或者配置classloader.
jbm-queue-service.xml (optional) 这里是定义启动所需要的Queue
**.jar (optional) 放些所需要的第三方包
所需要的些classes文件
3、客户端调用服务
目前在JBossESB中,一般有两种方式来调用service. 一种是通过Gateway listener, 另外一种是直接通过ServiceInvoker的API来调用.
①通过Gateway来调用服务
回到我们的例子,我们通过JMS Gateway来访问ESB的服务.
public class SendJMSMessage {
public void setupConnection() throws JMSException, NamingException
{
InitialContext iniCtx = new InitialContext();
Object tmp = iniCtx.lookup("ConnectionFactory");
QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
conn = qcf.createQueueConnection();
que = (Queue) iniCtx.lookup("queue/quickstart_helloworld_action_Request");
session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
conn.start();
System.out.println("Connection Started");
}
public void sendAMessage(String msg) throws JMSException {
QueueSender send = session.createSender(que);
ObjectMessage tm = session.createObjectMessage(msg);
tm.setStringProperty(StoreMessageToFile.PROPERTY_JBESB_FILENAME, "HelloWorldActionTest.log");
send.send(tm);
send.close();
}
public static void main(String args[]) throws Exception
{
SendJMSMessage sm = new SendJMSMessage();
sm.setupConnection();
sm.sendAMessage(args[0]);
sm.stop();
}
}
应该说,这是一个很普通发送JMS消息送到一个指定的Queue. 注意,我这里并没有全部拷贝这个SendJMSMessage类. 只是拷贝出重要的部分.(如果想要看完整的,请参考helloworld_action例子下面的代码)
②利用ServiceInvoker直接发送ESB Message
在helloworld_action例子中,没有直接SendESBMessage的客户端来调用,但是我们可以看下helloworld的sample下面的,因为是一样的.
public class SendEsbMessage
{
public static void main(String args[]) throws Exception
{
// Setting the ConnectionFactory such that it will use scout
System.setProperty("javax.xml.registry.ConnectionFactoryClass","org.apache.ws.scout.registry.ConnectionFactoryImpl");
if (args.length < 3)
{
System.out.println("Usage SendEsbMessage <category> <name> <text to send>");
}
Message esbMessage = MessageFactory.getInstance().getMessage();
esbMessage.getBody().add(args[2]);
new ServiceInvoker(args[0], args[1]).deliverAsync(esbMessage);
}
}
正如我们之前所说的,客户端用ServiceInvokerAPI大大简化了调用服务的过程. 我们在jboss-esb.xml中看到每个service都会有service-category和service-name的属性. 在ServiceInvoker中,用户只需要提供这两个属性,就能调用到ESB的服务,当然了,还需要juddi.properties文件. 这也是为什么我们的 sample下面一般会有这个文件.
ServiceInvoker的使用
ServiceInvoker是个相当重要的API,应该说在ESB service之间服务的互相调用,就是用ServiceInvoker来完成的. 因为ServiceInvoker对Courier等进行了一层的抽象封装. 所以用ServiceInvoker来调用服务,是可以支持fail-over等高级特性的.
4、小结
我们结合之前的概念,来看下这个例子的调用过程. 这里我们假设是通过JMS Gateway来调用ESB服务的.
(1). 从JMS Gateway listener接收到JMS Message.然后把JMS message 转成 ESB Message.
(2). 使用ServiceInvoker API发送 ESB Message到指定的service.
(3). ESBAwareListener接收到ESB Mesage后,找到对应的service,把Message提交给ActionProcessingPipeline来处理.
我们这里讲述了一个简单的调用oneway服务的一个过程.
三、 Jboss ESB的功能点及实例介绍
1、简单的测试通过Jboss ESB服务器进行消息转发的实例
(1)消费者端的代码(即要访问Jboss ESB服务器端的代码,访问者端的代码)
该类的路径在VSS上是:
Jboss ESB实例\实例1\book\src\org\jboss\seam\example\booking
package org.jboss.seam.example.booking;
import java.util.Hashtable;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.jboss.soa.esb.message.format.MessageFactory;
import org.jboss.soa.esb.message.format.MessageType;
import org.apache.log4j.Logger;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.format.MessageFactory;
import org.jboss.soa.esb.message.format.MessageType;
import org.jboss.soa.esb.client.ServiceInvoker;
public class TestESB {
QueueConnection conn;
QueueSession session;
Queue que;
private ServiceInvoker serviceInvoker;
@SuppressWarnings("unchecked")
public void setupConnection() throws JMSException, NamingException
{
Hashtable properties1 = new Hashtable();
properties1.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
properties1.put(Context.URL_PKG_PREFIXES,
"org.jboss.naming:org.jnp.interfaces");
properties1.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
InitialContext iniCtx = new InitialContext(properties1);
Object tmp = iniCtx.lookup("ConnectionFactory");
QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
conn = qcf.createQueueConnection();
que = (Queue) iniCtx.lookup("queue/esb-tb-bankRequestQueue");//("queue/esb-tb-bankRequestQueue");//("queue/quickstart_helloworld_action_Request");
session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
conn.start();
System.out.println("Connection Started");
}
public void stop() throws JMSException
{
conn.stop();
session.close();
conn.close();
}
public void sendAMessage(String msg) throws JMSException {
QueueSender send = session.createSender(que);
ObjectMessage tm = session.createObjectMessage(msg);
send.send(tm);
send.close();
}
public static void main(String args[]) throws Exception
{
TestESB sm = new TestESB();
sm.setupConnection();
sm.sendAMessage("yuexiangcheng");
sm.stop();
}
这是一个带有main()函数的主方法,目的就是为了测试。
properties1.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099"); 这句代码中的IP地址,表示Jboss ESB服务器的IP地址。
iniCtx.lookup("queue/esb-tb-bankRequestQueue"); 这句代码中的
queue/esb-tb-bankRequestQueue表示Jboss ESB服务器上暴露的服务接口。
(2)Jboss ESB服务器端的代码。
该实例的代码在VSS的路径是:
Jboss ESB实例\实例1\HelloESB
Jboss ESB服务器上主要的代码有两部分。
①jboss-esb.xml
代码如下:
<?xml version="1.0"?>
<jbossesb
xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd">
<providers>
<jms-provider name="JBossMQ" connection-factory="ConnectionFactory">
<jms-bus busid="quickstartGwChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/quickstart_helloworld_action_Request"
/>
</jms-bus>
<jms-bus busid="quickstartEsbChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/B"
/>
</jms-bus>
<!--加被岳乡成 -->
<jms-bus busid="creditAgencyRequest">
<jms-message-filter dest-type="QUEUE" dest-name="queue/esb-tb-creditAgencyQueue" />
</jms-bus>
<jms-bus busid="bankResponseGateway">
<jms-message-filter dest-type="QUEUE" dest-name="queue/esb-tb-bankGatewayResponseQueue"/>
</jms-bus>
<jms-bus busid="bankResponseListener">
<jms-message-filter dest-type="QUEUE" dest-name="queue/esb-tb-bankResponseQueue"/>
</jms-bus>
</jms-provider>
</providers>
<services>
<service category="HelloWorld_ActionESB"
name="SimpleListener"
description="Hello World" >
<listeners>
<jms-listener name="JMS-Gateway"
busidref="quickstartGwChannel"
is-gateway="true"
/>
<jms-listener name="JMS-ESBListener"
busidref="quickstartEsbChannel"
/>
</listeners>
<actions mep="OneWay">
<action name="action2"
class="org.jboss.soa.esb.actions.SystemPrintln"
/>
<action name="displayAction"
class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction"
process="displayMessage">
<property name="exceptionMethod" value="exceptionHandler"/>
</action>
<action name="playAction"
class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction"
process="playWithMessage">
<property name="exceptionMethod" value="exceptionHandler"/>
</action>
<action name="notificationAction"
class="org.jboss.soa.esb.actions.Notifier">
<property name="okMethod" value="notifyOK" />
<property name="notification-details">
<NotificationList type="OK">
<target class="NotifyConsole" />
<target class="NotifyQueues">
<messageProp name="quickstart" value="hello_world_action" />
<queue jndiName="queue/quickstart_helloworld_action_Response"/>
</target>
</NotificationList>
</property>
</action>
</actions>
</service>
<!--加被岳乡成 -->
<service category="tbCreditAGency" name="creditagency" description="Credit Agency Service">
<listeners>
<jms-listener name="trailblazer-jmscreditagency"
busidref="creditAgencyRequest"
maxThreads="1"/>
</listeners>
<actions>
<action class="org.jboss.soa.esb.samples.quickstart.testbyyuexiangcheng.CreditAgencyActions"
process="processCreditRequest" name="fido">
</action>
</actions>
</service>
<service category="tbJmsbank" name="jmsbankreplies" description="Trailblazer Bank Reply Service">
<listeners>
<jms-listener name="trailblazer-jmsbank"
busidref="bankResponseGateway"
maxThreads="1"
is-gateway="true"/>
<jms-listener name="trailblazer-jmsbankreplies"
busidref="bankResponseListener"
maxThreads="1"/>
</listeners>
<actions>
<action class="org.jboss.soa.esb.samples.quickstart.testbyyuexiangcheng.BankResponseActions"
process="processResponseFromJMSBank" name="pepe"/>
</actions>
</service>
</services>
</jbossesb>
上面红色部分表示Jboss ESB服务器上暴露的上面要调用的服务的接口的过程。
当通道接收到消息时,就会被拦截,就会转到上面绿色区域定义的类中去处理。
②Action类
该类的代码在VSS上的路径为:
Jboss ESB实例\实例1\HelloESB\src\org\jboss\soa\esb\samples\quickstart\testbyyuexiangcheng
package org.jboss.soa.esb.samples.quickstart.testbyyuexiangcheng;
import java.util.Random;
import org.apache.log4j.Logger;
import org.jboss.soa.esb.actions.AbstractActionLifecycle;
import org.jboss.soa.esb.helpers.ConfigTree;
import org.jboss.soa.esb.message.Message;
import org.jboss.soa.esb.message.format.MessageFactory;
import org.jboss.soa.esb.message.format.MessageType;
import org.jboss.soa.esb.util.Util;
public class CreditAgencyActions extends AbstractActionLifecycle {
protected ConfigTree _config;
private static Logger _logger = Logger.getLogger(CreditAgencyActions.class);
public CreditAgencyActions(ConfigTree config) { _config = config; }
public Message noOperation(Message message) { return message; }
public Message processCreditRequest(Message message) throws Exception{
_logger.debug("message received: " + Util.serialize(message) );
String csvData = (String) message.getBody().get();
_logger.debug("csv data received: " + csvData);
//generate a random score between 1 and 10
Random rand = new Random();
int n = 10;
int score = rand.nextInt(n+1);
//send back the reply
Message replyMessage = MessageFactory.getInstance().getMessage(MessageType.JBOSS_XML);
_logger.info("CreditAgency sending back a credit score of " + score);
replyMessage.getBody().add(Integer.toString(score));
return replyMessage;
}
public Message debugMessage(Message message) throws Exception{
_logger.debug("message received in processCreditRequest with message: " + Util.serialize(message));
return message;
}
}
2、 读取外部文档的数据,发送到Jboss ESB服务器上并且进行数据转换。
该实例的工程在VSS上的路径是:
Jboss ESB实例\实例2\James
该实例主要要注意三点:
①在工程中要提供一个要读取的文件,比如该实例中的SampleOrder.csv文件。
该文件在VSS上的路径为:
Jboss ESB实例\实例2\James\src\test
当然Jboss ESB还可以读取多种类型的文件,比如.xml文档等。
②调用者端的代码
该类在VSS的路径如下:
Jboss ESB实例\实例2\James\src\test
package test;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Hashtable;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.jboss.soa.esb.util.FileUtil;
public class testCvsMassage {
QueueConnection conn;
QueueSession session;
Queue que;
public void setupConnection() throws JMSException, NamingException
{
Hashtable properties1 = new Hashtable();
properties1.put(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
properties1.put(Context.URL_PKG_PREFIXES,
"org.jboss.naming:org.jnp.interfaces");
properties1.put(Context.PROVIDER_URL, "jnp://127.0.0.1:1099");
// InitialContext iniCtx = new InitialContext(properties1);
// Object tmp = iniCtx.lookup("ConnectionFactory");
// QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
// conn = qcf.createQueueConnection();
// que = (Queue) iniCtx.lookup("queue/esb-tb-bankRequestQueue");//("queue/esb-tb-bankRequestQueue");//("queue/quickstart_helloworld_action_Request");
// session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
// conn.start();
// System.out.println("Connection Started");
InitialContext iniCtx = new InitialContext(properties1);
Object tmp = iniCtx.lookup("ConnectionFactory");
QueueConnectionFactory qcf = (QueueConnectionFactory) tmp;
conn = qcf.createQueueConnection();
que = (Queue) iniCtx.lookup("queue/quickstart_transform_CSV2XML_gw");
session = conn.createQueueSession(false, QueueSession.AUTO_ACKNOWLEDGE);
conn.start();
System.out.println("Connection Started");
}
public void stop() throws JMSException
{
conn.stop();
session.close();
conn.close();
}
public void sendAMessage(String fileName) throws JMSException, FileNotFoundException, IOException {
QueueSender send = session.createSender(que);
ObjectMessage tm;
File file = new File(fileName);
if(!file.exists()) {
throw new IllegalArgumentException("Input message file [" + file.getAbsolutePath() + "] not found.");
}
String message = FileUtil.readTextFile(file);
tm = session.createObjectMessage(message);
tm.setStringProperty("jbesbfilename", "transformedmessageCSV2XML.log");
send.send(tm);
send.close();
System.out.println("*** Switch back to the ESB Java console now to see '" + fileName + "' before and after the transformation...");
}
public static void main(String args[]) throws Exception
{
testCvsMassage sm = new testCvsMassage();
sm.setupConnection();
sm.sendAMessage("SampleOrder.csv");
sm.stop();
}
}
上面的这句代码sm.sendAMessage("SampleOrder.csv");表示读取SampleOrder.csv文件中的内容。
③Jboss ESB端的代码
该代码在VSS上的路径为:
Jboss ESB实例\实例2\HelloESB\src\META-INF
Ⅰ、jboss-esb.xml
<?xml version="1.0"?>
<jbossesb
xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd">
<providers>
<jms-provider name="JBossMQ" connection-factory="ConnectionFactory">
<jms-bus busid="quickstartGwChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/quickstart_helloworld_action_Request"
/>
</jms-bus>
<jms-bus busid="quickstartEsbChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/B"
/>
</jms-bus>
<!--加被岳乡成 -->
<jms-bus busid="creditAgencyRequest">
<jms-message-filter dest-type="QUEUE" dest-name="queue/esb-tb-creditAgencyQueue" />
</jms-bus>
<jms-bus busid="bankResponseGateway">
<jms-message-filter dest-type="QUEUE" dest-name="queue/esb-tb-bankGatewayResponseQueue"/>
</jms-bus>
<jms-bus busid="bankResponseListener">
<jms-message-filter dest-type="QUEUE" dest-name="queue/esb-tb-bankResponseQueue"/>
</jms-bus>
<!--加被岳乡成 -->
<jms-bus busid="quickstartCSVGwChannel">
<jms-message-filter dest-type="QUEUE" dest-name="queue/quickstart_transform_CSV2XML_gw" />
</jms-bus>
<jms-bus busid="quickstartCSVEsbChannel">
<jms-message-filter dest-type="QUEUE" dest-name="queue/quickstart_transform_CSV2XML_esb" />
</jms-bus>
</jms-provider>
</providers>
<services>
<service category="HelloWorld_ActionESB"
name="SimpleListener"
description="Hello World" >
<listeners>
<jms-listener name="JMS-Gateway"
busidref="quickstartGwChannel"
is-gateway="true"
/>
<jms-listener name="JMS-ESBListener"
busidref="quickstartEsbChannel"
/>
</listeners>
<actions mep="OneWay">
<action name="action2"
class="org.jboss.soa.esb.actions.SystemPrintln"
/>
<action name="displayAction"
class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction"
process="displayMessage">
<property name="exceptionMethod" value="exceptionHandler"/>
</action>
<action name="playAction"
class="org.jboss.soa.esb.samples.quickstart.helloworldaction.MyJMSListenerAction"
process="playWithMessage">
<property name="exceptionMethod" value="exceptionHandler"/>
</action>
<action name="notificationAction"
class="org.jboss.soa.esb.actions.Notifier">
<property name="okMethod" value="notifyOK" />
<property name="notification-details">
<NotificationList type="OK">
<target class="NotifyConsole" />
<target class="NotifyQueues">
<messageProp name="quickstart" value="hello_world_action" />
<queue jndiName="queue/quickstart_helloworld_action_Response"/>
</target>
</NotificationList>
</property>
</action>
</actions>
</service>
<!--加被岳乡成 -->
<service category="tbCreditAGency" name="creditagency" description="Credit Agency Service">
<listeners>
<jms-listener name="trailblazer-jmscreditagency"
busidref="creditAgencyRequest"
maxThreads="1"/>
</listeners>
<actions>
<action class="org.jboss.soa.esb.samples.quickstart.testbyyuexiangcheng.CreditAgencyActions"
process="processCreditRequest" name="fido">
</action>
</actions>
</service>
<service category="tbJmsbank" name="jmsbankreplies" description="Trailblazer Bank Reply Service">
<listeners>
<jms-listener name="trailblazer-jmsbank"
busidref="bankResponseGateway"
maxThreads="1"
is-gateway="true"/>
<jms-listener name="trailblazer-jmsbankreplies"
busidref="bankResponseListener"
maxThreads="1"/>
</listeners>
<actions>
<action class="org.jboss.soa.esb.samples.quickstart.testbyyuexiangcheng.BankResponseActions"
process="processResponseFromJMSBank" name="pepe"/>
</actions>
</service>
<!--加被岳乡成 -->
<service category="QuickstartTransformCSV" name="SimpleListener" description="Hello World">
<listeners>
<jms-listener name="CSVJMS-Gateway" busidref="quickstartCSVGwChannel" is-gateway="true"/>
<jms-listener name="CSVquickstart" busidref="quickstartCSVEsbChannel"/>
</listeners>
<actions mep="OneWay">
<!--
Note that with this quickstart, the transformation is broken into 2 transforms; CSV to XML
and XML to XML. These 2 transformations could easly be merged into a single transform, saving
on XML processing.
-->
<action name="print-before" class="org.jboss.soa.esb.actions.SystemPrintln">
<property name="message" value="[transform_CSV2Smooks_Intermediate_format] Message before CVS to XML transformation" />
</action>
<!--
Transform 1: Source CSV to Canonical XML...
-->
<action name="transform-from-csv" class="org.jboss.soa.esb.smooks.SmooksAction">
<property name="smooksConfig" value="/smooks-res.xml" />
<property name="messageProfile" value="source-csv" />
</action>
<action name="print-after-csv-tranform" class="org.jboss.soa.esb.actions.SystemPrintln">
<property name="message" value="[transform_CSV2Smooks_Intermediate_format] Message after CVS to XML transformation" />
</action>
<!--
Transform 2: Canonical XML to target XML...
-->
<action name="transform-to-xml" class="org.jboss.soa.esb.smooks.SmooksAction">
<property name="smooksConfig" value="/smooks-res.xml" />
<property name="messageProfile" value="canonical-xml" />
</action>
<action name="print-after-xml-transform" class="org.jboss.soa.esb.actions.SystemPrintln">
<property name="message" value=">>>> Message after Smooks intermediate xml -> target xml : " />
</action>
</actions>
</service>
</services>
</jbossesb>
上面绿色区域的代码表示Jboss ESB服务器把.cvs文件转换为.xml文件的过程。
<action name="transform-from-csv" class="org.jboss.soa.esb.smooks.SmooksAction">这句代码中的class="org.jboss.soa.esb.smooks.SmooksAction"是Jboss ESB提供的。
Jboss ESB提供了好多关于数据转换的例子,请详细参考。
3、 基于内容的路由
关于内容的路由,我在这里就不详细说了,请详细参考:
jbossesb-4.4.GA\samples\quickstarts下的
4、 Jboss ESB的业务流
关于Jboss ESB的业务流,我在这里也不详细说了,请详细参考:
jbossesb-4.4.GA\samples\quickstarts下的
5、 以JMS为消息在Jboss ESB上的一个应用。
该实例的源码在VSS上的路径是:
SOA\ JMS在Jboss ESB中的应用
这个实例包括三个部分<1>Jboss ESB服务器端(192.168.1.101 esb文件夹下的工程)。<2>服务消费者端(192.168.1.111文件夹下的工程)。<3>服务提供者端(192.168.1.121文件夹下的工程)。
①Jboss ESB服务器端
Ⅰ、Jboss-esb.xml文件
该文件在VSS上的路径为:
JMS在Jboss ESB中的应用\192.168.1.101 esb\Medicare_esb\src\META-INF
<?xml version = "1.0" encoding = "UTF-8"?>
<jbossesb xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd" parameterReloadSecs="5">
<providers>
<jms-provider name="JBossMQ" connection-factory="ConnectionFactory">
<jms-bus busid="quickstartGwChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/quickstart_transform_pojo_gw"
/>
</jms-bus>
<jms-bus busid="quickstartEsbChannel">
<jms-message-filter
dest-type="QUEUE"
dest-name="queue/quickstart_transform_pojo_esb"
/>
</jms-bus>
</jms-provider>
</providers>
<services>
<service
category="MyTransformationServicesESB"
name="MyFirstTransformationServiceESB"
description="ESB: Takes XML in and produces a POJO">
<listeners>
<jms-listener name="JMS-Gateway"
busidref="quickstartGwChannel"
is-gateway="true"
/>
<jms-listener name="jmsTransformer"
busidref="quickstartEsbChannel"
/>
</listeners>
<actions mep="OneWay">
<action name="displayBeforeTransformer"
class="org.jboss.soa.esb.samples.medicare.MyJMSListenerAction"
process="displayMessage"
/>
<action name="returnToSender"
class="org.jboss.soa.esb.samples.medicare.MyJMSListenerAction" process="sendResponse" />
<!--
<action name="receiveMsg"
class="org.jboss.soa.esb.samples.medicare.ReceiveMessage" process="displayMessage" />
<action name="receiveMsg"
class="org.jboss.soa.esb.samples.medicare.ReceiveMessage" process="sendResponse" />
-->
</actions>
</service>
</services>
</jbossesb>
Ⅱ、 在Jboss ESB服务器上的Action
在VSS上的路径为:
JMS在Jboss ESB中的应用\192.168.1.101 esb\Medicare_esb\src\org\jboss\soa\esb\samples\medicare
这个文件夹下的内容就是消息的拦截器,负责对消息的拦截。详细内容请查看相关的代码。
②消费者端的代码。
该工程在VSS上的路径为:
JMS在Jboss ESB中的应用\192.168.1.121
相关的代码请详细参考该工程。
③提供者端的代码。
该工程在VSS上的路径为:
JMS在Jboss ESB中的应用\192.168.1.111
相关的代码请详细参考该工程。
6、 以Web Service为基础在Jboss ESB上的一个应用。
该工程在VSS上的路径为:
SOA\SOA(V1.2)
这个实例也包括三个部分<1>Jboss ESB服务器端(Esb Service(192.168.1.101)文件夹下的工程)。<2>服务消费者端(Request endpoint(192.168.1.112)文件夹下的工程)。<3>服务提供者端(Respose endpoint(192.168.1.111)文件夹下的工程)。
服务消费者端和服务提供者端我已经在另一个文档中《Web Service简介及开发实例》中做了详细的介绍。
现在我只简单的讨论一下再Jboss ESB服务器端的代码。
①先看Jboss-esb.xml文件
该文件在VSS上的路径为:
SOA(V1.2)\Esb Service(192.168.1.101)\WebService\src\META-INF
<?xml version = "1.0" encoding = "UTF-8"?>
<jbossesb
xmlns="http://anonsvn.labs.jboss.com/labs/jbossesb/trunk/product/etc/schemas/xml/jbossesb-1.0.1.xsd"
parameterReloadSecs="5">
<providers>
<jms-provider name="JBossMQ" connection-factory="ConnectionFactory">
<jms-bus busid="quickstartGwChannel">
<jms-message-filter dest-type="QUEUE" dest-name="queue/quickstart_webservice_producer_gw"/>
</jms-bus>
<jms-bus busid="quickstartEsbChannel">
<jms-message-filter dest-type="QUEUE" dest-name="queue/quickstart_webservice_producer_esb"/>
</jms-bus>
</jms-provider>
<jbr-provider name="JBR-Http" protocol="http" >
<jbr-bus busid="Http-1" port="8765" />
</jbr-provider>
<jbr-provider name="JBR-Socket" protocol="socket" host="localhost">
<jbr-bus busid="Socket-1" port="8888" />
</jbr-provider>
</providers>
<services>
<service category="MyServiceCategory" name="MyWSProducerService" description="WS Frontend speaks natively to the ESB">
<listeners>
<jms-listener name="JMS-Gateway" busidref="quickstartGwChannel" is-gateway="true"/>
<jbr-listener name="Http-Gateway" busidref="Http-1" is-gateway="true"/>
<jbr-listener name="Socket-Gateway" busidref="Socket-1" is-gateway="true"/>
<jms-listener name="JMS-ESBListener" busidref="quickstartEsbChannel"/>
</listeners>
<actions>
<action name="print-before" class="org.jboss.soa.esb.actions.SystemPrintln">
<property name="message"
value="[Quickstart_webservice_producer] BEFORE invoking jbossws endpoint"/>
</action>
<action name="JBossWSAdapter" class="org.jboss.soa.esb.actions.soap.SOAPProcessor">
<property name="jbossws-endpoint" value="GoodbyeWorldWS"/>
</action>
<action name="print-after" class="org.jboss.soa.esb.actions.SystemPrintln">
<property name="message"
value="[Quickstart_webservice_producer] AFTER invoking jbossws endpoint"/>
</action>
<action name="testStore" class="org.jboss.soa.esb.actions.TestMessageStore"/>
</actions>
</service>
</services>
</jbossesb>
②Jboss ESB服务器上的Action类,代码如下:
该类在VSS上的路径为:
SOA(V1.2)\EsbService(192.168.1.101)\WebService\src\org\jboss\soa\esb\samples\quickstart\webserviceproducer\webservice
代码如下:
package org.jboss.soa.esb.samples.quickstart.webserviceproducer.webservice;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.stream.StreamResult;
/**
* @author
*/
@WebService(name = "GoodbyeWorldWS", targetNamespace="http://webservice_producer/goodbyeworld")
public class GoodbyeWorldWS {
public static final String INDEXOFOBJECTSTART = "<Hotel>";
public static final String INDEXOFOBJECTEND = "</Hotel>";
public static final int OBJECTSTARTFLAGLENGTH = INDEXOFOBJECTSTART.length();
public static final int OBJECTENDFLAGLENGTH = INDEXOFOBJECTEND.length();
@WebMethod
@WebResult(name="ListHotel")
public String sayGoodbye(@WebParam(name="message") String message){
try {
//传送参数需要创建Name
SOAPFactory soapFactory = SOAPFactory.newInstance();
//Next, create the actual message
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message1 = messageFactory.createMessage();
//Create objects for the message parts
SOAPPart soapPart = message1.getSOAPPart();
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
//Populate the body
//Create the main element and namespace
SOAPElement bodyElement =
body.addChildElement(envelope.createName("getHotelObject" ,
"serch",
"http://tower/ehr_DEV"));
bodyElement.setEncodingStyle(SOAPConstants.URI_NS_SOAP_ENCODING);
//传送参数新建一个Name对象
Name name = soapFactory.createName("arg0");
SOAPElement symbol = bodyElement.addChildElement(name);
symbol.addTextNode(message);
//Add content
//Save the message
message1.saveChanges();
//Send the message and get a reply
//Set the destination
//Send the message
List<String> destinationList = readTxtFile("D:/webServiceConfig.txt");
String resultString = getResultString(destinationList,message1);
if("".equals(resultString)){
return "";
}else{
return resultString;
}
} catch(Exception e) {
System.out.println(e.getMessage());
}
return "";
}
public static List<String> readTxtFile(String fileName){
String read;
FileReader fileread;
List<String> l = new ArrayList<String>();
try {
fileread = new FileReader(fileName);
BufferedReader bufread = new BufferedReader(fileread);
try {
while ((read = bufread.readLine()) != null) {
l.add(read);
}
} catch (IOException e) {
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return l;
}
public static String getResultString(List<String> destinationList,SOAPMessage message){
try {
String resultString = "";
for(int i = 0;i<destinationList.size();i++){
String destination = destinationList.get(i);
SOAPConnectionFactory soapConnFactory = SOAPConnectionFactory.newInstance();
SOAPConnection connection = soapConnFactory.createConnection();
SOAPMessage reply = connection.call(message, destination);
String stringBady = getSOAPMessageStringBady(reply);
resultString = resultString + stringBady;
connection.close();
}
return resultString;
} catch (UnsupportedOperationException e) {
e.printStackTrace();
} catch (SOAPException e) {
e.printStackTrace();
}
return "";
}
public static String getSOAPMessageStringBady(SOAPMessage reply) {
try {
String sb = "";
Source source = reply.getSOAPPart().getContent();
Transformer transformer = TransformerFactory.newInstance().newTransformer();
ByteArrayOutputStream myOutStr = new ByteArrayOutputStream();
StreamResult res = new StreamResult();
res.setOutputStream(myOutStr);
transformer.transform(source,res);
String temp = myOutStr.toString().trim();
int indexOfObjectStart = temp.indexOf(INDEXOFOBJECTSTART);
if(indexOfObjectStart==-1){
return sb;
}else{
int indexOfObjectEnd = temp.lastIndexOf(INDEXOFOBJECTEND);
sb = temp.substring(indexOfObjectStart,indexOfObjectEnd+OBJECTENDFLAGLENGTH);
return sb;
}
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerFactoryConfigurationError e) {
e.printStackTrace();
} catch (SOAPException e) {
e.printStackTrace();
} catch (TransformerException e) {
e.printStackTrace();
}
return "";
}
}
- Jboss_ESB简介及开发实例.rar (643 KB)
- 下载次数: 747
评论
5 楼
yingyingda1987
2009-11-11
好不容易答对题给留个言,开始学习。
4 楼
tkivdrip
2009-10-21
岳乡成 写道
把Excel文件 Word文档 读成字符流,发送一个字符流。
哦 好的 我原来用 AXIS 它是用DataHandler 来封装文件的 不过 1.4 版本 时还需要写 wsd文件
3 楼
岳乡成
2009-09-26
把Excel文件 Word文档 读成字符流,发送一个字符流。
2 楼
tkivdrip
2009-09-25
如果要在应用中传递文件怎么办呢 例如经常的 Excel 文件 Word文档
1 楼
antrt
2009-08-21
祝贺国内最专业的JBoss中文社区开通运行http://jboss.cn
近年来,在Java企业级应用领域,特别是J2EE应用服务器领域,JBoss取得了巨大的成功。从一个专注于EJB容器实现的开源项目到现如今Java 开源企业级应用服务领域的巨头的转变仅仅花了不到7年的时间,它的发展速度相当的惊人,并且在市场占有率和服务满意度上丝毫不逊色与其它的非开源竞争对手 (IBM WebSphere,BEA WebLogic,Oracle Application Server等),创造了Java开源领域的又一个神话。作为J2EE这个产业链上的一个疯狂淘金者,JBoss在它7年的发展历程中,不仅见证了 J2EE的发展,同时也在J2EE的发展和推广过程中占据着举足轻重的分量。
http://jboss.cn中文社区旨在建立国内一流的JBoss专业论坛,主要讨论企业或者个人在JBoss使用中遇到的问题,给大家提供一个交流的平台!现正式开通运行,诚寻各界JBoss技术人员加入成为版主。欢迎联系: Email: jboss@jboss.cn MSN: jboss@jboss.cn
近年来,在Java企业级应用领域,特别是J2EE应用服务器领域,JBoss取得了巨大的成功。从一个专注于EJB容器实现的开源项目到现如今Java 开源企业级应用服务领域的巨头的转变仅仅花了不到7年的时间,它的发展速度相当的惊人,并且在市场占有率和服务满意度上丝毫不逊色与其它的非开源竞争对手 (IBM WebSphere,BEA WebLogic,Oracle Application Server等),创造了Java开源领域的又一个神话。作为J2EE这个产业链上的一个疯狂淘金者,JBoss在它7年的发展历程中,不仅见证了 J2EE的发展,同时也在J2EE的发展和推广过程中占据着举足轻重的分量。
http://jboss.cn中文社区旨在建立国内一流的JBoss专业论坛,主要讨论企业或者个人在JBoss使用中遇到的问题,给大家提供一个交流的平台!现正式开通运行,诚寻各界JBoss技术人员加入成为版主。欢迎联系: Email: jboss@jboss.cn MSN: jboss@jboss.cn
相关推荐
### jbossesb开发手册知识点概述 #### 一、引言 JBoss ESB(Enterprise Service Bus)是一款开源的企业服务总线解决方案,旨在为应用程序之间的通信提供一个灵活且可扩展的基础架构。本手册旨在帮助初学者理解JBoss...
JBoss ESB(Enterprise Service Bus)是Red Hat公司开发的一款开源服务总线,它提供了一种中间件解决方案,用于构建松散耦合、灵活且可扩展的企业级应用。作为新手入门,理解JBoss ESB的基本概念、功能以及如何操作...
《JBoss ESB 开发指南》是一本专为开发者设计的详实教程,旨在提供关于最新版本JBoss ESB(企业服务总线)的全面编程和开发指导。JBoss ESB是一款开源的企业服务总线解决方案,它允许在分布式环境中集成各种服务和...
"JBossESB学习笔记"中可能涵盖了以下主题: - JBoss ESB的安装与配置 - 创建、部署和测试ESB服务 - 使用ESB进行消息路由和转换的实践 - AOP在JBoss ESB中的应用示例 - ESB的监控与故障排查 - 高级特性,如工作流...
《JBoss_ESB_Beginners_Guide》是一本由Kevin Conner、Tom Cunningham、Len DiMaggio和Magesh Kumar B共同编写的实用指南,旨在帮助初学者使用JBoss ESB开发服务导向的应用程序。 书中首先强调了基于服务的体系结构...
- **JBoss ESB文档库**:包含各种版本的用户指南、开发指南和技术白皮书。 - **最新JBoss Tools/Developer Studio文档构建**:提供了最新的JBoss工具集的安装和使用指南。 #### 二、JBoss ESB支持 本节将详细介绍...
本文档实例Dome基于的技术是:JSF + Jboss-seam-2.1.1.GA. + Jboss 4.2.3 GA + EJB 3.0 + Jboss ESB + My-SQL-5.0.8 + JDK 1.6
在软件开发中,企业服务总线(Enterprise Service Bus,ESB)是一种架构模式,它提供了一种在分布式系统中集成和交互服务的方式。C#中的Remote技术是.NET框架提供的一个关键组件,用于实现跨进程通信,它在ESB中扮演...
在这个例子中,需要用到Spring的相关jar包,比如`jbossesb-spring.jar`和`spring-2.5.6.SEC01.jar`。这些jar包可以在下载的JBoss ESB安装包内找到。Spring是一个流行的Java企业级应用框架,它提供了依赖注入、AOP...
在企业服务总线(Enterprise Service Bus,简称ESB)的架构中,Custom_Action作为一项关键特性,允许开发人员自定义处理逻辑,增强了ESB的灵活性与功能多样性。本知识点详细解析ESB应用中的Custom_Action概念及其在...
此外,文档中还包含了JBoss ESB入门指南的内容,该指南由JBoss ESB开发团队和社区编写。 总之,**Red Hat JBoss Enterprise SOA Platform 5 SOA Getting Started Guide**为管理员和开发者提供了一份详尽的指南,...
在开发和设计ESB解决方案时,理解并有效地利用Message Filters可以显著优化系统的性能和功能。通过结合其他ESB特性,如路由、转换和事务管理,可以构建出强大且灵活的分布式系统。在JBoss ESB中,开发者可以通过图形...
### WS-BPEL:ESB开发协议详解 #### 一、引言 WS-BPEL(Web Services Business Process Execution Language)是一种用于定义业务流程的标准语言,尤其适用于基于Web服务的应用集成场景。它允许开发者通过组合现有...
JBoss Fuse是一个强大的开源企业服务总线(Enterprise Service Bus,ESB),它将多个关键的开源组件集成到一个单一的、轻量级的容器中,为企业的应用集成提供了灵活且可扩展的解决方案。该产品源自Red Hat公司,其...
《JBoss Drools Business Rules》是一本由 Paul Browne 编写的书籍,首次出版于2009年,该书旨在介绍如何利用 JBoss Drools 捕获、自动化及重用业务流程。本书版权属于 Packt Publishing,并在 Birmingham 和 Mumbai...