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>
启用远程管理的话将允许未被授权的访问,如果启用的话,需要确保在配置中添加了安全限制。

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