1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.bremersee.xml;
18
19 import static org.springframework.util.ObjectUtils.isEmpty;
20
21 import java.io.ByteArrayInputStream;
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.net.URL;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.LinkedHashMap;
30 import java.util.LinkedHashSet;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Set;
34 import javax.xml.XMLConstants;
35 import javax.xml.transform.Source;
36 import javax.xml.transform.stream.StreamSource;
37 import javax.xml.validation.Schema;
38 import javax.xml.validation.SchemaFactory;
39 import lombok.AccessLevel;
40 import lombok.NoArgsConstructor;
41 import lombok.ToString;
42 import org.reflections.util.ClasspathHelper;
43 import org.springframework.core.io.DefaultResourceLoader;
44 import org.springframework.core.io.ResourceLoader;
45 import org.springframework.util.FileCopyUtils;
46 import org.w3c.dom.ls.LSResourceResolver;
47 import org.xml.sax.ErrorHandler;
48 import org.xml.sax.SAXException;
49 import org.xml.sax.SAXNotRecognizedException;
50 import org.xml.sax.SAXNotSupportedException;
51
52
53
54
55
56
57 @SuppressWarnings("SameNameButDifferent")
58 @NoArgsConstructor(access = AccessLevel.PACKAGE)
59 @ToString
60 class SchemaBuilderImpl implements SchemaBuilder {
61
62
63
64
65 String schemaLanguage = XMLConstants.W3C_XML_SCHEMA_NS_URI;
66
67
68
69
70 String factoryClassName;
71
72
73
74
75 ClassLoader classLoader;
76
77
78
79
80 ResourceLoader resourceLoader = new DefaultResourceLoader();
81
82
83
84
85 LSResourceResolver resourceResolver;
86
87
88
89
90 ErrorHandler errorHandler;
91
92
93
94
95 final Map<String, Boolean> features = new LinkedHashMap<>();
96
97
98
99
100 final Map<String, Object> properties = new LinkedHashMap<>();
101
102
103
104
105
106
107 SchemaFactory createSchemaFactory() {
108 SchemaFactory schemaFactory;
109 if (!isEmpty(factoryClassName)) {
110 if (isEmpty(classLoader)) {
111 schemaFactory = SchemaFactory
112 .newInstance(schemaLanguage, factoryClassName, ClasspathHelper.contextClassLoader());
113 } else {
114 schemaFactory = SchemaFactory.newInstance(schemaLanguage, factoryClassName, classLoader);
115 }
116 } else {
117 schemaFactory = SchemaFactory.newInstance(schemaLanguage);
118 }
119 if (!isEmpty(resourceResolver)) {
120 schemaFactory.setResourceResolver(resourceResolver);
121 }
122 if (!isEmpty(errorHandler)) {
123 schemaFactory.setErrorHandler(errorHandler);
124 }
125 try {
126 for (Map.Entry<String, Boolean> feature : features.entrySet()) {
127 schemaFactory.setFeature(feature.getKey(), feature.getValue());
128 }
129 for (Map.Entry<String, Object> property : properties.entrySet()) {
130 schemaFactory.setProperty(property.getKey(), property.getValue());
131 }
132
133 } catch (SAXNotSupportedException | SAXNotRecognizedException e) {
134 throw new XmlRuntimeException(e);
135 }
136 return schemaFactory;
137 }
138
139 @Override
140 public SchemaBuilderImpl copy() {
141 SchemaBuilderImpl copy = new SchemaBuilderImpl();
142 copy.schemaLanguage = schemaLanguage;
143 copy.factoryClassName = factoryClassName;
144 copy.classLoader = classLoader;
145 copy.resourceLoader = resourceLoader;
146 copy.resourceResolver = resourceResolver;
147 copy.errorHandler = errorHandler;
148 copy.features.putAll(features);
149 copy.properties.putAll(properties);
150 return copy;
151 }
152
153 @Override
154 public SchemaBuilder withSchemaLanguage(String schemaLanguage) {
155 if (isEmpty(schemaLanguage)) {
156 this.schemaLanguage = schemaLanguage;
157 }
158 return this;
159 }
160
161 @Override
162 public SchemaBuilder withFactory(String factoryClassName) {
163 this.factoryClassName = factoryClassName;
164 return this;
165 }
166
167 @Override
168 public SchemaBuilder withClassLoader(ClassLoader classLoader) {
169 this.classLoader = classLoader;
170 return this;
171 }
172
173 @Override
174 public SchemaBuilder withResourceLoader(ResourceLoader resourceLoader) {
175 if (!isEmpty(resourceLoader)) {
176 this.resourceLoader = resourceLoader;
177 }
178 return this;
179 }
180
181 @Override
182 public SchemaBuilder withResourceResolver(LSResourceResolver resourceResolver) {
183 this.resourceResolver = resourceResolver;
184 return this;
185 }
186
187 @Override
188 public SchemaBuilder withErrorHandler(ErrorHandler errorHandler) {
189 this.errorHandler = errorHandler;
190 return this;
191 }
192
193 @Override
194 public SchemaBuilder withFeature(String name, Boolean value) {
195 if (!isEmpty(name)) {
196 features.put(name, value);
197 }
198 return this;
199 }
200
201 @Override
202 public SchemaBuilder withProperty(String name, Object value) {
203 if (!isEmpty(name)) {
204 properties.put(name, value);
205 }
206 return this;
207 }
208
209 @Override
210 public List<Source> fetchSchemaSources(Collection<String> locations) {
211 List<Source> sources = new ArrayList<>();
212 if (!isEmpty(locations)) {
213 Set<String> locationSet = new LinkedHashSet<>(locations);
214 for (String location : locationSet) {
215 try (InputStream is = resourceLoader.getResource(location).getInputStream()) {
216 byte[] bytes = FileCopyUtils.copyToByteArray(is);
217 sources.add(new StreamSource(new ByteArrayInputStream(bytes)));
218 } catch (IOException e) {
219 throw new XmlRuntimeException(e);
220 }
221 }
222 }
223 return Collections.unmodifiableList(sources);
224 }
225
226 @Override
227 public Schema buildSchema(URL url) {
228 try {
229 if (isEmpty(url)) {
230 return createSchemaFactory().newSchema();
231 }
232 return createSchemaFactory().newSchema(url);
233 } catch (SAXException e) {
234 throw new XmlRuntimeException(e);
235 }
236 }
237
238 @Override
239 public Schema buildSchema(File file) {
240 try {
241 if (isEmpty(file)) {
242 return createSchemaFactory().newSchema();
243 }
244 return createSchemaFactory().newSchema(file);
245 } catch (SAXException e) {
246 throw new XmlRuntimeException(e);
247 }
248 }
249
250 @Override
251 public Schema buildSchema(Source[] sources) {
252 try {
253 if (isEmpty(sources)) {
254 return createSchemaFactory().newSchema();
255 }
256 return createSchemaFactory().newSchema(sources);
257 } catch (SAXException e) {
258 throw new XmlRuntimeException(e);
259 }
260 }
261
262 }