JAX-WS Provider和Dispatch

在以前的文章中,涉及到了WebService的搭建。全部的EndPoint均是高度面向對象,面向邏輯了。Server與Client之間交互的消息,均由JAXB轉爲JAVA類型。若是想對消息的原始數據進行修改,可使用Handler Chain。java

然而,JAXWS也提供了另外一種編程方式,Provider和Dispatch,讓咱們拋開高度抽象的EndPoint和JAXB,拋開了工具wsgen,wsimport,直接面向消息編程。node

Provider

介紹

Provider是server端直接面向消息編程的接口。咱們先看下Provider接口中的方法:
web

package javax.xml.ws.Provider
public interface Provider<T> {
  public T invoke(T request);
}

服務端EndPoint必須實現此接口。Provider就像是HttpServlet,invoke()就像是service()。invoke方法參數是接收的原始消息,返回值是返回的消息。編程

T是對消息封裝的一種泛型。結合Provider的Annotation @ServiceMode,它能夠爲三種封裝類型:tomcat

  1. javax.xml.transform.Source 將消息中的Payload封裝爲XML類型Source。適用於@ServiceMode(value=Service.Mode.PAYLOAD)。服務器

  2. javax.xml.soap.SOAPMessage 將消息總體封裝爲SOAPMessage。適用於@ServiceMode(value=Service.Mode.MESSAGE)。dom

  3. javax.activation.DataSource異步

Provider沒法使用wsgen命令生成WSDL文件,因此,只能先用WebService Interface生成WSDL,而後再編寫Provider。
ide

下面的例子是基於以前的圖書館系統而修改的,因此複用以前圖書館系統的WSDL文件。工具

建立Java Web Project

建立一個java web project,取名叫LibraryProvider。而後將以前圖書館系統的WSDL文件複製到新項目的WEB-INF目錄下面。

建立Provider

建立java類,LibraryProvider:

@ServiceMode(value=Service.Mode.PAYLOAD)
@WebServiceProvider()
public class LibraryProvider implements Provider<Source> {
    private static int currentId = 0;
    private static Map<Integer, Book> books= new HashMap<Integer, Book>();
    private static class Book {
        public int getId() {
            return id;
        }
        public void setId(int id) {
            this.id = id;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getAuthor() {
            return author;
        }
        public void setAuthor(String author) {
            this.author = author;
        }
        private int id;
        private String name;
        private String author;
    }

    @Override
    public Source invoke(Source request) {
        try {
            DOMResult dom = new DOMResult();
            Transformer trans = TransformerFactory.newInstance().newTransformer();
            trans.transform(request, dom);
            Node node = dom.getNode();
            Node root = node.getFirstChild();
            String operation = root.getLocalName();
            if ("addRawBook".equals(operation)) {
                return addRawBook(root);
            }
            
            if ("getRawBook".equals(operation)) {
                return getRawBook(root);
            }

            if ("deleteBook".equals(operation)) {
                return deleteBook(root);
            }
            
            return request;
        } catch(Exception e) {
            e.printStackTrace();
            throw new RuntimeException("Error in provider endpoint", e);
        }
    }

    private Source addRawBook(Node root) {
        String name = root.getChildNodes().item(0).getChildNodes().item(0).getNodeValue();
        String author = root.getChildNodes().item(1).getChildNodes().item(0).getNodeValue();
        Book b = new Book();
        b.setName(name);
        b.setAuthor(author);
        b.setId(++currentId);
        books.put(b.getId(), b);
        String body =
                "<ns2:addRawBookResponse xmlns:ns2=\"http://library.mycompany.com\"><id>"
                +currentId
                +"</id></ns2:addRawBookResponse>";
        Source source = new StreamSource(new ByteArrayInputStream(body.getBytes()));
        return source;
    }
    
    private Source getRawBook(Node root) {
        String idString = root.getChildNodes().item(0).getChildNodes().item(0).getNodeValue();
        Book b = books.get(Integer.parseInt(idString));
        String body =
                "<ns2:getRawBookResponse xmlns:ns2=\"http://library.mycompany.com\"><rawBook>"
                +b.toString()
                +"</rawBook></ns2:getRawBookResponse>";
        Source source = new StreamSource(new ByteArrayInputStream(body.getBytes()));
        return source;
    }
    
    private Source deleteBook(Node root) {
        // 略
    }
}

sun-jaxws.xml

在WEB-INF下建立sun-jaxws.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<endpoints
    xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime"
    version="2.0">

    <endpoint
        name="provider"
        implementation="com.mycompany.library.LibraryProvider"
        wsdl="WEB-INF/wsdl/LibraryService.wsdl"
        service="{http://library.mycompany.com}LibraryService"
        port="{http://library.mycompany.com}LibraryPort"
        url-pattern="/service" />

</endpoints>

打包部署運行

將project導出爲war包library.war,部署到tomcat下。訪問http://127.0.0.1:8080/library/service?wsdl 

而後使用wsimport,產生client端的代碼。對client端進行調用,查看結果。

異步

關於提供服務端異步執行功能的AsyncProvider,我會另寫一篇文章介紹。

Dispatch

介紹

接口Dispatch和Provider相對,用於client端。其功能與Provider同樣,提供了面向消息的編程方法。先看下Dispatch提供了哪些方法:

package javax.xml.ws;

import java.util.concurrent.Future;
public interface Dispatch<T> extends BindingProvider {

    public T invoke(T msg);
    public Response<T> invokeAsync(T msg);
    public Future<?> invokeAsync(T msg, AsyncHandler<T> handler);
    public void invokeOneWay(T msg);
}

T泛型與Provider中的T同樣。而方法invoke與Provider中的invoke也相同。Dispatch還提供了另外3個方法:

  1. Response<T> invokeAsync(T msg); 爲異步poll的方式, Response是一個Future。

  2. Future<?> invokeAsync(T msg, AsyncHandler<T> handler); 爲異步callback方式。Handler會在另外一個線程中處理返回的值。

  3. void invokeOneWay(T msg); 處理單向消息。

異步

關於異步,會在另外一篇文章中贊成描述。

建立client

因爲Dispatch擺脫了JAXB,因此不須要調用wsimport命令。只須要一個簡單的client程序,就能夠調用服務器端的service。咱們以圖書館webservice爲例。

public class Client {
    public static void main(String[] a) throws Exception {
        URL url = new URL("http://127.0.0.1:8080/library/service?wsdl");
        final QName serviceQName = new QName("http://library.mycompany.com", "LibraryService");
        Service service = Service.create(url, serviceQName);
        
        // 建立一個新的port,也可使用WSDL中已有的port。若是WSDL中已經有此port,則不須要再進行binding。
        QName portName = new QName("http://library.mycompany.com", "RandomPort");
        service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING,"http://127.0.0.1:8080/library/service");
        // 爲port建立一個dispatch。全部流向port的消息都將由dispatch處理。
        Dispatch<Source> sourceDispatch = service.createDispatch(portName, Source.class, Service.Mode.PAYLOAD);
    
        // add book
        String body = "<ns2:addRawBook xmlns:ns2=\"http://library.mycompany.com\"><name>java</name><author>xpbug</author></ns2:addRawBook>";
        Source result = sourceDispatch.invoke(new StreamSource(new StringReader(body)));
        System.out.println(sourceToXMLString(result));
    
    }
    
    private static String sourceToXMLString(Source result) {

        String xmlResult = null;
        try {
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer();
            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
            OutputStream out = new ByteArrayOutputStream();
            StreamResult streamResult = new StreamResult();
            streamResult.setOutputStream(out);
            transformer.transform(result, streamResult);
            xmlResult = streamResult.getOutputStream().toString();
        } catch (TransformerException e) {
            e.printStackTrace();
        }
        return xmlResult;
    }
}

不須要任何額外的命令,依賴,以及部署,即可直接運行上面的程序。

相關文章
相關標籤/搜索