使用字符串表示服务接口中的 XML 文档:设计详细信息

本文档以 java.netbpcatalog 项目下的面向文档的应用程序为例,说明了在设计以文档为中心的接口和端点时将字符串用作文档类型的策略。此应用程序具有一个服务端点,该服务端点旨在将字符串用作接口和端点实现中的文档类型。XML 文档以客户端发送的订单表示。

该应用程序由以下主要实体组成:

服务的 WSDL 文件

WSDL 文件对 Web 服务进行了描述。请注意在 WSDL 中声明的应用程序定义的服务异常。此服务的 WSDL 中的一个代码片段如下:

<>  <types>
    <schema targetNamespace="urn:StringPurchaseOrderService" xmlns:tns="urn:StringPurchaseOrderService" 
    xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema">
      <complexType name="submitPO">
        <sequence>
          <element name="String_1" type="string" 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="StringPurchaseOrderServiceSEI_submitPO">
    <part name="parameters" element="tns:submitPO"/>
  </message>
  <message name="StringPurchaseOrderServiceSEI_submitPOResponse">
    <part name="result" element="tns:submitPOResponse"/>
  </message>
  <message name="InvalidPOException">
    <part name="InvalidPOException" element="tns:InvalidPOException"/>
  </message>
  <portType name="StringPurchaseOrderServiceSEI">
    <operation name="submitPO">
      <input message="tns:StringPurchaseOrderServiceSEI_submitPO"/>
      <output message="tns:StringPurchaseOrderServiceSEI_submitPOResponse"/>
      <fault name="InvalidPOException" message="tns:InvalidPOException"/>
    </operation>
  </portType>

代码示例 1:服务的 WSDL 中的代码片段

服务端点接口

端点接口具有一个 submitPO() 方法,该方法将 XML 文档作为字符串。下面是服务端点接口:

public interface StringPurchaseOrderServiceSEI extends Remote {  
    public String submitPO(String xmlPO)
                                throws InvalidPOException, RemoteException;
}
代码示例 2:服务端点接口

Java[TM] 端点实现

对于此应用程序,我们选择使用 Enterprise JavaBeans[TM] (EJB[TM]) 组件来实现服务接口。还可以使用 Web 组件来实现端点。两种选择均可。请注意,getID() 方法仅将订单 ID 返回至客户端。在实际情况下,将结果返回至客户端之前还需要执行一些操作,但我们不把重点放在业务逻辑上。此外,请注意端点首先根据其结构验证文档。值得注意的一点是订单 XML 被作为字符串进行处理。端点实现类显示如下:

public class StringPurchaseOrderServiceBean implements SessionBean {
   
    private SessionContext sc;
    private DocumentBuilderFactory docBuilderFactory;
   
    public StringPurchaseOrderServiceBean(){}
   
    public String submitPO(String xmlPO) throws InvalidPOException, RemoteException {
        String id =null;
        if (!(validate(xmlPO))) {
            throw new InvalidPOException("Error parsing the purchase order XML document!!!");
        }
        try {
            //extract the PO ID from the document and return to the client
            id = getID(xmlPO);
        } catch (Exception e) {
            throw new EJBException("StringPurchaseOrderService implementation had trouble parsing PO.xml, some system or
            configuration problem " + e.getMessage(), e);
        }
        //this is done just to illustrate throwing an application specific exception
        if(id.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 id;
    }
   
    private String getID(String xmlDoc) throws org.xml.sax.SAXException, javax.xml.parsers.ParserConfigurationException, 
        java.io.IOException {
        String ret = "";
        DocumentBuilder db = null;
        if (docBuilderFactory != null)
            db = docBuilderFactory.newDocumentBuilder();
        InputSource is =  new InputSource(new StringReader(xmlDoc));
        Document doc = db.parse(is);
        Element root = doc.getDocumentElement();
        NodeList list = root.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) return child.getNodeValue();
            }
        }
        return ret;
    }
  private boolean validate(String xmlDoc) {
        Document doc = null;
        try {
            DocumentBuilderFactory dbf = null;
            DocumentBuilder db = null;
            try {
                dbf = DocumentBuilderFactory.newInstance();
                dbf.setValidating(true);
                dbf.setNamespaceAware(true);
                dbf.setAttribute("http://java.sun.com/xml/jaxp/properties/schemaLanguage",
                        "http://www.w3.org/2001/XMLSchema");
                if (dbf != null){
                    db = dbf.newDocumentBuilder();
                }
                db.setEntityResolver(new POEntityResolver());
                db.setErrorHandler(new POXMLErrorHandler());
            } catch ( javax.xml.parsers.ParserConfigurationException pce) {
                System.err.println(pce);
            }
            InputSource is =  new InputSource(new StringReader(xmlDoc));
            doc = db.parse(is);
            return true;
        } catch (Exception e) {
            System.err.println("XML Validation Error " + e);
        }
        return false;
    }
   
    //life cycle methods
    ...
}
代码示例 3:端点实现

部署描述符

将 J2EE[TM] 中的 Web 服务打包为 war 或 ear 文件之类的部署模块。在此应用程序中,我们将其打包为一个 ear 文件。Web 服务端点的可移植打包需要多个部署描述符以及 Java 类。下面是端点部署描述符中的一些代码片段:

<enterprise-beans>
  <session>     
    <ejb-name>StringPurchaseOrderServiceBean</ejb-name>
    <service-endpoint>
      com.sun.j2ee.blueprints.stringposervice.StringPurchaseOrderServiceSEI
    </service-endpoint>    
    <ejb-class>
      com.sun.j2ee.blueprints.stringposervice.StringPurchaseOrderServiceBean
    </ejb-class>    
    <session-type>Stateless</session-type>   
    <transaction-type>Container</transaction-type>
  </session>  
</enterprise-beans>
代码示例 4:ejb-jar.xml 部署描述符中的代码片段

请注意,服务端点接口在 ejb-jar.xml 中定义为 <service-endpoint>。端点也需要一个显示为如下内容的 Web 服务部署描述符文件 webservices.xml:

<webservice-description>
  <webservice-description-name>StringPurchaseOrderService</webservice-description-name>
  <wsdl-file>META-INF/wsdl/StringPurchaseOrderService.wsdl</wsdl-file>
  <jaxrpc-mapping-file>META-INF/stringpurchaseorderservice-mapping.xml</jaxrpc-mapping-file>
  <port-component>
    <description>port component description</description>
    <port-component-name>StringPurchaseOrderService</port-component-name>
    <wsdl-port xmlns:PurchaseOrderns="urn:StringPurchaseOrderService">PurchaseOrderns:StringPurchaseOrderServiceSEIPort</wsdl-port>
    <service-endpoint-interface>
      com.sun.j2ee.blueprints.stringposervice.StringPurchaseOrderServiceSEI
    </service-endpoint-interface>
    <service-impl-bean>
      <ejb-link>StringPurchaseOrderServiceBean</ejb-link>
    </service-impl-bean>
 </port-component>
</webservice-description>
代码示例 5:webservice.xml 部署描述符中的代码片段

Web 服务部署描述符文件包含有关服务的信息,例如 WSDL 文件和 JAX-RPC 映射文件的名称以及服务端点接口和服务实现类的名称。


© Sun Microsystems 2005。Java BluePrints Solutions Catalog 中的所有内容受版权保护,未经 Sun Microsystems 的明确书面许可,不得在其他产品中发布。