1 /* EventFilter.java --
2    Copyright (C) 1999,2000,2001 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 package gnu.xml.pipeline;
39 
40 import java.lang.reflect.InvocationTargetException;
41 import java.lang.reflect.Method;
42 
43 import org.xml.sax.*;
44 import org.xml.sax.ext.*;
45 import org.xml.sax.helpers.XMLFilterImpl;
46 
47 /**
48  * A customizable event consumer, used to assemble various kinds of filters
49  * using SAX handlers and an optional second consumer.  It can be constructed
50  * in two ways: <ul>
51  *
52  *  <li> To serve as a passthrough, sending all events to a second consumer.
53  *  The second consumer may be identified through {@link #getNext}.
54  *
55  *  <li> To serve as a dead end, with all handlers null;
56  *  {@link #getNext} returns null.
57  *
58  * </ul>
59  *
60  * <p> Additionally, SAX handlers may be assigned, which completely replace
61  * the "upstream" view (through {@link EventConsumer}) of handlers, initially
62  * null or the "next" consumer provided to the constructor.  To make
63  * it easier to build specialized filter classes, this class implements
64  * all the standard SAX consumer handlers, and those implementations
65  * delegate "downstream" to the consumer accessed by {@link #getNext}.
66  *
67  * <p> The simplest way to create a custom a filter class is to create a
68  * subclass which overrides one or more handler interface methods.  The
69  * constructor for that subclass then registers itself as a handler for
70  * those interfaces using a call such as <em>setContentHandler(this)</em>,
71  * so the "upstream" view of event delivery is modified from the state
72  * established in the base class constructor.  That way,
73  * the overridden methods intercept those event callbacks
74  * as they go "downstream", and
75  * all other event callbacks will pass events to any next consumer.
76  * Overridden methods may invoke superclass methods (perhaps after modifying
77  * parameters) if they wish to delegate such calls.  Such subclasses
78  * should use {@link #getErrorHandler} to report errors using the
79  * common error reporting mechanism.
80  *
81  * <p> Another important technique is to construct a filter consisting
82  * of only a few specific types of handler.  For example, one could easily
83  * prune out lexical events or various declarations by providing handlers
84  * which don't pass those events downstream, or by providing null handlers.
85  *
86  * <hr />
87  *
88  * <p> This may be viewed as the consumer oriented analogue of the SAX2
89  * {@link org.xml.sax.helpers.XMLFilterImpl XMLFilterImpl} class.
90  * Key differences include: <ul>
91  *
92  *      <li> This fully separates consumer and producer roles:  it
93  *      does not implement the producer side <em>XMLReader</em> or
94  *      <em>EntityResolver</em> interfaces, so it can only be used
95  *      in "push" mode (it has no <em>parse()</em> methods).
96  *
97  *      <li> "Extension" handlers are fully supported, enabling a
98  *      richer set of application requirements.
99  *      And it implements {@link EventConsumer}, which groups related
100  *      consumer methods together, rather than leaving them separated.
101  *
102  *      <li> The chaining which is visible is "downstream" to the next
103  *      consumer, not "upstream" to the preceding producer.
104  *      It supports "fan-in", where
105  *      a consumer can be fed by several producers.  (For "fan-out",
106  *      see the {@link TeeConsumer} class.)
107  *
108  *      <li> Event chaining is set up differently.  It is intended to
109  *      work "upstream" from terminus towards producer, during filter
110  *      construction, as described above.
111  *      This is part of an early binding model:
112  *      events don't need to pass through stages which ignore them.
113  *
114  *      <li> ErrorHandler support is separated, on the grounds that
115  *      pipeline stages need to share the same error handling policy.
116  *      For the same reason, error handler setup goes "downstream":
117  *      when error handlers get set, they are passed to subsequent
118  *      consumers.
119  *
120  *      </ul>
121  *
122  * <p> The {@link #chainTo chainTo()} convenience routine supports chaining to
123  * an XMLFilterImpl, in its role as a limited functionality event
124  * consumer.  Its event producer role ({@link XMLFilter}) is ignored.
125  *
126  * <hr />
127  *
128  * <p> The {@link #bind bind()} routine may be used associate event pipelines
129  * with any kind of {@link XMLReader} that will produce the events.
130  * Such pipelines don't necessarily need to have any members which are
131  * implemented using this class.  That routine has some intelligence
132  * which supports automatic changes to parser feature flags, letting
133  * event piplines become largely independent of the particular feature
134  * sets of parsers.
135  *
136  * @author David Brownell
137  */
138 public class EventFilter
139     implements EventConsumer, ContentHandler, DTDHandler,
140             LexicalHandler, DeclHandler
141 {
142     // SAX handlers
143     private ContentHandler              docHandler, docNext;
144     private DTDHandler                  dtdHandler, dtdNext;
145     private LexicalHandler              lexHandler, lexNext;
146     private DeclHandler                 declHandler, declNext;
147     // and ideally, one more for the stuff SAX2 doesn't show
148 
149     private Locator                     locator;
150     private EventConsumer               next;
151     private ErrorHandler                errHandler;
152 
153 
154     /** SAX2 URI prefix for standard feature flags. */
155     public static final String          FEATURE_URI
156         = "http://xml.org/sax/features/";
157     /** SAX2 URI prefix for standard properties (mostly for handlers). */
158     public static final String          PROPERTY_URI
159         = "http://xml.org/sax/properties/";
160 
161     /** SAX2 property identifier for {@link DeclHandler} events */
162     public static final String          DECL_HANDLER
163         = PROPERTY_URI + "declaration-handler";
164     /** SAX2 property identifier for {@link LexicalHandler} events */
165     public static final String          LEXICAL_HANDLER
166         = PROPERTY_URI + "lexical-handler";
167 
168     //
169     // These class objects will be null if the relevant class isn't linked.
170     // Small configurations (pJava and some kinds of embedded systems) need
171     // to facilitate smaller executables.  So "instanceof" is undesirable
172     // when bind() sees if it can remove some stages.
173     //
174     // SECURITY NOTE:  assuming all these classes are part of the same sealed
175     // package, there's no problem saving these in the instance of this class
176     // that's associated with "this" class loader.  But that wouldn't be true
177     // for classes in another package.
178     //
179     private static boolean              loaded;
180     private static Class                nsClass;
181     private static Class                validClass;
182     private static Class                wfClass;
183     private static Class                xincClass;
184 
getClassLoader()185     static ClassLoader getClassLoader ()
186     {
187         Method m = null;
188 
189         try {
190             m = Thread.class.getMethod("getContextClassLoader");
191         } catch (NoSuchMethodException e) {
192             // Assume that we are running JDK 1.1, use the current ClassLoader
193             return EventFilter.class.getClassLoader();
194         }
195 
196         try {
197             return (ClassLoader) m.invoke(Thread.currentThread());
198         } catch (IllegalAccessException e) {
199             // assert(false)
200             throw new UnknownError(e.getMessage());
201         } catch (InvocationTargetException e) {
202             // assert(e.getTargetException() instanceof SecurityException)
203             throw new UnknownError(e.getMessage());
204         }
205     }
206 
loadClass(ClassLoader classLoader, String className)207     static Class loadClass (ClassLoader classLoader, String className)
208     {
209         try {
210             if (classLoader == null)
211                 return Class.forName(className);
212             else
213                 return classLoader.loadClass(className);
214         } catch (Exception e) {
215             return null;
216         }
217     }
218 
loadClasses()219     static private void loadClasses ()
220     {
221         ClassLoader     loader = getClassLoader ();
222 
223         nsClass = loadClass (loader, "gnu.xml.pipeline.NSFilter");
224         validClass = loadClass (loader, "gnu.xml.pipeline.ValidationConsumer");
225         wfClass = loadClass (loader, "gnu.xml.pipeline.WellFormednessFilter");
226         xincClass = loadClass (loader, "gnu.xml.pipeline.XIncludeFilter");
227         loaded = true;
228     }
229 
230 
231     /**
232      * Binds the standard SAX2 handlers from the specified consumer
233      * pipeline to the specified producer.  These handlers include the core
234      * {@link ContentHandler} and {@link DTDHandler}, plus the extension
235      * {@link DeclHandler} and {@link LexicalHandler}.  Any additional
236      * application-specific handlers need to be bound separately.
237      * The {@link ErrorHandler} is handled differently:  the producer's
238      * error handler is passed through to the consumer pipeline.
239      * The producer is told to include namespace prefix information if it
240      * can, since many pipeline stages need that Infoset information to
241      * work well.
242      *
243      * <p> At the head of the pipeline, certain standard event filters are
244      * recognized and handled specially.  This facilitates construction
245      * of processing pipelines that work regardless of the capabilities
246      * of the XMLReader implementation in use; for example, it permits
247      * validating output of a {@link gnu.xml.util.DomParser}. <ul>
248      *
249      *  <li> {@link NSFilter} will be removed if the producer can be
250      *  told not to discard namespace data, using the "namespace-prefixes"
251      *  feature flag.
252      *
253      *  <li> {@link ValidationConsumer} will be removed if the producer
254      *  can be told to validate, using the "validation" feature flag.
255      *
256      *  <li> {@link WellFormednessFilter} is always removed, on the
257      *  grounds that no XMLReader is permitted to producee malformed
258      *  event streams and this would just be processing overhead.
259      *
260      *  <li> {@link XIncludeFilter} stops the special handling, except
261      *  that it's told about the "namespace-prefixes" feature of the
262      *  event producer so that the event stream is internally consistent.
263      *
264      *  <li> The first consumer which is not one of those classes stops
265      *  such special handling.  This means that if you want to force
266      *  one of those filters to be used, you could just precede it with
267      *  an instance of {@link EventFilter} configured as a pass-through.
268      *  You might need to do that if you are using an {@link NSFilter}
269      *  subclass to fix names found in attributes or character data.
270      *
271      *  </ul>
272      *
273      * <p> Other than that, this method works with any kind of event consumer,
274      * not just event filters.  Note that in all cases, the standard handlers
275      * are assigned; any previous handler assignments for the handler will
276      * be overridden.
277      *
278      * @param producer will deliver events to the specified consumer
279      * @param consumer pipeline supplying event handlers to be associated
280      *  with the producer (may not be null)
281      */
bind(XMLReader producer, EventConsumer consumer)282     public static void bind (XMLReader producer, EventConsumer consumer)
283     {
284         Class   klass = null;
285         boolean prefixes;
286 
287         if (!loaded)
288             loadClasses ();
289 
290         // DOM building, printing, layered validation, and other
291         // things don't work well when prefix info is discarded.
292         // Include it by default, whenever possible.
293         try {
294             producer.setFeature (FEATURE_URI + "namespace-prefixes",
295                 true);
296             prefixes = true;
297         } catch (SAXException e) {
298             prefixes = false;
299         }
300 
301         // NOTE:  This loop doesn't use "instanceof", since that
302         // would prevent compiling/linking without those classes
303         // being present.
304         while (consumer != null) {
305             klass = consumer.getClass ();
306 
307             // we might have already changed this problematic SAX2 default.
308             if (nsClass != null && nsClass.isAssignableFrom (klass)) {
309                 if (!prefixes)
310                     break;
311                 consumer = ((EventFilter)consumer).getNext ();
312 
313             // the parser _might_ do DTD validation by default ...
314             // if not, maybe we can change this setting.
315             } else if (validClass != null
316                     && validClass.isAssignableFrom (klass)) {
317                 try {
318                     producer.setFeature (FEATURE_URI + "validation",
319                         true);
320                     consumer = ((ValidationConsumer)consumer).getNext ();
321                 } catch (SAXException e) {
322                     break;
323                 }
324 
325             // parsers are required not to have such bugs
326             } else if (wfClass != null && wfClass.isAssignableFrom (klass)) {
327                 consumer = ((WellFormednessFilter)consumer).getNext ();
328 
329             // stop on the first pipeline stage we can't remove
330             } else
331                 break;
332 
333             if (consumer == null)
334                 klass = null;
335         }
336 
337         // the actual setting here doesn't matter as much
338         // as that producer and consumer agree
339         if (xincClass != null && klass != null
340                 && xincClass.isAssignableFrom (klass))
341             ((XIncludeFilter)consumer).setSavingPrefixes (prefixes);
342 
343         // Some SAX parsers can't handle null handlers -- bleech
344         DefaultHandler2 h = new DefaultHandler2 ();
345 
346         if (consumer != null && consumer.getContentHandler () != null)
347             producer.setContentHandler (consumer.getContentHandler ());
348         else
349             producer.setContentHandler (h);
350         if (consumer != null && consumer.getDTDHandler () != null)
351             producer.setDTDHandler (consumer.getDTDHandler ());
352         else
353             producer.setDTDHandler (h);
354 
355         try {
356             Object      dh;
357 
358             if (consumer != null)
359                 dh = consumer.getProperty (DECL_HANDLER);
360             else
361                 dh = null;
362             if (dh == null)
363                 dh = h;
364             producer.setProperty (DECL_HANDLER, dh);
365         } catch (Exception e) { /* ignore */ }
366         try {
367             Object      lh;
368 
369             if (consumer != null)
370                 lh = consumer.getProperty (LEXICAL_HANDLER);
371             else
372                 lh = null;
373             if (lh == null)
374                 lh = h;
375             producer.setProperty (LEXICAL_HANDLER, lh);
376         } catch (Exception e) { /* ignore */ }
377 
378         // this binding goes the other way around
379         if (producer.getErrorHandler () == null)
380             producer.setErrorHandler (h);
381         if (consumer != null)
382             consumer.setErrorHandler (producer.getErrorHandler ());
383     }
384 
385     /**
386      * Initializes all handlers to null.
387      */
388         // constructor used by PipelineFactory
EventFilter()389     public EventFilter () { }
390 
391 
392     /**
393      * Handlers that are not otherwise set will default to those from
394      * the specified consumer, making it easy to pass events through.
395      * If the consumer is null, all handlers are initialzed to null.
396      */
397         // constructor used by PipelineFactory
EventFilter(EventConsumer consumer)398     public EventFilter (EventConsumer consumer)
399     {
400         if (consumer == null)
401             return;
402 
403         next = consumer;
404 
405         // We delegate through the "xxNext" handlers, and
406         // report the "xxHandler" ones on our input side.
407 
408         // Normally a subclass would both override handler
409         // methods and register itself as the "xxHandler".
410 
411         docHandler = docNext = consumer.getContentHandler ();
412         dtdHandler = dtdNext = consumer.getDTDHandler ();
413         try {
414             declHandler = declNext = (DeclHandler)
415                     consumer.getProperty (DECL_HANDLER);
416         } catch (SAXException e) { /* leave value null */ }
417         try {
418             lexHandler = lexNext = (LexicalHandler)
419                     consumer.getProperty (LEXICAL_HANDLER);
420         } catch (SAXException e) { /* leave value null */ }
421     }
422 
423     /**
424      * Treats the XMLFilterImpl as a limited functionality event consumer,
425      * by arranging to deliver events to it; this lets such classes be
426      * "wrapped" as pipeline stages.
427      *
428      * <p> <em>Upstream Event Setup:</em>
429      * If no handlers have been assigned to this EventFilter, then the
430      * handlers from specified XMLFilterImpl are returned from this
431      * {@link EventConsumer}: the XMLFilterImpl is just "wrapped".
432      * Otherwise the specified handlers will be returned.
433      *
434      * <p> <em>Downstream Event Setup:</em>
435      * Subclasses may chain event delivery to the specified XMLFilterImpl
436      * by invoking the appropiate superclass methods,
437      * as if their constructor passed a "next" EventConsumer to the
438      * constructor for this class.
439      * If this EventFilter has an ErrorHandler, it is assigned as
440      * the error handler for the XMLFilterImpl, just as would be
441      * done for a next stage implementing {@link EventConsumer}.
442      *
443      * @param next the next downstream component of the pipeline.
444      * @exception IllegalStateException if the "next" consumer has
445      *  already been set through the constructor.
446      */
chainTo(XMLFilterImpl next)447     public void chainTo (XMLFilterImpl next)
448     {
449         if (this.next != null)
450             throw new IllegalStateException ();
451 
452         docNext = next.getContentHandler ();
453         if (docHandler == null)
454             docHandler = docNext;
455         dtdNext = next.getDTDHandler ();
456         if (dtdHandler == null)
457             dtdHandler = dtdNext;
458 
459         try {
460             declNext = (DeclHandler) next.getProperty (DECL_HANDLER);
461             if (declHandler == null)
462                 declHandler = declNext;
463         } catch (SAXException e) { /* leave value null */ }
464         try {
465             lexNext = (LexicalHandler) next.getProperty (LEXICAL_HANDLER);
466             if (lexHandler == null)
467                 lexHandler = lexNext;
468         } catch (SAXException e) { /* leave value null */ }
469 
470         if (errHandler != null)
471             next.setErrorHandler (errHandler);
472     }
473 
474     /**
475      * Records the error handler that should be used by this stage, and
476      * passes it "downstream" to any subsequent stage.
477      */
setErrorHandler(ErrorHandler handler)478     final public void setErrorHandler (ErrorHandler handler)
479     {
480         errHandler = handler;
481         if (next != null)
482             next.setErrorHandler (handler);
483     }
484 
485     /**
486      * Returns the error handler assigned this filter stage, or null
487      * if no such assigment has been made.
488      */
getErrorHandler()489     final public ErrorHandler getErrorHandler ()
490     {
491         return errHandler;
492     }
493 
494 
495     /**
496      * Returns the next event consumer in sequence; or null if there
497      * is no such handler.
498      */
getNext()499     final public EventConsumer getNext ()
500         { return next; }
501 
502 
503     /**
504      * Assigns the content handler to use; a null handler indicates
505      * that these events will not be forwarded.
506      * This overrides the previous settting for this handler, which was
507      * probably pointed to the next consumer by the base class constructor.
508      */
setContentHandler(ContentHandler h)509     final public void setContentHandler (ContentHandler h)
510     {
511         docHandler = h;
512     }
513 
514     /** Returns the content handler being used. */
getContentHandler()515     final public ContentHandler getContentHandler ()
516     {
517         return docHandler;
518     }
519 
520     /**
521      * Assigns the DTD handler to use; a null handler indicates
522      * that these events will not be forwarded.
523      * This overrides the previous settting for this handler, which was
524      * probably pointed to the next consumer by the base class constructor.
525      */
setDTDHandler(DTDHandler h)526     final public void setDTDHandler (DTDHandler h)
527         { dtdHandler = h; }
528 
529     /** Returns the dtd handler being used. */
getDTDHandler()530     final public DTDHandler getDTDHandler ()
531     {
532         return dtdHandler;
533     }
534 
535     /**
536      * Stores the property, normally a handler; a null handler indicates
537      * that these events will not be forwarded.
538      * This overrides the previous handler settting, which was probably
539      * pointed to the next consumer by the base class constructor.
540      */
setProperty(String id, Object o)541     final public void setProperty (String id, Object o)
542     throws SAXNotRecognizedException, SAXNotSupportedException
543     {
544         try {
545             Object      value = getProperty (id);
546 
547             if (value == o)
548                 return;
549             if (DECL_HANDLER.equals (id)) {
550                 declHandler = (DeclHandler) o;
551                 return;
552             }
553             if (LEXICAL_HANDLER.equals (id)) {
554                 lexHandler = (LexicalHandler) o;
555                 return;
556             }
557             throw new SAXNotSupportedException (id);
558 
559         } catch (ClassCastException e) {
560             throw new SAXNotSupportedException (id);
561         }
562     }
563 
564     /** Retrieves a property of unknown intent (usually a handler) */
getProperty(String id)565     final public Object getProperty (String id)
566     throws SAXNotRecognizedException
567     {
568         if (DECL_HANDLER.equals (id))
569             return declHandler;
570         if (LEXICAL_HANDLER.equals (id))
571             return lexHandler;
572 
573         throw new SAXNotRecognizedException (id);
574     }
575 
576     /**
577      * Returns any locator provided to the next consumer, if this class
578      * (or a subclass) is handling {@link ContentHandler } events.
579      */
getDocumentLocator()580     public Locator getDocumentLocator ()
581         { return locator; }
582 
583 
584     // CONTENT HANDLER DELEGATIONS
585 
586     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
setDocumentLocator(Locator locator)587     public void setDocumentLocator (Locator locator)
588     {
589         this.locator = locator;
590         if (docNext != null)
591             docNext.setDocumentLocator (locator);
592     }
593 
594     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
startDocument()595     public void startDocument () throws SAXException
596     {
597         if (docNext != null)
598             docNext.startDocument ();
599     }
600 
601     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
skippedEntity(String name)602     public void skippedEntity (String name) throws SAXException
603     {
604         if (docNext != null)
605             docNext.skippedEntity (name);
606     }
607 
608     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
processingInstruction(String target, String data)609     public void processingInstruction (String target, String data)
610     throws SAXException
611     {
612         if (docNext != null)
613             docNext.processingInstruction (target, data);
614     }
615 
616     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
characters(char ch [], int start, int length)617     public void characters (char ch [], int start, int length)
618     throws SAXException
619     {
620         if (docNext != null)
621             docNext.characters (ch, start, length);
622     }
623 
624     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
ignorableWhitespace(char ch [], int start, int length)625     public void ignorableWhitespace (char ch [], int start, int length)
626     throws SAXException
627     {
628         if (docNext != null)
629             docNext.ignorableWhitespace (ch, start, length);
630     }
631 
632     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
startPrefixMapping(String prefix, String uri)633     public void startPrefixMapping (String prefix, String uri)
634     throws SAXException
635     {
636         if (docNext != null)
637             docNext.startPrefixMapping (prefix, uri);
638     }
639 
640     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
startElement( String uri, String localName, String qName, Attributes atts )641     public void startElement (
642         String uri, String localName,
643         String qName, Attributes atts
644     ) throws SAXException
645     {
646         if (docNext != null)
647             docNext.startElement (uri, localName, qName, atts);
648     }
649 
650     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
endElement(String uri, String localName, String qName)651     public void endElement (String uri, String localName, String qName)
652     throws SAXException
653     {
654         if (docNext != null)
655             docNext.endElement (uri, localName, qName);
656     }
657 
658     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
endPrefixMapping(String prefix)659     public void endPrefixMapping (String prefix) throws SAXException
660     {
661         if (docNext != null)
662             docNext.endPrefixMapping (prefix);
663     }
664 
665     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
endDocument()666     public void endDocument () throws SAXException
667     {
668         if (docNext != null)
669             docNext.endDocument ();
670         locator = null;
671     }
672 
673 
674     // DTD HANDLER DELEGATIONS
675 
676     /** <b>SAX1:</b> passes this callback to the next consumer, if any */
unparsedEntityDecl( String name, String publicId, String systemId, String notationName )677     public void unparsedEntityDecl (
678         String name,
679         String publicId,
680         String systemId,
681         String notationName
682     ) throws SAXException
683     {
684         if (dtdNext != null)
685             dtdNext.unparsedEntityDecl (name, publicId, systemId, notationName);
686     }
687 
688     /** <b>SAX1:</b> passes this callback to the next consumer, if any */
notationDecl(String name, String publicId, String systemId)689     public void notationDecl (String name, String publicId, String systemId)
690     throws SAXException
691     {
692         if (dtdNext != null)
693             dtdNext.notationDecl (name, publicId, systemId);
694     }
695 
696 
697     // LEXICAL HANDLER DELEGATIONS
698 
699     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
startDTD(String name, String publicId, String systemId)700     public void startDTD (String name, String publicId, String systemId)
701     throws SAXException
702     {
703         if (lexNext != null)
704             lexNext.startDTD (name, publicId, systemId);
705     }
706 
707     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
endDTD()708     public void endDTD ()
709     throws SAXException
710     {
711         if (lexNext != null)
712             lexNext.endDTD ();
713     }
714 
715     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
comment(char ch [], int start, int length)716     public void comment (char ch [], int start, int length)
717     throws SAXException
718     {
719         if (lexNext != null)
720             lexNext.comment (ch, start, length);
721     }
722 
723     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
startCDATA()724     public void startCDATA ()
725     throws SAXException
726     {
727         if (lexNext != null)
728             lexNext.startCDATA ();
729     }
730 
731     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
endCDATA()732     public void endCDATA ()
733     throws SAXException
734     {
735         if (lexNext != null)
736             lexNext.endCDATA ();
737     }
738 
739     /**
740      * <b>SAX2:</b> passes this callback to the next consumer, if any.
741      */
startEntity(String name)742     public void startEntity (String name)
743     throws SAXException
744     {
745         if (lexNext != null)
746             lexNext.startEntity (name);
747     }
748 
749     /**
750      * <b>SAX2:</b> passes this callback to the next consumer, if any.
751      */
endEntity(String name)752     public void endEntity (String name)
753     throws SAXException
754     {
755         if (lexNext != null)
756             lexNext.endEntity (name);
757     }
758 
759 
760     // DECLARATION HANDLER DELEGATIONS
761 
762 
763     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
elementDecl(String name, String model)764     public void elementDecl (String name, String model)
765     throws SAXException
766     {
767         if (declNext != null)
768             declNext.elementDecl (name, model);
769     }
770 
771     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
attributeDecl(String eName, String aName, String type, String mode, String value)772     public void attributeDecl (String eName, String aName,
773             String type, String mode, String value)
774     throws SAXException
775     {
776         if (declNext != null)
777             declNext.attributeDecl (eName, aName, type, mode, value);
778     }
779 
780     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
externalEntityDecl(String name, String publicId, String systemId)781     public void externalEntityDecl (String name,
782         String publicId, String systemId)
783     throws SAXException
784     {
785         if (declNext != null)
786             declNext.externalEntityDecl (name, publicId, systemId);
787     }
788 
789     /** <b>SAX2:</b> passes this callback to the next consumer, if any */
internalEntityDecl(String name, String value)790     public void internalEntityDecl (String name, String value)
791     throws SAXException
792     {
793         if (declNext != null)
794             declNext.internalEntityDecl (name, value);
795     }
796 }
797