diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/IntegrationXmlNamespaceHandler.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/IntegrationXmlNamespaceHandler.java index 072505af96..57ebcb5d0c 100644 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/IntegrationXmlNamespaceHandler.java +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/IntegrationXmlNamespaceHandler.java @@ -34,7 +34,7 @@ public class IntegrationXmlNamespaceHandler extends AbstractIntegrationNamespace registerBeanDefinitionParser("xpath-selector", new XPathSelectorParser()); registerBeanDefinitionParser("xpath-expression", new XPathExpressionParser()); registerBeanDefinitionParser("xpath-splitter", new XPathMessageSplitterParser()); - registerBeanDefinitionParser("validating-router", new XmlPayloadValidatingRouterParser()); + registerBeanDefinitionParser("validating-filter", new XmlPayloadValidatingFilterParser()); } } diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XmlPayloadValidatingFilterParser.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XmlPayloadValidatingFilterParser.java new file mode 100644 index 0000000000..f688a4c1b8 --- /dev/null +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XmlPayloadValidatingFilterParser.java @@ -0,0 +1,59 @@ +/* + * Copyright 2002-2010 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.integration.xml.config; + +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.config.xml.AbstractConsumerEndpointParser; +import org.springframework.integration.config.xml.IntegrationNamespaceUtils; +import org.w3c.dom.Element; + +/** + * @author Jonas Partner + * @author Oleg Zhurakousky + */ +public class XmlPayloadValidatingFilterParser extends AbstractConsumerEndpointParser { + private static String SELECTOR = + "org.springframework.integration.xml.selector.SchemaValidatingMessageSelector"; + private static String FILTER = + "org.springframework.integration.config.FilterFactoryBean"; + + @Override + protected boolean shouldGenerateId() { + return true; + } + + @Override + protected boolean shouldGenerateIdAsFallback() { + return true; + } + + @Override + protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) { + BeanDefinitionBuilder filterBuilder = BeanDefinitionBuilder.genericBeanDefinition(FILTER); + + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(filterBuilder, element, "discard-channel"); + IntegrationNamespaceUtils.setValueIfAttributeDefined(filterBuilder, element, "throw-exception-on-rejection"); + + BeanDefinitionBuilder selectorBuilder = BeanDefinitionBuilder.genericBeanDefinition(SELECTOR); + selectorBuilder.addConstructorArgValue(element.getAttribute("schema-location")); + selectorBuilder.addPropertyValue("schemaType", element.getAttribute("schema-type")); + + filterBuilder.addPropertyValue("targetObject", selectorBuilder.getBeanDefinition()); + return filterBuilder; + } +} diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XmlPayloadValidatingRouterParser.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XmlPayloadValidatingRouterParser.java deleted file mode 100644 index 83f3e8f7e6..0000000000 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/config/XmlPayloadValidatingRouterParser.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2002-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.integration.xml.config; - -import javax.xml.XMLConstants; - -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.xml.ParserContext; -import org.springframework.integration.config.xml.AbstractConsumerEndpointParser; -import org.springframework.integration.xml.router.SchemaValidator; -import org.springframework.integration.xml.router.XmlPayloadValidatingRouter; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; -import org.w3c.dom.Element; - -/** - * @author Jonas Partner - */ -public class XmlPayloadValidatingRouterParser extends - AbstractConsumerEndpointParser { - - @Override - protected boolean shouldGenerateId() { - return false; - } - - @Override - protected boolean shouldGenerateIdAsFallback() { - return true; - } - - @Override - protected BeanDefinitionBuilder parseHandler(Element element, - ParserContext parserContext) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder - .genericBeanDefinition(); - builder.getBeanDefinition().setBeanClass( - XmlPayloadValidatingRouter.class); - String channelResolver = element.getAttribute("channel-resolver"); - - String validChannelName = element.getAttribute("valid-channel"); - String invalidChannelName = element.getAttribute("invalid-channel"); - String schemaType = element.getAttribute("schema-type"); - String schemaLocation = element.getAttribute("schema-location"); - - Assert.state(schemaType.equals("xml-schema") - || schemaType.equals("relax-ng"), "Unrecognised schema type " - + schemaType); - - - Assert.state(StringUtils.hasText(invalidChannelName) - && StringUtils.hasText(validChannelName), - "valid-channel and invalid-channel must both be specified"); - - builder.addConstructorArgValue(validChannelName); - builder.addConstructorArgValue(invalidChannelName); - - - - BeanDefinition validatorBeanDefinition; - if (schemaType.equals("xml-schema")) { - validatorBeanDefinition = createValidator(XMLConstants.W3C_XML_SCHEMA_NS_URI, schemaLocation); - } else { - validatorBeanDefinition = createValidator(XMLConstants.RELAXNG_NS_URI, schemaLocation); - } - builder.addConstructorArgValue(validatorBeanDefinition); - - - if (StringUtils.hasText(channelResolver)) { - builder.addPropertyReference("channelResolver", channelResolver); - } - - return builder; - } - - protected BeanDefinition createValidator(String schemaType, String schemaLocation){ - BeanDefinitionBuilder xmlValidator = BeanDefinitionBuilder - .genericBeanDefinition(); - xmlValidator.getBeanDefinition().setBeanClass(SchemaValidator.class); - xmlValidator.addConstructorArgValue(schemaLocation); - xmlValidator.addConstructorArgValue(schemaType); - - return xmlValidator.getBeanDefinition(); - } - -} diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/router/XmlPayloadValidatingRouter.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/router/XmlPayloadValidatingRouter.java deleted file mode 100644 index b4b661b4b6..0000000000 --- a/spring-integration-xml/src/main/java/org/springframework/integration/xml/router/XmlPayloadValidatingRouter.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2002-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.integration.xml.router; - -import org.springframework.integration.Message; -import org.springframework.integration.router.AbstractSingleChannelNameRouter; -import org.springframework.integration.xml.DefaultXmlPayloadConverter; -import org.springframework.integration.xml.XmlPayloadConverter; - -public class XmlPayloadValidatingRouter extends AbstractSingleChannelNameRouter{ - - private final String validMessageChannelName; - - private final String invalidMessageChannelName; - - private final XmlValidator xmlValidator; - - private volatile XmlPayloadConverter converter = new DefaultXmlPayloadConverter(); - - - public XmlPayloadValidatingRouter(String validMessageChannelName, - String invalidMessageChannelName, XmlValidator xmlValidator) { - super(); - this.validMessageChannelName = validMessageChannelName; - this.invalidMessageChannelName = invalidMessageChannelName; - this.xmlValidator = xmlValidator; - } - - /** - * Converter used to convert payloads prior to validation - * - * @param converter - */ - public void setConverter(XmlPayloadConverter converter) { - this.converter = converter; - } - - - @Override - protected String determineTargetChannelName(Message message) { - return xmlValidator.isValid(converter.convertToSource(message.getPayload())) ? validMessageChannelName : invalidMessageChannelName; - } - - - - -} diff --git a/spring-integration-xml/src/main/java/org/springframework/integration/xml/selector/SchemaValidatingMessageSelector.java b/spring-integration-xml/src/main/java/org/springframework/integration/xml/selector/SchemaValidatingMessageSelector.java new file mode 100644 index 0000000000..33df93f65e --- /dev/null +++ b/spring-integration-xml/src/main/java/org/springframework/integration/xml/selector/SchemaValidatingMessageSelector.java @@ -0,0 +1,73 @@ +/* + * Copyright 2002-2010 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.integration.xml.selector; + +import org.springframework.core.io.Resource; +import org.springframework.integration.Message; +import org.springframework.integration.MessageHandlingException; +import org.springframework.integration.core.MessageSelector; +import org.springframework.integration.xml.DefaultXmlPayloadConverter; +import org.springframework.integration.xml.XmlPayloadConverter; +import org.springframework.util.Assert; +import org.springframework.xml.validation.XmlValidator; +import org.springframework.xml.validation.XmlValidatorFactory; +import org.xml.sax.SAXParseException; +/** + * + * @author Oleg Zhurakousky + * @since 2.0 + * + */ +public class SchemaValidatingMessageSelector implements MessageSelector{ + + private final XmlValidator xmlValidator; + private volatile String schemaType = XmlValidatorFactory.SCHEMA_W3C_XML; + + private volatile XmlPayloadConverter converter = new DefaultXmlPayloadConverter(); + + + public SchemaValidatingMessageSelector(Resource schema) throws Exception{ + Assert.notNull(schema, "You must provide XML schema location to perform validation"); + this.xmlValidator = XmlValidatorFactory.createValidator(schema, schemaType); + } + + /** + * Converter used to convert payloads prior to validation + * + * @param converter + */ + public void setConverter(XmlPayloadConverter converter) { + this.converter = converter; + } + + public void setSchemaType(String schemaType) { + this.schemaType = schemaType; + } + + @Override + public boolean accept(Message message) { + // TODO Need to figure out how the exceptions could be propagated since the return from this method is true/false + // and 'throw-exception-on-rejection'is actually set on the filter + try { + SAXParseException[] validationExceptions = xmlValidator.validate(converter.convertToSource(message.getPayload())); + return validationExceptions.length == 0 ? true : false; + } catch (Exception e) { + e.printStackTrace(); + throw new MessageHandlingException(message, e); + } + } +} diff --git a/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-2.0.xsd b/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-2.0.xsd index adf751481d..438f986123 100644 --- a/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-2.0.xsd +++ b/spring-integration-xml/src/main/resources/org/springframework/integration/xml/config/spring-integration-xml-2.0.xsd @@ -510,11 +510,11 @@ - + - Defines a validating router. + Defines a validating filter. @@ -530,17 +530,8 @@ - - - - - - - - - - - + + diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XmlPayloadValidatingFilterParserTests-context.xml b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XmlPayloadValidatingFilterParserTests-context.xml new file mode 100644 index 0000000000..30e11e3ae2 --- /dev/null +++ b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XmlPayloadValidatingFilterParserTests-context.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XmlPayloadValidatingFilterParserTests.java b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XmlPayloadValidatingFilterParserTests.java new file mode 100644 index 0000000000..a0f7a58930 --- /dev/null +++ b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XmlPayloadValidatingFilterParserTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2002-2010 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.integration.xml.config; + +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; + +import org.junit.Test; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.integration.MessageChannel; +import org.springframework.integration.core.PollableChannel; +import org.springframework.integration.message.GenericMessage; +import org.springframework.integration.xml.util.XmlTestUtil; +import org.springframework.test.context.ContextConfiguration; +import org.w3c.dom.Document; + +/** + * @author Jonas Partner + * @author Oleg Zhurakousky + */ +@ContextConfiguration +public class XmlPayloadValidatingFilterParserTests { + + @Test + public void testValidMessage() throws Exception { + ApplicationContext ac = new ClassPathXmlApplicationContext("XmlPayloadValidatingFilterParserTests-context.xml", this.getClass()); + Document doc = XmlTestUtil.getDocumentForString("hello"); + GenericMessage docMessage = new GenericMessage(doc); + PollableChannel validChannel = ac.getBean("validOutputChannel", PollableChannel.class); + MessageChannel inputChannel = ac.getBean("inputChannel", MessageChannel.class); + inputChannel.send(docMessage); + assertNotNull(validChannel.receive(100)); + + } + @Test + public void testInvalidMessage() throws Exception { + ApplicationContext ac = new ClassPathXmlApplicationContext("XmlPayloadValidatingFilterParserTests-context.xml", this.getClass()); + Document doc = XmlTestUtil.getDocumentForString(""); + GenericMessage docMessage = new GenericMessage(doc); + PollableChannel validChannel = ac.getBean("validOutputChannel", PollableChannel.class); + PollableChannel invalidChannel = ac.getBean("invalidOutputChannel", PollableChannel.class); + MessageChannel inputChannel = ac.getBean("inputChannel", MessageChannel.class); + inputChannel.send(docMessage); + assertNotNull(invalidChannel.receive(100)); + assertNull(validChannel.receive(100)); + } +} diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XmlPayloadValidatingRouterParserTests.java b/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XmlPayloadValidatingRouterParserTests.java deleted file mode 100644 index dac5ed6fdc..0000000000 --- a/spring-integration-xml/src/test/java/org/springframework/integration/xml/config/XmlPayloadValidatingRouterParserTests.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2002-2010 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.integration.xml.config; - -import static org.junit.Assert.assertEquals; - -import org.junit.After; -import org.junit.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.beans.factory.config.AutowireCapableBeanFactory; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.integration.MessageChannel; -import org.springframework.integration.channel.QueueChannel; -import org.springframework.integration.endpoint.EventDrivenConsumer; -import org.springframework.integration.message.GenericMessage; -import org.springframework.integration.xml.util.XmlTestUtil; -import org.springframework.test.context.ContextConfiguration; -import org.w3c.dom.Document; - -/** - * @author Jonas Partner - */ -@ContextConfiguration -public class XmlPayloadValidatingRouterParserTests { - - String channelConfig = " "; - - @Autowired @Qualifier("test-input") - MessageChannel inputChannel; - - @Autowired @Qualifier("validOutputChannel") - QueueChannel validOutputChannel; - - @Autowired @Qualifier("invalidOutputChannel") - QueueChannel invalidOutputChannel; - - - ConfigurableApplicationContext appContext; - - public EventDrivenConsumer buildContext(String routerDef){ - appContext = TestXmlApplicationContextHelper.getTestAppContext( channelConfig + routerDef); - appContext.getAutowireCapableBeanFactory().autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false); - EventDrivenConsumer consumer = (EventDrivenConsumer) appContext.getBean("router"); - consumer.start(); - return consumer; - } - - @After - public void tearDown(){ - if(appContext != null){ - appContext.close(); - } - } - - @Test - public void testValidMessage() throws Exception { - Document doc = XmlTestUtil.getDocumentForString("hello"); - GenericMessage docMessage = new GenericMessage(doc); - buildContext(""); - inputChannel.send(docMessage); - assertEquals("Wrong number of messages", 1, validOutputChannel.getQueueSize()); - } - - @Test - public void testInvalidMessage() throws Exception { - Document doc = XmlTestUtil.getDocumentForString(""); - GenericMessage docMessage = new GenericMessage(doc); - buildContext(""); - inputChannel.send(docMessage); - assertEquals("Wrong number of messages", 1, invalidOutputChannel.getQueueSize()); - } - -} diff --git a/spring-integration-xml/src/test/java/org/springframework/integration/xml/router/XmlPayloadValidatingRouterTests.java b/spring-integration-xml/src/test/java/org/springframework/integration/xml/router/XmlPayloadValidatingRouterTests.java deleted file mode 100644 index 48e3b526a6..0000000000 --- a/spring-integration-xml/src/test/java/org/springframework/integration/xml/router/XmlPayloadValidatingRouterTests.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.springframework.integration.xml.router; - -import static org.junit.Assert.*; - -import javax.xml.transform.Source; -import javax.xml.transform.sax.SAXSource; - -import org.junit.Before; -/* - * Copyright 2002-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. - */ - -import org.junit.Test; -import org.springframework.integration.Message; -import org.springframework.integration.support.MessageBuilder; - -public class XmlPayloadValidatingRouterTests { - - String validChannelName = "VALID"; - - String invalidChannelName = "INVALID"; - - Source testSource; - - Message testMessage; - - @Before - public void setUp(){ - testSource = new SAXSource(); - testMessage = MessageBuilder.withPayload(testSource).build(); - } - - @Test - public void testValidMessage(){ - StubValidator validator = new StubValidator(true); - XmlPayloadValidatingRouter router = new XmlPayloadValidatingRouter(validChannelName, invalidChannelName, validator); - String returnedChannelName = router.determineTargetChannelName(testMessage); - assertEquals("Wrong channel name", validChannelName, returnedChannelName); - assertEquals("Source not passed to validator ", testSource, validator.passedIn); - } - - @Test - public void testInvalidMessage(){ - StubValidator validator = new StubValidator(false); - XmlPayloadValidatingRouter router = new XmlPayloadValidatingRouter(validChannelName, invalidChannelName, validator); - String returnedChannelName = router.determineTargetChannelName(testMessage); - assertEquals("Wrong channel name", invalidChannelName, returnedChannelName); - assertEquals("Source not passed to validator ", testSource, validator.passedIn); - } - - - static class StubValidator implements XmlValidator { - - private final boolean validationResult; - - Source passedIn; - - public StubValidator(boolean validationResult) { - this.validationResult = validationResult; - } - - public boolean isValid(Source source) { - passedIn = source; - return validationResult; - } - - } - -}