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.processor.validation; 018 019import java.io.ByteArrayInputStream; 020import java.io.File; 021import java.io.IOException; 022import java.io.InputStream; 023import java.net.URL; 024 025import javax.xml.XMLConstants; 026import javax.xml.transform.Source; 027import javax.xml.transform.stream.StreamSource; 028import javax.xml.validation.Schema; 029import javax.xml.validation.SchemaFactory; 030 031import org.w3c.dom.ls.LSResourceResolver; 032import org.xml.sax.SAXException; 033 034import org.apache.camel.CamelContext; 035import org.apache.camel.converter.IOConverter; 036import org.apache.camel.util.IOHelper; 037import org.apache.camel.util.ObjectHelper; 038import org.apache.camel.util.ResourceHelper; 039 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042 043/** 044 * Reads the schema used in the processor {@link ValidatingProcessor}. Contains 045 * the method {@link clearCachedSchema()} to force re-reading the schema. 046 */ 047public class SchemaReader { 048 049 private static final Logger LOG = LoggerFactory.getLogger(SchemaReader.class); 050 051 private String schemaLanguage = XMLConstants.W3C_XML_SCHEMA_NS_URI; 052 // must be volatile because is accessed from different threads see ValidatorEndpoint.clearCachedSchema 053 private volatile Schema schema; 054 private Source schemaSource; 055 // must be volatile because is accessed from different threads see ValidatorEndpoint.clearCachedSchema 056 private volatile SchemaFactory schemaFactory; 057 private URL schemaUrl; 058 private File schemaFile; 059 private byte[] schemaAsByteArray; 060 private final String schemaResourceUri; 061 private LSResourceResolver resourceResolver; 062 063 private final CamelContext camelContext; 064 065 066 public SchemaReader() { 067 this.camelContext = null; 068 this.schemaResourceUri = null; 069 } 070 071 /** Specify a camel context and a schema resource URI in order to read the schema via the class resolver specified in the Camel context. */ 072 public SchemaReader(CamelContext camelContext, String schemaResourceUri) { 073 ObjectHelper.notNull(camelContext, "camelContext"); 074 ObjectHelper.notNull(schemaResourceUri, "schemaResourceUri"); 075 this.camelContext = camelContext; 076 this.schemaResourceUri = schemaResourceUri; 077 } 078 079 public void loadSchema() throws Exception { 080 // force loading of schema 081 schema = createSchema(); 082 } 083 084 // Properties 085 // ----------------------------------------------------------------------- 086 087 public Schema getSchema() throws IOException, SAXException { 088 if (schema == null) { 089 synchronized (this) { 090 if (schema == null) { 091 schema = createSchema(); 092 } 093 } 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 byte[] getSchemaAsByteArray() { 138 return schemaAsByteArray; 139 } 140 141 public void setSchemaAsByteArray(byte[] schemaAsByteArray) { 142 this.schemaAsByteArray = schemaAsByteArray; 143 } 144 145 public SchemaFactory getSchemaFactory() { 146 if (schemaFactory == null) { 147 synchronized (this) { 148 if (schemaFactory == null) { 149 schemaFactory = createSchemaFactory(); 150 } 151 } 152 } 153 return schemaFactory; 154 } 155 156 public void setSchemaFactory(SchemaFactory schemaFactory) { 157 this.schemaFactory = schemaFactory; 158 } 159 160 public LSResourceResolver getResourceResolver() { 161 return resourceResolver; 162 } 163 164 public void setResourceResolver(LSResourceResolver resourceResolver) { 165 this.resourceResolver = resourceResolver; 166 } 167 168 protected SchemaFactory createSchemaFactory() { 169 SchemaFactory factory = SchemaFactory.newInstance(schemaLanguage); 170 if (getResourceResolver() != null) { 171 factory.setResourceResolver(getResourceResolver()); 172 } 173 return factory; 174 } 175 176 protected Source createSchemaSource() throws IOException { 177 throw new IllegalArgumentException("You must specify either a schema, schemaFile, schemaSource, schemaUrl, or schemaUri property"); 178 } 179 180 protected Schema createSchema() throws SAXException, IOException { 181 SchemaFactory factory = getSchemaFactory(); 182 183 URL url = getSchemaUrl(); 184 if (url != null) { 185 synchronized (this) { 186 return factory.newSchema(url); 187 } 188 } 189 190 File file = getSchemaFile(); 191 if (file != null) { 192 synchronized (this) { 193 return factory.newSchema(file); 194 } 195 } 196 197 byte[] bytes = getSchemaAsByteArray(); 198 if (bytes != null) { 199 synchronized (this) { 200 return factory.newSchema(new StreamSource(new ByteArrayInputStream(schemaAsByteArray))); 201 } 202 } 203 204 if (schemaResourceUri != null) { 205 synchronized (this) { 206 bytes = readSchemaResource(); 207 return factory.newSchema(new StreamSource(new ByteArrayInputStream(bytes))); 208 } 209 } 210 211 Source source = getSchemaSource(); 212 synchronized (this) { 213 return factory.newSchema(source); 214 } 215 216 } 217 218 protected byte[] readSchemaResource() throws IOException { 219 LOG.debug("reading schema resource: {}", schemaResourceUri); 220 InputStream is = ResourceHelper.resolveMandatoryResourceAsInputStream(camelContext, schemaResourceUri); 221 byte[] bytes = null; 222 try { 223 bytes = IOConverter.toBytes(is); 224 } finally { 225 // and make sure to close the input stream after the schema has been 226 // loaded 227 IOHelper.close(is); 228 } 229 return bytes; 230 } 231 232}