diff --git a/core/src/main/java/org/springframework/ws/WebServiceMessageFactory.java b/core/src/main/java/org/springframework/ws/WebServiceMessageFactory.java index 80466119..0260b95c 100644 --- a/core/src/main/java/org/springframework/ws/WebServiceMessageFactory.java +++ b/core/src/main/java/org/springframework/ws/WebServiceMessageFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2006-2007 the original author or authors. + * Copyright 2002-2010 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. @@ -44,7 +44,7 @@ public interface WebServiceMessageFactory { * If the given stream is an instance of {@link org.springframework.ws.transport.TransportInputStream * TransportInputStream}, the headers will be read from the request. * - * @param inputStream the inputstream to read the message from + * @param inputStream the input stream to read the message from * @return the created message * @throws java.io.IOException if an I/O exception occurs */ diff --git a/core/src/main/java/org/springframework/ws/soap/SoapMessageFactory.java b/core/src/main/java/org/springframework/ws/soap/SoapMessageFactory.java index f3c442e8..aaf1d6ef 100644 --- a/core/src/main/java/org/springframework/ws/soap/SoapMessageFactory.java +++ b/core/src/main/java/org/springframework/ws/soap/SoapMessageFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 the original author or authors. + * Copyright 2002-2010 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. @@ -16,6 +16,9 @@ package org.springframework.ws.soap; +import java.io.IOException; +import java.io.InputStream; + import org.springframework.ws.WebServiceMessageFactory; /** @@ -38,4 +41,24 @@ public interface SoapMessageFactory extends WebServiceMessageFactory { */ void setSoapVersion(SoapVersion version); + /** + * Creates a new, empty SoapMessage. + * + * @return the empty message + */ + SoapMessage createWebServiceMessage(); + + /** + * Reads a {@link SoapMessage} from the given input stream. + *

+ * If the given stream is an instance of {@link org.springframework.ws.transport.TransportInputStream + * TransportInputStream}, the headers will be read from the request. + * + * @param inputStream the input stream to read the message from + * @return the created message + * @throws java.io.IOException if an I/O exception occurs + */ + SoapMessage createWebServiceMessage(InputStream inputStream) throws IOException; + + } diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessageFactory.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessageFactory.java index 0944f5e4..13f41776 100644 --- a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessageFactory.java +++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessageFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2010 the original author or authors. + * Copyright 2002-2010 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. @@ -28,7 +28,6 @@ import javax.xml.stream.XMLStreamReader; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import org.springframework.ws.WebServiceMessage; import org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor; import org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping; import org.springframework.ws.soap.SoapMessageFactory; @@ -191,11 +190,11 @@ public class AxiomSoapMessageFactory implements SoapMessageFactory, Initializing } } - public WebServiceMessage createWebServiceMessage() { + public AxiomSoapMessage createWebServiceMessage() { return new AxiomSoapMessage(soapFactory, payloadCaching, langAttributeOnSoap11FaultString); } - public WebServiceMessage createWebServiceMessage(InputStream inputStream) throws IOException { + public AxiomSoapMessage createWebServiceMessage(InputStream inputStream) throws IOException { Assert.isInstanceOf(TransportInputStream.class, inputStream, "AxiomSoapMessageFactory requires a TransportInputStream"); TransportInputStream transportInputStream = (TransportInputStream) inputStream; @@ -242,7 +241,7 @@ public class AxiomSoapMessageFactory implements SoapMessageFactory, Initializing } /** Creates an AxiomSoapMessage without attachments. */ - private WebServiceMessage createAxiomSoapMessage(InputStream inputStream, String contentType, String soapAction) + private AxiomSoapMessage createAxiomSoapMessage(InputStream inputStream, String contentType, String soapAction) throws XMLStreamException { XMLStreamReader reader = inputFactory.createXMLStreamReader(inputStream, getCharSetEncoding(contentType)); String envelopeNamespace = getSoapEnvelopeNamespace(contentType); diff --git a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java index 21587ac7..fa05dee0 100644 --- a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java +++ b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2010 the original author or authors. + * Copyright 2002-2010 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. @@ -21,15 +21,17 @@ import java.io.IOException; import java.io.InputStream; import java.io.PushbackInputStream; import java.util.Iterator; +import java.util.Map; import java.util.StringTokenizer; import javax.xml.soap.MessageFactory; import javax.xml.soap.MimeHeaders; import javax.xml.soap.SOAPConstants; import javax.xml.soap.SOAPException; +import javax.xml.soap.SOAPMessage; import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; -import org.springframework.ws.WebServiceMessage; import org.springframework.ws.soap.SoapMessageCreationException; import org.springframework.ws.soap.SoapMessageFactory; import org.springframework.ws.soap.SoapVersion; @@ -63,6 +65,8 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB private boolean langAttributeOnSoap11FaultString = true; + private Map messageProperties; + /** Default, empty constructor. */ public SaajSoapMessageFactory() { } @@ -82,6 +86,14 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB this.messageFactory = messageFactory; } + /** + * Sets the SAAJ message properties. These properties will be set on created messages. + * @see javax.xml.soap.SOAPMessage#setProperty(String, Object) + */ + public void setMessageProperties(Map messageProperties) { + this.messageProperties = messageProperties; + } + /** * Defines whether a {@code xml:lang} attribute should be set on SOAP 1.1 {@code } elements. *

@@ -90,7 +102,7 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB * * @see WS-I Basic Profile 1.1 */ - public void setlangAttributeOnSoap11FaultString(boolean langAttributeOnSoap11FaultString) { + public void setLangAttributeOnSoap11FaultString(boolean langAttributeOnSoap11FaultString) { this.langAttributeOnSoap11FaultString = langAttributeOnSoap11FaultString; } @@ -152,20 +164,24 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB } } - public WebServiceMessage createWebServiceMessage() { + public SaajSoapMessage createWebServiceMessage() { try { - return new SaajSoapMessage(messageFactory.createMessage(), langAttributeOnSoap11FaultString); + SOAPMessage saajMessage = messageFactory.createMessage(); + postProcess(saajMessage); + return new SaajSoapMessage(saajMessage, langAttributeOnSoap11FaultString); } catch (SOAPException ex) { throw new SoapMessageCreationException("Could not create empty message: " + ex.getMessage(), ex); } } - public WebServiceMessage createWebServiceMessage(InputStream inputStream) throws IOException { + public SaajSoapMessage createWebServiceMessage(InputStream inputStream) throws IOException { MimeHeaders mimeHeaders = parseMimeHeaders(inputStream); try { inputStream = checkForUtf8ByteOrderMark(inputStream); - return new SaajSoapMessage(messageFactory.createMessage(mimeHeaders, inputStream)); + SOAPMessage saajMessage = messageFactory.createMessage(mimeHeaders, inputStream); + postProcess(saajMessage); + return new SaajSoapMessage(saajMessage); } catch (SOAPException ex) { // SAAJ 1.3 RI has a issue with handling multipart XOP content types which contain "startinfo" rather than @@ -176,7 +192,9 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB contentType = contentType.replace("startinfo", "start-info"); mimeHeaders.setHeader(TransportConstants.HEADER_CONTENT_TYPE, contentType); try { - return new SaajSoapMessage(messageFactory.createMessage(mimeHeaders, inputStream), + SOAPMessage saajMessage = messageFactory.createMessage(mimeHeaders, inputStream); + postProcess(saajMessage); + return new SaajSoapMessage(saajMessage, langAttributeOnSoap11FaultString); } catch (SOAPException e) { @@ -223,6 +241,20 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB return pushbackInputStream; } + /** + * Template method that allows for post-processing of the given {@link SOAPMessage}. + *

Default implementation sets {@linkplain SOAPMessage#setProperty(String, Object) message properties}, if any. + * @param soapMessage the message to post process + * @see #setMessageProperties(java.util.Map) + */ + protected void postProcess(SOAPMessage soapMessage) throws SOAPException { + if (!CollectionUtils.isEmpty(messageProperties)) { + for (Map.Entry entry : messageProperties.entrySet()) { + soapMessage.setProperty(entry.getKey(), entry.getValue()); + } + } + } + public String toString() { StringBuilder builder = new StringBuilder("SaajSoapMessageFactory["); builder.append(SaajUtils.getSaajVersionString()); diff --git a/core/src/test/java/org/springframework/ws/soap/saaj/SaajSoap11MessageFactoryTest.java b/core/src/test/java/org/springframework/ws/soap/saaj/SaajSoap11MessageFactoryTest.java index e791534d..788abd38 100644 --- a/core/src/test/java/org/springframework/ws/soap/saaj/SaajSoap11MessageFactoryTest.java +++ b/core/src/test/java/org/springframework/ws/soap/saaj/SaajSoap11MessageFactoryTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2005-2010 the original author or authors. + * Copyright 2002-2010 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. @@ -16,12 +16,22 @@ package org.springframework.ws.soap.saaj; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Collections; +import java.util.Map; import javax.xml.soap.MessageFactory; import javax.xml.soap.SOAPConstants; +import javax.xml.soap.SOAPMessage; import org.springframework.ws.WebServiceMessageFactory; +import org.springframework.ws.soap.SoapMessage; import org.springframework.ws.soap.soap11.AbstractSoap11MessageFactoryTestCase; +import org.junit.Test; + +import static org.junit.Assert.assertTrue; + public class SaajSoap11MessageFactoryTest extends AbstractSoap11MessageFactoryTestCase { @Override @@ -30,5 +40,16 @@ public class SaajSoap11MessageFactoryTest extends AbstractSoap11MessageFactoryTe return new SaajSoapMessageFactory(messageFactory); } + @Test + public void properties() throws IOException { + Map properties = Collections.singletonMap(SOAPMessage.WRITE_XML_DECLARATION, "true"); + ((SaajSoapMessageFactory)messageFactory).setMessageProperties(properties); + SoapMessage soapMessage = (SoapMessage) messageFactory.createWebServiceMessage(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + soapMessage.writeTo(os); + String result = os.toString("UTF-8"); + assertTrue("XML declaration not written", result.startsWith("