WSDL 文件对 Web 服务进行了描述。代码示例 1 包含了此服务 WSDL 中的代码片段。我们选择的开发形式是从 WSDL 开始的,并基于 WSDL 生成必要的 Java[TM] 类。因此,为消息部分在 WSDL 中选择正确的类型是非常重要的,因为这些类型会在生成的 Java 代码中产生参数类型。请注意请求消息被声明为 type="anyType",这将生成 Java 接口(如代码示例 2 所示),接口中的服务将输入参数映射到 Java SOAPElement
类型。此外,还请注意在 WSDL 中声明的应用程序定义的服务异常。
<types>
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="urn:AnyTypePurchaseOrderService">
<complexType name="submitPO">
<sequence>
<element name="BusinessDocumentRequest"
type="anyType" nillable="true"/>
</sequence>
</complexType>
<complexType
name="submitPOResponse">
<sequence>
<element name="result" type="string"
nillable="true"/>
</sequence>
</complexType>
<complexType
name="InvalidPOException">
<sequence>
<element name="message" type="string"
nillable="true"/>
</sequence>
</complexType>
<element name="submitPO"
type="tns:submitPO"/>
<element name="submitPOResponse"
type="tns:submitPOResponse"/>
<element name="InvalidPOException"
type="tns:InvalidPOException"/>
</schema>
</types>
<message
name="AnyTypePurchaseOrderServiceSEI_submitPO">
<part name="parameters"
element="ns1:submitPO"/>
</message>
<message
name="AnyTypePurchaseOrderServiceSEI_submitPOResponse">
<part name="result"
element="ns1:submitPOResponse"/>
</message>
<message name="InvalidPOException">
<part
name="InvalidPOException" element="ns1:InvalidPOException"/>
</message>
<portType
name="AnyTypePurchaseOrderServiceSEI">
<operation name="submitPO">
<input
message="tns:AnyTypePurchaseOrderServiceSEI_submitPO"/>
<output
message="tns:AnyTypePurchaseOrderServiceSEI_submitPOResponse"/>
<fault
name="InvalidPOException" message="tns:InvalidPOException"/>
</operation>
</portType>
javax.xml.soap.SOAPElement
对象的 submitPO()
方法。此外,还从 WSDL 生成了应用程序定义的异常 InvalidPOException
。public interface
AnyTypePurchaseOrderServiceSEI extends Remote {
public String submitPO(SOAPElement
businessDocumentRequest)
throws
InvalidPOException,
RemoteException;
}
代码示例 2:服务端点接口SOAPElement
处理。端点实现类如代码示例 3 所示。public class
AnyTypePurchaseOrderServiceBean implements SessionBean {
private SessionContext sc;
private POXMLUtil xmlUtil;
public AnyTypePurchaseOrderServiceBean() {}
public String submitPO(SOAPElement request) throws
InvalidPOException, RemoteException {
String poID = null;
SOAPElement reply = null;
try {
NodeList list = ((Element)request).getElementsByTagName("poId");
for
(int loop = 0; loop < list.getLength(); loop++) {
Node node = list.item(loop);
if (node != null) {
Node child = node.getFirstChild();
if ((child != null) && child.getNodeValue() != null){
poID = child.getNodeValue();
}
}
}
} catch (Exception exe) {
throw new EJBException("AnyTypePOService Having
Problems:"+exe.getMessage(), exe);
}
//this is done just to
illustrate throwing an application specific exception
if(poID.equals("100"))
throw new InvalidPOException("Invalid ID for the purchase order!!! " +
"For demo purposes, we throw " +
"an application defined exception for the ID value of 100.");
return poID;
}
//life cycle methods
...
}
代码示例 3:端点实现我们已经查看了服务代码,我们再简单看一下此应用程序的客户端。客户端将使用代码示例 1 中的 WSDL 文件,并生成一个 Java 服务接口(如代码示例 4 所示),并且使用此服务的 Java 接口(如代码示例 5 中的客户端代码所示)将订单发送到服务中。请注意,将收集此客户端应用程序中的订单数据作为 Web 应用程序(它包含客户端定义的 PurchaseOrder
类型中的数据,如代码示例 6 所示)的输入,并将此订单 Java 对象转换为 SOAPElement,然后发送到服务中。
public interface
AnyTypePurchaseOrderServiceSEI extends Remote {
public String
submitPO(SOAPElement businessDocumentRequest) throws
com.sun.j2ee.blueprints.docoriented.client.anytypeposervice.InvalidPOException,
RemoteException;
}
public class AnyTypePOServiceBD {
private ServiceLocator serviceLocator;
public AnyTypePOServiceBD(){
serviceLocator = new
ServiceLocator();
}
public String submitPO(PurchaseOrder po) throws
RequestHandlerException {
try {
//this flag is to generate a wrapper element BusinessDocumentRequest
//as
defined in the WSDL
boolean wrapper = true;
AnyTypePurchaseOrderServiceSEI port = (AnyTypePurchaseOrderServiceSEI)
serviceLocator.getServicePort(JNDINames.ANY_TYPE_SERVICE_REF,
AnyTypePurchaseOrderServiceSEI.class);
SOAPElement requestSOAPElem =
po.toXMLSOAPElement(wrapper);
return port.submitPO(requestSOAPElem);
} catch(InvalidPOException
ipe){
ipe.printStackTrace(System.err);
throw new RequestHandlerException("Request Handler Exception: Service
Endpoint Application-Defined Exception "+ipe.getMessage(), ipe);
} catch(RemoteException re){
re.printStackTrace(System.err);
throw new RuntimeException("The web service you are trying to access is
not available. A possible reason could be that the service has not been
deployed yet. "+ re.getMessage(), re);
}
}
}
代码示例 5:将订单 XML 文档发送到 anyType 服务的客户端代码由客户端应用程序生成的帮助 PurchaseOrder 类如代码示例 6 所示。在客户端应用程序中,会提交 Web 页表单,然后用数据填充 PurchaseOrder
。然后在代码示例 5 中使用此类以获取提交到服务的订单 XML 文档的表示。请注意 PurchaseOrder 类具有一个转换 Java 订单的方法 toXMLSOAPElement()
。特别要注意的是,订单 XML 被封装在此服务的 WSDL 定义的 BusinessDocumentRequest
父元素中。因此,在使用 anyTpe 定义服务时,客户端必须修改 XML 文档并将其封装在 WSDL 定义的父元素中。这会给要使用服务接口(使用 anyType 表示与服务交换的文档)的客户端带来一些负担。
public class PurchaseOrder
{
private String poId;
private Calendar createDate;
private Address shipTo;
private Address billTo;
private LineItem[] items;
public PurchaseOrder() {}
public PurchaseOrder(String poId, Calendar
createDate,
Address shipTo, Address billTo, LineItem[] items) {
this.poId = poId;
this.shipTo = shipTo;
this.createDate = createDate;
this.billTo = billTo;
this.items = items;
}
...
public SOAPElement toXMLSOAPElement(boolean
wrapper) {
SOAPElement soapElem = null;
try {
//construct the DOM tree
DocumentBuilderFactory docBuilderFactory =
DocumentBuilderFactory.newInstance();
docBuilderFactory.setNamespaceAware(true);
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element poElem = doc.createElement("PurchaseOrder");
if(wrapper){
Element docElem = doc.createElement("BusinessDocumentRequest");
doc.appendChild(docElem);
docElem.appendChild(poElem);
}
else{
doc.appendChild(poElem);
}
Element elem = doc.createElement("poId");
elem.appendChild(doc.createTextNode(poId));
poElem.appendChild(elem);
elem
= doc.createElement("createDate");
elem.appendChild(doc.createTextNode((new
SimpleDateFormat("MM-dd-yy")).format(createDate.getTime())));
poElem.appendChild(elem);
elem
= doc.createElement("shipTo");
poElem.appendChild(shipTo.toDOM(doc, elem));
elem
= doc.createElement("billTo");
poElem.appendChild(billTo.toDOM(doc, elem));
for(int i = 0; i < items.length; ++i){
poElem.appendChild(items[i].toDOM(doc));
}
//create a SOAPElement
SOAPElement parent = SOAPFactory.newInstance().createElement("dummy");
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.transform(new DOMSource(doc), new DOMResult(parent));
soapElem = (SOAPElement) parent.getChildElements().next();
} catch(TransformerException
te) {
te.printStackTrace(System.err);
throw new RuntimeException(te.getMessage(), te);
}
catch(ParserConfigurationException pce) {
pce.printStackTrace(System.err);
throw new RuntimeException(pce.getMessage(), pce);
} catch(SOAPException se) {
se.printStackTrace(System.err);
throw new RuntimeException(se.getMessage(), se);
}
return soapElem;
}
<enterprise-beans>
<session>
<ejb-name>AnyTypePurchaseOrderServiceBean</ejb-name>
<service-endpoint>com.sun.j2ee.blueprints.anytypeposervice.AnyTypePurchaseOrderServiceSEI</service-endpoint>
<ejb-class>com.sun.j2ee.blueprints.anytypeposervice.AnyTypePurchaseOrderServiceBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Container</transaction-type>
</session>
</enterprise-beans>
代码示例 7:ejb-jar.xml 部署描述符中的代码片段<service-endpoint>
。端点还需要 Web 服务部署描述符文件 webservices.xml,如下所示: <webservice-description>
<webservice-description-name>AnyTypePurchaseOrderService</webservice-description-name>
<wsdl-file>META-INF/wsdl/AnyTypePurchaseOrderService.wsdl</wsdl-file>
<jaxrpc-mapping-file>META-INF/anytypepurchaseorderservice-mapping.xml</jaxrpc-mapping-file>
<port-component>
<description>port component
description</description>
<port-component-name>AnyTypePurchaseOrderService</port-component-name>
<wsdl-port
xmlns:PurchaseOrderns="urn:AnyTypePurchaseOrderService">PurchaseOrderns:AnyTypePurchaseOrderServiceSEIPort</wsdl-port>
<service-endpoint-interface>
com.sun.j2ee.blueprints.anytypeposervice.AnyTypePurchaseOrderServiceSEI
</service-endpoint-interface>
<service-impl-bean>
<ejb-link>AnyTypePurchaseOrderServiceBean</ejb-link>
</service-impl-bean>
</port-component>
</webservice-description>
代码示例 8:webservice.xml 部署描述符中的代码片段