19f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/*
29f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Licensed to the Apache Software Foundation (ASF) under one
39f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * or more contributor license agreements. See the NOTICE file
49f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed with this work for additional information
59f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * regarding copyright ownership. The ASF licenses this file
69f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * to you under the Apache License, Version 2.0 (the  "License");
79f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * you may not use this file except in compliance with the License.
89f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * You may obtain a copy of the License at
99f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *     http://www.apache.org/licenses/LICENSE-2.0
119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Unless required by applicable law or agreed to in writing, software
139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * See the License for the specific language governing permissions and
169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * limitations under the License.
179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/*
199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * $Id: IncrementalSAXSource_Filter.java 468653 2006-10-28 07:07:05Z minchau $
209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonpackage org.apache.xml.dtm.ref;
239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport java.io.IOException;
259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.res.XMLErrorResources;
279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.res.XMLMessages;
289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.utils.ThreadControllerWrapper;
299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.Attributes;
319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.ContentHandler;
329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.DTDHandler;
339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.ErrorHandler;
349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.InputSource;
359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.Locator;
369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.SAXException;
379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.SAXNotRecognizedException;
389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.SAXNotSupportedException;
399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.SAXParseException;
409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.XMLReader;
419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.xml.sax.ext.LexicalHandler;
429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/** <p>IncrementalSAXSource_Filter implements IncrementalSAXSource, using a
449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * standard SAX2 event source as its input and parcelling out those
459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * events gradually in reponse to deliverMoreNodes() requests.  Output from the
469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * filter will be passed along to a SAX handler registered as our
479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * listener, but those callbacks will pass through a counting stage
489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * which periodically yields control back to the controller coroutine.
499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * </p>
509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>%REVIEW%: This filter is not currenly intended to be reusable
529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * for parsing additional streams/documents. We may want to consider
539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * making it resettable at some point in the future. But it's a
549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * small object, so that'd be mostly a convenience issue; the cost
559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * of allocating each time is trivial compared to the cost of processing
569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * any nontrival stream.</p>
579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>For a brief usage example, see the unit-test main() method.</p>
599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * <p>This is a simplification of the old CoroutineSAXParser, focusing
619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * specifically on filtering. The resulting controller protocol is _far_
629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * simpler and less error-prone; the only controller operation is deliverMoreNodes(),
639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * and the only requirement is that deliverMoreNodes(false) be called if you want to
649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * discard the rest of the stream and the previous deliverMoreNodes() didn't return
659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * false.
669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * */
679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonpublic class IncrementalSAXSource_Filter
689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimplements IncrementalSAXSource, ContentHandler, DTDHandler, LexicalHandler, ErrorHandler, Runnable
699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  boolean DEBUG=false; //Internal status report
719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Data
749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private CoroutineManager fCoroutineManager = null;
769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private int fControllerCoroutineID = -1;
779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private int fSourceCoroutineID = -1;
789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private ContentHandler clientContentHandler=null; // %REVIEW% support multiple?
809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private LexicalHandler clientLexicalHandler=null; // %REVIEW% support multiple?
819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private DTDHandler clientDTDHandler=null; // %REVIEW% support multiple?
829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private ErrorHandler clientErrorHandler=null; // %REVIEW% support multiple?
839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private int eventcounter;
849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private int frequency=5;
859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Flag indicating that no more events should be delivered -- either
879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // because input stream ran to completion (endDocument), or because
889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // the user requested an early stop via deliverMoreNodes(false).
899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private boolean fNoMoreEvents=false;
909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Support for startParse()
929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private XMLReader fXMLReader=null;
939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private InputSource fXMLReaderInputSource=null;
949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Constructors
979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public IncrementalSAXSource_Filter() {
1009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    this.init( new CoroutineManager(), -1, -1);
1019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** Create a IncrementalSAXSource_Filter which is not yet bound to a specific
1049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * SAX event source.
1059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * */
1069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public IncrementalSAXSource_Filter(CoroutineManager co, int controllerCoroutineID)
1079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    this.init( co, controllerCoroutineID, -1 );
1099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
1129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Factories
1139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
1149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  static public IncrementalSAXSource createIncrementalSAXSource(CoroutineManager co, int controllerCoroutineID) {
1159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return new IncrementalSAXSource_Filter(co, controllerCoroutineID);
1169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
1199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Public methods
1209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
1219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void init( CoroutineManager co, int controllerCoroutineID,
1239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    int sourceCoroutineID)
1249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(co==null)
1269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      co = new CoroutineManager();
1279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    fCoroutineManager = co;
1289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    fControllerCoroutineID = co.co_joinCoroutineSet(controllerCoroutineID);
1299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    fSourceCoroutineID = co.co_joinCoroutineSet(sourceCoroutineID);
1309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if (fControllerCoroutineID == -1 || fSourceCoroutineID == -1)
1319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      throw new RuntimeException(XMLMessages.createXMLMessage(XMLErrorResources.ER_COJOINROUTINESET_FAILED, null)); //"co_joinCoroutineSet() failed");
1329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    fNoMoreEvents=false;
1349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    eventcounter=frequency;
1359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** Bind our input streams to an XMLReader.
1389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Just a convenience routine; obviously you can explicitly register
1409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * this as a listener with the same effect.
1419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * */
1429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void setXMLReader(XMLReader eventsource)
1439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    fXMLReader=eventsource;
1459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    eventsource.setContentHandler(this);
1469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    eventsource.setDTDHandler(this);
1479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    eventsource.setErrorHandler(this); // to report fatal errors in filtering mode
1489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Not supported by all SAX2 filters:
1509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    try
1519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      eventsource.
1539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        setProperty("http://xml.org/sax/properties/lexical-handler",
1549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    this);
1559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    catch(SAXNotRecognizedException e)
1579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // Nothing we can do about it
1599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    catch(SAXNotSupportedException e)
1619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // Nothing we can do about it
1639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Should we also bind as other varieties of handler?
1669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // (DTDHandler and so on)
1679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Register a content handler for us to output to
1709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void setContentHandler(ContentHandler handler)
1719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    clientContentHandler=handler;
1739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Register a DTD handler for us to output to
1759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void setDTDHandler(DTDHandler handler)
1769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    clientDTDHandler=handler;
1789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Register a lexical handler for us to output to
1809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Not all filters support this...
1819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // ??? Should we register directly on the filter?
1829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // NOTE NAME -- subclassing issue in the Xerces version
1839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void setLexicalHandler(LexicalHandler handler)
1849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    clientLexicalHandler=handler;
1869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Register an error handler for us to output to
1889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // NOTE NAME -- subclassing issue in the Xerces version
1899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void setErrHandler(ErrorHandler handler)
1909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    clientErrorHandler=handler;
1929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Set the number of events between resumes of our coroutine
1959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Immediately resets number of events before _next_ resume as well.
1969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void setReturnFrequency(int events)
1979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(events<1) events=1;
1999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    frequency=eventcounter=events;
2009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
2039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // ContentHandler methods
2049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // These  pass the data to our client ContentHandler...
2059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // but they also count the number of events passing through,
2069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // and resume our coroutine each time that counter hits zero and
2079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // is reset.
2089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
2099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Note that for everything except endDocument and fatalError, we do the count-and-yield
2109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // BEFORE passing the call along. I'm hoping that this will encourage JIT
2119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // compilers to realize that these are tail-calls, reducing the expense of
2129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // the additional layer of data flow.
2139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
2149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // %REVIEW% Glenn suggests that pausing after endElement, endDocument,
2159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // and characters may be sufficient. I actually may not want to
2169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // stop after characters, since in our application these wind up being
2179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // concatenated before they're processed... but that risks huge blocks of
2189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // text causing greater than usual readahead. (Unlikely? Consider the
2199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // possibility of a large base-64 block in a SOAP stream.)
2209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
2219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void characters(char[] ch, int start, int length)
2229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
2239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
2249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(--eventcounter<=0)
2259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
2269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        co_yield(true);
2279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        eventcounter=frequency;
2289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(clientContentHandler!=null)
2309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientContentHandler.characters(ch,start,length);
2319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void endDocument()
2339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
2349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
2359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // EXCEPTION: In this case we need to run the event BEFORE we yield.
2369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(clientContentHandler!=null)
2379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientContentHandler.endDocument();
2389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    eventcounter=0;
2409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    co_yield(false);
2419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void endElement(java.lang.String namespaceURI, java.lang.String localName,
2439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      java.lang.String qName)
2449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
2459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
2469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(--eventcounter<=0)
2479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
2489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        co_yield(true);
2499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        eventcounter=frequency;
2509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(clientContentHandler!=null)
2529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientContentHandler.endElement(namespaceURI,localName,qName);
2539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void endPrefixMapping(java.lang.String prefix)
2559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
2569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
2579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(--eventcounter<=0)
2589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
2599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        co_yield(true);
2609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        eventcounter=frequency;
2619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(clientContentHandler!=null)
2639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientContentHandler.endPrefixMapping(prefix);
2649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void ignorableWhitespace(char[] ch, int start, int length)
2669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
2679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
2689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(--eventcounter<=0)
2699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
2709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        co_yield(true);
2719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        eventcounter=frequency;
2729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(clientContentHandler!=null)
2749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientContentHandler.ignorableWhitespace(ch,start,length);
2759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void processingInstruction(java.lang.String target, java.lang.String data)
2779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
2789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
2799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(--eventcounter<=0)
2809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
2819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        co_yield(true);
2829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        eventcounter=frequency;
2839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(clientContentHandler!=null)
2859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientContentHandler.processingInstruction(target,data);
2869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void setDocumentLocator(Locator locator)
2889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
2899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(--eventcounter<=0)
2909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
2919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // This can cause a hang.  -sb
2929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // co_yield(true);
2939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        eventcounter=frequency;
2949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(clientContentHandler!=null)
2969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientContentHandler.setDocumentLocator(locator);
2979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void skippedEntity(java.lang.String name)
2999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
3009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(--eventcounter<=0)
3029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
3039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        co_yield(true);
3049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        eventcounter=frequency;
3059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
3069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(clientContentHandler!=null)
3079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientContentHandler.skippedEntity(name);
3089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void startDocument()
3109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
3119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    co_entry_pause();
3139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Otherwise, begin normal event delivery
3159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(--eventcounter<=0)
3169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
3179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        co_yield(true);
3189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        eventcounter=frequency;
3199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
3209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(clientContentHandler!=null)
3219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientContentHandler.startDocument();
3229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void startElement(java.lang.String namespaceURI, java.lang.String localName,
3249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      java.lang.String qName, Attributes atts)
3259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
3269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(--eventcounter<=0)
3289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
3299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        co_yield(true);
3309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        eventcounter=frequency;
3319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
3329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(clientContentHandler!=null)
3339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientContentHandler.startElement(namespaceURI, localName, qName, atts);
3349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void startPrefixMapping(java.lang.String prefix, java.lang.String uri)
3369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
3379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(--eventcounter<=0)
3399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
3409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        co_yield(true);
3419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        eventcounter=frequency;
3429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
3439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(clientContentHandler!=null)
3449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientContentHandler.startPrefixMapping(prefix,uri);
3459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
3489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // LexicalHandler support. Not all SAX2 filters support these events
3499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // but we may want to pass them through when they exist...
3509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
3519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // %REVIEW% These do NOT currently affect the eventcounter; I'm asserting
3529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // that they're rare enough that it makes little or no sense to
3539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // pause after them. As such, it may make more sense for folks who
3549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // actually want to use them to register directly with the filter.
3559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // But I want 'em here for now, to remind us to recheck this assertion!
3569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
3579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void comment(char[] ch, int start, int length)
3589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
3599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(null!=clientLexicalHandler)
3619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientLexicalHandler.comment(ch,start,length);
3629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void endCDATA()
3649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
3659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(null!=clientLexicalHandler)
3679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientLexicalHandler.endCDATA();
3689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void endDTD()
3709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
3719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(null!=clientLexicalHandler)
3739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientLexicalHandler.endDTD();
3749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void endEntity(java.lang.String name)
3769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
3779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(null!=clientLexicalHandler)
3799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientLexicalHandler.endEntity(name);
3809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void startCDATA()
3829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
3839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(null!=clientLexicalHandler)
3859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientLexicalHandler.startCDATA();
3869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void startDTD(java.lang.String name, java.lang.String publicId,
3889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      java.lang.String systemId)
3899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
3909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(null!=clientLexicalHandler)
3929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientLexicalHandler. startDTD(name, publicId, systemId);
3939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void startEntity(java.lang.String name)
3959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       throws org.xml.sax.SAXException
3969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(null!=clientLexicalHandler)
3989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientLexicalHandler.startEntity(name);
3999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
4029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // DTDHandler support.
4039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void notationDecl(String a, String b, String c) throws SAXException
4059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(null!=clientDTDHandler)
4079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	  	clientDTDHandler.notationDecl(a,b,c);
4089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void unparsedEntityDecl(String a, String b, String c, String d)  throws SAXException
4109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	if(null!=clientDTDHandler)
4129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	  	clientDTDHandler.unparsedEntityDecl(a,b,c,d);
4139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
4169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // ErrorHandler support.
4179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
4189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // PROBLEM: Xerces is apparently _not_ calling the ErrorHandler for
4199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // exceptions thrown by the ContentHandler, which prevents us from
4209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // handling this properly when running in filtering mode with Xerces
4219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // as our event source.  It's unclear whether this is a Xerces bug
4229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // or a SAX design flaw.
4239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
4249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // %REVIEW% Current solution: In filtering mode, it is REQUIRED that
4259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // event source make sure this method is invoked if the event stream
4269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // abends before endDocument is delivered. If that means explicitly calling
4279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // us in the exception handling code because it won't be delivered as part
4289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // of the normal SAX ErrorHandler stream, that's fine; Not Our Problem.
4299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
4309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void error(SAXParseException exception) throws SAXException
4319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(null!=clientErrorHandler)
4339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientErrorHandler.error(exception);
4349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void fatalError(SAXParseException exception) throws SAXException
4379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // EXCEPTION: In this case we need to run the event BEFORE we yield --
4399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // just as with endDocument, this terminates the event stream.
4409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(null!=clientErrorHandler)
4419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientErrorHandler.error(exception);
4429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    eventcounter=0;
4449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    co_yield(false);
4459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void warning(SAXParseException exception) throws SAXException
4499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(null!=clientErrorHandler)
4519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      clientErrorHandler.error(exception);
4529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
4569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // coroutine support
4579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
4589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public int getSourceCoroutineID() {
4609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return fSourceCoroutineID;
4619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public int getControllerCoroutineID() {
4639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return fControllerCoroutineID;
4649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** @return the CoroutineManager this CoroutineFilter object is bound to.
4679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * If you're using the do...() methods, applications should only
4689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * need to talk to the CoroutineManager once, to obtain the
4699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * application's Coroutine ID.
4709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * */
4719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public CoroutineManager getCoroutineManager()
4729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return fCoroutineManager;
4749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** <p>In the SAX delegation code, I've inlined the count-down in
4779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * the hope of encouraging compilers to deliver better
4789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * performance. However, if we subclass (eg to directly connect the
4799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * output to a DTM builder), that would require calling super in
4809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * order to run that logic... which seems inelegant.  Hence this
4819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * routine for the convenience of subclasses: every [frequency]
4829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * invocations, issue a co_yield.</p>
4839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
4849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param moreExepected Should always be true unless this is being called
4859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * at the end of endDocument() handling.
4869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * */
4879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  protected void count_and_yield(boolean moreExpected) throws SAXException
4889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(!moreExpected) eventcounter=0;
4909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(--eventcounter<=0)
4929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
4939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        co_yield(true);
4949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        eventcounter=frequency;
4959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
4969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
4999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * co_entry_pause is called in startDocument() before anything else
5009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * happens. It causes the filter to wait for a "go ahead" request
5019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * from the controller before delivering any events. Note that
5029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * the very first thing the controller tells us may be "I don't
5039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * need events after all"!
5049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
5059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private void co_entry_pause() throws SAXException
5069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
5079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(fCoroutineManager==null)
5089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
5099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // Nobody called init()? Do it now...
5109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      init(null,-1,-1);
5119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
5129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    try
5149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
5159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      Object arg=fCoroutineManager.co_entry_pause(fSourceCoroutineID);
5169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if(arg==Boolean.FALSE)
5179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        co_yield(false);
5189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
5199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    catch(NoSuchMethodException e)
5209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
5219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // Coroutine system says we haven't registered. That's an
5229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // application coding error, and is unrecoverable.
5239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if(DEBUG) e.printStackTrace();
5249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      throw new SAXException(e);
5259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
5269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
5279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
5299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Co_Yield handles coroutine interactions while a parse is in progress.
5309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
5319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * When moreRemains==true, we are pausing after delivering events, to
5329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * ask if more are needed. We will resume the controller thread with
5339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *   co_resume(Boolean.TRUE, ...)
5349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * When control is passed back it may indicate
5359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *      Boolean.TRUE    indication to continue delivering events
5369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *      Boolean.FALSE   indication to discontinue events and shut down.
5379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
5389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * When moreRemains==false, we shut down immediately without asking the
5399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * controller's permission. Normally this means end of document has been
5409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * reached.
5419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
5429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Shutting down a IncrementalSAXSource_Filter requires terminating the incoming
5439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * SAX event stream. If we are in control of that stream (if it came
5449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * from an XMLReader passed to our startReader() method), we can do so
5459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * very quickly by throwing a reserved exception to it. If the stream is
5469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * coming from another source, we can't do that because its caller may
5479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * not be prepared for this "normal abnormal exit", and instead we put
5489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * ourselves in a "spin" mode where events are discarded.
5499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
5509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private void co_yield(boolean moreRemains) throws SAXException
5519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
5529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Horrendous kluge to run filter to completion. See below.
5539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(fNoMoreEvents)
5549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      return;
5559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    try // Coroutine manager might throw no-such.
5579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
5589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      Object arg=Boolean.FALSE;
5599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if(moreRemains)
5609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
5619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // Yield control, resume parsing when done
5629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        arg = fCoroutineManager.co_resume(Boolean.TRUE, fSourceCoroutineID,
5639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                          fControllerCoroutineID);
5649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
5669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // If we're at end of document or were told to stop early
5689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if(arg==Boolean.FALSE)
5699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
5709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        fNoMoreEvents=true;
5719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if(fXMLReader!=null)    // Running under startParseThread()
5739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          throw new StopException(); // We'll co_exit from there.
5749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // Yield control. We do NOT expect anyone to ever ask us again.
5769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        fCoroutineManager.co_exit_to(Boolean.FALSE, fSourceCoroutineID,
5779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                     fControllerCoroutineID);
5789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
5799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
5809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    catch(NoSuchMethodException e)
5819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
5829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // Shouldn't happen unless we've miscoded our coroutine logic
5839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // "Shut down the garbage smashers on the detention level!"
5849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      fNoMoreEvents=true;
5859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      fCoroutineManager.co_exit(fSourceCoroutineID);
5869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      throw new SAXException(e);
5879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
5889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
5899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
5919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  // Convenience: Run an XMLReader in a thread
5929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //
5939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
5949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** Launch a thread that will run an XMLReader's parse() operation within
5959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *  a thread, feeding events to this IncrementalSAXSource_Filter. Mostly a convenience
5969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *  routine, but has the advantage that -- since we invoked parse() --
5979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *  we can halt parsing quickly via a StopException rather than waiting
5989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *  for the SAX stream to end by itself.
5999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
6009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @throws SAXException is parse thread is already in progress
6019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * or parsing can not be started.
6029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * */
6039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void startParse(InputSource source) throws SAXException
6049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
6059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(fNoMoreEvents)
6069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      throw new SAXException(XMLMessages.createXMLMessage(XMLErrorResources.ER_INCRSAXSRCFILTER_NOT_RESTARTABLE, null)); //"IncrmentalSAXSource_Filter not currently restartable.");
6079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(fXMLReader==null)
6089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      throw new SAXException(XMLMessages.createXMLMessage(XMLErrorResources.ER_XMLRDR_NOT_BEFORE_STARTPARSE, null)); //"XMLReader not before startParse request");
6099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    fXMLReaderInputSource=source;
6119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Xalan thread pooling...
6139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // org.apache.xalan.transformer.TransformerImpl.runTransformThread(this);
6149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    ThreadControllerWrapper.runThread(this, -1);
6159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
6169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /* Thread logic to support startParseThread()
6189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
6199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void run()
6209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
6219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Guard against direct invocation of start().
6229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(fXMLReader==null) return;
6239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(DEBUG)System.out.println("IncrementalSAXSource_Filter parse thread launched");
6259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Initially assume we'll run successfully.
6279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    Object arg=Boolean.FALSE;
6289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // For the duration of this operation, all coroutine handshaking
6309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // will occur in the co_yield method. That's the nice thing about
6319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // coroutines; they give us a way to hand off control from the
6329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // middle of a synchronous method.
6339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    try
6349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
6359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      fXMLReader.parse(fXMLReaderInputSource);
6369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
6379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    catch(IOException ex)
6389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
6399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      arg=ex;
6409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
6419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    catch(StopException ex)
6429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
6439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // Expected and harmless
6449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if(DEBUG)System.out.println("Active IncrementalSAXSource_Filter normal stop exception");
6459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
6469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    catch (SAXException ex)
6479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
6489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      Exception inner=ex.getException();
6499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if(inner instanceof StopException){
6509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // Expected and harmless
6519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if(DEBUG)System.out.println("Active IncrementalSAXSource_Filter normal stop exception");
6529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
6539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      else
6549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
6559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // Unexpected malfunction
6569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if(DEBUG)
6579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
6589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          System.out.println("Active IncrementalSAXSource_Filter UNEXPECTED SAX exception: "+inner);
6599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          inner.printStackTrace();
6609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
6619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        arg=ex;
6629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
6639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    } // end parse
6649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Mark as no longer running in thread.
6669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    fXMLReader=null;
6679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    try
6699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
6709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // Mark as done and yield control to the controller coroutine
6719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      fNoMoreEvents=true;
6729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      fCoroutineManager.co_exit_to(arg, fSourceCoroutineID,
6739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                   fControllerCoroutineID);
6749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
6759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    catch(java.lang.NoSuchMethodException e)
6769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
6779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // Shouldn't happen unless we've miscoded our coroutine logic
6789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // "CPO, shut down the garbage smashers on the detention level!"
6799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      e.printStackTrace(System.err);
6809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      fCoroutineManager.co_exit(fSourceCoroutineID);
6819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
6829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
6839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** Used to quickly terminate parse when running under a
6859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      startParse() thread. Only its type is important. */
6869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  class StopException extends RuntimeException
6879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
6889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          static final long serialVersionUID = -1129245796185754956L;
6899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
6909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
6919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** deliverMoreNodes() is a simple API which tells the coroutine
6929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * parser that we need more nodes.  This is intended to be called
6939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * from one of our partner routines, and serves to encapsulate the
6949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * details of how incremental parsing has been achieved.
6959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
6969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param parsemore If true, tells the incremental filter to generate
6979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * another chunk of output. If false, tells the filter that we're
6989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * satisfied and it can terminate parsing of this document.
6999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
7009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return Boolean.TRUE if there may be more events available by invoking
7019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * deliverMoreNodes() again. Boolean.FALSE if parsing has run to completion (or been
7029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * terminated by deliverMoreNodes(false). Or an exception object if something
7039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * malfunctioned. %REVIEW% We _could_ actually throw the exception, but
7049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * that would require runinng deliverMoreNodes() in a try/catch... and for many
7059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * applications, exception will be simply be treated as "not TRUE" in
7069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * any case.
7079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * */
7089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public Object deliverMoreNodes(boolean parsemore)
7099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
7109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // If parsing is already done, we can immediately say so
7119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if(fNoMoreEvents)
7129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      return Boolean.FALSE;
7139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    try
7159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
7169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      Object result =
7179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        fCoroutineManager.co_resume(parsemore?Boolean.TRUE:Boolean.FALSE,
7189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                    fControllerCoroutineID, fSourceCoroutineID);
7199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if(result==Boolean.FALSE)
7209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        fCoroutineManager.co_exit(fControllerCoroutineID);
7219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      return result;
7239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
7249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // SHOULD NEVER OCCUR, since the coroutine number and coroutine manager
7269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // are those previously established for this IncrementalSAXSource_Filter...
7279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // So I'm just going to return it as a parsing exception, for now.
7289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    catch(NoSuchMethodException e)
7299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
7309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return e;
7319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
7329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
7339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  //================================================================
7369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** Simple unit test. Attempt coroutine parsing of document indicated
7379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * by first argument (as a URI), report progress.
7389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
7399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /*
7409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public static void main(String args[])
7419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
7429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    System.out.println("Starting...");
7439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    org.xml.sax.XMLReader theSAXParser=
7459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      new org.apache.xerces.parsers.SAXParser();
7469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    for(int arg=0;arg<args.length;++arg)
7499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
7509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // The filter is not currently designed to be restartable
7519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // after a parse has ended. Generate a new one each time.
7529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      IncrementalSAXSource_Filter filter=
7539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        new IncrementalSAXSource_Filter();
7549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // Use a serializer as our sample output
7559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      org.apache.xml.serialize.XMLSerializer trace;
7569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      trace=new org.apache.xml.serialize.XMLSerializer(System.out,null);
7579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      filter.setContentHandler(trace);
7589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      filter.setLexicalHandler(trace);
7599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      try
7619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
7629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        InputSource source = new InputSource(args[arg]);
7639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        Object result=null;
7649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        boolean more=true;
7659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // init not issued; we _should_ automagically Do The Right Thing
7679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // Bind parser, kick off parsing in a thread
7699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        filter.setXMLReader(theSAXParser);
7709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        filter.startParse(source);
7719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        for(result = filter.deliverMoreNodes(more);
7739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            (result instanceof Boolean && ((Boolean)result)==Boolean.TRUE);
7749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            result = filter.deliverMoreNodes(more))
7759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
7769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          System.out.println("\nSome parsing successful, trying more.\n");
7779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          // Special test: Terminate parsing early.
7799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          if(arg+1<args.length && "!".equals(args[arg+1]))
7809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          {
7819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            ++arg;
7829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            more=false;
7839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          }
7849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
7869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (result instanceof Boolean && ((Boolean)result)==Boolean.FALSE)
7889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
7899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          System.out.println("\nFilter ended (EOF or on request).\n");
7909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
7919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        else if (result == null) {
7929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          System.out.println("\nUNEXPECTED: Filter says shut down prematurely.\n");
7939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
7949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        else if (result instanceof Exception) {
7959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          System.out.println("\nFilter threw exception:");
7969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          ((Exception)result).printStackTrace();
7979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
7989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
7999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
8009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      catch(SAXException e)
8019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
8029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        e.printStackTrace();
8039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
8049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    } // end for
8059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
8069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    */
8079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson} // class IncrementalSAXSource_Filter
808