Author: davsclaus
Date: Tue Feb 19 19:38:04 2013
New Revision: 1447881

URL: http://svn.apache.org/r1447881
Log:
CAMEL-6047: Added headerName option to validator component. Thanks to Laurynas 
Lubys for the patch.

Added:
    
camel/trunk/camel-core/src/main/java/org/apache/camel/processor/validation/NoXmlHeaderValidationException.java
Modified:
    
camel/trunk/camel-core/src/main/java/org/apache/camel/processor/validation/ValidatingProcessor.java
    
camel/trunk/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorRouteTest.java

Added: 
camel/trunk/camel-core/src/main/java/org/apache/camel/processor/validation/NoXmlHeaderValidationException.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/processor/validation/NoXmlHeaderValidationException.java?rev=1447881&view=auto
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/processor/validation/NoXmlHeaderValidationException.java
 (added)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/processor/validation/NoXmlHeaderValidationException.java
 Tue Feb 19 19:38:04 2013
@@ -0,0 +1,37 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.camel.processor.validation;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.ValidationException;
+
+/**
+ * An exception thrown if the XML header is not available on the inbound 
message
+ *
+ * @version 
+ */
+public class NoXmlHeaderValidationException extends ValidationException {
+    private static final long serialVersionUID = 4502520681354358599L;
+
+    public NoXmlHeaderValidationException(Exchange exchange, String header) {
+        super(exchange, "XML header \"" + header + "\" could not be found on 
the input message");
+    }
+
+    public NoXmlHeaderValidationException(Exchange exchange, String header, 
Throwable cause) {
+        super("XML header \"" + header + "\"  could not found on the input 
message", exchange, cause);
+    }
+}

Modified: 
camel/trunk/camel-core/src/main/java/org/apache/camel/processor/validation/ValidatingProcessor.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/processor/validation/ValidatingProcessor.java?rev=1447881&r1=1447880&r2=1447881&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/main/java/org/apache/camel/processor/validation/ValidatingProcessor.java
 (original)
+++ 
camel/trunk/camel-core/src/main/java/org/apache/camel/processor/validation/ValidatingProcessor.java
 Tue Feb 19 19:38:04 2013
@@ -55,8 +55,6 @@ import org.slf4j.LoggerFactory;
 /**
  * A processor which validates the XML version of the inbound message body
  * against some schema either in XSD or RelaxNG
- * 
- * @version
  */
 public class ValidatingProcessor implements Processor {
     private static final Logger LOG = 
LoggerFactory.getLogger(ValidatingProcessor.class);
@@ -72,6 +70,8 @@ public class ValidatingProcessor impleme
     private boolean useSharedSchema = true;
     private LSResourceResolver resourceResolver;
     private boolean failOnNullBody = true;
+    private boolean failOnNullHeader = true;
+    private String headerName;
 
     public void process(Exchange exchange) throws Exception {
         Schema schema;
@@ -90,19 +90,26 @@ public class ValidatingProcessor impleme
             Result result = null;
             // only convert to input stream if really needed
             if (isInputStreamNeeded(exchange)) {
-                is = exchange.getIn().getBody(InputStream.class);
+                is = getContentToValidate(exchange, InputStream.class);
                 if (is != null) {
                     source = getSource(exchange, is);
                 }
             } else {
-                Object body = exchange.getIn().getBody();
-                if (body != null) {
-                    source = getSource(exchange, body);
+                Object content = getContentToValidate(exchange);
+                if (content != null) {
+                    source = getSource(exchange, content);
                 }
             }
 
-            if (source == null && isFailOnNullBody()) {
-                throw new NoXmlBodyValidationException(exchange);
+            if (shouldUseHeader()) {
+                if (source == null && isFailOnNullHeader()) {
+                    throw new NoXmlHeaderValidationException(exchange,
+                            headerName);
+                }
+            } else {
+                if (source == null && isFailOnNullBody()) {
+                    throw new NoXmlBodyValidationException(exchange);
+                }
             }
 
             if (source instanceof DOMSource) {
@@ -129,8 +136,8 @@ public class ValidatingProcessor impleme
                 } 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());
+                            Collections.<SAXParseException>emptyList(),
+                            Collections.<SAXParseException>emptyList());
                 }
             }
         } finally {
@@ -138,6 +145,26 @@ public class ValidatingProcessor impleme
         }
     }
 
+    private Object getContentToValidate(Exchange exchange) {
+        if (shouldUseHeader()) {
+            return exchange.getIn().getHeader(headerName);
+        } else {
+            return exchange.getIn().getBody();
+        }
+    }
+
+    private <T> T getContentToValidate(Exchange exchange, Class<T> clazz) {
+        if (shouldUseHeader()) {
+            return exchange.getIn().getHeader(headerName, clazz);
+        } else {
+            return exchange.getIn().getBody(clazz);
+        }
+    }
+
+    private boolean shouldUseHeader() {
+        return headerName != null;
+    }
+
     public void loadSchema() throws Exception {
         // force loading of schema
         schema = createSchema();
@@ -250,6 +277,22 @@ public class ValidatingProcessor impleme
         this.failOnNullBody = failOnNullBody;
     }
 
+    public boolean isFailOnNullHeader() {
+        return failOnNullHeader;
+    }
+
+    public void setFailOnNullHeader(boolean failOnNullHeader) {
+        this.failOnNullHeader = failOnNullHeader;
+    }
+
+    public String getHeaderName() {
+        return headerName;
+    }
+
+    public void setHeaderName(String headerName) {
+        this.headerName = headerName;
+    }
+
     // Implementation methods
     // -----------------------------------------------------------------------
 
@@ -280,31 +323,31 @@ public class ValidatingProcessor impleme
     }
 
     /**
-     * Checks whether we need an {@link InputStream} to access the message 
body.
+     * Checks whether we need an {@link InputStream} to access the message 
body or header.
      * <p/>
-     * Depending on the content in the message body, we may not need to convert
+     * Depending on the content in the message body or header, 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) {
+        Object content = getContentToValidate(exchange);
+        if (content == null) {
             return false;
         }
 
-        if (body instanceof InputStream) {
+        if (content instanceof InputStream) {
             return true;
-        } else if (body instanceof Source) {
+        } else if (content instanceof Source) {
             return false;
-        } else if (body instanceof String) {
+        } else if (content instanceof String) {
             return false;
-        } else if (body instanceof byte[]) {
+        } else if (content instanceof byte[]) {
             return false;
-        } else if (body instanceof Node) {
+        } else if (content instanceof Node) {
             return false;
-        } else if 
(exchange.getContext().getTypeConverterRegistry().lookup(Source.class, 
body.getClass()) != null) {
+        } else if 
(exchange.getContext().getTypeConverterRegistry().lookup(Source.class, 
content.getClass()) != null) {
             //there is a direct and hopefully optimized converter to Source
             return false;
         }
@@ -313,48 +356,48 @@ public class ValidatingProcessor impleme
     }
 
     /**
-     * Converts the inbound body to a {@link Source}, if the body is 
<b>not</b> already a {@link Source}.
+     * Converts the inbound body or header to a {@link Source}, if it 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>
+     * <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) {
+    protected Source getSource(Exchange exchange, Object content) {
         if (isUseDom()) {
             // force DOM
-            return 
exchange.getContext().getTypeConverter().tryConvertTo(DOMSource.class, 
exchange, body);
+            return 
exchange.getContext().getTypeConverter().tryConvertTo(DOMSource.class, 
exchange, content);
         }
 
-        // body may already be a source
-        if (body instanceof Source) {
-            return (Source) body;
+        // body or header may already be a source
+        if (content instanceof Source) {
+            return (Source) content;
         }
         Source source = null;
-        if (body instanceof InputStream) {
-            return new StreamSource((InputStream)body);
+        if (content instanceof InputStream) {
+            return new StreamSource((InputStream) content);
         }
-        if (body != null) {
-            TypeConverter tc = 
exchange.getContext().getTypeConverterRegistry().lookup(Source.class, 
body.getClass());
+        if (content != null) {
+            TypeConverter tc = 
exchange.getContext().getTypeConverterRegistry().lookup(Source.class, 
content.getClass());
             if (tc != null) {
-                source = tc.convertTo(Source.class, exchange, body);
+                source = tc.convertTo(Source.class, exchange, content);
             }
         }
 
         if (source == null) {
             // then try SAX
-            source = 
exchange.getContext().getTypeConverter().tryConvertTo(SAXSource.class, 
exchange, body);
+            source = 
exchange.getContext().getTypeConverter().tryConvertTo(SAXSource.class, 
exchange, content);
         }
         if (source == null) {
             // then try stream
-            source = 
exchange.getContext().getTypeConverter().tryConvertTo(StreamSource.class, 
exchange, body);
+            source = 
exchange.getContext().getTypeConverter().tryConvertTo(StreamSource.class, 
exchange, content);
         }
         if (source == null) {
             // and fallback to DOM
-            source = 
exchange.getContext().getTypeConverter().tryConvertTo(DOMSource.class, 
exchange, body);
+            source = 
exchange.getContext().getTypeConverter().tryConvertTo(DOMSource.class, 
exchange, content);
         }
         if (source == null) {
             if (isFailOnNullBody()) {

Modified: 
camel/trunk/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorRouteTest.java
URL: 
http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorRouteTest.java?rev=1447881&r1=1447880&r2=1447881&view=diff
==============================================================================
--- 
camel/trunk/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorRouteTest.java
 (original)
+++ 
camel/trunk/camel-core/src/test/java/org/apache/camel/component/validator/ValidatorRouteTest.java
 Tue Feb 19 19:38:04 2013
@@ -17,9 +17,12 @@
 package org.apache.camel.component.validator;
 
 import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.ExchangePattern;
 import org.apache.camel.ValidationException;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.processor.validation.NoXmlHeaderValidationException;
 
 /**
  *
@@ -40,6 +43,18 @@ public class ValidatorRouteTest extends 
         MockEndpoint.assertIsSatisfied(validEndpoint, invalidEndpoint, 
finallyEndpoint);
     }
 
+    public void testValidMessageInHeader() throws Exception {
+        validEndpoint.expectedMessageCount(1);
+        finallyEndpoint.expectedMessageCount(1);
+
+        template.sendBodyAndHeader("direct:startHeaders",
+                null,
+                "headerToValidate",
+                "<mail 
xmlns='http://foo.com/bar'><subject>Hey</subject><body>Hello 
world!</body></mail>");
+
+        MockEndpoint.assertIsSatisfied(validEndpoint, invalidEndpoint, 
finallyEndpoint);
+    }
+
     public void testInvalidMessage() throws Exception {
         invalidEndpoint.expectedMessageCount(1);
         finallyEndpoint.expectedMessageCount(1);
@@ -49,7 +64,45 @@ public class ValidatorRouteTest extends 
 
         MockEndpoint.assertIsSatisfied(validEndpoint, invalidEndpoint, 
finallyEndpoint);
     }
-    
+
+    public void testInvalidMessageInHeader() throws Exception {
+        invalidEndpoint.expectedMessageCount(1);
+        finallyEndpoint.expectedMessageCount(1);
+
+        template.sendBodyAndHeader("direct:startHeaders",
+                null,
+                "headerToValidate",
+                "<mail xmlns='http://foo.com/bar'><body>Hello 
world!</body></mail>");
+
+        MockEndpoint.assertIsSatisfied(validEndpoint, invalidEndpoint, 
finallyEndpoint);
+    }
+
+    public void testNullHeaderNoFail() throws Exception {
+        validEndpoint.expectedMessageCount(1);
+
+        template.sendBodyAndHeader("direct:startNullHeaderNoFail", null, 
"headerToValidate", null);
+
+        MockEndpoint.assertIsSatisfied(validEndpoint);
+    }
+
+    public void testNullHeader() throws Exception {
+        validEndpoint.setExpectedMessageCount(0);
+
+        Exchange in = 
resolveMandatoryEndpoint("direct:startNoHeaderException").createExchange(ExchangePattern.InOut);
+
+        in.getIn().setBody(null);
+        in.getIn().setHeader("headerToValidate", null);
+
+        Exchange out = template.send("direct:startNoHeaderException", in);
+
+        MockEndpoint.assertIsSatisfied(validEndpoint, invalidEndpoint, 
finallyEndpoint);
+
+        Exception exception = out.getException();
+        assertTrue("Should be failed", out.isFailed());
+        assertTrue("Exception should be correct type", exception instanceof 
NoXmlHeaderValidationException);
+        assertTrue("Exception should mention missing header", 
exception.getMessage().contains("headerToValidate"));
+    }
+
     public void testInvalideBytesMessage() throws Exception {
         invalidEndpoint.expectedMessageCount(1);
         finallyEndpoint.expectedMessageCount(1);
@@ -60,6 +113,18 @@ public class ValidatorRouteTest extends 
         MockEndpoint.assertIsSatisfied(validEndpoint, invalidEndpoint, 
finallyEndpoint);
     }
 
+    public void testInvalidBytesMessageInHeader() throws Exception {
+        invalidEndpoint.expectedMessageCount(1);
+        finallyEndpoint.expectedMessageCount(1);
+
+        template.sendBodyAndHeader("direct:startHeaders",
+                null,
+                "headerToValidate",
+                "<mail xmlns='http://foo.com/bar'><body>Hello 
world!</body></mail>".getBytes());
+
+        MockEndpoint.assertIsSatisfied(validEndpoint, invalidEndpoint, 
finallyEndpoint);
+    }
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -83,6 +148,24 @@ public class ValidatorRouteTest extends 
                     .doFinally()
                         .to("mock:finally")
                     .end();
+
+                from("direct:startHeaders")
+                    .doTry()
+                        
.to("validator:org/apache/camel/component/validator/schema.xsd?headerName=headerToValidate")
+                        .to("mock:valid")
+                    .doCatch(ValidationException.class)
+                        .to("mock:invalid")
+                    .doFinally()
+                        .to("mock:finally")
+                    .end();
+
+                from("direct:startNoHeaderException")
+                        
.to("validator:org/apache/camel/component/validator/schema.xsd?headerName=headerToValidate")
+                        .to("mock:valid");
+
+                from("direct:startNullHeaderNoFail")
+                        
.to("validator:org/apache/camel/component/validator/schema.xsd?headerName=headerToValidate&failOnNullHeader=false")
+                        .to("mock:valid");
             }
         };
     }


Reply via email to