Jboss ESB簡介及開發實例

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 "";

}

}
發佈了14 篇原創文章 · 獲贊 0 · 訪問量 1511
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章