From 0a07669a1576a282777b8fd7484f8f7aab1ef517 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Sun, 13 May 2007 00:37:24 +0000 Subject: [PATCH] Fixed SWS-107: Support JAXB's MTOM/XOP/MIME support --- .../AbstractMarshallingPayloadEndpoint.java | 98 ++++-- .../oxm/jaxb/Jaxb2Marshaller.java | 288 +++++++++++++----- .../oxm/jaxb/BinaryObject.java | 57 ++++ .../oxm/jaxb/Jaxb2MarshallerTest.java | 58 +++- .../oxm/jaxb/Jaxb2UnmarshallerTest.java | 59 +++- .../springframework/oxm/jaxb/spring-ws.png | Bin 0 -> 24355 bytes .../oxm/mime/MimeContainer.java | 53 ++++ .../oxm/mime/MimeMarshaller.java | 49 +++ .../oxm/mime/MimeUnmarshaller.java | 47 +++ .../org/springframework/oxm/mime/package.html | 5 + 10 files changed, 593 insertions(+), 121 deletions(-) create mode 100644 oxm-tiger/src/test/java/org/springframework/oxm/jaxb/BinaryObject.java create mode 100644 oxm-tiger/src/test/resources/org/springframework/oxm/jaxb/spring-ws.png create mode 100644 oxm/src/main/java/org/springframework/oxm/mime/MimeContainer.java create mode 100644 oxm/src/main/java/org/springframework/oxm/mime/MimeMarshaller.java create mode 100644 oxm/src/main/java/org/springframework/oxm/mime/MimeUnmarshaller.java create mode 100644 oxm/src/main/java/org/springframework/oxm/mime/package.html diff --git a/core/src/main/java/org/springframework/ws/server/endpoint/AbstractMarshallingPayloadEndpoint.java b/core/src/main/java/org/springframework/ws/server/endpoint/AbstractMarshallingPayloadEndpoint.java index e178b667..8340a4e2 100644 --- a/core/src/main/java/org/springframework/ws/server/endpoint/AbstractMarshallingPayloadEndpoint.java +++ b/core/src/main/java/org/springframework/ws/server/endpoint/AbstractMarshallingPayloadEndpoint.java @@ -16,14 +16,22 @@ package org.springframework.ws.server.endpoint; +import java.io.IOException; +import javax.activation.DataHandler; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.oxm.Marshaller; import org.springframework.oxm.Unmarshaller; +import org.springframework.oxm.mime.MimeContainer; +import org.springframework.oxm.mime.MimeMarshaller; +import org.springframework.oxm.mime.MimeUnmarshaller; import org.springframework.util.Assert; import org.springframework.ws.WebServiceMessage; import org.springframework.ws.context.MessageContext; +import org.springframework.ws.mime.Attachment; +import org.springframework.ws.mime.MimeMessage; /** * Endpoint that unmarshals the request payload, and marshals the response object. This endpoint needs a @@ -39,39 +47,29 @@ import org.springframework.ws.context.MessageContext; */ public abstract class AbstractMarshallingPayloadEndpoint implements MessageEndpoint, InitializingBean { - /** - * Logger available to subclasses. - */ + /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); private Marshaller marshaller; private Unmarshaller unmarshaller; - /** - * Returns the marshaller used for transforming objects into XML. - */ + /** Returns the marshaller used for transforming objects into XML. */ public final Marshaller getMarshaller() { return marshaller; } - /** - * Sets the marshaller used for transforming objects into XML. - */ + /** Sets the marshaller used for transforming objects into XML. */ public final void setMarshaller(Marshaller marshaller) { this.marshaller = marshaller; } - /** - * Returns the unmarshaller used for transforming XML into objects. - */ + /** Returns the unmarshaller used for transforming XML into objects. */ public final Unmarshaller getUnmarshaller() { return unmarshaller; } - /** - * Sets the unmarshaller used for transforming XML into objects. - */ + /** Sets the unmarshaller used for transforming XML into objects. */ public final void setUnmarshaller(Unmarshaller unmarshaller) { this.unmarshaller = unmarshaller; } @@ -84,36 +82,82 @@ public abstract class AbstractMarshallingPayloadEndpoint implements MessageEndpo public final void invoke(MessageContext messageContext) throws Exception { WebServiceMessage request = messageContext.getRequest(); - Object requestObject = unmarshaller.unmarshal(request.getPayloadSource()); + Object requestObject = unmarshalRequest(request); + Object responseObject = invokeInternal(requestObject); + if (responseObject != null) { + WebServiceMessage response = messageContext.getResponse(); + marshalResponse(responseObject, response); + } + } + + private Object unmarshalRequest(WebServiceMessage request) throws IOException { + Object requestObject; + if (unmarshaller instanceof MimeUnmarshaller && request instanceof MimeMessage) { + MimeUnmarshaller mimeUnmarshaller = (MimeUnmarshaller) unmarshaller; + MimeMessageContainer container = new MimeMessageContainer((MimeMessage) request); + requestObject = mimeUnmarshaller.unmarshal(request.getPayloadSource(), container); + } + else { + requestObject = unmarshaller.unmarshal(request.getPayloadSource()); + } if (logger.isDebugEnabled()) { logger.debug("Unmarshalled payload request to [" + requestObject + "]"); } - Object responseObject = invokeInternal(requestObject); - if (responseObject != null) { - if (logger.isDebugEnabled()) { - logger.debug("Marshalling [" + responseObject + "] to response payload"); - } - WebServiceMessage response = messageContext.getResponse(); + return requestObject; + } + + private void marshalResponse(Object responseObject, WebServiceMessage response) throws IOException { + if (logger.isDebugEnabled()) { + logger.debug("Marshalling [" + responseObject + "] to response payload"); + } + if (marshaller instanceof MimeMarshaller && response instanceof MimeMessage) { + MimeMarshaller mimeMarshaller = (MimeMarshaller) marshaller; + MimeMessageContainer container = new MimeMessageContainer((MimeMessage) response); + mimeMarshaller.marshal(responseObject, response.getPayloadResult(), container); + } + else { marshaller.marshal(responseObject, response.getPayloadResult()); } } /** * Template method that gets called after the marshaller and unmarshaller have been set. - * - *

The default implementation does nothing. + *

+ * The default implementation does nothing. */ public void afterMarshallerSet() throws Exception { } /** * Template method that subclasses must implement to process a request. - * - *

The unmarshaled request object is passed as a parameter, and an the returned object is marshalled to a - * response. If no response is required, return null. + *

+ * The unmarshaled request object is passed as a parameter, and an the returned object is marshalled to a response. + * If no response is required, return null. * * @param requestObject the unnmarshalled message payload as object * @return the object to be marshalled as response, or null if a response is not required */ protected abstract Object invokeInternal(Object requestObject) throws Exception; + + private static class MimeMessageContainer implements MimeContainer { + + private final MimeMessage mimeMessage; + + public MimeMessageContainer(MimeMessage mimeMessage) { + this.mimeMessage = mimeMessage; + } + + public boolean isXopPackage() { + return mimeMessage.isXopPackage(); + } + + public void addAttachment(String contentId, DataHandler dataHandler) { + mimeMessage.addAttachment(contentId, dataHandler); + } + + public DataHandler getAttachment(String contentId) { + Attachment attachment = mimeMessage.getAttachment(contentId); + return attachment.getDataHandler(); + } + } } diff --git a/oxm-tiger/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java b/oxm-tiger/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java index ea2798aa..6220b975 100644 --- a/oxm-tiger/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java +++ b/oxm-tiger/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java @@ -16,8 +16,14 @@ package org.springframework.oxm.jaxb; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.util.Map; +import java.util.UUID; +import javax.activation.DataHandler; +import javax.activation.DataSource; import javax.xml.XMLConstants; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; @@ -26,18 +32,24 @@ import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.adapters.XmlAdapter; +import javax.xml.bind.attachment.AttachmentMarshaller; +import javax.xml.bind.attachment.AttachmentUnmarshaller; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.validation.Schema; import org.springframework.core.io.Resource; +import org.springframework.oxm.XmlMappingException; +import org.springframework.oxm.mime.MimeContainer; +import org.springframework.oxm.mime.MimeMarshaller; +import org.springframework.oxm.mime.MimeUnmarshaller; import org.springframework.util.ClassUtils; +import org.springframework.util.FileCopyUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.xml.transform.StaxResult; import org.springframework.xml.transform.StaxSource; import org.springframework.xml.validation.SchemaLoaderUtils; -import org.xml.sax.SAXException; /** * Implementation of the Marshaller interface for JAXB 2.0. @@ -58,7 +70,7 @@ import org.xml.sax.SAXException; * @see #setUnmarshallerListener(javax.xml.bind.Unmarshaller.Listener) * @see #setAdapters(javax.xml.bind.annotation.adapters.XmlAdapter[]) */ -public class Jaxb2Marshaller extends AbstractJaxbMarshaller { +public class Jaxb2Marshaller extends AbstractJaxbMarshaller implements MimeMarshaller, MimeUnmarshaller { private Resource[] schemaResources; @@ -136,61 +148,9 @@ public class Jaxb2Marshaller extends AbstractJaxbMarshaller { return clazz.getAnnotation(XmlRootElement.class) != null || JAXBElement.class.isAssignableFrom(clazz); } - public void marshal(Object graph, Result result) { - try { - if (result instanceof StaxResult) { - marshalStaxResult(graph, (StaxResult) result); - } - else { - createMarshaller().marshal(graph, result); - } - } - catch (JAXBException ex) { - throw convertJaxbException(ex); - } - } - - public Object unmarshal(Source source) { - try { - if (source instanceof StaxSource) { - return unmarshalStaxSource((StaxSource) source); - } - else { - return createUnmarshaller().unmarshal(source); - } - } - catch (JAXBException ex) { - throw convertJaxbException(ex); - } - } - - protected void initJaxbMarshaller(Marshaller marshaller) throws JAXBException { - if (schema != null) { - marshaller.setSchema(schema); - } - if (marshallerListener != null) { - marshaller.setListener(marshallerListener); - } - if (adapters != null) { - for (int i = 0; i < adapters.length; i++) { - marshaller.setAdapter(adapters[i]); - } - } - } - - protected void initJaxbUnmarshaller(Unmarshaller unmarshaller) throws JAXBException { - if (schema != null) { - unmarshaller.setSchema(schema); - } - if (unmarshallerListener != null) { - unmarshaller.setListener(unmarshallerListener); - } - if (adapters != null) { - for (int i = 0; i < adapters.length; i++) { - unmarshaller.setAdapter(adapters[i]); - } - } - } + /* + * JAXBContext + */ protected JAXBContext createJaxbContext() throws Exception { if (JaxbUtils.getJaxbVersion() < JaxbUtils.JAXB_2) { @@ -200,7 +160,13 @@ public class Jaxb2Marshaller extends AbstractJaxbMarshaller { if (StringUtils.hasLength(getContextPath()) && !ObjectUtils.isEmpty(classesToBeBound)) { throw new IllegalArgumentException("specify either contextPath or classesToBeBound property; not both"); } - loadSchema(); + if (!ObjectUtils.isEmpty(schemaResources)) { + if (logger.isDebugEnabled()) { + logger.debug( + "Setting validation schema to " + StringUtils.arrayToCommaDelimitedString(schemaResources)); + } + schema = SchemaLoaderUtils.loadSchema(schemaResources, schemaLanguage); + } if (StringUtils.hasLength(getContextPath())) { return createJaxbContextFromContextPath(); } @@ -238,37 +204,219 @@ public class Jaxb2Marshaller extends AbstractJaxbMarshaller { } } - private void loadSchema() throws IOException, SAXException { - if (!ObjectUtils.isEmpty(schemaResources)) { - if (logger.isDebugEnabled()) { - logger.debug( - "Setting validation schema to " + StringUtils.arrayToCommaDelimitedString(schemaResources)); + /* + * Marshaller/Unmarshaller + */ + + protected void initJaxbMarshaller(Marshaller marshaller) throws JAXBException { + if (schema != null) { + marshaller.setSchema(schema); + } + if (marshallerListener != null) { + marshaller.setListener(marshallerListener); + } + if (adapters != null) { + for (int i = 0; i < adapters.length; i++) { + marshaller.setAdapter(adapters[i]); } - schema = SchemaLoaderUtils.loadSchema(schemaResources, schemaLanguage); } } - private void marshalStaxResult(Object graph, StaxResult staxResult) throws JAXBException { + protected void initJaxbUnmarshaller(Unmarshaller unmarshaller) throws JAXBException { + if (schema != null) { + unmarshaller.setSchema(schema); + } + if (unmarshallerListener != null) { + unmarshaller.setListener(unmarshallerListener); + } + if (adapters != null) { + for (int i = 0; i < adapters.length; i++) { + unmarshaller.setAdapter(adapters[i]); + } + } + } + + /* + * Marshalling + */ + + public void marshal(Object graph, Result result) throws XmlMappingException { + marshal(graph, result, null); + } + + public void marshal(Object graph, Result result, MimeContainer mimeContainer) throws XmlMappingException { + try { + Marshaller marshaller = createMarshaller(); + if (mimeContainer != null) { + marshaller.setAttachmentMarshaller(new Jaxb2AttachmentMarshaller(mimeContainer)); + } + if (result instanceof StaxResult) { + marshalStaxResult(marshaller, graph, (StaxResult) result); + } + else { + marshaller.marshal(graph, result); + } + } + catch (JAXBException ex) { + throw convertJaxbException(ex); + } + } + + private void marshalStaxResult(Marshaller jaxbMarshaller, Object graph, StaxResult staxResult) + throws JAXBException { if (staxResult.getXMLStreamWriter() != null) { - createMarshaller().marshal(graph, staxResult.getXMLStreamWriter()); + jaxbMarshaller.marshal(graph, staxResult.getXMLStreamWriter()); } else if (staxResult.getXMLEventWriter() != null) { - createMarshaller().marshal(graph, staxResult.getXMLEventWriter()); + jaxbMarshaller.marshal(graph, staxResult.getXMLEventWriter()); } else { throw new IllegalArgumentException("StaxResult contains neither XMLStreamWriter nor XMLEventConsumer"); } } - private Object unmarshalStaxSource(StaxSource staxSource) throws JAXBException { + /* + * Unmarshalling + */ + + public Object unmarshal(Source source) throws XmlMappingException { + return unmarshal(source, null); + } + + public Object unmarshal(Source source, MimeContainer mimeContainer) throws XmlMappingException { + try { + Unmarshaller unmarshaller = createUnmarshaller(); + if (mimeContainer != null) { + unmarshaller.setAttachmentUnmarshaller(new Jaxb2AttachmentUnmarshaller(mimeContainer)); + } + if (source instanceof StaxSource) { + return unmarshalStaxSource(unmarshaller, (StaxSource) source); + } + else { + return unmarshaller.unmarshal(source); + } + } + catch (JAXBException ex) { + throw convertJaxbException(ex); + } + } + + private Object unmarshalStaxSource(Unmarshaller jaxbUnmarshaller, StaxSource staxSource) throws JAXBException { if (staxSource.getXMLStreamReader() != null) { - return createUnmarshaller().unmarshal(staxSource.getXMLStreamReader()); + return jaxbUnmarshaller.unmarshal(staxSource.getXMLStreamReader()); } else if (staxSource.getXMLEventReader() != null) { - return createUnmarshaller().unmarshal(staxSource.getXMLEventReader()); + return jaxbUnmarshaller.unmarshal(staxSource.getXMLEventReader()); } else { throw new IllegalArgumentException("StaxSource contains neither XMLStreamReader nor XMLEventReader"); } } + + /* + * Inner classes + */ + + private static class Jaxb2AttachmentMarshaller extends AttachmentMarshaller { + + private final MimeContainer mimeContainer; + + public Jaxb2AttachmentMarshaller(MimeContainer mimeContainer) { + this.mimeContainer = mimeContainer; + } + + public String addMtomAttachment(byte[] data, + int offset, + int length, + String mimeType, + String elementNamespace, + String elementLocalName) { + ByteArrayDataSource dataSource = new ByteArrayDataSource(mimeType, data, offset, length); + return addMtomAttachment(new DataHandler(dataSource), elementNamespace, elementLocalName); + } + + public String addMtomAttachment(DataHandler dataHandler, String elementNamespace, String elementLocalName) { + String contentId = UUID.randomUUID() + "@" + elementNamespace; + mimeContainer.addAttachment(contentId, dataHandler); + return "cid:" + contentId; + } + + public String addSwaRefAttachment(DataHandler dataHandler) { + String contentId = UUID.randomUUID() + "@" + dataHandler.getName(); + mimeContainer.addAttachment(contentId, dataHandler); + return contentId; + } + + @Override + public boolean isXOPPackage() { + return mimeContainer.isXopPackage(); + } + } + + private static class Jaxb2AttachmentUnmarshaller extends AttachmentUnmarshaller { + + private final MimeContainer mimeContainer; + + public Jaxb2AttachmentUnmarshaller(MimeContainer mimeContainer) { + this.mimeContainer = mimeContainer; + } + + public byte[] getAttachmentAsByteArray(String cid) { + try { + DataHandler dataHandler = getAttachmentAsDataHandler(cid); + return FileCopyUtils.copyToByteArray(dataHandler.getInputStream()); + } + catch (IOException ex) { + return null; + } + } + + public DataHandler getAttachmentAsDataHandler(String cid) { + return mimeContainer.getAttachment(cid); + } + + @Override + public boolean isXOPPackage() { + return mimeContainer.isXopPackage(); + } + } + + /* + * DataSource that wraps around a byte array + */ + private static class ByteArrayDataSource implements DataSource { + + private byte[] data; + + private String contentType; + + private int offset; + + private int length; + + public ByteArrayDataSource(String contentType, byte[] data, int offset, int length) { + this.contentType = contentType; + this.data = data; + this.offset = offset; + this.length = length; + } + + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(data, offset, length); + } + + public OutputStream getOutputStream() throws IOException { + throw new UnsupportedOperationException(); + } + + public String getContentType() { + return contentType; + } + + public String getName() { + return "ByteArrayDataSource"; + } + } + } + diff --git a/oxm-tiger/src/test/java/org/springframework/oxm/jaxb/BinaryObject.java b/oxm-tiger/src/test/java/org/springframework/oxm/jaxb/BinaryObject.java new file mode 100644 index 00000000..7f15d041 --- /dev/null +++ b/oxm-tiger/src/test/java/org/springframework/oxm/jaxb/BinaryObject.java @@ -0,0 +1,57 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed 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.springframework.oxm.jaxb; + +import javax.activation.DataHandler; +import javax.xml.bind.annotation.XmlAttachmentRef; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(namespace = "http://springframework.org/spring-ws") +public class BinaryObject { + + @XmlElement(namespace = "http://springframework.org/spring-ws") + private byte[] bytes; + + @XmlElement(namespace = "http://springframework.org/spring-ws") + private DataHandler dataHandler; + + @XmlElement(namespace = "http://springframework.org/spring-ws") + @XmlAttachmentRef + private DataHandler swaDataHandler; + + public BinaryObject() { + } + + public BinaryObject(byte[] bytes, DataHandler dataHandler) { + this.bytes = bytes; + this.dataHandler = dataHandler; + swaDataHandler = dataHandler; + } + + public byte[] getBytes() { + return bytes; + } + + public DataHandler getDataHandler() { + return dataHandler; + } + + public DataHandler getSwaDataHandler() { + return swaDataHandler; + } +} diff --git a/oxm-tiger/src/test/java/org/springframework/oxm/jaxb/Jaxb2MarshallerTest.java b/oxm-tiger/src/test/java/org/springframework/oxm/jaxb/Jaxb2MarshallerTest.java index c4095708..9850a7d9 100644 --- a/oxm-tiger/src/test/java/org/springframework/oxm/jaxb/Jaxb2MarshallerTest.java +++ b/oxm-tiger/src/test/java/org/springframework/oxm/jaxb/Jaxb2MarshallerTest.java @@ -19,6 +19,8 @@ package org.springframework.oxm.jaxb; import java.io.ByteArrayOutputStream; import java.io.StringWriter; import java.util.Collections; +import javax.activation.DataHandler; +import javax.activation.FileDataSource; import javax.xml.bind.JAXBElement; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; @@ -31,15 +33,22 @@ import javax.xml.transform.sax.SAXResult; import javax.xml.transform.stream.StreamResult; import org.custommonkey.xmlunit.XMLTestCase; -import org.easymock.MockControl; +import static org.easymock.EasyMock.*; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; import org.springframework.oxm.XmlMappingException; import org.springframework.oxm.jaxb2.FlightType; import org.springframework.oxm.jaxb2.Flights; +import org.springframework.oxm.mime.MimeContainer; +import org.springframework.util.FileCopyUtils; import org.springframework.xml.transform.StaxResult; +import org.springframework.xml.transform.StringResult; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Text; +import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; +import org.xml.sax.Locator; public class Jaxb2MarshallerTest extends XMLTestCase { @@ -159,34 +168,53 @@ public class Jaxb2MarshallerTest extends XMLTestCase { } public void testMarshalSaxResult() throws Exception { - MockControl handlerControl = MockControl.createStrictControl(ContentHandler.class); - ContentHandler handlerMock = (ContentHandler) handlerControl.getMock(); - handlerMock.setDocumentLocator(null); - handlerControl.setMatcher(MockControl.ALWAYS_MATCHER); + ContentHandler handlerMock = createStrictMock(ContentHandler.class); + handlerMock.setDocumentLocator(isA(Locator.class)); handlerMock.startDocument(); handlerMock.startPrefixMapping("", "http://samples.springframework.org/flight"); - handlerMock.startElement("http://samples.springframework.org/flight", "flights", "flights", null); - handlerControl.setMatcher(MockControl.ALWAYS_MATCHER); - handlerMock.startElement("http://samples.springframework.org/flight", "flight", "flight", null); - handlerControl.setMatcher(MockControl.ALWAYS_MATCHER); - handlerMock.startElement("http://samples.springframework.org/flight", "number", "number", null); - handlerControl.setMatcher(MockControl.ALWAYS_MATCHER); - handlerMock.characters(new char[]{'4', '2'}, 0, 2); - handlerControl.setMatcher(MockControl.ALWAYS_MATCHER); + handlerMock.startElement(eq("http://samples.springframework.org/flight"), eq("flights"), eq("flights"), + isA(Attributes.class)); + handlerMock.startElement(eq("http://samples.springframework.org/flight"), eq("flight"), eq("flight"), + isA(Attributes.class)); + handlerMock.startElement(eq("http://samples.springframework.org/flight"), eq("number"), eq("number"), + isA(Attributes.class)); + handlerMock.characters(isA(char[].class), eq(0), eq(2)); handlerMock.endElement("http://samples.springframework.org/flight", "number", "number"); handlerMock.endElement("http://samples.springframework.org/flight", "flight", "flight"); handlerMock.endElement("http://samples.springframework.org/flight", "flights", "flights"); handlerMock.endPrefixMapping(""); handlerMock.endDocument(); + replay(handlerMock); - handlerControl.replay(); SAXResult result = new SAXResult(handlerMock); marshaller.marshal(flights, result); - handlerControl.verify(); + verify(handlerMock); } public void testSupports() throws Exception { assertTrue("Jaxb2Marshaller does not support Flights", marshaller.supports(Flights.class)); assertTrue("Jaxb2Marshaller does not support JAXBElement", marshaller.supports(JAXBElement.class)); } + + public void testMarshalAttachments() throws Exception { + marshaller = new Jaxb2Marshaller(); + marshaller.setClassesToBeBound(new Class[]{BinaryObject.class}); + marshaller.afterPropertiesSet(); + MimeContainer mimeContainer = createMock(MimeContainer.class); + + Resource logo = new ClassPathResource("spring-ws.png", getClass()); + DataHandler dataHandler = new DataHandler(new FileDataSource(logo.getFile())); + + expect(mimeContainer.isXopPackage()).andReturn(true); + mimeContainer.addAttachment(isA(String.class), isA(DataHandler.class)); + expectLastCall().times(3); + + replay(mimeContainer); + byte[] bytes = FileCopyUtils.copyToByteArray(logo.getInputStream()); + BinaryObject object = new BinaryObject(bytes, dataHandler); + Result result = new StringResult(); + marshaller.marshal(object, result, mimeContainer); + verify(mimeContainer); + assertTrue("No XML written", result.toString().length() > 0); + } } diff --git a/oxm-tiger/src/test/java/org/springframework/oxm/jaxb/Jaxb2UnmarshallerTest.java b/oxm-tiger/src/test/java/org/springframework/oxm/jaxb/Jaxb2UnmarshallerTest.java index 63bbd874..2eb722b5 100644 --- a/oxm-tiger/src/test/java/org/springframework/oxm/jaxb/Jaxb2UnmarshallerTest.java +++ b/oxm-tiger/src/test/java/org/springframework/oxm/jaxb/Jaxb2UnmarshallerTest.java @@ -16,30 +16,34 @@ package org.springframework.oxm.jaxb; -import java.io.StringReader; import java.io.ByteArrayInputStream; - +import java.io.StringReader; +import javax.activation.DataHandler; +import javax.activation.FileDataSource; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamSource; -import javax.xml.transform.sax.SAXSource; +import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; -import javax.xml.stream.XMLEventReader; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamSource; import junit.framework.TestCase; - +import static org.easymock.EasyMock.*; import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; import org.springframework.oxm.jaxb2.FlightType; import org.springframework.oxm.jaxb2.Flights; +import org.springframework.oxm.mime.MimeContainer; import org.springframework.xml.transform.StaxSource; - +import org.springframework.xml.transform.StringSource; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Text; -import org.xml.sax.XMLReader; import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; public class Jaxb2UnmarshallerTest extends TestCase { @@ -107,6 +111,43 @@ public class Jaxb2UnmarshallerTest extends TestCase { testFlights(flights); } + public void testMarshalAttachments() throws Exception { + unmarshaller = new Jaxb2Marshaller(); + unmarshaller.setClassesToBeBound(new Class[]{BinaryObject.class}); + unmarshaller.afterPropertiesSet(); + MimeContainer mimeContainer = createMock(MimeContainer.class); + + Resource logo = new ClassPathResource("spring-ws.png", getClass()); + DataHandler dataHandler = new DataHandler(new FileDataSource(logo.getFile())); + + expect(mimeContainer.isXopPackage()).andReturn(true); + expect(mimeContainer.getAttachment( + "cid:6b76528d-7a9c-4def-8e13-095ab89e9bb7@http://springframework.org/spring-ws")) + .andReturn(dataHandler); + expect(mimeContainer.getAttachment( + "cid:99bd1592-0521-41a2-9688-a8bfb40192fb@http://springframework.org/spring-ws")) + .andReturn(dataHandler); + expect(mimeContainer.getAttachment("696cfb9a-4d2d-402f-bb5c-59fa69e7f0b3@spring-ws.png")) + .andReturn(dataHandler); + replay(mimeContainer); + String content = "" + "" + + "" + + "" + "" + + "" + + "" + + "696cfb9a-4d2d-402f-bb5c-59fa69e7f0b3@spring-ws.png" + + ""; + + Source source = new StringSource(content); + Object result = unmarshaller.unmarshal(source, mimeContainer); + assertTrue("Result is not a BinaryObject", result instanceof BinaryObject); + verify(mimeContainer); + BinaryObject object = (BinaryObject) result; + assertNotNull("bytes property not set", object.getBytes()); + assertTrue("bytes property not set", object.getBytes().length > 0); + assertNotNull("datahandler property not set", object.getSwaDataHandler()); + } + private void testFlights(Object o) { Flights flights = (Flights) o; assertNotNull("Flights is null", flights); diff --git a/oxm-tiger/src/test/resources/org/springframework/oxm/jaxb/spring-ws.png b/oxm-tiger/src/test/resources/org/springframework/oxm/jaxb/spring-ws.png new file mode 100644 index 0000000000000000000000000000000000000000..f589a8a8023b02a2f4a3d44d15c8f86525790381 GIT binary patch literal 24355 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 Optimized Packaging + */ +public interface MimeContainer { + + /** + * Indicates whether this container is a XOP package. + * + * @return true when the constraints specified in Identifying + * XOP Documents are met. + * @see XOP Packages + */ + boolean isXopPackage(); + + /** + * Adds the given data handler as an attachment to this container. + * + * @param contentId the content id of the attachment + * @param dataHandler the data handler containing the data of the attachment + */ + void addAttachment(String contentId, DataHandler dataHandler); + + /** + * Returns the attachment with the given content id, or null if not found. + * + * @param contentId the content id + * @return the attachment, as a data handler + */ + DataHandler getAttachment(String contentId); +} diff --git a/oxm/src/main/java/org/springframework/oxm/mime/MimeMarshaller.java b/oxm/src/main/java/org/springframework/oxm/mime/MimeMarshaller.java new file mode 100644 index 00000000..71ee95c6 --- /dev/null +++ b/oxm/src/main/java/org/springframework/oxm/mime/MimeMarshaller.java @@ -0,0 +1,49 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed 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.springframework.oxm.mime; + +import java.io.IOException; +import javax.xml.transform.Result; + +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.XmlMappingException; + +/** + * Subinterface of {@link Marshaller} that can use MIME attachments to optimize storage of binary data. Attachments can + * be added as MTOM, XOP, or SwA. + * + * @author Arjen Poutsma + * @see SOAP Message Transmission Optimization + * Mechanism + * @see XML-binary Optimized Packaging + */ +public interface MimeMarshaller extends Marshaller { + + /** + * Marshals the object graph with the given root into the provided {@link Result}, writing binary data to a {@link + * MimeContainer}. + * + * @param graph the root of the object graph to marshal + * @param result the result to marshal to + * @param mimeContainer the MIME container to write extracted binary content to + * @throws XmlMappingException if the given object cannot be marshalled to the result + * @throws IOException if an I/O exception occurs + */ + void marshal(Object graph, Result result, MimeContainer mimeContainer) throws XmlMappingException, IOException; + + +} diff --git a/oxm/src/main/java/org/springframework/oxm/mime/MimeUnmarshaller.java b/oxm/src/main/java/org/springframework/oxm/mime/MimeUnmarshaller.java new file mode 100644 index 00000000..c19c4a9a --- /dev/null +++ b/oxm/src/main/java/org/springframework/oxm/mime/MimeUnmarshaller.java @@ -0,0 +1,47 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed 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.springframework.oxm.mime; + +import java.io.IOException; +import javax.xml.transform.Source; + +import org.springframework.oxm.Unmarshaller; +import org.springframework.oxm.XmlMappingException; + +/** + * Subinterface of {@link org.springframework.oxm.Marshaller} that can use MIME attachments to optimize storage of + * binary data. Attachments can be added as MTOM, XOP, or SwA. + * + * @author Arjen Poutsma + * @see SOAP Message Transmission Optimization + * Mechanism + * @see XML-binary Optimized Packaging + */ +public interface MimeUnmarshaller extends Unmarshaller { + + /** + * Unmarshals the given provided {@link Source} into an object graph, reading binary attachments from a {@link + * MimeContainer}. + * + * @param source the source to marshal from + * @param mimeContainer the MIME container to read extracted binary content from + * @return the object graph + * @throws XmlMappingException if the given source cannot be mapped to an object + * @throws IOException if an I/O Exception occurs + */ + Object unmarshal(Source source, MimeContainer mimeContainer) throws XmlMappingException, IOException; +} diff --git a/oxm/src/main/java/org/springframework/oxm/mime/package.html b/oxm/src/main/java/org/springframework/oxm/mime/package.html new file mode 100644 index 00000000..c5563d6e --- /dev/null +++ b/oxm/src/main/java/org/springframework/oxm/mime/package.html @@ -0,0 +1,5 @@ + + +Contains (un)marshallers optimized to store binary data in MIME attachments. + + \ No newline at end of file