本文描述了一個(gè)用Java編寫(xiě)的不使用專門(mén)SOAP庫(kù)的簡(jiǎn)單通用SOAP客戶機(jī)。該客戶機(jī)可以讓您用任何 XML 編輯器(或文本編輯器)創(chuàng)建自己的請(qǐng)求, 而不是在暗中為您創(chuàng)建 SOAP 請(qǐng)求 XML 文檔。 該客戶機(jī)向您顯示實(shí)際的 SOAP 響應(yīng) XML 文檔,而不是僅僅提供遠(yuǎn)程方法的返回值。 這個(gè)簡(jiǎn)短的 Java 程序精確顯示了什么是 SOAP:打開(kāi) HTTP 連接、發(fā)送適當(dāng) XML 以調(diào)用遠(yuǎn)程方法、接著讀取服務(wù)器返回的 XML 響應(yīng)。
通用 Java SOAP 客戶機(jī)
SOAP(簡(jiǎn)單對(duì)象訪問(wèn)協(xié)議)是 IBM、Microsoft、DevelopMentor 和 UserLand Software 為在網(wǎng)絡(luò)上交換信息而開(kāi)發(fā)的一種已在發(fā)展的 W3C 標(biāo)準(zhǔn)。 隨著Web上可以公開(kāi)使用的SOAP服務(wù)器的不斷增加,SOAP幾乎對(duì)用任何語(yǔ)言編寫(xiě)的程序——即使是用流行的簡(jiǎn)單語(yǔ)言(如 Visual Basic、JavaScript 和 perl)編寫(xiě)的非常短小的程序——執(zhí)行著HTML對(duì)Web瀏覽器所做的事:它為這些程序提供一個(gè)簡(jiǎn)單的方法來(lái)利用萬(wàn)維網(wǎng)上不斷增加的可用信息源。
與 HTML 類似,SOAP 提供一套標(biāo)記來(lái)表示在Web上使用HTTP傳輸協(xié)議(從 SOAP 1.1 以來(lái),SMTP 也可以)發(fā)送的不同信息塊的作用。但是,SOAP向您提供的能力遠(yuǎn)遠(yuǎn)強(qiáng)于HTML。使用SOAP,您的程序向 SOAP服務(wù)器發(fā)送“SOAP請(qǐng)求”(一個(gè)簡(jiǎn)短的XML文檔,描述在遠(yuǎn)程機(jī)器上要調(diào)用的方法和所有要傳遞給它的參數(shù))。SOAP服務(wù)器將嘗試用那些參數(shù)執(zhí)行該方法,并將SOAP響應(yīng)發(fā)回程序。響應(yīng)可以是執(zhí)行的結(jié)果,也可以是相應(yīng)的錯(cuò)誤消息。可以使用公共SOAP服務(wù)器為提出請(qǐng)求的客戶機(jī)提供股票價(jià)格、最新的貨幣兌換率、FedEx 包裹跟蹤信息、代數(shù)表達(dá)式的解決方案以及其它各類信息。
在SOAP存在之前,嘗試使用這種信息的程序必須先捕獲Web頁(yè)面,然后“刮下”HTML,以查找適當(dāng)?shù)奈谋尽?對(duì)這些Web頁(yè)面進(jìn)行可視的重新設(shè)計(jì)(例如,將當(dāng)前股票價(jià)格放到表中第三列而不是第二列中)就可以使這些程序無(wú)用。SOAP規(guī)范以及它所攜帶的簡(jiǎn)要的SOAP請(qǐng)求和響應(yīng)模式為客戶機(jī)和服務(wù)器之間的聯(lián)絡(luò)提供了一個(gè)框架,該框架是那些強(qiáng)健得多的信息收集工具的基礎(chǔ)。
有許多SOAP客戶機(jī)可用于大多數(shù)的流行編程語(yǔ)言;有關(guān)詳盡列表,請(qǐng)參閱 SOAP::Lite for Perl 主頁(yè)上的 SOAP Toolkits 部分(請(qǐng)參閱參考資料)。大多數(shù) SOAP 客戶機(jī)都提供類庫(kù)、COM 對(duì)象或從您自己程序調(diào)用的等同對(duì)象。通常,使用這些客戶機(jī)庫(kù)遵循以下模式:
· 程序傳遞要調(diào)用的遠(yuǎn)程方法的名稱和所有必需參數(shù)。
· 庫(kù)組裝 SOAP 請(qǐng)求的適當(dāng) XML 文檔以將這一信息打包。
· 庫(kù)將這一 XML 文檔傳遞給 SOAP 端點(diǎn) URL 標(biāo)識(shí)的 SOAP 服務(wù)器,這與通過(guò)指定服務(wù)器的 URL 將瀏覽器指向 Web 服務(wù)器地址很類似。
· SOAP 服務(wù)器嘗試執(zhí)行方法后,它組裝包含執(zhí)行結(jié)果的 SOAP 響應(yīng) XML 文檔,并將它發(fā)回 SOAP 客戶機(jī)。
· 接收SOAP響應(yīng)時(shí),客戶機(jī)庫(kù)對(duì)XML進(jìn)行語(yǔ)法分析以獲得方法調(diào)用的結(jié)果,并將結(jié)果傳遞給使用庫(kù)的程序。
SOAPClient4XG
SOAP 的介紹(請(qǐng)參閱 developerWorks 上 Graham Glass 編寫(xiě)得極佳的“ Web 服務(wù)革命”專欄)總是討論用于 SOAP 請(qǐng)求和響應(yīng)的 XML 的結(jié)構(gòu),但是我接觸到的 SOAP 客戶機(jī)總是會(huì)暗中進(jìn)行 XML 組裝和語(yǔ)法分析,所以我從來(lái)不用知道。 作為使用 XML 的人員,我曾想自己執(zhí)行 XML 部分;我認(rèn)為如果 SOAP 這樣簡(jiǎn)單,那么我應(yīng)該能夠編寫(xiě)一個(gè)簡(jiǎn)單的 SOAP 客戶機(jī)來(lái)讀取 SOAP 請(qǐng)求的 XML 文檔、將它發(fā)送到命令行上指定的 SOAP 端點(diǎn) URL、讀回響應(yīng)文檔并輸出該響應(yīng)。這將使它成為一個(gè)真正的通用 SOAP 客戶機(jī),因?yàn)樗{(diào)用任何 SOAP 服務(wù)器上的任何方法。
清單1中顯示的 SoapClient4XG(“SOAP Client for XML Geeks”)Java類執(zhí)行該任務(wù),而不使用早先提到的 SOAP Toolkits 頁(yè)面上列出的任何專用 Java SOAP 類(請(qǐng)參閱參考資料)。 檢查了必需的 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); } } } } }
| |