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, label = "advanced", 052 description = "Configures the W3C XML Schema Namespace URI.") 053 private String schemaLanguage = XMLConstants.W3C_XML_SCHEMA_NS_URI; 054 @UriParam(label = "advanced", description = "To use a custom javax.xml.validation.SchemaFactory") 055 private SchemaFactory schemaFactory; 056 @UriParam(label = "advanced", description = "To use a custom org.apache.camel.processor.validation.ValidatorErrorHandler. The default error handler captures the errors and throws an exception.") 057 private ValidatorErrorHandler errorHandler = new DefaultValidationErrorHandler(); 058 @UriParam(label = "advanced", description = "Whether DOMSource/DOMResult or SaxSource/SaxResult should be used by the validator.") 059 private boolean useDom; 060 @UriParam(defaultValue = "true", label = "advanced", 061 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.") 062 private boolean useSharedSchema = true; 063 @UriParam(label = "advanced", description = "To use a custom LSResourceResolver") 064 private LSResourceResolver resourceResolver; 065 @UriParam(defaultValue = "true", description = "Whether to fail if no body exists.") 066 private boolean failOnNullBody = true; 067 @UriParam(defaultValue = "true", description = "Whether to fail if no header exists when validating against a header.") 068 private boolean failOnNullHeader = true; 069 @UriParam(description = "To validate against a header instead of the message body.") 070 private String headerName; 071 072 public ValidatorEndpoint() { 073 } 074 075 public ValidatorEndpoint(String endpointUri, Component component, String resourceUri) { 076 super(endpointUri, component); 077 this.resourceUri = resourceUri; 078 } 079 080 @Override 081 public Producer createProducer() throws Exception { 082 ValidatingProcessor validator = new ValidatingProcessor(); 083 084 InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(getCamelContext().getClassResolver(), resourceUri); 085 byte[] bytes = null; 086 try { 087 bytes = IOConverter.toBytes(is); 088 } finally { 089 // and make sure to close the input stream after the schema has been loaded 090 IOHelper.close(is); 091 } 092 093 validator.setSchemaAsByteArray(bytes); 094 LOG.debug("{} using schema resource: {}", this, resourceUri); 095 configureValidator(validator); 096 097 // force loading of schema at create time otherwise concurrent 098 // processing could cause thread safe issues for the javax.xml.validation.SchemaFactory 099 validator.loadSchema(); 100 101 return new ValidatorProducer(this, validator); 102 } 103 104 @Override 105 public Consumer createConsumer(Processor processor) throws Exception { 106 throw new UnsupportedOperationException("Cannot consume from validator"); 107 } 108 109 @Override 110 public boolean isSingleton() { 111 return true; 112 } 113 114 protected void configureValidator(ValidatingProcessor validator) throws Exception { 115 if (resourceResolver != null) { 116 validator.setResourceResolver(resourceResolver); 117 } else { 118 validator.setResourceResolver(new DefaultLSResourceResolver(getCamelContext(), resourceUri)); 119 } 120 validator.setSchemaLanguage(getSchemaLanguage()); 121 validator.setSchemaFactory(getSchemaFactory()); 122 validator.setErrorHandler(getErrorHandler()); 123 validator.setUseDom(isUseDom()); 124 validator.setUseSharedSchema(isUseSharedSchema()); 125 validator.setFailOnNullBody(isFailOnNullBody()); 126 validator.setFailOnNullHeader(isFailOnNullHeader()); 127 validator.setHeaderName(getHeaderName()); 128 } 129 130 public String getResourceUri() { 131 return resourceUri; 132 } 133 134 /** 135 * 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. 136 */ 137 public void setResourceUri(String resourceUri) { 138 this.resourceUri = resourceUri; 139 } 140 141 public String getSchemaLanguage() { 142 return schemaLanguage; 143 } 144 145 /** 146 * Configures the W3C XML Schema Namespace URI. 147 */ 148 public void setSchemaLanguage(String schemaLanguage) { 149 this.schemaLanguage = schemaLanguage; 150 } 151 152 public SchemaFactory getSchemaFactory() { 153 return schemaFactory; 154 } 155 156 /** 157 * To use a custom javax.xml.validation.SchemaFactory 158 */ 159 public void setSchemaFactory(SchemaFactory schemaFactory) { 160 this.schemaFactory = schemaFactory; 161 } 162 163 public ValidatorErrorHandler getErrorHandler() { 164 return errorHandler; 165 } 166 167 /** 168 * To use a custom org.apache.camel.processor.validation.ValidatorErrorHandler. 169 * <p/> 170 * The default error handler captures the errors and throws an exception. 171 */ 172 public void setErrorHandler(ValidatorErrorHandler errorHandler) { 173 this.errorHandler = errorHandler; 174 } 175 176 public boolean isUseDom() { 177 return useDom; 178 } 179 180 /** 181 * Whether DOMSource/DOMResult or SaxSource/SaxResult should be used by the validator. 182 */ 183 public void setUseDom(boolean useDom) { 184 this.useDom = useDom; 185 } 186 187 public boolean isUseSharedSchema() { 188 return useSharedSchema; 189 } 190 191 /** 192 * 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. 193 */ 194 public void setUseSharedSchema(boolean useSharedSchema) { 195 this.useSharedSchema = useSharedSchema; 196 } 197 198 public LSResourceResolver getResourceResolver() { 199 return resourceResolver; 200 } 201 202 /** 203 * To use a custom LSResourceResolver 204 */ 205 public void setResourceResolver(LSResourceResolver resourceResolver) { 206 this.resourceResolver = resourceResolver; 207 } 208 209 public boolean isFailOnNullBody() { 210 return failOnNullBody; 211 } 212 213 /** 214 * Whether to fail if no body exists. 215 */ 216 public void setFailOnNullBody(boolean failOnNullBody) { 217 this.failOnNullBody = failOnNullBody; 218 } 219 220 public boolean isFailOnNullHeader() { 221 return failOnNullHeader; 222 } 223 224 /** 225 * Whether to fail if no header exists when validating against a header. 226 */ 227 public void setFailOnNullHeader(boolean failOnNullHeader) { 228 this.failOnNullHeader = failOnNullHeader; 229 } 230 231 public String getHeaderName() { 232 return headerName; 233 } 234 235 /** 236 * To validate against a header instead of the message body. 237 */ 238 public void setHeaderName(String headerName) { 239 this.headerName = headerName; 240 } 241}