From 57e49441af263ccb98e98fd42c74655f04c379c3 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Fri, 18 Jul 2008 08:47:48 +0000 Subject: [PATCH] SWS-391 --- .../ws/WebServiceException.java | 4 +- .../AbstractValidatingInterceptor.java | 275 ++++++++++++++++++ .../PayloadValidatingInterceptor.java | 63 ++++ .../WebServiceValidationException.java | 41 +++ .../client/support/interceptor/package.html | 2 +- .../PayloadValidatingInterceptorTest.java | 248 ++++++++++++++++ .../support/interceptor/invalidMessage.xml | 4 + .../support/interceptor/productSchema.xsd | 18 ++ .../ws/client/support/interceptor/schema.xsd | 22 ++ .../ws/client/support/interceptor/schema2.xsd | 32 ++ .../client/support/interceptor/sizeSchema.xsd | 12 + .../support/interceptor/validMessage.xml | 5 + .../support/interceptor/validSoapMessage.xml | 12 + 13 files changed, 734 insertions(+), 4 deletions(-) create mode 100644 core/src/main/java/org/springframework/ws/client/support/interceptor/AbstractValidatingInterceptor.java create mode 100644 core/src/main/java/org/springframework/ws/client/support/interceptor/PayloadValidatingInterceptor.java create mode 100644 core/src/main/java/org/springframework/ws/client/support/interceptor/WebServiceValidationException.java create mode 100644 core/src/test/java/org/springframework/ws/client/support/interceptor/PayloadValidatingInterceptorTest.java create mode 100644 core/src/test/resources/org/springframework/ws/client/support/interceptor/invalidMessage.xml create mode 100644 core/src/test/resources/org/springframework/ws/client/support/interceptor/productSchema.xsd create mode 100644 core/src/test/resources/org/springframework/ws/client/support/interceptor/schema.xsd create mode 100644 core/src/test/resources/org/springframework/ws/client/support/interceptor/schema2.xsd create mode 100644 core/src/test/resources/org/springframework/ws/client/support/interceptor/sizeSchema.xsd create mode 100644 core/src/test/resources/org/springframework/ws/client/support/interceptor/validMessage.xml create mode 100644 core/src/test/resources/org/springframework/ws/client/support/interceptor/validSoapMessage.xml diff --git a/core/src/main/java/org/springframework/ws/WebServiceException.java b/core/src/main/java/org/springframework/ws/WebServiceException.java index 703c8d44..d2c96455 100644 --- a/core/src/main/java/org/springframework/ws/WebServiceException.java +++ b/core/src/main/java/org/springframework/ws/WebServiceException.java @@ -16,8 +16,6 @@ package org.springframework.ws; -import java.io.Serializable; - import org.springframework.core.NestedRuntimeException; /** @@ -26,7 +24,7 @@ import org.springframework.core.NestedRuntimeException; * @author Arjen Poutsma * @since 1.0.0 */ -public abstract class WebServiceException extends NestedRuntimeException implements Serializable { +public abstract class WebServiceException extends NestedRuntimeException { /** * Create a new instance of the WebServiceException class. diff --git a/core/src/main/java/org/springframework/ws/client/support/interceptor/AbstractValidatingInterceptor.java b/core/src/main/java/org/springframework/ws/client/support/interceptor/AbstractValidatingInterceptor.java new file mode 100644 index 00000000..7269a0b1 --- /dev/null +++ b/core/src/main/java/org/springframework/ws/client/support/interceptor/AbstractValidatingInterceptor.java @@ -0,0 +1,275 @@ +/* + * Copyright 2008 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.client.support.interceptor; + +import java.io.IOException; +import javax.xml.transform.Source; + +import org.xml.sax.SAXParseException; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.Resource; +import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; +import org.springframework.util.StringUtils; +import org.springframework.ws.WebServiceMessage; +import org.springframework.ws.client.WebServiceClientException; +import org.springframework.ws.client.WebServiceIOException; +import org.springframework.ws.context.MessageContext; +import org.springframework.xml.transform.TransformerObjectSupport; +import org.springframework.xml.validation.XmlValidator; +import org.springframework.xml.validation.XmlValidatorFactory; +import org.springframework.xml.xsd.XsdSchema; +import org.springframework.xml.xsd.XsdSchemaCollection; + +/** + * Abstract base class for {@link ClientInterceptor} implementations that validate part of the message using a schema. + * The exact message part is determined by the {@link #getValidationRequestSource(WebServiceMessage)} and {@link + * #getValidationResponseSource(WebServiceMessage)} template methods. + *

+ * By default, only the request message is validated, but this behaviour can be changed using the + * validateRequest and validateResponse properties. + * + * @author Arjen Poutsma + * @see #getValidationRequestSource(WebServiceMessage) + * @see #getValidationResponseSource(WebServiceMessage) + * @since 1.5.4 + */ +public abstract class AbstractValidatingInterceptor extends TransformerObjectSupport + implements ClientInterceptor, InitializingBean { + + private String schemaLanguage = XmlValidatorFactory.SCHEMA_W3C_XML; + + private Resource[] schemas; + + private boolean validateRequest = true; + + private boolean validateResponse = false; + + private XmlValidator validator; + + public String getSchemaLanguage() { + return schemaLanguage; + } + + /** + * Sets the schema language. Default is the W3C XML Schema: http://www.w3.org/2001/XMLSchema". + * + * @see XmlValidatorFactory#SCHEMA_W3C_XML + * @see XmlValidatorFactory#SCHEMA_RELAX_NG + */ + public void setSchemaLanguage(String schemaLanguage) { + this.schemaLanguage = schemaLanguage; + } + + /** Returns the schema resources to use for validation. */ + public Resource[] getSchemas() { + return schemas; + } + + /** + * Sets the schema resource to use for validation. Setting this property, {@link + * #setXsdSchemaCollection(XsdSchemaCollection) xsdSchemaCollection}, {@link #setSchema(Resource) schema}, or {@link + * #setSchemas(Resource[]) schemas} is required. + */ + public void setSchema(Resource schema) { + setSchemas(new Resource[]{schema}); + } + + /** + * Sets the schema resources to use for validation. Setting this property, {@link + * #setXsdSchemaCollection(XsdSchemaCollection) xsdSchemaCollection}, {@link #setSchema(Resource) schema}, or {@link + * #setSchemas(Resource[]) schemas} is required. + */ + public void setSchemas(Resource[] schemas) { + Assert.notEmpty(schemas, "schemas must not be empty or null"); + for (int i = 0; i < schemas.length; i++) { + Assert.notNull(schemas[i], "schema must not be null"); + Assert.isTrue(schemas[i].exists(), "schema \"" + schemas[i] + "\" does not exit"); + } + this.schemas = schemas; + } + + /** + * Sets the {@link XsdSchema} to use for validation. Setting this property, {@link + * #setXsdSchemaCollection(XsdSchemaCollection) xsdSchemaCollection}, {@link #setSchema(Resource) schema}, or {@link + * #setSchemas(Resource[]) schemas} is required. + * + * @param schema the xsd schema to use + * @throws java.io.IOException in case of I/O errors + */ + public void setXsdSchema(XsdSchema schema) throws IOException { + this.validator = schema.createValidator(); + } + + /** + * Sets the {@link XsdSchemaCollection} to use for validation. Setting this property, {@link + * #setXsdSchema(XsdSchema) xsdSchema}, {@link #setSchema(Resource) schema}, or {@link #setSchemas(Resource[]) + * schemas} is required. + * + * @param schemaCollection the xsd schema collection to use + * @throws java.io.IOException in case of I/O errors + */ + public void setXsdSchemaCollection(XsdSchemaCollection schemaCollection) throws IOException { + this.validator = schemaCollection.createValidator(); + } + + /** Indicates whether the request should be validated against the schema. Default is true. */ + public void setValidateRequest(boolean validateRequest) { + this.validateRequest = validateRequest; + } + + /** Indicates whether the response should be validated against the schema. Default is false. */ + public void setValidateResponse(boolean validateResponse) { + this.validateResponse = validateResponse; + } + + public void afterPropertiesSet() throws Exception { + if (validator == null && !ObjectUtils.isEmpty(schemas)) { + 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); + } + Assert.notNull(validator, "Setting 'schema', 'schemas', 'xsdSchema', or 'xsdSchemaCollection' is required"); + } + + /** + * Validates the request message in the given message context. Validation only occurs if {@link + * #setValidateRequest(boolean) validateRequest} is set to true, which is the default. + *

+ * Returns true if the request is valid, or false if it isn't. + * + * @param messageContext the message context + * @return true if the message is valid; false otherwise + * @see #setValidateRequest(boolean) + */ + public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException { + if (validateRequest) { + Source requestSource = getValidationRequestSource(messageContext.getRequest()); + if (requestSource != null) { + SAXParseException[] errors; + try { + errors = validator.validate(requestSource); + } + catch (IOException e) { + throw new WebServiceIOException("Could not validate response: " + e.getMessage(), e); + } + if (!ObjectUtils.isEmpty(errors)) { + return handleRequestValidationErrors(messageContext, errors); + } + else if (logger.isDebugEnabled()) { + logger.debug("Request message validated"); + } + } + } + return true; + } + + /** + * Template method that is called when the request message contains validation errors. + *

+ * Default implementation logs all errors, and throws a {@link WebServiceValidationException}. Subclasses can + * override this method to customize this behavior. + * + * @param messageContext the message context + * @param errors the validation errors + * @return true to continue processing the request, false otherwise + */ + protected boolean handleRequestValidationErrors(MessageContext messageContext, SAXParseException[] errors) { + for (int i = 0; i < errors.length; i++) { + logger.error("XML validation error on request: " + errors[i].getMessage()); + } + throw new WebServiceValidationException(errors); + } + + /** + * Validates the response message in the given message context. Validation only occurs if {@link + * #setValidateResponse(boolean) validateResponse} is set to true, which is not the + * default. + *

+ * Returns true if the request is valid, or false if it isn't. + * + * @param messageContext the message context. + * @return true if the response is valid; false otherwise + * @see #setValidateResponse(boolean) + */ + public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException { + if (validateResponse) { + Source responseSource = getValidationResponseSource(messageContext.getResponse()); + if (responseSource != null) { + SAXParseException[] errors; + try { + errors = validator.validate(responseSource); + } + catch (IOException e) { + throw new WebServiceIOException("Could not validate response: " + e.getMessage(), e); + } + if (!ObjectUtils.isEmpty(errors)) { + return handleResponseValidationErrors(messageContext, errors); + } + else if (logger.isDebugEnabled()) { + logger.debug("Response message validated"); + } + } + } + return true; + } + + /** + * Template method that is called when the response message contains validation errors. + *

+ * Default implementation logs all errors, and returns false, i.e. do not cot continue to process the + * respone interceptor chain. + * + * @param messageContext the message context + * @param errors the validation errors + * @return true to continue the reponse interceptor chain, false (the default) otherwise + */ + protected boolean handleResponseValidationErrors(MessageContext messageContext, SAXParseException[] errors) + throws WebServiceValidationException { + for (int i = 0; i < errors.length; i++) { + logger.warn("XML validation error on response: " + errors[i].getMessage()); + } + return false; + } + + /** Does nothing by default. Faults are not validated. */ + public boolean handleFault(MessageContext messageContext) throws WebServiceClientException { + return true; + } + + /** + * Abstract template method that returns the part of the request message that is to be validated. + * + * @param request the request message + * @return the part of the message that is to validated, or null not to validate anything + */ + protected abstract Source getValidationRequestSource(WebServiceMessage request); + + /** + * Abstract template method that returns the part of the response message that is to be validated. + * + * @param response the response message + * @return the part of the message that is to validated, or null not to validate anything + */ + protected abstract Source getValidationResponseSource(WebServiceMessage response); +} diff --git a/core/src/main/java/org/springframework/ws/client/support/interceptor/PayloadValidatingInterceptor.java b/core/src/main/java/org/springframework/ws/client/support/interceptor/PayloadValidatingInterceptor.java new file mode 100644 index 00000000..65662832 --- /dev/null +++ b/core/src/main/java/org/springframework/ws/client/support/interceptor/PayloadValidatingInterceptor.java @@ -0,0 +1,63 @@ +/* + * Copyright 2006 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.client.support.interceptor; + +import javax.xml.transform.Source; + +import org.springframework.ws.WebServiceMessage; + +/** + * Client-side interceptor that validates the contents of WebServiceMessages using a schema. Allows for + * both W3C XML and RELAX NG schemas. + *

+ * When the payload is invalid, this interceptor stops processing of the interceptor chain. + *

+ * The schema to validate against is set with the schema property or schemas property. By + * default, only the request message is validated, but this behaviour can be changed using the + * validateRequest and validateResponse properties. Responses that contains faults are not + * validated. + * + * @author Stefan Schmidt + * @author Arjen Poutsma + * @see #setSchema(org.springframework.core.io.Resource) + * @see #setSchemas(org.springframework.core.io.Resource[]) + * @see #setValidateRequest(boolean) + * @see #setValidateResponse(boolean) + * @since 1.5.4 + */ +public class PayloadValidatingInterceptor extends AbstractValidatingInterceptor { + + /** + * Returns the part of the request message that is to be validated. Default + * + * @param request the request message + * @return the part of the message that is to validated, or null not to validate anything + */ + protected Source getValidationRequestSource(WebServiceMessage request) { + return request.getPayloadSource(); + } + + /** + * Returns the part of the response message that is to be validated. + * + * @param response the response message + * @return the part of the message that is to validated, or null not to validate anything + */ + protected Source getValidationResponseSource(WebServiceMessage response) { + return response.getPayloadSource(); + } +} diff --git a/core/src/main/java/org/springframework/ws/client/support/interceptor/WebServiceValidationException.java b/core/src/main/java/org/springframework/ws/client/support/interceptor/WebServiceValidationException.java new file mode 100644 index 00000000..1a27626d --- /dev/null +++ b/core/src/main/java/org/springframework/ws/client/support/interceptor/WebServiceValidationException.java @@ -0,0 +1,41 @@ +package org.springframework.ws.client.support.interceptor; + +import org.xml.sax.SAXParseException; + +import org.springframework.ws.client.WebServiceClientException; + +/** + * Exception thrown whenever a validation error occurs on the client-side. + * + * @author Stefan Schmidt + * @author Arjen Poutsma + * @since 1.5.4 + */ +public class WebServiceValidationException extends WebServiceClientException { + + private SAXParseException[] validationErrors; + + /** + * Create a new instance of the WebServiceValidationException class. + * + * @param msg the detail message + */ + public WebServiceValidationException(SAXParseException[] validationErrors) { + super(createMessage(validationErrors)); + this.validationErrors = validationErrors; + } + + private static String createMessage(SAXParseException[] validationErrors) { + StringBuffer buffer = new StringBuffer("XML validation error on response: "); + + for (int i = 0; i < validationErrors.length; i++) { + buffer.append(validationErrors[i].getMessage()); + } + return buffer.toString(); + } + + /** Returns the validation errors. */ + public SAXParseException[] getValidationErrors() { + return validationErrors; + } +} diff --git a/core/src/main/java/org/springframework/ws/client/support/interceptor/package.html b/core/src/main/java/org/springframework/ws/client/support/interceptor/package.html index 11d590a6..56c1c49e 100644 --- a/core/src/main/java/org/springframework/ws/client/support/interceptor/package.html +++ b/core/src/main/java/org/springframework/ws/client/support/interceptor/package.html @@ -1,5 +1,5 @@ -Provides the ClientInterceptor interface. +Provides the ClientInterceptor interface, and validating interceptors. diff --git a/core/src/test/java/org/springframework/ws/client/support/interceptor/PayloadValidatingInterceptorTest.java b/core/src/test/java/org/springframework/ws/client/support/interceptor/PayloadValidatingInterceptorTest.java new file mode 100644 index 00000000..ab92ca27 --- /dev/null +++ b/core/src/test/java/org/springframework/ws/client/support/interceptor/PayloadValidatingInterceptorTest.java @@ -0,0 +1,248 @@ +/* + * Copyright 2006 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.client.support.interceptor; + +import java.io.InputStream; +import javax.xml.XMLConstants; +import javax.xml.soap.MessageFactory; +import javax.xml.soap.SOAPConstants; +import javax.xml.soap.SOAPMessage; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamSource; + +import org.custommonkey.xmlunit.XMLTestCase; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.ws.MockWebServiceMessage; +import org.springframework.ws.MockWebServiceMessageFactory; +import org.springframework.ws.client.WebServiceClientException; +import org.springframework.ws.context.DefaultMessageContext; +import org.springframework.ws.context.MessageContext; +import org.springframework.ws.soap.SoapMessage; +import org.springframework.ws.soap.saaj.SaajSoapMessage; +import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; +import org.springframework.ws.soap.saaj.support.SaajUtils; +import org.springframework.xml.xsd.SimpleXsdSchema; + +public class PayloadValidatingInterceptorTest extends XMLTestCase { + + private PayloadValidatingInterceptor interceptor; + + private MessageContext context; + + private SaajSoapMessageFactory soap11Factory; + + private Transformer transformer; + + private static final String INVALID_MESSAGE = "invalidMessage.xml"; + + private static final String SCHEMA = "schema.xsd"; + + private static final String VALID_MESSAGE = "validMessage.xml"; + + private static final String PRODUCT_SCHEMA = "productSchema.xsd"; + + private static final String SIZE_SCHEMA = "sizeSchema.xsd"; + + private static final String VALID_SOAP_MESSAGE = "validSoapMessage.xml"; + + private static final String SCHEMA2 = "schema2.xsd"; + + protected void setUp() throws Exception { + interceptor = new PayloadValidatingInterceptor(); + interceptor.setSchema(new ClassPathResource(SCHEMA, getClass())); + interceptor.setValidateRequest(true); + interceptor.setValidateResponse(true); + interceptor.afterPropertiesSet(); + + soap11Factory = new SaajSoapMessageFactory(MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL)); + + transformer = TransformerFactory.newInstance().newTransformer(); + } + + public void testHandleInvalidRequest() throws Exception { + SoapMessage invalidMessage = (SoapMessage) soap11Factory.createWebServiceMessage(); + InputStream inputStream = getClass().getResourceAsStream(INVALID_MESSAGE); + transformer.transform(new StreamSource(inputStream), invalidMessage.getPayloadResult()); + context = new DefaultMessageContext(invalidMessage, soap11Factory); + + boolean validated; + try { + validated = interceptor.handleRequest(context); + } + catch (WebServiceClientException e) { + validated = false; + assertNotNull("No exception details provided in WebServiceClientException", e.getMessage()); + } + assertFalse("Invalid response from interceptor", validated); + } + + public void testHandlerInvalidRequest() throws Exception { + MockWebServiceMessage request = new MockWebServiceMessage(); + request.setPayload(new ClassPathResource(INVALID_MESSAGE, getClass())); + context = new DefaultMessageContext(request, new MockWebServiceMessageFactory()); + + boolean validated; + try { + validated = interceptor.handleRequest(context); + } + catch (WebServiceClientException e) { + validated = false; + assertNotNull("No exception details provided in WebServiceClientException", e.getMessage()); + } + assertFalse("Invalid response from interceptor", validated); + } + + public void testHandleValidRequest() throws Exception { + MockWebServiceMessage request = new MockWebServiceMessage(); + request.setPayload(new ClassPathResource(VALID_MESSAGE, getClass())); + context = new DefaultMessageContext(request, new MockWebServiceMessageFactory()); + boolean result = interceptor.handleRequest(context); + assertTrue("Invalid response from interceptor", result); + assertFalse("Response set", context.hasResponse()); + } + + public void testHandleInvalidResponse() throws Exception { + MockWebServiceMessage request = new MockWebServiceMessage(); + context = new DefaultMessageContext(request, new MockWebServiceMessageFactory()); + MockWebServiceMessage response = (MockWebServiceMessage) context.getResponse(); + response.setPayload(new ClassPathResource(INVALID_MESSAGE, getClass())); + + boolean result = interceptor.handleResponse(context); + assertFalse("Invalid response from interceptor", result); + } + + public void testHandleValidResponse() throws Exception { + MockWebServiceMessage request = new MockWebServiceMessage(); + context = new DefaultMessageContext(request, new MockWebServiceMessageFactory()); + MockWebServiceMessage response = (MockWebServiceMessage) context.getResponse(); + response.setPayload(new ClassPathResource(VALID_MESSAGE, getClass())); + boolean result = interceptor.handleResponse(context); + assertTrue("Invalid response from interceptor", result); + } + + public void testNamespacesInType() throws Exception { + // Make sure we use Xerces for this testcase: the JAXP implementation used internally by JDK 1.5 has a bug + // See http://opensource.atlassian.com/projects/spring/browse/SWS-35 + String previousSchemaFactory = + System.getProperty("javax.xml.validation.SchemaFactory:" + XMLConstants.W3C_XML_SCHEMA_NS_URI, ""); + System.setProperty("javax.xml.validation.SchemaFactory:" + XMLConstants.W3C_XML_SCHEMA_NS_URI, + "org.apache.xerces.jaxp.validation.XMLSchemaFactory"); + try { + PayloadValidatingInterceptor interceptor = new PayloadValidatingInterceptor(); + interceptor.setSchema(new ClassPathResource(SCHEMA2, PayloadValidatingInterceptorTest.class)); + interceptor.afterPropertiesSet(); + MessageFactory messageFactory = MessageFactory.newInstance(); + SOAPMessage saajMessage = + SaajUtils.loadMessage(new ClassPathResource(VALID_SOAP_MESSAGE, getClass()), messageFactory); + context = new DefaultMessageContext(new SaajSoapMessage(saajMessage), + new SaajSoapMessageFactory(messageFactory)); + + boolean result = interceptor.handleRequest(context); + assertTrue("Invalid response from interceptor", result); + assertFalse("Response set", context.hasResponse()); + } + finally { + // Reset the property + System.setProperty("javax.xml.validation.SchemaFactory:" + XMLConstants.W3C_XML_SCHEMA_NS_URI, + previousSchemaFactory); + } + } + + public void testNonExistingSchema() throws Exception { + try { + interceptor.setSchema(new ClassPathResource("invalid")); + interceptor.afterPropertiesSet(); + fail("IllegalArgumentException expected"); + } + catch (IllegalArgumentException ex) { + // expected + } + } + + public void testHandlerInvalidRequestMultipleSchemas() throws Exception { + interceptor.setSchemas(new Resource[]{new ClassPathResource(PRODUCT_SCHEMA, getClass()), + new ClassPathResource(SIZE_SCHEMA, getClass())}); + interceptor.afterPropertiesSet(); + MockWebServiceMessage request = new MockWebServiceMessage(new ClassPathResource(INVALID_MESSAGE, getClass())); + context = new DefaultMessageContext(request, new MockWebServiceMessageFactory()); + + boolean validated; + try { + validated = interceptor.handleRequest(context); + } + catch (WebServiceClientException e) { + validated = false; + assertNotNull("No exception details provided in WebServiceClientException", e.getMessage()); + } + assertFalse("Invalid response from interceptor", validated); + } + + public void testHandleValidRequestMultipleSchemas() throws Exception { + interceptor.setSchemas(new Resource[]{new ClassPathResource(PRODUCT_SCHEMA, getClass()), + new ClassPathResource(SIZE_SCHEMA, getClass())}); + interceptor.afterPropertiesSet(); + MockWebServiceMessage request = new MockWebServiceMessage(new ClassPathResource(VALID_MESSAGE, getClass())); + context = new DefaultMessageContext(request, new MockWebServiceMessageFactory()); + + boolean result = interceptor.handleRequest(context); + assertTrue("Invalid response from interceptor", result); + assertFalse("Response set", context.hasResponse()); + } + + public void testHandleInvalidResponseMultipleSchemas() throws Exception { + interceptor.setSchemas(new Resource[]{new ClassPathResource(PRODUCT_SCHEMA, getClass()), + new ClassPathResource(SIZE_SCHEMA, getClass())}); + interceptor.afterPropertiesSet(); + MockWebServiceMessage request = new MockWebServiceMessage(); + context = new DefaultMessageContext(request, new MockWebServiceMessageFactory()); + MockWebServiceMessage response = (MockWebServiceMessage) context.getResponse(); + response.setPayload(new ClassPathResource(INVALID_MESSAGE, getClass())); + boolean result = interceptor.handleResponse(context); + assertFalse("Invalid response from interceptor", result); + } + + public void testHandleValidResponseMultipleSchemas() throws Exception { + interceptor.setSchemas(new Resource[]{new ClassPathResource(PRODUCT_SCHEMA, getClass()), + new ClassPathResource(SIZE_SCHEMA, getClass())}); + interceptor.afterPropertiesSet(); + MockWebServiceMessage request = new MockWebServiceMessage(); + context = new DefaultMessageContext(request, new MockWebServiceMessageFactory()); + MockWebServiceMessage response = (MockWebServiceMessage) context.getResponse(); + response.setPayload(new ClassPathResource(VALID_MESSAGE, getClass())); + boolean result = interceptor.handleResponse(context); + assertTrue("Invalid response from interceptor", result); + } + + public void testXsdSchema() throws Exception { + PayloadValidatingInterceptor interceptor = new PayloadValidatingInterceptor(); + SimpleXsdSchema schema = new SimpleXsdSchema(new ClassPathResource(SCHEMA, getClass())); + schema.afterPropertiesSet(); + interceptor.setXsdSchema(schema); + interceptor.setValidateRequest(true); + interceptor.setValidateResponse(true); + interceptor.afterPropertiesSet(); + MockWebServiceMessage request = new MockWebServiceMessage(); + request.setPayload(new ClassPathResource(VALID_MESSAGE, getClass())); + context = new DefaultMessageContext(request, new MockWebServiceMessageFactory()); + boolean result = interceptor.handleRequest(context); + assertTrue("Invalid response from interceptor", result); + assertFalse("Response set", context.hasResponse()); + } +} diff --git a/core/src/test/resources/org/springframework/ws/client/support/interceptor/invalidMessage.xml b/core/src/test/resources/org/springframework/ws/client/support/interceptor/invalidMessage.xml new file mode 100644 index 00000000..809bda71 --- /dev/null +++ b/core/src/test/resources/org/springframework/ws/client/support/interceptor/invalidMessage.xml @@ -0,0 +1,4 @@ + + + 20 + diff --git a/core/src/test/resources/org/springframework/ws/client/support/interceptor/productSchema.xsd b/core/src/test/resources/org/springframework/ws/client/support/interceptor/productSchema.xsd new file mode 100644 index 00000000..b85cf8db --- /dev/null +++ b/core/src/test/resources/org/springframework/ws/client/support/interceptor/productSchema.xsd @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff --git a/core/src/test/resources/org/springframework/ws/client/support/interceptor/schema.xsd b/core/src/test/resources/org/springframework/ws/client/support/interceptor/schema.xsd new file mode 100644 index 00000000..60d338c5 --- /dev/null +++ b/core/src/test/resources/org/springframework/ws/client/support/interceptor/schema.xsd @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/test/resources/org/springframework/ws/client/support/interceptor/schema2.xsd b/core/src/test/resources/org/springframework/ws/client/support/interceptor/schema2.xsd new file mode 100644 index 00000000..b6058e92 --- /dev/null +++ b/core/src/test/resources/org/springframework/ws/client/support/interceptor/schema2.xsd @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/core/src/test/resources/org/springframework/ws/client/support/interceptor/sizeSchema.xsd b/core/src/test/resources/org/springframework/ws/client/support/interceptor/sizeSchema.xsd new file mode 100644 index 00000000..60613d2b --- /dev/null +++ b/core/src/test/resources/org/springframework/ws/client/support/interceptor/sizeSchema.xsd @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/core/src/test/resources/org/springframework/ws/client/support/interceptor/validMessage.xml b/core/src/test/resources/org/springframework/ws/client/support/interceptor/validMessage.xml new file mode 100644 index 00000000..9ff7f778 --- /dev/null +++ b/core/src/test/resources/org/springframework/ws/client/support/interceptor/validMessage.xml @@ -0,0 +1,5 @@ + + + 42 + 10 + diff --git a/core/src/test/resources/org/springframework/ws/client/support/interceptor/validSoapMessage.xml b/core/src/test/resources/org/springframework/ws/client/support/interceptor/validSoapMessage.xml new file mode 100644 index 00000000..e4b67716 --- /dev/null +++ b/core/src/test/resources/org/springframework/ws/client/support/interceptor/validSoapMessage.xml @@ -0,0 +1,12 @@ + + + + + + 123 + Fritz + Meier + + + +