content: /*
   *  This file is part of AndroidIDE.
   *
   *  AndroidIDE is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  AndroidIDE is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *   along with AndroidIDE.  If not, see <https://www.gnu.org/licenses/>.
   */
  
  /*
   * reserved comment block
   * DO NOT REMOVE OR ALTER!
   */
  /*
   * Copyright 1999-2004 The Apache Software Foundation.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *     http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  /*
   * $Id: IncrementalSAXSource_Xerces.java,v 1.2.4.1 2005/09/15 08:15:08 suresh_emailid Exp $
   */
  
  package jaxp.sun.org.apache.xml.internal.dtm.ref;
  
  import java.io.IOException;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Method;
  
  import jaxp.sun.org.apache.xerces.internal.parsers.SAXParser;
  import jaxp.sun.org.apache.xml.internal.res.XMLErrorResources;
  import jaxp.sun.org.apache.xml.internal.res.XMLMessages;
  import jaxp.sun.org.apache.xalan.internal.utils.ObjectFactory;
  
  import jaxp.sun.org.apache.xml.internal.serialize.XMLSerializer;
  import jaxp.sun.org.apache.xml.internal.utils.WrappedRuntimeException;
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXException;
  import org.xml.sax.XMLReader;
  
  
  /** <p>IncrementalSAXSource_Xerces takes advantage of the fact that Xerces1
   * incremental mode is already a coroutine of sorts, and just wraps our
   * IncrementalSAXSource API around it.</p>
   *
   * <p>Usage example: See main().</p>
   *
   * <p>Status: Passes simple main() unit-test. NEEDS JAVADOC.</p>
   * */
  public class IncrementalSAXSource_Xerces
    implements IncrementalSAXSource
  {
    //
    // Reflection. To allow this to compile with both Xerces1 and Xerces2, which
    // require very different methods and objects, we need to avoid static
    // references to those APIs. So until Xerces2 is pervasive and we're willing
    // to make it a prerequisite, we will rely upon relection.
    //
    Method fParseSomeSetup=null; // Xerces1 method
    Method fParseSome=null; // Xerces1 method
    Object fPullParserConfig=null; // Xerces2 pull control object
    Method fConfigSetInput=null; // Xerces2 method
    Method fConfigParse=null; // Xerces2 method
    Method fSetInputSource=null; // Xerces2 pull control method
    Constructor fConfigInputSourceCtor=null; // Xerces2 initialization method
    Method fConfigSetByteStream=null; // Xerces2 initialization method
    Method fConfigSetCharStream=null; // Xerces2 initialization method
    Method fConfigSetEncoding=null; // Xerces2 initialization method
    Method fReset=null; // Both Xerces1 and Xerces2, but diff. signatures
  
    //
    // Data
    //
    SAXParser fIncrementalParser;
    private boolean fParseInProgress=false;
  
    //
    // Constructors
    //
  
    /** Create a IncrementalSAXSource_Xerces, and create a SAXParser
     * to go with it. Xerces2 incremental parsing is only supported if
     * this constructor is used, due to limitations in the Xerces2 API (as of
     * Beta 3). If you don't like that restriction, tell the Xerces folks that
     * there should be a simpler way to request incremental SAX parsing.
     * */
    public IncrementalSAXSource_Xerces()
                  throws NoSuchMethodException
          {
                  try
                  {
                          // Xerces-2 incremental parsing support (as of Beta 3)
                          // ContentHandlers still get set on fIncrementalParser (to get
                          // conversion from XNI events to SAX events), but
                          // _control_ for incremental parsing must be exercised via the config.
                          //
                          // At this time there's no way to read the existing config, only
                          // to assert a new one... and only when creating a brand-new parser.
                          //
                          // Reflection is used to allow us to continue to compile against
                          // Xerces1. If/when we can abandon the older versions of the parser,
                          // this will simplify significantly.
  
                          // If we can't get the magic constructor, no need to look further.
                          Class xniConfigClass= ObjectFactory.findProviderClass(
                              "jaxp.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration",
                              true);
                          Class[] args1={xniConfigClass};
                          Constructor ctor=SAXParser.class.getConstructor(args1);
  
                          // Build the parser configuration object. StandardParserConfiguration
                          // happens to implement XMLPullParserConfiguration, which is the API
                          // we're going to want to use.
                          Class xniStdConfigClass=ObjectFactory.findProviderClass(
                              "jaxp.sun.org.apache.xerces.internal.parsers.StandardParserConfiguration",
                              true);
                          fPullParserConfig=xniStdConfigClass.newInstance();
                          Object[] args2={fPullParserConfig};
                          fIncrementalParser = (SAXParser)ctor.newInstance(args2);
  
                          // Preload all the needed the configuration methods... I want to know they're
                          // all here before we commit to trying to use them, just in case the
                          // API changes again.
                          Class fXniInputSourceClass=ObjectFactory.findProviderClass(
                              "jaxp.sun.org.apache.xerces.internal.xni.parser.XMLInputSource",
                              true);
                          Class[] args3={fXniInputSourceClass};
                          fConfigSetInput=xniStdConfigClass.getMethod("setInputSource",args3);
  
                          Class[] args4={String.class,String.class,String.class};
                          fConfigInputSourceCtor=fXniInputSourceClass.getConstructor(args4);
                          Class[] args5={java.io.InputStream.class};
                          fConfigSetByteStream=fXniInputSourceClass.getMethod("setByteStream",args5);
                          Class[] args6={java.io.Reader.class};
                          fConfigSetCharStream=fXniInputSourceClass.getMethod("setCharacterStream",args6);
                          Class[] args7={String.class};
                          fConfigSetEncoding=fXniInputSourceClass.getMethod("setEncoding",args7);
  
                          Class[] argsb={Boolean.TYPE};
                          fConfigParse=xniStdConfigClass.getMethod("parse",argsb);
                          Class[] noargs=new Class[0];
                          fReset=fIncrementalParser.getClass().getMethod("reset",noargs);
                  }
                  catch(Exception e)
                  {
              // Fallback if this fails (implemented in createIncrementalSAXSource) is
                          // to attempt Xerces-1 incremental setup. Can't do tail-call in
                          // constructor, so create new, copy Xerces-1 initialization,
                          // then throw it away... Ugh.
                          IncrementalSAXSource_Xerces dummy=new IncrementalSAXSource_Xerces(new SAXParser());
                          this.fParseSomeSetup=dummy.fParseSomeSetup;
                          this.fParseSome=dummy.fParseSome;
                          this.fIncrementalParser=dummy.fIncrementalParser;
                  }
    }
  
    /** Create a IncrementalSAXSource_Xerces wrapped around
     * an existing SAXParser. Currently this works only for recent
     * releases of Xerces-1.  Xerces-2 incremental is currently possible
     * only if we are allowed to create the parser instance, due to
     * limitations in the API exposed by Xerces-2 Beta 3; see the
     * no-args constructor for that code.
     *
     * @exception if the SAXParser class doesn't support the Xerces
     * incremental parse operations. In that case, caller should
     * fall back upon the IncrementalSAXSource_Filter approach.
     * */
    public IncrementalSAXSource_Xerces(SAXParser parser)
      throws NoSuchMethodException
    {
                  // Reflection is used to allow us to compile against
                  // Xerces2. If/when we can abandon the older versions of the parser,
                  // this constructor will simply have to fail until/unless the
                  // Xerces2 incremental support is made available on previously
                  // constructed SAXParser instances.
      fIncrementalParser=parser;
                  Class me=parser.getClass();
      Class[] parms={InputSource.class};
      fParseSomeSetup=me.getMethod("parseSomeSetup",parms);
      parms=new Class[0];
      fParseSome=me.getMethod("parseSome",parms);
      // Fallback if this fails (implemented in createIncrementalSAXSource) is
      // to use IncrementalSAXSource_Filter rather than Xerces-specific code.
    }
  
    //
    // Factories
    //
    static public IncrementalSAXSource createIncrementalSAXSource()
          {
                  try
                  {
                          return new IncrementalSAXSource_Xerces();
                  }
                  catch(NoSuchMethodException e)
                  {
                          // Xerces version mismatch; neither Xerces1 nor Xerces2 succeeded.
                          // Fall back on filtering solution.
                          IncrementalSAXSource_Filter iss=new IncrementalSAXSource_Filter();
                          iss.setXMLReader(new SAXParser());
                          return iss;
                  }
    }
  
    static public IncrementalSAXSource
    createIncrementalSAXSource(SAXParser parser) {
                  try
                  {
                          return new IncrementalSAXSource_Xerces(parser);
                  }
                  catch(NoSuchMethodException e)
                  {
                          // Xerces version mismatch; neither Xerces1 nor Xerces2 succeeded.
                          // Fall back on filtering solution.
                          IncrementalSAXSource_Filter iss=new IncrementalSAXSource_Filter();
                          iss.setXMLReader(parser);
                          return iss;
                  }
    }
  
    //
    // Public methods
    //
  
    // Register handler directly with the incremental parser
    public void setContentHandler(org.xml.sax.ContentHandler handler)
    {
      // Typecast required in Xerces2; SAXParser doesn't inheret XMLReader
      // %OPT% Cast at asignment?
      ((XMLReader)fIncrementalParser).setContentHandler(handler);
    }
  
    // Register handler directly with the incremental parser
    public void setLexicalHandler(org.xml.sax.ext.LexicalHandler handler)
    {
      // Not supported by all SAX2 parsers but should work in Xerces:
      try
      {
        // Typecast required in Xerces2; SAXParser doesn't inheret XMLReader
        // %OPT% Cast at asignment?
        ((XMLReader)fIncrementalParser).setProperty("http://xml.org/sax/properties/lexical-handler",
                                       handler);
      }
      catch(org.xml.sax.SAXNotRecognizedException e)
      {
        // Nothing we can do about it
      }
      catch(org.xml.sax.SAXNotSupportedException e)
      {
        // Nothing we can do about it
      }
    }
  
    // Register handler directly with the incremental parser
    public void setDTDHandler(org.xml.sax.DTDHandler handler)
    {
      // Typecast required in Xerces2; SAXParser doesn't inheret XMLReader
      // %OPT% Cast at asignment?
      ((XMLReader)fIncrementalParser).setDTDHandler(handler);
    }
  
    //================================================================
    /** startParse() is a simple API which tells the IncrementalSAXSource
     * to begin reading a document.
     *
     * @throws SAXException is parse thread is already in progress
     * or parsing can not be started.
     * */
    public void startParse(InputSource source) throws SAXException
    {
      if (fIncrementalParser==null)
        throw new SAXException(XMLMessages.createXMLMessage(XMLErrorResources.ER_STARTPARSE_NEEDS_SAXPARSER, null)); //"startParse needs a non-null SAXParser.");
      if (fParseInProgress)
        throw new SAXException(XMLMessages.createXMLMessage(XMLErrorResources.ER_STARTPARSE_WHILE_PARSING, null)); //"startParse may not be called while parsing.");
  
      boolean ok=false;
  
      try
      {
        ok = parseSomeSetup(source);
      }
      catch(Exception ex)
      {
        throw new SAXException(ex);
      }
  
      if(!ok)
        throw new SAXException(XMLMessages.createXMLMessage(XMLErrorResources.ER_COULD_NOT_INIT_PARSER, null)); //"could not initialize parser with");
    }
  
  
    /** deliverMoreNodes() is a simple API which tells the coroutine
     * parser that we need more nodes.  This is intended to be called
     * from one of our partner routines, and serves to encapsulate the
     * details of how incremental parsing has been achieved.
     *
     * @param parsemore If true, tells the incremental parser to generate
     * another chunk of output. If false, tells the parser that we're
     * satisfied and it can terminate parsing of this document.
     * @return Boolean.TRUE if the CoroutineParser believes more data may be available
     * for further parsing. Boolean.FALSE if parsing ran to completion.
     * Exception if the parser objected for some reason.
     * */
    public Object deliverMoreNodes (boolean parsemore)
    {
      if(!parsemore)
      {
        fParseInProgress=false;
        return Boolean.FALSE;
      }
  
      Object arg;
      try {
        boolean keepgoing = parseSome();
        arg = keepgoing ? Boolean.TRUE : Boolean.FALSE;
      } catch (SAXException ex) {
        arg = ex;
      } catch (IOException ex) {
        arg = ex;
      } catch (Exception ex) {
        arg = new SAXException(ex);
      }
      return arg;
    }
  
          // Private methods -- conveniences to hide the reflection details
          private boolean parseSomeSetup(InputSource source)
                  throws SAXException, IOException, IllegalAccessException,
                                           java.lang.reflect.InvocationTargetException,
                                           java.lang.InstantiationException
          {
                  if(fConfigSetInput!=null)
                  {
                          // Obtain input from SAX inputSource object, construct XNI version of
                          // that object. Logic adapted from Xerces2.
                          Object[] parms1={source.getPublicId(),source.getSystemId(),null};
                          Object xmlsource=fConfigInputSourceCtor.newInstance(parms1);
                          Object[] parmsa={source.getByteStream()};
                          fConfigSetByteStream.invoke(xmlsource,parmsa);
                          parmsa[0]=source.getCharacterStream();
                          fConfigSetCharStream.invoke(xmlsource,parmsa);
                          parmsa[0]=source.getEncoding();
                          fConfigSetEncoding.invoke(xmlsource,parmsa);
  
                          // Bugzilla5272 patch suggested by Sandy Gao.
                          // Has to be reflection to run with Xerces2
                          // after compilation against Xerces1. or vice
                          // versa, due to return type mismatches.
                          Object[] noparms=new Object[0];
                          fReset.invoke(fIncrementalParser,noparms);
  
                          parmsa[0]=xmlsource;
                          fConfigSetInput.invoke(fPullParserConfig,parmsa);
  
                          // %REVIEW% Do first pull. Should we instead just return true?
                          return parseSome();
                  }
                  else
                  {
                          Object[] parm={source};
                          Object ret=fParseSomeSetup.invoke(fIncrementalParser,parm);
                          return ((Boolean)ret).booleanValue();
                  }
          }
  //  Would null work???
      private static final Object[] noparms=new Object[0];
      private static final Object[] parmsfalse={Boolean.FALSE};
      private boolean parseSome()
                  throws SAXException, IOException, IllegalAccessException,
                                           java.lang.reflect.InvocationTargetException
          {
                  // Take next parsing step, return false iff parsing complete:
                  if(fConfigSetInput!=null)
                  {
                          Object ret=(Boolean)(fConfigParse.invoke(fPullParserConfig,parmsfalse));
                          return ((Boolean)ret).booleanValue();
                  }
                  else
                  {
                          Object ret=fParseSome.invoke(fIncrementalParser,noparms);
                          return ((Boolean)ret).booleanValue();
                  }
          }
  
  
    //================================================================
    /** Simple unit test. Attempt coroutine parsing of document indicated
     * by first argument (as a URI), report progress.
     */
    public static void _main(String args[])
    {
      System.out.println("Starting...");
  
      CoroutineManager co = new CoroutineManager();
      int appCoroutineID = co.co_joinCoroutineSet(-1);
      if (appCoroutineID == -1)
      {
        System.out.println("ERROR: Couldn't allocate coroutine number.\n");
        return;
      }
      IncrementalSAXSource parser=
        createIncrementalSAXSource();
  
      // Use a serializer as our sample output
      XMLSerializer trace;
      trace=new XMLSerializer(System.out,null);
      parser.setContentHandler(trace);
      parser.setLexicalHandler(trace);
  
      // Tell coroutine to begin parsing, run while parsing is in progress
  
      for(int arg=0;arg<args.length;++arg)
      {
        try
        {
          InputSource source = new InputSource(args[arg]);
          Object result=null;
          boolean more=true;
          parser.startParse(source);
          for(result = parser.deliverMoreNodes(more);
              result==Boolean.TRUE;
              result = parser.deliverMoreNodes(more))
          {
            System.out.println("\nSome parsing successful, trying more.\n");
  
            // Special test: Terminate parsing early.
            if(arg+1<args.length && "!".equals(args[arg+1]))
            {
              ++arg;
              more=false;
            }
  
          }
  
          if (result instanceof Boolean && ((Boolean)result)==Boolean.FALSE)
          {
            System.out.println("\nParser ended (EOF or on request).\n");
          }
          else if (result == null) {
            System.out.println("\nUNEXPECTED: Parser says shut down prematurely.\n");
          }
          else if (result instanceof Exception) {
            throw new WrappedRuntimeException((Exception)result);
            //          System.out.println("\nParser threw exception:");
            //          ((Exception)result).printStackTrace();
          }
  
        }
  
        catch(SAXException e)
        {
          e.printStackTrace();
        }
      }
  
    }
  
  
  } // class IncrementalSAXSource_Xerces
  