客戶端服務軟件包
通過指引WSDL編譯器到應用服務器提供的WSDL上可自動生成客戶端服務軟件包。這個軟件包包含許多類。我們需要修改的唯一類就是客戶端Stub類。同樣地,服務器Web 服務軟件包也包含類Tie,它可將Web服務請求綁定到EJB方法上,客戶端Stub類為每個服務商業方法的每個客戶端配備一個方法。
服務Stub類的名稱為 <ServiceName>ServantInterface_Stub,其中<ServiceName>就是服務名。我們看看類XactServiceServantInterface_Stub 內的submitWork()方法:
/*
* Implementation of submitWork
*/
public java.lang.String submitWork(java.lang.String string_1)
throws java.rmi.RemoteException {
try {
StreamingSenderState _state = _start(_handlerChain);
InternalSOAPMessage _request = _state.getRequest();
_request.setOperationCode(SubmitWork_OPCODE);
Xact.XactServiceServantInterface_SubmitWork_RequestStruct
_myXactServiceServantInterface_SubmitWork_RequestStruct =new Xact.XactServiceServantInterface_SubmitWork_RequestStruct();
_myXactServiceServantInterface_SubmitWork_RequestStruct.setString_1(string_1);
SOAPBlockInfo _bodyBlock = new SOAPBlockInfo(ns1_SubmitWork_SubmitWork_QNAME);
_bodyBlock.setValue(_myXactServiceServantInterface_SubmitWork_RequestStruct);
_bodyBlock.setSerializer(myXactServiceServantInterface_SubmitWork_RequestStruct_SOAPSerializer);
_request.setBody(_bodyBlock);
_state.getMessageContext().setProperty(HttpClientTransport.HTTP_SOAPACTION_PROPERTY, "");
Serializer.attachPendingReportToMessage(_state.getMessageContext());
_send((String) _getProperty(ENDPOINT_ADDRESS_PROPERTY), _state);
Xact.XactServiceServantInterface_SubmitWork_ResponseStruct
_myXactServiceServantInterface_SubmitWork_ResponseStruct = null;
Object _responseObj = _state.getResponse().getBody().getValue();
if (_responseObj instanceof SOAPDeserializationState) {
_myXactServiceServantInterface_SubmitWork_ResponseStruct =
(Xact.XactServiceServantInterface_SubmitWork_ResponseStruct)
((SOAPDeserializationState)_responseObj).getInstance();
} else {
_myXactServiceServantInterface_SubmitWork_ResponseStruct =(Xact.XactServiceServantInterface_SubmitWork_ResponseStruct)responseObj;
}
return _myXactServiceServantInterface_SubmitWork_ResponseStruct
.getResult();
} catch (RemoteException e) {
// Let this one through unchanged
throw e;
} catch (JAXRPCException e) {
throw new RemoteException(e.getMessage(), e);
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw (RuntimeException)e;
} else {
throw new RemoteException(e.getMessage(), e);
}
}
}
在上述的代碼中,我們在_send()之前立即添加了下面的單行:
Serializer.attachPendingReportToMessage(_state.getMessageContext());
如果沒有待解決的客戶端報告需要發送,attachPendingReportToMessage 就返回。否則,它將當前報告連在XML之後並將它當作文本附件添加到SOAP信息中。我們對其他的商業方法也作了同樣的修改,在它們的每個_send()調用之前立即添加了上面的代碼行。
信息驅動的 bean
現在我們可以記錄客戶端事務響應次數並將它們通過HTTP/SOAP的運輸,我們需要一條可以在應用服務器上處理這些報告的方法。最適合完成這個任務的就是信息驅動的EJB組件因為響應次數報告應該異步地搬運到用戶事務上。Web 服務類 Tie將XML ClientReport對象列隊。下面的EJB代碼可讀取和處理這些報告:
package TestBean;
import javax.jms.*;
import javax.ejb.*;
import Payload.*;
/**
* Created May 23, 2003 6:01:04 PM
* Code generated by the Sun ONE Studio EJB Builder
* @author Brian
*/
public class TestMDBBean implements
javax.ejb.MessageDrivenBean, javax.jms.MessageListener {
private transient javax.ejb.MessageDrivenContext context;
/**
* @see javax.ejb.MessageDrivenBean
#setMessageDrivenContext
(javax.ejb.MessageDrivenContext)
*/
public void setMessageDrivenContext
(javax.ejb.MessageDrivenContext aContext) {
context=aContext;
}
/**
* See section 15.4.4 of the EJB 2.0 specification
*/
public void ejbCreate() {
}
/**
* @see javax.jms.MessageListener#onMessage(javax.jms.Message)
*/
public void onMessage(javax.jms.Message aMessage) {
TextMessage msg = null;
try {
if (aMessage instanceof TextMessage) {
msg = (TextMessage) aMessage;
String crXML = msg.getText();
//System.out.println("MESSAGE BEAN: Message");
//System.out.println(crXML);
ClientReport cr = Serializer.ClientReportXML(crXML);
System.out.println
("Took:" + String.valueOf(cr.getClientElapsedMS()) +
" MS. for: " + cr.getType().toString());
} else {
System.out.println("Message of wrong type: " +
aMessage.getClass().getName());
}
} catch (JMSException e) {
System.err.println("MessageBean.onMessage: " +
"JMSException: " + e.toString());
context.setRollbackOnly();
} catch (Throwable te) {
System.err.println("MessageBean.onMessage: " +
"Exception: " + te.toString());
}
}
/**
* @see javax.ejb.MessageDrivenBean#ejbRemove()
*/
public void ejbRemove() {
}
}
通常,報告會登記到數據庫中用於在線分析和報告。在本例中,我們將報告打印到控制台以便演示客戶端如何接收它們的過程。方法 onMessage()使用Serializer.ClientReportXML() 創建來自列隊等待的XML字符串的ClientReport對象。我們在這裡做一下解碼工作以便可以將處理次數保存在事務處理工作流程中。
樣品實現
用來運行樣品應用的所有代碼都可從Resources處下載。我開發代碼時使用的工具是Sun ONE Studio, Enterprise Edition Update 1。 這個工具箱包括一個J2EE開發IDE 和一個J2EE應用服務,它的Web 服務設備采用了嵌入式的Java Web Service Developer Pack 1.0_01。 Resources 處有自由下載URL的信息和到開發者文檔的鏈接。
建立和配置服務器應用
這部分假設你已經了解Sun ONE 應用框架的應用知識。另外,本指示假設你使用微軟的Windows系統。配置的完整源代碼預先已經建立。Web服務客戶端和服務器軟件包已經生成(並為了次數報告的連續化做好修改),但是下面的描述也包含了關於如何在Sun ONE IDE之內建立組件的一些背景知識。
要建立和配置服務器應用,首先,在Windows 開始菜單中選擇程序,再在程序中選擇Sun Microsystems,然後依次選擇Sun ONE Application Server和 Start Application Server項。
實用類似的Windows 命令可啟動IDE。右擊資源管理器中的“運行”鍵,點擊安裝的服務器,並保證應用服務的運行實例已經設置為默認服務器。
解壓下載的工具包到某個目錄下並右擊IDE資源管理器窗口的文件系統圖標。使用Mount/Local Directory 對話框,實現兩個不同的安裝命令:
<download directory>/Metrics/Metrics 打開Payload軟件包。
<download directory>/Metrics/TransactionServer 打開服務器EJB、 Web 模塊、和服務器應用組件。
EJBModule_Xact 為應用服務原型,它包括三個商業方法:submitWork()、 checkWork()、和getResult()。要創建同一目錄下的TransactionProcessor/Xact_Module可右擊 EJB 然後依次選擇New、JSP & Servlet、和Web Module命令。創建TransactionService軟件包中的Web 模塊可依次選擇New、Web Services、和 Web Module 向導,然後選擇EJB組件的Java方法作為源程序。右擊Web Module並選擇Create New Web Service項可自動創建TransactionService/XactServiceGenServer。但是在右擊之前請小心,因為它會關閉添加到類Tie上的Serialize 調用。
創建應用程序TransactionServerApp 需要依次選擇New、J2EE、和Application命令。 右擊空的應用,選擇Add Modules 項,然後選擇EJBModule_Xact 和Xact_Service Web Module項就可添加組件到應用程序上。
本部分給出了如何建立代碼組件的一般思想。你需要將這些組件配置到你的應用服務上。在IDE之內,右擊TransactionServerApp即可進行配置。檢查一下應用服務系統控制台以保證它的配置正確。