JAX-WS a SOAP Attachments

Pokud potřebujete poslat přes webovou službu trochu víc dat, než je pár detailů o klientovi, je dobré tyto data posílat jako SOAP attachment a ne přímo v nějakém tagu samotné zprávy. A přesně to, jsem se snažil řešit na projektu. Používáme JAX-WS a aplikace běží to na Weblogicu Server. Weblogic je znamý tím, že si „sem-tam“ některé knihovny upraví k obrazu svému a pak se výsledek může chovat trochu jinak, než by člověk mohl čekat. Nevím, zda se v mém případě jednalo o nějakou lahůdku Weblogicu, ale postup k cíli nebyl vůbec přímočarý.

Typická služba vypadá takto:

import ...

@WebService(targetNamespace = "http://schemas/wsdl")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT, use = SOAPBinding.Use.LITERAL)
public interface Documentation {

    @WebMethod
    @WebResult(name = "receiveDocument")
    @XmlMimeType("application/octet-stream")
    DataHandler getDocument(
            @WebParam(name = "documentId",
                    targetNamespace = "http://schemas/wsdl",
                    mode = WebParam.Mode.IN) Integer documentId);
}

a následná implementace:

import ...

@WebService(serviceName = "Documentation", endpointInterface = "Documentation")
@SchemaValidation
public class DocumentationImpl  implements Documentation {

    @Override
    public DataHandler getDocument(Integer documentId) {
        return getService().getDocument(documentId);
    }
}

Pokud chceme používat SOAP attachmentů, můžeme využít implementace od SUNu (vlastně teď Oraclu). Souhrnně se této technice říká Message Transmission Optimization Mechanism (zkráceně MTOM) a právě SUN nabízí pro tyto účely implementaci pro JAX-WS (upozorňuji, že třeba v AXISu to funguje úplně jinak).

Vše se tváří naprosto triviálně – stačí jako jeden výstupní parametr použít s typem javax.activation.DataHandler, nastavit u tohoto parametru pomocí javax.xml.bind.annotation.XmlMimeType správný content type a celou třídu oanotovat pomocí @MTOM. Vše by mělo zázračně začít fungovat. Jenže ono to nefunguje.

Ač o tom není v dokumentaci ani zmínka záleží na tom, kde se anotace umístí. Tato anotace se totiž neumisťuje do interface, kde bych to očekával, ale přímo do třídy, která implementuje naše rozhraní této webové služby. Abychom nám začali fungovat attachmenty, upravíme příklad, který jsem uvedl na začátku tohoto článku:

import ...

@MTOM
@StreamingAttachment(parseEagerly = true, memoryThreshold = 40000L)
@WebService(serviceName = "Documentation", endpointInterface = "Documentation")
@SchemaValidation
public class DocumentationImpl  implements Documentation {

    @Override
    public DataHandler getDocument(Integer documentId) {
        return getService().getDocument(documentId);
    }
}

Přidal jsem dvě anotace: @MTOM a @StreamingAttachment(...). Ta první aktivuje tuto funkčnost a od nyní se všechny atributy typu DataHandler budou přenášet jako SOAP attachment. Anotaci @StreamingAttachment(...) využijeme v případě, že budeme přenášet skutečně velké soubory a posílání souboru nám bere moc paměti. A ještě jedna chytrá věc-v anotaci @MTOM je parametr threshold, který říká, od jaké velikosti se daný element pošle jako SOAP attachment a kdy se pošle přímo v elementu samotné zprávy.

Na závěr ještě ukázku, jak pak vypadají data ze služby:

HTTP/1.1 200 OK
Date: Sat, 06 Feb 2010 07:46:28 GMT
Transfer-Encoding: chunked
Content-Type: multipart/related;start="";type="application/xop+xml";boundary="uuid:783e56c7-ff09-40d8-91cd-d0ec0ce9555e";start-info="text/xml"
X-Powered-By: Servlet/2.5 JSP/2.1

--uuid:783e56c7-ff09-40d8-91cd-d0ec0ce9555e
Content-Id: 
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
Content-Transfer-Encoding: binary



  
    
      
        
      
    
  

--uuid:783e56c7-ff09-40d8-91cd-d0ec0ce9555e
Content-Id: <383e4726-8e85-4a46-a917-23811ec4ef3e@example.jaxws.sun.com>
Content-Type: application/pdf
Content-Transfer-Encoding: binary

%PDF-1.4
.
.
.
%%EOF

--uuid:783e56c7-ff09-40d8-91cd-d0ec0ce9555e-

Napsat komentář