Added handleFault to EndpointInterceptor, moved SoapEndpointInterceptor and SoapEhndpointMapping to org.sfwrk.ws.soap.server package.

This commit is contained in:
Arjen Poutsma
2007-05-14 15:28:37 +00:00
parent c45824d2d8
commit 10e47d5ab6
31 changed files with 268 additions and 167 deletions

View File

@@ -24,9 +24,9 @@ import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.server.EndpointInvocationChain;
import org.springframework.ws.server.endpoint.mapping.AbstractAnnotationMethodEndpointMapping;
import org.springframework.ws.soap.SoapEndpointMapping;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.server.SoapEndpointInvocationChain;
import org.springframework.ws.soap.server.SoapEndpointMapping;
import org.springframework.ws.soap.server.endpoint.annotation.SoapAction;
/**

View File

@@ -23,14 +23,15 @@ import org.springframework.ws.context.MessageContext;
* existing or custom interceptors for certain groups of endpoints, to add common preprocessing behavior without needing
* to modify each endpoint implementation.
* <p/>
* A <code>EndpointInterceptor</code> gets called before the appropriate <code>EndpointAdapter</code> triggers the
* invocation of the endpoint itself. This mechanism can be used for a large field of preprocessing aspects, e.g. for
* authorization checks, or message header checks. Its main purpose is to allow for factoring out repetitive endpoint
* code.
* A <code>EndpointInterceptor</code> gets called before the appropriate {@link EndpointAdapter} triggers the invocation
* of the endpoint itself. This mechanism can be used for a large field of preprocessing aspects, e.g. for authorization
* checks, or message header checks. Its main purpose is to allow for factoring out repetitive endpoint code.
* <p/>
* Typically an interceptor chain is defined per <code>EndpointMapping</code> bean, sharing its granularity. To be able
* to apply a certain interceptor chain to a group of handlers, one needs to map the desired handlers via one
* <code>EndpointMapping</code> bean.
* Typically an interceptor chain is defined per {@link EndpointMapping} bean, sharing its granularity. To be able to
* apply a certain interceptor chain to a group of handlers, one needs to map the desired handlers via one
* <code>EndpointMapping</code> bean.The interceptors themselves are defined as beans in the application context,
* referenced by the mapping bean definition via its <code>interceptors</code> property (in XML: a &lt;list&gt; of
* &lt;ref&gt;).
*
* @author Arjen Poutsma
* @see EndpointInvocationChain#getInterceptors()
@@ -40,23 +41,57 @@ import org.springframework.ws.context.MessageContext;
public interface EndpointInterceptor {
/**
* Processes the incoming request message.
* Processes the incoming request message. Called after {@link EndpointMapping} determined an appropriate endpoint
* object, but before {@link EndpointAdapter} invokes the endpoint.
* <p/>
* {@link MessageDispatcher} processes an endpoint in an invocation chain, consisting of any number of interceptors,
* with the endpoint itself at the end. With this method, each interceptor can decide to abort the chain, typically
* creating a custom response.
*
* @param messageContext contains the incoming request message
* @param endpoint chosen endpoint to invoke
* @return <code>true</code> to continue processing of the request interceptor chain; <code>false</code> to indicate
* blocking of the request handler chain, <em>without invoking the endpoint</em>
* blocking of the request endpoint chain, <em>without invoking the endpoint</em>
* @throws Exception in case of errors
* @see org.springframework.ws.context.MessageContext#getRequest()
*/
boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception;
/**
* Processes the outgoing response message.
* Processes the outgoing response message. Called after {@link EndpointAdapter} actually invoked the endpoint. Can
* manipulate the response, if any, by adding new headers, etc.
* <p/>
* {@link MessageDispatcher} processes an endpoint in an invocation chain, consisting of any number of interceptors,
* with the endpoint itself at the end. With this method, each interceptor can post-process an invocation, getting
* applied in inverse order of the execution chain.
* <p/>
* Note: Will only be called if this interceptor's {@link #handleRequest} method has successfully completed.
*
* @param messageContext contains both request and response messages
* @param endpoint chosen endpoint to invoke
* @return <code>true</code> to continue processing of the reponse interceptor chain; <code>false</code> to indicate
* blocking of the response handler chain.
* blocking of the response endpoint chain.
* @throws Exception in case of errors
* @see org.springframework.ws.context.MessageContext#getRequest()
* @see org.springframework.ws.context.MessageContext#hasResponse()
* @see org.springframework.ws.context.MessageContext#getResponse()
*/
boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception;
/**
* Processes the outgoing response fault. Called after {@link EndpointAdapter} actually invoked the endpoint. Can
* manipulate the response, if any, by adding new headers, etc.
* <p/>
* {@link MessageDispatcher} processes an endpoint in an invocation chain, consisting of any number of interceptors,
* with the endpoint itself at the end. With this method, each interceptor can post-process an invocation, getting
* applied in inverse order of the execution chain.
* <p/>
* Note: Will only be called if this interceptor's {@link #handleRequest} method has successfully completed.
*
* @param messageContext contains both request and response messages, the response should contains a Fault
* @param endpoint chosen endpoint to invoke
* @return <code>true</code> to continue processing of the reponse interceptor chain; <code>false</code> to indicate
* blocking of the response handler chain.
*/
boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception;
}

View File

@@ -179,7 +179,7 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa
return;
}
// Apply handleRequest of registered interceptors
if (!ObjectUtils.isEmpty(mappedEndpoint.getInterceptors())) {
if (mappedEndpoint.getInterceptors() != null) {
for (int i = 0; i < mappedEndpoint.getInterceptors().length; i++) {
EndpointInterceptor interceptor = mappedEndpoint.getInterceptors()[i];
interceptorIndex = i;
@@ -303,15 +303,21 @@ public class MessageDispatcher implements WebServiceMessageReceiver, BeanNameAwa
* @param messageContext the message context, whose request and response are filled
* @see EndpointInterceptor#handleResponse(MessageContext,Object)
*/
protected void triggerHandleResponse(EndpointInvocationChain mappedEndpoint,
int interceptorIndex,
MessageContext messageContext) throws Exception {
private void triggerHandleResponse(EndpointInvocationChain mappedEndpoint,
int interceptorIndex,
MessageContext messageContext) throws Exception {
if (mappedEndpoint != null && messageContext.hasResponse() &&
!ObjectUtils.isEmpty(mappedEndpoint.getInterceptors())) {
boolean resume = true;
boolean hasFault = messageContext.getResponse().hasFault();
for (int i = interceptorIndex; resume && i >= 0; i--) {
EndpointInterceptor interceptor = mappedEndpoint.getInterceptors()[i];
resume = interceptor.handleResponse(messageContext, mappedEndpoint.getEndpoint());
if (!hasFault) {
resume = interceptor.handleResponse(messageContext, mappedEndpoint.getEndpoint());
}
else {
resume = interceptor.handleFault(messageContext, mappedEndpoint.getEndpoint());
}
}
}
}

View File

@@ -42,16 +42,12 @@ public abstract class AbstractLoggingInterceptor extends TransformerObjectSuppor
private boolean logResponse = true;
/**
* Indicates whether the request should be logged. Default is <code>true</code>.
*/
/** Indicates whether the request should be logged. Default is <code>true</code>. */
public final void setLogRequest(boolean logRequest) {
this.logRequest = logRequest;
}
/**
* Indicates whether the response should be logged. Default is <code>true</code>.
*/
/** Indicates whether the response should be logged. Default is <code>true</code>. */
public final void setLogResponse(boolean logResponse) {
this.logResponse = logResponse;
}
@@ -86,6 +82,11 @@ public abstract class AbstractLoggingInterceptor extends TransformerObjectSuppor
return true;
}
/** Does nothing by default. Faults are not logged. */
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
return true;
}
private Transformer createNonIndentingTransformer() throws TransformerConfigurationException {
Transformer transformer = createTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");

View File

@@ -111,6 +111,18 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup
this.validateResponse = validateResponse;
}
public void afterPropertiesSet() throws Exception {
Assert.notEmpty(schemas, "setting either the schema or schemas property is required");
Assert.hasLength(schemaLanguage, "schemaLanguage is required");
for (int i = 0; i < schemas.length; i++) {
Assert.isTrue(schemas[i].exists(), "schema [" + schemas[i] + "] does not exist");
}
if (logger.isInfoEnabled()) {
logger.info("Validating using " + StringUtils.arrayToCommaDelimitedString(schemas));
}
validator = XmlValidatorFactory.createValidator(schemas, schemaLanguage);
}
/**
* Validates the request message in the given message context. Validation only occurs if
* <code>validateRequest</code> is set to <code>true</code>, which is the default.
@@ -196,16 +208,9 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup
return false;
}
public void afterPropertiesSet() throws Exception {
Assert.notEmpty(schemas, "setting either the schema or schemas property is required");
Assert.hasLength(schemaLanguage, "schemaLanguage is required");
for (int i = 0; i < schemas.length; i++) {
Assert.isTrue(schemas[i].exists(), "schema [" + schemas[i] + "] does not exist");
}
if (logger.isInfoEnabled()) {
logger.info("Validating using " + StringUtils.arrayToCommaDelimitedString(schemas));
}
validator = XmlValidatorFactory.createValidator(schemas, schemaLanguage);
/** Does nothing by default. Faults are not validated. */
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
return true;
}
/**

View File

@@ -56,16 +56,12 @@ public class PayloadTransformingInterceptor implements EndpointInterceptor, Init
private Templates responseTemplates;
/**
* Sets the XSLT stylesheet to use for transforming incoming request.
*/
/** Sets the XSLT stylesheet to use for transforming incoming request. */
public void setRequestXslt(Resource requestXslt) {
this.requestXslt = requestXslt;
}
/**
* Sets the XSLT stylesheet to use for transforming outgoing responses.
*/
/** Sets the XSLT stylesheet to use for transforming outgoing responses. */
public void setResponseXslt(Resource responseXslt) {
this.responseXslt = responseXslt;
}
@@ -106,6 +102,11 @@ public class PayloadTransformingInterceptor implements EndpointInterceptor, Init
return true;
}
/** Does nothing by default. Faults are not transformed. */
public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
return true;
}
public void afterPropertiesSet() throws Exception {
if (requestXslt == null && responseXslt == null) {
throw new IllegalArgumentException("Setting either 'requestXslt' or 'responseXslt' is required");

View File

@@ -51,6 +51,13 @@ public interface SoapElement {
*/
void addAttribute(QName name, String value);
/**
* Removes the attribute with the specified name.
*
* @param name the qualified name of the attribute to remove
*/
void removeAttribute(QName name);
/**
* Returns the value of the attribute with the specified qualified name.
*
@@ -66,5 +73,4 @@ public interface SoapElement {
*/
Iterator getAllAttibutes();
}

View File

@@ -69,13 +69,4 @@ public interface SoapHeader extends SoapElement {
*/
Iterator examineAllHeaderElements() throws SoapHeaderException;
/**
* Returns an <code>Iterator</code> over all the <code>SoapHeaderElement</code>s with the specified header.
*
* @param name the qualified name of header elements to look for
* @return an iterator over all the header elements
* @throws SoapHeaderException if the header cannot be returned
* @see SoapHeaderElement
*/
Iterator examineHeaderElements(QName name) throws SoapHeaderException;
}

View File

@@ -59,9 +59,20 @@ public interface SoapHeaderElement extends SoapElement {
*/
void setMustUnderstand(boolean mustUnderstand) throws SoapHeaderException;
/**
* Returns a <code>Result</code> that allows for writing to the <strong>contents</strong> of the header element.
*/
/** Returns a <code>Result</code> that allows for writing to the <strong>contents</strong> of the header element. */
Result getResult() throws SoapHeaderException;
/**
* Returns the text content of this header element, if any.
*
* @return the text content of this header element
*/
String getText();
/**
* Sets the text content of this header element.
*
* @param content the new text content of this header element
*/
void setText(String content);
}

View File

@@ -79,6 +79,18 @@ class AxiomSoapElement implements SoapElement {
}
}
public void removeAttribute(QName name) {
try {
OMAttribute attribute = getAxiomElement().getAttribute(name);
if (attribute != null) {
getAxiomElement().removeAttribute(attribute);
}
}
catch (OMException ex) {
throw new AxiomSoapElementException(ex);
}
}
public final String getAttributeValue(QName name) {
try {
return getAxiomElement().getAttributeValue(name);

View File

@@ -57,6 +57,14 @@ class AxiomSoapHeaderElement extends AxiomSoapElement implements SoapHeaderEleme
}
public String getText() {
return getAxiomHeaderBlock().getText();
}
public void setText(String content) {
getAxiomHeaderBlock().setText(content);
}
protected SOAPHeaderBlock getAxiomHeaderBlock() {
return (SOAPHeaderBlock) getAxiomElement();
}

View File

@@ -81,11 +81,24 @@ public class Saaj11Implementation implements SaajImplementation {
return new SAXResult(new SaajContentHandler(element));
}
public String getText(SOAPElement element) {
return element.getValue();
}
public void setText(SOAPElement element, String content) throws SOAPException {
element.addTextNode(content);
}
public void addAttribute(SOAPElement element, QName name, String value) throws SOAPException {
Name attributeName = SaajUtils.toName(name, element);
element.addAttribute(attributeName, value);
}
public void removeAttribute(SOAPElement element, QName name) throws SOAPException {
Name attributeName = SaajUtils.toName(name, element);
element.removeAttribute(attributeName);
}
public String getAttributeValue(SOAPElement element, QName name) throws SOAPException {
Name attributeName = SaajUtils.toName(name, element);
return element.getAttributeValue(attributeName);
@@ -100,11 +113,6 @@ public class Saaj11Implementation implements SaajImplementation {
return results.iterator();
}
public Iterator getChildElements(SOAPElement element, QName name) throws SOAPException {
Name childName = SaajUtils.toName(name, element);
return element.getChildElements(childName);
}
public QName getFaultCode(SOAPFault fault) {
String code = fault.getFaultCode();
int idx = code.indexOf(':');

View File

@@ -109,6 +109,11 @@ public class Saaj12Implementation implements SaajImplementation {
element.addAttribute(attributeName, value);
}
public void removeAttribute(SOAPElement element, QName name) throws SOAPException {
Name attributeName = SaajUtils.toName(name, element);
element.removeAttribute(attributeName);
}
public String getAttributeValue(SOAPElement element, QName name) throws SOAPException {
Name attributeName = SaajUtils.toName(name, element);
return element.getAttributeValue(attributeName);
@@ -123,9 +128,12 @@ public class Saaj12Implementation implements SaajImplementation {
return results.iterator();
}
public Iterator getChildElements(SOAPElement element, QName name) throws SOAPException {
Name childName = SaajUtils.toName(name, element);
return element.getChildElements(childName);
public String getText(SOAPElement element) {
return element.getValue();
}
public void setText(SOAPElement element, String content) {
element.setValue(content);
}
public SOAPEnvelope getEnvelope(SOAPMessage message) throws SOAPException {

View File

@@ -139,10 +139,22 @@ public class Saaj13Implementation implements SaajImplementation {
return new DOMResult(element);
}
public String getText(SOAPElement element) {
return element.getValue();
}
public void setText(SOAPElement element, String content) {
element.setValue(content);
}
public void addAttribute(SOAPElement element, QName name, String value) throws SOAPException {
element.addAttribute(name, value);
}
public void removeAttribute(SOAPElement element, QName name) throws SOAPException {
element.removeAttribute(name);
}
public String getAttributeValue(SOAPElement element, QName name) throws SOAPException {
return element.getAttributeValue(name);
}
@@ -151,10 +163,6 @@ public class Saaj13Implementation implements SaajImplementation {
return element.getAllAttributesAsQNames();
}
public Iterator getChildElements(SOAPElement element, QName name) throws SOAPException {
return element.getChildElements(name);
}
public SOAPEnvelope getEnvelope(SOAPMessage message) throws SOAPException {
return message.getSOAPPart().getEnvelope();
}

View File

@@ -53,18 +53,24 @@ public interface SaajImplementation {
/** Returns the writable <code>Result</code> of the given element. */
Result getResult(SOAPElement element);
/** Returns the text of the given element */
String getText(SOAPElement element);
/** Returns the text of the given element */
void setText(SOAPElement element, String content) throws SOAPException;
/** Adds an attribute to the specified element. */
void addAttribute(SOAPElement element, QName name, String value) throws SOAPException;
/** Removes an attribute from the specified element. */
void removeAttribute(SOAPElement element, QName name) throws SOAPException;
/** Returns the attribute value * */
String getAttributeValue(SOAPElement element, QName name) throws SOAPException;
/** Returns all attributes as an iterator of QNames. * */
Iterator getAllAttibutes(SOAPElement element);
/** Returns an iterator over the child elements with the given name. */
Iterator getChildElements(SOAPElement element, QName name) throws SOAPException;
/** Returns the envelope of the given message. */
SOAPEnvelope getEnvelope(SOAPMessage message) throws SOAPException;

View File

@@ -57,6 +57,15 @@ class SaajSoapElement implements SoapElement {
}
}
public void removeAttribute(QName name) {
try {
getImplementation().removeAttribute(element, name);
}
catch (SOAPException ex) {
throw new SaajSoapElementException(ex);
}
}
public String getAttributeValue(QName name) {
try {
return getImplementation().getAttributeValue(element, name);

View File

@@ -44,16 +44,6 @@ class SaajSoapHeader extends SaajSoapElement implements SoapHeader {
return new SaajSoapHeaderElementIterator(iterator);
}
public Iterator examineHeaderElements(QName name) throws SoapHeaderException {
try {
Iterator iterator = getImplementation().getChildElements(getSaajHeader(), name);
return new SaajSoapHeaderElementIterator(iterator);
}
catch (SOAPException ex) {
throw new SaajSoapHeaderException(ex);
}
}
public Iterator examineMustUnderstandHeaderElements(String actorOrRole) throws SoapHeaderException {
Iterator iterator = getImplementation().examineMustUnderstandHeaderElements(getSaajHeader(), actorOrRole);
return new SaajSoapHeaderElementIterator(iterator);

View File

@@ -16,6 +16,7 @@
package org.springframework.ws.soap.saaj;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.transform.Result;
@@ -54,6 +55,19 @@ class SaajSoapHeaderElement extends SaajSoapElement implements SoapHeaderElement
getImplementation().setMustUnderstand(getSaajHeaderElement(), mustUnderstand);
}
public String getText() {
return getImplementation().getText(getSaajHeaderElement());
}
public void setText(String content) {
try {
getImplementation().setText(getSaajHeaderElement(), content);
}
catch (SOAPException ex) {
throw new SaajSoapHeaderException(ex);
}
}
protected SOAPHeaderElement getSaajHeaderElement() {
return (SOAPHeaderElement) getSaajElement();
}

View File

@@ -14,10 +14,10 @@
* limitations under the License.
*/
package org.springframework.ws.soap;
package org.springframework.ws.soap.server;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.soap.SoapHeaderElement;
/**
* SOAP-specific extension of the <code>EndpointInterceptor</code> interface. Allows for handling of SOAP faults, which
@@ -27,17 +27,6 @@ import org.springframework.ws.server.EndpointInterceptor;
*/
public interface SoapEndpointInterceptor extends EndpointInterceptor {
/**
* Processes the fault. Both request and response of the message context should be filled; the body of the response
* message contains the fault.
*
* @param messageContext contains both request and response messages, the response should contains a SOAP Fault
* @param endpoint chosen endpoint to invoke
* @return <code>true</code> to continue processing of the reponse interceptor chain; <code>false</code> to indicate
* blocking of the response handler chain.
*/
boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception;
/**
* Given a <code>SoapHeaderElement</code>, return whether or not this <code>SoapEndpointInterceptor</code>
* understands it.

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.springframework.ws.soap;
package org.springframework.ws.soap.server;
import org.springframework.ws.server.EndpointMapping;
@@ -30,14 +30,10 @@ import org.springframework.ws.server.EndpointMapping;
*/
public interface SoapEndpointMapping extends EndpointMapping {
/**
* Sets a single SOAP actor/actorOrRole to apply to all endpoints mapped by the delegate endpoint mapping.
*/
/** Sets a single SOAP actor/actorOrRole to apply to all endpoints mapped by the delegate endpoint mapping. */
void setActorOrRole(String actorOrRole);
/**
* Sets the array of SOAP actors/actorsOrRoles to apply to all endpoints mapped by the delegate endpoint mapping.
*/
/** Sets the array of SOAP actors/actorsOrRoles to apply to all endpoints mapped by the delegate endpoint mapping. */
void setActorsOrRoles(String[] actorsOrRoles);
}

View File

@@ -22,14 +22,12 @@ 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;
import org.springframework.ws.server.EndpointInvocationChain;
import org.springframework.ws.server.MessageDispatcher;
import org.springframework.ws.soap.SoapBody;
import org.springframework.ws.soap.SoapEndpointInterceptor;
import org.springframework.ws.soap.SoapFault;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapHeaderElement;
@@ -43,13 +41,11 @@ import org.springframework.ws.soap.soap12.Soap12Header;
*
* @author Arjen Poutsma
* @see org.springframework.ws.soap.SoapMessage
* @see org.springframework.ws.soap.SoapEndpointInterceptor
* @see SoapEndpointInterceptor
*/
public class SoapMessageDispatcher extends MessageDispatcher {
/**
* Default message used when creating a SOAP MustUnderstand fault.
*/
/** Default message used when creating a SOAP MustUnderstand fault. */
public static final String DEFAULT_MUST_UNDERSTAND_FAULT =
"One or more mandatory SOAP header blocks not understood";
@@ -130,7 +126,7 @@ public class SoapMessageDispatcher extends MessageDispatcher {
* <code>SoapEndpointInterceptor</code>. If they are, returns <code>true</code>. If they are not, a SOAP fault is
* created, and false is returned.
*
* @see org.springframework.ws.soap.SoapEndpointInterceptor#understands(org.springframework.ws.soap.SoapHeaderElement)
* @see SoapEndpointInterceptor#understands(org.springframework.ws.soap.SoapHeaderElement)
*/
private boolean handleRequestForRole(EndpointInvocationChain mappedEndpoint,
MessageContext messageContext,
@@ -180,41 +176,4 @@ public class SoapMessageDispatcher extends MessageDispatcher {
return false;
}
}
/**
* Trigger handleResponse or handleFault on the mapped EndpointInterceptors. Will just invoke said method on all
* interceptors whose handleRequest invocation returned <code>true</code>, in addition to the last interceptor who
* returned <code>false</code>.
*
* @param mappedEndpoint the mapped EndpointInvocationChain
* @param interceptorIndex index of last interceptor that was called
* @param messageContext the message context, whose request and response are filled
* @see org.springframework.ws.server.EndpointInterceptor#handleResponse(org.springframework.ws.context.MessageContext,
*Object)
*/
protected void triggerHandleResponse(EndpointInvocationChain mappedEndpoint,
int interceptorIndex,
MessageContext messageContext) throws Exception {
if (mappedEndpoint != null && messageContext.hasResponse() &&
!ObjectUtils.isEmpty(mappedEndpoint.getInterceptors())) {
boolean hasFault = false;
if (messageContext.getResponse() instanceof SoapMessage) {
SoapMessage soapResponse = (SoapMessage) messageContext.getResponse();
hasFault = soapResponse.getSoapBody().hasFault();
}
boolean resume = true;
for (int i = interceptorIndex; resume && i >= 0; i--) {
EndpointInterceptor interceptor = mappedEndpoint.getInterceptors()[i];
if (hasFault) {
if (interceptor instanceof SoapEndpointInterceptor) {
SoapEndpointInterceptor soapEndpointInterceptor = (SoapEndpointInterceptor) interceptor;
resume = soapEndpointInterceptor.handleFault(messageContext, mappedEndpoint.getEndpoint());
}
}
else {
resume = interceptor.handleResponse(messageContext, mappedEndpoint.getEndpoint());
}
}
}
}
}

View File

@@ -21,9 +21,9 @@ import javax.xml.transform.Source;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.AbstractLoggingInterceptor;
import org.springframework.ws.soap.SoapEndpointInterceptor;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.server.SoapEndpointInterceptor;
/**
* SOAP-specific <code>EndpointInterceptor</code> that logs the complete request and response envelope of
@@ -39,9 +39,7 @@ public class SoapEnvelopeLoggingInterceptor extends AbstractLoggingInterceptor i
private boolean logFault = true;
/**
* Indicates whether a SOAP Fault should be logged. Default is <code>true</code>.
*/
/** Indicates whether a SOAP Fault should be logged. Default is <code>true</code>. */
public void setLogFault(boolean logFault) {
this.logFault = logFault;
}

View File

@@ -21,8 +21,8 @@ import org.springframework.util.Assert;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInvocationChain;
import org.springframework.ws.server.EndpointMapping;
import org.springframework.ws.soap.SoapEndpointMapping;
import org.springframework.ws.soap.server.SoapEndpointInvocationChain;
import org.springframework.ws.soap.server.SoapEndpointMapping;
/**
* <code>EndpointMapping</code> implement that adds SOAP actors or roles to a delegate endpoint. Delegates to another
@@ -46,9 +46,7 @@ public class DelegatingSoapEndpointMapping implements InitializingBean, SoapEndp
private String[] actorsOrRoles;
/**
* Sets the delegate <code>EndpointMapping</code> to resolve the endpoint with.
*/
/** Sets the delegate <code>EndpointMapping</code> to resolve the endpoint with. */
public void setDelegate(EndpointMapping delegate) {
this.delegate = delegate;
}

View File

@@ -22,10 +22,10 @@ import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.server.EndpointInvocationChain;
import org.springframework.ws.server.endpoint.mapping.AbstractMapBasedEndpointMapping;
import org.springframework.ws.soap.SoapEndpointMapping;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
import org.springframework.ws.soap.server.SoapEndpointInvocationChain;
import org.springframework.ws.soap.server.SoapEndpointMapping;
/**
* Implementation of the <code>EndpointMapping</code> interface to map from <code>SOAPAction</code> headers to endpoint

View File

@@ -307,6 +307,47 @@ public class MessageDispatcherTest extends TestCase {
factoryControl.verify();
}
public void testFaultFlow() throws Exception {
MockControl adapterControl = MockControl.createControl(EndpointAdapter.class);
EndpointAdapter adapterMock = (EndpointAdapter) adapterControl.getMock();
dispatcher.setEndpointAdapters(Collections.singletonList(adapterMock));
Object endpoint = new Object();
adapterControl.expectAndReturn(adapterMock.supports(endpoint), true);
MockControl mappingControl = MockControl.createControl(EndpointMapping.class);
EndpointMapping mappingMock = (EndpointMapping) mappingControl.getMock();
dispatcher.setEndpointMappings(Collections.singletonList(mappingMock));
MockControl interceptorControl = MockControl.createStrictControl(EndpointInterceptor.class);
EndpointInterceptor interceptorMock = (EndpointInterceptor) interceptorControl.getMock();
interceptorControl.expectAndReturn(interceptorMock.handleRequest(messageContext, endpoint), true);
adapterMock.invoke(messageContext, endpoint);
interceptorControl.expectAndReturn(interceptorMock.handleFault(messageContext, endpoint), true);
EndpointInvocationChain chain =
new EndpointInvocationChain(endpoint, new EndpointInterceptor[]{interceptorMock});
mappingControl.expectAndReturn(mappingMock.getEndpoint(messageContext), chain);
MockWebServiceMessage response = new MockWebServiceMessage();
response.setFault(true);
factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), response);
mappingControl.replay();
interceptorControl.replay();
adapterControl.replay();
factoryControl.replay();
// response required for interceptor invocation
messageContext.getResponse();
dispatcher.dispatch(messageContext);
mappingControl.verify();
interceptorControl.verify();
adapterControl.verify();
factoryControl.verify();
}
public void testNoEndpointFound() throws Exception {
dispatcher.setEndpointMappings(Collections.EMPTY_LIST);
try {

View File

@@ -94,17 +94,6 @@ public abstract class AbstractSoapHeaderTestCase extends AbstractSoapElementTest
assertHeaderElementEqual(headerElement, content);
}
public void testExamineHeaderElements() throws Exception {
QName qName = new QName("http://www.springframework.org", "localName", "spring");
soapHeader.addHeaderElement(qName);
Iterator iterator = soapHeader.examineHeaderElements(qName);
assertNotNull("No Iterator returned", iterator);
assertTrue("header element iterator has no elements", iterator.hasNext());
SoapHeaderElement headerElement = (SoapHeaderElement) iterator.next();
assertNotNull("No SoapHeaderElement returned", headerElement);
assertEquals("Invalid qName for element", qName, headerElement.getName());
}
protected void assertHeaderElementEqual(SoapHeaderElement headerElement, String expected) throws Exception {
StringResult result = new StringResult();
transformer.transform(headerElement.getSource(), result);

View File

@@ -29,7 +29,6 @@ import org.easymock.MockControl;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.SoapBody;
import org.springframework.ws.soap.SoapEndpointInterceptor;
import org.springframework.ws.soap.SoapHeader;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.ws.soap.SoapMessage;

View File

@@ -24,9 +24,9 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.util.Assert;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.SoapBody;
import org.springframework.ws.soap.SoapEndpointInterceptor;
import org.springframework.ws.soap.SoapHeaderElement;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.server.SoapEndpointInterceptor;
/**
* Interceptor base class for interceptors that handle WS-Security.

View File

@@ -6,6 +6,9 @@
</properties>
<body>
<release version="1.0-RC1">
<action dev="poutsma" type="add">Pulled handleFault() from SoapEndpointInterceptor up to
EndpointInterceptor
</action>
<action dev="poutsma" type="fix" issue="SWS-119">Remove IOExceptions from WebServiceTemplate. A runtime
exception hierarchy has been created in org.springframework.ws.client.
</action>

View File

@@ -19,6 +19,16 @@ Upgrading from version 1.0-M3 to 1.0-RC1
The <<<WebServiceTemplate>> no longer declares an IOException for each method. Rather, an runtime exception
hierarchy has been created in <<<org.springframework.ws.client>>>.
* EndpointInterceptor
The <<<EndpointInterceptor>>> has a <<<handleFault>>> method now, which gets invoked
(rather than <<<handleResponse>>>) when <<<WebServiceMessage.hasFault()>>> is true for the response.
* SoapMessageDispatcher
* All of SoapMessageDispatcher's strategy interfaces (<<<SoapEndpointInterceptor>>>, <<<SoapEndpointMapping>>>)
have been moved from <<<org.springframework.ws.soap>>> to <<<org.springframework.ws.soap.server>>>.
Upgrading from version 1.0-M2 to 1.0-M3
@@ -42,9 +52,9 @@ the project update their applications:
To make a clear distinction between server-side and client-side code, we had to move the various server-side classes.
* The <<<MessageDispatcher>>> has been moved to the <<<EndpointInvocationChain>>> to <<<org.springframework.ws.server>>> package.
* The <<<MessageDispatcher>>> has been moved to the <<<org.springframework.ws.server>>> package.
* The <<<SoapMessageDispatcher>>> has been moved to the EndpointInvocationChain to <<<org.springframework.ws.soap.server>>> package.
* The <<<SoapMessageDispatcher>>> has been moved to the <<<org.springframework.ws.soap.server>>> package.
* All of MessageDispatcher's strategy interfaces (<<<EndpointAdapter>>>, <<<EndpointInterceptor>>>, <<<EndpointMapping>>>, <<<EndpointExceptionResolver>>>) have been moved from <<<org.springframework.ws>>> to <<<org.springframework.ws.server>>>.

View File

@@ -46,12 +46,12 @@ public abstract class XPathExpressionFactory {
static {
// Check whether JAXP 1.3, or Jaxen are available
if (JaxpVersion.getJaxpVersion() >= JaxpVersion.JAXP_13) {
logger.info("JAXP 1.3 available");
logger.debug("JAXP 1.3 available");
}
try {
ClassUtils.forName(JAXEN_CLASS_NAME);
jaxenAvailable = true;
logger.info("Jaxen available");
logger.debug("Jaxen available");
}
catch (ClassNotFoundException ex) {
jaxenAvailable = false;