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