You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2012/10/17 18:43:15 UTC
svn commit: r1399335 - in /camel/branches/camel-2.10.x: ./
camel-core/src/main/java/org/apache/camel/component/validator/
camel-core/src/main/java/org/apache/camel/processor/validation/
camel-core/src/test/java/org/apache/camel/component/validator/
Author: davsclaus
Date: Wed Oct 17 16:43:15 2012
New Revision: 1399335
URL: http://svn.apache.org/viewvc?rev=1399335&view=rev
Log:
CAMEL-5608: Ensure validator component closes input stream after usage. Align code with the xlst/xpath is doing. Added option to fail if no body or not.
Modified:
camel/branches/camel-2.10.x/ (props changed)
camel/branches/camel-2.10.x/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorComponent.java
camel/branches/camel-2.10.x/camel-core/src/main/java/org/apache/camel/processor/validation/ValidatingProcessor.java
camel/branches/camel-2.10.x/camel-core/src/test/java/org/apache/camel/component/validator/FileValidatorRouteTest.java
Propchange: camel/branches/camel-2.10.x/
------------------------------------------------------------------------------
Merged /camel/trunk:r1399333
Propchange: camel/branches/camel-2.10.x/
------------------------------------------------------------------------------
Binary property 'svnmerge-integrated' - no diff available.
Modified: camel/branches/camel-2.10.x/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorComponent.java
URL: http://svn.apache.org/viewvc/camel/branches/camel-2.10.x/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorComponent.java?rev=1399335&r1=1399334&r2=1399335&view=diff
==============================================================================
--- camel/branches/camel-2.10.x/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorComponent.java (original)
+++ camel/branches/camel-2.10.x/camel-core/src/main/java/org/apache/camel/component/validator/ValidatorComponent.java Wed Oct 17 16:43:15 2012
@@ -27,6 +27,7 @@ import org.apache.camel.Endpoint;
import org.apache.camel.impl.DefaultComponent;
import org.apache.camel.impl.ProcessorEndpoint;
import org.apache.camel.processor.validation.ValidatingProcessor;
+import org.apache.camel.util.IOHelper;
import org.apache.camel.util.ResourceHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -52,6 +53,8 @@ public class ValidatorComponent extends
// force loading of schema at create time otherwise concurrent
// processing could cause thread safe issues for the javax.xml.validation.SchemaFactory
validator.loadSchema();
+ // and make sure to close the input stream after the schema has been loaded
+ IOHelper.close(is);
return new ProcessorEndpoint(uri, this, validator);
}
Modified: camel/branches/camel-2.10.x/camel-core/src/main/java/org/apache/camel/processor/validation/ValidatingProcessor.java
URL: http://svn.apache.org/viewvc/camel/branches/camel-2.10.x/camel-core/src/main/java/org/apache/camel/processor/validation/ValidatingProcessor.java?rev=1399335&r1=1399334&r2=1399335&view=diff
==============================================================================
--- camel/branches/camel-2.10.x/camel-core/src/main/java/org/apache/camel/processor/validation/ValidatingProcessor.java (original)
+++ camel/branches/camel-2.10.x/camel-core/src/main/java/org/apache/camel/processor/validation/ValidatingProcessor.java Wed Oct 17 16:43:15 2012
@@ -18,27 +18,39 @@ package org.apache.camel.processor.valid
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
import java.net.URL;
import java.util.Collections;
-
import javax.xml.XMLConstants;
+import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.stax.StAXSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
+import org.w3c.dom.Node;
import org.w3c.dom.ls.LSResourceResolver;
-
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.apache.camel.Exchange;
+import org.apache.camel.ExpectedBodyTypeException;
import org.apache.camel.Processor;
+import org.apache.camel.RuntimeTransformException;
+import org.apache.camel.TypeConverter;
+import org.apache.camel.converter.jaxp.XmlConverter;
+import org.apache.camel.util.IOHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* A processor which validates the XML version of the inbound message body
@@ -47,7 +59,8 @@ import org.apache.camel.Processor;
* @version
*/
public class ValidatingProcessor implements Processor {
- // for lazy creation of the Schema
+ private static final Logger LOG = LoggerFactory.getLogger(ValidatingProcessor.class);
+ private XmlConverter converter = new XmlConverter();
private String schemaLanguage = XMLConstants.W3C_XML_SCHEMA_NS_URI;
private Schema schema;
private Source schemaSource;
@@ -58,6 +71,7 @@ public class ValidatingProcessor impleme
private boolean useDom;
private boolean useSharedSchema = true;
private LSResourceResolver resourceResolver;
+ private boolean failOnNullBody = true;
public void process(Exchange exchange) throws Exception {
Schema schema;
@@ -69,39 +83,59 @@ public class ValidatingProcessor impleme
Validator validator = schema.newValidator();
- Source source;
- Result result;
+ // the underlying input stream, which we need to close to avoid locking files or other resources
+ Source source = null;
+ InputStream is = null;
try {
- if (useDom) {
- source = exchange.getIn().getBody(DOMSource.class);
- result = new DOMResult();
+ Result result = null;
+ // only convert to input stream if really needed
+ if (isInputStreamNeeded(exchange)) {
+ is = exchange.getIn().getBody(InputStream.class);
+ if (is != null) {
+ source = getSource(exchange, is);
+ }
} else {
- source = exchange.getIn().getBody(SAXSource.class);
- result = new SAXResult();
+ Object body = exchange.getIn().getBody();
+ if (body != null) {
+ source = getSource(exchange, body);
+ }
}
- } catch (Exception e) {
- throw new NoXmlBodyValidationException(exchange, e);
- }
- if (source == null) {
- throw new NoXmlBodyValidationException(exchange);
- }
- // create a new errorHandler and set it on the validator
- // must be a local instance to avoid problems with concurrency (to be
- // thread safe)
- ValidatorErrorHandler handler = errorHandler.getClass().newInstance();
- validator.setErrorHandler(handler);
+ if (source == null && isFailOnNullBody()) {
+ throw new NoXmlBodyValidationException(exchange);
+ }
- try {
- validator.validate(source, result);
- } catch (SAXParseException e) {
- // can be thrown for non well formed XML
- throw new SchemaValidationException(exchange, schema, Collections.singletonList(e),
- Collections.<SAXParseException> emptyList(),
- Collections.<SAXParseException> emptyList());
- }
+ if (source instanceof DOMSource) {
+ result = new DOMResult();
+ } else if (source instanceof StreamSource) {
+ result = new StreamResult(new StringWriter());
+ } else if (source instanceof SAXSource) {
+ result = new SAXResult();
+ } else if (source instanceof StAXSource) {
+ result = null;
+ }
- handler.handleErrors(exchange, schema, result);
+ if (source != null) {
+ // create a new errorHandler and set it on the validator
+ // must be a local instance to avoid problems with concurrency (to be
+ // thread safe)
+ ValidatorErrorHandler handler = errorHandler.getClass().newInstance();
+ validator.setErrorHandler(handler);
+
+ try {
+ LOG.trace("Validating {}", source);
+ validator.validate(source, result);
+ handler.handleErrors(exchange, schema, result);
+ } catch (SAXParseException e) {
+ // can be thrown for non well formed XML
+ throw new SchemaValidationException(exchange, schema, Collections.singletonList(e),
+ Collections.<SAXParseException> emptyList(),
+ Collections.<SAXParseException> emptyList());
+ }
+ }
+ } finally {
+ IOHelper.close(is);
+ }
}
public void loadSchema() throws Exception {
@@ -177,17 +211,17 @@ public class ValidatingProcessor impleme
this.errorHandler = errorHandler;
}
+ @Deprecated
public boolean isUseDom() {
return useDom;
}
/**
- * Sets whether DOMSource and DOMResult should be used, or SaxSource and
- * SaxResult.
- *
- * @param useDom
- * true to use DOM otherwise Sax is used
+ * Sets whether DOMSource and DOMResult should be used.
+ *
+ * @param useDom true to use DOM otherwise
*/
+ @Deprecated
public void setUseDom(boolean useDom) {
this.useDom = useDom;
}
@@ -208,6 +242,14 @@ public class ValidatingProcessor impleme
this.resourceResolver = resourceResolver;
}
+ public boolean isFailOnNullBody() {
+ return failOnNullBody;
+ }
+
+ public void setFailOnNullBody(boolean failOnNullBody) {
+ this.failOnNullBody = failOnNullBody;
+ }
+
// Implementation methods
// -----------------------------------------------------------------------
@@ -236,4 +278,96 @@ public class ValidatingProcessor impleme
}
return factory.newSchema(getSchemaSource());
}
+
+ /**
+ * Checks whether we need an {@link InputStream} to access the message body.
+ * <p/>
+ * Depending on the content in the message body, we may not need to convert
+ * to {@link InputStream}.
+ *
+ * @param exchange the current exchange
+ * @return <tt>true</tt> to convert to {@link InputStream} beforehand converting to {@link Source} afterwards.
+ */
+ protected boolean isInputStreamNeeded(Exchange exchange) {
+ Object body = exchange.getIn().getBody();
+ if (body == null) {
+ return false;
+ }
+
+ if (body instanceof InputStream) {
+ return true;
+ } else if (body instanceof Source) {
+ return false;
+ } else if (body instanceof String) {
+ return false;
+ } else if (body instanceof byte[]) {
+ return false;
+ } else if (body instanceof Node) {
+ return false;
+ } else if (exchange.getContext().getTypeConverterRegistry().lookup(Source.class, body.getClass()) != null) {
+ //there is a direct and hopefully optimized converter to Source
+ return false;
+ }
+ // yes an input stream is needed
+ return true;
+ }
+
+ /**
+ * Converts the inbound body to a {@link Source}, if the body is <b>not</b> already a {@link Source}.
+ * <p/>
+ * This implementation will prefer to source in the following order:
+ * <ul>
+ * <li>DOM - DOM if explicit configured to use DOM</li>
+ * <li>SAX - SAX as 2nd choice</li>
+ * <li>Stream - Stream as 3rd choice</li>
+ * <li>DOM - DOM as 4th choice</li>
+ * </ul>
+ */
+ protected Source getSource(Exchange exchange, Object body) {
+ if (isUseDom()) {
+ // force DOM
+ return exchange.getContext().getTypeConverter().tryConvertTo(DOMSource.class, exchange, body);
+ }
+
+ // body may already be a source
+ if (body instanceof Source) {
+ return (Source) body;
+ }
+ Source source = null;
+ if (body instanceof InputStream) {
+ return new StreamSource((InputStream)body);
+ }
+ if (body != null) {
+ TypeConverter tc = exchange.getContext().getTypeConverterRegistry().lookup(Source.class, body.getClass());
+ if (tc != null) {
+ source = tc.convertTo(Source.class, body);
+ }
+ }
+
+ if (source == null) {
+ // then try SAX
+ source = exchange.getContext().getTypeConverter().tryConvertTo(SAXSource.class, exchange, body);
+ }
+ if (source == null) {
+ // then try stream
+ source = exchange.getContext().getTypeConverter().tryConvertTo(StreamSource.class, exchange, body);
+ }
+ if (source == null) {
+ // and fallback to DOM
+ source = exchange.getContext().getTypeConverter().tryConvertTo(DOMSource.class, exchange, body);
+ }
+ if (source == null) {
+ if (isFailOnNullBody()) {
+ throw new ExpectedBodyTypeException(exchange, Source.class);
+ } else {
+ try {
+ source = converter.toDOMSource(converter.createDocument());
+ } catch (ParserConfigurationException e) {
+ throw new RuntimeTransformException(e);
+ }
+ }
+ }
+ return source;
+ }
+
}
\ No newline at end of file
Modified: camel/branches/camel-2.10.x/camel-core/src/test/java/org/apache/camel/component/validator/FileValidatorRouteTest.java
URL: http://svn.apache.org/viewvc/camel/branches/camel-2.10.x/camel-core/src/test/java/org/apache/camel/component/validator/FileValidatorRouteTest.java?rev=1399335&r1=1399334&r2=1399335&view=diff
==============================================================================
--- camel/branches/camel-2.10.x/camel-core/src/test/java/org/apache/camel/component/validator/FileValidatorRouteTest.java (original)
+++ camel/branches/camel-2.10.x/camel-core/src/test/java/org/apache/camel/component/validator/FileValidatorRouteTest.java Wed Oct 17 16:43:15 2012
@@ -16,11 +16,14 @@
*/
package org.apache.camel.component.validator;
+import java.io.File;
+
import org.apache.camel.ContextTestSupport;
import org.apache.camel.Exchange;
import org.apache.camel.ValidationException;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.util.FileUtil;
/**
*
@@ -40,6 +43,10 @@ public class FileValidatorRouteTest exte
Exchange.FILE_NAME, "valid.xml");
MockEndpoint.assertIsSatisfied(validEndpoint, invalidEndpoint, finallyEndpoint);
+
+ // should be able to delete the file
+ oneExchangeDone.matchesMockWaitTime();
+ assertTrue("Should be able to delete the file", FileUtil.deleteFile(new File("target/validator/valid.xml")));
}
public void testInvalidMessage() throws Exception {
@@ -51,12 +58,15 @@ public class FileValidatorRouteTest exte
Exchange.FILE_NAME, "invalid.xml");
MockEndpoint.assertIsSatisfied(validEndpoint, invalidEndpoint, finallyEndpoint);
+
+ // should be able to delete the file
+ oneExchangeDone.matchesMockWaitTime();
+ assertTrue("Should be able to delete the file", FileUtil.deleteFile(new File("target/validator/invalid.xml")));
}
@Override
protected void setUp() throws Exception {
deleteDirectory("target/validator");
-
super.setUp();
validEndpoint = resolveMandatoryEndpoint("mock:valid", MockEndpoint.class);
invalidEndpoint = resolveMandatoryEndpoint("mock:invalid", MockEndpoint.class);
@@ -68,7 +78,7 @@ public class FileValidatorRouteTest exte
return new RouteBuilder() {
@Override
public void configure() throws Exception {
- from("file:target/validator")
+ from("file:target/validator?noop=true")
.doTry()
.to("validator:org/apache/camel/component/validator/schema.xsd")
.to("mock:valid")