Question

I just want to know, is there any simple way for parsing MTOM/XOP SOAP response. The problem is that I use plain HTTP to send soap message and javax.xml for parsing response. But some services responds me with mulipart/related and it requires much more complex logic to parse it (performance matters). So I wonder may I somehow take advantage of apache cxf, apache axiom or any other library for parsing MTOM/XOP SOAP response?

Was it helpful?

Solution

These unit tests show you how to use CXF to extract attachments out of an MTOM message. I'll inline one of the tests in case this link doesn't exist in the future:

private MessageImpl msg;

@Before
public void setUp() throws Exception {
    msg = new MessageImpl();
    Exchange exchange = new ExchangeImpl();
    msg.setExchange(exchange);
}

@Test
public void testDeserializerMtom() throws Exception {
    InputStream is = getClass().getResourceAsStream("mimedata");
    String ct = "multipart/related; type=\"application/xop+xml\"; "
                + "start=\"<soap.xml@xfire.codehaus.org>\"; "
                + "start-info=\"text/xml; charset=utf-8\"; "
                + "boundary=\"----=_Part_4_701508.1145579811786\"";

    msg.put(Message.CONTENT_TYPE, ct);
    msg.setContent(InputStream.class, is);

    AttachmentDeserializer deserializer = new AttachmentDeserializer(msg);
    deserializer.initializeAttachments();

    InputStream attBody = msg.getContent(InputStream.class);
    assertTrue(attBody != is);
    assertTrue(attBody instanceof DelegatingInputStream);

    Collection<Attachment> atts = msg.getAttachments();
    assertNotNull(atts);

    Iterator<Attachment> itr = atts.iterator();
    assertTrue(itr.hasNext());

    Attachment a = itr.next();
    assertNotNull(a);

    InputStream attIs = a.getDataHandler().getInputStream();

    // check the cached output stream
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    IOUtils.copy(attBody, out);
    assertTrue(out.toString().startsWith("<env:Envelope"));

    // try streaming a character off the wire
    assertTrue(attIs.read() == '/');
    assertTrue(attIs.read() == '9');
}

In your case, the ct will come from the content type header of the response. The "mimedata" will be the content of the response.

OTHER TIPS

No need to use CXF, the standard javax.mail.internet.MimeMultipart class do the job and it's very easy to use (also to create MTOM request).

Here a very simple sample to decode parts of a MTOM response:

MimeMultipart mp = new MimeMultipart(new ByteArrayDataSource(data, contentType));
int count = mp.getCount();
for (int i = 0; i < count; i++) {
    BodyPart bp = mp.getBodyPart(i);
    bp.saveFile(filepath + "_" + i);
}

I had same issue and solved as @Nicolas Albert

public byte[] mimeParser(InputStream isMtm) {
    ByteArrayOutputStream baos = null;
    try {
        MimeMultipart mp = new MimeMultipart(new ByteArrayDataSource(isMtm,
                ct));
        int count = mp.getCount();
        baos = new ByteArrayOutputStream();
        for (int i = 0; i < count; i++) {
            BodyPart bodyPart = mp.getBodyPart(i);
            if (!Part.ATTACHMENT
                    .equalsIgnoreCase(bodyPart.getDisposition())
                    && !StringUtils.isNotBlank(bodyPart.getFileName())) {
                continue; // dealing with attachments only
            }
            bodyPart.writeTo(baos);
        }

        byte[] attachment = baos.toByteArray();
        FileUtils.writeByteArrayToFile(new File("E:/wss/attachment.zip"), attachment);
        return attachment;
    } catch (Exception ex) {
        ex.printStackTrace();
    } finally {
        if (baos != null) {
            try {
                baos.close();
            } catch (Exception ex) {

            }
        }
    }
    return null;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top