001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.component.validator; 018 019import java.io.InputStream; 020import javax.xml.XMLConstants; 021import javax.xml.validation.SchemaFactory; 022 023import org.w3c.dom.ls.LSResourceResolver; 024 025import org.apache.camel.Component; 026import org.apache.camel.Consumer; 027import org.apache.camel.Processor; 028import org.apache.camel.Producer; 029import org.apache.camel.converter.IOConverter; 030import org.apache.camel.impl.DefaultEndpoint; 031import org.apache.camel.processor.validation.DefaultValidationErrorHandler; 032import org.apache.camel.processor.validation.ValidatingProcessor; 033import org.apache.camel.processor.validation.ValidatorErrorHandler; 034import org.apache.camel.spi.Metadata; 035import org.apache.camel.spi.UriEndpoint; 036import org.apache.camel.spi.UriParam; 037import org.apache.camel.spi.UriPath; 038import org.apache.camel.util.IOHelper; 039import org.apache.camel.util.ResourceHelper; 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042 043@UriEndpoint(scheme = "validator", title = "Validator", syntax = "validator:resourceUri", producerOnly = true, label = "core,validation") 044public class ValidatorEndpoint extends DefaultEndpoint { 045 046 private static final Logger LOG = LoggerFactory.getLogger(ValidatorEndpoint.class); 047 048 @UriPath(description = "URL to a local resource on the classpath or a full URL to a remote resource or resource on the file system which contains the XSD to validate against.") 049 @Metadata(required = "true") 050 private String resourceUri; 051 @UriParam(defaultValue = XMLConstants.W3C_XML_SCHEMA_NS_URI, description = "Configures the W3C XML Schema Namespace URI.") 052 private String schemaLanguage = XMLConstants.W3C_XML_SCHEMA_NS_URI; 053 @UriParam(description = "To use a custom javax.xml.validation.SchemaFactory") 054 private SchemaFactory schemaFactory; 055 @UriParam(description = "To use a custom org.apache.camel.processor.validation.ValidatorErrorHandler. The default error handler captures the errors and throws an exception.") 056 private ValidatorErrorHandler errorHandler = new DefaultValidationErrorHandler(); 057 @UriParam(description = "Whether DOMSource/DOMResult or SaxSource/SaxResult should be used by the validator.") 058 private boolean useDom; 059 @UriParam(defaultValue = "true", description = "Whether the Schema instance should be shared or not. This option is introduced to work around a JDK 1.6.x bug. Xerces should not have this issue.") 060 private boolean useSharedSchema = true; 061 @UriParam(description = "To use a custom LSResourceResolver") 062 private LSResourceResolver resourceResolver; 063 @UriParam(defaultValue = "true", description = "Whether to fail if no body exists.") 064 private boolean failOnNullBody = true; 065 @UriParam(defaultValue = "true", description = "Whether to fail if no header exists when validating against a header.") 066 private boolean failOnNullHeader = true; 067 @UriParam(description = "To validate against a header instead of the message body.") 068 private String headerName; 069 070 public ValidatorEndpoint() { 071 } 072 073 public ValidatorEndpoint(String endpointUri, Component component, String resourceUri) { 074 super(endpointUri, component); 075 this.resourceUri = resourceUri; 076 } 077 078 @Override 079 public Producer createProducer() throws Exception { 080 ValidatingProcessor validator = new ValidatingProcessor(); 081 082 InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(getCamelContext().getClassResolver(), resourceUri); 083 byte[] bytes = null; 084 try { 085 bytes = IOConverter.toBytes(is); 086 } finally { 087 // and make sure to close the input stream after the schema has been loaded 088 IOHelper.close(is); 089 } 090 091 validator.setSchemaAsByteArray(bytes); 092 LOG.debug("{} using schema resource: {}", this, resourceUri); 093 configureValidator(validator); 094 095 // force loading of schema at create time otherwise concurrent 096 // processing could cause thread safe issues for the javax.xml.validation.SchemaFactory 097 validator.loadSchema(); 098 099 return new ValidatorProducer(this, validator); 100 } 101 102 @Override 103 public Consumer createConsumer(Processor processor) throws Exception { 104 throw new UnsupportedOperationException("Cannot consume from validator"); 105 } 106 107 @Override 108 public boolean isSingleton() { 109 return true; 110 } 111 112 protected void configureValidator(ValidatingProcessor validator) throws Exception { 113 if (resourceResolver != null) { 114 validator.setResourceResolver(resourceResolver); 115 } else { 116 validator.setResourceResolver(new DefaultLSResourceResolver(getCamelContext(), resourceUri)); 117 } 118 validator.setSchemaLanguage(getSchemaLanguage()); 119 validator.setSchemaFactory(getSchemaFactory()); 120 validator.setErrorHandler(getErrorHandler()); 121 validator.setUseDom(isUseDom()); 122 validator.setUseSharedSchema(isUseSharedSchema()); 123 validator.setFailOnNullBody(isFailOnNullBody()); 124 validator.setFailOnNullHeader(isFailOnNullHeader()); 125 validator.setHeaderName(getHeaderName()); 126 } 127 128 public String getResourceUri() { 129 return resourceUri; 130 } 131 132 /** 133 * URL to a local resource on the classpath or a full URL to a remote resource or resource on the file system which contains the XSD to validate against. 134 */ 135 public void setResourceUri(String resourceUri) { 136 this.resourceUri = resourceUri; 137 } 138 139 public String getSchemaLanguage() { 140 return schemaLanguage; 141 } 142 143 /** 144 * Configures the W3C XML Schema Namespace URI. 145 */ 146 public void setSchemaLanguage(String schemaLanguage) { 147 this.schemaLanguage = schemaLanguage; 148 } 149 150 public SchemaFactory getSchemaFactory() { 151 return schemaFactory; 152 } 153 154 /** 155 * To use a custom javax.xml.validation.SchemaFactory 156 */ 157 public void setSchemaFactory(SchemaFactory schemaFactory) { 158 this.schemaFactory = schemaFactory; 159 } 160 161 public ValidatorErrorHandler getErrorHandler() { 162 return errorHandler; 163 } 164 165 /** 166 * To use a custom org.apache.camel.processor.validation.ValidatorErrorHandler. 167 * <p/> 168 * The default error handler captures the errors and throws an exception. 169 */ 170 public void setErrorHandler(ValidatorErrorHandler errorHandler) { 171 this.errorHandler = errorHandler; 172 } 173 174 public boolean isUseDom() { 175 return useDom; 176 } 177 178 /** 179 * Whether DOMSource/DOMResult or SaxSource/SaxResult should be used by the validator. 180 */ 181 public void setUseDom(boolean useDom) { 182 this.useDom = useDom; 183 } 184 185 public boolean isUseSharedSchema() { 186 return useSharedSchema; 187 } 188 189 /** 190 * Whether the Schema instance should be shared or not. This option is introduced to work around a JDK 1.6.x bug. Xerces should not have this issue. 191 */ 192 public void setUseSharedSchema(boolean useSharedSchema) { 193 this.useSharedSchema = useSharedSchema; 194 } 195 196 public LSResourceResolver getResourceResolver() { 197 return resourceResolver; 198 } 199 200 /** 201 * To use a custom LSResourceResolver 202 */ 203 public void setResourceResolver(LSResourceResolver resourceResolver) { 204 this.resourceResolver = resourceResolver; 205 } 206 207 public boolean isFailOnNullBody() { 208 return failOnNullBody; 209 } 210 211 /** 212 * Whether to fail if no body exists. 213 */ 214 public void setFailOnNullBody(boolean failOnNullBody) { 215 this.failOnNullBody = failOnNullBody; 216 } 217 218 public boolean isFailOnNullHeader() { 219 return failOnNullHeader; 220 } 221 222 /** 223 * Whether to fail if no header exists when validating against a header. 224 */ 225 public void setFailOnNullHeader(boolean failOnNullHeader) { 226 this.failOnNullHeader = failOnNullHeader; 227 } 228 229 public String getHeaderName() { 230 return headerName; 231 } 232 233 /** 234 * To validate against a header instead of the message body. 235 */ 236 public void setHeaderName(String headerName) { 237 this.headerName = headerName; 238 } 239}