KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > thaiopensource > validate > schematron > SchemaReaderImpl


1 package com.thaiopensource.validate.schematron;
2
3 import com.thaiopensource.util.PropertyMap;
4 import com.thaiopensource.util.PropertyMapBuilder;
5 import com.thaiopensource.util.Localizer;
6 import com.thaiopensource.util.PropertyId;
7 import com.thaiopensource.validate.IncorrectSchemaException;
8 import com.thaiopensource.validate.Schema;
9 import com.thaiopensource.validate.SchemaReader;
10 import com.thaiopensource.validate.ValidateProperty;
11 import com.thaiopensource.validate.Validator;
12 import com.thaiopensource.validate.Option;
13 import com.thaiopensource.validate.rng.CompactSchemaReader;
14 import com.thaiopensource.validate.rng.RngProperty;
15 import com.thaiopensource.xml.sax.CountingErrorHandler;
16 import com.thaiopensource.xml.sax.DelegatingContentHandler;
17 import com.thaiopensource.xml.sax.DraconianErrorHandler;
18 import com.thaiopensource.xml.sax.ForkContentHandler;
19 import com.thaiopensource.xml.sax.XMLReaderCreator;
20 import org.xml.sax.Attributes JavaDoc;
21 import org.xml.sax.ContentHandler JavaDoc;
22 import org.xml.sax.ErrorHandler JavaDoc;
23 import org.xml.sax.InputSource JavaDoc;
24 import org.xml.sax.Locator JavaDoc;
25 import org.xml.sax.SAXException JavaDoc;
26 import org.xml.sax.SAXParseException JavaDoc;
27 import org.xml.sax.XMLReader JavaDoc;
28
29 import javax.xml.transform.ErrorListener JavaDoc;
30 import javax.xml.transform.SourceLocator JavaDoc;
31 import javax.xml.transform.Templates JavaDoc;
32 import javax.xml.transform.Transformer JavaDoc;
33 import javax.xml.transform.TransformerConfigurationException JavaDoc;
34 import javax.xml.transform.TransformerException JavaDoc;
35 import javax.xml.transform.TransformerFactory JavaDoc;
36 import javax.xml.transform.sax.SAXResult JavaDoc;
37 import javax.xml.transform.sax.SAXSource JavaDoc;
38 import javax.xml.transform.stream.StreamSource JavaDoc;
39 import java.io.IOException JavaDoc;
40 import java.io.InputStream JavaDoc;
41
42 class SchemaReaderImpl implements SchemaReader {
43   static final String JavaDoc SCHEMATRON_URI = "http://www.ascc.net/xml/schematron";
44   private static final String JavaDoc LOCATION_URI = "http://www.thaiopensource.com/ns/location";
45   private static final String JavaDoc ERROR_URI = "http://www.thaiopensource.com/ns/error";
46   private final Localizer localizer = new Localizer(SchemaReaderImpl.class);
47
48   private final Class JavaDoc transformerFactoryClass;
49   private final Templates JavaDoc schematron;
50   private final Schema schematronSchema;
51   private static final String JavaDoc SCHEMATRON_SCHEMA = "schematron.rnc";
52   private static final String JavaDoc SCHEMATRON_STYLESHEET = "schematron.xsl";
53   private static final PropertyId[] supportedPropertyIds = {
54     ValidateProperty.ERROR_HANDLER,
55     ValidateProperty.XML_READER_CREATOR,
56     SchematronProperty.DIAGNOSE,
57     SchematronProperty.PHASE,
58   };
59
60   SchemaReaderImpl(TransformerFactory JavaDoc transformerFactory) throws TransformerConfigurationException JavaDoc, IncorrectSchemaException {
61     this.transformerFactoryClass = transformerFactory.getClass();
62     String JavaDoc resourceName = fullResourceName(SCHEMATRON_STYLESHEET);
63     StreamSource JavaDoc source = new StreamSource JavaDoc(getResourceAsStream(resourceName));
64     initTransformerFactory(transformerFactory);
65     schematron = transformerFactory.newTemplates(source);
66     InputSource JavaDoc schemaSource = new InputSource JavaDoc(getResourceAsStream(fullResourceName(SCHEMATRON_SCHEMA)));
67     PropertyMapBuilder builder = new PropertyMapBuilder();
68     ValidateProperty.ERROR_HANDLER.put(builder, new DraconianErrorHandler());
69     RngProperty.CHECK_ID_IDREF.add(builder);
70     try {
71       schematronSchema = CompactSchemaReader.getInstance().createSchema(schemaSource, builder.toPropertyMap());
72     }
73     catch (SAXException JavaDoc e) {
74       throw new IncorrectSchemaException();
75     }
76     catch (IOException JavaDoc e) {
77       throw new IncorrectSchemaException();
78     }
79   }
80
81   public Option getOption(String JavaDoc uri) {
82     return SchematronProperty.getOption(uri);
83   }
84
85   private void initTransformerFactory(TransformerFactory JavaDoc factory) {
86     String JavaDoc name = factory.getClass().getName();
87     try {
88       if (name.equals("com.icl.saxon.TransformerFactoryImpl"))
89         factory.setAttribute("http://icl.com/saxon/feature/linenumbering",
90                              Boolean.TRUE);
91       else if (name.equals("org.apache.xalan.processor.TransformerFactoryImpl")) {
92         // Try both the documented URI and the URI that the code expects.
93
try {
94           // This is the URI that the code expects.
95
factory.setAttribute("http://xml.apache.org/xalan/properties/source-location",
96                                Boolean.TRUE);
97         }
98         catch (IllegalArgumentException JavaDoc e) {
99           // This is the URI that's documented.
100
factory.setAttribute("http://apache.org/xalan/features/source_location",
101                                Boolean.TRUE);
102         }
103       }
104     }
105     catch (IllegalArgumentException JavaDoc e) {
106     }
107   }
108
109   static class ValidateStage extends XMLReaderImpl {
110     private final ContentHandler validator;
111     private ContentHandler contentHandler;
112     private final XMLReader JavaDoc reader;
113     private final CountingErrorHandler ceh;
114
115     ValidateStage(XMLReader JavaDoc reader, Validator validator, CountingErrorHandler ceh) {
116       this.reader = reader;
117       this.validator = validator.getContentHandler();
118       this.ceh = ceh;
119     }
120
121     public void parse(InputSource JavaDoc input)
122             throws SAXException JavaDoc, IOException JavaDoc {
123       reader.parse(input);
124       if (ceh.getHadErrorOrFatalError())
125         throw new SAXException JavaDoc(new IncorrectSchemaException());
126     }
127
128     public void setContentHandler(ContentHandler handler) {
129       this.contentHandler = handler;
130       reader.setContentHandler(new ForkContentHandler(validator, contentHandler));
131     }
132
133     public ContentHandler getContentHandler() {
134       return contentHandler;
135     }
136   }
137
138   static class UserException extends Exception JavaDoc {
139     private final SAXException JavaDoc exception;
140
141     UserException(SAXException JavaDoc exception) {
142       this.exception = exception;
143     }
144
145     SAXException JavaDoc getException() {
146       return exception;
147     }
148   }
149
150   static class UserWrapErrorHandler extends CountingErrorHandler {
151     UserWrapErrorHandler(ErrorHandler errorHandler) {
152       super(errorHandler);
153     }
154
155     public void warning(SAXParseException JavaDoc exception)
156             throws SAXException JavaDoc {
157       try {
158         super.warning(exception);
159       }
160       catch (SAXException JavaDoc e) {
161         throw new SAXException JavaDoc(new UserException(e));
162       }
163     }
164
165     public void error(SAXParseException JavaDoc exception)
166             throws SAXException JavaDoc {
167       try {
168         super.error(exception);
169       }
170       catch (SAXException JavaDoc e) {
171         throw new SAXException JavaDoc(new UserException(e));
172       }
173     }
174
175     public void fatalError(SAXParseException JavaDoc exception)
176             throws SAXException JavaDoc {
177       try {
178         super.fatalError(exception);
179       }
180       catch (SAXException JavaDoc e) {
181         throw new SAXException JavaDoc(new UserException(e));
182       }
183     }
184   }
185
186   static class ErrorFilter extends DelegatingContentHandler {
187     private final ErrorHandler eh;
188     private final Localizer localizer;
189     private Locator JavaDoc locator;
190
191     ErrorFilter(ContentHandler delegate, ErrorHandler eh, Localizer localizer) {
192       super(delegate);
193       this.eh = eh;
194       this.localizer = localizer;
195     }
196
197     public void setDocumentLocator(Locator JavaDoc locator) {
198       this.locator = locator;
199       super.setDocumentLocator(locator);
200     }
201
202     public void startElement(String JavaDoc namespaceURI, String JavaDoc localName,
203                              String JavaDoc qName, Attributes JavaDoc atts)
204             throws SAXException JavaDoc {
205       if (namespaceURI.equals(ERROR_URI) && localName.equals("error"))
206         eh.error(new SAXParseException JavaDoc(localizer.message(atts.getValue("", "message"),
207                                                          atts.getValue("", "arg")),
208                                        locator));
209       super.startElement(namespaceURI, localName, qName, atts);
210     }
211   }
212
213   static class LocationFilter extends DelegatingContentHandler implements Locator JavaDoc {
214     private final String JavaDoc systemId;
215     private int lineNumber = -1;
216     private SAXException JavaDoc exception = null;
217
218     LocationFilter(ContentHandler delegate, String JavaDoc systemId) {
219       super(delegate);
220       this.systemId = systemId;
221     }
222
223     SAXException JavaDoc getException() {
224       return exception;
225     }
226
227     public void setDocumentLocator(Locator JavaDoc locator) {
228     }
229
230     public void startDocument()
231             throws SAXException JavaDoc {
232       getDelegate().setDocumentLocator(this);
233       super.startDocument();
234     }
235
236     public void startElement(String JavaDoc namespaceURI, String JavaDoc localName,
237                              String JavaDoc qName, Attributes JavaDoc atts)
238             throws SAXException JavaDoc {
239       String JavaDoc value = atts.getValue(LOCATION_URI, "line-number");
240       if (value != null) {
241         try {
242           lineNumber = Integer.parseInt(value);
243         }
244         catch (NumberFormatException JavaDoc e) {
245           lineNumber = -1;
246         }
247       }
248       else
249         lineNumber = -1;
250       try {
251         super.startElement(namespaceURI, localName, qName, atts);
252       }
253       catch (SAXException JavaDoc e) {
254         this.exception = e;
255         setDelegate(null);
256       }
257       lineNumber = -1;
258     }
259
260     public String JavaDoc getPublicId() {
261       return null;
262     }
263
264     public String JavaDoc getSystemId() {
265       return systemId;
266     }
267
268     public int getLineNumber() {
269       return lineNumber;
270     }
271
272     public int getColumnNumber() {
273       return -1;
274     }
275   }
276
277   static class TransformStage extends XMLReaderImpl {
278     private ContentHandler contentHandler;
279     private final Transformer JavaDoc transformer;
280     private final SAXSource JavaDoc transformSource;
281     private final String JavaDoc systemId;
282     private final CountingErrorHandler ceh;
283     private final Localizer localizer;
284
285     TransformStage(Transformer JavaDoc transformer, SAXSource JavaDoc transformSource, String JavaDoc systemId,
286                    CountingErrorHandler ceh, Localizer localizer) {
287       this.transformer = transformer;
288       this.transformSource = transformSource;
289       this.systemId = systemId;
290       this.ceh = ceh;
291       this.localizer = localizer;
292     }
293
294     public void parse(InputSource JavaDoc input)
295             throws IOException JavaDoc, SAXException JavaDoc {
296       try {
297         LocationFilter handler = new LocationFilter(new ErrorFilter(contentHandler, ceh, localizer),
298                                                                     systemId);
299         transformer.transform(transformSource, new SAXResult JavaDoc(handler));
300         SAXException JavaDoc exception = handler.getException();
301         if (exception != null)
302           throw exception;
303       }
304       catch (TransformerException JavaDoc e) {
305         if (e.getException() instanceof IOException JavaDoc)
306           throw (IOException JavaDoc)e.getException();
307         throw ValidatorImpl.toSAXException(e);
308       }
309       if (ceh.getHadErrorOrFatalError())
310         throw new SAXException JavaDoc(new IncorrectSchemaException());
311     }
312
313     public ContentHandler getContentHandler() {
314       return contentHandler;
315     }
316
317     public void setContentHandler(ContentHandler contentHandler) {
318       this.contentHandler = contentHandler;
319     }
320   }
321
322   static class SAXErrorListener implements ErrorListener JavaDoc {
323      private final ErrorHandler eh;
324      private final String JavaDoc systemId;
325      private boolean hadError = false;
326      SAXErrorListener(ErrorHandler eh, String JavaDoc systemId) {
327        this.eh = eh;
328        this.systemId = systemId;
329      }
330
331      boolean getHadError() {
332        return hadError;
333      }
334
335      public void warning(TransformerException JavaDoc exception)
336              throws TransformerException JavaDoc {
337        SAXParseException JavaDoc spe = transform(exception);
338        try {
339          eh.warning(spe);
340        }
341        catch (SAXException JavaDoc e) {
342          throw new TransformerException JavaDoc(new UserException(e));
343        }
344      }
345
346      public void error(TransformerException JavaDoc exception)
347              throws TransformerException JavaDoc {
348        hadError = true;
349        SAXParseException JavaDoc spe = transform(exception);
350        try {
351          eh.error(spe);
352        }
353        catch (SAXException JavaDoc e) {
354          throw new TransformerException JavaDoc(new UserException(e));
355        }
356      }
357
358      public void fatalError(TransformerException JavaDoc exception)
359              throws TransformerException JavaDoc {
360        hadError = true;
361        SAXParseException JavaDoc spe = transform(exception);
362        try {
363          eh.fatalError(spe);
364        }
365        catch (SAXException JavaDoc e) {
366          throw new TransformerException JavaDoc(new UserException(e));
367        }
368      }
369
370      SAXParseException JavaDoc transform(TransformerException JavaDoc exception) throws TransformerException JavaDoc {
371        Throwable JavaDoc cause = exception.getException();
372        // Xalan takes it upon itself to catch exceptions and pass them to the ErrorListener.
373
if (cause instanceof RuntimeException JavaDoc)
374          throw (RuntimeException JavaDoc)cause;
375        if (cause instanceof SAXException JavaDoc
376            || cause instanceof IncorrectSchemaException
377            || cause instanceof IOException JavaDoc)
378          throw exception;
379        SourceLocator JavaDoc locator = exception.getLocator();
380        if (locator == null)
381          return new SAXParseException JavaDoc(exception.getMessage(), null);
382        // Xalan sometimes loses the systemId; work around this.
383
String JavaDoc s = locator.getSystemId();
384        if (s == null)
385         s = systemId;
386        return new SAXParseException JavaDoc(exception.getMessage(),
387                                     null,
388                                     s,
389                                     locator.getLineNumber(),
390                                     -1);
391      }
392    }
393
394   public Schema createSchema(InputSource JavaDoc in, PropertyMap properties)
395           throws IOException JavaDoc, SAXException JavaDoc, IncorrectSchemaException {
396     ErrorHandler eh = ValidateProperty.ERROR_HANDLER.get(properties);
397     SAXErrorListener errorListener = new SAXErrorListener(eh, in.getSystemId());
398     UserWrapErrorHandler ueh1 = new UserWrapErrorHandler(eh);
399     UserWrapErrorHandler ueh2 = new UserWrapErrorHandler(eh);
400     try {
401       PropertyMapBuilder builder = new PropertyMapBuilder(properties);
402       ValidateProperty.ERROR_HANDLER.put(builder, ueh1);
403       SAXSource JavaDoc source = createValidatingSource(in, builder.toPropertyMap(), ueh1);
404       source = createTransformingSource(source,
405                                         SchematronProperty.PHASE.get(properties),
406                                         properties.contains(SchematronProperty.DIAGNOSE),
407                                         in.getSystemId(),
408                                         ueh2);
409       TransformerFactory JavaDoc transformerFactory = (TransformerFactory JavaDoc)transformerFactoryClass.newInstance();
410       initTransformerFactory(transformerFactory);
411       transformerFactory.setErrorListener(errorListener);
412       Templates JavaDoc templates = transformerFactory.newTemplates(source);
413       return new SchemaImpl(templates, properties, supportedPropertyIds);
414     }
415     catch (TransformerConfigurationException JavaDoc e) {
416       throw toSAXException(e, errorListener.getHadError()
417                               || ueh1.getHadErrorOrFatalError()
418                               || ueh2.getHadErrorOrFatalError());
419     }
420     catch (InstantiationException JavaDoc e) {
421       throw new SAXException JavaDoc(e);
422     }
423     catch (IllegalAccessException JavaDoc e) {
424       throw new SAXException JavaDoc(e);
425     }
426   }
427
428   private SAXSource JavaDoc createValidatingSource(InputSource JavaDoc in, PropertyMap properties, CountingErrorHandler ceh) throws SAXException JavaDoc {
429     Validator validator = schematronSchema.createValidator(properties);
430     XMLReaderCreator xrc = ValidateProperty.XML_READER_CREATOR.get(properties);
431     XMLReader JavaDoc xr = xrc.createXMLReader();
432     xr.setErrorHandler(ceh);
433     return new SAXSource JavaDoc(new ValidateStage(xr, validator, ceh), in);
434   }
435
436   private SAXSource JavaDoc createTransformingSource(SAXSource JavaDoc in, String JavaDoc phase, boolean diagnose,
437                                              String JavaDoc systemId, CountingErrorHandler ceh) throws SAXException JavaDoc {
438     try {
439       Transformer JavaDoc transformer = schematron.newTransformer();
440       transformer.setErrorListener(new DraconianErrorListener());
441       if (phase != null)
442         transformer.setParameter("phase", phase);
443       if (diagnose)
444         transformer.setParameter("diagnose", Boolean.TRUE);
445       return new SAXSource JavaDoc(new TransformStage(transformer, in, systemId, ceh, localizer),
446                            new InputSource JavaDoc(systemId));
447     }
448     catch (TransformerConfigurationException JavaDoc e) {
449       throw new SAXException JavaDoc(e);
450     }
451   }
452
453   private SAXException JavaDoc toSAXException(TransformerException JavaDoc e, boolean hadError) throws IOException JavaDoc, IncorrectSchemaException {
454       return causeToSAXException(e.getException(), hadError);
455     }
456
457   private SAXException JavaDoc causeToSAXException(Throwable JavaDoc cause, boolean hadError) throws IOException JavaDoc, IncorrectSchemaException {
458       if (cause instanceof RuntimeException JavaDoc)
459         throw (RuntimeException JavaDoc)cause;
460       if (cause instanceof IOException JavaDoc)
461         throw (IOException JavaDoc)cause;
462       if (cause instanceof IncorrectSchemaException)
463         throw (IncorrectSchemaException)cause;
464       if (cause instanceof SAXException JavaDoc)
465         return causeToSAXException(((SAXException JavaDoc)cause).getException(), hadError);
466       if (cause instanceof TransformerException JavaDoc)
467         return toSAXException((TransformerException JavaDoc)cause, hadError);
468       if (cause instanceof UserException)
469         return toSAXException((UserException)cause);
470       if (hadError)
471         throw new IncorrectSchemaException();
472       return new SAXException JavaDoc(localizer.message("unexpected_schema_creation_error"),
473                               cause instanceof Exception JavaDoc ? (Exception JavaDoc)cause : null);
474     }
475
476   private static SAXException JavaDoc toSAXException(UserException e) throws IOException JavaDoc, IncorrectSchemaException {
477       SAXException JavaDoc se = e.getException();
478       Exception JavaDoc cause = se.getException();
479       if (cause instanceof IncorrectSchemaException)
480         throw (IncorrectSchemaException)cause;
481       if (cause instanceof IOException JavaDoc)
482         throw (IOException JavaDoc)cause;
483       return se;
484     }
485
486   private static String JavaDoc fullResourceName(String JavaDoc name) {
487     String JavaDoc className = SchemaReaderImpl.class.getName();
488     return className.substring(0, className.lastIndexOf('.')).replace('.', '/') + "/resources/" + name;
489   }
490
491   private static InputStream JavaDoc getResourceAsStream(String JavaDoc resourceName) {
492     ClassLoader JavaDoc cl = SchemaReaderImpl.class.getClassLoader();
493     // XXX see if we should borrow 1.2 code from Service
494
if (cl == null)
495       return ClassLoader.getSystemResourceAsStream(resourceName);
496     else
497       return cl.getResourceAsStream(resourceName);
498   }
499 }
500
Popular Tags