/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.cxf.attachment;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Properties;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Session;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.util.ByteArrayDataSource;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.message.Attachment;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageImpl;
import org.junit.Assert;
import org.junit.Test;
public class AttachmentSerializerTest extends Assert {
@Test
public void testMessageWriteXopOn1() throws Exception {
doTestMessageWrite(true, "text/xml");
}
@Test
public void testMessageWriteXopOn2() throws Exception {
doTestMessageWrite(true, "application/soap+xml; action=\"urn:foo\"");
}
@Test
public void testMessageWriteXopOff1() throws Exception {
doTestMessageWrite(false, "text/xml");
}
@Test
public void testMessageWriteXopOff2() throws Exception {
doTestMessageWrite(false, "application/soap+xml; action=\"urn:foo\"");
}
private void doTestMessageWrite(boolean xop, String soapContentType) throws Exception {
MessageImpl msg = new MessageImpl();
Collection<Attachment> atts = new ArrayList<>();
AttachmentImpl a = new AttachmentImpl("test.xml");
InputStream is = getClass().getResourceAsStream("my.wav");
ByteArrayDataSource ds = new ByteArrayDataSource(is, "application/octet-stream");
a.setDataHandler(new DataHandler(ds));
atts.add(a);
msg.setAttachments(atts);
// Set the SOAP content type
msg.put(Message.CONTENT_TYPE, soapContentType);
String soapCtType = null;
String soapCtParams = null;
String soapCtParamsEscaped = null;
int p = soapContentType.indexOf(';');
if (p != -1) {
soapCtParams = soapContentType.substring(p);
soapCtParamsEscaped = escapeQuotes(soapCtParams);
soapCtType = soapContentType.substring(0, p);
} else {
soapCtParams = "";
soapCtParamsEscaped = "";
soapCtType = soapContentType;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
msg.setContent(OutputStream.class, out);
AttachmentSerializer serializer = new AttachmentSerializer(msg);
if (!xop) {
// default is "on"
serializer.setXop(xop);
}
serializer.writeProlog();
// we expect the following rules at the package header level
// - the package header must have media type multipart/related.
// - the start-info property must be present for mtom but otherwise optional. its
// value must contain the content type associated with the root content's xml serialization,
// including its parameters as appropriate.
// - the action property should not appear directly in the package header level
// - the type property must contain the media type type/subtype of the root content part.
// namely application/xop+xml for mtom but otherwise text/xml or application/soap+xml
// depending on the soap version 1.1 or 1.2, respectively.
String ct = (String) msg.get(Message.CONTENT_TYPE);
assertTrue(ct.indexOf("multipart/related;") == 0);
assertTrue(ct.indexOf("start=\"<root.message@cxf.apache.org>\"") > -1);
assertTrue(ct.indexOf("start-info=\"" + soapCtType + soapCtParamsEscaped + "\"") > -1);
assertTrue(ct.indexOf("action=\"") == -1);
if (xop) {
assertTrue(ct.indexOf("type=\"application/xop+xml\"") > -1);
} else {
assertTrue(ct.indexOf("type=\"" + soapCtType + "\"") > -1);
}
out.write("<soap:Body/>".getBytes());
serializer.writeAttachments();
out.flush();
DataSource source = new ByteArrayDataSource(new ByteArrayInputStream(out.toByteArray()), ct);
MimeMultipart mpart = new MimeMultipart(source);
Session session = Session.getDefaultInstance(new Properties());
MimeMessage inMsg = new MimeMessage(session);
inMsg.setContent(mpart);
inMsg.addHeaderLine("Content-Type: " + ct);
MimeMultipart multipart = (MimeMultipart) inMsg.getContent();
MimeBodyPart part = (MimeBodyPart) multipart.getBodyPart(0);
// we expect the following rules at the root content level
// - the envelope header must have type application/xop+xml for mtom but otherwise the content's
// serialization type.
// - the type property must be present for mtom and it must contain the content's serialization type
// including its parameters if appropriate.
// - the action must appear if it was present in the original message (i.e., for soap 1.2)
if (xop) {
assertEquals("application/xop+xml; charset=UTF-8; type=\"" + soapCtType + soapCtParamsEscaped + "\"",
part.getHeader("Content-Type")[0]);
} else {
assertEquals(soapCtType + "; charset=UTF-8" + soapCtParams,
part.getHeader("Content-Type")[0]);
}
assertEquals("binary", part.getHeader("Content-Transfer-Encoding")[0]);
assertEquals("<root.message@cxf.apache.org>", part.getHeader("Content-ID")[0]);
InputStream in = part.getDataHandler().getInputStream();
ByteArrayOutputStream bodyOut = new ByteArrayOutputStream();
IOUtils.copy(in, bodyOut);
out.close();
in.close();
assertEquals("<soap:Body/>", bodyOut.toString());
MimeBodyPart part2 = (MimeBodyPart) multipart.getBodyPart(1);
assertEquals("application/octet-stream", part2.getHeader("Content-Type")[0]);
assertEquals("binary", part2.getHeader("Content-Transfer-Encoding")[0]);
assertEquals("<test.xml>", part2.getHeader("Content-ID")[0]);
}
@Test
public void testMessageMTOM() throws Exception {
MessageImpl msg = new MessageImpl();
Collection<Attachment> atts = new ArrayList<>();
AttachmentImpl a = new AttachmentImpl("test.xml");
InputStream is = getClass().getResourceAsStream("my.wav");
ByteArrayDataSource ds = new ByteArrayDataSource(is, "application/octet-stream");
a.setDataHandler(new DataHandler(ds));
atts.add(a);
msg.setAttachments(atts);
// Set the SOAP content type
msg.put(Message.CONTENT_TYPE, "application/soap+xml");
ByteArrayOutputStream out = new ByteArrayOutputStream();
msg.setContent(OutputStream.class, out);
AttachmentSerializer serializer = new AttachmentSerializer(msg);
serializer.writeProlog();
String ct = (String) msg.get(Message.CONTENT_TYPE);
assertTrue(ct.indexOf("multipart/related;") == 0);
assertTrue(ct.indexOf("start=\"<root.message@cxf.apache.org>\"") > -1);
assertTrue(ct.indexOf("start-info=\"application/soap+xml\"") > -1);
out.write("<soap:Body/>".getBytes());
serializer.writeAttachments();
out.flush();
DataSource source = new ByteArrayDataSource(new ByteArrayInputStream(out.toByteArray()), ct);
MimeMultipart mpart = new MimeMultipart(source);
Session session = Session.getDefaultInstance(new Properties());
MimeMessage inMsg = new MimeMessage(session);
inMsg.setContent(mpart);
inMsg.addHeaderLine("Content-Type: " + ct);
MimeMultipart multipart = (MimeMultipart) inMsg.getContent();
MimeBodyPart part = (MimeBodyPart) multipart.getBodyPart(0);
assertEquals("application/xop+xml; charset=UTF-8; type=\"application/soap+xml\"",
part.getHeader("Content-Type")[0]);
assertEquals("binary", part.getHeader("Content-Transfer-Encoding")[0]);
assertEquals("<root.message@cxf.apache.org>", part.getHeader("Content-ID")[0]);
InputStream in = part.getDataHandler().getInputStream();
ByteArrayOutputStream bodyOut = new ByteArrayOutputStream();
IOUtils.copy(in, bodyOut);
out.close();
in.close();
assertEquals("<soap:Body/>", bodyOut.toString());
MimeBodyPart part2 = (MimeBodyPart) multipart.getBodyPart(1);
assertEquals("application/octet-stream", part2.getHeader("Content-Type")[0]);
assertEquals("binary", part2.getHeader("Content-Transfer-Encoding")[0]);
assertEquals("<test.xml>", part2.getHeader("Content-ID")[0]);
}
private static String escapeQuotes(String s) {
return s.indexOf('"') != 0 ? s.replace("\"", "\\\"") : s;
}
}