Fixed various MTOM issues.
This commit is contained in:
@@ -24,7 +24,7 @@ import org.springframework.util.StringUtils;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.server.EndpointMapping;
|
||||
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
|
||||
import org.springframework.ws.server.endpoint.mapping.support.PayloadRootUtils;
|
||||
import org.springframework.ws.server.endpoint.support.PayloadRootUtils;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link EndpointMapping} interface that uses the {@link PayloadRoot} annotation to map methods
|
||||
|
||||
@@ -25,6 +25,14 @@ public interface MimeMessage extends WebServiceMessage {
|
||||
*/
|
||||
boolean isXopPackage();
|
||||
|
||||
/**
|
||||
* Turns this message into a XOP package.
|
||||
*
|
||||
* @return <code>true</code> when the message is a XOP package
|
||||
* @see <a href="http://www.w3.org/TR/2005/REC-xop10-20050125/#xop_packages">XOP Packages</a>
|
||||
*/
|
||||
boolean convertToXopPackage();
|
||||
|
||||
/**
|
||||
* Returns the <code>Attachment</code> with the specified content Id.
|
||||
*
|
||||
|
||||
@@ -17,21 +17,16 @@
|
||||
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;
|
||||
import org.springframework.ws.server.endpoint.support.MarshallingUtils;
|
||||
|
||||
/**
|
||||
* Endpoint that unmarshals the request payload, and marshals the response object. This endpoint needs a
|
||||
@@ -84,8 +79,8 @@ public abstract class AbstractMarshallingPayloadEndpoint implements MessageEndpo
|
||||
"AbstractMarshallingPayloadEndpoint(Marshaller, Unmarshaller) constructor.");
|
||||
}
|
||||
else {
|
||||
this.marshaller = marshaller;
|
||||
this.unmarshaller = (Unmarshaller) marshaller;
|
||||
this.setMarshaller(marshaller);
|
||||
this.setUnmarshaller((Unmarshaller) marshaller);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,12 +93,12 @@ public abstract class AbstractMarshallingPayloadEndpoint implements MessageEndpo
|
||||
protected AbstractMarshallingPayloadEndpoint(Marshaller marshaller, Unmarshaller unmarshaller) {
|
||||
Assert.notNull(marshaller, "marshaller must not be null");
|
||||
Assert.notNull(unmarshaller, "unmarshaller must not be null");
|
||||
this.marshaller = marshaller;
|
||||
this.unmarshaller = unmarshaller;
|
||||
this.setMarshaller(marshaller);
|
||||
this.setUnmarshaller(unmarshaller);
|
||||
}
|
||||
|
||||
/** Returns the marshaller used for transforming objects into XML. */
|
||||
public final Marshaller getMarshaller() {
|
||||
public Marshaller getMarshaller() {
|
||||
return marshaller;
|
||||
}
|
||||
|
||||
@@ -113,7 +108,7 @@ public abstract class AbstractMarshallingPayloadEndpoint implements MessageEndpo
|
||||
}
|
||||
|
||||
/** Returns the unmarshaller used for transforming XML into objects. */
|
||||
public final Unmarshaller getUnmarshaller() {
|
||||
public Unmarshaller getUnmarshaller() {
|
||||
return unmarshaller;
|
||||
}
|
||||
|
||||
@@ -123,8 +118,8 @@ public abstract class AbstractMarshallingPayloadEndpoint implements MessageEndpo
|
||||
}
|
||||
|
||||
public final void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(marshaller, "marshaller is required");
|
||||
Assert.notNull(unmarshaller, "unmarshaller is required");
|
||||
Assert.notNull(getMarshaller(), "marshaller is required");
|
||||
Assert.notNull(getUnmarshaller(), "unmarshaller is required");
|
||||
afterMarshallerSet();
|
||||
}
|
||||
|
||||
@@ -139,15 +134,7 @@ public abstract class AbstractMarshallingPayloadEndpoint implements MessageEndpo
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
Object requestObject = MarshallingUtils.unmarshal(getUnmarshaller(), request);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Unmarshalled payload request to [" + requestObject + "]");
|
||||
}
|
||||
@@ -158,14 +145,7 @@ public abstract class AbstractMarshallingPayloadEndpoint implements MessageEndpo
|
||||
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());
|
||||
}
|
||||
MarshallingUtils.marshal(getMarshaller(), responseObject, response);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,33 +159,11 @@ public abstract class AbstractMarshallingPayloadEndpoint implements MessageEndpo
|
||||
/**
|
||||
* Template method that subclasses must implement to process a request.
|
||||
* <p/>
|
||||
* The unmarshaled request object is passed as a parameter, and the returned object is marshalled to a response.
|
||||
* If no response is required, return <code>null</code>.
|
||||
* The unmarshaled request object is passed as a parameter, and the returned object is marshalled to a response. If
|
||||
* no response is required, return <code>null</code>.
|
||||
*
|
||||
* @param requestObject the unnmarshalled message payload as an object
|
||||
* @return the object to be marshalled as response, or <code>null</code> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.ws.server.endpoint.adapter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
@@ -26,6 +27,7 @@ import org.springframework.ws.WebServiceMessage;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.server.EndpointMapping;
|
||||
import org.springframework.ws.server.endpoint.MethodEndpoint;
|
||||
import org.springframework.ws.server.endpoint.support.MarshallingUtils;
|
||||
|
||||
/**
|
||||
* Adapter that supports endpoint methods that use marshalling. Supports methods with the following signature:
|
||||
@@ -62,8 +64,8 @@ public class MarshallingMethodEndpointAdapter extends AbstractMethodEndpointAdap
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new <code>MarshallingMethodEndpointAdapter</code>. The {@link Marshaller} and {@link Unmarshaller}
|
||||
* must be injected using properties.
|
||||
* Creates a new <code>MarshallingMethodEndpointAdapter</code>. The {@link Marshaller} and {@link Unmarshaller} must
|
||||
* be injected using properties.
|
||||
*
|
||||
* @see #setMarshaller(org.springframework.oxm.Marshaller)
|
||||
* @see #setUnmarshaller(org.springframework.oxm.Unmarshaller)
|
||||
@@ -129,17 +131,28 @@ public class MarshallingMethodEndpointAdapter extends AbstractMethodEndpointAdap
|
||||
|
||||
protected void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception {
|
||||
WebServiceMessage request = messageContext.getRequest();
|
||||
Object requestObject = unmarshaller.unmarshal(request.getPayloadSource());
|
||||
Object requestObject = unmarshalRequest(request);
|
||||
Object responseObject = methodEndpoint.invoke(new Object[]{requestObject});
|
||||
if (responseObject != null) {
|
||||
WebServiceMessage response = messageContext.getResponse();
|
||||
marshalResponse(responseObject, response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Object unmarshalRequest(WebServiceMessage request) throws IOException {
|
||||
Object requestObject = MarshallingUtils.unmarshal(unmarshaller, request);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Unmarshalled payload request to [" + requestObject + "]");
|
||||
}
|
||||
Object responseObject = methodEndpoint.invoke(new Object[]{requestObject});
|
||||
if (responseObject != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Marshalling [" + responseObject + "] to response payload");
|
||||
}
|
||||
WebServiceMessage response = messageContext.getResponse();
|
||||
marshaller.marshal(responseObject, response.getPayloadResult());
|
||||
}
|
||||
return requestObject;
|
||||
}
|
||||
|
||||
private void marshalResponse(Object responseObject, WebServiceMessage response) throws IOException {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Marshalling [" + responseObject + "] to response payload");
|
||||
}
|
||||
MarshallingUtils.marshal(marshaller, responseObject, response);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.server.endpoint.mapping.support.PayloadRootUtils;
|
||||
import org.springframework.ws.server.endpoint.support.PayloadRootUtils;
|
||||
|
||||
/**
|
||||
* Implementation of the <code>EndpointMapping</code> interface to map from the qualified name of the request payload
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.ws.WebServiceMessage;
|
||||
import org.springframework.ws.context.MessageContext;
|
||||
import org.springframework.ws.server.endpoint.mapping.support.PayloadRootUtils;
|
||||
import org.springframework.ws.server.endpoint.support.PayloadRootUtils;
|
||||
|
||||
/**
|
||||
* Simple subclass of {@link AbstractMethodEndpointMapping} that maps from the local name of the request payload to
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides helper classes for <code>EndpointMapping</code> implementations.
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.ws.server.endpoint.support;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.activation.DataHandler;
|
||||
|
||||
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.ws.WebServiceMessage;
|
||||
import org.springframework.ws.mime.Attachment;
|
||||
import org.springframework.ws.mime.MimeMessage;
|
||||
|
||||
/**
|
||||
* Helper class for endpoints and endpoint mappings that use marshalling.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public abstract class MarshallingUtils {
|
||||
|
||||
private MarshallingUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Unmarshals the payload of the given message using the provided {@link Unmarshaller}.
|
||||
*
|
||||
* @param unmarshaller the unmarshaller
|
||||
* @param message the message of which the payload is to be unmarshalled
|
||||
* @return the unmarshalled object
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
public static Object unmarshal(Unmarshaller unmarshaller, WebServiceMessage message) throws IOException {
|
||||
if (unmarshaller instanceof MimeUnmarshaller && message instanceof MimeMessage) {
|
||||
MimeUnmarshaller mimeUnmarshaller = (MimeUnmarshaller) unmarshaller;
|
||||
MimeMessageContainer container = new MimeMessageContainer((MimeMessage) message);
|
||||
return mimeUnmarshaller.unmarshal(message.getPayloadSource(), container);
|
||||
}
|
||||
else {
|
||||
return unmarshaller.unmarshal(message.getPayloadSource());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshals the given object to the payload of the given message using the provided {@link Marshaller}.
|
||||
*
|
||||
* @param marshaller the marshaller
|
||||
* @param graph the root of the object graph to marshal
|
||||
* @param message the message of which the payload is to be unmarshalled
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
public static void marshal(Marshaller marshaller, Object graph, WebServiceMessage message) throws IOException {
|
||||
if (marshaller instanceof MimeMarshaller && message instanceof MimeMessage) {
|
||||
MimeMarshaller mimeMarshaller = (MimeMarshaller) marshaller;
|
||||
MimeMessageContainer container = new MimeMessageContainer((MimeMessage) message);
|
||||
mimeMarshaller.marshal(graph, message.getPayloadResult(), container);
|
||||
}
|
||||
else {
|
||||
marshaller.marshal(graph, message.getPayloadResult());
|
||||
}
|
||||
}
|
||||
|
||||
private static class MimeMessageContainer implements MimeContainer {
|
||||
|
||||
private final MimeMessage mimeMessage;
|
||||
|
||||
public MimeMessageContainer(MimeMessage mimeMessage) {
|
||||
this.mimeMessage = mimeMessage;
|
||||
}
|
||||
|
||||
public boolean isXopPackage() {
|
||||
return mimeMessage.isXopPackage();
|
||||
}
|
||||
|
||||
public boolean convertToXopPackage() {
|
||||
return mimeMessage.convertToXopPackage();
|
||||
}
|
||||
|
||||
public void addAttachment(String contentId, DataHandler dataHandler) {
|
||||
mimeMessage.addAttachment(contentId, dataHandler);
|
||||
}
|
||||
|
||||
public DataHandler getAttachment(String contentId) {
|
||||
Attachment attachment = mimeMessage.getAttachment(contentId);
|
||||
return attachment != null ? attachment.getDataHandler() : null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ws.server.endpoint.mapping.support;
|
||||
package org.springframework.ws.server.endpoint.support;
|
||||
|
||||
import javax.xml.namespace.QName;
|
||||
import javax.xml.stream.XMLStreamConstants;
|
||||
@@ -38,6 +38,10 @@ import org.w3c.dom.Node;
|
||||
*/
|
||||
public abstract class PayloadRootUtils {
|
||||
|
||||
private PayloadRootUtils() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the root qualified name of the given source, transforming it if necessary.
|
||||
*
|
||||
@@ -0,0 +1,6 @@
|
||||
<html>
|
||||
<body>
|
||||
Provides helper classes for <code>EndpointAdapter</code>, <code>EndpointInteceptor</code>, and
|
||||
<code>EndpointMapping</code> implementations.
|
||||
</body>
|
||||
</html>
|
||||
@@ -23,9 +23,11 @@ import javax.activation.DataHandler;
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
|
||||
import org.apache.axiom.attachments.Attachments;
|
||||
import org.apache.axiom.om.OMElement;
|
||||
import org.apache.axiom.om.OMException;
|
||||
import org.apache.axiom.om.OMOutputFormat;
|
||||
import org.apache.axiom.om.impl.MTOMConstants;
|
||||
import org.apache.axiom.soap.SOAPBody;
|
||||
import org.apache.axiom.soap.SOAPEnvelope;
|
||||
import org.apache.axiom.soap.SOAPFactory;
|
||||
import org.apache.axiom.soap.SOAPMessage;
|
||||
@@ -81,11 +83,7 @@ public class AxiomSoapMessage extends AbstractSoapMessage {
|
||||
* @param payloadCaching whether the contents of the SOAP body should be cached or not
|
||||
*/
|
||||
public AxiomSoapMessage(SOAPMessage soapMessage, String soapAction, boolean payloadCaching) {
|
||||
axiomMessage = soapMessage;
|
||||
axiomFactory = (SOAPFactory) soapMessage.getSOAPEnvelope().getOMFactory();
|
||||
this.attachments = new Attachments();
|
||||
this.soapAction = soapAction;
|
||||
this.payloadCaching = payloadCaching;
|
||||
this(soapMessage, new Attachments(), soapAction, payloadCaching);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -100,6 +98,8 @@ public class AxiomSoapMessage extends AbstractSoapMessage {
|
||||
Attachments attachments,
|
||||
String soapAction,
|
||||
boolean payloadCaching) {
|
||||
Assert.notNull(soapMessage, "'soapMessage' must not be null");
|
||||
Assert.notNull(attachments, "'attachments' must not be null");
|
||||
axiomMessage = soapMessage;
|
||||
axiomFactory = (SOAPFactory) soapMessage.getSOAPEnvelope().getOMFactory();
|
||||
this.attachments = attachments;
|
||||
@@ -147,7 +147,15 @@ public class AxiomSoapMessage extends AbstractSoapMessage {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean convertToXopPackage() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Attachment getAttachment(String contentId) {
|
||||
Assert.hasLength(contentId, "contentId must not be empty");
|
||||
if (contentId.startsWith("<") && contentId.endsWith(">")) {
|
||||
contentId = contentId.substring(1, contentId.length() - 1);
|
||||
}
|
||||
DataHandler dataHandler = attachments.getDataHandler(contentId);
|
||||
return dataHandler != null ? new AxiomAttachment(contentId, dataHandler) : null;
|
||||
}
|
||||
@@ -191,6 +199,27 @@ public class AxiomSoapMessage extends AbstractSoapMessage {
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer("AxiomSoapMessage");
|
||||
try {
|
||||
SOAPEnvelope envelope = axiomMessage.getSOAPEnvelope();
|
||||
if (envelope != null) {
|
||||
SOAPBody body = envelope.getBody();
|
||||
if (body != null) {
|
||||
OMElement bodyElement = body.getFirstElement();
|
||||
if (bodyElement != null) {
|
||||
buffer.append(' ');
|
||||
buffer.append(bodyElement.getQName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OMException ex) {
|
||||
// ignore
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private class AxiomAttachmentIterator implements Iterator {
|
||||
|
||||
private final Iterator iterator;
|
||||
|
||||
@@ -37,6 +37,7 @@ import org.springframework.ws.soap.AbstractSoapMessage;
|
||||
import org.springframework.ws.soap.SoapEnvelope;
|
||||
import org.springframework.ws.soap.SoapMessage;
|
||||
import org.springframework.ws.soap.saaj.support.SaajUtils;
|
||||
import org.springframework.ws.transport.TransportConstants;
|
||||
|
||||
/**
|
||||
* SAAJ-specific implementation of the {@link SoapMessage} interface. Created via the {@link SaajSoapMessageFactory},
|
||||
@@ -47,16 +48,12 @@ import org.springframework.ws.soap.saaj.support.SaajUtils;
|
||||
*/
|
||||
public class SaajSoapMessage extends AbstractSoapMessage {
|
||||
|
||||
private static final String MIME_HEADER_SOAP_ACTION = "SOAPAction";
|
||||
|
||||
private static final String MIME_HEADER_CONTENT_ID = "Content-Id";
|
||||
|
||||
private static final String MIME_HEADER_CONTENT_TYPE = "Content-Type";
|
||||
|
||||
private SOAPMessage saajMessage;
|
||||
|
||||
private SoapEnvelope envelope;
|
||||
|
||||
private static final String CONTENT_TYPE_XOP = "application/xop+xml";
|
||||
|
||||
/**
|
||||
* Create a new <code>SaajSoapMessage</code> based on the given SAAJ <code>SOAPMessage</code>.
|
||||
*
|
||||
@@ -93,13 +90,13 @@ public class SaajSoapMessage extends AbstractSoapMessage {
|
||||
|
||||
public String getSoapAction() {
|
||||
MimeHeaders mimeHeaders = getImplementation().getMimeHeaders(getSaajMessage());
|
||||
String[] values = mimeHeaders.getHeader(MIME_HEADER_SOAP_ACTION);
|
||||
String[] values = mimeHeaders.getHeader(TransportConstants.HEADER_SOAP_ACTION);
|
||||
return ObjectUtils.isEmpty(values) ? null : values[0];
|
||||
}
|
||||
|
||||
public void setSoapAction(String soapAction) {
|
||||
MimeHeaders mimeHeaders = getImplementation().getMimeHeaders(getSaajMessage());
|
||||
mimeHeaders.setHeader(MIME_HEADER_SOAP_ACTION, soapAction);
|
||||
mimeHeaders.setHeader(TransportConstants.HEADER_SOAP_ACTION, soapAction);
|
||||
}
|
||||
|
||||
public void writeTo(OutputStream outputStream) throws IOException {
|
||||
@@ -113,16 +110,55 @@ public class SaajSoapMessage extends AbstractSoapMessage {
|
||||
}
|
||||
|
||||
public boolean isXopPackage() {
|
||||
SOAPPart saajPart = saajMessage.getSOAPPart();
|
||||
String[] contentTypes = saajPart.getMimeHeader(MIME_HEADER_CONTENT_TYPE);
|
||||
for (int i = 0; i < contentTypes.length; i++) {
|
||||
if (contentTypes[i].indexOf("application/xop+xml") != -1) {
|
||||
return true;
|
||||
if (SaajUtils.getSaajVersion() >= SaajUtils.SAAJ_13) {
|
||||
SOAPPart saajPart = saajMessage.getSOAPPart();
|
||||
String[] contentTypes = saajPart.getMimeHeader(TransportConstants.HEADER_CONTENT_TYPE);
|
||||
for (int i = 0; i < contentTypes.length; i++) {
|
||||
if (contentTypes[i].indexOf(CONTENT_TYPE_XOP) != -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean convertToXopPackage() {
|
||||
if (SaajUtils.getSaajVersion() >= SaajUtils.SAAJ_13) {
|
||||
convertMessageToXop();
|
||||
convertPartToXop();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void convertMessageToXop() {
|
||||
MimeHeaders mimeHeaders = saajMessage.getMimeHeaders();
|
||||
String[] oldContentTypes = mimeHeaders.getHeader(TransportConstants.HEADER_CONTENT_TYPE);
|
||||
String oldContentType =
|
||||
!ObjectUtils.isEmpty(oldContentTypes) ? oldContentTypes[0] : getVersion().getContentType();
|
||||
StringBuffer buffer = new StringBuffer(CONTENT_TYPE_XOP);
|
||||
buffer.append(";type=");
|
||||
buffer.append('"');
|
||||
buffer.append(oldContentType);
|
||||
buffer.append('"');
|
||||
mimeHeaders.setHeader(TransportConstants.HEADER_CONTENT_TYPE, buffer.toString());
|
||||
}
|
||||
|
||||
private void convertPartToXop() {
|
||||
SOAPPart saajPart = saajMessage.getSOAPPart();
|
||||
String[] oldContentTypes = saajPart.getMimeHeader(TransportConstants.HEADER_CONTENT_TYPE);
|
||||
String oldContentType =
|
||||
!ObjectUtils.isEmpty(oldContentTypes) ? oldContentTypes[0] : getVersion().getContentType();
|
||||
StringBuffer buffer = new StringBuffer(CONTENT_TYPE_XOP);
|
||||
buffer.append(";type=");
|
||||
buffer.append('"');
|
||||
buffer.append(oldContentType);
|
||||
buffer.append('"');
|
||||
saajPart.setMimeHeader(TransportConstants.HEADER_CONTENT_TYPE, buffer.toString());
|
||||
}
|
||||
|
||||
public Iterator getAttachments() throws AttachmentException {
|
||||
Iterator iterator = getImplementation().getAttachments(getSaajMessage());
|
||||
return new SaajAttachmentIterator(iterator);
|
||||
@@ -131,13 +167,8 @@ public class SaajSoapMessage extends AbstractSoapMessage {
|
||||
public Attachment getAttachment(String contentId) {
|
||||
Assert.hasLength(contentId, "contentId must not be empty");
|
||||
MimeHeaders mimeHeaders = new MimeHeaders();
|
||||
mimeHeaders.setHeader(MIME_HEADER_CONTENT_ID, contentId);
|
||||
mimeHeaders.setHeader(TransportConstants.HEADER_CONTENT_ID, contentId);
|
||||
Iterator iterator = getImplementation().getAttachment(getSaajMessage(), mimeHeaders);
|
||||
if (!iterator.hasNext()) {
|
||||
// try to prefix it with an MTOM-specific < and >
|
||||
mimeHeaders.setHeader(MIME_HEADER_CONTENT_ID, "<" + contentId + ">");
|
||||
iterator = getImplementation().getAttachment(getSaajMessage(), mimeHeaders);
|
||||
}
|
||||
if (!iterator.hasNext()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,8 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB
|
||||
|
||||
private String messageFactoryProtocol;
|
||||
|
||||
private static final String CONTENT_TYPE = "Content-Type";
|
||||
|
||||
/** Default, empty constructor. */
|
||||
public SaajSoapMessageFactory() {
|
||||
}
|
||||
@@ -161,6 +163,19 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB
|
||||
return new SaajSoapMessage(messageFactory.createMessage(mimeHeaders, inputStream));
|
||||
}
|
||||
catch (SOAPException ex) {
|
||||
// SAAJ 1.3 RI has a issue with handling multipart XOP content types which contain "startinfo" rather than
|
||||
// "start-info", so let's try and do something about it
|
||||
String contentType = StringUtils.arrayToCommaDelimitedString(mimeHeaders.getHeader(CONTENT_TYPE));
|
||||
if (contentType.indexOf("startinfo") != -1) {
|
||||
contentType = contentType.replace("startinfo", "start-info");
|
||||
mimeHeaders.setHeader(CONTENT_TYPE, contentType);
|
||||
try {
|
||||
return new SaajSoapMessage(messageFactory.createMessage(mimeHeaders, inputStream));
|
||||
}
|
||||
catch (SOAPException e) {
|
||||
// fall-through
|
||||
}
|
||||
}
|
||||
throw new SoapMessageCreationException("Could not create message from InputStream: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.ws.transport;
|
||||
|
||||
/**
|
||||
* Declares useful transport constants.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
*/
|
||||
public interface TransportConstants {
|
||||
|
||||
/** The "Content-Id" header. */
|
||||
String HEADER_CONTENT_ID = "Content-Id";
|
||||
|
||||
/** The "Content-Type" header. */
|
||||
String HEADER_CONTENT_TYPE = "Content-Type";
|
||||
|
||||
/** The "Content-Length" header. */
|
||||
String HEADER_CONTENT_LENGTH = "Content-Length";
|
||||
|
||||
/** The "SOAPAction" header. */
|
||||
String HEADER_SOAP_ACTION = "SOAPAction";
|
||||
|
||||
}
|
||||
@@ -125,6 +125,13 @@ public class MockWebServiceMessage implements WebServiceMessage {
|
||||
writer.write(content.toString());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer buffer = new StringBuffer("MockWebServiceMessage {");
|
||||
buffer.append(content);
|
||||
buffer.append('}');
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
private class StringBufferWriter extends Writer {
|
||||
|
||||
private StringBufferWriter() {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ws.server.endpoint.mapping.support;
|
||||
package org.springframework.ws.server.endpoint.support;
|
||||
|
||||
import java.io.StringReader;
|
||||
import javax.xml.namespace.QName;
|
||||
@@ -88,7 +88,27 @@ public abstract class AbstractSoap11MessageFactoryTestCase extends AbstractSoapM
|
||||
Iterator iter = soapMessage.getAttachments();
|
||||
assertTrue("No attachments read", iter.hasNext());
|
||||
|
||||
Attachment attachment = soapMessage.getAttachment("1.urn:uuid:492264AB42E57108E01176731445504@apache.org");
|
||||
Attachment attachment = soapMessage.getAttachment("<1.urn:uuid:492264AB42E57108E01176731445504@apache.org>");
|
||||
assertNotNull("No attachment read", attachment);
|
||||
}
|
||||
|
||||
public void testCreateSoapMessageMtomWeirdStartInfo() throws Exception {
|
||||
InputStream is = AbstractSoap11MessageFactoryTestCase.class.getResourceAsStream("soap11-mtom.bin");
|
||||
Properties headers = new Properties();
|
||||
headers.setProperty("Content-Type", "multipart/related;" + "startinfo=\"text/xml\";" +
|
||||
"type=\"application/xop+xml\";" + "start=\"<0.urn:uuid:492264AB42E57108E01176731445508@apache.org>\";" +
|
||||
"boundary=\"MIMEBoundaryurn_uuid_492264AB42E57108E01176731445507\"");
|
||||
TransportInputStream tis = new MockTransportInputStream(is, headers);
|
||||
|
||||
WebServiceMessage message = messageFactory.createWebServiceMessage(tis);
|
||||
assertTrue("Not a SoapMessage", message instanceof SoapMessage);
|
||||
SoapMessage soapMessage = (SoapMessage) message;
|
||||
assertEquals("Invalid soap version", SoapVersion.SOAP_11, soapMessage.getVersion());
|
||||
assertTrue("Message not a XOP pacakge", soapMessage.isXopPackage());
|
||||
Iterator iter = soapMessage.getAttachments();
|
||||
assertTrue("No attachments read", iter.hasNext());
|
||||
|
||||
Attachment attachment = soapMessage.getAttachment("<1.urn:uuid:492264AB42E57108E01176731445504@apache.org>");
|
||||
assertNotNull("No attachment read", attachment);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ public abstract class AbstractSoap12MessageFactoryTestCase extends AbstractSoapM
|
||||
assertTrue("Not a SoapMessage", message instanceof SoapMessage);
|
||||
SoapMessage soapMessage = (SoapMessage) message;
|
||||
assertEquals("Invalid soap version", SoapVersion.SOAP_12, soapMessage.getVersion());
|
||||
assertFalse("Message a XOP pacakge", soapMessage.isXopPackage());
|
||||
assertFalse("Message is a XOP pacakge", soapMessage.isXopPackage());
|
||||
}
|
||||
|
||||
public void testCreateSoapMessageSwA() throws Exception {
|
||||
@@ -61,7 +61,7 @@ public abstract class AbstractSoap12MessageFactoryTestCase extends AbstractSoapM
|
||||
assertTrue("Not a SoapMessage", message instanceof SoapMessage);
|
||||
SoapMessage soapMessage = (SoapMessage) message;
|
||||
assertEquals("Invalid soap version", SoapVersion.SOAP_12, soapMessage.getVersion());
|
||||
assertFalse("Message a XOP pacakge", soapMessage.isXopPackage());
|
||||
assertFalse("Message is a XOP package", soapMessage.isXopPackage());
|
||||
Attachment attachment = soapMessage.getAttachment("interface21");
|
||||
assertNotNull("No attachment read", attachment);
|
||||
}
|
||||
@@ -78,11 +78,11 @@ public abstract class AbstractSoap12MessageFactoryTestCase extends AbstractSoapM
|
||||
assertTrue("Not a SoapMessage", message instanceof SoapMessage);
|
||||
SoapMessage soapMessage = (SoapMessage) message;
|
||||
assertEquals("Invalid soap version", SoapVersion.SOAP_12, soapMessage.getVersion());
|
||||
assertTrue("Message not a XOP pacakge", soapMessage.isXopPackage());
|
||||
assertTrue("Message is not a XOP pacakge", soapMessage.isXopPackage());
|
||||
Iterator iter = soapMessage.getAttachments();
|
||||
assertTrue("No attachments read", iter.hasNext());
|
||||
|
||||
Attachment attachment = soapMessage.getAttachment("1.urn:uuid:40864869929B855F971176851454452@apache.org");
|
||||
Attachment attachment = soapMessage.getAttachment("<1.urn:uuid:40864869929B855F971176851454452@apache.org>");
|
||||
assertNotNull("No attachment read", attachment);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
log4j.rootCategory=INFO, stdout
|
||||
log4j.logger.org.springframework.ws=DEBUG
|
||||
log4j.logger.httpclient.wire.header=DEBUG
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
|
||||
@@ -314,8 +314,8 @@ public class Jaxb2Marshaller extends AbstractJaxbMarshaller implements MimeMarsh
|
||||
}
|
||||
|
||||
/*
|
||||
* Inner classes
|
||||
*/
|
||||
* Inner classes
|
||||
*/
|
||||
|
||||
private static class Jaxb2AttachmentMarshaller extends AttachmentMarshaller {
|
||||
|
||||
@@ -337,7 +337,7 @@ public class Jaxb2Marshaller extends AbstractJaxbMarshaller implements MimeMarsh
|
||||
|
||||
public String addMtomAttachment(DataHandler dataHandler, String elementNamespace, String elementLocalName) {
|
||||
String contentId = UUID.randomUUID() + "@" + elementNamespace;
|
||||
mimeContainer.addAttachment(contentId, dataHandler);
|
||||
mimeContainer.addAttachment("<" + contentId + ">", dataHandler);
|
||||
return "cid:" + contentId;
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ public class Jaxb2Marshaller extends AbstractJaxbMarshaller implements MimeMarsh
|
||||
|
||||
@Override
|
||||
public boolean isXOPPackage() {
|
||||
return mimeContainer.isXopPackage();
|
||||
return mimeContainer.convertToXopPackage();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -367,12 +367,15 @@ public class Jaxb2Marshaller extends AbstractJaxbMarshaller implements MimeMarsh
|
||||
return FileCopyUtils.copyToByteArray(dataHandler.getInputStream());
|
||||
}
|
||||
catch (IOException ex) {
|
||||
return null;
|
||||
throw new JaxbUnmarshallingFailureException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public DataHandler getAttachmentAsDataHandler(String cid) {
|
||||
return mimeContainer.getAttachment(cid);
|
||||
public DataHandler getAttachmentAsDataHandler(String contentId) {
|
||||
if (contentId.startsWith("cid:")) {
|
||||
contentId = '<' + contentId.substring("cid:".length()) + '>';
|
||||
}
|
||||
return mimeContainer.getAttachment(contentId);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.oxm.jaxb;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Marshaller;
|
||||
@@ -27,7 +26,6 @@ import javax.xml.bind.ValidationEventHandler;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.oxm.XmlMappingException;
|
||||
|
||||
@@ -45,9 +43,7 @@ import org.springframework.oxm.XmlMappingException;
|
||||
public abstract class AbstractJaxbMarshaller
|
||||
implements org.springframework.oxm.Marshaller, org.springframework.oxm.Unmarshaller, InitializingBean {
|
||||
|
||||
/**
|
||||
* Logger available to subclasses.
|
||||
*/
|
||||
/** Logger available to subclasses. */
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private String contextPath;
|
||||
@@ -60,16 +56,12 @@ public abstract class AbstractJaxbMarshaller
|
||||
|
||||
private ValidationEventHandler validationEventHandler;
|
||||
|
||||
/**
|
||||
* Returns the JAXB Context path.
|
||||
*/
|
||||
/** Returns the JAXB Context path. */
|
||||
protected String getContextPath() {
|
||||
return contextPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the JAXB Context path.
|
||||
*/
|
||||
/** Sets the JAXB Context path. */
|
||||
public void setContextPath(String contextPath) {
|
||||
this.contextPath = contextPath;
|
||||
}
|
||||
@@ -79,7 +71,7 @@ public abstract class AbstractJaxbMarshaller
|
||||
* <code>Marshaller</code>, and allow for features such as indentation.
|
||||
*
|
||||
* @param properties the properties
|
||||
* @see javax.xml.bind.Marshaller#setProperty(String, Object)
|
||||
* @see javax.xml.bind.Marshaller#setProperty(String,Object)
|
||||
* @see javax.xml.bind.Marshaller#JAXB_ENCODING
|
||||
* @see javax.xml.bind.Marshaller#JAXB_FORMATTED_OUTPUT
|
||||
* @see javax.xml.bind.Marshaller#JAXB_NO_NAMESPACE_SCHEMA_LOCATION
|
||||
@@ -94,7 +86,7 @@ public abstract class AbstractJaxbMarshaller
|
||||
* <code>Unmarshaller</code>.
|
||||
*
|
||||
* @param properties the properties
|
||||
* @see javax.xml.bind.Unmarshaller#setProperty(String, Object)
|
||||
* @see javax.xml.bind.Unmarshaller#setProperty(String,Object)
|
||||
*/
|
||||
public void setUnmarshallerProperties(Map properties) {
|
||||
this.unmarshallerProperties = properties;
|
||||
@@ -110,6 +102,11 @@ public abstract class AbstractJaxbMarshaller
|
||||
this.validationEventHandler = validationEventHandler;
|
||||
}
|
||||
|
||||
/** Returns the {@link JAXBContext} created in {@link #afterPropertiesSet()}. */
|
||||
public JAXBContext getJaxbContext() {
|
||||
return jaxbContext;
|
||||
}
|
||||
|
||||
public final void afterPropertiesSet() throws Exception {
|
||||
try {
|
||||
jaxbContext = createJaxbContext();
|
||||
@@ -133,9 +130,7 @@ public abstract class AbstractJaxbMarshaller
|
||||
return JaxbUtils.convertJaxbException(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a newly created JAXB marshaller. JAXB marshallers are not necessarily thread safe.
|
||||
*/
|
||||
/** Returns a newly created JAXB marshaller. JAXB marshallers are not necessarily thread safe. */
|
||||
protected Marshaller createMarshaller() {
|
||||
try {
|
||||
Marshaller marshaller = jaxbContext.createMarshaller();
|
||||
@@ -156,9 +151,7 @@ public abstract class AbstractJaxbMarshaller
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a newly created JAXB unmarshaller. JAXB unmarshallers are not necessarily thread safe.
|
||||
*/
|
||||
/** Returns a newly created JAXB unmarshaller. JAXB unmarshallers are not necessarily thread safe. */
|
||||
protected Unmarshaller createUnmarshaller() {
|
||||
try {
|
||||
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
|
||||
@@ -197,8 +190,6 @@ public abstract class AbstractJaxbMarshaller
|
||||
protected void initJaxbUnmarshaller(Unmarshaller unmarshaller) throws JAXBException {
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method that returns a newly created JAXB context. Called from <code>afterPropertiesSet()</code>.
|
||||
*/
|
||||
/** Template method that returns a newly created JAXB context. Called from <code>afterPropertiesSet()</code>. */
|
||||
protected abstract JAXBContext createJaxbContext() throws Exception;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.springframework.oxm.jaxb;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.xml.bind.UnmarshalException;
|
||||
|
||||
import org.springframework.oxm.UnmarshallingFailureException;
|
||||
@@ -30,4 +31,7 @@ public class JaxbUnmarshallingFailureException extends UnmarshallingFailureExcep
|
||||
super("JAXB unmarshalling exception: " + ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
public JaxbUnmarshallingFailureException(IOException ex) {
|
||||
super("JAXB unmarshalling exception: " + ex.getMessage(), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,14 @@ public interface MimeContainer {
|
||||
*/
|
||||
boolean isXopPackage();
|
||||
|
||||
/**
|
||||
* Turns this message into a XOP package.
|
||||
*
|
||||
* @return <code>true</code> when the message is a XOP package
|
||||
* @see <a href="http://www.w3.org/TR/2005/REC-xop10-20050125/#xop_packages">XOP Packages</a>
|
||||
*/
|
||||
boolean convertToXopPackage();
|
||||
|
||||
/**
|
||||
* Adds the given data handler as an attachment to this container.
|
||||
*
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
</properties>
|
||||
<body>
|
||||
<release version="1.0-rc2">
|
||||
<action dev="poutsma" type="fix">Fixed various MTOM issues, added an MTOM sample</action>
|
||||
<action dev="poutsma" type="add" issue="SWS-135">Implement client-side TransportContext</action>
|
||||
<action dev="poutsma" type="add" issue="SWS-133">Added ignoreExtraAttributes and ignoreExtraElements
|
||||
properties to CastorMarshaller
|
||||
|
||||
Reference in New Issue
Block a user