1 /*
2 * Copyright 2010 University Corporation for Advanced Internet Development, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.opensaml.xml.schema;
18
19 import java.io.File;
20 import java.io.InputStream;
21 import java.util.ArrayList;
22 import java.util.List;
23
24 import javax.xml.XMLConstants;
25 import javax.xml.transform.Source;
26 import javax.xml.transform.stream.StreamSource;
27 import javax.xml.validation.Schema;
28 import javax.xml.validation.SchemaFactory;
29
30 import org.opensaml.xml.parse.LoggingErrorHandler;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import org.xml.sax.SAXException;
34
35 /** A helper class for building {@link Schema} from a set of input. */
36 public final class SchemaBuilder {
37
38 /** Language of the schema files. */
39 public static enum SchemaLanguage {
40
41 /** W3 XML Schema. */
42 XML("xsd"),
43
44 /** OASIS RELAX NG Schema. */
45 RELAX("rng");
46
47 /** File extension used for the schema files. */
48 private String schemaFileExtension;
49
50 /**
51 * Constructor.
52 *
53 * @param extension file extension used for the schema files
54 */
55 private SchemaLanguage(String extension) {
56 schemaFileExtension = extension;
57 }
58
59 /**
60 * Gets the file extension used for the schema files.
61 *
62 * @return file extension used for the schema files
63 */
64 public String getSchemaFileExtension() {
65 return schemaFileExtension;
66 }
67 };
68
69 /** Constructor. */
70 private SchemaBuilder() {}
71
72 /**
73 * Builds a schema from the given schema source.
74 *
75 * @param lang schema language, must not be null
76 * @param schemaFileOrDirectory file or directory which contains schema sources
77 *
78 * @return the constructed schema
79 *
80 * @throws SAXException thrown if there is a problem converting the schema sources in to a schema
81 */
82 public static Schema buildSchema(SchemaLanguage lang, String schemaFileOrDirectory) throws SAXException {
83 if(schemaFileOrDirectory == null){
84 return null;
85 }
86
87 return buildSchema(lang, new File(schemaFileOrDirectory));
88 }
89
90 /**
91 * Builds a schema from the given schema sources.
92 *
93 * @param lang schema language, must not be null
94 * @param schemaFilesOrDirectories files or directories which contains schema sources
95 *
96 * @return the constructed schema
97 *
98 * @throws SAXException thrown if there is a problem converting the schema sources in to a schema
99 */
100 public static Schema buildSchema(SchemaLanguage lang, String[] schemaFilesOrDirectories) throws SAXException {
101 if(schemaFilesOrDirectories == null || schemaFilesOrDirectories.length == 0){
102 return null;
103 }
104
105 return buildSchema(lang, schemaFilesOrDirectories);
106 }
107
108 /**
109 * Builds a schema from the given schema source.
110 *
111 * @param lang schema language, must not be null
112 * @param schemaFileOrDirectory file or directory which contains schema sources
113 *
114 * @return the constructed schema
115 *
116 * @throws SAXException thrown if there is a problem converting the schema sources in to a schema
117 */
118 public static Schema buildSchema(SchemaLanguage lang, File schemaFileOrDirectory) throws SAXException {
119 if(schemaFileOrDirectory == null){
120 return null;
121 }
122
123 return buildSchema(lang, new File[]{schemaFileOrDirectory});
124 }
125
126 /**
127 * Builds a schema from the given schema sources.
128 *
129 * @param lang schema language, must not be null
130 * @param schemaFilesOrDirectories files or directories which contains schema sources
131 *
132 * @return the constructed schema
133 *
134 * @throws SAXException thrown if there is a problem converting the schema sources in to a schema
135 */
136 public static Schema buildSchema(SchemaLanguage lang, File[] schemaFilesOrDirectories) throws SAXException {
137 if(schemaFilesOrDirectories == null || schemaFilesOrDirectories.length == 0){
138 return null;
139 }
140
141 ArrayList<File> schemaFiles = new ArrayList<File>();
142 getSchemaFiles(lang, schemaFilesOrDirectories, schemaFiles);
143
144 if(schemaFiles.isEmpty()){
145 return null;
146 }
147
148 ArrayList<Source> schemaSources = new ArrayList<Source>();
149 for(File schemaFile : schemaFiles){
150 schemaSources.add(new StreamSource(schemaFile));
151 }
152 return buildSchema(lang, schemaSources.toArray(new Source[]{}));
153 }
154
155 /**
156 * Builds a schema from the given schema source.
157 *
158 * @param lang schema language, must not be null
159 * @param schemaSource schema source
160 *
161 * @return the constructed schema
162 *
163 * @throws SAXException thrown if there is a problem converting the schema sources in to a schema
164 */
165 public static Schema buildSchema(SchemaLanguage lang, InputStream schemaSource) throws SAXException {
166 if(schemaSource == null){
167 return null;
168 }
169
170 return buildSchema(lang, new StreamSource[] { new StreamSource(schemaSource) });
171 }
172
173 /**
174 * Builds a schema from the given schema sources.
175 *
176 * @param lang schema language, must not be null
177 * @param schemaSources schema sources
178 *
179 * @return the constructed schema
180 *
181 * @throws SAXException thrown if there is a problem converting the schema sources in to a schema
182 */
183 public static Schema buildSchema(SchemaLanguage lang, InputStream[] schemaSources) throws SAXException {
184 if(schemaSources == null || schemaSources.length == 0){
185 return null;
186 }
187
188 ArrayList<StreamSource> sources = new ArrayList<StreamSource>();
189 for (InputStream schemaSource : schemaSources) {
190 if (schemaSource == null) {
191 continue;
192 }
193 sources.add(new StreamSource(schemaSource));
194 }
195
196 if (sources.isEmpty()) {
197 return null;
198 }
199
200 return buildSchema(lang, sources.toArray(new Source[] {}));
201 }
202
203 /**
204 * Gets all of the schema files in the given set of readable files, directories or subdirectories.
205 *
206 * @param lang schema language, must not be null
207 * @param schemaFilesOrDirectories files and directories which may contain schema files
208 * @param accumulatedSchemaFiles list that accumulates the schema files
209 */
210 protected static void getSchemaFiles(SchemaLanguage lang, File[] schemaFilesOrDirectories,
211 List<File> accumulatedSchemaFiles) {
212 Logger log = getLogger();
213
214 if(lang == null){
215 throw new IllegalArgumentException("Schema language may not be null");
216 }
217
218 if (schemaFilesOrDirectories == null || schemaFilesOrDirectories.length == 0) {
219 return;
220 }
221
222 for (File handle : schemaFilesOrDirectories) {
223 if (handle == null) {
224 continue;
225 }
226
227 if (!handle.canRead()) {
228 log.debug("Ignoring '{}', no read permission", handle.getAbsolutePath());
229 }
230
231 if (handle.isFile() && handle.getName().endsWith(lang.getSchemaFileExtension())) {
232 log.debug("Added schema source '{}'", handle.getAbsolutePath());
233 accumulatedSchemaFiles.add(handle);
234 }
235
236 if (handle.isDirectory()) {
237 getSchemaFiles(lang, handle.listFiles(), accumulatedSchemaFiles);
238 }
239 }
240 }
241
242 /**
243 * Builds a schema from the given schema sources.
244 *
245 * @param lang schema language, must not be null
246 * @param schemaSources schema sources, must not be null
247 *
248 * @return the constructed schema
249 *
250 * @throws SAXException thrown if there is a problem converting the schema sources in to a schema
251 */
252 protected static Schema buildSchema(SchemaLanguage lang, Source[] schemaSources) throws SAXException {
253 if(lang == null){
254 throw new IllegalArgumentException("Schema language may not be null");
255 }
256
257 if(schemaSources == null){
258 throw new IllegalArgumentException("Schema sources may not be null");
259 }
260
261 SchemaFactory schemaFactory;
262
263 if (lang == SchemaLanguage.XML) {
264 schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
265 } else {
266 schemaFactory = SchemaFactory.newInstance(XMLConstants.RELAXNG_NS_URI);
267 }
268
269 schemaFactory.setErrorHandler(new LoggingErrorHandler(LoggerFactory.getLogger(SchemaBuilder.class)));
270 return schemaFactory.newSchema(schemaSources);
271 }
272
273 /**
274 * Get an SLF4J Logger.
275 *
276 * @return a Logger instance
277 */
278 private static Logger getLogger() {
279 return LoggerFactory.getLogger(SchemaBuilder.class);
280 }
281 }