Save This Page
Home » openjdk-7 » com.sun.org.apache.xml.internal » dtm » ref » [javadoc | source]
    1   /*
    2    * reserved comment block
    3    * DO NOT REMOVE OR ALTER!
    4    */
    5   /*
    6    * Copyright 1999-2004 The Apache Software Foundation.
    7    *
    8    * Licensed under the Apache License, Version 2.0 (the "License");
    9    * you may not use this file except in compliance with the License.
   10    * You may obtain a copy of the License at
   11    *
   12    *     http://www.apache.org/licenses/LICENSE-2.0
   13    *
   14    * Unless required by applicable law or agreed to in writing, software
   15    * distributed under the License is distributed on an "AS IS" BASIS,
   16    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   17    * See the License for the specific language governing permissions and
   18    * limitations under the License.
   19    */
   20   /*
   21    * $Id: IncrementalSAXSource_Filter.java,v 1.2.4.1 2005/09/15 08:15:07 suresh_emailid Exp $
   22    */
   23   
   24   package com.sun.org.apache.xml.internal.dtm.ref;
   25   
   26   import java.io.IOException;
   27   
   28   import com.sun.org.apache.xml.internal.res.XMLErrorResources;
   29   import com.sun.org.apache.xml.internal.res.XMLMessages;
   30   import com.sun.org.apache.xml.internal.utils.ThreadControllerWrapper;
   31   
   32   import org.xml.sax.Attributes;
   33   import org.xml.sax.ContentHandler;
   34   import org.xml.sax.DTDHandler;
   35   import org.xml.sax.ErrorHandler;
   36   import org.xml.sax.InputSource;
   37   import org.xml.sax.Locator;
   38   import org.xml.sax.SAXException;
   39   import org.xml.sax.SAXNotRecognizedException;
   40   import org.xml.sax.SAXNotSupportedException;
   41   import org.xml.sax.SAXParseException;
   42   import org.xml.sax.XMLReader;
   43   import org.xml.sax.ext.LexicalHandler;
   44   
   45   /** <p>IncrementalSAXSource_Filter implements IncrementalSAXSource, using a
   46    * standard SAX2 event source as its input and parcelling out those
   47    * events gradually in reponse to deliverMoreNodes() requests.  Output from the
   48    * filter will be passed along to a SAX handler registered as our
   49    * listener, but those callbacks will pass through a counting stage
   50    * which periodically yields control back to the controller coroutine.
   51    * </p>
   52    *
   53    * <p>%REVIEW%: This filter is not currenly intended to be reusable
   54    * for parsing additional streams/documents. We may want to consider
   55    * making it resettable at some point in the future. But it's a
   56    * small object, so that'd be mostly a convenience issue; the cost
   57    * of allocating each time is trivial compared to the cost of processing
   58    * any nontrival stream.</p>
   59    *
   60    * <p>For a brief usage example, see the unit-test main() method.</p>
   61    *
   62    * <p>This is a simplification of the old CoroutineSAXParser, focusing
   63    * specifically on filtering. The resulting controller protocol is _far_
   64    * simpler and less error-prone; the only controller operation is deliverMoreNodes(),
   65    * and the only requirement is that deliverMoreNodes(false) be called if you want to
   66    * discard the rest of the stream and the previous deliverMoreNodes() didn't return
   67    * false.
   68    *
   69    * This class is final and package private for security reasons. Please
   70    * see CR 6537912 for further details.
   71    *
   72    * */
   73   final class IncrementalSAXSource_Filter
   74   implements IncrementalSAXSource, ContentHandler, DTDHandler, LexicalHandler, ErrorHandler, Runnable
   75   {
   76     boolean DEBUG=false; //Internal status report
   77   
   78     //
   79     // Data
   80     //
   81     private CoroutineManager fCoroutineManager = null;
   82     private int fControllerCoroutineID = -1;
   83     private int fSourceCoroutineID = -1;
   84   
   85     private ContentHandler clientContentHandler=null; // %REVIEW% support multiple?
   86     private LexicalHandler clientLexicalHandler=null; // %REVIEW% support multiple?
   87     private DTDHandler clientDTDHandler=null; // %REVIEW% support multiple?
   88     private ErrorHandler clientErrorHandler=null; // %REVIEW% support multiple?
   89     private int eventcounter;
   90     private int frequency=5;
   91   
   92     // Flag indicating that no more events should be delivered -- either
   93     // because input stream ran to completion (endDocument), or because
   94     // the user requested an early stop via deliverMoreNodes(false).
   95     private boolean fNoMoreEvents=false;
   96   
   97     // Support for startParse()
   98     private XMLReader fXMLReader=null;
   99     private InputSource fXMLReaderInputSource=null;
  100   
  101     //
  102     // Constructors
  103     //
  104   
  105     public IncrementalSAXSource_Filter() {
  106       this.init( new CoroutineManager(), -1, -1);
  107     }
  108   
  109     /** Create a IncrementalSAXSource_Filter which is not yet bound to a specific
  110      * SAX event source.
  111      * */
  112     public IncrementalSAXSource_Filter(CoroutineManager co, int controllerCoroutineID)
  113     {
  114       this.init( co, controllerCoroutineID, -1 );
  115     }
  116   
  117     //
  118     // Factories
  119     //
  120     static public IncrementalSAXSource createIncrementalSAXSource(CoroutineManager co, int controllerCoroutineID) {
  121       return new IncrementalSAXSource_Filter(co, controllerCoroutineID);
  122     }
  123   
  124     //
  125     // Public methods
  126     //
  127   
  128     public void init( CoroutineManager co, int controllerCoroutineID,
  129                       int sourceCoroutineID)
  130     {
  131       if(co==null)
  132         co = new CoroutineManager();
  133       fCoroutineManager = co;
  134       fControllerCoroutineID = co.co_joinCoroutineSet(controllerCoroutineID);
  135       fSourceCoroutineID = co.co_joinCoroutineSet(sourceCoroutineID);
  136       if (fControllerCoroutineID == -1 || fSourceCoroutineID == -1)
  137         throw new RuntimeException(XMLMessages.createXMLMessage(XMLErrorResources.ER_COJOINROUTINESET_FAILED, null)); //"co_joinCoroutineSet() failed");
  138   
  139       fNoMoreEvents=false;
  140       eventcounter=frequency;
  141     }
  142   
  143     /** Bind our input streams to an XMLReader.
  144      *
  145      * Just a convenience routine; obviously you can explicitly register
  146      * this as a listener with the same effect.
  147      * */
  148     public void setXMLReader(XMLReader eventsource)
  149     {
  150       fXMLReader=eventsource;
  151       eventsource.setContentHandler(this);
  152       eventsource.setDTDHandler(this);
  153       eventsource.setErrorHandler(this); // to report fatal errors in filtering mode
  154   
  155       // Not supported by all SAX2 filters:
  156       try
  157       {
  158         eventsource.
  159           setProperty("http://xml.org/sax/properties/lexical-handler",
  160                       this);
  161       }
  162       catch(SAXNotRecognizedException e)
  163       {
  164         // Nothing we can do about it
  165       }
  166       catch(SAXNotSupportedException e)
  167       {
  168         // Nothing we can do about it
  169       }
  170   
  171       // Should we also bind as other varieties of handler?
  172       // (DTDHandler and so on)
  173     }
  174   
  175     // Register a content handler for us to output to
  176     public void setContentHandler(ContentHandler handler)
  177     {
  178       clientContentHandler=handler;
  179     }
  180     // Register a DTD handler for us to output to
  181     public void setDTDHandler(DTDHandler handler)
  182     {
  183       clientDTDHandler=handler;
  184     }
  185     // Register a lexical handler for us to output to
  186     // Not all filters support this...
  187     // ??? Should we register directly on the filter?
  188     // NOTE NAME -- subclassing issue in the Xerces version
  189     public void setLexicalHandler(LexicalHandler handler)
  190     {
  191       clientLexicalHandler=handler;
  192     }
  193     // Register an error handler for us to output to
  194     // NOTE NAME -- subclassing issue in the Xerces version
  195     public void setErrHandler(ErrorHandler handler)
  196     {
  197       clientErrorHandler=handler;
  198     }
  199   
  200     // Set the number of events between resumes of our coroutine
  201     // Immediately resets number of events before _next_ resume as well.
  202     public void setReturnFrequency(int events)
  203     {
  204       if(events<1) events=1;
  205       frequency=eventcounter=events;
  206     }
  207   
  208     //
  209     // ContentHandler methods
  210     // These  pass the data to our client ContentHandler...
  211     // but they also count the number of events passing through,
  212     // and resume our coroutine each time that counter hits zero and
  213     // is reset.
  214     //
  215     // Note that for everything except endDocument and fatalError, we do the count-and-yield
  216     // BEFORE passing the call along. I'm hoping that this will encourage JIT
  217     // compilers to realize that these are tail-calls, reducing the expense of
  218     // the additional layer of data flow.
  219     //
  220     // %REVIEW% Glenn suggests that pausing after endElement, endDocument,
  221     // and characters may be sufficient. I actually may not want to
  222     // stop after characters, since in our application these wind up being
  223     // concatenated before they're processed... but that risks huge blocks of
  224     // text causing greater than usual readahead. (Unlikely? Consider the
  225     // possibility of a large base-64 block in a SOAP stream.)
  226     //
  227     public void characters(char[] ch, int start, int length)
  228          throws org.xml.sax.SAXException
  229     {
  230       if(--eventcounter<=0)
  231         {
  232           co_yield(true);
  233           eventcounter=frequency;
  234         }
  235       if(clientContentHandler!=null)
  236         clientContentHandler.characters(ch,start,length);
  237     }
  238     public void endDocument()
  239          throws org.xml.sax.SAXException
  240     {
  241       // EXCEPTION: In this case we need to run the event BEFORE we yield.
  242       if(clientContentHandler!=null)
  243         clientContentHandler.endDocument();
  244   
  245       eventcounter=0;
  246       co_yield(false);
  247     }
  248     public void endElement(java.lang.String namespaceURI, java.lang.String localName,
  249         java.lang.String qName)
  250          throws org.xml.sax.SAXException
  251     {
  252       if(--eventcounter<=0)
  253         {
  254           co_yield(true);
  255           eventcounter=frequency;
  256         }
  257       if(clientContentHandler!=null)
  258         clientContentHandler.endElement(namespaceURI,localName,qName);
  259     }
  260     public void endPrefixMapping(java.lang.String prefix)
  261          throws org.xml.sax.SAXException
  262     {
  263       if(--eventcounter<=0)
  264         {
  265           co_yield(true);
  266           eventcounter=frequency;
  267         }
  268       if(clientContentHandler!=null)
  269         clientContentHandler.endPrefixMapping(prefix);
  270     }
  271     public void ignorableWhitespace(char[] ch, int start, int length)
  272          throws org.xml.sax.SAXException
  273     {
  274       if(--eventcounter<=0)
  275         {
  276           co_yield(true);
  277           eventcounter=frequency;
  278         }
  279       if(clientContentHandler!=null)
  280         clientContentHandler.ignorableWhitespace(ch,start,length);
  281     }
  282     public void processingInstruction(java.lang.String target, java.lang.String data)
  283          throws org.xml.sax.SAXException
  284     {
  285       if(--eventcounter<=0)
  286         {
  287           co_yield(true);
  288           eventcounter=frequency;
  289         }
  290       if(clientContentHandler!=null)
  291         clientContentHandler.processingInstruction(target,data);
  292     }
  293     public void setDocumentLocator(Locator locator)
  294     {
  295       if(--eventcounter<=0)
  296         {
  297           // This can cause a hang.  -sb
  298           // co_yield(true);
  299           eventcounter=frequency;
  300         }
  301       if(clientContentHandler!=null)
  302         clientContentHandler.setDocumentLocator(locator);
  303     }
  304     public void skippedEntity(java.lang.String name)
  305          throws org.xml.sax.SAXException
  306     {
  307       if(--eventcounter<=0)
  308         {
  309           co_yield(true);
  310           eventcounter=frequency;
  311         }
  312       if(clientContentHandler!=null)
  313         clientContentHandler.skippedEntity(name);
  314     }
  315     public void startDocument()
  316          throws org.xml.sax.SAXException
  317     {
  318       co_entry_pause();
  319   
  320       // Otherwise, begin normal event delivery
  321       if(--eventcounter<=0)
  322         {
  323           co_yield(true);
  324           eventcounter=frequency;
  325         }
  326       if(clientContentHandler!=null)
  327         clientContentHandler.startDocument();
  328     }
  329     public void startElement(java.lang.String namespaceURI, java.lang.String localName,
  330         java.lang.String qName, Attributes atts)
  331          throws org.xml.sax.SAXException
  332     {
  333       if(--eventcounter<=0)
  334         {
  335           co_yield(true);
  336           eventcounter=frequency;
  337         }
  338       if(clientContentHandler!=null)
  339         clientContentHandler.startElement(namespaceURI, localName, qName, atts);
  340     }
  341     public void startPrefixMapping(java.lang.String prefix, java.lang.String uri)
  342          throws org.xml.sax.SAXException
  343     {
  344       if(--eventcounter<=0)
  345         {
  346           co_yield(true);
  347           eventcounter=frequency;
  348         }
  349       if(clientContentHandler!=null)
  350         clientContentHandler.startPrefixMapping(prefix,uri);
  351     }
  352   
  353     //
  354     // LexicalHandler support. Not all SAX2 filters support these events
  355     // but we may want to pass them through when they exist...
  356     //
  357     // %REVIEW% These do NOT currently affect the eventcounter; I'm asserting
  358     // that they're rare enough that it makes little or no sense to
  359     // pause after them. As such, it may make more sense for folks who
  360     // actually want to use them to register directly with the filter.
  361     // But I want 'em here for now, to remind us to recheck this assertion!
  362     //
  363     public void comment(char[] ch, int start, int length)
  364          throws org.xml.sax.SAXException
  365     {
  366       if(null!=clientLexicalHandler)
  367         clientLexicalHandler.comment(ch,start,length);
  368     }
  369     public void endCDATA()
  370          throws org.xml.sax.SAXException
  371     {
  372       if(null!=clientLexicalHandler)
  373         clientLexicalHandler.endCDATA();
  374     }
  375     public void endDTD()
  376          throws org.xml.sax.SAXException
  377     {
  378       if(null!=clientLexicalHandler)
  379         clientLexicalHandler.endDTD();
  380     }
  381     public void endEntity(java.lang.String name)
  382          throws org.xml.sax.SAXException
  383     {
  384       if(null!=clientLexicalHandler)
  385         clientLexicalHandler.endEntity(name);
  386     }
  387     public void startCDATA()
  388          throws org.xml.sax.SAXException
  389     {
  390       if(null!=clientLexicalHandler)
  391         clientLexicalHandler.startCDATA();
  392     }
  393     public void startDTD(java.lang.String name, java.lang.String publicId,
  394         java.lang.String systemId)
  395          throws org.xml.sax.SAXException
  396     {
  397       if(null!=clientLexicalHandler)
  398         clientLexicalHandler. startDTD(name, publicId, systemId);
  399     }
  400     public void startEntity(java.lang.String name)
  401          throws org.xml.sax.SAXException
  402     {
  403       if(null!=clientLexicalHandler)
  404         clientLexicalHandler.startEntity(name);
  405     }
  406   
  407     //
  408     // DTDHandler support.
  409   
  410     public void notationDecl(String a, String b, String c) throws SAXException
  411     {
  412           if(null!=clientDTDHandler)
  413                   clientDTDHandler.notationDecl(a,b,c);
  414     }
  415     public void unparsedEntityDecl(String a, String b, String c, String d)  throws SAXException
  416     {
  417           if(null!=clientDTDHandler)
  418                   clientDTDHandler.unparsedEntityDecl(a,b,c,d);
  419     }
  420   
  421     //
  422     // ErrorHandler support.
  423     //
  424     // PROBLEM: Xerces is apparently _not_ calling the ErrorHandler for
  425     // exceptions thrown by the ContentHandler, which prevents us from
  426     // handling this properly when running in filtering mode with Xerces
  427     // as our event source.  It's unclear whether this is a Xerces bug
  428     // or a SAX design flaw.
  429     //
  430     // %REVIEW% Current solution: In filtering mode, it is REQUIRED that
  431     // event source make sure this method is invoked if the event stream
  432     // abends before endDocument is delivered. If that means explicitly calling
  433     // us in the exception handling code because it won't be delivered as part
  434     // of the normal SAX ErrorHandler stream, that's fine; Not Our Problem.
  435     //
  436     public void error(SAXParseException exception) throws SAXException
  437     {
  438       if(null!=clientErrorHandler)
  439         clientErrorHandler.error(exception);
  440     }
  441   
  442     public void fatalError(SAXParseException exception) throws SAXException
  443     {
  444       // EXCEPTION: In this case we need to run the event BEFORE we yield --
  445       // just as with endDocument, this terminates the event stream.
  446       if(null!=clientErrorHandler)
  447         clientErrorHandler.error(exception);
  448   
  449       eventcounter=0;
  450       co_yield(false);
  451   
  452     }
  453   
  454     public void warning(SAXParseException exception) throws SAXException
  455     {
  456       if(null!=clientErrorHandler)
  457         clientErrorHandler.error(exception);
  458     }
  459   
  460   
  461     //
  462     // coroutine support
  463     //
  464   
  465     public int getSourceCoroutineID() {
  466       return fSourceCoroutineID;
  467     }
  468     public int getControllerCoroutineID() {
  469       return fControllerCoroutineID;
  470     }
  471   
  472     /** @return the CoroutineManager this CoroutineFilter object is bound to.
  473      * If you're using the do...() methods, applications should only
  474      * need to talk to the CoroutineManager once, to obtain the
  475      * application's Coroutine ID.
  476      * */
  477     public CoroutineManager getCoroutineManager()
  478     {
  479       return fCoroutineManager;
  480     }
  481   
  482     /** <p>In the SAX delegation code, I've inlined the count-down in
  483      * the hope of encouraging compilers to deliver better
  484      * performance. However, if we subclass (eg to directly connect the
  485      * output to a DTM builder), that would require calling super in
  486      * order to run that logic... which seems inelegant.  Hence this
  487      * routine for the convenience of subclasses: every [frequency]
  488      * invocations, issue a co_yield.</p>
  489      *
  490      * @param moreExepected Should always be true unless this is being called
  491      * at the end of endDocument() handling.
  492      * */
  493     protected void count_and_yield(boolean moreExpected) throws SAXException
  494     {
  495       if(!moreExpected) eventcounter=0;
  496   
  497       if(--eventcounter<=0)
  498         {
  499           co_yield(true);
  500           eventcounter=frequency;
  501         }
  502     }
  503   
  504     /**
  505      * co_entry_pause is called in startDocument() before anything else
  506      * happens. It causes the filter to wait for a "go ahead" request
  507      * from the controller before delivering any events. Note that
  508      * the very first thing the controller tells us may be "I don't
  509      * need events after all"!
  510      */
  511     private void co_entry_pause() throws SAXException
  512     {
  513       if(fCoroutineManager==null)
  514       {
  515         // Nobody called init()? Do it now...
  516         init(null,-1,-1);
  517       }
  518   
  519       try
  520       {
  521         Object arg=fCoroutineManager.co_entry_pause(fSourceCoroutineID);
  522         if(arg==Boolean.FALSE)
  523           co_yield(false);
  524       }
  525       catch(NoSuchMethodException e)
  526       {
  527         // Coroutine system says we haven't registered. That's an
  528         // application coding error, and is unrecoverable.
  529         if(DEBUG) e.printStackTrace();
  530         throw new SAXException(e);
  531       }
  532     }
  533   
  534     /**
  535      * Co_Yield handles coroutine interactions while a parse is in progress.
  536      *
  537      * When moreRemains==true, we are pausing after delivering events, to
  538      * ask if more are needed. We will resume the controller thread with
  539      *   co_resume(Boolean.TRUE, ...)
  540      * When control is passed back it may indicate
  541      *      Boolean.TRUE    indication to continue delivering events
  542      *      Boolean.FALSE   indication to discontinue events and shut down.
  543      *
  544      * When moreRemains==false, we shut down immediately without asking the
  545      * controller's permission. Normally this means end of document has been
  546      * reached.
  547      *
  548      * Shutting down a IncrementalSAXSource_Filter requires terminating the incoming
  549      * SAX event stream. If we are in control of that stream (if it came
  550      * from an XMLReader passed to our startReader() method), we can do so
  551      * very quickly by throwing a reserved exception to it. If the stream is
  552      * coming from another source, we can't do that because its caller may
  553      * not be prepared for this "normal abnormal exit", and instead we put
  554      * ourselves in a "spin" mode where events are discarded.
  555      */
  556     private void co_yield(boolean moreRemains) throws SAXException
  557     {
  558       // Horrendous kluge to run filter to completion. See below.
  559       if(fNoMoreEvents)
  560         return;
  561   
  562       try // Coroutine manager might throw no-such.
  563       {
  564         Object arg=Boolean.FALSE;
  565         if(moreRemains)
  566         {
  567           // Yield control, resume parsing when done
  568           arg = fCoroutineManager.co_resume(Boolean.TRUE, fSourceCoroutineID,
  569                                             fControllerCoroutineID);
  570   
  571         }
  572   
  573         // If we're at end of document or were told to stop early
  574         if(arg==Boolean.FALSE)
  575         {
  576           fNoMoreEvents=true;
  577   
  578           if(fXMLReader!=null)    // Running under startParseThread()
  579             throw new StopException(); // We'll co_exit from there.
  580   
  581           // Yield control. We do NOT expect anyone to ever ask us again.
  582           fCoroutineManager.co_exit_to(Boolean.FALSE, fSourceCoroutineID,
  583                                        fControllerCoroutineID);
  584         }
  585       }
  586       catch(NoSuchMethodException e)
  587       {
  588         // Shouldn't happen unless we've miscoded our coroutine logic
  589         // "Shut down the garbage smashers on the detention level!"
  590         fNoMoreEvents=true;
  591         fCoroutineManager.co_exit(fSourceCoroutineID);
  592         throw new SAXException(e);
  593       }
  594     }
  595   
  596     //
  597     // Convenience: Run an XMLReader in a thread
  598     //
  599   
  600     /** Launch a thread that will run an XMLReader's parse() operation within
  601      *  a thread, feeding events to this IncrementalSAXSource_Filter. Mostly a convenience
  602      *  routine, but has the advantage that -- since we invoked parse() --
  603      *  we can halt parsing quickly via a StopException rather than waiting
  604      *  for the SAX stream to end by itself.
  605      *
  606      * @throws SAXException is parse thread is already in progress
  607      * or parsing can not be started.
  608      * */
  609     public void startParse(InputSource source) throws SAXException
  610     {
  611       if(fNoMoreEvents)
  612         throw new SAXException(XMLMessages.createXMLMessage(XMLErrorResources.ER_INCRSAXSRCFILTER_NOT_RESTARTABLE, null)); //"IncrmentalSAXSource_Filter not currently restartable.");
  613       if(fXMLReader==null)
  614         throw new SAXException(XMLMessages.createXMLMessage(XMLErrorResources.ER_XMLRDR_NOT_BEFORE_STARTPARSE, null)); //"XMLReader not before startParse request");
  615   
  616       fXMLReaderInputSource=source;
  617   
  618       // Xalan thread pooling...
  619       // com.sun.org.apache.xalan.internal.transformer.TransformerImpl.runTransformThread(this);
  620       ThreadControllerWrapper.runThread(this, -1);
  621     }
  622   
  623     /* Thread logic to support startParseThread()
  624      */
  625     public void run()
  626     {
  627       // Guard against direct invocation of start().
  628       if(fXMLReader==null) return;
  629   
  630       if(DEBUG)System.out.println("IncrementalSAXSource_Filter parse thread launched");
  631   
  632       // Initially assume we'll run successfully.
  633       Object arg=Boolean.FALSE;
  634   
  635       // For the duration of this operation, all coroutine handshaking
  636       // will occur in the co_yield method. That's the nice thing about
  637       // coroutines; they give us a way to hand off control from the
  638       // middle of a synchronous method.
  639       try
  640       {
  641         fXMLReader.parse(fXMLReaderInputSource);
  642       }
  643       catch(IOException ex)
  644       {
  645         arg=ex;
  646       }
  647       catch(StopException ex)
  648       {
  649         // Expected and harmless
  650         if(DEBUG)System.out.println("Active IncrementalSAXSource_Filter normal stop exception");
  651       }
  652       catch (SAXException ex)
  653       {
  654         Exception inner=ex.getException();
  655         if(inner instanceof StopException){
  656           // Expected and harmless
  657           if(DEBUG)System.out.println("Active IncrementalSAXSource_Filter normal stop exception");
  658         }
  659         else
  660         {
  661           // Unexpected malfunction
  662           if(DEBUG)
  663           {
  664             System.out.println("Active IncrementalSAXSource_Filter UNEXPECTED SAX exception: "+inner);
  665             inner.printStackTrace();
  666           }
  667           arg=ex;
  668         }
  669       } // end parse
  670   
  671       // Mark as no longer running in thread.
  672       fXMLReader=null;
  673   
  674       try
  675       {
  676         // Mark as done and yield control to the controller coroutine
  677         fNoMoreEvents=true;
  678         fCoroutineManager.co_exit_to(arg, fSourceCoroutineID,
  679                                      fControllerCoroutineID);
  680       }
  681       catch(java.lang.NoSuchMethodException e)
  682       {
  683         // Shouldn't happen unless we've miscoded our coroutine logic
  684         // "CPO, shut down the garbage smashers on the detention level!"
  685         e.printStackTrace(System.err);
  686         fCoroutineManager.co_exit(fSourceCoroutineID);
  687       }
  688     }
  689   
  690     /** Used to quickly terminate parse when running under a
  691         startParse() thread. Only its type is important. */
  692     class StopException extends RuntimeException
  693     {
  694             static final long serialVersionUID = -1129245796185754956L;
  695     }
  696   
  697     /** deliverMoreNodes() is a simple API which tells the coroutine
  698      * parser that we need more nodes.  This is intended to be called
  699      * from one of our partner routines, and serves to encapsulate the
  700      * details of how incremental parsing has been achieved.
  701      *
  702      * @param parsemore If true, tells the incremental filter to generate
  703      * another chunk of output. If false, tells the filter that we're
  704      * satisfied and it can terminate parsing of this document.
  705      *
  706      * @return Boolean.TRUE if there may be more events available by invoking
  707      * deliverMoreNodes() again. Boolean.FALSE if parsing has run to completion (or been
  708      * terminated by deliverMoreNodes(false). Or an exception object if something
  709      * malfunctioned. %REVIEW% We _could_ actually throw the exception, but
  710      * that would require runinng deliverMoreNodes() in a try/catch... and for many
  711      * applications, exception will be simply be treated as "not TRUE" in
  712      * any case.
  713      * */
  714     public Object deliverMoreNodes(boolean parsemore)
  715     {
  716       // If parsing is already done, we can immediately say so
  717       if(fNoMoreEvents)
  718         return Boolean.FALSE;
  719   
  720       try
  721       {
  722         Object result =
  723           fCoroutineManager.co_resume(parsemore?Boolean.TRUE:Boolean.FALSE,
  724                                       fControllerCoroutineID, fSourceCoroutineID);
  725         if(result==Boolean.FALSE)
  726           fCoroutineManager.co_exit(fControllerCoroutineID);
  727   
  728         return result;
  729       }
  730   
  731       // SHOULD NEVER OCCUR, since the coroutine number and coroutine manager
  732       // are those previously established for this IncrementalSAXSource_Filter...
  733       // So I'm just going to return it as a parsing exception, for now.
  734       catch(NoSuchMethodException e)
  735         {
  736           return e;
  737         }
  738     }
  739   
  740   
  741     //================================================================
  742     /** Simple unit test. Attempt coroutine parsing of document indicated
  743      * by first argument (as a URI), report progress.
  744      */
  745       /*
  746     public static void _main(String args[])
  747     {
  748       System.out.println("Starting...");
  749   
  750       org.xml.sax.XMLReader theSAXParser=
  751         new com.sun.org.apache.xerces.internal.parsers.SAXParser();
  752   
  753   
  754       for(int arg=0;arg<args.length;++arg)
  755       {
  756         // The filter is not currently designed to be restartable
  757         // after a parse has ended. Generate a new one each time.
  758         IncrementalSAXSource_Filter filter=
  759           new IncrementalSAXSource_Filter();
  760         // Use a serializer as our sample output
  761         com.sun.org.apache.xml.internal.serialize.XMLSerializer trace;
  762         trace=new com.sun.org.apache.xml.internal.serialize.XMLSerializer(System.out,null);
  763         filter.setContentHandler(trace);
  764         filter.setLexicalHandler(trace);
  765   
  766         try
  767         {
  768           InputSource source = new InputSource(args[arg]);
  769           Object result=null;
  770           boolean more=true;
  771   
  772           // init not issued; we _should_ automagically Do The Right Thing
  773   
  774           // Bind parser, kick off parsing in a thread
  775           filter.setXMLReader(theSAXParser);
  776           filter.startParse(source);
  777   
  778           for(result = filter.deliverMoreNodes(more);
  779               (result instanceof Boolean && ((Boolean)result)==Boolean.TRUE);
  780               result = filter.deliverMoreNodes(more))
  781           {
  782             System.out.println("\nSome parsing successful, trying more.\n");
  783   
  784             // Special test: Terminate parsing early.
  785             if(arg+1<args.length && "!".equals(args[arg+1]))
  786             {
  787               ++arg;
  788               more=false;
  789             }
  790   
  791           }
  792   
  793           if (result instanceof Boolean && ((Boolean)result)==Boolean.FALSE)
  794           {
  795             System.out.println("\nFilter ended (EOF or on request).\n");
  796           }
  797           else if (result == null) {
  798             System.out.println("\nUNEXPECTED: Filter says shut down prematurely.\n");
  799           }
  800           else if (result instanceof Exception) {
  801             System.out.println("\nFilter threw exception:");
  802             ((Exception)result).printStackTrace();
  803           }
  804   
  805         }
  806         catch(SAXException e)
  807         {
  808           e.printStackTrace();
  809         }
  810       } // end for
  811     }
  812       */
  813   } // class IncrementalSAXSource_Filter

Save This Page
Home » openjdk-7 » com.sun.org.apache.xml.internal » dtm » ref » [javadoc | source]