Apache Axis用戶指南(1)

本文是Apache Axis的用戶指南的第一部分。
筆者在學習的過程中,作爲記錄,簡單的翻譯了一下。筆者已經翻譯了Apache Axis的安裝及應用文檔,也談不上翻譯,只是筆者在學習的過程中,將筆者認爲重要的部分作爲記錄,並加以筆者實踐的結果。建議在閱讀本文之前先閱讀Apache Axis安裝指南。
0.介紹
SOAPSOAP是基於XML的通信協議和編碼格式,它用於交互應用程序通信。現在的版本是SOAP 1.2,但是SOAP 1.1版本使用的更加廣泛。SOAPW3CXML協議工作組管理。SOAP被廣泛的認爲是跨平臺、跨語言的計算機應用和Web Service的核心。
AXISAxisSOAP Engine----用來構造SOAP處理器,例如客戶端,服務器端,網管等等。Axis是使用Java實現的,但是Axis提供一個C++的客戶端實現。Axis不僅僅是一個SOAP Engine,它還包括以下內容:
·獨立的服務器
·可以plug inservlet engine中的服務器
·支持WSDL
·根據WSDL生成Java
·樣例程序
·SOAPMonitor
Axis 1.4的特性如下:
·兼容SOAP 1.1/1.2兩個版本
·靈活的配置和發佈
·支持JWS
·支持所有的基本類型,以及類型映射系統
·自動的Java Beans序列化/反序列化,包含自定義的Java屬性-->XML元素/屬性的映射
·自動的Java集合與SOAP數組的雙向轉換。
·提供RPC和基於消息的SOAP服務
·由發佈的服務自動生成WSDL
·WSDL2Java工具
·Java2WSDL工具
·基本的安全擴展,可以集成到Servlet 2.2的安全/角色中
·支持面向繪畫的服務,通過使用HTTP Cookie或者獨立於傳輸的SOAP Headers
·SOAP with Attachments規範的初步支持
·EJB作爲Web Service來訪問
·HTTP Servlet的傳輸
·基於JMS的支持
·獨立的服務器版本
·大量的例子
根據Apache Axis安裝指南,安裝Apache AxisApache Tocmat服務器。運行本文所適用的例子之前,確保CLASSPATH包含以下類庫:
·       axis-1_2/lib/axis.jar
·       axis-1_2/lib/jaxrpc.jar
·       axis-1_2/lib/saaj.jar
·       axis-1_2/lib/commons-logging.jar
·       axis-1_2/lib/commons-discovery.jar
·       axis-1_2/lib/wsdl4j.jar
·       axis-1_2/ (for the sample code)
·       遵守JAXP-1.1XML解析器,推薦使用Xerces,因爲在Apache Axis測試的時候使用的就是這個解析器
1.使用Axis開發Web Service
Getting Started
首先來看一個例子Web Service客戶端程序,它調用Apache提供的Axis服務器的echoString方法:
package samples.userguide.example1;
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import javax.xml.namespace.QName;
public class TestClient {
public static void main(String[] args) {
try {
           String endpoint =
"http://nagoya.apache.org:5049/axis/services/echo";
           Service service = new Service();
           Call call = (Call) service.createCall();
           call.setTargetEndpointAddress(new java.net.URL(endpoint));
           call.setOperationName(new QName("http://soapinterop.org/",
                                       "echoString"));
           String ret = (String) call.invoke(new Object[] { "Hello!" });
           System.out.println("Sent 'Hello!', got '" + ret + "'");
} catch (Exception e) {
           System.err.println(e.toString());
}
}
}
程序首先創建了ServiceCall對象,他們是標準的JAX-RPC對象,用來存儲關於調用服務的元數據,然後設置了SOAP消息目的地的終端節點的URL,接着定義了Web Service的操作名,最後激活服務,傳遞一個數組參數(一個字符串)
可以查看SOAP請求消息的結構如下:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <SOAP-ENV:Body>
    <ns1:echoString xmlns:ns1="http://soapinterop.org/">
      <arg0 xsi:type="xsd:string">Hello!</arg0>
    </ns1:echoString>
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
字符串參數自動的序列化成XML,服務器響應就是一個String,我們將它反序列化後並打印出來。
可以使用tcpmon或者SOAP monitor來查看請求和響應信息。(筆者並沒有網絡連接,不能連接到Apache網站,所以這個例子沒有運行成功。)
命名參數
在上面的例子中,可以看到Axis自動的將XML編碼的參數命名爲arg0,arg1,放在SOAP消息中。如果想改變這種命名,很簡單,在調用invoke()方法之前,使用addParameter方法對每個參數命名,同時使用setReturnType對返回的參數命名,如下所示:
call.addParameter(“testParam”,
org.apache.axis.Constants.XSD_STRING,
javax.xml.rpc.ParameterMode.IN);
         call.setReturnType(org.apache.axis.Constants.XSD_STRING);
進行上述設置後,會將testParam這個參數名賦給並且只賦給第一個調用方法的第一個參數。同時還定義了參數的類型(org.apache.axis.Constants.XSD_STRING)和這個參數是輸入還是輸出或者輸入輸出參數。在本例中是一個輸入參數。現在再運行這個程序時,消息如下:
<testParam xsi:type="xsd:string">Hello!</testParam>
”untyped”服務器互操作
在上面的例子中,強制設置了invoke()方法的返回值類型,本來是一個Object類型,但是轉換爲適當的實際類型---例如,我們已經知道echoString方法返回一個字符串,那麼我們希望調用client.invoke()返回一個字符串。我們先來看一下它是如何工作的:
下面是echoString的一個響應:
<?xml version="1.0" encoding="UTF-8"?>
 <SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                    xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <SOAP-ENV:Body>
   <ns1:echoStringResponse xmlns:ns1="http://soapinterop.org/">
    <result xsi:type="xsd:string">Hello!</result>
   </ns1:echoStringResponse>
 </SOAP-ENV:Body>
 </SOAP-ENV:Envelope>
其中紅色的部分包含了一個類型聲明,Axis使用它來決定將元素的內容反序列化成什麼類型的Java對象,在本例中將其反序列化成一個Java String對象。很多工具將這種XML中的顯示類型信息叫做自描述。另外,一些工具返回如下的響應:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                   xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 <SOAP-ENV:Body>
 <ns1:echoStringResponse xmlns:ns1="http://soapinterop.org/">
   <result>Hello, I'm a string!</result>
 </ns1:echoStringResponse>
 </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
它不包含類型的生命,那麼Java如何將<result>中的內容進行反序列化呢?反序列化成什麼類型的對象呢?答案就是metadata,關於數據的數據。在本例中,我們需要一個對服務的描述來告訴我們期望的返回類型。下面是在Axis客戶端需要做的:
call.setReturnType( org.apache.axis.Constants.XSD_STRING );
這個方法會告訴Axis客戶端,如果返回值類型沒有被聲明,那麼就將返回值的xsi:type屬性定義成預定義的SOAP String類型。
另外還可以通過下面的方法設置返回類型的Java類:
call.setReturnClass(String.class);
現在,使用Axis作爲客戶端訪問SOAP服務就介紹完了。總結一下,利用Axis作爲客戶端訪問SOAP服務的步驟如下:
創建服務終端節點
初始化Service,初始化方法:
Service()
Service(EngineConfiguration config)
Service(EngineConfiguration engineConfiguration, AxisClient axisClient)
Service(java.io.InputStream wsdlInputStream, QName serviceName)
Service(Parser parser, QName serviceName)
Service(QName serviceName)
Service(java.lang.String wsdlLocation, QName serviceName)
Service(java.net.URL wsdlDoc, QName serviceName)
初始化Call,初始化方法調用Service的如下方法:
Call        createCall()
          Creates a new Call object with no prefilled data.
 Call        createCall(QName portName)
          Creates a new Call object - will prefill as much info from the WSDL as it can.
 Call        createCall(QName portName, QName operationName)
          Creates a new Call object - will prefill as much info from the WSDL as it can.
 Call        createCall(QName portName, java.lang.String operationName)
          Creates a new Call object - will prefill as much info from the WSDL as it can.
設置調用的一些參數:
void         addParameter(java.lang.String paramName, QName xmlType, java.lang.Class javaType, ParameterMode parameterMode)
 void       addParameter(java.lang.String paramName, QName xmlType, ParameterMode parameterMode)
 void       setOperationName(QName operationName)
 void       setPortTypeName(QName portType)
 void       setProperty(java.lang.String name, java.lang.Object value)
 void       setReturnType(QName xmlType)
 void       setReturnType(QName xmlType, java.lang.Class javaType)
 void       setTargetEndpointAddress(java.lang.String address)
.......(org.apache.axis.client.Callorg.apache.axis.Calljavax.xml.rpc.Call的方法)
調用invoke方法,調用SOAP服務
2.使用Axis發佈Web Service
首先看一下下面這個非常簡單的類:
public class Calculator {
         public int add(int i1, int i2) {
                   return i1 + i2;
         }
 
         public int subtract(int i1, int i2) {
                   return i1 – i2;
         }
}
如何將這個類可以通過SOAP訪問呢?方法有很多種,我們通過Axis提供的最簡單辦法來完成:
JWS(Java Web Service)文件---瞬時部署
Calculator.java文件拷貝到<your-webapp-root>/axis/目錄下,並修改擴展名爲jws,即拷貝後的文件爲Calculator.jws,例如筆者拷貝的目錄及文件名爲TOMCAT_HOME/webapps/axis/Calulator.jws
接下來就可以通過下面的URL訪問Web Service
Axis將自動的查找文件,編譯java類,轉換成SOAP調用。使用下面的客戶端程序:
/*
 * Copyright 2001-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
package samples.userguide.example2;
 
import org.apache.axis.client.Call;
import org.apache.axis.client.Service;
import org.apache.axis.encoding.XMLType;
import org.apache.axis.utils.Options;
 
import javax.xml.rpc.ParameterMode;
 
public class CalcClient
{
   public static void main(String [] args) throws Exception {
       Options options = new Options(args);
       String endpoint = "http://localhost:" + options.getPort() +
                         "/axis/Calculator.jws";
       args = options.getRemainingArgs();
       if (args == null || args.length != 3) {
           System.err.println("Usage: CalcClient <add|subtract> arg1 arg2");
           return;
       }
       String method = args[0];
       if (!(method.equals("add") || method.equals("subtract"))) {
           System.err.println("Usage: CalcClient <add|subtract> arg1 arg2");
           return;
       }
       Integer i1 = new Integer(args[1]);
       Integer i2 = new Integer(args[2]);
 
       Service service = new Service();
       Call     call    = (Call) service.createCall();
 
       call.setTargetEndpointAddress( new java.net.URL(endpoint) );
       call.setOperationName( method );
       call.addParameter( "op1", XMLType.XSD_INT, ParameterMode.IN );
       call.addParameter( "op2", XMLType.XSD_INT, ParameterMode.IN );
       call.setReturnType( XMLType.XSD_INT );
       Integer ret = (Integer) call.invoke( new Object [] { i1, i2 });
      
       System.out.println("Got result : " + ret);
   }
}
使用下面的調用來調用Calculator.jws
G:/jee/eclipse/workspace/AxisUserGuide>java samples.userguide.example2.CalcClien
t -p8080 add 2 5
Got result : 7
 
G:/jee/eclipse/workspace/AxisUserGuide>java samples.userguide.example2.CalcClien
t -p8080 subtract 10 9
Got result : 1
 
G:/jee/eclipse/workspace/AxisUserGuide>java samples.userguide.example2.CalcClien
t -p8080 unknown 1 2
Usage: CalcClient <add|subtract> arg1 arg2
當端口不是8080的時候,需要改成自定義的端口。
由於JWS web服務是目的在於實現簡單的web服務。不能使用package。當使用package的時候,將出現如下的錯誤:
G:/jee/eclipse/workspace/AxisUserGuide>java samples.userguide.example2.CalcClien
t -p8080 subtract 10 9
Exception in thread "main" AxisFault
 faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.userException
 faultSubcode:
 faultString: java.io.FileNotFoundException: G:/eclipse/workspace/apache-tomcat-
5.5.25/webapps/axis/WEB-INF/jwsClasses/samples/userguide/example2/Calculator.cla
ss (指定されたファイルが見つかりません。)
 faultActor:
 faultNode:
 faultDetail:
        {http://xml.apache.org/axis/}hostname:neusoft-dc6b5f1
3.自定義部署介紹WSDD
使用JWS的唯一有點就是簡單,但是靈活性很差,不可以進行配置,不能指定自定義類型,不能使用Handlers,所以很少使用。
使用部署描述符
爲了靈活的使用Axis,主要使用其配置的功能,首先應該屬性Axis Web Service Deployment Descriptor(WSDD)格式。部署描述符包含了需要部署到Axis中的內容,也就是說,Axis Engine需要使用的內容。通常部署一個Web Service,那麼我們就從基本的服務開始開始瞭解wsdd。首先看下面這個wsdd文件:
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
 <service name="MyService" provider="java:RPC">
 <parameter name="className" value="samples.userguide.example3.MyService"/>
 <parameter name="allowedMethods" value="*"/>
 </service>
</deployment>
比較簡單,最外層的元素告訴engine這是一個WSDD部署,同時定義了java這個名稱空間。接着service元素進行實際的Web Service的定義。service是一個目標鏈,也就是說它可能包含以下內容中的部分或者全部:請求流、核心處理器(對於服務來說叫做provider)、響應流。在本例中,providerjava:RPC,建立在Axis中,提示了這是個Java RPC服務。實際上處理這個的類是org.apache.axis.providers.java.RPCProvider。一些其他的providers包括如下:
通過使用一系列的參數來告訴RPCProvider它需要實例化的類以及調用的類(例如samples.userguide.example3.MyService)。上面例子中的參數分別爲指定服務的類、允許通過SOAP訪問的方法,”*”表示所有的方法都可以訪問。也可以通過空白或者都好分割的方面名來限制SOAP可以訪問的方法列表。
4.高級WSDD—指定更多的選項
WSDD描述符可以包含關於服務的更多的信息,以及其他的部分,例如Axis中的Handlers,我們將在後面進行介紹。
服務範圍
Axis支持三種範圍的服務對象,”Request””Session””Application”,其中Request Scope是默認的,爲每個SOAP請求創建一個新的對象,Session Scope針對每個允許使用session的客戶端創建一個新的對象,Application scope爲所有的請求創建一個單例的共享對象。可以通過<parameter>指定,例如:
<service name=”MyService” ...>
<parameter name=”scope” value=”value”>
         ...
</service>
使用AdminClient
使用AdminClient,或者說org.apache.axis.client.AdminClient類來將wsdd文件發送到Axis服務器,以便真正的部署服務。如果將Axis部署到不是tomcat的服務器上的話,需要使用-p<port>參數,默認的是8080,一個典型的調用AdminClient的方式是:
java org.apache.axis.client.AdminClient deploy.wsdd
<Admin>Done processing</Admin>
這個命令使服務可以通過SOAP進行訪問,通過運行Client類來檢查一下:
java samples.userguide.example3.Client –lhttp://localhost:8080/axis/services/MyService “test me!”
You typed : test me!
整個運行過程如下:
如果將soapmonitorrequestresponse兩個flow加入到deploy.wsdd文件中:
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
 
 <service name="MyService" provider="java:RPC">
 <requestFlow>
      <handler type="soapmonitor"/>
 </requestFlow>
 <responseFlow>
      <handler type="soapmonitor"/>
 </responseFlow>
 <parameter name="className" value="samples.userguide.example3.MyService"/>
 <parameter name="allowedMethods" value="*"/>
 </service>
</deployment>
那麼可以通過訪問http://localhost:8080/axis/SOAPMonitor來查看SOAP請求和響應信息:
如果想驗證部署的服務已經在運行,可以將其卸載後再重新調用,undeploy.wsdd的文件內容如下:
<undeployment xmlns="http://xml.apache.org/axis/wsdd/">
 <service name="MyService"/>
</undeployment>
卸載服務的方法和發佈服務的方法相同,只是替換wsdd文件而已,卸載後再調用服務時,查看發生了什麼:
也可以使用AdminClient來列出所有發佈到服務器上的組件:
D:/axis-1_4>java org.apache.axis.client.AdminClient list
<ns1:deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.
apache.org/axis/wsdd/providers/java" xmlns:ns1="http://xml.apache.org/axis/wsdd/
">
 <ns1:globalConfiguration>
 <ns1:parameter name="sendMultiRefs" value="true"/>
 ......
<ns1:parameter name="attachments.implementation" value="org.apache.axis.attach
ments.AttachmentsImpl"/>
 <ns1:requestFlow>
   <ns1:handler type="java:org.apache.axis.handlers.JWSHandler">
    <ns1:parameter name="scope" value="session"/>
   </ns1:handler>
   <ns1:handler type="java:org.apache.axis.handlers.JWSHandler">
    <ns1:parameter name="scope" value="request"/>
    <ns1:parameter name="extension" value=".jwr"/>
   </ns1:handler>
 </ns1:requestFlow>
 </ns1:globalConfiguration>
 <ns1:handler name="soapmonitor" type="java:org.apache.axis.handlers.SOAPMonitor
Handler">
 <ns1:parameter name="wsdlURL" value="/axis/SOAPMonitorService-impl.wsdl"/>
 <ns1:parameter name="namespace" value="http://tempuri.org/wsdl/2001/12/SOAPMon
itorService-impl.wsdl"/>
 <ns1:parameter name="serviceName" value="SOAPMonitorService"/>
 <ns1:parameter name="portName" value="Demo"/>
 </ns1:handler>
 .......other ns1:handler
 <ns1:service name="AdminService" provider="java:MSG">
 <ns1:parameter name="allowedMethods" value="AdminService"/>
 <ns1:parameter name="enableRemoteAdmin" value="false"/>
 <ns1:parameter name="className" value="org.apache.axis.utils.Admin"/>
 <ns1:namespace>http://xml.apache.org/axis/wsdd/</ns1:namespace>
 </ns1:service>
 .......other ns1:service
 <ns1:transport name="http">
 <ns1:requestFlow>
   <ns1:handler type="URLMapper"/>
   <ns1:handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/>
 </ns1:requestFlow>
 <ns1:parameter name="qs:list" value="org.apache.axis.transport.http.QSListHand
ler"/>
.......other parameter
 </ns1:transport>
 ......other transport
</ns1:deployment>
在上面的打印的信息中,包含了serviceshandlerstransports和其它的內容。實際上它就是server-config.wsdd文件的內容。我們在稍後會更詳細的介紹它。
更多的部署相關—HandlersChains 處理器和鏈
現在介紹一些Axis更強大的特性。比方說,想統計一下服務被調用了多少次,那麼就是用一個handler來完成。在Axis包含這樣的例子。當需要使用一個如上的handler類的時候,首先需要部署Handler本身(也就是說在wsdd文件中需要對其進行聲明),然後在service中使用handler的名字,這個名字由你決定。下面是一個handlerwsdd文件:
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
            xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
 
 <!-- define the logging handler configuration -->
 <handler name="track" type="java:samples.userguide.example4.LogHandler">
 <parameter name="filename" value="d:/MyService.log"/>
 </handler>
 
 <!-- define the service, using the log handler we just defined -->
 <service name="LogTestService" provider="java:RPC">
 <requestFlow>
   <handler type="track"/>
 </requestFlow>
 
 <parameter name="className" value="samples.userguide.example4.Service"/>
 <parameter name="allowedMethods" value="*"/>
 </service>
 
</deployment>
第一部分定義了一個Handler叫做”track”,實現的類爲samples.userguide.example4.LogHandler。這個類接受一個參數filename,用於將日誌信息記錄到這個文件中。
然後再wsdd重定義了LogTestService服務,和第一個例子相似,也是RPC服務。不同之處在於service元素包含了一個<requestFlow>元素,這表示當服務被調用的時候,一些Handlers會被提前調用。通過插入一個track引用,這樣就可以確保在調用服務的時候,每個消息都會被記錄。
根據前面的例子,發佈服務並調用:
         執行多次調用後,查看d:/MyService.log文件的內容,如下所示:
遠程管理
默認情況下,Axis服務器只允許在本機上訪問管理請求,如果希望啓用遠程管理,那麼需要設置AdminServiceenableRemoteAdmin屬性爲true。查看TOMCAT_HOME/webapps/axis/WEB-INF目錄下的server-config.wsdd文件,可以看到AdminService的部署描述,添加如下的屬性:
<service name="AdminService" provider="java:MSG">
 <parameter name="allowedMethods" value="AdminService"/>
 <parameter name="enableRemoteAdmin" value="true"/>
 <parameter name="className" value="org.apache.axis.utils.Admin"/>
 <namespace>http://xml.apache.org/axis/wsdd/</namespace>
 </service>
啓用遠程管理的話將允許未被授權的訪問,如果啓用的話,需要確保在配置中添加了安全限制。

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章