应用程序客户机端点调用的请求
同步调用
在同步调用中,客户机将消息发送给服务,并等待响应。服务接收到该消息,对其进行处理,并发送回响应。
按照 WSDL 语法中的定义,请求-响应操作包含输入和输出元素——首先是输入,然后是输出。清单 1. 请求-响应操作的 WSDL<wsdl:definitions .... >
<wsdl:portType .... > *
<wsdl:operation name="nmtoken" parameterOrder="nmtokens">
   <wsdl:input name="nmtoken"? message="qname"/>
   <wsdl:output name="nmtoken"? message="qname"/>
   <wsdl:fault name="nmtoken" message="qname"/>*
</wsdl:operation>
</wsdl:portType >
</wsdl:definitions> WSIF 可提供动态调用 Web 服务的灵活性。WSIF 将对 WSDL 进行解析,获取为服务定义的关于服务、端口、绑定和操作的信息。用户可以在运行时选择端口、传输和操作,并提供输入参数来调用 Web 服务。此处的优势在于,不需要为每个 Web 服务编写独立的客户机。使用 WSIF 的另一个优势是,即使 Web 服务的端点改变,客户机也不用改变。事实上,客户机甚至不需要知道 Web 服务的位置。而且,如果在将来给定服务作为 EJB 提供,客户机可以使用新 WSDL 调用 EJB,而不要对客户机代码进行任何修改。WSIF 对 WSDL 进行分析,从而为输入、输出和错误的 WSIFService、WSIFPort、WSIFoperation、WSIFMessage 创建对象实例,并执行相应操作。WSIF 分发中提供了一个动态调用 Web 服务的一个示例。此方法特别适用于调用简单 Web 服务。WSIF 可以用于调用 RPC 和文档样式的 Web 服务。在清单 2 中,示例代码演示了如何使用 WSIF 来调用 RPC 样式的 Web 服务。清单 2. 使用 WSIF 的 RPC 样式请求-响应 Web 服务客户机示例代码// ...
// get service factory object
WSIFServiceFactory factory = WSIFServiceFactory.newInstance();
// get service object for given wsdl definition object and service object
WSIFService dpf =
factory.getService(definition, service);
// get port from wsif service object for given port name
port = dpf.getPort(portName);
// get operation object from port object for given operation and input/output message names
|-------- XML error:  The previous line is longer than the max of 90 characters ---------|
WSIFOperation operation = port.createOperation(operationName,inputMessage,outputMessage);
// create input message
WSIFMessage input = operation.createInputMessage();
// invoke the service
operation.executeRequestResponseOperation(input, output, fault); 如果 Web 服务是文档样式的 Web 服务,则应用程序可以使用 Axis 客户机:
应用程序动态创建一个客户机(在应用程序执行期间完成),并使用 Web 服务定义中提供的端点信息(具体的端口地址)。
客户机创建 Axis 客户机的“Call”对象的实例,并将 Call 对象中的目标端点地址设置为 Web 服务端点的地址。
接下来,客户机读取调用的服务所需的输入参数。为此,客户机会在运行时使用 JAXB[12] 将 Java 格式的输入参数转换为 XML 元素对象 (org.w3c.dom.Element)。Java Architecture for XML Binding (JAXB) 提供了一种非常方便的方法,可将 XML 模式绑定到 Java 代码中的表示形式。
客户机将创建一个由这些 Element 对象组成的数组,并调用 Axis Call 对象的 invoke 方法。
invoke 方法构造 SOAP 请求消息,并通过发送消息来调用服务,从服务获取输出参数,然后将其作为 org.apache.axis.message.SOAPBodyElement 对象数组返回给客户机。
客户机然后构造与从服务接受到的输出参数对应的等效 Java 对象,这同样也是在运行时使用 JAXB(从 XML 到 Java 绑定)完成的。
然后,客户机将这一组 Java 对象提供给应用程序。
这种调用方法尤其适合用于调用具有复杂数据类型的文档样式 Web 服务。会首先使用 JAXB 将复杂数据类型转换为 XML,然后传递给服务调用者。输入参数也以 XML 格式接收,并使用 JAXB 解析回 Java 对象。清单 3. 使用 WSIF 的 RPC 样式请求-响应 Web 服务客户机示例代码SOAPBodyElement[] element = // create SOAPBodyElement array using input objects
// create call object
Service service = new Service();
Call call = (Call) service.createCall();
// set end point (http address)
call.setTargetEndpointAddress(endPoint);
// invoke the service by passing the SOAPBodyElement
Vector output = (Vector) call.invoke(element);
// create element array from vector
Element elemArray[] = new Element[output.size()];
for (int i = 0; i < output.size(); i++) {
if (output.get(i) instanceof Element) { elemArray[i] = (Element) output.get(i); }
if (output.get(i) instanceof SOAPBodyElement)
{ elemArray[i] = ((SOAPBodyElement) output.get(i)).getAsDOM(); }
}
// convert Element array back into Java Objects using JAXB
异步调用
在异步调用中,客户机将消息发送到服务,服务然后使用该消息。此时,客户机并不会等待服务进行应答。
如 WSDL 语法所定义的,单向操作仅具有输入元素。清单 4. 单向操作的 WSDL<wsdl:definitions> <wsdl:portType .... > *
<wsdl:operation name="nmtoken">
   <wsdl:input name="nmtoken"? message="qname"/>
</wsdl:operation>
</wsdl:portType >
</wsdl:definitions>>可以通过使用 SOAP over JMS 实现异步调用。JMS 的缺省行为就是进行异步消息传递。
清单 5. 使用 SOAP over JMS 的单向 Web 服务客户机示例代码// ...
// provide JMS handler
Call.addTransportPackage(packageName);
Call.setTransportForProtocol("JMSTransport",JMSTransport.class);
// get client configuration
EngineConfiguration defaultConfig =(new DefaultEngineConfigurationFactory()).getClientEngineConfig();
// create custom configuration for client
SimpleProvider config = new SimpleProvider(defaultConfig);
// get chain for given transport
SimpleTargetedChain chain = new SimpleTargetedChain(new JMSSender(connectionFactory, destination));
config.deployTransport("JMSTransport", chain);
// create service using custom configuration
Service service = new Service(config);
Call call = (Call) service.createCall();
call.setOperation(super.getOperation());
// set JMS specific information (topic/queue name, context factory) in call
// these values will be needed in chain for actually sending JMS message
call.setProperty(JMSConstants.DESTINATION, destination);
call.setProperty("transport.jms.ConnectionFactoryJNDIName",connectionFactory);
if (destinationDomain.equalsIgnoreCase("topic"))
{
call.setProperty(JMSConstants.DOMAIN,JMSConstants.DOMAIN_TOPIC);
}
if (destinationDomain.equalsIgnoreCase("queue"))
{
call.setProperty(JMSConstants.DOMAIN,JMSConstants.DOMAIN_QUEUE);
}
call.setTransport(new JMSTransport());// invoke the web service
call.invoke(params);
// ...WSIF 支持异步调用。可以通过调用 API 中的不同方法来使用 WSIF 客户机进行异步调用。清单 6. 使用 WSIF 的单向 Web 服务客户机示例代码
// ...
// create operation
WSIFOperation operation = port.createOperation(operationName,inputMessage,outputMessage);
// prepare input
WSIFMessage input = operation.createInputMessage();
// invoke web service one-way
operation.executeInputOnlyOperation(input);
// ...