使用 WSDD 來發布服務
This document is provided as is. You are welcomed to use it for non-commercial purpose.Written by: 國立中興大學資管系呂瑞麟
請勿轉貼
在前一個範例中,我們使用了 Axis 的特殊功能--稱之為 instant web service-- 來完成我們的 web service。他的好處在於速度快,只要把 .jws 的檔案放到 Axis 的目錄下就完成了 web service 的佈置,只可惜這個方式我們沒有辦法從 Axis 所提供的 List 功能中看到發布的服務。另外,JWS 還有其他缺點,例如 JWS 無法使用 packages, 而且由於它是在使用的時候才 compile,造成沒辦法即時知道錯誤。因此, 文件上建議如果要長期使用一個服務的話,請使用另一種服務發布的方式, 而這個方式需要使用 Axis 的 Web Service Deployment Descriptor(WSDD)。 使用 WSDD 來發布服務的步驟整理如下(我們使用同樣的範例來說明):
-  我將之前的 TimeService.jws 重新命名為 QueryTime.java 以避免可能的
衝突(程式碼如下所示),並將 compile 好的 .class 檔放到
axis\WEB-INF\classes。
import java.util.*; public class QueryTime { // 經過測試,我們也可以把 d.toString() 的值以 XML 的格式回傳, // 例如: return "<date>" + d.toString() + "</date>" public String getTime() { Date d = new Date(); return "當地時間 " + d.toString(); } }
-  產生一個註冊用的 WSDD 檔,以我們的範例而言,這個 WSDD 檔的內容
如下,並假設這個檔案的名稱是 deploy-time.wsdd。
這個檔案的第 1、2、以及最後一行幾乎都是固定的。第 4 到 7 行代表一個即將 要註冊的 service。由第 4 行可以看出,將要註冊的 service 名稱為 "TimeService", 另外,因為 AXIS 採用 RPC 的方式來傳遞資料,所以 provider 的值為 "java:RPC"。 最後,在第二個 04 行定義了被傳遞的 SOAP 訊息的格式是 wrapped/literal (也就是 document/literal wrapped)的方式,這是目前所知道最容易在不同 web services 平台上交換資料的方式。 這個 service 的參數由第 5 以及 6 行表達,第 5 行說明我們要呼叫的 service 的類別名稱為 "QueryTime",而第 6 行說明這個類別內的 public 方法都可以 呼叫。請注意,service 的類別名稱 "QueryTime" 指的就是之前設計的 QueryTime.java,這兩個一定要一致,否則無法正常運作。 定義完了 WSDD 檔案之後,我們必須利用 Axis 所提供的工具來註冊該服務。為了 安全性的考量,Axis 規定只能在安裝 Axis 的電腦上(也就是提供服務的電腦上) 執行註冊,由於這個程式很長,我們將下列的內容放到一個 adminclient.bat 的批次檔內。01 <deployment xmlns="http://xml.apache.org/axis/wsdd/" 02 xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"> 03 04 <service name="TimeService" provider="java:RPC" 04 style="wrapped" use="literal"> 05 <parameter name="className" value="QueryTime" /> 06 <parameter name="allowedMethods" value="*" /> 07 </service> 08 </deployment> 
 然後執行下列指令來完成註冊。@echo off set TEMP=%CLASSPATH% set CLASSPATH=%CLASSPATH%;d:\tomcat\webapps\axis\WEB-INF\lib\axis.jar;d:\tomcat\webapps\axis\WEB-INF\lib\axis-ant.jar;d:\tomcat\webapps\axis\WEB-INF\lib\commons-discovery-0.2.jar;d:\tomcat\webapps\axis\WEB-INF\lib\commons-logging-1.0.4.jar;d:\tomcat\webapps\axis\WEB-INF\lib\jaxrpc.jar;d:\tomcat\webapps\axis\WEB-INF\lib\log4j-1.2.8.jar;d:\tomcat\webapps\axis\WEB-INF\lib\saaj.jar;d:\tomcat\webapps\axis\WEB-INF\lib\wsdl4j-1.5.1.jar java org.apache.axis.client.AdminClient -lhttp://localhost:8080/axis/services/AdminService %1 set CLASSPATH=%TEMP% adminclient.bat deploy-time.wsdd 
-  檢查你所註冊的 service 是否成功。檢查的方式有以下三種:
-  利用 adminclient.bat list來檢查服務是否註冊成功,執行該指令後
的畫面如下:
 在紅色框框中,就是剛剛註冊的 TimeService。除此之外,我們也可以看出還有其他 服務,例如 AdminService 和 Version。
 
-  可以自行開發程式來瀏覽,程式碼如下所示:
跟之前 adminclient.bat 一樣,我們需要設定適當的 CLASSPATH;為了簡化起見, 請產生如下的兩個檔案,並假設其名稱分別為 compile.bat 和 run.bat:import org.apache.axis.client.AdminClient; public class ListWSDD { public static void main(String[] args) throws Exception { String host = "http://localhost:8080"; String servicepath = "/axis/services"; String endpoint = host + servicepath; AdminClient ac = new AdminClient(); ac.setTargetEndpointAddress(new java.net.URL (endpoint)); System.out.println(ac.list()); } }@echo off set TEMP=%CLASSPATH% set CLASSPATH=%CLASSPATH%;d:\tomcat\webapps\axis\WEB-INF\lib\axis.jar;d:\tomcat\webapps\axis\WEB-INF\lib\axis-ant.jar;d:\tomcat\webapps\axis\WEB-INF\lib\commons-discovery-0.2.jar;d:\tomcat\webapps\axis\WEB-INF\lib\commons-logging-1.0.4.jar;d:\tomcat\webapps\axis\WEB-INF\lib\jaxrpc.jar;d:\tomcat\webapps\axis\WEB-INF\lib\log4j-1.2.8.jar;d:\tomcat\webapps\axis\WEB-INF\lib\saaj.jar;d:\tomcat\webapps\axis\WEB-INF\lib\wsdl4j-1.5.1.jar javac %* set CLASSPATH=%TEMP% 如果你清楚環境變數 CLASSPATH 的設定方式,你也可以直接在控制台進行設定, 如此一來就可以減少設定上的麻煩。完成了以上檔案之後,我們就可以進行編譯以及 執行,編譯以及執行的指令如下:@echo off set TEMP=%CLASSPATH% set CLASSPATH=%CLASSPATH%;d:\tomcat\webapps\axis\WEB-INF\lib\axis.jar;d:\tomcat\webapps\axis\WEB-INF\lib\axis-ant.jar;d:\tomcat\webapps\axis\WEB-INF\lib\commons-discovery-0.2.jar;d:\tomcat\webapps\axis\WEB-INF\lib\commons-logging-1.0.4.jar;d:\tomcat\webapps\axis\WEB-INF\lib\jaxrpc.jar;d:\tomcat\webapps\axis\WEB-INF\lib\log4j-1.2.8.jar;d:\tomcat\webapps\axis\WEB-INF\lib\saaj.jar;d:\tomcat\webapps\axis\WEB-INF\lib\wsdl4j-1.5.1.jar java %* set CLASSPATH=%TEMP% 執行後的畫面就像之前執行 adminclient.bat list 的結果一樣。 由於這樣的結果是一份 XML 的文件,我們可以針對結果再進一步處理。compile.bat QueryWSDD.java run.bat QueryWSDD 
-  AXIS 也提供了瀏覽器的查詢介面,在瀏覽器輸入 http://localhost:8080/axis/servlet/AxisServlet 其畫面如下。或許有人會覺得很奇怪,
這個方式超簡單,為什麼還要之前的兩種方式?答案當然就是看"需求",有時候
自動化的過程是由程式負責的,而不是"人"。
 
 
 
 
 
-  利用 adminclient.bat list來檢查服務是否註冊成功,執行該指令後
的畫面如下:
-  你也可以把剛剛註冊的服務移除掉。移除的方式很簡單,只要把
下列的 wsdd 檔建立好(假設這個檔案的名稱為 undeploy-time.wsdd),
然後利用剛剛建好的 deploy.bat 來執行 adminclient.bat undeploy-time.wsdd
即可完成移除服務的步驟。undeploy-time.wsdd 的結構很簡單,
除了 <undeployment> 必要的根元素之外,我們只需要定義即將移除的
服務名稱,也就是 TimeService。
<undeployment xmlns="http://xml.apache.org/axis/wsdd/"> <service name="TimeService"/> </undeployment> 
-  請在瀏覽器輸入 http://localhost:8080/axis/services/TimeService?method=getTime,就可以在瀏覽器內看到執行結果,其畫面如下:
   
-  開發客戶端程式:大部分 service 的 client 程式開發都是利用 service 的
WSDL 來開發所需要的 proxy 類別。為了降低程式人員的困難,Axis 提供了一個工具
(WSDL2Java 類別)讓開發人員可以輕易的產生所需的 proxy 類別。請產生如下的
檔案,並將其命名為 wsdl.bat:
完成後,請執行以下指令來產生所需的 proxy 類別:@echo off set TEMP=%CLASSPATH% set CLASSPATH=%CLASSPATH%;d:\tomcat\webapps\axis\WEB-INF\lib\axis.jar;d:\tomcat\webapps\axis\WEB-INF\lib\axis-ant.jar;d:\tomcat\webapps\axis\WEB-INF\lib\commons-discovery-0.2.jar;d:\tomcat\webapps\axis\WEB-INF\lib\commons-logging-1.0.4.jar;d:\tomcat\webapps\axis\WEB-INF\lib\jaxrpc.jar;d:\tomcat\webapps\axis\WEB-INF\lib\log4j-1.2.8.jar;d:\tomcat\webapps\axis\WEB-INF\lib\saaj.jar;d:\tomcat\webapps\axis\WEB-INF\lib\wsdl4j-1.5.1.jar java org.apache.axis.wsdl.WSDL2Java %* set CLASSPATH=%TEMP% 在上例中,aa.bb.cc.dd 代表提供服務的主機位置。如果是 IP address,則 WSDL2Java 會在目前的目錄下產生一個 _aa\_bb\_cc\_dd\axis\services\服務名稱 的一系列子目錄,而且所有的 proxy 類別會放在 服務名稱 的目錄內。 如果 aa.bb.cc.dd 是 hostname,則 WSDL2Java 會在目前的目錄下產生一個 aa\bb\cc\dd\axis\services\服務名稱 的一系列子目錄。 以本範例來說,我們輸入的指令如下:wsdl.bat http://aa.bb.cc.dd/axis/services/服務名稱?wsdl 
 來取得 TimeService 的 WSDL,而且經過 WSDL2Java 的處理,它會在 目前路徑下產生了 localhost\axis\services\TimeService 一系列子目錄,並且產生了 QueryTime.java, QueryTimeService.java, QueryTimeServiceLocator.java, TimeServiceSoapBindingStub.java 四個類別。由於這個服務所對應的類別是 QueryTime,所以 QueryTime.java 代表遠端服務的類別(或者物件),這個代表遠端物件的類別會被用來呼叫 operation。 要尋找遠端的服務,client 程式必須經由 QueryTimeServiceLocator 來 找到遠端的服務 QueryTimeService(Axis 採用的名稱規則是:若遠端物件是 QueryTime,則代表該服務的名稱就是 QueryTimeService,而實際上去執行的 Locator 就命名為 QueryTimeServiceLocator;從這樣的命名規則,我們知道 遠端物件的名稱最好不要以 Service 做結尾以避免混淆);而經由 QueryTimeService 的 get 方法(一般來說,get 方法的名稱為 get服務名稱();以本範例來說, 也就是 getTimeService())來找到遠端的物件 QueryTime。 TimeServiceSoapBindingStub 就是 Stub 類別,一般來說, 我們不會直接使用 stub。 有了 proxy 類別之後,客戶端的程式就可以變的非常簡單(呼叫遠端物件的 方式就非常像呼叫 local 端物件的樣子):wsdl.bat http://localhost:8080/axis/services/TimeService?wsdl 
 import java.rmi.*; import javax.xml.rpc.*; import localhost.axis.services.TimeService.*; public class TimeClient { public static void main(String[] args) throws RemoteException, ServiceException { // 呼叫服務的方式,一般分為兩個步驟。首先,先初始化一個 Service Locator // 物件,再由這個物件的 get 方法,取得代表遠端服務的 stub。 QueryTimeService service = new QueryTimeServiceLocator(); QueryTime call = service.getTimeService(); // 由於 stub 在概念上代表遠端服務的物件,所以就可以直接 // 使用該物件的 get 方法來執行方法 getTime() String result = call.getTime(); System.out.println(result); } }
-  編譯以及執行該程式的畫面如下,畫面中的警告訊息可以忽略。
 
Written by: 國立中興大學資管系呂瑞麟
 
沒有留言:
張貼留言