INT-558 XmlPayloadValidatingRouter

This commit is contained in:
Jonas Partner
2009-02-16 13:13:55 +00:00
parent 977ab1b34a
commit d65d6d7c49
14 changed files with 579 additions and 2 deletions

View File

@@ -21,13 +21,15 @@ import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import org.springframework.integration.core.MessagingException;
import org.springframework.xml.transform.StringSource;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.springframework.integration.core.MessagingException;
/**
* Default implementation of {@link XmlPayloadConverter}.
* Supports {@link Document} and {@link String}.
@@ -70,6 +72,20 @@ public class DefaultXmlPayloadConverter implements XmlPayloadConverter {
}
return convertToDocument(object);
}
public Source convertToSource(Object object){
Source source;
if(object instanceof Source){
source = (Source)object;
} else if (object instanceof Document){
source = new DOMSource((Document)object);
} else if (object instanceof String){
source = new StringSource((String)object);
} else {
throw new MessagingException("unsupported payload type [" + object.getClass().getName() + "]");
}
return source;
}
protected synchronized DocumentBuilder getDocumentBuilder() {
try {

View File

@@ -16,6 +16,8 @@
package org.springframework.integration.xml;
import javax.xml.transform.Source;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
@@ -29,5 +31,7 @@ public interface XmlPayloadConverter {
public Document convertToDocument(Object object);
public Node convertToNode(Object object);
public Source convertToSource(Object object);
}

View File

@@ -31,6 +31,7 @@ public class IntegrationXmlNamespaceHandler extends NamespaceHandlerSupport {
registerBeanDefinitionParser("xpath-selector", new XPathSelectorParser());
registerBeanDefinitionParser("xpath-expression", new XPathExpressionParser());
registerBeanDefinitionParser("xpath-splitter", new XPathMessageSplitterParser());
registerBeanDefinitionParser("validating-router", new XmlPayloadValidatingRouterParser());
}
}

View File

@@ -0,0 +1,103 @@
/*
* 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 {
private XPathExpressionParser xpathParser = new XPathExpressionParser();
@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();
}
}

View File

@@ -277,6 +277,49 @@
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="validating-router">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>
Defines an validating router.
</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element ref="si-core:poller" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:string" use="required"/>
<xsd:attribute name="input-channel" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="channel-resolver" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.channel.ChannelResolver"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="valid-channel" type="xsd:string" use="required" />
<xsd:attribute name="invalid-channel" type="xsd:string" use="required" />
<xsd:attribute name="schema-location" use="required" />
<xsd:attribute name="schema-type" default="xml-schema">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="xml-schema"/>
<xsd:enumeration value="relax-ng"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="inputOutputEndpoint">
<xsd:sequence>

View File

@@ -0,0 +1,52 @@
/*
* 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 java.io.IOException;
import javax.xml.transform.Source;
import org.springframework.core.io.Resource;
import org.springframework.integration.core.MessagingException;
import org.springframework.xml.validation.XmlValidationException;
import org.springframework.xml.validation.XmlValidatorFactory;
import org.xml.sax.SAXParseException;
public class SchemaValidator implements XmlValidator {
private final org.springframework.xml.validation.XmlValidator xmlValidator;
public SchemaValidator(Resource schemaResource, String schemaLanguage)
throws IOException {
super();
this.xmlValidator = XmlValidatorFactory.createValidator(schemaResource,
schemaLanguage);
}
public boolean isValid(Source source) {
try {
SAXParseException[] exceptions = xmlValidator.validate(source);
return exceptions.length < 1;
} catch (IOException ioE) {
throw new MessagingException(
"Exception applying schema validation", ioE);
} catch (XmlValidationException validationException){
return false;
}
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.core.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;
}
}

View File

@@ -0,0 +1,25 @@
/*
* 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 javax.xml.transform.Source;
public interface XmlValidator {
public boolean isValid(Source source) ;
}