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 */
017 package org.apache.camel.processor.validation;
018
019 import java.io.File;
020 import java.io.IOException;
021 import java.net.URL;
022 import java.util.Collections;
023
024 import javax.xml.XMLConstants;
025 import javax.xml.transform.Result;
026 import javax.xml.transform.Source;
027 import javax.xml.transform.dom.DOMResult;
028 import javax.xml.transform.dom.DOMSource;
029 import javax.xml.transform.sax.SAXResult;
030 import javax.xml.transform.sax.SAXSource;
031 import javax.xml.validation.Schema;
032 import javax.xml.validation.SchemaFactory;
033 import javax.xml.validation.Validator;
034
035 import org.w3c.dom.ls.LSResourceResolver;
036
037 import org.xml.sax.SAXException;
038 import org.xml.sax.SAXParseException;
039
040 import org.apache.camel.Exchange;
041 import org.apache.camel.Processor;
042
043 /**
044 * A processor which validates the XML version of the inbound message body
045 * against some schema either in XSD or RelaxNG
046 *
047 * @version
048 */
049 public class ValidatingProcessor implements Processor {
050 // for lazy creation of the Schema
051 private String schemaLanguage = XMLConstants.W3C_XML_SCHEMA_NS_URI;
052 private Schema schema;
053 private Source schemaSource;
054 private SchemaFactory schemaFactory;
055 private URL schemaUrl;
056 private File schemaFile;
057 private ValidatorErrorHandler errorHandler = new DefaultValidationErrorHandler();
058 private boolean useDom;
059 private boolean useSharedSchema = true;
060 private LSResourceResolver resourceResolver;
061
062 public void process(Exchange exchange) throws Exception {
063 Schema schema;
064 if (isUseSharedSchema()) {
065 schema = getSchema();
066 } else {
067 schema = createSchema();
068 }
069
070 Validator validator = schema.newValidator();
071
072 Source source;
073 Result result;
074 try {
075 if (useDom) {
076 source = exchange.getIn().getBody(DOMSource.class);
077 result = new DOMResult();
078 } else {
079 source = exchange.getIn().getBody(SAXSource.class);
080 result = new SAXResult();
081 }
082 } catch (Exception e) {
083 throw new NoXmlBodyValidationException(exchange, e);
084 }
085 if (source == null) {
086 throw new NoXmlBodyValidationException(exchange);
087 }
088
089 // create a new errorHandler and set it on the validator
090 // must be a local instance to avoid problems with concurrency (to be
091 // thread safe)
092 ValidatorErrorHandler handler = errorHandler.getClass().newInstance();
093 validator.setErrorHandler(handler);
094
095 try {
096 validator.validate(source, result);
097 } catch (SAXParseException e) {
098 // can be thrown for non well formed XML
099 throw new SchemaValidationException(exchange, schema, Collections.singletonList(e),
100 Collections.<SAXParseException> emptyList(),
101 Collections.<SAXParseException> emptyList());
102 }
103
104 handler.handleErrors(exchange, schema, result);
105 }
106
107 public void loadSchema() throws Exception {
108 // force loading of schema
109 schema = createSchema();
110 }
111
112 // Properties
113 // -----------------------------------------------------------------------
114
115 public Schema getSchema() throws IOException, SAXException {
116 if (schema == null) {
117 schema = createSchema();
118 }
119 return schema;
120 }
121
122 public void setSchema(Schema schema) {
123 this.schema = schema;
124 }
125
126 public String getSchemaLanguage() {
127 return schemaLanguage;
128 }
129
130 public void setSchemaLanguage(String schemaLanguage) {
131 this.schemaLanguage = schemaLanguage;
132 }
133
134 public Source getSchemaSource() throws IOException {
135 if (schemaSource == null) {
136 schemaSource = createSchemaSource();
137 }
138 return schemaSource;
139 }
140
141 public void setSchemaSource(Source schemaSource) {
142 this.schemaSource = schemaSource;
143 }
144
145 public URL getSchemaUrl() {
146 return schemaUrl;
147 }
148
149 public void setSchemaUrl(URL schemaUrl) {
150 this.schemaUrl = schemaUrl;
151 }
152
153 public File getSchemaFile() {
154 return schemaFile;
155 }
156
157 public void setSchemaFile(File schemaFile) {
158 this.schemaFile = schemaFile;
159 }
160
161 public SchemaFactory getSchemaFactory() {
162 if (schemaFactory == null) {
163 schemaFactory = createSchemaFactory();
164 }
165 return schemaFactory;
166 }
167
168 public void setSchemaFactory(SchemaFactory schemaFactory) {
169 this.schemaFactory = schemaFactory;
170 }
171
172 public ValidatorErrorHandler getErrorHandler() {
173 return errorHandler;
174 }
175
176 public void setErrorHandler(ValidatorErrorHandler errorHandler) {
177 this.errorHandler = errorHandler;
178 }
179
180 public boolean isUseDom() {
181 return useDom;
182 }
183
184 /**
185 * Sets whether DOMSource and DOMResult should be used, or SaxSource and
186 * SaxResult.
187 *
188 * @param useDom
189 * true to use DOM otherwise Sax is used
190 */
191 public void setUseDom(boolean useDom) {
192 this.useDom = useDom;
193 }
194
195 public boolean isUseSharedSchema() {
196 return useSharedSchema;
197 }
198
199 public void setUseSharedSchema(boolean useSharedSchema) {
200 this.useSharedSchema = useSharedSchema;
201 }
202
203 public LSResourceResolver getResourceResolver() {
204 return resourceResolver;
205 }
206
207 public void setResourceResolver(LSResourceResolver resourceResolver) {
208 this.resourceResolver = resourceResolver;
209 }
210
211 // Implementation methods
212 // -----------------------------------------------------------------------
213
214 protected SchemaFactory createSchemaFactory() {
215 SchemaFactory factory = SchemaFactory.newInstance(schemaLanguage);
216 if (getResourceResolver() != null) {
217 factory.setResourceResolver(getResourceResolver());
218 }
219 return factory;
220 }
221
222 protected Source createSchemaSource() throws IOException {
223 throw new IllegalArgumentException("You must specify either a schema, schemaFile, schemaSource or schemaUrl property");
224 }
225
226 protected Schema createSchema() throws SAXException, IOException {
227 SchemaFactory factory = getSchemaFactory();
228
229 URL url = getSchemaUrl();
230 if (url != null) {
231 return factory.newSchema(url);
232 }
233 File file = getSchemaFile();
234 if (file != null) {
235 return factory.newSchema(file);
236 }
237 return factory.newSchema(getSchemaSource());
238 }
239 }