Payload軟件包
Payload軟件包可用於客戶端,也可用於服務器。它包含三個類:ClientReport、CurrentReport、和 Serializer。
ClientReport 表示一個客戶端次數報告:
package Payload;
import java.io.*;
import java.util.*;
/**
*
* @author Brian Connolly [email protected]
*/
public class ClientReport implements Serializable {
public Date clientStartDateTime;
public Date serverStartDateTime;
public long clientElapsedMS;
public String type;
public String status;
public String transactionID;
public String clientID;
//Default public constructor for WSDL
public ClientReport() {
}
/*
. . . Get, set property methods are not shown
*/
在上述代碼中,clientStartDateTime記錄客戶端初始化事務的時間。serverStartDateTime 當前沒有使用;它的用途是保存事務的服務器開始時間以便事務次數可與服務器資源使用的隨時間的變化關聯起來。
ClientElapsedMS是我們記錄的主要工具:從客戶端開始記錄新事務到它收到最後一個Web服務調用的結果為止這段時間的毫秒數。
Type允許客戶端使用類型特征化事務。通常,事物系統提供許多種類型的事務。我們期望某些類型對於服務器來說相對容易一些,某些類型相對難一些,這樣當我們分析響應次數和測量服務器資源時我們能夠將他們辨別出來。
Status記錄事務完成時的完成狀態。
ClientID 是客戶端標記符。當分析服務品質時我們可以使用它來區別同一個客戶端完成的事務。
客戶端使用第二個類CurrentReport來定界應用事務:
package Payload;
import java.util.*;
import java.rmi.server.*;
/**
*
* @author Brian Connolly [email protected]
*/
public class CurrentReport {
public static UID ClientIdentifier = new UID();
/** Holds value of property currentReport */
public static ClientReport Report;
public static ClientReport LastReport;
/** Creates a new instance of CurrentReport */
public CurrentReport() {
}
public void BeginTransaction() {
Report = new ClientReport();
Report.setClientID(ClientIdentifier.toString());
Report.setClientStartDateTime( new Date());
}
public void CommitTransaction(String transactionID, String type, String status) {
Report.setTransactionID(transactionID);
Report.setStatus(status);
Report.setType(type);
long l1 = Report.getClientStartDateTime().getTime();
long l2 = new Date().getTime();
Report.setClientElapsedMS(l2-l1);
LastReport = Report;
Report = null;
}
/** Getter for property currentReport
* @return Value of property currentReport
*/
public static ClientReport getReport() {
ClientReport last = LastReport;
LastReport = null;
return last;
}
/** Setter for property currentReport
* @param currentReport New value of property currentReport
*/
public void setReport(ClientReport Report) {
this.LastReport = Report;
}
}
CurrentReport保存進行中的事務的當前 ClientReport 。它也保存LastReport,也就是一個完成的事務。它還產生一個作為唯一設備標記符使用的客戶端標記符——在實際的應用中,這個客戶端標記符可被修改為全局的唯一標記符。CurrentReport是非線程安全的;我們假設在客戶端應用中只有一個單線程執行服務器事務。
beginTransaction() 創建一個新的ClientReport,設置它的客戶端標記符並且記錄事務起始時間。commitTransaction() 計算事務的毫秒數並且保存最後一個調用的副本,以方便以後的到服務器的上傳。
Serializer 是Payload 軟件包中的第三個類。客戶端和服務器都要使用者各類。客戶端使用attachPendingReportToMessage()連載待解決的當作XML的ClientReport ,並將它當作文本附件添加到SOAP信息中。服務器使用queueFirstAttachmentText()剝離信息附件並將它列隊等待處理次數報告的、信息驅動的EJB組件的使用:
package Payload;
import java.io.*;
import java.util.Iterator;
import java.beans.*;
import javax.xml.rpc.handler.soap.*;
import javax.xml.soap.*;
import javax.jms.*;
import javax.naming.*;
/**
*
* @author Brian Connolly [email protected]
*/
public class Serializer {
// Common queue connections used by queueFirstAttachment
private static Context jndiContext = null;
private static QueueConnectionFactory queueConnectionFactory = null;
private static QueueConnection queueConnection = null;
private static QueueSession queueSession = null;
private static Queue queue = null;
private static QueueSender queueSender = null;
private static boolean connectionEstablished = false;
/** Creates a new instance of Serializer */
public Serializer() {
}
private static String ClientReportXML(ClientReport r) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
XMLEncoder sstream = new XMLEncoder(baos);
sstream.writeObject(r);
sstream.flush();
sstream.close();
return baos.toString();
}
public static ClientReport ClientReportXML(String crXML) {
ByteArrayInputStream bais = new ByteArrayInputStream(crXML.getBytes());
XMLDecoder sstream = new XMLDecoder(bais);
return (ClientReport)sstream.readObject();
}
public static void attachPendingReportToMessage(SOAPMessageContext smc) {
try{
ClientReport cr = CurrentReport.getReport();
if (cr != null) {
SOAPMessage mc = smc.getMessage();
AttachmentPart ap = mc.createAttachmentPart(Serializer.ClientReportXML(cr),new String("text/plain"));
mc.addAttachmentPart(ap);
}
}
catch(Exception e){
// Make sure that application processing proceeds undisturbed
}
}
public static void queueFirstAttachmentText(SOAPMessageContext smc) {
String sattachment;
try{
SOAPMessage mc = smc.getMessage();
Iterator attachments = mc.getAttachments();
if(attachments.hasNext()){
AttachmentPart attachment = (AttachmentPart)attachments.next();
sattachment = attachment.getContent().toString();
attachments.remove();
queueReportXML(sattachment);
}
}
catch (SOAPException e){
System.out.println("Queue Attachment exception:" + e.toString());
}
}
/*
Synchronized because all callers share the queue resources
*/
public static synchronized void queueReportXML(String clientReportXML) {
TextMessage message = null;
if (!connectionEstablished) {
try{
jndiContext = new InitialContext();
queueConnectionFactory = (QueueConnectionFactory) jndiContext.lookup(
"jms/TestMDBFactory");
System.out.println("have factory");
queue = (Queue) jndiContext.lookup("jms/TestMDBQueue");
queueConnection = queueConnectionFactory.createQueueConnection();
queueSession = queueConnection.createQueueSession (false, Session.AUTO_ACKNOWLEDGE);
queueSender = queueSession.createSender(queue);
connectionEstablished = true;
}
catch (Exception e){
System.out.println("Exception occurred connecting to queue: "+ e.toSt ring());
}
}
try {
message = queueSession.createTextMessage();
message.setText(clientReportXML);
//System.out.println("Sending message: " + (String)message.getText());
queueSender.send(message);
} catch (JMSException e) {
System.out.println("Exception occurred: " + e.toString());
} catch (Exception e){
// Make sure that application processing proceeds undisturbed
}
}
}
注意:queueReportXML()是同步的。因為Serializer類保存一個單一的靜態隊列連接,我們必須保證在一段時間內只有一個執行線程使用該連接。
注意:該實現假設它自己是HTTP/SOAP信息附件的唯一創建者和使用者。如果一個實現將附件用作其他用途,類Serializer 需要修改以便標志和檢索包含信息報告的特殊附件。
我們使用該結構的目的之一是保證次數報告處理失敗不影響商業應用的完成。Serializer 軟件包暴露的每個方法捕捉產生的任何異常,以便事務的處理可以不管這些異常繼續進行。