KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > validation > impl > AbstractValidator


1 /*
2  * Copyright 1999-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.cocoon.components.validation.impl;
17
18 import java.io.IOException JavaDoc;
19
20 import org.apache.avalon.framework.activity.Disposable;
21 import org.apache.avalon.framework.logger.LogEnabled;
22 import org.apache.avalon.framework.logger.Logger;
23 import org.apache.avalon.framework.service.ServiceException;
24 import org.apache.avalon.framework.service.ServiceManager;
25 import org.apache.avalon.framework.service.Serviceable;
26 import org.apache.cocoon.components.validation.Schema;
27 import org.apache.cocoon.components.validation.SchemaParser;
28 import org.apache.cocoon.components.validation.ValidationHandler;
29 import org.apache.cocoon.components.validation.Validator;
30 import org.apache.cocoon.components.validation.ValidatorException;
31 import org.apache.excalibur.source.Source;
32 import org.apache.excalibur.source.SourceResolver;
33 import org.apache.excalibur.xml.sax.NOPContentHandler;
34 import org.apache.excalibur.xml.sax.SAXParser;
35 import org.apache.excalibur.xml.sax.XMLizable;
36 import org.xml.sax.Attributes JavaDoc;
37 import org.xml.sax.ErrorHandler JavaDoc;
38 import org.xml.sax.InputSource JavaDoc;
39 import org.xml.sax.SAXException JavaDoc;
40
41 /**
42  * <p>The {@link AbstractValidator} provides a generic implementation of the methods
43  * specified by the {@link Validator} interface.</p>
44  *
45  * <p>Final implementations must implement three component management methods
46  * {@link #lookupParserByGrammar(String)}, {@link #lookupParserByName(String)} and
47  * {@link #releaseParser(SchemaParser)}.</p>
48  *
49  * <p>In addition to this, they might also override the default implementation of
50  * the {@link #getSchema(SchemaParser, Source, String)} method, for example when
51  * caching {@link Schema} instances.</p>
52  *
53  * <p>This implementation provides a simple grammar identification mechanism, which
54  * can be overridden by reimplementing the {@link #detectGrammar(Source)} method
55  * provided by this class.</p>
56  *
57  * @author <a HREF="mailto:pier@betaversion.org">Pier Fumagalli</a>
58  */

59 public abstract class AbstractValidator
60 implements Validator, Serviceable, Disposable, LogEnabled {
61
62     /** <p>The configured {@link ServiceManager} instance.</p> */
63     protected ServiceManager manager = null;
64     /** <p>The configured {@link SourceResolver} instance.</p> */
65     protected SourceResolver resolver = null;
66     /** <p>The configured {@link Logger} instance.</p> */
67     protected Logger logger = null;
68
69     /**
70      * <p>Create a new {@link AbstractValidator} instance.</p>
71      */

72     public AbstractValidator() {
73         super();
74     }
75
76     /**
77      * <p>Enable logging.</p>
78      */

79     public void enableLogging(Logger logger) {
80         this.logger = logger;
81     }
82
83     /**
84      * <p>Specify the {@link ServiceManager} available to this instance.</p>
85      */

86     public void service(ServiceManager manager)
87     throws ServiceException {
88         this.manager = manager;
89         this.resolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
90     }
91
92     /**
93      * <p>Dispose of this component instance.</p>
94      */

95     public void dispose() {
96         if (this.resolver != null) this.manager.release(this.resolver);
97     }
98
99     /* =========================================================================== */
100     /* IMPLEMENTATION OF THE VALIDATOR INTERFACE */
101     /* =========================================================================== */
102
103     /**
104      * <p>Return a {@link ValidationHandler} validating an XML document according to
105      * the schema found at the specified location.</p>
106      *
107      * <p>The {@link Validator} will attempt to automatically detect the grammar
108      * language of the specified schema, and each error or warning occurring while
109      * validating the document will trigger a {@link SAXException} to be thrown back
110      * to the caller.</p>
111      *
112      * @param uri the location of the schema to use to validate the document.
113      * @return a <b>non null</b> {@link ValidationHandler} able to SAX events from
114      * the original XML document to validate.
115      * @throws IOException if an I/O error occurred parsing the schema.
116      * @throws SAXException if a grammar error occurred parsing the schema.
117      * @throws ValidatorException if the grammar language of the specified schema
118      * could not be detected or was not supported.
119      * @link SchemaParser#getSchema(String, String)
120      * @link Schema#createValidator(ErrorHandler)
121      */

122     public ValidationHandler getValidationHandler(String JavaDoc uri)
123     throws IOException JavaDoc, SAXException JavaDoc, ValidatorException {
124         return this.getValidationHandler(uri, null, null);
125     }
126
127     /**
128      * <p>Return a {@link ValidationHandler} validating an XML document according to
129      * the schema found at the specified location.</p>
130      *
131      * <p>Each error or warning occurring while validating the document will trigger
132      * a {@link SAXException} to be thrown back to the caller.</p>
133      *
134      * @param uri the location of the schema to use to validate the document.
135      * @param grammar the grammar language of the schema to parse.
136      * @return a <b>non null</b> {@link ValidationHandler} able to SAX events from
137      * the original XML document to validate.
138      * @throws IOException if an I/O error occurred parsing the schema.
139      * @throws SAXException if a grammar error occurred parsing the schema.
140      * @throws ValidatorException if the specified grammar language wasn't supported.
141      * @link SchemaParser#getSchema(String, String)
142      * @link Schema#createValidator(ErrorHandler)
143      */

144     public ValidationHandler getValidationHandler(String JavaDoc uri, String JavaDoc grammar)
145     throws IOException JavaDoc, SAXException JavaDoc, ValidatorException {
146         return this.getValidationHandler(uri, grammar, null);
147     }
148
149     /**
150      * <p>Return a {@link ValidationHandler} validating an XML document according to
151      * the schema found at the specified location.</p>
152      *
153      * <p>The {@link Validator} will attempt to automatically detect the grammar
154      * language of the specified schema, while each validation error or warning will
155      * be passed to the specified {@link ErrorHandler} which will have the ability
156      * to generate and throw a {@link SAXException} back to the caller.</p>
157      *
158      * @param uri the location of the schema to use to validate the document.
159      * @param errorHandler the {@link ErrorHandler} notified of validation problems.
160      * @return a <b>non null</b> {@link ValidationHandler} able to SAX events from
161      * the original XML document to validate.
162      * @throws IOException if an I/O error occurred parsing the schema.
163      * @throws SAXException if a grammar error occurred parsing the schema.
164      * @throws ValidatorException if the grammar language of the specified schema
165      * could not be detected or was not supported.
166      * @link SchemaParser#getSchema(String, String)
167      * @link Schema#createValidator(ErrorHandler)
168      */

169     public ValidationHandler getValidationHandler(String JavaDoc uri, ErrorHandler JavaDoc errorHandler)
170     throws IOException JavaDoc, SAXException JavaDoc, ValidatorException {
171         return this.getValidationHandler(uri, null, errorHandler);
172     }
173
174     /**
175      * <p>Return a {@link ValidationHandler} validating an XML document according to
176      * the schema found at the specified location.</p>
177      *
178      * <p>Each validation error or warning will be passed to the specified
179      * {@link ErrorHandler} which will have the ability to generate and throw a
180      * {@link SAXException} back to the caller.</p>
181      *
182      * @param uri the location of the schema to use to validate the document.
183      * @param grammar the grammar language of the schema to parse.
184      * @param errorHandler the {@link ErrorHandler} notified of validation problems.
185      * @return a <b>non null</b> {@link ValidationHandler} able to SAX events from
186      * the original XML document to validate.
187      * @throws IOException if an I/O error occurred parsing the schema.
188      * @throws SAXException if a grammar error occurred parsing the schema.
189      * @throws ValidatorException if the specified grammar language wasn't supported.
190      * @link SchemaParser#getSchema(String, String)
191      * @link Schema#createValidator(ErrorHandler)
192      */

193     public ValidationHandler getValidationHandler(String JavaDoc uri, String JavaDoc grammar,
194                                                ErrorHandler JavaDoc errorHandler)
195     throws IOException JavaDoc, SAXException JavaDoc, ValidatorException {
196         if (uri == null) throw new IOException JavaDoc("Specified schema URI was null");
197         Source source = null;
198         try {
199             source = this.resolver.resolveURI(uri);
200             return this.getValidationHandler(source, grammar, errorHandler);
201         } finally {
202             if (source != null) this.resolver.release(source);
203         }
204     }
205
206     /**
207      * <p>Return a {@link ValidationHandler} validating an XML document according to
208      * the schema found at the specified location.</p>
209      *
210      * <p>The {@link Validator} will attempt to automatically detect the grammar
211      * language of the specified schema, and each error or warning occurring while
212      * validating the document will trigger a {@link SAXException} to be thrown back
213      * to the caller.</p>
214      *
215      * @param source the {@link Source} identifying the schema to use for validation.
216      * @return a <b>non null</b> {@link ValidationHandler} able to SAX events from
217      * the original XML document to validate.
218      * @throws IOException if an I/O error occurred parsing the schema.
219      * @throws SAXException if a grammar error occurred parsing the schema.
220      * @throws ValidatorException if the grammar language of the specified schema
221      * could not be detected or was not supported.
222      * @link SchemaParser#getSchema(String, String)
223      * @link Schema#createValidator(ErrorHandler)
224      */

225     public ValidationHandler getValidationHandler(Source source)
226     throws IOException JavaDoc, SAXException JavaDoc, ValidatorException {
227         return this.getValidationHandler(source, null, null);
228     }
229
230     /**
231      * <p>Return a {@link ValidationHandler} validating an XML document according to
232      * the schema found at the specified location.</p>
233      *
234      * <p>Each error or warning occurring while validating the document will trigger
235      * a {@link SAXException} to be thrown back to the caller.</p>
236      *
237      * @param source the {@link Source} identifying the schema to use for validation.
238      * @param grammar the grammar language of the schema to parse.
239      * @return a <b>non null</b> {@link ValidationHandler} able to SAX events from
240      * the original XML document to validate.
241      * @throws IOException if an I/O error occurred parsing the schema.
242      * @throws SAXException if a grammar error occurred parsing the schema.
243      * @throws ValidatorException if the specified grammar language wasn't supported.
244      * @link SchemaParser#getSchema(String, String)
245      * @link Schema#createValidator(ErrorHandler)
246      */

247     public ValidationHandler getValidationHandler(Source source, String JavaDoc grammar)
248     throws IOException JavaDoc, SAXException JavaDoc, ValidatorException {
249         return this.getValidationHandler(source, grammar, null);
250     }
251
252     /**
253      * <p>Return a {@link ValidationHandler} validating an XML document according to
254      * the schema found at the specified location.</p>
255      *
256      * <p>The {@link Validator} will attempt to automatically detect the grammar
257      * language of the specified schema, while each validation error or warning will
258      * be passed to the specified {@link ErrorHandler} which will have the ability
259      * to generate and throw a {@link SAXException} back to the caller.</p>
260      *
261      * @param source the {@link Source} identifying the schema to use for validation.
262      * @param errorHandler the {@link ErrorHandler} notified of validation problems.
263      * @return a <b>non null</b> {@link ValidationHandler} able to SAX events from
264      * the original XML document to validate.
265      * @throws IOException if an I/O error occurred parsing the schema.
266      * @throws SAXException if a grammar error occurred parsing the schema.
267      * @throws ValidatorException if the grammar language of the specified schema
268      * could not be detected or was not supported.
269      * @link SchemaParser#getSchema(String, String)
270      * @link Schema#createValidator(ErrorHandler)
271      */

272     public ValidationHandler getValidationHandler(Source source,
273                                                   ErrorHandler JavaDoc errorHandler)
274     throws IOException JavaDoc, SAXException JavaDoc, ValidatorException {
275         return this.getValidationHandler(source, null, errorHandler);
276     }
277
278     /**
279      * <p>Return a {@link ValidationHandler} validating an XML document according to
280      * the schema found at the specified location.</p>
281      *
282      * <p>Each validation error or warning will be passed to the specified
283      * {@link ErrorHandler} which will have the ability to generate and throw a
284      * {@link SAXException} back to the caller.</p>
285      *
286      * @param source the {@link Source} identifying the schema to use for validation.
287      * @param grammar the grammar language of the schema to parse.
288      * @param errorHandler the {@link ErrorHandler} notified of validation problems.
289      * @return a <b>non null</b> {@link ValidationHandler} able to SAX events from
290      * the original XML document to validate.
291      * @throws IOException if an I/O error occurred parsing the schema.
292      * @throws SAXException if a grammar error occurred parsing the schema.
293      * @throws ValidatorException if the specified grammar language wasn't supported.
294      * @link SchemaParser#getSchema(String, String)
295      * @link Schema#createValidator(ErrorHandler)
296      */

297     public ValidationHandler getValidationHandler(Source source, String JavaDoc grammar,
298                                                ErrorHandler JavaDoc errorHandler)
299     throws IOException JavaDoc, SAXException JavaDoc, ValidatorException {
300         if (errorHandler == null) errorHandler = DraconianErrorHandler.INSTANCE;
301
302         SchemaParser parser = null;
303         try {
304             /* If no grammar was supplied, try to detect one */
305             if (grammar == null) grammar = this.detectGrammar(source);
306
307             /* Save the grammar name and try to find a schema parser */
308             String JavaDoc language = grammar;
309             parser = this.lookupParserByGrammar(grammar);
310
311             /*
312              * If the schema parser for the language was not found, we might have to
313              * look up for the form name:grammar as specified by Validator.
314              */

315             if (parser == null) {
316                 int index = grammar.indexOf(':');
317                 if (index > 0) {
318                     String JavaDoc name = grammar.substring(0, index);
319                     language = grammar.substring(index + 1);
320                     parser = this.lookupParserByName(name);
321                 }
322             }
323
324             /* If still we didn't find any parser, simply die of natural death */
325             if (parser == null) {
326                 String JavaDoc message = "Unsupported grammar language" + grammar;
327                 throw new ValidatorException(message);
328             }
329
330             /* Somehow we have a schema parser, check it supports the gramar */
331             String JavaDoc languages[] = parser.getSupportedGrammars();
332             for (int x = 0; x < languages.length; x++) {
333                 if (! language.equals(languages[x])) continue;
334                 /* Hah! language supported, go ahead and parse now */
335                 Schema schema = this.getSchema(parser, source, language);
336                 return schema.createValidator(errorHandler);
337             }
338
339             /* Something really odd going on, this should never happen */
340             String JavaDoc message = "Schema parser " + parser.getClass().getName() +
341                              " does not support grammar " + grammar;
342             throw new ValidatorException(message);
343
344         } finally {
345             if (parser != null) this.releaseParser(parser);
346         }
347     }
348
349     /* =========================================================================== */
350     /* METHODS TO BE IMPLEMENTED BY THE EXTENDING CLASSES */
351     /* =========================================================================== */
352
353     /**
354      * <p>Attempt to acquire a {@link SchemaParser} interface able to understand
355      * the grammar language specified.</p>
356      *
357      * @param grammar the grammar language that must be understood by the returned
358      * {@link SchemaParser}
359      * @return a {@link SchemaParser} instance or <b>null</b> if none was found able
360      * to understand the specified grammar language.
361      */

362     protected abstract SchemaParser lookupParserByGrammar(String JavaDoc grammar);
363
364     /**
365      * <p>Attempt to acquire a {@link SchemaParser} interface associated with the
366      * specified instance name.</p>
367      *
368      * @param name the name associated with the {@link SchemaParser} to be returned.
369      * @return a {@link SchemaParser} instance or <b>null</b> if none was found.
370      */

371     protected abstract SchemaParser lookupParserByName(String JavaDoc name);
372
373     /**
374      * <p>Release a previously acquired {@link SchemaParser} instance back to its
375      * original component manager.</p>
376      *
377      * <p>This method is supplied in case solid implementations of this class relied
378      * on the {@link ServiceManager} to manage {@link SchemaParser}s instances.</p>
379      *
380      * @param parser the {@link SchemaParser} whose instance is to be released.
381      */

382     protected abstract void releaseParser(SchemaParser parser);
383     
384     /* =========================================================================== */
385     /* METHODS SPECIFIC TO ABSTRACTVALIDATOR OVERRIDABLE BY OTHER IMPLEMENTATIONS */
386     /* =========================================================================== */
387
388     /**
389      * <p>Return a {@link Schema} instance from the specified {@link SchemaParser}
390      * associated with the given {@link Source} and grammar language.</p>
391      *
392      * <p>This method simply implements resolution returning the {@link Schema}
393      * instance acquired calling <code>parser.getSchema(source,grammar)</code>.</p>
394      *
395      * @param parser the {@link SchemaParser} producing the {@link Schema}.
396      * @param source the {@link Source} associated with the {@link Schema} to return.
397      * @param grammar the grammar language of the schema to produce.
398      * @throws SAXException if a grammar error occurred parsing the schema.
399      * @throws IOException if an I/O error occurred parsing the schema.
400      */

401     protected Schema getSchema(SchemaParser parser, Source source, String JavaDoc grammar)
402     throws IOException JavaDoc, SAXException JavaDoc {
403         if (this.logger.isDebugEnabled()) {
404             this.logger.debug("Parsing schema \"" + source.getURI() + "\" using " +
405                               "grammar \"" + grammar + "\" and SourceParser " +
406                               parser.getClass().getName());
407         }
408
409         try {
410             return parser.parseSchema(source, grammar);
411         } catch (IllegalArgumentException JavaDoc exception) {
412             String JavaDoc message = "Schema parser " + parser.getClass().getName() +
413                              " does not support grammar " + grammar;
414             throw new ValidatorException(message, exception);
415         }
416     }
417
418     /**
419      * <p>Attempt to detect the grammar language used by the schema identified
420      * by the specified {@link Source}.</p>
421      *
422      * @param source a {@link Source} instance pointing to the schema to be analyzed.
423      * @throws IOException if an I/O error occurred accessing the schema.
424      * @throws SAXException if an error occurred parsing the schema.
425      * @throws ValidatorException if the language of the schema could not be guessed.
426      */

427     protected String JavaDoc detectGrammar(Source source)
428     throws IOException JavaDoc, SAXException JavaDoc, ValidatorException {
429         if (this.logger.isDebugEnabled()) {
430             this.logger.debug("Detecting grammar for \"" + source.getURI() + "\"");
431         }
432
433         SAXParser xmlParser = null;
434         String JavaDoc grammar = null;
435
436         try {
437             DetectionHandler handler = new DetectionHandler();
438             if (source instanceof XMLizable) {
439                 XMLizable xmlizable = (XMLizable) source;
440                 xmlizable.toSAX(handler);
441             } else {
442                 xmlParser = (SAXParser) this.manager.lookup((SAXParser.ROLE));
443                 InputSource JavaDoc input = new InputSource JavaDoc();
444                 input.setSystemId(source.getURI());
445                 input.setByteStream(source.getInputStream());
446                 xmlParser.parse(input, handler);
447             }
448         } catch (ServiceException exception) {
449             throw new SAXException JavaDoc("Unable to access XML parser", exception);
450         } catch (DetectionException exception) {
451             grammar = exception.grammar;
452         } finally {
453             if (xmlParser != null) this.manager.release(xmlParser);
454         }
455
456         if (("".equals(grammar)) || (grammar == null)) {
457             String JavaDoc message = "Unable to detect grammar for schema at ";
458             throw new ValidatorException(message + source.getURI());
459         } else {
460             if (this.logger.isDebugEnabled()) {
461                 this.logger.debug("Grammar \"" + grammar + "\" detected for " +
462                                   "schema \"" + source.getURI());
463             }
464             return grammar;
465         }
466     }
467
468     /* =========================================================================== */
469     /* METHODS AND INNER CLASSES FOR AUTOMATIC GRAMMAR LANGUAGE DETECTION */
470     /* =========================================================================== */
471
472     /**
473      * <p>A simple implementation of a {@link ValidationHandler} detecting schemas
474      * based on the namespace of the root element.</p>
475      */

476     private static final class DetectionHandler extends NOPContentHandler {
477         
478         /**
479          * <p>Detect the namespace of the root element and always throw a
480          * {@link SAXException} or a {@link DetectionException}.</p>
481          */

482         public void startElement(String JavaDoc ns, String JavaDoc lnam, String JavaDoc qnam, Attributes JavaDoc a)
483         throws SAXException JavaDoc {
484             throw new DetectionException(ns);
485         }
486     }
487
488     /**
489      * <p>An exception thrown by {@link DetectionHandler} representing that
490      * a grammar was successfully detected.</p>
491      */

492     private static final class DetectionException extends SAXException JavaDoc {
493
494         private final String JavaDoc grammar;
495
496         private DetectionException(String JavaDoc grammar) {
497             super ("Grammar detected: " + grammar);
498             this.grammar = grammar;
499         }
500     }
501 }
502
Popular Tags