Source for gnu.xml.pipeline.EventFilter

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