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