第一章 J2EEWeb服務客戶端質量報告(2 / 3)

Report.setClientID(ClientIdentifier.toString());

Report.setClientStartDateTime(newDate());

}

publicvoidCommitTransaction(StringtransactionID,Stringtype,Stringstatus){

Report.setTransactionID(transactionID);

Report.setStatus(status);

Report.setType(type);

longl1=Report.getClientStartDateTime().getTime();

longl2=newDate().getTime();

Report.setClientElapsedMS(l2-l1);

LastReport=Report;

Report=null;

}

/**GetterforpropertycurrentReport

*@returnValueofpropertycurrentReport

*/

publicstaticClientReportgetReport(){

ClientReportlast=LastReport;

LastReport=null;

returnlast;

}

/**SetterforpropertycurrentReport

*@paramcurrentReportNewvalueofpropertycurrentReport

*/

publicvoidsetReport(ClientReportReport){

this.LastReport=Report;

}

}

CurrentReport保存進行中的事務的當前ClientReport。它也保存LastReport,也就是一個完成的事務。它還產生一個作為唯一設備標記符使用的客戶端標記符--在實際的應用中,這個客戶端標記符可被修改為全局的唯一標記符。CurrentReport是非線程安全的;我們假設在客戶端應用中隻有一個單線程執行服務器事務。

beginTransaction()創建一個新的ClientReport,設置它的客戶端標記符並且記錄事務起始時間。commitTransaction()計算事務的毫秒數並且保存最後一個調用的副本,以方便以後的到服務器的上傳。

Serializer是Payload軟件包中的第三個類。客戶端和服務器都要使用者各類。客戶端使用attachPendingReportToMessage()連載待解決的當作XML的ClientReport,並將它當作文本附件添加到SOAP信息中。服務器使用queueFirstAttachmentText()剝離信息附件並將它列隊等待處理次數報告的、信息驅動的EJB組件的使用:

packagePayload;

importjava.io.*;

importjava.util.Iterator;

importjava.beans.*;

importjavax.xml.rpc.handler.soap.*;

importjavax.xml.soap.*;

importjavax.jms.*;

importjavax.naming.*;

/**

*

*@[email protected]

*/

publicclassSerializer{

//CommonqueueconnectionsusedbyqueueFirstAttachment

privatestaticContextjndiContext=null;

privatestaticQueueConnectionFactoryqueueConnectionFactory=null;

privatestaticQueueConnectionqueueConnection=null;

privatestaticQueueSessionqueueSession=null;

privatestaticQueuequeue=null;

privatestaticQueueSenderqueueSender=null;

privatestaticbooleanconnectionEstablished=false;

/**CreatesanewinstanceofSerializer*/

publicSerializer(){

}

privatestaticStringClientReportXML(ClientReportr){

ByteArrayOutputStreambaos=newByteArrayOutputStream();

XMLEncodersstream=newXMLEncoder(baos);

sstream.writeObject(r);

sstream.flush();

sstream.close();

returnbaos.toString();

}

publicstaticClientReportClientReportXML(StringcrXML){

ByteArrayInputStreambais=newByteArrayInputStream(crXML.getBytes());

XMLDecodersstream=newXMLDecoder(bais);

return(ClientReport)sstream.readObject();

}

publicstaticvoidattachPendingReportToMessage(SOAPMessageContextsmc){

try{

ClientReportcr=CurrentReport.getReport();

if(cr!=null){

SOAPMessagemc=smc.getMessage();

AttachmentPartap=mc.createAttachmentPart(Serializer.ClientReportXML(cr),newString("text/plain"));

mc.addAttachmentPart(ap);

}

}

catch(Exceptione){

//Makesurethatapplicationprocessingproceedsundisturbed

}

}

publicstaticvoidqueueFirstAttachmentText(SOAPMessageContextsmc){

Stringsattachment;

try{

SOAPMessagemc=smc.getMessage();

Iteratorattachments=mc.getAttachments();

if(attachments.hasNext()){

AttachmentPartattachment=(AttachmentPart)attachments.next();

sattachment=attachment.getContent().toString();

attachments.remove();

queueReportXML(sattachment);

}

}

catch(SOAPExceptione){

System.out.println("QueueAttachmentexception:"+e.toString());

}

}

/*

Synchronizedbecauseallcallerssharethequeueresources

*/

publicstaticsynchronizedvoidqueueReportXML(StringclientReportXML){

TextMessagemessage=null;

if(!connectionEstablished){

try{

jndiContext=newInitialContext();

queueConnectionFactory=(QueueConnectionFactory)jndiContext.lookup(

"jms/TestMDBFactory");

System.out.println("havefactory");

queue=(Queue)jndiContext.lookup("jms/TestMDBQueue");

queueConnection=queueConnectionFactory.createQueueConnection();

queueSession=queueConnection.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);

queueSender=queueSession.createSender(queue);

connectionEstablished=true;

}

catch(Exceptione){

System.out.println("Exceptionoccurredconnectingtoqueue:"+e.toString());

}

}

try{

message=queueSession.createTextMessage();

message.setText(clientReportXML);

//System.out.println("Sendingmessage:"+(String)message.getText());

queueSender.send(message);

}catch(JMSExceptione){

System.out.println("Exceptionoccurred:"+e.toString());

}catch(Exceptione){

//Makesurethatapplicationprocessingproceedsundisturbed

}

}

}

注意:queueReportXML()是同步的。因為Serializer類保存一個單一的靜態隊列連接,我們必須保證在一段時間內隻有一個執行線程使用該連接。

注意:該實現假設它自己是HTTP/SOAP信息附件的唯一創建者和使用者。如果一個實現將附件用作其他用途,類Serializer需要修改以便標誌和檢索包含信息報告的特殊附件。

我們使用該結構的目的之一是保證次數報告處理失敗不影響商業應用的完成。Serializer軟件包暴露的每個方法捕捉產生的任何異常,以便事務的處理可以不管這些異常繼續進行。

客戶端服務軟件包

通過指引WSDL編譯器到應用服務器提供的WSDL上可自動生成客戶端服務軟件包。這個軟件包包含許多類。我們需要修改的唯一類就是客戶端Stub類。同樣地,服務器Web服務軟件包也包含類Tie,它可將Web服務請求綁定到EJB方法上,客戶端Stub類為每個服務商業方法的每個客戶端配備一個方法。

服務Stub類的名稱為<ServiceName>ServantInterface_Stub,其中<ServiceName>就是服務名。我們看看類XactServiceServantInterface_Stub內的submitWork()方法:

/*

*ImplementationofsubmitWork

*/

publicjava.lang.StringsubmitWork(java.lang.Stringstring_1)

throwsjava.rmi.RemoteException{

try{

StreamingSenderState_state=_start(_handlerChain);

InternalSOAPMessage_request=_state.getRequest();

_request.setOperationCode(SubmitWork_OPCODE);

Xact.XactServiceServantInterface_SubmitWork_RequestStruct

_myXactServiceServantInterface_SubmitWork_RequestStruct=newXact.XactServiceServantInterface_SubmitWork_RequestStruct();

_myXactServiceServantInterface_SubmitWork_RequestStruct.setString_1(string_1);

SOAPBlockInfo_bodyBlock=newSOAPBlockInfo(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(_responseObjinstanceofSOAPDeserializationState){

_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(RemoteExceptione){

//Letthisonethroughunchanged

throwe;

}catch(JAXRPCExceptione){

thrownewRemoteException(e.getMessage(),e);

}catch(Exceptione){

if(einstanceofRuntimeException){

throw(RuntimeException)e;

}else{

thrownewRemoteException(e.getMessage(),e);

}

}

}

在上述的代碼中,我們在_send()之前立即添加了下麵的單行:

Serializer.attachPendingReportToMessage(_state.getMessageContext());

如果沒有待解決的客戶端報告需要發送,attachPendingReportToMessage就返回。否則,它將當前報告連在XML之後並將它當作文本附件添加到SOAP信息中。我們對其他的商業方法也作了同樣的修改,在它們的每個_send()調用之前立即添加了上麵的代碼行。

信息驅動的bean

現在我們可以記錄客戶端事務響應次數並將它們通過HTTP/SOAP的運輸,我們需要一條可以在應用服務器上處理這些報告的方法。最適合完成這個任務的就是信息驅動的EJB組件因為響應次數報告應該異步地搬運到用戶事務上。Web服務類Tie將XMLClientReport對象列隊。下麵的EJB代碼可讀取和處理這些報告:

packageTestBean;

importjavax.jms.*;

importjavax.ejb.*;

importPayload.*;

/**

*CreatedMay23,20036:01:04PM

*CodegeneratedbytheSunONEStudioEJBBuilder

*@authorBrian

*/

publicclassTestMDBBeanimplements

javax.ejb.MessageDrivenBean,javax.jms.MessageListener{

privatetransientjavax.ejb.MessageDrivenContextcontext;

/**

*@seejavax.ejb.MessageDrivenBean

#setMessageDrivenContext

(javax.ejb.MessageDrivenContext)

*/

publicvoidsetMessageDrivenContext

(javax.ejb.MessageDrivenContextaContext){

context=aContext;

}

/**

*Seesection15.4.4oftheEJB2.0specification