尽管XML消息交换是Web服务的核心,但是大多数Web服务应用程序都不关心XML。 而是,这些应用程序希望交换特定于该应用程序的业务数据。 在这种情况下,XML只是一种用于表示支持Web服务接口的业务数据的格式。 XML为此很好地工作,因为XML提供了与平台无关的表示形式,可以通过各种工具来处理。 但是应用程序最终需要将XML与它们自己的内部数据结构进行相互转换,以在应用程序中使用数据。
数据绑定是用于处理XML与应用程序数据结构之间的这种转换的技术的术语。 可以为应用程序编写自定义数据绑定代码,但是大多数开发人员发现使用以通用方式处理转换的数据绑定框架更适用,适用于各种应用程序。 Apache Axis2 Web服务框架的主要优势之一是从一开始就设计为可与各种数据绑定框架一起使用。 您可以选择最适合您的数据绑定方法,并使用该方法来处理XML和数据结构之间的转换,同时使用Axis2框架(和扩展)来处理实际的Web服务工作。
本文向您展示如何将Axis2的数据绑定灵活性与示例代码一起用于使用支持的三种数据绑定实现的同一Web服务。 找出为什么您可能更喜欢其中一种数据绑定。
链接到Axis2
在本系列的上一篇文章中 ,您了解了Axis2用于XML消息处理的AXIOM文档模型。 AXIOM与其他文档模型的不同之处在于,AXIOM支持按需构建模型,而不是一次全部构建模型。 当使用数据绑定框架将XML与应用程序数据结构之间来回转换时,数据绑定XML通常只是AXIOM文档模型的虚拟部分。 除非出于某种原因(例如,使用WS-Security时进行加密或签名)需要该模型,否则不会将其扩展为完整的文档模型。
为了将应用程序与直接使用AXIOM隔离开来,Axis2支持从Web服务描述语言(WSDL)服务描述生成链接代码。 生成的链接代码使用您选择的数据绑定框架处理将数据结构与XML相互转换的细节,从而使您的应用程序可以直接访问数据结构。 Axis2还提供了一些其他方面的有限支持,即从现有代码生成WSDL。
Axis2为服务客户端和服务提供者生成链接代码。 客户端链接代码采用存根类的形式,它始终扩展Axis2 org.apache.axis2.client.Stub
类。 提供程序(或服务器)链接代码采用特定于服务的实现框架以及实现org.apache.axis2.engine.MessageReceiver
接口的消息接收器类的形式。 客户端和服务器链接代码的生成均由WSDL2Java工具处理。 接下来,您将看一下实际的链接代码,然后深入研究使用WSDL2Java工具的细节,并通过快速查看从现有代码开始的方法来完成本节。
客户端链接代码
客户端存根代码定义了应用程序代码调用服务操作的访问方法。 首先,您通常使用默认构造函数(如果您的服务端点始终与用于生成存根的WSDL中定义的端点相同)创建存根类的实例,或者使用不同的端点引用作为字符串。 创建存根的实例之后,可以选择使用基类org.apache.axis2.client.Stub
类定义的方法来配置各种功能。 然后,您可以调用特定于服务的访问方法来实际调用操作。
清单1显示了一个示例,该示例说明了如何创建一个存根,并将服务端点(从WSDL中的端点)更改为客户端系统(本地主机)上的默认Tcpmon端口8800。 Tcpmon是监视Web服务消息交换的流行工具,因此在客户端代码中将此选项作为选项通常很有用。 创建存根实例后,超时值将从默认值更改(在调试提供程序代码时也很有用,因为您可以轻易超过20秒的标准超时时间),并调用服务方法。
清单1.客户端存根用法示例
LibraryStub stub = new LibraryStub("http://localhost:8800/axis2/services/library");
stub.getServiceClient().getOptions().setTimeoutInMilliseconds(10000000);
Types[] types = stub.getTypes();
清单1的代码显示了一个同步服务方法调用,其中客户端线程在该服务调用内阻塞,并且直到调用完成且结果可用时才返回。 Axis2还使用回调接口支持异步调用。 清单2显示了清单1的代码,该代码被修改为使用简单的异步调用(这很简单,因为应用程序代码只是等待操作完成,而不做任何有用的事情)。
清单2.客户端存根异步示例
LibraryStub stub = new LibraryStub("http://localhost:8800/axis2/services/library");
TypesCallback cb = new TypesCallback();
stub.startgetTypes(cb);
Type[] types;
synchronized (cb) {
while (!cb.m_done) {
try {
cb.wait();
} catch (Exception e) {}
}
types = cb.m_result;
if (types == null) {
throw cb.m_exception;
}
}
...
private static class TypesCallback extends LibraryCallbackHandler
{
private boolean m_done;
private Types[] m_result;
private Exception m_exception;
public synchronized void receiveResultgetTypes(Type[] resp) {
m_result = resp;
m_done = true;
notify();
}
public synchronized void receiveErrorgetTypes(Exception e) {
m_exception = e;
m_done = true;
notify();
}
}
使用清单2中使用的HTTP连接,响应通常立即返回给客户端。 在通过将请求与响应分离的传输进行操作(例如Java™消息服务(JMS)或简单邮件传输协议(SMTP))时,异步调用最为有用,因为在这种情况下,请求之间的时间可能会大大延迟发送以及何时收到响应。 当然,使用HTTP访问的服务也可能涉及大量的处理延迟。 对于具有此类延迟的HTTP服务,可以使用WS-Addressing来允许分离的响应,异步调用对于处理这些响应很有用。
除了存根类(如果有异步支持,则为回调处理程序类),还为客户端代码生成了一个接口。 接口定义与WSDL portType
定义的操作匹配的服务方法。 存根实现此接口,并添加一些内部使用的专用方法。 您可以直接使用存根,如清单1和清单2所示 ,或者仅使用该接口仅查看那些属于服务定义的方法。 无论哪种方式,当您调用其中一种服务方法时,存根都会使用所选的数据绑定框架处理将请求数据对象转换为XML,然后将返回的XML转换为响应数据对象的过程。
如果您只想直接在客户端上使用XML,则根本不需要使用生成的客户端存根类。 相反,您可以使用org.apache.axis2.client.ServiceClient
类。 这样做意味着您首先需要配置服务和操作,然后调用ServiceClient.createClient()
方法来为该操作创建org.apache.axis2.client.OperationClient
。 为了方便起见,WSDL2Java工具(在本文稍后介绍)提供了一个选项,即使您直接使用XML,也可以生成存根类。 这种情况下生成的存根看起来很像数据绑定示例,只不过它传递了AXIOM元素而不是数据对象。
服务器链接代码
Axis2的服务器端链接代码是消息接收器,定义为Axis2服务配置的一部分。 此消息接收器必须实现org.apache.axis2.engine.MessageReceiver
接口。 该接口定义了一个void receive(org.apache.axis2.context.MessageContext)
方法。 当收到请求消息时,Axis2框架将调用此方法,然后该方法负责处理请求的所有处理(如果合适,还包括生成响应)。
如果直接使用XML(以AXIOM元素的形式),则可以将标准org.apache.axis2.receivers.RawXML*MessageReceiver
类之一用于服务器端链接(其中*表示消息的类型)服务使用的交换)。 否则,您将使用生成的消息接收器类,该类在基于Axis2 AXIOM的接口和使用数据对象的服务代码之间进行调整。 该服务代码以框架实现的形式生成,其服务方法仅引发异常。 您需要将自己的代码添加到框架中以完成服务器端连接。
清单3显示了服务器端框架的一个示例(为了可读性而重新格式化),其中的getBook()
方法保持生成状态,而getTypes()
方法通过委派给实际的实现类来实现。
清单3.服务器框架示例
public class LibrarySkeleton
{
private final LibraryServer m_server;
public LibrarySkeleton() {
m_server = new LibraryServer();
}
/**
* Auto generated method signature
*
* @param isbn
* @return book value
*/
public com.sosnoski.ws.library.Book getBook(java.lang.String isbn) {
//Todo fill this with the necessary business logic
throw new java.lang.UnsupportedOperationException("Please implement " +
this.getClass().getName() + "#getBook");
}
/**
* Get the types of books included in library.
*
* @return types
*/
public com.sosnoski.ws.library.Type[] getTypes() {
return m_server.getTypes();
}
}
直接向此类添加代码的不利之处在于,如果服务接口发生更改,则需要重新生成该类并合并您的更改。 您可以通过使用单独的实现类来扩展生成的框架,从而避免覆盖框架方法而无需更改生成的代码,来避免这种情况。 为此,您需要更改生成的services.xml服务描述。 这很容易; 只需将骨架类名称替换为实现类名称即可。 本文后面介绍的数据绑定示例都使用单独的实现类方法。 您可以在“ 下载”部分中查看这些示例的Ant build.xml文件,以了解如何自动执行替换。
Axis2工具
Axis2提供了各种工具来帮助开发人员使用该框架。 其中最重要的工具是使您可以从WSDL服务定义中生成Java链接代码(在上一节中找到)并从现有Java代码中生成WSDL服务定义的工具。
从WSDL生成代码
Axis2提供了一个WSDL2Java工具,用于根据WSDL服务描述生成代码。 您可以通过将org.apache.axis2.wsdl.WSDL2Java
类作为Java应用程序运行,或通过Ant任务,Maven插件或Eclipse或IDEA插件直接使用此工具。 选择太多的弊端在于,在功能和错误修复方面,替代方法通常落后于基本Java应用程序,因此通常最好直接运行Java应用程序(本文将介绍)。
WSDL2Java提供了许多不同的命令行选项,选项的数量随着时间的推移而增加。 Axis2文档包含对选项的完整引用,因此您仅在此处查看一些最重要的选项:
-
-o path
设置输出类和文件的目标目录(默认为工作目录) -
-p package-name
—为生成的类设置目标软件包(默认是从WSDL名称空间生成的) -
-d name
name-设置数据绑定框架(用于ADB的adb ,用于XMLBeans的xmlbeans,用于JiBX的jibx以及用于无数据绑定的none ;默认为adb ) -
-uw
—解开doc / lit-wrapped消息,仅用于受支持的框架(当前为ADB和JiBX) -
-s
仅生成同步客户端接口 -
-ss
生成服务器端代码 -
-sd
生成服务器端部署文件 -
-uri path
设置WSDL的路径以生成服务
还有一些特定于特定数据绑定框架的WSDL2Java选项。 在本文后面的数据绑定示例中,您可以看到其中两个选项。
从代码生成WSDL
Axis2还提供了Java2WSDL工具,可用于从现有服务代码生成WSDL服务定义。 但是,此工具有很多限制,包括无法使用Java集合类以及在构造从Java类生成的XML时缺乏灵活性。 限制的部分原因是由于Web服务开发方式的变化而导致对该领域缺乏兴趣。
通常,从现有代码开始开发Web服务时,Web服务和SOA领域中的许多机构都不满意。 他们认为,当Web服务的整个原理是XML应该独立于实现时,从代码开始就鼓励将XML消息结构耦合到特定的实现。 这种担忧当然有一些实质,但也有一些相反的论点。 一是从头开始编写WSDL服务和XML模式定义所涉及的困难。 WSDL和模式都是复杂的标准,使用这些定义的可用工具需要对要有效使用的标准有很好的了解。 如果开发人员在没有标准基础的情况下使用它,则生成的WSDL和模式通常比从代码生成的WSDL和模式更混乱。 另一个问题严格可行。 开发人员通常具有现有代码来实现现在需要作为Web服务公开的功能,并且他们希望能够在不进行实质性更改的情况下使用该现有代码。 因此,在可预见的将来,从代码生成WSDL可能仍然是一个问题。
对于Java2WSDL的更强大的替代方法,可以尝试使用我开发的Jibx2Wsdl工具( 有关更多信息,请参见参考资料部分)。 Jibx2Wsdl从一个或多个提供的服务类生成一整套WSDL,模式和JiBX绑定定义。 它支持Java 5枚举和通用集合,同时保持与旧版Java虚拟机(JVM)的兼容性,并自动从Java源文件中导出Javadocs作为生成的WSDL和架构定义的文档。 Jibx2Wsdl还提供了广泛的自定义机制来控制如何从Java类派生服务和XML表示,这甚至允许将Java 5之前的集合与类型化数据一起使用。 尽管Jibx2Wsdl专门用于简化使用JiBX数据绑定框架(也是由我创建)的现有类作为Web服务的部署,但是生成的WSDL和模式与数据绑定无关。 您可以将它们与其他Java数据绑定框架甚至其他平台一起使用-生成所有内容,然后丢弃JiBX绑定并保留其余内容。
如果使用的是Java 5或更高版本,另一种选择是使用XML绑定的Java体系结构(JAXB)2.0和XML Web服务的Java API(JAX-WS)批注将数据对象和服务类公开为Web服务。 这些批注提供的自定义级别与Jibx2Wsdl所提供的级别不同,但是它们使您可以将配置信息直接嵌入到源代码中,这对某些开发人员来说很有吸引力。 Axis2从1.2版本开始提供对JAXB 2.0和JAX-WS的实验性支持,并且在将来的版本中将对此进行改进。 Jibx2Wsdl的未来版本可能还支持使用JAXB 2.0和JAX-WS批注作为自定义项。 (本系列的后续文章将更深入地介绍JAXB 2.0和JAX-WS,并回到那时从代码生成WSDL的主题。)
数据绑定比较
Axis2(从1.2版本开始)完全支持三种数据绑定替代方案,并且还在不断增加。 本文使用三个完全支持的数据绑定框架对示例代码进行了比较,并介绍了与Axis2一起使用时每个框架的一些优缺点。
清单4中显示的示例代码(也包含在“ 下载”部分的示例下载中)用于图书馆服务,该服务维护按主题类型组织的书籍的集合。 库上定义了一些操作,包括:
-
getBook
-
getTypes
-
addBook
-
getBooksByType
清单4提供了此服务的WSDL的局部视图,仅显示了getBook
操作中涉及的部分。
清单4.库服务WSDL
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://ws.sosnoski.com/library/wsdl"
xmlns:wns="http://ws.sosnoski.com/library/wsdl"
xmlns:tns="http://ws.sosnoski.com/library/types"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<schema elementFormDefault="qualified"
targetNamespace="http://ws.sosnoski.com/library/wsdl"
xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="http://ws.sosnoski.com/library/types"/>
<element name="getBook">
<complexType>
<sequence>
<element name="isbn" type="string"/>
</sequence>
</complexType>
</element>
<element name="getBookResponse">
<complexType>
<sequence>
<element name="getBookReturn" minOccurs="0" type="tns:BookInformation"/>
</sequence>
</complexType>
</element>
...
</schema>
<schema elementFormDefault="qualified"
targetNamespace="http://ws.sosnoski.com/library/types"
xmlns="http://www.w3.org/2001/XMLSchema">
<complexType name="BookInformation">
<sequence>
<element name="author" minOccurs="0" maxOccurs="unbounded" type="string"/>
<element name="title" type="string"/>
</sequence>
<attribute name="type" use="required" type="string"/>
<attribute name="isbn" use="required" type="string"/>
</complexType>
...
</schema>
</wsdl:types>
<wsdl:message name="getBookRequest">
<wsdl:part element="wns:getBook" name="parameters"/>
</wsdl:message>
<wsdl:message name="getBookResponse">
<wsdl:part element="wns:getBookResponse" name="parameters"/>
</wsdl:message>
...
<wsdl:portType name="Library">
<wsdl:operation name="getBook">
<wsdl:input message="wns:getBookRequest" name="getBookRequest"/>
<wsdl:output message="wns:getBookResponse" name="getBookResponse"/>
</wsdl:operation>
...
</wsdl:portType>
<wsdl:binding name="LibrarySoapBinding" type="wns:Library">
<wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getBook">
<wsdlsoap:operation soapAction="urn:getBook"/>
<wsdl:input name="getBookRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="getBookResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
...
</wsdl:binding>
...
</wsdl:definitions>
实际的服务实现代码很简单,用一个硬编码的书单填充一个库实例。 客户端代码按以下顺序执行一系列查询:
- 一本
getBook
- 一个
getTypes
- 一对
addBook
,其中第二对返回SOAP Fault,以尝试添加重复的书本ID - 一个
getBooksByType
示例之间的实现细节有所不同,因为每个示例都使用适合该数据绑定的数据对象。 除非另有说明,否则显示的所有代码均与Axis2 1.1.1和1.2一致。 随着本文的发布,正在进行中的Axis2 1.3版本由于对与服务故障相对应的生成的异常类的命名进行了更改,因此需要对代码进行一些小的更改。 提供了两个版本的代码(请参见下载部分)。
在本文中,尽管提供的下载内容(请参见下载部分)包括客户端和服务器代码以及所有示例的Ant构建文件,但您仅查看客户端代码。 接下来,查看三个数据绑定框架的客户端代码,并了解每种方法的优缺点。
Axis2数据绑定
ADB是Axis2的数据绑定扩展。 与其他数据绑定框架不同,ADB代码仅可用于Axis2 Web服务。 此限制是对亚行的重要限制,但也具有一些优势。 由于ADB与Axis2集成在一起,因此可以针对Axis2的要求对代码进行优化。 一个例子是,ADB建立在Axis2核心的AXis对象模型(AXIOM)文档模型上(如本系列中的上一篇文章所述 )。 亚行还提供了其他数据绑定框架目前不具备的一些增强功能,包括自动附件处理。 WSDL2Java为ADB代码生成提供全面支持,包括生成与XML模式组件相对应的数据模型类。
ADB模式支持有一些限制。 在当前的Axis2 1.2版本中,这些限制包括架构功能,例如具有maxOccurs="unbounded"
合成器,具有attributeFormDefault="qualified"
架构定义以及一些类似的变体。 但是Axis2 1.2 ADB架构支持比Axis2 1.1发行版要好得多,并且在每个Axis2框架发行版之前,支持都可能会持续改善,直到支持所有主要架构功能。
ADB代码生成的基本形式使用直接模型,其中单独的类对应于每个操作所使用的输入和输出消息。 清单5显示了使用这种基本形式的ADB代码生成的示例应用程序的客户端代码中最有趣的部分。 客户机代码演示与ADB生成的类,如相互作用GetBookDocument
和GetBookDocument.GetBook
用于参数的类getBook()
方法的调用,并且GetBookResponseDocument
和BookInformation
用于从该呼叫的返回类。
清单5. ADB客户端代码
// create the client stub
AdbLibraryStub stub = new AdbLibraryStub(target);
// retrieve a book directly
String isbn = "0061020052";
GetBook gb = new GetBook();
gb.setIsbn(isbn);
GetBookResponse gbr = stub.getBook(gb);
BookInformation book = gbr.getGetBookReturn();
if (book == null) {
System.out.println("No book found with ISBN '" + isbn + '\'');
} else {
System.out.println("Retrieved '" + book.getTitle() + '\'');
}
// retrieve the list of types defined
GetTypesResponse gtr = stub.getTypes(new GetTypes());
TypeInformation[] types = gtr.getGetTypesReturn();
System.out.println("Retrieved " + types.length + " types:");
for (int i = 0; i < types.length; i++) {
System.out.println(" '" + types[i].getName() + "' with " +
types[i].getCount() + " books");
}
// add a new book
String title = "The Dragon Never Sleeps";
isbn = "0445203498";
try {
AddBook ab = new AddBook();
ab.setType("scifi");
ab.setAuthor(new String[] { "Cook, Glen" });
ab.setIsbn(isbn);
ab.setTitle(title);
stub.addBook(ab);
System.out.println("Added '" + title + '\'');
ab.setTitle("This Should Not Work");
stub.addBook(ab);
System.out.println("Added duplicate book - should not happen!");
} catch (AddDuplicateFaultException e) {
System.out.println("Failed adding '" + title +
"' with ISBN '" + isbn + "' - matches existing title '" +
e.getFaultMessage().getBook().getTitle() + '\'');
}
// create a callback instance
CallbackHandler cb = new CallbackHandler();
// retrieve all books of a type asynchronously
GetBooksByType gbbt = new GetBooksByType();
gbbt.setType("scifi");
stub.startgetBooksByType(gbbt, cb);
long start = System.currentTimeMillis();
synchronized (cb) {
while (!cb.m_done) {
try {
cb.wait(100);
} catch (Exception e) {}
}
}
System.out.println("Asynchronous operation took " +
(System.currentTimeMillis()-start) + " millis");
if (cb.m_response != null) {
BookInformation[] books = cb.m_response.getGetBooksByTypeReturn();
...
清单5使用了-u WSDL2Java选项生成的代码,该代码特定于ADB。 使用此选项,将为每个消息和数据模型类生成一个单独的Java源文件。 如果不使用此选项,则ADB代码生成将所有这些类生成为生成的存根的静态内部类。 使用单独的类要容易得多,因此,如果使用ADB,则应指定-u选项。
代码生成的直接形式导致每个操作的输入和输出都有大量单独的类(与-u选项无关,后者只是以不同的方式组织相同的类)。 这些生成的消息类通常包含很少的数据(对于GetTypes
类,甚至不包含)有用的数据,但是生成的方法签名需要这些数据。 幸运的是,还有另一种形式的代码生成适用于许多常见服务。
亚行展开
Web服务通常是基于现有编程API的方法调用形式开发的,在这种情况下,将现有API嵌入Web服务是很方便的。 这很容易做到; 毕竟,为服务定义的操作(从技术上来说,是为portType定义的,如果有人想挑剔的话)实质上等同于接口定义中的方法调用。 唯一的主要区别是该服务将输入和输出定义为XML消息,而不是调用参数和返回值。 因此,要将现有API嵌入到Web服务定义中,您只需要一个约定,以约定如何将调用参数和返回值表示为XML消息结构。
幸运的是,Microsoft®早在这方面就建立了约定,从而使我们其余的人不必自己做一些事情。 此约定称为包装文档/文字约定,是.NET在将方法调用公开为Web服务操作时使用的默认表示形式。 本质上,这种包装方法表示每个输入消息都是仅由一系列子元素组成的XML元素,每个输出消息都是具有单个子元素的XML元素。 除了完全的.NET互操作性之外,Microsoft实现还有其他一些技术细节并不是很重要,但是除了这些细节之外,用于库示例的消息(有关部分视图,请参见清单4 )也遵循这种方法。
WSDL2Java支持在ADB代码生成中解包此类打包的doc / lit服务。 当将拆包与合适的WSDL服务定义一起使用时,生成的客户端存根(以及服务器框架)将更简单,更直接。 清单6显示了与清单5等效的客户机应用程序代码,但将-uw参数传递给WSDL2Java来生成未包装的接口。 清单5中消除了增加了清单5复杂性的消息类( GetTypes
类除外),并且服务方法接受参数并直接返回结果,而不是嵌入消息类中。 在后台,ADB仍然会生成消息类并在生成的代码中使用它们,但是您的代码通常可以忽略这些类并直接使用数据。
清单6. ADB展开的客户端代码
// create the client stub
AdbUnwrapLibraryStub stub = new AdbUnwrapLibraryStub(target);
// retrieve a book directly
String isbn = "0061020052";
BookInformation book = stub.getBook(isbn);
if (book == null) {
System.out.println("No book found with ISBN '" + isbn + '\'');
} else {
System.out.println("Retrieved '" + book.getTitle() + '\'');
}
// retrieve the list of types defined
TypeInformation[] types = stub.getTypes(new GetTypes());
System.out.println("Retrieved " + types.length + " types:");
for (int i = 0; i < types.length; i++) {
System.out.println(" '" + types[i].getName() + "' with " +
types[i].getCount() + " books");
}
// add a new book
String title = "The Dragon Never Sleeps";
isbn = "0445203498";
try {
stub.addBook("scifi", isbn, new String[] { "Cook, Glen" }, title);
System.out.println("Added '" + title + '\'');
title = "This Should Not Work";
stub.addBook("xml", isbn, new String[] { "Nobody, Ima" }, title);
System.out.println("Added duplicate book - should not happen!");
} catch (AddDuplicateFaultException e) {
System.out.println("Failed adding '" + title +
"' with ISBN '" + isbn + "' - matches existing title '" +
e.getFaultMessage().getBook().getTitle() + '\'');
}
// create a callback instance
BooksByTypeCallback cb = new BooksByTypeCallback();
// retrieve all books of a type asynchronously
stub.startgetBooksByType("scifi", cb);
long start = System.currentTimeMillis();
synchronized (cb) {
while (!cb.m_done) {
try {
cb.wait(100L);
} catch (Exception e) {}
}
}
System.out.println("Asynchronous operation took " +
(System.currentTimeMillis()-start) + " millis");
if (cb.m_books != null) {
BookInformation[] books = cb.m_books;
...
ADB展开支持的主要问题在于,它尚不完全稳定。 清单6的代码适合与Axis2 1.2一起使用,并且包含了一些原本用于Axis2 1.1.1中未包装的ADB的代码的重大改进。 但是WSDL2Java工具要求通过将数据类的内联模式移动到单独的模式文档中,来重组与其他示例一起使用的