1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.helger.schematron.pure;
18
19 import java.io.File;
20 import java.io.InputStream;
21 import java.net.MalformedURLException;
22 import java.net.URL;
23 import java.nio.charset.Charset;
24
25 import javax.annotation.Nonnull;
26 import javax.annotation.Nullable;
27 import javax.annotation.concurrent.NotThreadSafe;
28 import javax.xml.xpath.XPathFunctionResolver;
29 import javax.xml.xpath.XPathVariableResolver;
30
31 import org.oclc.purl.dsdl.svrl.SchematronOutputType;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34 import org.w3c.dom.Document;
35 import org.w3c.dom.Node;
36 import org.xml.sax.EntityResolver;
37
38 import com.helger.commons.ValueEnforcer;
39 import com.helger.commons.annotation.Nonempty;
40 import com.helger.commons.io.resource.ClassPathResource;
41 import com.helger.commons.io.resource.FileSystemResource;
42 import com.helger.commons.io.resource.IReadableResource;
43 import com.helger.commons.io.resource.URLResource;
44 import com.helger.commons.io.resource.inmemory.AbstractMemoryReadableResource;
45 import com.helger.commons.io.resource.inmemory.ReadableResourceByteArray;
46 import com.helger.commons.io.resource.inmemory.ReadableResourceInputStream;
47 import com.helger.commons.state.EValidity;
48 import com.helger.schematron.AbstractSchematronResource;
49 import com.helger.schematron.SchematronDebug;
50 import com.helger.schematron.SchematronException;
51 import com.helger.schematron.pure.bound.IPSBoundSchema;
52 import com.helger.schematron.pure.bound.PSBoundSchemaCache;
53 import com.helger.schematron.pure.bound.PSBoundSchemaCacheKey;
54 import com.helger.schematron.pure.errorhandler.DoNothingPSErrorHandler;
55 import com.helger.schematron.pure.errorhandler.IPSErrorHandler;
56 import com.helger.schematron.pure.exchange.PSWriter;
57 import com.helger.schematron.pure.model.PSSchema;
58 import com.helger.schematron.svrl.SVRLWriter;
59 import com.helger.xml.serialize.write.XMLWriterSettings;
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 @NotThreadSafe
75 public class SchematronResourcePure extends AbstractSchematronResource
76 {
77 private static final Logger s_aLogger = LoggerFactory.getLogger (SchematronResourcePure.class);
78
79 private String m_sPhase;
80 private IPSErrorHandler m_aErrorHandler;
81 private XPathVariableResolver m_aVariableResolver;
82 private XPathFunctionResolver m_aFunctionResolver;
83
84 private IPSBoundSchema m_aBoundSchema;
85
86 public SchematronResourcePure (@Nonnull final IReadableResource aResource)
87 {
88 this (aResource, (String) null, (IPSErrorHandler) null);
89 }
90
91 public SchematronResourcePure (@Nonnull final IReadableResource aResource,
92 @Nullable final String sPhase,
93 @Nullable final IPSErrorHandler aErrorHandler)
94 {
95 super (aResource);
96 setPhase (sPhase);
97 setErrorHandler (aErrorHandler);
98 }
99
100
101
102
103 @Nullable
104 public String getPhase ()
105 {
106 return m_sPhase;
107 }
108
109
110
111
112
113
114
115
116
117
118 @Nonnull
119 public SchematronResourcePure setPhase (@Nullable final String sPhase)
120 {
121 if (m_aBoundSchema != null)
122 throw new IllegalStateException ("Schematron was already bound and can therefore not be altered!");
123 m_sPhase = sPhase;
124 return this;
125 }
126
127
128
129
130
131 @Nullable
132 public IPSErrorHandler getErrorHandler ()
133 {
134 return m_aErrorHandler;
135 }
136
137
138
139
140
141
142
143
144 @Nonnull
145 public SchematronResourcePure setErrorHandler (@Nullable final IPSErrorHandler aErrorHandler)
146 {
147 if (m_aBoundSchema != null)
148 throw new IllegalStateException ("Schematron was already bound and can therefore not be altered!");
149 m_aErrorHandler = aErrorHandler;
150 return this;
151 }
152
153
154
155
156 @Nullable
157 public XPathVariableResolver getVariableResolver ()
158 {
159 return m_aVariableResolver;
160 }
161
162
163
164
165
166
167
168
169
170
171 @Nonnull
172 public SchematronResourcePure setVariableResolver (@Nullable final XPathVariableResolver aVariableResolver)
173 {
174 if (m_aBoundSchema != null)
175 throw new IllegalStateException ("Schematron was already bound and can therefore not be altered!");
176 m_aVariableResolver = aVariableResolver;
177 return this;
178 }
179
180
181
182
183 @Nullable
184 public XPathFunctionResolver getFunctionResolver ()
185 {
186 return m_aFunctionResolver;
187 }
188
189
190
191
192
193
194
195
196
197
198 @Nonnull
199 public SchematronResourcePure setFunctionResolver (@Nullable final XPathFunctionResolver aFunctionResolver)
200 {
201 if (m_aBoundSchema != null)
202 throw new IllegalStateException ("Schematron was already bound and can therefore not be altered!");
203 m_aFunctionResolver = aFunctionResolver;
204 return this;
205 }
206
207
208
209
210
211
212
213
214
215
216
217
218 @Nonnull
219 public SchematronResourcePure setEntityResolver (@Nullable final EntityResolver aEntityResolver)
220 {
221 if (m_aBoundSchema != null)
222 throw new IllegalStateException ("Schematron was already bound and can therefore not be altered!");
223 internalSetEntityResolver (aEntityResolver);
224 return this;
225 }
226
227 @Nonnull
228 protected IPSBoundSchema createBoundSchema ()
229 {
230 final IReadableResource aResource = getResource ();
231 final IPSErrorHandler aErrorHandler = getErrorHandler ();
232 final PSBoundSchemaCacheKey aCacheKey = new PSBoundSchemaCacheKey (aResource,
233 getPhase (),
234 aErrorHandler,
235 getVariableResolver (),
236 getFunctionResolver (),
237 getEntityResolver ());
238 if (aResource instanceof AbstractMemoryReadableResource || !isUseCache ())
239 {
240
241 try
242 {
243 return aCacheKey.createBoundSchema ();
244 }
245 catch (final SchematronException ex)
246 {
247
248 throw new IllegalStateException ("Failed to bind Schematron", ex);
249 }
250 }
251
252
253
254 return PSBoundSchemaCache.getInstance ().getFromCache (aCacheKey);
255 }
256
257
258
259
260
261
262 @Nonnull
263 public IPSBoundSchema getOrCreateBoundSchema ()
264 {
265 if (m_aBoundSchema == null)
266 try
267 {
268 m_aBoundSchema = createBoundSchema ();
269 }
270 catch (final RuntimeException ex)
271 {
272 if (m_aErrorHandler != null)
273 m_aErrorHandler.error (getResource (), null, "Error creating bound schema", ex);
274 throw ex;
275 }
276
277 return m_aBoundSchema;
278 }
279
280 public boolean isValidSchematron ()
281 {
282
283 try
284 {
285 final IPSErrorHandler aErrorHandler = m_aErrorHandler != null ? m_aErrorHandler : new DoNothingPSErrorHandler ();
286 return getOrCreateBoundSchema ().getOriginalSchema ().isValid (aErrorHandler);
287 }
288 catch (final RuntimeException ex)
289 {
290
291 return false;
292 }
293 }
294
295
296
297
298
299 public void validateCompletely ()
300 {
301
302 final IPSErrorHandler aErrorHandler = m_aErrorHandler != null ? m_aErrorHandler : new DoNothingPSErrorHandler ();
303 validateCompletely (aErrorHandler);
304 }
305
306
307
308
309
310
311
312
313 public void validateCompletely (@Nonnull final IPSErrorHandler aErrorHandler)
314 {
315 ValueEnforcer.notNull (aErrorHandler, "ErrorHandler");
316
317 try
318 {
319 getOrCreateBoundSchema ().getOriginalSchema ().validateCompletely (aErrorHandler);
320 }
321 catch (final RuntimeException ex)
322 {
323
324 }
325 }
326
327 @Nonnull
328 public EValidity getSchematronValidity (@Nonnull final Node aXMLNode) throws Exception
329 {
330 ValueEnforcer.notNull (aXMLNode, "XMLNode");
331
332 if (!isValidSchematron ())
333 return EValidity.INVALID;
334
335 return getOrCreateBoundSchema ().validatePartially (aXMLNode);
336 }
337
338
339
340
341
342
343
344
345
346
347 @Nonnull
348 public SchematronOutputType applySchematronValidationToSVRL (@Nonnull final Node aXMLNode) throws SchematronException
349 {
350 ValueEnforcer.notNull (aXMLNode, "XMLNode");
351
352 final SchematronOutputType aSOT = getOrCreateBoundSchema ().validateComplete (aXMLNode);
353
354
355 if (SchematronDebug.isShowCreatedSVRL ())
356 s_aLogger.info ("Created SVRL:\n" + SVRLWriter.createXMLString (aSOT));
357
358 return aSOT;
359 }
360
361 @Nullable
362 public Document applySchematronValidation (@Nonnull final Node aXMLNode) throws Exception
363 {
364 ValueEnforcer.notNull (aXMLNode, "XMLNode");
365
366 final SchematronOutputType aSO = applySchematronValidationToSVRL (aXMLNode);
367 return aSO == null ? null : SVRLWriter.createXML (aSO);
368 }
369
370
371
372
373
374
375
376
377
378 @Nonnull
379 public static SchematronResourcePure fromClassPath (@Nonnull @Nonempty final String sSCHPath)
380 {
381 return new SchematronResourcePure (new ClassPathResource (sSCHPath));
382 }
383
384
385
386
387
388
389
390
391
392 @Nonnull
393 public static SchematronResourcePure fromFile (@Nonnull @Nonempty final String sSCHPath)
394 {
395 return new SchematronResourcePure (new FileSystemResource (sSCHPath));
396 }
397
398
399
400
401
402
403
404
405
406 @Nonnull
407 public static SchematronResourcePure fromFile (@Nonnull final File aSCHFile)
408 {
409 return new SchematronResourcePure (new FileSystemResource (aSCHFile));
410 }
411
412
413
414
415
416
417
418
419
420
421
422
423 @Nonnull
424 public static SchematronResourcePure fromURL (@Nonnull @Nonempty final String sSCHURL) throws MalformedURLException
425 {
426 return new SchematronResourcePure (new URLResource (sSCHURL));
427 }
428
429
430
431
432
433
434
435
436
437 @Nonnull
438 public static SchematronResourcePure fromURL (@Nonnull final URL aSCHURL)
439 {
440 return new SchematronResourcePure (new URLResource (aSCHURL));
441 }
442
443
444
445
446
447
448
449
450
451
452
453 @Nonnull
454 public static SchematronResourcePure fromInputStream (@Nonnull final InputStream aSchematronIS)
455 {
456 return new SchematronResourcePure (new ReadableResourceInputStream (aSchematronIS));
457 }
458
459
460
461
462
463
464
465
466
467
468
469 @Nonnull
470 public static SchematronResourcePure fromByteArray (@Nonnull final byte [] aSchematron)
471 {
472 return new SchematronResourcePure (new ReadableResourceByteArray (aSchematron));
473 }
474
475
476
477
478
479
480
481
482
483
484
485
486
487 @Nonnull
488 public static SchematronResourcePure fromString (@Nonnull final String sSchematron, @Nonnull final Charset aCharset)
489 {
490 return fromByteArray (sSchematron.getBytes (aCharset));
491 }
492
493
494
495
496
497
498
499
500
501
502 @Nonnull
503 public static SchematronResourcePure fromSchema (@Nonnull final PSSchema aSchematron)
504 {
505 return fromString (new PSWriter ().getXMLString (aSchematron), XMLWriterSettings.DEFAULT_XML_CHARSET_OBJ);
506 }
507 }