From ba2744ab8221ad43910774b7e98413f83d99c17c Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Thu, 24 Mar 2011 10:12:51 +0000 Subject: [PATCH] SWS-242 - Allow for custom ErrorHandler in PayloadValidatingInterceptor --- .../AbstractValidatingInterceptor.java | 24 +++++++++--- .../PayloadValidatingInterceptorTest.java | 37 +++++++++++++++++-- .../validation/Jaxp10ValidatorFactory.java | 21 +++++++---- .../validation/Jaxp13ValidatorFactory.java | 20 ++++++---- .../validation/ValidationErrorHandler.java | 34 +++++++++++++++++ .../xml/validation/XmlValidator.java | 18 +++++++-- .../xml/validation/XmlValidatorFactory.java | 10 ++--- .../AbstractValidatorFactoryTestCase.java | 26 ++++++++++++- .../Jaxp10ValidatorFactoryTest.java | 9 ++++- 9 files changed, 161 insertions(+), 38 deletions(-) create mode 100644 xml/src/main/java/org/springframework/xml/validation/ValidationErrorHandler.java diff --git a/core/src/main/java/org/springframework/ws/server/endpoint/interceptor/AbstractValidatingInterceptor.java b/core/src/main/java/org/springframework/ws/server/endpoint/interceptor/AbstractValidatingInterceptor.java index 765128b8..8a1b2686 100644 --- a/core/src/main/java/org/springframework/ws/server/endpoint/interceptor/AbstractValidatingInterceptor.java +++ b/core/src/main/java/org/springframework/ws/server/endpoint/interceptor/AbstractValidatingInterceptor.java @@ -1,11 +1,11 @@ /* - * Copyright 2005-2010 the original author or authors. + * Copyright 2005-2011 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 + * 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, @@ -31,6 +31,7 @@ import org.springframework.ws.server.EndpointInterceptor; import org.springframework.ws.soap.SoapFault; import org.springframework.ws.soap.SoapMessage; import org.springframework.xml.transform.TransformerObjectSupport; +import org.springframework.xml.validation.ValidationErrorHandler; import org.springframework.xml.validation.XmlValidator; import org.springframework.xml.validation.XmlValidatorFactory; import org.springframework.xml.xsd.XsdSchema; @@ -65,6 +66,8 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup private XmlValidator validator; + private ValidationErrorHandler errorHandler; + public String getSchemaLanguage() { return schemaLanguage; } @@ -131,6 +134,15 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup this.validator = schemaCollection.createValidator(); } + /** + * Sets the error handler to use for validation. If not set, a default error handler will be used. + * + * @param errorHandler the error handler. + */ + public void setErrorHandler(ValidationErrorHandler errorHandler) { + this.errorHandler = errorHandler; + } + /** Indicates whether the request should be validated against the schema. Default is true. */ public void setValidateRequest(boolean validateRequest) { this.validateRequest = validateRequest; @@ -171,7 +183,7 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup if (validateRequest) { Source requestSource = getValidationRequestSource(messageContext.getRequest()); if (requestSource != null) { - SAXParseException[] errors = validator.validate(requestSource); + SAXParseException[] errors = validator.validate(requestSource, errorHandler); if (!ObjectUtils.isEmpty(errors)) { return handleRequestValidationErrors(messageContext, errors); } @@ -213,7 +225,7 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup if (validateResponse) { Source responseSource = getValidationResponseSource(messageContext.getResponse()); if (responseSource != null) { - SAXParseException[] errors = validator.validate(responseSource); + SAXParseException[] errors = validator.validate(responseSource, errorHandler); if (!ObjectUtils.isEmpty(errors)) { return handleResponseValidationErrors(messageContext, errors); } @@ -227,11 +239,11 @@ public abstract class AbstractValidatingInterceptor extends TransformerObjectSup /** * 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. + * all errors, and returns false, i.e. do not cot continue to process the response interceptor chain. * * @param messageContext the message context * @param errors the validation errors - * @return true to continue the reponse interceptor chain, false (the default) otherwise + * @return true to continue the response interceptor chain, false (the default) otherwise */ protected boolean handleResponseValidationErrors(MessageContext messageContext, SAXParseException[] errors) { for (SAXParseException error : errors) { diff --git a/core/src/test/java/org/springframework/ws/soap/server/endpoint/interceptor/PayloadValidatingInterceptorTest.java b/core/src/test/java/org/springframework/ws/soap/server/endpoint/interceptor/PayloadValidatingInterceptorTest.java index e603c48c..56ff9f94 100644 --- a/core/src/test/java/org/springframework/ws/soap/server/endpoint/interceptor/PayloadValidatingInterceptorTest.java +++ b/core/src/test/java/org/springframework/ws/soap/server/endpoint/interceptor/PayloadValidatingInterceptorTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2005-2010 the original author or authors. + * Copyright 2005-2011 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 + * 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, @@ -44,11 +44,13 @@ import org.springframework.ws.soap.soap11.Soap11Fault; import org.springframework.ws.soap.soap12.Soap12Fault; import org.springframework.ws.transport.MockTransportInputStream; import org.springframework.ws.transport.TransportInputStream; +import org.springframework.xml.validation.ValidationErrorHandler; import org.springframework.xml.xsd.SimpleXsdSchema; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.LocatorImpl; @@ -95,7 +97,7 @@ public class PayloadValidatingInterceptorTest { @Test public void testHandleInvalidRequestSoap11() throws Exception { - SoapMessage invalidMessage = (SoapMessage) soap11Factory.createWebServiceMessage(); + SoapMessage invalidMessage = soap11Factory.createWebServiceMessage(); InputStream inputStream = getClass().getResourceAsStream(INVALID_MESSAGE); transformer.transform(new StreamSource(inputStream), invalidMessage.getPayloadResult()); context = new DefaultMessageContext(invalidMessage, soap11Factory); @@ -115,7 +117,7 @@ public class PayloadValidatingInterceptorTest { @Test public void testHandleInvalidRequestSoap12() throws Exception { - SoapMessage invalidMessage = (SoapMessage) soap12Factory.createWebServiceMessage(); + SoapMessage invalidMessage = soap12Factory.createWebServiceMessage(); InputStream inputStream = getClass().getResourceAsStream(INVALID_MESSAGE); transformer.transform(new StreamSource(inputStream), invalidMessage.getPayloadResult()); context = new DefaultMessageContext(invalidMessage, soap12Factory); @@ -365,4 +367,31 @@ public class PayloadValidatingInterceptorTest { } + @Test + public void customErrorHandler() throws Exception { + ValidationErrorHandler errorHandler = new ValidationErrorHandler() { + public SAXParseException[] getErrors() { + return new SAXParseException[0]; + } + + public void warning(SAXParseException exception) throws SAXException { + } + + public void error(SAXParseException exception) throws SAXException { + } + + public void fatalError(SAXParseException exception) throws SAXException { + } + }; + interceptor.setErrorHandler(errorHandler); + SoapMessage invalidMessage = soap11Factory.createWebServiceMessage(); + InputStream inputStream = getClass().getResourceAsStream(INVALID_MESSAGE); + transformer.transform(new StreamSource(inputStream), invalidMessage.getPayloadResult()); + context = new DefaultMessageContext(invalidMessage, soap11Factory); + + boolean result = interceptor.handleRequest(context, null); + Assert.assertTrue("Invalid response from interceptor", result); + Assert.assertFalse("Context has response", context.hasResponse()); + } + } \ No newline at end of file diff --git a/xml/src/main/java/org/springframework/xml/validation/Jaxp10ValidatorFactory.java b/xml/src/main/java/org/springframework/xml/validation/Jaxp10ValidatorFactory.java index 316c3001..699de203 100644 --- a/xml/src/main/java/org/springframework/xml/validation/Jaxp10ValidatorFactory.java +++ b/xml/src/main/java/org/springframework/xml/validation/Jaxp10ValidatorFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2005-2010 the original author or authors. + * Copyright 2005-2011 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 + * 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, @@ -46,7 +46,9 @@ import org.xml.sax.helpers.DefaultHandler; * * @author Arjen Poutsma * @since 1.0.0 + * @deprecated in favor of {@link Jaxp13ValidatorFactory} */ +@Deprecated abstract class Jaxp10ValidatorFactory { private static final String SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; @@ -80,9 +82,14 @@ abstract class Jaxp10ValidatorFactory { parserFactory.setValidating(true); } + public SAXParseException[] validate(Source source, ValidationErrorHandler errorHandler) + throws IOException { + return validate(source); + } + public SAXParseException[] validate(Source source) throws IOException { SAXParser parser = createSAXParser(); - ValidationErrorHandler errorHandler = new ValidationErrorHandler(); + DefaultValidationErrorHandler errorHandler = new DefaultValidationErrorHandler(); try { if (source instanceof SAXSource) { validateSAXSource((SAXSource) source, parser, errorHandler); @@ -104,7 +111,7 @@ abstract class Jaxp10ValidatorFactory { } } - private void validateDOMSource(DOMSource domSource, SAXParser parser, ValidationErrorHandler errorHandler) + private void validateDOMSource(DOMSource domSource, SAXParser parser, DefaultValidationErrorHandler errorHandler) throws IOException, SAXException { try { // Sadly, JAXP 1.0 DOM doesn't implement DOM level 3, so we cannot use Document.normalizeDocument() @@ -123,7 +130,7 @@ abstract class Jaxp10ValidatorFactory { private void validateStreamSource(StreamSource streamSource, SAXParser parser, - ValidationErrorHandler errorHandler) throws SAXException, IOException { + DefaultValidationErrorHandler errorHandler) throws SAXException, IOException { if (streamSource.getInputStream() != null) { parser.parse(streamSource.getInputStream(), errorHandler); } @@ -135,7 +142,7 @@ abstract class Jaxp10ValidatorFactory { } } - private void validateSAXSource(SAXSource source, SAXParser parser, ValidationErrorHandler errorHandler) + private void validateSAXSource(SAXSource source, SAXParser parser, DefaultValidationErrorHandler errorHandler) throws SAXException, IOException { parser.parse(source.getInputSource(), errorHandler); } @@ -157,7 +164,7 @@ abstract class Jaxp10ValidatorFactory { } /** DefaultHandler extension that stores errors and fatal errors in a list. */ - private static class ValidationErrorHandler extends DefaultHandler { + private static class DefaultValidationErrorHandler extends DefaultHandler { private List errors = new ArrayList(); diff --git a/xml/src/main/java/org/springframework/xml/validation/Jaxp13ValidatorFactory.java b/xml/src/main/java/org/springframework/xml/validation/Jaxp13ValidatorFactory.java index 88682e77..d478bae2 100644 --- a/xml/src/main/java/org/springframework/xml/validation/Jaxp13ValidatorFactory.java +++ b/xml/src/main/java/org/springframework/xml/validation/Jaxp13ValidatorFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2005-2010 the original author or authors. + * Copyright 2005-2011 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 + * 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, @@ -21,10 +21,10 @@ import java.util.ArrayList; import java.util.List; import javax.xml.transform.Source; import javax.xml.validation.Schema; +import javax.xml.validation.Validator; import org.springframework.core.io.Resource; -import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; @@ -55,8 +55,14 @@ abstract class Jaxp13ValidatorFactory { } public SAXParseException[] validate(Source source) throws IOException { - javax.xml.validation.Validator validator = schema.newValidator(); - ValidationErrorHandler errorHandler = new ValidationErrorHandler(); + return validate(source, null); + } + + public SAXParseException[] validate(Source source, ValidationErrorHandler errorHandler) throws IOException { + if (errorHandler == null) { + errorHandler = new DefaultValidationErrorHandler(); + } + Validator validator = schema.newValidator(); validator.setErrorHandler(errorHandler); try { validator.validate(source); @@ -69,11 +75,11 @@ abstract class Jaxp13ValidatorFactory { } /** ErrorHandler implementation that stores errors and fatal errors in a list. */ - private static class ValidationErrorHandler implements ErrorHandler { + private static class DefaultValidationErrorHandler implements ValidationErrorHandler { private List errors = new ArrayList(); - private SAXParseException[] getErrors() { + public SAXParseException[] getErrors() { return errors.toArray(new SAXParseException[errors.size()]); } diff --git a/xml/src/main/java/org/springframework/xml/validation/ValidationErrorHandler.java b/xml/src/main/java/org/springframework/xml/validation/ValidationErrorHandler.java new file mode 100644 index 00000000..415a1aa9 --- /dev/null +++ b/xml/src/main/java/org/springframework/xml/validation/ValidationErrorHandler.java @@ -0,0 +1,34 @@ +/* + * Copyright 2005-2011 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.xml.validation; + +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXParseException; + +/** + * Subinterface of {@link ErrorHandler} that allows the registered errors to be retrieved. + * @author Arjen Poutsma + * @since 2.0.1 + */ +public interface ValidationErrorHandler extends ErrorHandler { + + /** + * Returns the errors collected by this error handler. + * @return the errors + */ + SAXParseException[] getErrors(); +} diff --git a/xml/src/main/java/org/springframework/xml/validation/XmlValidator.java b/xml/src/main/java/org/springframework/xml/validation/XmlValidator.java index daea4e85..645da421 100644 --- a/xml/src/main/java/org/springframework/xml/validation/XmlValidator.java +++ b/xml/src/main/java/org/springframework/xml/validation/XmlValidator.java @@ -1,11 +1,11 @@ /* - * Copyright 2006 the original author or authors. + * Copyright 2005-2011 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 + * 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, @@ -27,7 +27,7 @@ import org.xml.sax.SAXParseException; * Instances of this class are designed to be thread safe. * * @author Arjen Poutsma - * @see XmlValidatorFactory#createValidator(org.springframework.core.io.Resource,String) + * @see XmlValidatorFactory#createValidator(org.springframework.core.io.Resource, String) * @since 1.0.0 */ public interface XmlValidator { @@ -43,4 +43,16 @@ public interface XmlValidator { */ SAXParseException[] validate(Source source) throws IOException; + /** + * Validates the given {@link Source} and {@link ValidationErrorHandler}, and returns an array of {@link + * SAXParseException}s as result. The array will be empty if no validation errors are found. + * + * @param source the input document + * @param errorHandler the error handler to use. May be {@code null}, in which case a default will be used. + * @return an array of SAXParseExceptions + * @throws IOException if the source cannot be read + * @throws XmlValidationException if the source cannot be validated + */ + SAXParseException[] validate(Source source, ValidationErrorHandler errorHandler) throws IOException; + } \ No newline at end of file diff --git a/xml/src/main/java/org/springframework/xml/validation/XmlValidatorFactory.java b/xml/src/main/java/org/springframework/xml/validation/XmlValidatorFactory.java index f7a20cf5..be7b1e79 100644 --- a/xml/src/main/java/org/springframework/xml/validation/XmlValidatorFactory.java +++ b/xml/src/main/java/org/springframework/xml/validation/XmlValidatorFactory.java @@ -1,11 +1,11 @@ /* - * Copyright 2005-2010 the original author or authors. + * Copyright 2005-2011 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 + * 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, @@ -91,12 +91,8 @@ public abstract class XmlValidatorFactory { logger.trace("Creating JAXP 1.3 XmlValidator"); return Jaxp13ValidatorFactory.createValidator(schemaResources, schemaLanguage); } - else if (JaxpVersion.getJaxpVersion() >= JaxpVersion.JAXP_10) { - logger.trace("Creating JAXP 1.0 XmlValidator"); - return Jaxp10ValidatorFactory.createValidator(schemaResources, schemaLanguage); - } else { - throw new IllegalStateException("Could not locate JAXP 1.0 or higher."); + throw new IllegalStateException("Could not locate JAXP 1.3."); } } diff --git a/xml/src/test/java/org/springframework/xml/validation/AbstractValidatorFactoryTestCase.java b/xml/src/test/java/org/springframework/xml/validation/AbstractValidatorFactoryTestCase.java index 94b08eb7..8c96c612 100644 --- a/xml/src/test/java/org/springframework/xml/validation/AbstractValidatorFactoryTestCase.java +++ b/xml/src/test/java/org/springframework/xml/validation/AbstractValidatorFactoryTestCase.java @@ -1,11 +1,11 @@ /* - * Copyright 2005-2010 the original author or authors. + * Copyright 2005-2011 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 + * 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, @@ -33,6 +33,7 @@ import org.junit.Before; import org.junit.Test; import org.w3c.dom.Document; import org.xml.sax.InputSource; +import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; public abstract class AbstractValidatorFactoryTestCase { @@ -135,4 +136,25 @@ public abstract class AbstractValidatorFactoryTestCase { Assert.assertEquals("ValidationErrors returned", 0, errors.length); } + @Test + public void customErrorHandler() throws Exception { + ValidationErrorHandler myHandler = new ValidationErrorHandler() { + public SAXParseException[] getErrors() { + return new SAXParseException[0]; + } + + public void warning(SAXParseException exception) throws SAXException { + } + + public void error(SAXParseException exception) throws SAXException { + } + + public void fatalError(SAXParseException exception) throws SAXException { + } + }; + SAXParseException[] errors = validator.validate(new StreamSource(invalidInputStream), myHandler); + Assert.assertNotNull("Null returned for errors", errors); + Assert.assertEquals("ValidationErrors returned", 0, errors.length); + } + } diff --git a/xml/src/test/java/org/springframework/xml/validation/Jaxp10ValidatorFactoryTest.java b/xml/src/test/java/org/springframework/xml/validation/Jaxp10ValidatorFactoryTest.java index 754ccc65..a97b92ce 100644 --- a/xml/src/test/java/org/springframework/xml/validation/Jaxp10ValidatorFactoryTest.java +++ b/xml/src/test/java/org/springframework/xml/validation/Jaxp10ValidatorFactoryTest.java @@ -1,11 +1,11 @@ /* - * Copyright 2005-2010 the original author or authors. + * Copyright 2005-2011 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 + * 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, @@ -26,4 +26,9 @@ public class Jaxp10ValidatorFactoryTest extends AbstractValidatorFactoryTestCase protected XmlValidator createValidator(Resource[] schemaResources, String schemaLanguage) throws IOException { return Jaxp10ValidatorFactory.createValidator(schemaResources, schemaLanguage); } + + @Override + public void customErrorHandler() throws Exception { + // Not supported on JAXP 1.0 + } }