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 @NoArgsConstructor(access = AccessLevel.PACKAGE)
58 @ToString
59 class SchemaBuilderImpl implements SchemaBuilder {
60
61
62
63
64 String schemaLanguage = XMLConstants.W3C_XML_SCHEMA_NS_URI;
65
66
67
68
69 String factoryClassName;
70
71
72
73
74 ClassLoader classLoader;
75
76
77
78
79 ResourceLoader resourceLoader = new DefaultResourceLoader();
80
81
82
83
84 LSResourceResolver resourceResolver;
85
86
87
88
89 ErrorHandler errorHandler;
90
91
92
93
94 final Map<String, Boolean> features = new LinkedHashMap<>();
95
96
97
98
99 final Map<String, Object> properties = new LinkedHashMap<>();
100
101
102
103
104
105
106 SchemaFactory createSchemaFactory() {
107 SchemaFactory schemaFactory;
108 if (!isEmpty(factoryClassName)) {
109 if (isEmpty(classLoader)) {
110 schemaFactory = SchemaFactory
111 .newInstance(schemaLanguage, factoryClassName, ClasspathHelper.contextClassLoader());
112 } else {
113 schemaFactory = SchemaFactory.newInstance(schemaLanguage, factoryClassName, classLoader);
114 }
115 } else {
116 schemaFactory = SchemaFactory.newInstance(schemaLanguage);
117 }
118 if (!isEmpty(resourceResolver)) {
119 schemaFactory.setResourceResolver(resourceResolver);
120 }
121 if (!isEmpty(errorHandler)) {
122 schemaFactory.setErrorHandler(errorHandler);
123 }
124 try {
125 for (Map.Entry<String, Boolean> feature : features.entrySet()) {
126 schemaFactory.setFeature(feature.getKey(), feature.getValue());
127 }
128 for (Map.Entry<String, Object> property : properties.entrySet()) {
129 schemaFactory.setProperty(property.getKey(), property.getValue());
130 }
131
132 } catch (SAXNotSupportedException | SAXNotRecognizedException e) {
133 throw new XmlRuntimeException(e);
134 }
135 return schemaFactory;
136 }
137
138 @Override
139 public SchemaBuilderImpl copy() {
140 SchemaBuilderImpl copy = new SchemaBuilderImpl();
141 copy.schemaLanguage = schemaLanguage;
142 copy.factoryClassName = factoryClassName;
143 copy.classLoader = classLoader;
144 copy.resourceLoader = resourceLoader;
145 copy.resourceResolver = resourceResolver;
146 copy.errorHandler = errorHandler;
147 copy.features.putAll(features);
148 copy.properties.putAll(properties);
149 return copy;
150 }
151
152 @Override
153 public SchemaBuilder withSchemaLanguage(String schemaLanguage) {
154 if (isEmpty(schemaLanguage)) {
155 this.schemaLanguage = schemaLanguage;
156 }
157 return this;
158 }
159
160 @Override
161 public SchemaBuilder withFactory(String factoryClassName) {
162 this.factoryClassName = factoryClassName;
163 return this;
164 }
165
166 @Override
167 public SchemaBuilder withClassLoader(ClassLoader classLoader) {
168 this.classLoader = classLoader;
169 return this;
170 }
171
172 @Override
173 public SchemaBuilder withResourceLoader(ResourceLoader resourceLoader) {
174 if (!isEmpty(resourceLoader)) {
175 this.resourceLoader = resourceLoader;
176 }
177 return this;
178 }
179
180 @Override
181 public SchemaBuilder withResourceResolver(LSResourceResolver resourceResolver) {
182 this.resourceResolver = resourceResolver;
183 return this;
184 }
185
186 @Override
187 public SchemaBuilder withErrorHandler(ErrorHandler errorHandler) {
188 this.errorHandler = errorHandler;
189 return this;
190 }
191
192 @Override
193 public SchemaBuilder withFeature(String name, Boolean value) {
194 if (!isEmpty(name)) {
195 features.put(name, value);
196 }
197 return this;
198 }
199
200 @Override
201 public SchemaBuilder withProperty(String name, Object value) {
202 if (!isEmpty(name)) {
203 properties.put(name, value);
204 }
205 return this;
206 }
207
208 @Override
209 public List<Source> fetchSchemaSources(Collection<String> locations) {
210 List<Source> sources = new ArrayList<>();
211 if (!isEmpty(locations)) {
212 Set<String> locationSet = new LinkedHashSet<>(locations);
213 for (String location : locationSet) {
214 try (InputStream is = resourceLoader.getResource(location).getInputStream()) {
215 byte[] bytes = FileCopyUtils.copyToByteArray(is);
216 sources.add(new StreamSource(new ByteArrayInputStream(bytes)));
217 } catch (IOException e) {
218 throw new XmlRuntimeException(e);
219 }
220 }
221 }
222 return Collections.unmodifiableList(sources);
223 }
224
225 @Override
226 public Schema buildSchema(URL url) {
227 try {
228 if (isEmpty(url)) {
229 return createSchemaFactory().newSchema();
230 }
231 return createSchemaFactory().newSchema(url);
232 } catch (SAXException e) {
233 throw new XmlRuntimeException(e);
234 }
235 }
236
237 @Override
238 public Schema buildSchema(File file) {
239 try {
240 if (isEmpty(file)) {
241 return createSchemaFactory().newSchema();
242 }
243 return createSchemaFactory().newSchema(file);
244 } catch (SAXException e) {
245 throw new XmlRuntimeException(e);
246 }
247 }
248
249 @Override
250 public Schema buildSchema(Source[] sources) {
251 try {
252 if (isEmpty(sources)) {
253 return createSchemaFactory().newSchema();
254 }
255 return createSchemaFactory().newSchema(sources);
256 } catch (SAXException e) {
257 throw new XmlRuntimeException(e);
258 }
259 }
260
261 }