jkesselm    01/05/15 14:54:10

  Modified:    java/src/org/apache/xml/dtm Tag: DTM_EXP
                        CoroutineSAXParser.java DTMManagerDefault.java
  Log:
  SAX filtering mode written, confirmed not to break old unit test.
  Still need new unit test to check the new mode.
  
  Revision  Changes    Path
  No                   revision
  
  
  No                   revision
  
  
  1.1.2.11  +137 -45   
xml-xalan/java/src/org/apache/xml/dtm/Attic/CoroutineSAXParser.java
  
  Index: CoroutineSAXParser.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xml/dtm/Attic/CoroutineSAXParser.java,v
  retrieving revision 1.1.2.10
  retrieving revision 1.1.2.11
  diff -u -r1.1.2.10 -r1.1.2.11
  --- CoroutineSAXParser.java   2001/05/15 18:36:40     1.1.2.10
  +++ CoroutineSAXParser.java   2001/05/15 21:54:01     1.1.2.11
  @@ -65,6 +65,7 @@
   import org.xml.sax.ContentHandler;
   import org.xml.sax.Locator;
   import org.xml.sax.Attributes;
  +import org.xml.sax.XMLReader;
   import java.io.IOException;
   import org.apache.xml.dtm.CoroutineManager;
   
  @@ -92,7 +93,8 @@
     private int fAppCoroutineID = -1;
     private int fParserCoroutineID = -1;
     private boolean fParseInProgress=false;
  -  private org.xml.sax.XMLReader xmlreader=null;
  +  private XMLReader fXMLReader=null;
  +  private boolean fRunningInThread=false;
     private org.xml.sax.ContentHandler clientContentHandler=null;
     private org.xml.sax.ext.LexicalHandler clientLexicalHandler=null;
     private int eventcounter;
  @@ -103,42 +105,76 @@
     //
   
     /** Create a CoroutineSAXParser which is not yet bound to a specific
  -   * SAX event source. This can be used for situations where we will want
  -   * to bind to that source after we've bound a listener to the
  -   * CoroutineSAXParser, or where we're going to want to issue the
  -   * parse() request (to start events flowing) in the main thread
  -   * rather than in the coroutine's thread.
  -   *
  -   * %TBD% I'm concerned about making sure we properly announce endDocument
  -   * to the application coroutine. I'm also concerned about launching this
  -   * thread, given that existing code starts by waiting for an InputSource.
  -   * This may need a significant redesign so CoroutineSAXParser _only_
  -   * provides a "throttle" on a separately configured and launched
  -   * XMLReader... or become a separate CoroutineSAXThrottle which is
  -   * subclassed to provide today's CoroutineSAXParser.
  +   * SAX event source.
  +   *
  +   * THIS VERSION DOES NOT LAUNCH A THREAD! It is presumed that the
  +   * application coroutine will be started in a secondary thread and
  +   * will be waiting for our first yield(), and that the parser will
  +   * be run in the main thread.
      * 
  -   * Status: NONFUNCTIONAL.
  +   * Status: Experimental
      * 
  -   * @see setXMLReader (required to support this approach, not yet written)
  +   * @see setXMLReader
      * */
     public CoroutineSAXParser(CoroutineManager co, int appCoroutineID)
     {
  -    // %TBD%
  +    fXMLReader=null;    // No reader yet
  +
  +    eventcounter=frequency;
  +
  +    fCoroutineManager = co;
  +    fAppCoroutineID = appCoroutineID;
  +    fParserCoroutineID = co.co_joinCoroutineSet(-1);
  +    if (fParserCoroutineID == -1)
  +      throw new RuntimeException("co_joinCoroutineSet() failed");
  +
  +    fRunningInThread=false; // Unless overridden by the other constructor
     }
   
     /** Wrap a SAX2 XMLReader (parser or other event source)
  -   * in a CoroutineSAXParser.
  -   * %TBD% whether we should consider supporting SAX1
  +   * in a CoroutineSAXParser. This version launches the CoroutineSAXParser
  +   * in a thread, and prepares it to invoke the parser from that thread
  +   * upon request.
  +   *
  +   * @see doParse
      */
     public CoroutineSAXParser(CoroutineManager co, int appCoroutineID,
  -                            org.xml.sax.XMLReader parser) {
  -    xmlreader=parser;
  -    xmlreader.setContentHandler(this);
  +                            XMLReader parser) {
  +    this(co,appCoroutineID);
  +    setXMLReader(parser);
  +
  +    fRunningInThread=true;
  +    Thread t = new Thread(this);
  +    t.setDaemon(false);
  +    t.start();
  +  }
  +
  +  //
  +  // Public methods
  +  //
  +
  +  /** Bind to the XMLReader. This operation is ignored if the reader has
  +   * previously been set.
  +   *
  +   * %REVIEW% Should it instead unbind from the previous reader?
  +   *
  +   * %TBD% This is a quick-hack solution. I'm not convinced that it's
  +   * adequate. In particular, since in this model parser.parse() is
  +   * invoked from outside rather than from our run() loop, I'm not
  +   * sure the end-of-file response is being delivered properly.
  +   * (There were questions of double-yields in earlier versions of the code.)
  +   * */
  +  public void setXMLReader(XMLReader parser)
  +  {
  +    if(fXMLReader!=null) return;
  +    
  +    fXMLReader=parser;
  +    fXMLReader.setContentHandler(this);
   
       // Not supported by all SAX2 parsers:
       try 
         {
  -        
xmlreader.setProperty("http://xml.org/sax/properties/lexical-handler";,
  +        
fXMLReader.setProperty("http://xml.org/sax/properties/lexical-handler";,
                                 this);
         }
       catch(SAXNotRecognizedException e)
  @@ -150,22 +186,10 @@
           // Nothing we can do about it
         }
   
  -    eventcounter=frequency;
  -
  -    fCoroutineManager = co;
  -    fAppCoroutineID = appCoroutineID;
  -    fParserCoroutineID = co.co_joinCoroutineSet(-1);
  -    if (fParserCoroutineID == -1)
  -      throw new RuntimeException("co_joinCoroutineSet() failed");
  -    Thread t = new Thread(this);
  -    t.setDaemon(false);
  -    t.start();
  +    // Should we also bind as other varieties of handler?
  +    // (DTDHandler and so on)
     }
   
  -  //
  -  // Public methods
  -  //
  -
     // Register a content handler for us to output to
     public void setContentHandler(ContentHandler handler)
     {
  @@ -226,9 +250,7 @@
         clientContentHandler.endDocument();
   
       eventcounter=0;  
  -    // We do not have to yield in this case. Just return.
  -    // When parser exits, the run() loop will yield false to indicate
  -    // parsing is done.
  +    co_yield(false);
     }
     public void endElement(java.lang.String namespaceURI, java.lang.String 
localName,
         java.lang.String qName) 
  @@ -446,18 +468,79 @@
      *                   Throws UserRequestedStopException
      *                   to return control to the run() loop.
      */
  -  private void co_yield(boolean notYetDone)
  +  private void co_yield(boolean moreRemains)
     {
  -    Object arg= notYetDone ? Boolean.TRUE : Boolean.FALSE;
  -    try
  +    Object arg= moreRemains ? Boolean.TRUE : Boolean.FALSE;
  +
  +    // %TBD% End-of-file behavior. When moreRemains==false, we have
  +    // just ended parsing the document and are about to return
  +    // from the parser.
  +    //
  +    // If we were invoked from the run() loop, we have to provide
  +    // the coroutine argument returned above as the next command
  +    // to be processed in that loop.
  +    //
  +    // Conversely, if we've been running in response to
  +    // fXMLReader.parse() invoked directly, we will not be returning
  +    // to that loop. In that case, the question becomes one of what we
  +    // should do instead. The simplest answer would seem to be to do a
  +    // co_exit_to immediately, since we don't have a command loop to
  +    // continue to talk to.
  +
  +    if(!moreRemains)
  +      {
  +     if(fRunningInThread)
  +       {
  +         // Just return. The command loop in run() will send the
  +         // "we're done" announcement and request the next command.
  +         return; // let the parser terminate itself
  +       }
  +       
  +     else try 
  +       {
  +         // Forced Termination dialog. Say we're done, wait for a
  +         // termination request (don't accept anything else), and
  +         // shut down.
  +         arg = fCoroutineManager.co_resume(arg, fParserCoroutineID,
  +                                           fAppCoroutineID);
  +         while(arg!=null)
  +           {
  +                System.err.println(
  +                  "Filtering CoroutineSAXParser: unexpected resume 
parameter, "
  +                  +arg.getClass()+" with value=\""+arg+'"');
  +             // If you don't do this, it can loop forever with the above
  +                // error printing out.  -sb
  +             arg = new RuntimeException(
  +                  "Filtering CoroutineSAXParser: unexpected resume 
parameter, "
  +                  +arg.getClass()+" with value=\""+arg+'"');
  +             arg = fCoroutineManager.co_resume(arg, fParserCoroutineID,
  +                                               fAppCoroutineID);
  +           }
  +         
  +         fCoroutineManager.co_exit_to(arg, fParserCoroutineID, 
fAppCoroutineID);
  +         return; // let the parser terminate itself
  +       }
  +     catch(java.lang.NoSuchMethodException e)
  +       {
  +         // Shouldn't happen unless we've miscoded our coroutine logic
  +         // "Shut down the garbage smashers on the detention level!"
  +         e.printStackTrace(System.err);
  +         fCoroutineManager.co_exit(fParserCoroutineID);
  +         throw shutdownException;
  +       }
  +      }
  +
  +
  +    else try
         {
           arg = fCoroutineManager.co_resume(arg, fParserCoroutineID, 
fAppCoroutineID);
  -        
  +
           if (arg == null) {
             fCoroutineManager.co_exit_to(arg, fParserCoroutineID, 
fAppCoroutineID);
             throw shutdownException;
           }
   
  +
           else if (arg instanceof Boolean) {
             boolean keepgoing = ((Boolean)arg).booleanValue();
             if (!keepgoing)
  @@ -526,7 +609,7 @@
               if (arg instanceof InputSource) {
                 try {
                 if(DEBUG)System.out.println("Inactive CoroutineSAXParser new 
parse "+arg);
  -                xmlreader.parse((InputSource)arg);
  +                fXMLReader.parse((InputSource)arg);
                   // Tell caller we returned from parsing
                   arg=Boolean.FALSE;
                 }
  @@ -604,6 +687,11 @@
      * communication protocol and to avoid having to explicitly use the
      * CoroutineParser's coroutine ID number.
      *
  +   * %REVIEW%: If we are NOT running in a thread (if we bound to an
  +   * externally invoked XMLReader), this operation is a no-op. I don't
  +   * _think_ it can safely synchronously invoke that reader's parse()
  +   * operation, or doMore(), which would be the obvious alternatives....
  +   *
      * %REVIEW% Can/should this unify with doMore? (if URI hasn't changed,
      * parse more from same file, else end and restart parsing...?
      *
  @@ -617,6 +705,10 @@
      * */
     public Object doParse(InputSource source, int appCoroutineID)
     {
  +    // %REVIEW% I'm not wild about this solution...
  +    if(!fRunningInThread)
  +      return Boolean.TRUE; // "Yes, we expect to deliver events."
  +
       try 
         {
           Object result=    
  
  
  
  1.1.2.11  +7 -1      
xml-xalan/java/src/org/apache/xml/dtm/Attic/DTMManagerDefault.java
  
  Index: DTMManagerDefault.java
  ===================================================================
  RCS file: 
/home/cvs/xml-xalan/java/src/org/apache/xml/dtm/Attic/DTMManagerDefault.java,v
  retrieving revision 1.1.2.10
  retrieving revision 1.1.2.11
  diff -u -r1.1.2.10 -r1.1.2.11
  --- DTMManagerDefault.java    2001/05/15 17:55:26     1.1.2.10
  +++ DTMManagerDefault.java    2001/05/15 21:54:03     1.1.2.11
  @@ -210,12 +210,17 @@
           
           // %TBD%  It's probably OK to have these bypass the CoRoutine stuff??
           // Or maybe not?
  +     // ... Depends on how broken will things get if they occur at the same
  +     // time that someone is trying to read the DTM model. I'd suggest that
  +     // we instead extend CoroutineParser to handle these, and let it
  +     // pass the registration through to the reader if that's the Right Thng
           reader.setDTDHandler(dtm);
           reader.setErrorHandler(dtm);
                             
           try
           {
             // This is a strange way to start the parse.
  +       // %REVIEW% Consider making coParser just be a throttling filter
             Object gotMore = coParser.doParse(xmlSource, appCoroutine);
             if( gotMore instanceof Exception)
             {
  @@ -224,7 +229,8 @@
             }
             else if (gotMore != Boolean.TRUE)
             {
  -      
  +         // This is a strange way to terminate the parser.
  +         // %REVIEW% Consider having coParser self-terminate at end of file.
               dtm.clearCoRoutine();
             }
           }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to