本文描述了一個用Java編寫的不使用專門SOAP庫的簡單通用SOAP客戶機(jī)。該客戶機(jī)可以讓您用任何 XML 編輯器(或文本編輯器)創(chuàng)建自己的請求, 而不是在暗中為您創(chuàng)建 SOAP 請求 XML 文檔。 該客戶機(jī)向您顯示實(shí)際的 SOAP 響應(yīng) XML 文檔,而不是僅僅提供遠(yuǎn)程方法的返回值。 這個簡短的 Java 程序精確顯示了什么是 SOAP:打開 HTTP 連接、發(fā)送適當(dāng) XML 以調(diào)用遠(yuǎn)程方法、接著讀取服務(wù)器返回的 XML 響應(yīng)。
通用 Java SOAP 客戶機(jī)
SOAP(簡單對象訪問協(xié)議)是 IBM、Microsoft、DevelopMentor 和 UserLand Software 為在網(wǎng)絡(luò)上交換信息而開發(fā)的一種已在發(fā)展的 W3C 標(biāo)準(zhǔn)。 隨著Web上可以公開使用的SOAP服務(wù)器的不斷增加,SOAP幾乎對用任何語言編寫的程序——即使是用流行的簡單語言(如 Visual Basic、JavaScript 和 perl)編寫的非常短小的程序——執(zhí)行著HTML對Web瀏覽器所做的事:它為這些程序提供一個簡單的方法來利用萬維網(wǎng)上不斷增加的可用信息源。
與 HTML 類似,SOAP 提供一套標(biāo)記來表示在Web上使用HTTP傳輸協(xié)議(從 SOAP 1.1 以來,SMTP 也可以)發(fā)送的不同信息塊的作用。但是,SOAP向您提供的能力遠(yuǎn)遠(yuǎn)強(qiáng)于HTML。使用SOAP,您的程序向 SOAP服務(wù)器發(fā)送“SOAP請求”(一個簡短的XML文檔,描述在遠(yuǎn)程機(jī)器上要調(diào)用的方法和所有要傳遞給它的參數(shù))。SOAP服務(wù)器將嘗試用那些參數(shù)執(zhí)行該方法,并將SOAP響應(yīng)發(fā)回程序。響應(yīng)可以是執(zhí)行的結(jié)果,也可以是相應(yīng)的錯誤消息。可以使用公共SOAP服務(wù)器為提出請求的客戶機(jī)提供股票價格、最新的貨幣兌換率、FedEx 包裹跟蹤信息、代數(shù)表達(dá)式的解決方案以及其它各類信息。
在SOAP存在之前,嘗試使用這種信息的程序必須先捕獲Web頁面,然后“刮下”HTML,以查找適當(dāng)?shù)奈谋尽?對這些Web頁面進(jìn)行可視的重新設(shè)計(jì)(例如,將當(dāng)前股票價格放到表中第三列而不是第二列中)就可以使這些程序無用。SOAP規(guī)范以及它所攜帶的簡要的SOAP請求和響應(yīng)模式為客戶機(jī)和服務(wù)器之間的聯(lián)絡(luò)提供了一個框架,該框架是那些強(qiáng)健得多的信息收集工具的基礎(chǔ)。
有許多SOAP客戶機(jī)可用于大多數(shù)的流行編程語言;有關(guān)詳盡列表,請參閱 SOAP::Lite for Perl 主頁上的 SOAP Toolkits 部分(請參閱參考資料)。大多數(shù) SOAP 客戶機(jī)都提供類庫、COM 對象或從您自己程序調(diào)用的等同對象。通常,使用這些客戶機(jī)庫遵循以下模式:
· 程序傳遞要調(diào)用的遠(yuǎn)程方法的名稱和所有必需參數(shù)。
· 庫組裝 SOAP 請求的適當(dāng) XML 文檔以將這一信息打包。
· 庫將這一 XML 文檔傳遞給 SOAP 端點(diǎn) URL 標(biāo)識的 SOAP 服務(wù)器,這與通過指定服務(wù)器的 URL 將瀏覽器指向 Web 服務(wù)器地址很類似。
· SOAP 服務(wù)器嘗試執(zhí)行方法后,它組裝包含執(zhí)行結(jié)果的 SOAP 響應(yīng) XML 文檔,并將它發(fā)回 SOAP 客戶機(jī)。
· 接收SOAP響應(yīng)時,客戶機(jī)庫對XML進(jìn)行語法分析以獲得方法調(diào)用的結(jié)果,并將結(jié)果傳遞給使用庫的程序。
SOAPClient4XG
SOAP 的介紹(請參閱 developerWorks 上 Graham Glass 編寫得極佳的“ Web 服務(wù)革命”專欄)總是討論用于 SOAP 請求和響應(yīng)的 XML 的結(jié)構(gòu),但是我接觸到的 SOAP 客戶機(jī)總是會暗中進(jìn)行 XML 組裝和語法分析,所以我從來不用知道。 作為使用 XML 的人員,我曾想自己執(zhí)行 XML 部分;我認(rèn)為如果 SOAP 這樣簡單,那么我應(yīng)該能夠編寫一個簡單的 SOAP 客戶機(jī)來讀取 SOAP 請求的 XML 文檔、將它發(fā)送到命令行上指定的 SOAP 端點(diǎn) URL、讀回響應(yīng)文檔并輸出該響應(yīng)。這將使它成為一個真正的通用 SOAP 客戶機(jī),因?yàn)樗{(diào)用任何 SOAP 服務(wù)器上的任何方法。
清單1中顯示的 SoapClient4XG(“SOAP Client for XML Geeks”)Java類執(zhí)行該任務(wù),而不使用早先提到的 SOAP Toolkits 頁面上列出的任何專用 Java SOAP 類(請參閱參考資料)。 檢查了必需的 SOAP 端點(diǎn) URL 和 SOAP XML 文檔文件名參數(shù)及可選的 SOAP 操作參數(shù)后,讀入文件,將它發(fā)送到 SOAP 服務(wù)器,讀回響應(yīng),然后將其輸出到標(biāo)準(zhǔn)出口。
清單1
Listing 1. The complete SOAP client /** * SOAPClient4XG. Read the SOAP envelope file passed as the second * parameter, pass it to the SOAP endpoint passed as the first parameter, and * print out the SOAP envelope passed as a response. with help from Michael * Brennan 03/09/01 * * * @author Bob DuCharme * @version 1.1 * @param SOAPUrl URL of SOAP Endpoint to send request. * @param xmlFile2Send A file with an XML document of the request. * * 5/23/01 revision: SOAPAction added */ import java.io.*; import java.net.*; public class SOAPClient4XG { public static void main(String[] args) throws Exception { if (args.length < 2) { System.err.println("Usage: java SOAPClient4XG " + "http://soapURL soapEnvelopefile.xml" + " [SOAPAction]"); System.err.println("SOAPAction is optional."); System.exit(1); } String SOAPUrl = args[0]; String xmlFile2Send = args[1]; String SOAPAction = ""; if (args.length > 2) SOAPAction = args[2]; // Create the connection where we're going to send the file. URL url = new URL(SOAPUrl); URLConnection connection = url.openConnection(); HttpURLConnection httpConn = (HttpURLConnection) connection; // Open the input file. After we copy it to a byte array, we can see // how big it is so that we can set the HTTP Cotent-Length // property. (See complete e-mail below for more on this.) FileInputStream fin = new FileInputStream(xmlFile2Send); ByteArrayOutputStream bout = new ByteArrayOutputStream(); // Copy the SOAP file to the open connection. copy(fin,bout); fin.close(); byte[] b = bout.toByteArray(); // Set the appropriate HTTP parameters. httpConn.setRequestProperty( "Content-Length", String.valueOf( b.length ) ); httpConn.setRequestProperty("Content-Type","text/xml; charset=utf-8"); httpConn.setRequestProperty("SOAPAction",SOAPAction); httpConn.setRequestMethod( "POST" ); httpConn.setDoOutput(true); httpConn.setDoInput(true); // Everything's set up; send the XML that was read in to b. OutputStream out = httpConn.getOutputStream(); out.write( b ); out.close(); // Read the response and write it to standard out. InputStreamReader isr = new InputStreamReader(httpConn.getInputStream()); BufferedReader in = new BufferedReader(isr); String inputLine; while ((inputLine = in.readLine()) != null) System.out.println(inputLine); in.close(); } // copy method from From E.R. Harold's book "Java I/O" public static void copy(InputStream in, OutputStream out) throws IOException { // do not allow other threads to read from the // input or write to the output while copying is // taking place synchronized (in) { synchronized (out) { byte[] buffer = new byte[256]; while (true) { int bytesRead = in.read(buffer); if (bytesRead == -1) break; out.write(buffer, 0, bytesRead); } } } } }
| |