Envoyer des pieces jointes à un service web avec MTOM
Je vais essayer de décrire l'ajout d'une pièce jointe à un message SOAP via l'API JAX-WS.
SOAP 1.2 permet d'envoyer à l'instar des mails des documents en pièce jointe d'un flux SOAP.
Ils peuvent être binaires ou tout simplement texte (ex. flux XML). Les flux binaires sont par défaut mis dans le message SOAP et encodé en base64. Ce qui augmente la taille du message d'environ 30% par rapport au flux binaire original....
Exemple de flux binaire encodé en base64:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body> <ns2:sendPDFResponse xmlns:ns2="http://proto.touret.info/"> <return>JVBERi0xLjQNJeLjz9MNCjYgMCBvYmoNPDwgDS9MaW5lYXJpemVkIDEgDS9PIDkgDS9IIFsgMTQ2MSAyMjcgXSANL0wgMjk1ODMgDS9FIDI3NTU4IA0vTiAxIA0vVCAyOTM0NiANPj4gDWVuZG9iag0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4cmVmDTYgNDMgDTAwMDAwMDAwMTYgMDAwMDAgbg0KMDAwMDAwMTIyMCAwMDAwMCBuDQowMDAwMDAxMzA5IDAwMDAwIG4NCjAwMDAwMDE2ODggMDAwMDAgbg0KMDAwMDAwMTg5MyAwMDAwMCBuDQowMDAwMDAyMDg0IDAwMDAwIG4NCjAwMDAwMDI2MjcgMDAwMDAgbg0KMDAwMDAwMzM3OSAwMDAwMCBuDQowMDAwMDAzNzUzIDAwMDAwIG4NCjAwMDAwMDQwOTcgMDAwMDAgbg0KMDAwMDAwNDE2NSAwMDAwMCBuDQowMDAwMDA0MjA0IDAwMDAwIG4NCj</return> </ns2:sendPDFResponse> </S:Body>
</S:Envelope>
On peut donc ajouter une pièce jointe dans un flux grâce à la classe DataHandler. Celle-ci fournit les mécanismes de sérialisation et de gestion des types MIME.
L' API permet également d'utiliser d'autres classes plus spécifiques : (ex.: la classe Image pour pour les images png et jpg)
Exemple:
@WebService @Stateless @SOAPBinding(style=SOAPBinding.Style.DOCUMENT,use=SOAPBinding.Use.LITERAL,parameterStyle=SOAPBinding.ParameterStyle.WRAPPED) public class PDFDownloaderBean implements PDFDownloaderBeanLocal { private DataHandler dataHandler; @WebMethod public DataHandler sendPDF() { try { dataHandler = new DataHandler(dataSource); e.printStackTrace(); } return dataHandler; } }
Ici nous renvoyons dans un flux SOAP un fichier binaire.
Nous pouvons voir dans SOAPUI que les données binaires renvoyées sont encodées en base64 et mises directement dans le flux XML. Pour que ces dernières soient réellement en pièce jointe, on peut: gérer les pièces jointes manuellement en utilisant la classe SOAPMessageContext dans un handler
@Override public boolean handleMessage(SOAPMessageContext context) { if (isOutBound) { try { AttachmentPart attachmentPart = context.getMessage().createAttachmentPart(); attachmentPart.setDataHandler(new DataHandler(dataSource)); attachmentPart.setContentId("pdf"); context.getMessage().addAttachmentPart(attachmentPart); e.printStackTrace(); } } return true; }
ou tout simplement utiliser MTOM. Ce mécanisme permet d'envoyer le flux binaire dans sa forme originale et nous éviter l'encodage en base64....
Pour activer MTOM sur notre service il faut simplement ajouter l'annotation @MTOM
@MTOM @WebService @Stateless @SOAPBinding(style=SOAPBinding.Style.DOCUMENT,use=SOAPBinding.Use.LITERAL,parameterStyle=SOAPBinding.ParameterStyle.WRAPPED) public class PDFDownloaderBean implements PDFDownloaderBeanLocal
Et voila la requête générée :
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:prot="http://proto.touret.info/"> <soapenv:Header/> <soapenv:Body> <prot:sendPDF/> </soapenv:Body> </soapenv:Envelope>
et la réponse
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns2:sendPDFResponse xmlns:ns2="http://proto.touret.info/"> <return> <Include href="cid:f25753c5-c8eb-4ced-b6cd-7c89c687a7c0@example.jaxws.sun.com" xmlns="http://www.w3.org/2004/08/xop/include"/> </return> </ns2:sendPDFResponse> </S:Body> </S:Envelope>
On peut voir que le message SOAP n'indique qu'une référence à la pièce jointe ( un peu comme les images inclus dans un mail HTML) et non le flux en base 64.