diff --git a/core/src/main/java/org/springframework/ws/server/endpoint/AbstractEndpointExceptionResolver.java b/core/src/main/java/org/springframework/ws/server/endpoint/AbstractEndpointExceptionResolver.java index c8de005c..98d93b17 100644 --- a/core/src/main/java/org/springframework/ws/server/endpoint/AbstractEndpointExceptionResolver.java +++ b/core/src/main/java/org/springframework/ws/server/endpoint/AbstractEndpointExceptionResolver.java @@ -20,43 +20,56 @@ import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.core.Ordered; import org.springframework.ws.context.MessageContext; import org.springframework.ws.server.EndpointExceptionResolver; /** * Abstract base class for {@link EndpointExceptionResolver EndpointExceptionResolvers}. - * + *

*

Provides a set of mapped endpoints that the resolver should map. * * @author Arjen Poutsma */ -public abstract class AbstractEndpointExceptionResolver implements EndpointExceptionResolver { +public abstract class AbstractEndpointExceptionResolver implements EndpointExceptionResolver, Ordered { /** Shared {@link Log} for subclasses to use. */ protected final Log logger = LogFactory.getLog(getClass()); + private int order = Integer.MAX_VALUE; // default: same as non-Ordered private Set mappedEndpoints; - /** - * Specify the set of endpoints that this exception resolver should map. - *

The exception mappings and the default fault will only apply to the - * specified endpoints. + * Specify the set of endpoints that this exception resolver should map.

The exception mappings and the default + * fault will only apply to the specified endpoints. *

- * If no endpoints are set, both the exception mappings and the default fault - * will apply to all handlers. This means that a specified default fault will - * be used as fallback for all exceptions; any further + * If no endpoints are set, both the exception mappings and the default fault will apply to all handlers. This means + * that a specified default fault will be used as fallback for all exceptions; any further * EndpointExceptionResolvers in the chain will be ignored in this case. */ public void setMappedEndpoints(Set mappedEndpoints) { this.mappedEndpoints = mappedEndpoints; } + /** + * Specify the order value for this mapping. + *

+ * Default value is {@link Integer#MAX_VALUE}, meaning that it's non-ordered. + * + * @see org.springframework.core.Ordered#getOrder() + */ + public final void setOrder(int order) { + this.order = order; + } + + public final int getOrder() { + return order; + } /** - * Default implementation that checks whether the given endpoint - * is in the set of {@link #setMappedEndpoints mapped endpoints}. + * Default implementation that checks whether the given endpoint is in the set of {@link + * #setMappedEndpoints mapped endpoints}. * * @see #resolveExceptionInternal(org.springframework.ws.context.MessageContext,Object,Exception) */ @@ -67,10 +80,8 @@ public abstract class AbstractEndpointExceptionResolver implements EndpointExcep return resolveExceptionInternal(messageContext, endpoint, ex); } - /** - * Template method for resolving exceptions that is called by - * {@link #resolveException}. + * Template method for resolving exceptions that is called by {@link #resolveException}. * * @param messageContext current message context * @param endpoint the executed endpoint, or null if none chosen at the time of the exception diff --git a/core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractEndpointMapping.java b/core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractEndpointMapping.java index 1b48ba5e..85c33844 100644 --- a/core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractEndpointMapping.java +++ b/core/src/main/java/org/springframework/ws/server/endpoint/mapping/AbstractEndpointMapping.java @@ -17,6 +17,7 @@ package org.springframework.ws.server.endpoint.mapping; import org.springframework.context.support.ApplicationObjectSupport; +import org.springframework.core.Ordered; import org.springframework.ws.context.MessageContext; import org.springframework.ws.server.EndpointInterceptor; import org.springframework.ws.server.EndpointInvocationChain; @@ -29,33 +30,14 @@ import org.springframework.ws.server.EndpointMapping; * @see #getEndpointInternal(org.springframework.ws.context.MessageContext) * @see org.springframework.ws.server.EndpointInterceptor */ -public abstract class AbstractEndpointMapping extends ApplicationObjectSupport implements EndpointMapping { +public abstract class AbstractEndpointMapping extends ApplicationObjectSupport implements EndpointMapping, Ordered { + + private int order = Integer.MAX_VALUE; // default: same as non-Ordered private Object defaultEndpoint; private EndpointInterceptor[] interceptors; - /** - * Returns the default endpoint for this endpoint mapping. - * - * @return the default endpoint mapping, or null if none - */ - protected final Object getDefaultEndpoint() { - return defaultEndpoint; - } - - /** - * Sets the default endpoint for this endpoint mapping. This endpoint will be returned if no specific mapping was - * found. - *

- * Default is null, indicating no default endpoint. - * - * @param defaultEndpoint the default endpoint, or null if none - */ - public final void setDefaultEndpoint(Object defaultEndpoint) { - this.defaultEndpoint = defaultEndpoint; - } - /** * Returns the the endpoint interceptors to apply to all endpoints mapped by this endpoint mapping. * @@ -74,6 +56,21 @@ public abstract class AbstractEndpointMapping extends ApplicationObjectSupport i this.interceptors = interceptors; } + public final int getOrder() { + return order; + } + + /** + * Specify the order value for this mapping. + *

+ * Default value is {@link Integer#MAX_VALUE}, meaning that it's non-ordered. + * + * @see org.springframework.core.Ordered#getOrder() + */ + public final void setOrder(int order) { + this.order = order; + } + /** * Look up an endpoint for the given message context, falling back to the default endpoint if no specific one is * found. @@ -115,6 +112,27 @@ public abstract class AbstractEndpointMapping extends ApplicationObjectSupport i return new EndpointInvocationChain(endpoint, interceptors); } + /** + * Returns the default endpoint for this endpoint mapping. + * + * @return the default endpoint mapping, or null if none + */ + protected final Object getDefaultEndpoint() { + return defaultEndpoint; + } + + /** + * Sets the default endpoint for this endpoint mapping. This endpoint will be returned if no specific mapping was + * found. + *

+ * Default is null, indicating no default endpoint. + * + * @param defaultEndpoint the default endpoint, or null if none + */ + public final void setDefaultEndpoint(Object defaultEndpoint) { + this.defaultEndpoint = defaultEndpoint; + } + /** * Resolves an endpoint string. If the given string can is a bean name, it is resolved using the application * context. diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Header.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Header.java new file mode 100644 index 00000000..29fb937b --- /dev/null +++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap11Header.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.ws.soap.axiom; + +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.apache.axiom.soap.RolePlayer; +import org.apache.axiom.soap.SOAPFactory; +import org.apache.axiom.soap.SOAPHeader; +import org.springframework.util.ObjectUtils; +import org.springframework.ws.soap.soap11.Soap11Header; + +/** + * Axiom-specific version of org.springframework.ws.soap.Soap11Header. + * + * @author Arjen Poutsma + */ +class AxiomSoap11Header extends AxiomSoapHeader implements Soap11Header { + + AxiomSoap11Header(SOAPHeader axiomHeader, SOAPFactory axiomFactory) { + super(axiomHeader, axiomFactory); + } + + public Iterator examineHeaderElementsToProcess(final String[] actors) { + RolePlayer rolePlayer = null; + if (!ObjectUtils.isEmpty(actors)) { + rolePlayer = new RolePlayer() { + + public List getRoles() { + return Arrays.asList(actors); + } + + public boolean isUltimateDestination() { + return false; + } + }; + } + Iterator result = getAxiomHeader().getHeadersToProcess(rolePlayer); + return new AxiomSoapHeaderElementIterator(result); + } +} diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Header.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Header.java index a482d0de..0d6fbd7a 100644 --- a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Header.java +++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoap12Header.java @@ -16,16 +16,22 @@ package org.springframework.ws.soap.axiom; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; import javax.xml.namespace.QName; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.OMException; import org.apache.axiom.om.OMNamespace; +import org.apache.axiom.soap.RolePlayer; import org.apache.axiom.soap.SOAPFactory; import org.apache.axiom.soap.SOAPHeader; import org.apache.axiom.soap.SOAPHeaderBlock; import org.apache.axiom.soap.SOAPProcessingException; +import org.springframework.util.ObjectUtils; import org.springframework.ws.soap.SoapHeaderElement; +import org.springframework.ws.soap.SoapHeaderException; import org.springframework.ws.soap.soap12.Soap12Header; import org.springframework.xml.namespace.QNameUtils; @@ -69,4 +75,23 @@ class AxiomSoap12Header extends AxiomSoapHeader implements Soap12Header { throw new AxiomSoapHeaderException(ex); } } + + public Iterator examineHeaderElementsToProcess(final String[] roles, final boolean isUltimateDestination) + throws SoapHeaderException { + RolePlayer rolePlayer = null; + if (!ObjectUtils.isEmpty(roles)) { + rolePlayer = new RolePlayer() { + + public List getRoles() { + return Arrays.asList(roles); + } + + public boolean isUltimateDestination() { + return isUltimateDestination; + } + }; + } + Iterator result = getAxiomHeader().getHeadersToProcess(rolePlayer); + return new AxiomSoapHeaderElementIterator(result); + } } diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapEnvelope.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapEnvelope.java index 20ebd351..0bbd2d65 100644 --- a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapEnvelope.java +++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapEnvelope.java @@ -36,7 +36,7 @@ class AxiomSoapEnvelope extends AxiomSoapElement implements SoapEnvelope { SOAPHeader axiomHeader = getAxiomEnvelope().getHeader(); String namespaceURI = getAxiomEnvelope().getNamespace().getNamespaceURI(); if (SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(namespaceURI)) { - return new AxiomSoapHeader(axiomHeader, getAxiomFactory()); + return new AxiomSoap11Header(axiomHeader, getAxiomFactory()); } else if (SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(namespaceURI)) { return new AxiomSoap12Header(axiomHeader, getAxiomFactory()); diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeader.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeader.java index d6e088b7..1c71ca1c 100644 --- a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeader.java +++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapHeader.java @@ -36,7 +36,7 @@ import org.springframework.xml.namespace.QNameUtils; * * @author Arjen Poutsma */ -class AxiomSoapHeader extends AxiomSoapElement implements SoapHeader { +abstract class AxiomSoapHeader extends AxiomSoapElement implements SoapHeader { AxiomSoapHeader(SOAPHeader axiomHeader, SOAPFactory axiomFactory) { super(axiomHeader, axiomFactory); @@ -89,11 +89,11 @@ class AxiomSoapHeader extends AxiomSoapElement implements SoapHeader { return (SOAPHeader) getAxiomElement(); } - private class AxiomSoapHeaderElementIterator implements Iterator { + protected class AxiomSoapHeaderElementIterator implements Iterator { private final Iterator axiomIterator; - private AxiomSoapHeaderElementIterator(Iterator axiomIterator) { + protected AxiomSoapHeaderElementIterator(Iterator axiomIterator) { this.axiomIterator = axiomIterator; } diff --git a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap11Header.java b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap11Header.java new file mode 100644 index 00000000..d3e9c90c --- /dev/null +++ b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap11Header.java @@ -0,0 +1,70 @@ +/* + * 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.soap.saaj; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import javax.xml.soap.SOAPConstants; +import javax.xml.soap.SOAPHeader; +import javax.xml.soap.SOAPHeaderElement; + +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import org.springframework.ws.soap.soap11.Soap11Header; + +/** + * SAAJ-specific implementation of the Soap11Header interface. Wraps a {@link javax.xml.soap.SOAPHeader}. + * + * @author Arjen Poutsma + */ +class SaajSoap11Header extends SaajSoapHeader implements Soap11Header { + + SaajSoap11Header(SOAPHeader header) { + super(header); + } + + public Iterator examineHeaderElementsToProcess(String[] actors) { + List result = new ArrayList(); + Iterator iterator = getImplementation().examineAllHeaderElements(getSaajHeader()); + while (iterator.hasNext()) { + SOAPHeaderElement saajHeaderElement = (SOAPHeaderElement) iterator.next(); + String headerActor = saajHeaderElement.getActor(); + if (shouldProcess(headerActor, actors)) { + result.add(saajHeaderElement); + } + } + return new SaajSoapHeaderElementIterator(result.iterator()); + } + + private boolean shouldProcess(String headerActor, String[] actors) { + if (!StringUtils.hasLength(headerActor)) { + return true; + } + if (SOAPConstants.URI_SOAP_ACTOR_NEXT.equals(headerActor)) { + return true; + } + if (!ObjectUtils.isEmpty(actors)) { + for (int i = 0; i < actors.length; i++) { + if (actors[i].equals(headerActor)) { + return true; + } + } + } + return false; + } +} diff --git a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap12Header.java b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap12Header.java index 3aefdbdb..4859e778 100644 --- a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap12Header.java +++ b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoap12Header.java @@ -16,12 +16,19 @@ package org.springframework.ws.soap.saaj; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import javax.xml.namespace.QName; +import javax.xml.soap.SOAPConstants; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPHeader; import javax.xml.soap.SOAPHeaderElement; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; import org.springframework.ws.soap.SoapHeaderElement; +import org.springframework.ws.soap.SoapHeaderException; import org.springframework.ws.soap.soap12.Soap12Header; /** @@ -56,4 +63,42 @@ class SaajSoap12Header extends SaajSoapHeader implements Soap12Header { throw new SaajSoapHeaderException(ex); } } + + public Iterator examineHeaderElementsToProcess(String[] roles, boolean isUltimateDestination) + throws SoapHeaderException { + List result = new ArrayList(); + Iterator iterator = getImplementation().examineAllHeaderElements(getSaajHeader()); + while (iterator.hasNext()) { + SOAPHeaderElement saajHeaderElement = (SOAPHeaderElement) iterator.next(); + String headerRole = saajHeaderElement.getRole(); + if (shouldProcess(headerRole, roles, isUltimateDestination)) { + result.add(saajHeaderElement); + } + } + return new SaajSoapHeaderElementIterator(result.iterator()); + + } + + private boolean shouldProcess(String headerRole, String[] roles, boolean isUltimateDestination) { + if (!StringUtils.hasLength(headerRole)) { + return true; + } + if (SOAPConstants.URI_SOAP_1_2_ROLE_NEXT.equals(headerRole)) { + return true; + } + if (SOAPConstants.URI_SOAP_1_2_ROLE_ULTIMATE_RECEIVER.equals(headerRole)) { + return isUltimateDestination; + } + if (SOAPConstants.URI_SOAP_1_2_ROLE_NONE.equals(headerRole)) { + return false; + } + if (!ObjectUtils.isEmpty(roles)) { + for (int i = 0; i < roles.length; i++) { + if (roles[i].equals(headerRole)) { + return true; + } + } + } + return false; + } } diff --git a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapEnvelope.java b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapEnvelope.java index 16ca8f88..d1ad66d9 100644 --- a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapEnvelope.java +++ b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapEnvelope.java @@ -68,7 +68,7 @@ class SaajSoapEnvelope extends SaajSoapElement implements SoapEnvelope { if (saajHeader != null) { if (getImplementation().getName(saajHeader).getNamespaceURI() .equals(SoapVersion.SOAP_11.getEnvelopeNamespaceUri())) { - header = new SaajSoapHeader(saajHeader); + header = new SaajSoap11Header(saajHeader); } else { header = new SaajSoap12Header(saajHeader); diff --git a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapHeader.java b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapHeader.java index 620358f1..714ce633 100644 --- a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapHeader.java +++ b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapHeader.java @@ -33,7 +33,7 @@ import org.springframework.ws.soap.SoapHeaderException; * * @author Arjen Poutsma */ -class SaajSoapHeader extends SaajSoapElement implements SoapHeader { +abstract class SaajSoapHeader extends SaajSoapElement implements SoapHeader { SaajSoapHeader(SOAPHeader header) { super(header); @@ -67,11 +67,11 @@ class SaajSoapHeader extends SaajSoapElement implements SoapHeader { return getImplementation().getResult(getSaajHeader()); } - private static class SaajSoapHeaderElementIterator implements Iterator { + protected static class SaajSoapHeaderElementIterator implements Iterator { private final Iterator iterator; - private SaajSoapHeaderElementIterator(Iterator iterator) { + protected SaajSoapHeaderElementIterator(Iterator iterator) { Assert.notNull(iterator, "iterator must not be null"); this.iterator = iterator; } diff --git a/core/src/main/java/org/springframework/ws/soap/server/SoapEndpointInvocationChain.java b/core/src/main/java/org/springframework/ws/soap/server/SoapEndpointInvocationChain.java index 338a4a01..a6350b38 100644 --- a/core/src/main/java/org/springframework/ws/soap/server/SoapEndpointInvocationChain.java +++ b/core/src/main/java/org/springframework/ws/soap/server/SoapEndpointInvocationChain.java @@ -32,6 +32,8 @@ public class SoapEndpointInvocationChain extends EndpointInvocationChain { private String[] actorsOrRoles; + private boolean isUltimateReceiver = true; + /** * Create new SoapEndpointInvocationChain. * @@ -54,13 +56,18 @@ public class SoapEndpointInvocationChain extends EndpointInvocationChain { /** * Create new EndpointInvocationChain. * - * @param endpoint the endpoint object to invoke - * @param interceptors the array of interceptors to apply - * @param actorsOrRoles the array of actorsOrRoles to set + * @param endpoint the endpoint object to invoke + * @param interceptors the array of interceptors to apply + * @param actorsOrRoles the array of actorsOrRoles to set + * @param isUltimateReceiver whether this chain fullfils the SOAP 1.2 Ultimate receiver role */ - public SoapEndpointInvocationChain(Object endpoint, EndpointInterceptor[] interceptors, String[] actorsOrRoles) { + public SoapEndpointInvocationChain(Object endpoint, + EndpointInterceptor[] interceptors, + String[] actorsOrRoles, + boolean isUltimateReceiver) { super(endpoint, interceptors); this.actorsOrRoles = actorsOrRoles; + this.isUltimateReceiver = isUltimateReceiver; } /** @@ -72,4 +79,9 @@ public class SoapEndpointInvocationChain extends EndpointInvocationChain { public String[] getActorsOrRoles() { return actorsOrRoles; } + + /** Indicates whether this chain fulfills the SOAP 1.2 Ultimate Receiver role. Default is true. */ + public boolean isUltimateReceiver() { + return isUltimateReceiver; + } } diff --git a/core/src/main/java/org/springframework/ws/soap/server/SoapEndpointMapping.java b/core/src/main/java/org/springframework/ws/soap/server/SoapEndpointMapping.java index 0d4ead82..a2b3eb54 100644 --- a/core/src/main/java/org/springframework/ws/soap/server/SoapEndpointMapping.java +++ b/core/src/main/java/org/springframework/ws/soap/server/SoapEndpointMapping.java @@ -36,4 +36,6 @@ public interface SoapEndpointMapping extends EndpointMapping { /** Sets the array of SOAP actors/actorsOrRoles to apply to all endpoints mapped by the delegate endpoint mapping. */ void setActorsOrRoles(String[] actorsOrRoles); + /** Indicates whether this the endpoint fulfills the SOAP 1.2 Ultimate Receiver role. */ + void setUltimateReceiver(boolean ultimateReceiver); } diff --git a/core/src/main/java/org/springframework/ws/soap/server/SoapMessageDispatcher.java b/core/src/main/java/org/springframework/ws/soap/server/SoapMessageDispatcher.java index 8dbb846d..c71baa38 100644 --- a/core/src/main/java/org/springframework/ws/soap/server/SoapMessageDispatcher.java +++ b/core/src/main/java/org/springframework/ws/soap/server/SoapMessageDispatcher.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.Locale; import javax.xml.namespace.QName; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.ws.context.MessageContext; import org.springframework.ws.server.EndpointInterceptor; @@ -32,7 +33,7 @@ import org.springframework.ws.soap.SoapFault; import org.springframework.ws.soap.SoapHeader; import org.springframework.ws.soap.SoapHeaderElement; import org.springframework.ws.soap.SoapMessage; -import org.springframework.ws.soap.SoapVersion; +import org.springframework.ws.soap.soap11.Soap11Header; import org.springframework.ws.soap.soap12.Soap12Header; /** @@ -46,33 +47,30 @@ import org.springframework.ws.soap.soap12.Soap12Header; public class SoapMessageDispatcher extends MessageDispatcher { /** Default message used when creating a SOAP MustUnderstand fault. */ - public static final String DEFAULT_MUST_UNDERSTAND_FAULT = + public static final String DEFAULT_MUST_UNDERSTAND_FAULT_STRING = "One or more mandatory SOAP header blocks not understood"; - private String mustUnderstandFault = DEFAULT_MUST_UNDERSTAND_FAULT; + private String mustUnderstandFaultString = DEFAULT_MUST_UNDERSTAND_FAULT_STRING; - private Locale mustUnderstandFaultLocale = Locale.ENGLISH; + private Locale mustUnderstandFaultStringLocale = Locale.ENGLISH; /** - * Sets the message used for MustUnderstand fault. Default to DEFAULT_MUST_UNDERSTAND_FAULT. - * - * @see #DEFAULT_MUST_UNDERSTAND_FAULT + * Sets the message used for MustUnderstand fault. Default to {@link + * #DEFAULT_MUST_UNDERSTAND_FAULT_STRING}. */ - public void setMustUnderstandFault(String mustUnderstandFault) { - this.mustUnderstandFault = mustUnderstandFault; + public void setMustUnderstandFaultString(String mustUnderstandFaultString) { + this.mustUnderstandFaultString = mustUnderstandFaultString; + } + + /** Sets the locale of the message used for MustUnderstand fault. Default to {@link Locale#ENGLISH}. */ + public void setMustUnderstandFaultStringLocale(Locale mustUnderstandFaultStringLocale) { + this.mustUnderstandFaultStringLocale = mustUnderstandFaultStringLocale; } /** - * Sets the locale of the message used for MustUnderstand fault. Default to - * Locale.ENGLISH. - */ - public void setMustUnderstandFaultLocale(Locale mustUnderstandFaultLocale) { - this.mustUnderstandFaultLocale = mustUnderstandFaultLocale; - } - - /** - * Process the MustUnderstand headers in the incoming SOAP request message. Iterates over all SOAP - * headers which should be understood, and determines whether these are supported. Generates a SOAP MustUnderstand + * Process the headers targeted at the actor or role fullfilled by the endpoint. Also processed the + * MustUnderstand headers in the incoming SOAP request message. Iterates over all SOAP headers which + * should be understood for this role, and determines whether these are supported. Generates a SOAP MustUnderstand * fault if a header is not understood. * * @param mappedEndpoint the mapped EndpointInvocationChain @@ -83,41 +81,59 @@ public class SoapMessageDispatcher extends MessageDispatcher { */ protected boolean handleRequest(EndpointInvocationChain mappedEndpoint, MessageContext messageContext) { if (messageContext.getRequest() instanceof SoapMessage) { - SoapMessage soapRequest = (SoapMessage) messageContext.getRequest(); - if (soapRequest.getSoapHeader() == null) { - // no headers to process - return true; - } - String[] roles = getRoles(mappedEndpoint, soapRequest.getVersion()); - if (logger.isDebugEnabled()) { - logger.debug("Handling MustUnderstand headers for actors/roles [" + - StringUtils.arrayToCommaDelimitedString(roles) + "]"); - } - for (int i = 0; i < roles.length; i++) { - if (!handleRequestForRole(mappedEndpoint, messageContext, roles[i])) { - return false; - } + String[] actorsOrRoles = null; + boolean isUltimateReceiver = true; + if (mappedEndpoint instanceof SoapEndpointInvocationChain) { + SoapEndpointInvocationChain soapChain = (SoapEndpointInvocationChain) mappedEndpoint; + actorsOrRoles = soapChain.getActorsOrRoles(); + isUltimateReceiver = soapChain.isUltimateReceiver(); } + return handleHeaders(mappedEndpoint, messageContext, actorsOrRoles, isUltimateReceiver); } return true; } - /** - * Determines the roles for a specific SOAP invocation chain. Gets the roles specified on the chain, and adds the - * SOAP-version specific 'next' role to it. - * - * @see org.springframework.ws.soap.SoapVersion#getNextActorOrRoleUri() - */ - protected String[] getRoles(EndpointInvocationChain mappedEndpoint, SoapVersion version) { - String[] mappedRoles = null; - if (mappedEndpoint instanceof SoapEndpointInvocationChain) { - SoapEndpointInvocationChain soapEndpoint = (SoapEndpointInvocationChain) mappedEndpoint; - mappedRoles = soapEndpoint.getActorsOrRoles(); + private boolean handleHeaders(EndpointInvocationChain mappedEndpoint, + MessageContext messageContext, + String[] actorsOrRoles, + boolean isUltimateReceiver) { + SoapMessage soapRequest = (SoapMessage) messageContext.getRequest(); + SoapHeader soapHeader = soapRequest.getSoapHeader(); + if (soapHeader == null) { + return true; } - if (mappedRoles == null) { - mappedRoles = new String[0]; + Iterator headerIterator; + if (soapHeader instanceof Soap11Header) { + headerIterator = ((Soap11Header) soapHeader).examineHeaderElementsToProcess(actorsOrRoles); + } + else { + headerIterator = + ((Soap12Header) soapHeader).examineHeaderElementsToProcess(actorsOrRoles, isUltimateReceiver); + } + List notUnderstoodHeaderNames = new ArrayList(); + while (headerIterator.hasNext()) { + SoapHeaderElement headerElement = (SoapHeaderElement) headerIterator.next(); + QName headerName = headerElement.getName(); + if (logger.isDebugEnabled()) { + if (!headerElement.getMustUnderstand()) { + logger.debug("Handling header " + headerName); + } + else { + logger.debug("Handling MustUnderstand header " + headerName); + } + } + if (headerElement.getMustUnderstand() && !headerUnderstood(mappedEndpoint, headerElement)) { + notUnderstoodHeaderNames.add(headerName); + } + } + if (notUnderstoodHeaderNames.isEmpty()) { + return true; + } + else { + SoapMessage response = (SoapMessage) messageContext.getResponse(); + createMustUnderstandFault(response, notUnderstoodHeaderNames, actorsOrRoles); + return false; } - return StringUtils.addStringToArray(mappedRoles, version.getNextActorOrRoleUri()); } /** @@ -128,52 +144,39 @@ public class SoapMessageDispatcher extends MessageDispatcher { * * @see SoapEndpointInterceptor#understands(org.springframework.ws.soap.SoapHeaderElement) */ - private boolean handleRequestForRole(EndpointInvocationChain mappedEndpoint, - MessageContext messageContext, - String actorOrRole) { - SoapHeader requestHeader = ((SoapMessage) messageContext.getRequest()).getSoapHeader(); - List notUnderstoodHeaderNames = new ArrayList(); - for (Iterator iterator = requestHeader.examineMustUnderstandHeaderElements(actorOrRole); iterator.hasNext();) { - SoapHeaderElement headerElement = (SoapHeaderElement) iterator.next(); - QName headerName = headerElement.getName(); - if (logger.isDebugEnabled()) { - logger.debug( - "Received mustUnderstand header [" + headerName + "] for actor/role [" + actorOrRole + "]"); - } - boolean understood = false; - for (int i = 0; i < mappedEndpoint.getInterceptors().length; i++) { - EndpointInterceptor interceptor = mappedEndpoint.getInterceptors()[i]; - if (interceptor instanceof SoapEndpointInterceptor && - ((SoapEndpointInterceptor) interceptor).understands(headerElement)) { - understood = true; - break; - } - } - if (!understood) { - notUnderstoodHeaderNames.add(headerName); + private boolean headerUnderstood(EndpointInvocationChain mappedEndpoint, SoapHeaderElement headerElement) { + EndpointInterceptor[] interceptors = mappedEndpoint.getInterceptors(); + for (int i = 0; i < interceptors.length; i++) { + EndpointInterceptor interceptor = interceptors[i]; + if (interceptor instanceof SoapEndpointInterceptor && + ((SoapEndpointInterceptor) interceptor).understands(headerElement)) { + return true; } } - if (notUnderstoodHeaderNames.isEmpty()) { - return true; + return false; + } + + private void createMustUnderstandFault(SoapMessage soapResponse, + List notUnderstoodHeaderNames, + String[] actorsOrRoles) { + if (logger.isWarnEnabled()) { + logger.warn("Could not handle mustUnderstand headers: " + + StringUtils.collectionToCommaDelimitedString(notUnderstoodHeaderNames) + ". Returning fault"); } - else { - if (logger.isWarnEnabled()) { - logger.warn("Could not handle mustUnderstand headers: " + - StringUtils.collectionToCommaDelimitedString(notUnderstoodHeaderNames) + ". Returning fault"); + SoapBody responseBody = soapResponse.getSoapBody(); + SoapFault fault = + responseBody.addMustUnderstandFault(mustUnderstandFaultString, mustUnderstandFaultStringLocale); + if (!ObjectUtils.isEmpty(actorsOrRoles)) { + fault.setFaultActorOrRole(actorsOrRoles[0]); + } + SoapHeader header = soapResponse.getSoapHeader(); + if (header instanceof Soap12Header) { + Soap12Header soap12Header = (Soap12Header) header; + for (Iterator iterator = notUnderstoodHeaderNames.iterator(); iterator.hasNext();) { + QName headerName = (QName) iterator.next(); + soap12Header.addNotUnderstoodHeaderElement(headerName); } - SoapMessage soapResponse = (SoapMessage) messageContext.getResponse(); - SoapBody responseBody = soapResponse.getSoapBody(); - SoapFault fault = responseBody.addMustUnderstandFault(mustUnderstandFault, mustUnderstandFaultLocale); - fault.setFaultActorOrRole(actorOrRole); - SoapHeader header = soapResponse.getSoapHeader(); - if (header instanceof Soap12Header) { - Soap12Header soap12Header = (Soap12Header) header; - for (Iterator iterator = notUnderstoodHeaderNames.iterator(); iterator.hasNext();) { - QName headerName = (QName) iterator.next(); - soap12Header.addNotUnderstoodHeaderElement(headerName); - } - } - return false; } } + } diff --git a/core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/DelegatingSoapEndpointMapping.java b/core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/DelegatingSoapEndpointMapping.java index f6c0da41..94cabd22 100644 --- a/core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/DelegatingSoapEndpointMapping.java +++ b/core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/DelegatingSoapEndpointMapping.java @@ -46,6 +46,8 @@ public class DelegatingSoapEndpointMapping implements InitializingBean, SoapEndp private String[] actorsOrRoles; + private boolean isUltimateReceiver = true; + /** Sets the delegate EndpointMapping to resolve the endpoint with. */ public void setDelegate(EndpointMapping delegate) { this.delegate = delegate; @@ -61,6 +63,10 @@ public class DelegatingSoapEndpointMapping implements InitializingBean, SoapEndp this.actorsOrRoles = actorsOrRoles; } + public final void setUltimateReceiver(boolean ultimateReceiver) { + isUltimateReceiver = ultimateReceiver; + } + /** * Creates a new SoapEndpointInvocationChain based on the delegate endpoint, the delegate interceptors, * and set actors/roles. @@ -70,7 +76,7 @@ public class DelegatingSoapEndpointMapping implements InitializingBean, SoapEndp public EndpointInvocationChain getEndpoint(MessageContext messageContext) throws Exception { EndpointInvocationChain delegateChain = delegate.getEndpoint(messageContext); return new SoapEndpointInvocationChain(delegateChain.getEndpoint(), delegateChain.getInterceptors(), - actorsOrRoles); + actorsOrRoles, isUltimateReceiver); } public void afterPropertiesSet() throws Exception { diff --git a/core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionEndpointMapping.java b/core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionEndpointMapping.java index 939c340a..c250d350 100644 --- a/core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionEndpointMapping.java +++ b/core/src/main/java/org/springframework/ws/soap/server/endpoint/mapping/SoapActionEndpointMapping.java @@ -53,6 +53,8 @@ public class SoapActionEndpointMapping extends AbstractMapBasedEndpointMapping i private String[] actorsOrRoles; + private boolean isUltimateReceiver = true; + public final void setActorOrRole(String actorOrRole) { Assert.notNull(actorOrRole, "actorOrRole must not be null"); actorsOrRoles = new String[]{actorOrRole}; @@ -63,6 +65,10 @@ public class SoapActionEndpointMapping extends AbstractMapBasedEndpointMapping i this.actorsOrRoles = actorsOrRoles; } + public final void setUltimateReceiver(boolean ultimateReceiver) { + isUltimateReceiver = ultimateReceiver; + } + /** * Creates a new SoapEndpointInvocationChain based on the given endpoint, and the set interceptors, and * actors/roles. @@ -76,7 +82,7 @@ public class SoapActionEndpointMapping extends AbstractMapBasedEndpointMapping i protected final EndpointInvocationChain createEndpointInvocationChain(MessageContext messageContext, Object endpoint, EndpointInterceptor[] interceptors) { - return new SoapEndpointInvocationChain(endpoint, interceptors, actorsOrRoles); + return new SoapEndpointInvocationChain(endpoint, interceptors, actorsOrRoles, isUltimateReceiver); } protected String getLookupKeyForMessage(MessageContext messageContext) throws Exception { diff --git a/core/src/main/java/org/springframework/ws/soap/soap11/Soap11Header.java b/core/src/main/java/org/springframework/ws/soap/soap11/Soap11Header.java new file mode 100644 index 00000000..f69d7288 --- /dev/null +++ b/core/src/main/java/org/springframework/ws/soap/soap11/Soap11Header.java @@ -0,0 +1,44 @@ +/* + * 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.soap.soap11; + +import java.util.Iterator; + +import org.springframework.ws.soap.SoapHeader; +import org.springframework.ws.soap.SoapHeaderElement; +import org.springframework.ws.soap.SoapHeaderException; + +/** + * Subinterface of SoapHeader that exposes SOAP 1.1 functionality. + * + * @author Arjen Poutsma + */ +public interface Soap11Header extends SoapHeader { + + /** + * Returns an Iterator over all the {@link SoapHeaderElement header elements} that should be processed + * for the given actors. Headers target to the "next" actor or role will always be included. + * + * @param actors an array of actors to search for + * @return an iterator over all the header elements that contain the specified actors + * @throws SoapHeaderException if the headers cannot be returned + * @see SoapHeaderElement + */ + Iterator examineHeaderElementsToProcess(String[] actors) throws SoapHeaderException; + + +} diff --git a/core/src/main/java/org/springframework/ws/soap/soap12/Soap12Header.java b/core/src/main/java/org/springframework/ws/soap/soap12/Soap12Header.java index 982d5e12..005a2d5f 100644 --- a/core/src/main/java/org/springframework/ws/soap/soap12/Soap12Header.java +++ b/core/src/main/java/org/springframework/ws/soap/soap12/Soap12Header.java @@ -16,10 +16,12 @@ package org.springframework.ws.soap.soap12; +import java.util.Iterator; import javax.xml.namespace.QName; import org.springframework.ws.soap.SoapHeader; import org.springframework.ws.soap.SoapHeaderElement; +import org.springframework.ws.soap.SoapHeaderException; /** * Subinterface of SoapHeader that exposes SOAP 1.2 functionality. @@ -48,4 +50,18 @@ public interface Soap12Header extends SoapHeader { */ SoapHeaderElement addUpgradeHeaderElement(java.lang.String[] supportedSoapUris); + /** + * Returns an Iterator over all the {@link SoapHeaderElement header elements} that should be processed + * for the given roles. Headers target to the "next" role will always be included, and those targeted to "none" will + * never be included. + * + * @param roles an array of roles to search for + * @param isUltimateReceiver whether to search for headers for the ultimate receiver + * @return an iterator over all the header elements that contain the specified roles + * @throws SoapHeaderException if the headers cannot be returned + * @see SoapHeaderElement + */ + Iterator examineHeaderElementsToProcess(String[] roles, boolean isUltimateReceiver) throws SoapHeaderException; + + } diff --git a/core/src/main/java/org/springframework/ws/transport/support/DefaultStrategiesHelper.java b/core/src/main/java/org/springframework/ws/transport/support/DefaultStrategiesHelper.java index 82660a4e..9488fe9f 100644 --- a/core/src/main/java/org/springframework/ws/transport/support/DefaultStrategiesHelper.java +++ b/core/src/main/java/org/springframework/ws/transport/support/DefaultStrategiesHelper.java @@ -37,6 +37,7 @@ import org.springframework.context.ApplicationContextAware; import org.springframework.context.ApplicationEventPublisherAware; import org.springframework.context.MessageSourceAware; import org.springframework.context.ResourceLoaderAware; +import org.springframework.core.OrderComparator; import org.springframework.core.io.Resource; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; @@ -123,6 +124,7 @@ public class DefaultStrategiesHelper { else { result = Collections.EMPTY_LIST; } + Collections.sort(result, new OrderComparator()); return result; } catch (ClassNotFoundException ex) { diff --git a/core/src/test/java/org/springframework/ws/soap/AbstractSoapHeaderTestCase.java b/core/src/test/java/org/springframework/ws/soap/AbstractSoapHeaderTestCase.java index f7dd1843..e56e495d 100644 --- a/core/src/test/java/org/springframework/ws/soap/AbstractSoapHeaderTestCase.java +++ b/core/src/test/java/org/springframework/ws/soap/AbstractSoapHeaderTestCase.java @@ -26,6 +26,10 @@ public abstract class AbstractSoapHeaderTestCase extends AbstractSoapElementTest protected SoapHeader soapHeader; + protected static final String NAMESPACE = "http://www.springframework.org"; + + protected static final String PREFIX = "spring"; + protected final SoapElement createSoapElement() throws Exception { soapHeader = createSoapHeader(); return soapHeader; @@ -34,7 +38,7 @@ public abstract class AbstractSoapHeaderTestCase extends AbstractSoapElementTest protected abstract SoapHeader createSoapHeader() throws Exception; public void testAddHeaderElement() throws Exception { - QName qName = new QName("http://www.springframework.org", "localName", "spring"); + QName qName = new QName(NAMESPACE, "localName", PREFIX); SoapHeaderElement headerElement = soapHeader.addHeaderElement(qName); assertNotNull("No SoapHeaderElement returned", headerElement); assertEquals("Invalid qName for element", qName, headerElement.getName()); @@ -45,7 +49,7 @@ public abstract class AbstractSoapHeaderTestCase extends AbstractSoapElementTest } public void testExamineAllHeaderElement() throws Exception { - QName qName = new QName("http://www.springframework.org", "localName", "spring"); + QName qName = new QName(NAMESPACE, "localName", PREFIX); SoapHeaderElement headerElement = soapHeader.addHeaderElement(qName); assertEquals("Invalid qName for element", qName, headerElement.getName()); assertNotNull("No SoapHeaderElement returned", headerElement); @@ -65,11 +69,11 @@ public abstract class AbstractSoapHeaderTestCase extends AbstractSoapElementTest } public void testExamineMustUnderstandHeaderElements() throws Exception { - QName qName1 = new QName("http://www.springframework.org", "localName1", "spring"); + QName qName1 = new QName(NAMESPACE, "localName1", PREFIX); SoapHeaderElement headerElement1 = soapHeader.addHeaderElement(qName1); headerElement1.setMustUnderstand(true); headerElement1.setActorOrRole("role1"); - QName qName2 = new QName("http://www.springframework.org", "localName2", "spring"); + QName qName2 = new QName(NAMESPACE, "localName2", PREFIX); SoapHeaderElement headerElement2 = soapHeader.addHeaderElement(qName2); headerElement2.setMustUnderstand(true); headerElement2.setActorOrRole("role2"); diff --git a/core/src/test/java/org/springframework/ws/soap/saaj/SaajSoap11HeaderTest.java b/core/src/test/java/org/springframework/ws/soap/saaj/SaajSoap11HeaderTest.java index 61d94a31..b99553c5 100644 --- a/core/src/test/java/org/springframework/ws/soap/saaj/SaajSoap11HeaderTest.java +++ b/core/src/test/java/org/springframework/ws/soap/saaj/SaajSoap11HeaderTest.java @@ -28,6 +28,6 @@ public class SaajSoap11HeaderTest extends AbstractSoap11HeaderTestCase { protected SoapHeader createSoapHeader() throws Exception { MessageFactory messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL); SOAPMessage saajMessage = messageFactory.createMessage(); - return new SaajSoapHeader(saajMessage.getSOAPPart().getEnvelope().getHeader()); + return new SaajSoap11Header(saajMessage.getSOAPPart().getEnvelope().getHeader()); } } diff --git a/core/src/test/java/org/springframework/ws/soap/server/SoapMessageDispatcherTest.java b/core/src/test/java/org/springframework/ws/soap/server/SoapMessageDispatcherTest.java index 8f425263..d2e3f864 100644 --- a/core/src/test/java/org/springframework/ws/soap/server/SoapMessageDispatcherTest.java +++ b/core/src/test/java/org/springframework/ws/soap/server/SoapMessageDispatcherTest.java @@ -121,10 +121,9 @@ public class SoapMessageDispatcherTest extends TestCase { Soap11Fault fault = (Soap11Fault) responseBody.getFault(); assertEquals("Invalid fault code", new QName(SOAPConstants.URI_NS_SOAP_1_1_ENVELOPE, "MustUnderstand"), fault.getFaultCode()); - assertEquals("Invalid fault string", SoapMessageDispatcher.DEFAULT_MUST_UNDERSTAND_FAULT, + assertEquals("Invalid fault string", SoapMessageDispatcher.DEFAULT_MUST_UNDERSTAND_FAULT_STRING, fault.getFaultStringOrReason()); assertEquals("Invalid fault string locale", Locale.ENGLISH, fault.getFaultStringLocale()); - assertEquals("Invalid fault actor", SOAPConstants.URI_SOAP_ACTOR_NEXT, fault.getFaultActorOrRole()); interceptorControl.verify(); } @@ -154,9 +153,8 @@ public class SoapMessageDispatcherTest extends TestCase { Soap12Fault fault = (Soap12Fault) responseBody.getFault(); assertEquals("Invalid fault code", new QName(SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE, "MustUnderstand"), fault.getFaultCode()); - assertEquals("Invalid fault string", SoapMessageDispatcher.DEFAULT_MUST_UNDERSTAND_FAULT, + assertEquals("Invalid fault string", SoapMessageDispatcher.DEFAULT_MUST_UNDERSTAND_FAULT_STRING, fault.getFaultReasonText(Locale.ENGLISH)); - assertEquals("Invalid fault actor", SOAPConstants.URI_SOAP_1_2_ROLE_NEXT, fault.getFaultActorOrRole()); SoapHeader responseHeader = response.getSoapHeader(); Iterator iterator = responseHeader.examineAllHeaderElements(); assertTrue("Response header has no elements", iterator.hasNext()); @@ -182,7 +180,7 @@ public class SoapMessageDispatcherTest extends TestCase { interceptorControl.replay(); SoapEndpointInvocationChain chain = new SoapEndpointInvocationChain(new Object(), - new SoapEndpointInterceptor[]{interceptorMock}, new String[]{headerActor}); + new SoapEndpointInterceptor[]{interceptorMock}, new String[]{headerActor}, true); boolean result = dispatcher.handleRequest(chain, context); assertTrue("actor-specific header not understood", result); @@ -205,7 +203,7 @@ public class SoapMessageDispatcherTest extends TestCase { interceptorControl.replay(); SoapEndpointInvocationChain chain = new SoapEndpointInvocationChain(new Object(), - new SoapEndpointInterceptor[]{interceptorMock}, new String[]{headerRole}); + new SoapEndpointInterceptor[]{interceptorMock}, new String[]{headerRole}, true); boolean result = dispatcher.handleRequest(chain, context); assertTrue("role-specific header not understood", result); @@ -221,7 +219,7 @@ public class SoapMessageDispatcherTest extends TestCase { interceptorControl.replay(); SoapEndpointInvocationChain chain = new SoapEndpointInvocationChain(new Object(), - new SoapEndpointInterceptor[]{interceptorMock}, new String[]{"role"}); + new SoapEndpointInterceptor[]{interceptorMock}, new String[]{"role"}, true); boolean result = dispatcher.handleRequest(chain, context); assertTrue("Invalid result", result); diff --git a/core/src/test/java/org/springframework/ws/soap/soap11/AbstractSoap11BodyTestCase.java b/core/src/test/java/org/springframework/ws/soap/soap11/AbstractSoap11BodyTestCase.java index a5bfcb15..ce1a83f1 100644 --- a/core/src/test/java/org/springframework/ws/soap/soap11/AbstractSoap11BodyTestCase.java +++ b/core/src/test/java/org/springframework/ws/soap/soap11/AbstractSoap11BodyTestCase.java @@ -29,6 +29,10 @@ import org.springframework.xml.transform.StringSource; public abstract class AbstractSoap11BodyTestCase extends AbstractSoapBodyTestCase { + public void testGetType() { + assertTrue("Invalid type returned", soapBody instanceof Soap11Body); + } + public void testGetName() throws Exception { assertEquals("Invalid qualified name", SoapVersion.SOAP_11.getBodyName(), soapBody.getName()); } diff --git a/core/src/test/java/org/springframework/ws/soap/soap11/AbstractSoap11HeaderTestCase.java b/core/src/test/java/org/springframework/ws/soap/soap11/AbstractSoap11HeaderTestCase.java index 75a6fa6d..85e4251c 100644 --- a/core/src/test/java/org/springframework/ws/soap/soap11/AbstractSoap11HeaderTestCase.java +++ b/core/src/test/java/org/springframework/ws/soap/soap11/AbstractSoap11HeaderTestCase.java @@ -16,17 +16,24 @@ package org.springframework.ws.soap.soap11; +import java.util.Iterator; import javax.xml.namespace.QName; import org.springframework.ws.soap.AbstractSoapHeaderTestCase; +import org.springframework.ws.soap.SoapHeaderElement; import org.springframework.ws.soap.SoapVersion; import org.springframework.xml.transform.StringResult; public abstract class AbstractSoap11HeaderTestCase extends AbstractSoapHeaderTestCase { + private static final String PREFIX = "spring"; + + public void testGetType() { + assertTrue("Invalid type returned", soapHeader instanceof Soap11Header); + } + public void testGetName() throws Exception { - assertEquals("Invalid qualified name", - new QName(SoapVersion.SOAP_11.getEnvelopeNamespaceUri(), "Header"), + assertEquals("Invalid qualified name", new QName(SoapVersion.SOAP_11.getEnvelopeNamespaceUri(), "Header"), soapHeader.getName()); } @@ -34,8 +41,51 @@ public abstract class AbstractSoap11HeaderTestCase extends AbstractSoapHeaderTes StringResult result = new StringResult(); transformer.transform(soapHeader.getSource(), result); assertXMLEqual("Invalid contents of header", - "", - result.toString()); + "", result.toString()); + } + + public void testExamineHeaderElementsToProcessActors() throws Exception { + QName qName = new QName(NAMESPACE, "localName1", PREFIX); + SoapHeaderElement headerElement = soapHeader.addHeaderElement(qName); + headerElement.setActorOrRole("role1"); + qName = new QName(NAMESPACE, "localName2", PREFIX); + headerElement = soapHeader.addHeaderElement(qName); + headerElement.setActorOrRole("role2"); + qName = new QName(NAMESPACE, "localName3", PREFIX); + headerElement = soapHeader.addHeaderElement(qName); + headerElement.setActorOrRole(SoapVersion.SOAP_11.getNextActorOrRoleUri()); + Iterator iterator = ((Soap11Header) soapHeader).examineHeaderElementsToProcess(new String[]{"role1"}); + assertNotNull("header element iterator is null", iterator); + assertTrue("header element iterator has no elements", iterator.hasNext()); + checkHeaderElement((SoapHeaderElement) iterator.next()); + assertTrue("header element iterator has no elements", iterator.hasNext()); + checkHeaderElement((SoapHeaderElement) iterator.next()); + assertFalse("header element iterator has too many elements", iterator.hasNext()); + } + + public void testExamineHeaderElementsToProcessNoActors() throws Exception { + QName qName = new QName(NAMESPACE, "localName1", PREFIX); + SoapHeaderElement headerElement = soapHeader.addHeaderElement(qName); + headerElement.setActorOrRole(""); + qName = new QName(NAMESPACE, "localName2", PREFIX); + headerElement = soapHeader.addHeaderElement(qName); + headerElement.setActorOrRole("role1"); + qName = new QName(NAMESPACE, "localName3", PREFIX); + headerElement = soapHeader.addHeaderElement(qName); + headerElement.setActorOrRole(SoapVersion.SOAP_11.getNextActorOrRoleUri()); + Iterator iterator = ((Soap11Header) soapHeader).examineHeaderElementsToProcess(new String[0]); + assertNotNull("header element iterator is null", iterator); + assertTrue("header element iterator has no elements", iterator.hasNext()); + checkHeaderElement((SoapHeaderElement) iterator.next()); + assertTrue("header element iterator has no elements", iterator.hasNext()); + checkHeaderElement((SoapHeaderElement) iterator.next()); + assertFalse("header element iterator has too many elements", iterator.hasNext()); + } + + private void checkHeaderElement(SoapHeaderElement headerElement) { + QName name = headerElement.getName(); + assertTrue("Invalid name on header element", new QName(NAMESPACE, "localName1", PREFIX).equals(name) || + new QName(NAMESPACE, "localName3", PREFIX).equals(name)); } } diff --git a/core/src/test/java/org/springframework/ws/soap/soap12/AbstractSoap12BodyTestCase.java b/core/src/test/java/org/springframework/ws/soap/soap12/AbstractSoap12BodyTestCase.java index d970a877..851a7c9e 100644 --- a/core/src/test/java/org/springframework/ws/soap/soap12/AbstractSoap12BodyTestCase.java +++ b/core/src/test/java/org/springframework/ws/soap/soap12/AbstractSoap12BodyTestCase.java @@ -30,6 +30,10 @@ import org.springframework.xml.transform.StringSource; public abstract class AbstractSoap12BodyTestCase extends AbstractSoapBodyTestCase { + public void testGetType() { + assertTrue("Invalid type returned", soapBody instanceof Soap12Body); + } + public void testGetName() throws Exception { assertEquals("Invalid qualified name", new QName(SoapVersion.SOAP_12.getEnvelopeNamespaceUri(), "Body"), soapBody.getName()); diff --git a/core/src/test/java/org/springframework/ws/soap/soap12/AbstractSoap12HeaderTestCase.java b/core/src/test/java/org/springframework/ws/soap/soap12/AbstractSoap12HeaderTestCase.java index 18a6e3a0..2ff52bbe 100644 --- a/core/src/test/java/org/springframework/ws/soap/soap12/AbstractSoap12HeaderTestCase.java +++ b/core/src/test/java/org/springframework/ws/soap/soap12/AbstractSoap12HeaderTestCase.java @@ -16,6 +16,7 @@ package org.springframework.ws.soap.soap12; +import java.util.Iterator; import javax.xml.namespace.QName; import org.springframework.ws.soap.AbstractSoapHeaderTestCase; @@ -25,6 +26,10 @@ import org.springframework.xml.transform.StringResult; public abstract class AbstractSoap12HeaderTestCase extends AbstractSoapHeaderTestCase { + public void testGetType() { + assertTrue("Invalid type returned", soapHeader instanceof Soap12Header); + } + public void testGetName() throws Exception { assertEquals("Invalid qualified name", new QName(SoapVersion.SOAP_12.getEnvelopeNamespaceUri(), "Header"), soapHeader.getName()); @@ -67,4 +72,60 @@ public abstract class AbstractSoap12HeaderTestCase extends AbstractSoapHeaderTes */ } + public void testExamineHeaderElementsToProcessActors() throws Exception { + QName qName = new QName(NAMESPACE, "localName1", PREFIX); + SoapHeaderElement headerElement = soapHeader.addHeaderElement(qName); + headerElement.setActorOrRole("role1"); + qName = new QName(NAMESPACE, "localName2", PREFIX); + headerElement = soapHeader.addHeaderElement(qName); + headerElement.setActorOrRole("role2"); + qName = new QName(NAMESPACE, "localName3", PREFIX); + headerElement = soapHeader.addHeaderElement(qName); + headerElement.setActorOrRole(SoapVersion.SOAP_12.getNextActorOrRoleUri()); + Iterator iterator = ((Soap12Header) soapHeader).examineHeaderElementsToProcess(new String[]{"role1"}, false); + assertNotNull("header element iterator is null", iterator); + assertTrue("header element iterator has no elements", iterator.hasNext()); + checkHeaderElement((SoapHeaderElement) iterator.next()); + assertTrue("header element iterator has no elements", iterator.hasNext()); + checkHeaderElement((SoapHeaderElement) iterator.next()); + assertFalse("header element iterator has too many elements", iterator.hasNext()); + } + + public void testExamineHeaderElementsToProcessNoActors() throws Exception { + QName qName = new QName(NAMESPACE, "localName1", PREFIX); + SoapHeaderElement headerElement = soapHeader.addHeaderElement(qName); + headerElement.setActorOrRole(""); + qName = new QName(NAMESPACE, "localName2", PREFIX); + headerElement = soapHeader.addHeaderElement(qName); + headerElement.setActorOrRole("role1"); + qName = new QName(NAMESPACE, "localName3", PREFIX); + headerElement = soapHeader.addHeaderElement(qName); + headerElement.setActorOrRole(SoapVersion.SOAP_12.getNextActorOrRoleUri()); + Iterator iterator = ((Soap12Header) soapHeader).examineHeaderElementsToProcess(new String[0], false); + assertNotNull("header element iterator is null", iterator); + assertTrue("header element iterator has no elements", iterator.hasNext()); + checkHeaderElement((SoapHeaderElement) iterator.next()); + assertTrue("header element iterator has no elements", iterator.hasNext()); + checkHeaderElement((SoapHeaderElement) iterator.next()); + assertFalse("header element iterator has too many elements", iterator.hasNext()); + } + + public void testExamineHeaderElementsToProcessUltimateDestination() throws Exception { + QName qName = new QName(NAMESPACE, "localName", PREFIX); + SoapHeaderElement headerElement = soapHeader.addHeaderElement(qName); + headerElement.setActorOrRole(SoapVersion.SOAP_12.getUltimateReceiverRoleUri()); + Iterator iterator = ((Soap12Header) soapHeader).examineHeaderElementsToProcess(new String[]{"role"}, true); + assertNotNull("header element iterator is null", iterator); + headerElement = (SoapHeaderElement) iterator.next(); + assertEquals("Invalid name on header element", new QName(NAMESPACE, "localName", PREFIX), + headerElement.getName()); + assertFalse("header element iterator has too many elements", iterator.hasNext()); + } + + private void checkHeaderElement(SoapHeaderElement headerElement) { + QName name = headerElement.getName(); + assertTrue("Invalid name on header element", new QName(NAMESPACE, "localName1", PREFIX).equals(name) || + new QName(NAMESPACE, "localName3", PREFIX).equals(name)); + } + }