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 c32712b6..b2fd69f1 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 @@ -16,6 +16,7 @@ package org.springframework.ws.soap.axiom; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; @@ -36,11 +37,17 @@ import org.apache.axiom.soap.impl.llom.soap11.SOAP11Factory; import org.apache.axiom.soap.impl.llom.soap12.SOAP12Factory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + 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; import org.springframework.ws.soap.SoapVersion; +import org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor; +import org.springframework.ws.soap.server.endpoint.mapping.SoapActionEndpointMapping; import org.springframework.ws.transport.TransportConstants; import org.springframework.ws.transport.TransportInputStream; @@ -48,13 +55,18 @@ import org.springframework.ws.transport.TransportInputStream; * Axiom-specific implementation of the {@link org.springframework.ws.WebServiceMessageFactory WebServiceMessageFactory} * interface. Creates {@link org.springframework.ws.soap.axiom.AxiomSoapMessage AxiomSoapMessages}. *
- * To increase reading performance on the the SOAP request created by this message context factory, you can set the - *payloadCaching property to false (default is true). This this will read the
- * contents of the body directly from the stream. However, when this setting is enabled, the payload can only be
- * read once. This means that any endpoint mappings or interceptors which are based on the message payload
- * (such as the PayloadRootQNameEndpointMapping, the PayloadValidatingInterceptor, or the
- * PayloadLoggingInterceptor) cannot be used. Instead, use an endpoint mapping that does not consume the
- * payload (i.e. the SoapActionEndpointMapping).
+ * To increase reading performance on the the SOAP request created by this message factory, you can set the {@link
+ * #setPayloadCaching(boolean) payloadCaching} property to false (default is true). This this
+ * will read the contents of the body directly from the stream. However, when this setting is enabled, the
+ * payload can only be read once. This means that any endpoint mappings or interceptors which are based on the
+ * message payload (such as the {@link PayloadRootQNameEndpointMapping}, the {@link PayloadValidatingInterceptor}, or
+ * the {@link PayloadLoggingInterceptor}) cannot be used. Instead, use an endpoint mapping that does not consume the
+ * payload (i.e. the {@link SoapActionEndpointMapping}).
+ *
+ * Additionally, this message factory can cache large attachments to disk by setting the {@link
+ * #setAttachmentCaching(boolean) attachmentCaching} property to true (default is false).
+ * Optionally, the location where attachments are stored can be defined via the {@link #setAttachmentCacheDir(File)
+ * attachmentCacheDir} property (defaults to the system temp file path).
*
* Mostly derived from org.apache.axis2.transport.http.HTTPTransportUtils and
* org.apache.axis2.transport.TransportUtils, which we cannot use since they are not part of the Axiom
@@ -79,6 +91,12 @@ public class AxiomSoapMessageFactory implements SoapMessageFactory, Initializing
private boolean payloadCaching = true;
+ private boolean attachmentCaching = false;
+
+ private File attachmentCacheDir;
+
+ private int attachmentCacheThreshold = 4096;
+
// use SOAP 1.1 by default
private SOAPFactory soapFactory = new SOAP11Factory();
@@ -88,14 +106,51 @@ public class AxiomSoapMessageFactory implements SoapMessageFactory, Initializing
}
/**
- * Indicates whether the SOAP Body payload should be cached or not. Default is true. Setting this to
- * false will increase performance, but also result in the fact that the message payload can only be
- * read once.
+ * Indicates whether the SOAP Body payload should be cached or not. Default is true.
+ *
+ * Setting this to false will increase performance, but also result in the fact that the message
+ * payload can only be read once.
*/
public void setPayloadCaching(boolean payloadCaching) {
this.payloadCaching = payloadCaching;
}
+ /**
+ * Indicates whether SOAP attachments should be cached or not. Default is false.
+ *
+ * Setting this to true will cause Axiom to store larger attachments on disk, rather than in memory.
+ * This decreases memory consumption, but decreases performance.
+ */
+ public void setAttachmentCaching(boolean attachmentCaching) {
+ this.attachmentCaching = attachmentCaching;
+ }
+
+ /**
+ * Sets the directory where SOAP attachments will be stored. Only used when {@link #setAttachmentCaching(boolean)
+ * attachmentCaching} is set to true.
+ *
+ * The parameter should be an existing, writable directory. This property defaults to the temporary directory of the
+ * operating system (i.e. the value of the java.io.tmpdir system property).
+ */
+ public void setAttachmentCacheDir(File attachmentCacheDir) {
+ Assert.notNull(attachmentCacheDir, "'attachmentCacheDir' must not be null");
+ Assert.isTrue(attachmentCacheDir.isDirectory(), "'attachmentCacheDir' must be a directory");
+ Assert.isTrue(attachmentCacheDir.canWrite(), "'attachmentCacheDir' must be writable");
+ this.attachmentCacheDir = attachmentCacheDir;
+ }
+
+ /**
+ * Sets the threshold for attachments caching, in bytes. Attachments larger than this threshold will be cached in
+ * the {@link #setAttachmentCacheDir(File) attachment cache directory}. Only used when {@link
+ * #setAttachmentCaching(boolean) attachmentCaching} is set to true.
+ *
+ * Defaults to 4096 bytes (i.e. 4 kilobytes).
+ */
+ public void setAttachmentCacheThreshold(int attachmentCacheThreshold) {
+ Assert.isTrue(attachmentCacheThreshold > 0, "'attachmentCacheThreshold' must be larger than 0");
+ this.attachmentCacheThreshold = attachmentCacheThreshold;
+ }
+
public void setSoapVersion(SoapVersion version) {
if (SoapVersion.SOAP_11 == version) {
soapFactory = new SOAP11Factory();
@@ -113,6 +168,10 @@ public class AxiomSoapMessageFactory implements SoapMessageFactory, Initializing
if (logger.isInfoEnabled()) {
logger.info(payloadCaching ? "Enabled payload caching" : "Disabled payload caching");
}
+ if (attachmentCacheDir == null) {
+ String tempDir = System.getProperty("java.io.tmpdir");
+ setAttachmentCacheDir(new File(tempDir));
+ }
}
public WebServiceMessage createWebServiceMessage() {
@@ -172,7 +231,8 @@ public class AxiomSoapMessageFactory implements SoapMessageFactory, Initializing
private AxiomSoapMessage createMultiPartAxiomSoapMessage(InputStream inputStream,
String contentType,
String soapAction) throws XMLStreamException {
- Attachments attachments = new Attachments(inputStream, contentType);
+ Attachments attachments = new Attachments(inputStream, contentType, attachmentCaching,
+ attachmentCacheDir.getAbsolutePath(), Integer.toString(attachmentCacheThreshold));
XMLStreamReader reader = inputFactory.createXMLStreamReader(attachments.getSOAPPartInputStream(),
getCharSetEncoding(attachments.getSOAPPartContentType()));
StAXSOAPModelBuilder builder;
diff --git a/core/src/test/java/org/springframework/ws/soap/axiom/AxiomSoap11MessageFactoryTest.java b/core/src/test/java/org/springframework/ws/soap/axiom/AxiomSoap11MessageFactoryTest.java
index faebf117..f5e76458 100644
--- a/core/src/test/java/org/springframework/ws/soap/axiom/AxiomSoap11MessageFactoryTest.java
+++ b/core/src/test/java/org/springframework/ws/soap/axiom/AxiomSoap11MessageFactoryTest.java
@@ -27,31 +27,4 @@ public class AxiomSoap11MessageFactoryTest extends AbstractSoap11MessageFactoryT
return factory;
}
-/*
- public void testCreateMtom() throws Exception {
- SOAP11Factory factory = new SOAP11Factory();
- SOAPEnvelope envelope = factory.getDefaultEnvelope();
-
- OMNamespace namespace = factory.createOMNamespace("http://springframework.org/spring-ws/mtom", "sws");
- OMElement element = factory.createOMElement("image", namespace);
- envelope.getBody().addChild(element);
- DataHandler dataHandler = new javax.activation.DataHandler(new FileDataSource("/Users/arjen/spring-ws/src/site/resources/images/spring-ws.png"));
-
- //create an OMText node with the above DataHandler and set optimized to true
- OMText textData = factory.createOMText(dataHandler, true);
-
- element.addChild(textData);
-
- OMOutputFormat format = new OMOutputFormat();
- format.setDoOptimize(true);
- format.setSOAP11(true);
- format.setCharSetEncoding("UTF-8");
- assertTrue(format.isOptimized());
- OutputStream os = new BufferedOutputStream(new FileOutputStream(
- "/Users/arjen/Projects/Spring/spring-ws/core/src/test/resources/org/springframework/ws/soap/soap11/soap11-mtom.bin"));
- try {
- envelope.serialize(os, format);
- } finally {
- os.close();
- */
}
\ No newline at end of file