您的位置:首页 > 其它

使用Axis2的底层API开发Web Service

2011-11-03 22:02 525 查看
标签:Axis2web

WebService
原创作品,允许转载,转载时请务必以超链接形式标明文章
原始出处 、作者信息和本声明。否则将追究法律责任。/article/4381701.html

本文是在理解官方指南的基础上,用实例实现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”>

<!--details for Services1-->

</service>

<service name=”Service2”>

<!--details for Services2-->

</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="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) { }

}

}

}

结果:

<?xml version='1.0' encoding='utf-8'?>

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">

<soapenv:Header />

<soapenv:Body>

<example1:echo xmlns:example1="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使用基于地址的关联机制,因此我们必须在服务器端和客户端“搭建”寻址模块。

结果:

<?xml version='1.0' encoding='utf-8'?>

<soapenv:Envelope xmlns:soapenv="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="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="http://example1.org/example1" xmlns:tns="http://ws.apache.org/axis2">

<example1:Text>Axis2 Echo String </example1:Text>

</example1:echo>

[SimpleHTTPServer] Stop called
本文出自 “子 孑” 博客,请务必保留此出处/article/4381701.html

<!--

0人
了这篇文章
-->

0人
了这篇文章
类别:Java┆技术圈( 0)┆阅读( 13815)┆评论( 22) ┆推送到技术圈返回首页
上一篇
基于JMF RTP的网络传输媒体流 下一篇
Axis2中使用模块

相关文章

使用Axis2来构建Web Service客户端
Axis2中使用模块
基于Tomcat5.0和Axis2开发Web Service代码详解
使用Axis2传输附件(AXIS2 MTOM)
WTP1.0开发WebService之Java Class实例
WTP1.0开发WebService之使用WSDL生成Service
Eclipse下使用Axis开发webservice
关于web2.0的学习

文章评论

<< 1 2
3 >> 页数 ( 1/3 )

[1楼]

[匿名]小雨

[align=right]2007-05-02 20:17:58[/align]
这么好的文章当然要收藏啦

短消息通知评论者

[2楼]

[匿名]maoma-katze

[align=right]2007-08-03 20:11:12[/align]
博主,你好!

不好意思,还是我!

上面的2.4EchoNonBlockingClient的方法说:很多Web Service需要在一个单一的客户端应用程序中启动时,一种解决方法是使用Non-Blocking API来调用这些Web Services。Axis2提供给用户一种基于回叫机制的non-blocking API。

我在机子上试了上面的方法。但运行失败了!

我在service.java程序中。写入了两处OMElement:

public OMElement nachName(OMElement element)

public OMElement vorName(OMElement element)

在services.xml文本中加入了:

<operation name="nachName">

<operation name="vorName">

最后在client.java程序中调用这个服务:

public class Client {

private static EndpointReference targetEPR =

new EndpointReference();

public static OMElement nachNamePayload(String nachname){}

public static OMElement vornamePayload(String vorName){}

public static void main(String[] args){}

try {调用nachnamePayload(基本上和上面的例子差不多)}

try{调用vornamePayload}

}

最后运行到第二个vornamePayload报错了,错误我拷贝如下:

gib den Name an:

maomao

gib den Vornamename an:

这时报错:

org.apache.axis2.AxisFault: The endpoint reference (EPR) for the Operation not found is http://192.168.150.69:8080/axis2/services/Mackunden and the WSA Action = urn:anonOutInOp

at org.apache.axis2.util.Utils.getInboundFaultFromMessageContext(Utils.java:434)

at org.apache.axis2.description.OutInAxisOperationClient.send(OutInAxisOperation.java:373)

at org.apache.axis2.description.OutInAxisOperationClient$NonBlockingInvocationWorker.run(OutInAxisOperation.java:405)

at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:665)

at edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:690)

at java.lang.Thread.run(Unknown Source)

我再继续输入katze,报错如下:

katze

org.apache.axis2.AxisFault: The endpoint reference (EPR) for the Operation not found is http://192.168.150.69:8080/axis2/services/Mackunden and the WSA Action = urn:anonOutInOp

博主,这是为什么呢?

1。第二次呼叫服务端找不到endpoint. 是不是在一个class里,只能调用一次endpoint?还是,根本就不应该在service.java 的class里加入两个in-out 的OMElemnt(就是说,在一个服务class里,只能返回一个OMElement)?

2。 如果把这两个服务分别写入两个service.java文件中,按上面介绍的,要定义一个servicegruppe.xml文档。那么<module ref=”ModuleName”/>

<parameter name=”serviceGroupParam1” locked=”false”>value1</parameter>

这两名里的·"ModuleName" 是被定义好的,还是可以自己随便给的? 还有就是parameter不是在每个<service name="service">里都要设置吗?为什么这里还要设置呢?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: