`
gym_1119
  • 浏览: 51217 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

(转载)使用Axis2的底层API开发Web Service

阅读更多
本文是在理解官方指南的基础上,用实例实现Axis2提供的4种调用机制,并给出测试结果。
author: ZJ 07-3-13
Blog: http://zhangjunhd.blog.51cto.com/
?
1.使用Axis2的底层API开发Web Service Server端
1.1创建一个WebService(取名为MyService)
??? 在MyService中有两个operations,如下所示。
public void ping(OMElement element){}//IN-ONLY模式。仅仅接收OMElement,并对其处理。
public OMElement echo(OMElement element){}//IN_OUT模式。接收OMElemen,并返回OMElement。
?
1.2如何写Web Service
1)创建实现服务的类。
2)创建services.xml来解析这个Web Service。
3)将其打包成一个*.aar文档(Axis Archive)。
4)部署Web Service。
?
1.2.1 创建实现服务的类
??? 此类中提供的方法必须与Web Service(在services.xml中声明)中的operations对应。除非你提供了数据绑定,否则所有的方法只能接收一个参数,其类型为OMElement。
public class MyService{
? public void ping(OMElement element){...}
? public OMElement echo(OMElement element){...}
}
MyService.java
package userguide.example1;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import javax.xml.stream.XMLStreamException;
public class MyService {
??? public OMElement echo(OMElement element) throws XMLStreamException {
??????? //Praparing the OMElement so that it can be attached to another OM Tree.
??????? //First the OMElement should be completely build in case it is not fully built and still
??????? //some of the xml is in the stream.
??????? element.build();
??????? //Secondly the OMElement should be detached from the current OMTree so that it can
????? ? // be attached some other OM Tree. Once detached the OmTree will remove its
?????? // connections to this OMElement.
??????? element.detach();
??????? return element;
??? }
??? public void ping(OMElement element) throws XMLStreamException {
??????? //Do some processing
??? }
??? public void pingF(OMElement element) throws AxisFault{
??????? throw new AxisFault("Fault being thrown");
??? }
}
?
1.2.2 创建services.xml
??? Axis2使用services.xml来充当一个Web Servicea的配置文件。每一个使用Axis2部署的Web Service都必须拥有一个services.xml。
<services>
? <description>
??? This is a sample Web Service with two operations,echo and ping.
? </description>
? <parameter name="”ServiceClass”" locked="”false”">
? userguide.example1.MyService
? </parameter>
? <operation name="”echo”">
??? <messagereceiver class="”org.apache.axis2.receivers.RawXMLINOutMessageReceiver”/">
??? <actionmapping>urn:echo</actionmapping>
? </operation>
? <operation name="”ping”">
??? <messagereceiver class="”org.apache.receivers.RawXMLINOnlyMessageReceiver”/">
??? <actionmapping>urn:ping</actionmapping>
? </operation>
</service>
注:The actionMapping is required only if you want to enable WS-Addressing.
??? 可以创建一个services.xml,其中包含一组服务。这样在运行期,你可以在这些服务间共享信息。
<servicegroup>
? <service name="”Service1”">
??? <!---->
? </service>
<service name="”Service2”">
??? <!---->
? </service>
? <module ref="”ModuleName”/">
? <parameter name="”serviceGroupParam1”" locked="”false”">value1</parameter>
</servicegroup>
注:name of the service is a compulsory attribute.
?
1.2.3打包与部署
??? 这里不再详述,参见《基于Tomcat5.0和Axis2开发Web Service应用实例 》。
?
2.使用Axis2底层APIs实现Web Service客户端
2.1ClientUtil
??? 创建一个客户端通用的SOAP包装Util文件。封装"getEchoOMElement"和"getPingOMElement"分别对应"echo"和"ping"这两个operation。
ClientUtil.java
package userguide.clients;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
public class ClientUtil {
??? public static OMElement getEchoOMElement() {
??????? OMFactory fac = OMAbstractFactory.getOMFactory();
??????? OMNamespace omNs = fac.createOMNamespace(
??????????????? "http://example1.org/example1", "example1");
??????? OMElement method = fac.createOMElement("echo", omNs);
??????? OMElement value = fac.createOMElement("Text", omNs);
??????? value.addChild(fac.createOMText(value, "Axis2 Echo String "));
??????? method.addChild(value);
??????? return method;
??? }
??? public static OMElement getPingOMElement() {
??????? OMFactory fac = OMAbstractFactory.getOMFactory();
??????? OMNamespace omNs = fac.createOMNamespace(
??????????????? "http://example1.org/example1", "example1");
??????? OMElement method = fac.createOMElement("ping", omNs);
??????? OMElement value = fac.createOMElement("Text", omNs);
??????? value.addChild(fac.createOMText(value, "Axis2 Ping String "));
??????? method.addChild(value);
??????? return method;
??? }
}
?
2.2EchoBlockingClient
??? Axis2向用户提供了从blocking single channel调用到non-blocking dual channel调用的多种调用Web Service的模式。下面用最简单的blocking调用机制来实现”MyService”中的"echo" operation。
EchoBlockingClient.java
package userguide.clients;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
/**
?* Sample for synchronous single channel blocking service invocation.
?* Message Exchage Pattern IN-OUT
?*/
public class EchoBlockingClient {
private static EndpointReference targetEPR =
?new EndpointReference("http://localhost:8080/axis2/services/MyService");
??? public static void main(String[] args) {
try {
??????????? OMElement payload = ClientUtil.getEchoOMElement();
??????????? Options options = new Options();
??????????? options.setTo(targetEPR); // this sets the location of MyService service
??????????? ServiceClient serviceClient = new ServiceClient();
??????????? serviceClient.setOptions(options);
??????????? OMElement result = sender.sendReceive(payload);
??????????? System.out.println(result);
} catch (AxisFault axisFault) {
???????? axisFault.printStackTrace();
}
}
??? 绿色部分显示了为了调用一个Web Service而需要对operation作的设置。剩下的部分是用来创建OMElement,用来发送和显示相应的OMElement。
?
结果:
<example1:echo xmlns:example1="&lt;/font&gt;&lt;font size=" 2"="">http://example1.org/example1"
xmlns:tns="http://ws.apache.org/axis2">
<example1:text>
Axis2 Echo String
</example1:text>
</example1:echo>
?
2.3 PingClient
??? 在”MyService”中,我们有一种IN-ONLY模式的名为"ping"的operation。应用它的客户端代码如下:
PingClient.java
package userguide.clients;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
/**
?* Sample for fire-and-forget service invocation
?* Message Exchage Pattern IN-Only
?*/
public class PingClient {
private static EndpointReference targetEPR =
?new EndpointReference("http://localhost:8080/axis2/services/MyService");
??? public static void main(String[] args) {
try {
?????? OMElement payload = ClientUtil.getPingOMElement();
?????? Options options = new Options();
?????? options.setTo(targetEPR);
?????? ServiceClient serviceClient = new ServiceClient();
?????? serviceClient.setOptions(options);
?????? serviceClient.fireAndForget(payload);
??????? /**
???????? * We have to block this thread untill we send the request , the problem
???????? * is if we go out of the main thread , then request wont send ,so
???????? * you have to wait some time :)
???????? */
?????? Thread.sleep(500);
???? }
catch (AxisFault axisFault) {
??????????? axisFault.printStackTrace();
???? }
}
??? 由于我们在访问一个IN-ONLY模式的operation,所以我们可以直接使用ServiceClient中的"fireAndForget()"方法来调用这个operation。而且那样做的话,不会阻塞发起端,因此,它会立刻将控制权返回给客户端。
?
2.4 EchoNonBlockingClient
??? 在客户端EchoBlockingClient,一旦调用"serviceClient.sendReceive(payload);",客户端将会被阻 塞直到operation完成。这种方式在有很多Web Service需要在一个单一的客户端应用程序中启动时很不可取。一种解决方法是使用Non-Blocking API来调用这些Web Services。Axis2提供给用户一种基于回叫机制的non-blocking API。
EchoNonBlockingClient.java
package userguide.clients;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.client.async.AsyncResult;
import org.apache.axis2.client.async.Callback;
/**
?* Sample for asynchronous single channel non-blocking service invocation.
?* Message Exchage Pattern IN-OUT
?*/
public class EchoNonBlockingClient {
private static EndpointReference targetEPR =
?new EndpointReference("http://127.0.0.1:8080/axis2/services/MyService");
??? public static void main(String[] args) {
??????? ServiceClient sender = null;
??????? try {
??????????? OMElement payload = ClientUtil.getEchoOMElement();
??????????? Options options = new Options();
??????????? options.setTo(targetEPR);
??????????? //Callback to handle the response
??????????? Callback callback = new Callback() {
??????????????? public void onComplete(AsyncResult result) {
??????????????????? System.out.println(result.getResponseEnvelope());
??????????????? }
??????????????? public void onError(Exception e) {
??????????????????? e.printStackTrace();
??????????????? }
??????????? };
??????????? //Non-Blocking Invocation
??????????? sender = new ServiceClient();
??????????? sender.setOptions(options);
??????????? sender.sendReceiveNonBlocking(payload, callback);
??????????? //Wait till the callback receives the response.
??????????? while (!callback.isComplete()) {
??????????????? Thread.sleep(1000);
??????????? }
??????? } catch (AxisFault axisFault) {
??????????? axisFault.printStackTrace();
??????? } catch (Exception ex) {
??????????? ex.printStackTrace();
??????? } finally {
??????????? try {
??????????????? sender.finalizeInvoke();
??????????? } catch (AxisFault axisFault) { }
??????? }
??? }
}
?
结果:
<!---->
<soapenv:envelope xmlns:soapenv="&lt;/font&gt;&lt;font size=" 2"="">http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:header>
<soapenv:body>
<example1:echo xmlns:example1="&lt;/font&gt;&lt;font size=" 2"="">http://example1.org/example1"
xmlns:tns="http://ws.apache.org/axis2">
<example1:text>
Axis2 Echo String
</example1:text>
</example1:echo>
</soapenv:body>
</soapenv:envelope>
??? sender.sendReceiveNonBlocking(payload, callback);这个调用接受一个callback对象作为参数。Axis2客户端API提供了一个抽象类CallBack,其中提供了方法:
public abstract void onComplete(AsyncResult result);
public abstract void onError(Exception e);
public boolean isComplete() {}
??? 用户需要重写"onComplete " 和 "onError "方法。一旦客户端收到Web Service的response,onComplete方法将会被调用,这样将中止阻塞状态。
?
2.5EchoNonBlockingDualClient
??? 当调用的Web Service需要很长一段时间来完成时,这种由Non-Blocking API提供的解决方式将有一定的局限性。这种局限性是由使用单一的传输连接来调用Web Service并接收response造成的。换句话说,客户端提供一种没有阻塞的调用机制,但request和response的传输使用单一的传输 (双工方式)连接(如HTTP)。长时间运行的Web Service调用或Web Service调用使用单工传输方式(如SMTP)不能简单地利用一个没有阻塞的调用。
??? 一种尝试地解决方法是request和response各自使用单独的传输连接(单工或双工均可)。这种方式产生的问题是如何解决相关性(关联 request和response)。WS-Addressing提供了一种很好的解决方法,在头中使用<wsa:messageid> 和 <wsa:relatesto> 标签。Axis2对这种基于关联机制的寻址方式提供了支持。
??? 用户可以选择Blocking 或Non-Blocking APIs的Web Service,并使用两个传输连接。通过使用一个布尔标记,同一个API可以调用多个在两个传输连接上的Web Services(IN-OUT operations)。下例使用Non-Blocking API 以及两个传输连接来实现上文中提到的"echo" operation。
EchoNonBlockingDualClient.java
package userguide.clients;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.client.async.AsyncResult;
import org.apache.axis2.client.async.Callback;
import javax.xml.namespace.QName;
/**
?* Sample for asynchronous dual channel non-blocking service invocation.
?* Message Exchage Pattern IN-OUT
?* Ulitmate asynchronous service invocation sample.
?*/
public class EchoNonBlockingDualClient {
private static EndpointReference targetEPR =
?new EndpointReference("http://127.0.0.1:8080/axis2/services/MyService");
??? public static void main(String[] args) {
??????? ServiceClient sender = null;
??????? try {
??????????? OMElement payload = ClientUtil.getEchoOMElement();
??????????? Options options = new Options();
??????????? options.setTo(targetEPR);
??????????? options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
??????????? options.setUseSeparateListener(true);
??????????? options.setAction("urn:echo");? // this is the action mapping we put within the service.xml
??????????? //Callback to handle the response
??????????? Callback callback = new Callback() {
??????????????? public void onComplete(AsyncResult result) {
??????????????????? System.out.println(result.getResponseEnvelope());
??????????????? }
??????????????? public void onError(Exception e) {
??????????????????? e.printStackTrace();
??????????????? }
??????????? };
??????????? //Non-Blocking Invocation
?????????? ConfigurationContext sysContext = ConfigurationContextFactory
??????????? .createConfigurationContextFromFileSystem(
???????????? "D:\\Dvp\\Axis2\\axis2\\WEB-INF", null);//见注解①
??????????? sender = new ServiceClient(sysContext, null);
??????????? sender.engageModule(new QName(Constants.MODULE_ADDRESSING));
??????????? sender.setOptions(options);
??????????? sender.sendReceiveNonBlocking(payload, callback);
??????????? //Wait till the callback receives the response.
??????????? while (!callback.isComplete()) {
??????????????? Thread.sleep(1000);
??????????? }
??????????? //Need to close the Client Side Listener.
??????? } catch (AxisFault axisFault) {
??????????? axisFault.printStackTrace();
??????? } catch (Exception ex) {
??????????? ex.printStackTrace();
??????? } finally {
??????????? try {
??????????????? sender.finalizeInvoke();
??????????? } catch (AxisFault axisFault) {
??????????????? //have to ignore this
??????????? }
??????? }
??? }
}
注解①
RE: [Axis2] 0.95 WS-Addressing web SERVICE-SIDE: module not found
??? I now have managed to get EchoNonBlockingDualClient working. I still can't get the original code to work, where ever I put addressing-0.95.mar, but the ConfigurationContext works.
??? The code I ended up with was:
?ConfigurationContext sysContext = ConfigurationContextFactory
?????????? .createConfigurationContextFromFileSystem(
??????????? "C:\\axis2", null);
? sender = new ServiceClient(sysContext, null);
??? with no need, obviously, for the .engageModule method.
??? I did discover though that the directory which the ConfigurationContext points to has to have two directories within it: "conf", which must contain the axis.xml configuration file, and the "modules" directory which contains addressing-0.95.mar.
??? 在方法"options.setUseSeparateListener(...)"中的布尔标记通知通知Axis2引擎使用两个不同的传输连接来分别处 理request和response。Finally中的 "serviceClient.finalizeInvoke()"方法通知Axis2引擎停用客户端的用于接收response的listener。
??? 在我们运行客户端的例程之前,我们还有一件事情要做。如前面提到的,Axis2使用基于地址的关联机制,因此我们必须在服务器端和客户端“搭建”寻址模块。

结果:
<!---->
<soapenv:envelope xmlns:soapenv="&lt;/font&gt;&lt;font size=" 2"="">http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<soapenv:header>
<wsa:to>http://59.14.131.187:6060/axis2/services/__ANONYMOUS_SERVICE__/__OPERATION_OUT_IN__
</wsa:to>
<wsa:replyto>
<wsa:address>
http://www.w3.org/2005/08/addressing/anonymous
</wsa:address>
</wsa:replyto>
<wsa:from>
<wsa:address>
http://127.0.0.1:8080/axis2/services/MyService
</wsa:address>
</wsa:from>
<wsa:faultto>
<wsa:address>
http://127.0.0.1:8080/axis2/services/MyService
</wsa:address>
</wsa:faultto>
<wsa:messageid>
urn:uuid:B087CBB98F1B51A24711742241136206
</wsa:messageid>
<wsa:action>urn:echo</wsa:action>
<wsa:relatesto wsa:relationshiptype="wsa:Reply">
urn:uuid:CA4B9513377E6E9E1511742241130391
</wsa:relatesto>
</soapenv:header>
<soapenv:body>
<example1:echo xmlns:example1="&lt;/font&gt;&lt;font size=" 2"="">http://example1.org/example1" xmlns:tns="http://ws.apache.org/axis2">
<example1:text>
Axis2 Echo String
</example1:text>
</example1:echo>
</soapenv:body>
</soapenv:envelope>
[SimpleHTTPServer] Stop called
?
2.6 实现服务器端的寻址
??? 根据Axis2的结构,寻址模块在"pre-dispatch"阶段已经给出它的句柄。因此,所谓的“搭建”仅仅是在”axis2.xml”(注意不是 services.xml)增加一个模块的引用。现在将下面这行字加入到axis2.xml,该文件在"/webapps/axis2/WEB- INF/conf"目录下。
<module ref="addressing">
注: 一旦你改变了axis2.xml,你必须重启这个servlet容器,改变才能生效。
?
2.7 实现客户端的寻址
??? 有两种方式。
??? 一种方法是在%Axis2_HOME%\axis2-std-1.0-bin\modules目录下得到addressing-< version>.mar。并且在你的classpath中对其可见。(此种方法目前,我还没有调试成功,具体见注解①。下面的第二种方法可用)
??? 另一种方法是创建一个ConfigurationContext,指定一个repository位置。Axis2支持repository的方式来保存服务和模块。
??? 你可以使用二进制distribution作为repository,只要它含有一个Axis2 repository认可的repository结构(其中应包含services和modules目录)。ConfigurationContext 中含有Axis2体系的运行时的上下文信息。
??? 如果你解压一个标准的二进制distribution到目录(譬如)$user_home/axis2/dist, 那么在 sender = new ServiceClient();之前加入(具体见EchoNonBlockingDualClient.java):
new ServiceClient();之前加入(具体见EchoNonBlockingDualClient.java):
ConfigurationContext configContext =
ConfigurationContextFactory.createConfigurationContextFromFileSystem(< Axis2RepositoryLocation >, null);
??? 用"sender = new ServiceClient(configContext, null);" 替换 "sender = new ServiceClient();"
这样可以在客户端和服务器端都实现寻址。
?
2.8 EchoBlockingDualClient
??? 这又是一个两路的传输的request/response客户端,但这次,我们使用一个Blocking API。实现机制和EchoNonBlockingDualClient差不多,唯一的不同是,这里不需要使用一个callback对象来处理 response。
EchoBlockingDualClient.java
package userguide.clients;
import org.apache.axiom.om.OMElement;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLOutputFactory;
import java.io.StringWriter;
/**
?* Sample for synchronous dual channel blocking service invocation.
?* Message Exchage Pattern IN-OUT
?*/
public class EchoBlockingDualClient {
private static EndpointReference targetEPR =
?new EndpointReference("http://127.0.0.1:8080/axis2/services/MyService");
??? public static void main(String[] args) {
??????? ServiceClient sender = null;
??????? try {
??????????? OMElement payload = ClientUtil.getEchoOMElement();
??????????? Options options = new Options();
??????????? options.setTo(targetEPR);
??????????? options.setAction("urn:echo");
??????????? //The boolean flag informs the axis2 engine to use two separate transport connection
??????????? //to retrieve the response.
??????????? options.setTransportInProtocol(Constants.TRANSPORT_HTTP);
??????????? options.setUseSeparateListener(true);
??????????? //Blocking Invocation
??????????? ConfigurationContext sysContext = ConfigurationContextFactory
??????????? .createConfigurationContextFromFileSystem(
???????????? "D:\\Dvp\\Axis2\\axis2\\WEB-INF", null);
??????????? sender = new ServiceClient(sysContext, null);
??????????? sender.engageModule(new QName(Constants.MODULE_ADDRESSING));
??????????? sender.setOptions(options);
??????????? OMElement result = sender.sendReceive(payload);
??????????? StringWriter writer = new StringWriter();
?????????? result.serialize(XMLOutputFactory.newInstance().createXMLStreamWriter(writer));
??????????? writer.flush();
??????????? System.out.println(writer.toString());
??????????? //Need to close the Client Side Listener.
??????? } catch (AxisFault axisFault) {
??????????? axisFault.printStackTrace();
??????? } catch (Exception ex) {
??????????? ex.printStackTrace();
??????? } finally{
??????????? try {
??????????????? sender.finalizeInvoke();
??????????? } catch (AxisFault axisFault) {
??????????????? //
??????????? }
??????? }
??? }
}
结果:
<example1:echo xmlns:example1="&lt;/font&gt;&lt;font style=" background-color:="" #ffffff;"="" size="2">http://example1.org/example1" xmlns:tns="http://ws.apache.org/axis2">
<example1:text>Axis2 Echo String </example1:text>
</example1:echo>
[SimpleHTTPServer] Stop called

礼物 2008-07-11 12:26 发表评论
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics