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-2002,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.
   */
  
  package jaxp.sun.org.apache.xerces.internal.parsers;
  
  import jaxp.sun.org.apache.xerces.internal.xni.grammars.Grammar;
  import jaxp.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
  import jaxp.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
  import jaxp.sun.org.apache.xerces.internal.util.XMLGrammarPoolImpl;
  
  import jaxp.sun.org.apache.xerces.internal.util.ShadowedSymbolTable;
  import jaxp.sun.org.apache.xerces.internal.util.SymbolTable;
  import jaxp.sun.org.apache.xerces.internal.util.SynchronizedSymbolTable;
  
  /**
   * A parser pool that enables caching of grammars. The caching parser
   * pool is constructed with a specific symbol table and grammar pool
   * that has already been populated with the grammars used by the
   * application.
   * <p>
   * Once the caching parser pool is constructed, specific parser
   * instances are created by calling the appropriate factory method
   * on the parser pool.
   * <p>
   * <strong>Note:</strong> There is a performance penalty for using
   * a caching parser pool due to thread safety. Access to the symbol
   * table and grammar pool must be synchronized to ensure the safe
   * operation of the symbol table and grammar pool.
   * <p>
   * <strong>Note:</strong> If performance is critical, then another
   * mechanism needs to be used instead of the caching parser pool.
   * One approach would be to create parser instances that do not
   * share these structures. Instead, each instance would get its
   * own copy to use while parsing. This avoids the synchronization
   * overhead at the expense of more memory and the time required
   * to copy the structures for each new parser instance. And even
   * when a parser instance is re-used, there is a potential for a
   * memory leak due to new symbols being added to the symbol table
   * over time. In other words, always take caution to make sure
   * that your application is thread-safe and avoids leaking memory.
   *
   * @author Andy Clark, IBM
   *
   */
  public class CachingParserPool {
  
      //
      // Constants
      //
  
      /** Default shadow symbol table (false). */
      public static final boolean DEFAULT_SHADOW_SYMBOL_TABLE = false;
  
      /** Default shadow grammar pool (false). */
      public static final boolean DEFAULT_SHADOW_GRAMMAR_POOL = false;
  
      //
      // Data
      //
  
      /**
       * Symbol table. The symbol table that the caching parser pool is
       * constructed with is automatically wrapped in a synchronized
       * version for thread-safety.
       */
      protected SymbolTable fSynchronizedSymbolTable;
  
      /**
       * Grammar pool. The grammar pool that the caching parser pool is
       * constructed with is automatically wrapped in a synchronized
       * version for thread-safety.
       */
      protected XMLGrammarPool fSynchronizedGrammarPool;
  
      /**
       * Shadow the symbol table for new parser instances. If true,
       * new parser instances use shadow copies of the main symbol
       * table and are not allowed to add new symbols to the main
       * symbol table. New symbols are added to the shadow symbol
       * table and are local to the parser instance.
       */
      protected boolean fShadowSymbolTable = DEFAULT_SHADOW_SYMBOL_TABLE;
  
      /**
       * Shadow the grammar pool for new parser instances. If true,
       * new parser instances use shadow copies of the main grammar
       * pool and are not allowed to add new grammars to the main
       * grammar pool. New grammars are added to the shadow grammar
       * pool and are local to the parser instance.
       */
      protected boolean fShadowGrammarPool = DEFAULT_SHADOW_GRAMMAR_POOL;
  
      //
      // Constructors
      //
  
      /** Default constructor. */
      public CachingParserPool() {
          this(new SymbolTable(), new XMLGrammarPoolImpl());
      } // <init>()
  
      /**
       * Constructs a caching parser pool with the specified symbol table
       * and grammar pool.
       *
       * @param symbolTable The symbol table.
       * @param grammarPool The grammar pool.
       */
      public CachingParserPool(SymbolTable symbolTable, XMLGrammarPool grammarPool) {
          fSynchronizedSymbolTable = new SynchronizedSymbolTable(symbolTable);
          fSynchronizedGrammarPool = new SynchronizedGrammarPool(grammarPool);
      } // <init>(SymbolTable,XMLGrammarPool)
  
      //
      // Public methods
      //
  
      /** Returns the symbol table. */
      public SymbolTable getSymbolTable() {
          return fSynchronizedSymbolTable;
      } // getSymbolTable():SymbolTable
  
      /** Returns the grammar pool. */
      public XMLGrammarPool getXMLGrammarPool() {
          return fSynchronizedGrammarPool;
      } // getXMLGrammarPool():XMLGrammarPool
  
      // setters and getters
  
      /**
       * Sets whether new parser instance receive shadow copies of the
       * main symbol table.
       *
       * @param shadow If true, new parser instances use shadow copies
       *               of the main symbol table and are not allowed to
       *               add new symbols to the main symbol table. New
       *               symbols are added to the shadow symbol table and
       *               are local to the parser instance. If false, new
       *               parser instances are allowed to add new symbols
       *               to the main symbol table.
       */
      public void setShadowSymbolTable(boolean shadow) {
          fShadowSymbolTable = shadow;
      } // setShadowSymbolTable(boolean)
  
      // factory methods
  
      /** Creates a new DOM parser. */
      public DOMParser createDOMParser() {
          SymbolTable symbolTable = fShadowSymbolTable
                                  ? new ShadowedSymbolTable(fSynchronizedSymbolTable)
                                  : fSynchronizedSymbolTable;
          XMLGrammarPool grammarPool = fShadowGrammarPool
                                  ? new ShadowedGrammarPool(fSynchronizedGrammarPool)
                                  : fSynchronizedGrammarPool;
          return new DOMParser(symbolTable, grammarPool);
      } // createDOMParser():DOMParser
  
      /** Creates a new SAX parser. */
      public SAXParser createSAXParser() {
          SymbolTable symbolTable = fShadowSymbolTable
                                  ? new ShadowedSymbolTable(fSynchronizedSymbolTable)
                                  : fSynchronizedSymbolTable;
          XMLGrammarPool grammarPool = fShadowGrammarPool
                                  ? new ShadowedGrammarPool(fSynchronizedGrammarPool)
                                  : fSynchronizedGrammarPool;
          return new SAXParser(symbolTable, grammarPool);
      } // createSAXParser():SAXParser
  
      //
      // Classes
      //
  
      /**
       * Synchronized grammar pool.
       *
       * @author Andy Clark, IBM
       */
      public static final class SynchronizedGrammarPool
          implements XMLGrammarPool {
  
          //
          // Data
          //
  
          /** Main grammar pool. */
          private XMLGrammarPool fGrammarPool;
  
          //
          // Constructors
          //
  
          /** Constructs a synchronized grammar pool. */
          public SynchronizedGrammarPool(XMLGrammarPool grammarPool) {
              fGrammarPool = grammarPool;
          } // <init>(XMLGrammarPool)
  
          //
          // GrammarPool methods
          //
  
          // retrieve the initial set of grammars for the validator
          // to work with.
          // REVISIT:  does this need to be synchronized since it's just reading?
          // @param grammarType type of the grammars to be retrieved.
          // @return the initial grammar set the validator may place in its "bucket"
          public Grammar [] retrieveInitialGrammarSet(String grammarType ) {
              synchronized (fGrammarPool) {
                  return fGrammarPool.retrieveInitialGrammarSet(grammarType);
              }
          } // retrieveInitialGrammarSet(String):  Grammar[]
  
          // retrieve a particular grammar.
          // REVISIT:  does this need to be synchronized since it's just reading?
          // @param gDesc description of the grammar to be retrieved
          // @return Grammar corresponding to gDesc, or null if none exists.
          public Grammar retrieveGrammar(XMLGrammarDescription gDesc) {
              synchronized (fGrammarPool) {
                  return fGrammarPool.retrieveGrammar(gDesc);
              }
          } // retrieveGrammar(XMLGrammarDesc):  Grammar
  
          // give the grammarPool the option of caching these grammars.
          // This certainly must be synchronized.
          // @param grammarType The type of the grammars to be cached.
          // @param grammars the Grammars that may be cached (unordered, Grammars previously
          //  given to the validator may be included).
          public void cacheGrammars(String grammarType, Grammar[] grammars) {
              synchronized (fGrammarPool) {
                  fGrammarPool.cacheGrammars(grammarType, grammars);
              }
          } // cacheGrammars(String, Grammar[]);
  
          /** lock the grammar pool */
          public void lockPool() {
              synchronized (fGrammarPool) {
                  fGrammarPool.lockPool();
              }
          } // lockPool()
  
          /** clear the grammar pool */
          public void clear() {
              synchronized (fGrammarPool) {
                  fGrammarPool.clear();
              }
          } // lockPool()
  
          /** unlock the grammar pool */
          public void unlockPool() {
              synchronized (fGrammarPool) {
                  fGrammarPool.unlockPool();
              }
          } // unlockPool()
  
          /***
           * Methods corresponding to original (pre Xerces2.0.0final)
           * grammarPool have been commented out.
           */
          /**
           * Puts the specified grammar into the grammar pool.
           *
           * @param key Key to associate with grammar.
           * @param grammar Grammar object.
           */
          /******
          public void putGrammar(String key, Grammar grammar) {
              synchronized (fGrammarPool) {
                  fGrammarPool.putGrammar(key, grammar);
              }
          } // putGrammar(String,Grammar)
          *******/
  
          /**
           * Returns the grammar associated to the specified key.
           *
           * @param key The key of the grammar.
           */
          /**********
          public Grammar getGrammar(String key) {
              synchronized (fGrammarPool) {
                  return fGrammarPool.getGrammar(key);
              }
          } // getGrammar(String):Grammar
          ***********/
  
          /**
           * Removes the grammar associated to the specified key from the
           * grammar pool and returns the removed grammar.
           *
           * @param key The key of the grammar.
           */
          /**********
          public Grammar removeGrammar(String key) {
              synchronized (fGrammarPool) {
                  return fGrammarPool.removeGrammar(key);
              }
          } // removeGrammar(String):Grammar
          ******/
  
          /**
           * Returns true if the grammar pool contains a grammar associated
           * to the specified key.
           *
           * @param key The key of the grammar.
           */
          /**********
          public boolean containsGrammar(String key) {
              synchronized (fGrammarPool) {
                  return fGrammarPool.containsGrammar(key);
              }
          } // containsGrammar(String):boolean
          ********/
  
      } // class SynchronizedGrammarPool
  
      /**
       * Shadowed grammar pool.
       * This class is predicated on the existence of a concrete implementation;
       * so using our own doesn't seem to bad an idea.
       *
       * @author Andy Clark, IBM
       * @author Neil Graham, IBM
       */
      public static final class ShadowedGrammarPool
          extends XMLGrammarPoolImpl {
  
          //
          // Data
          //
  
          /** Main grammar pool. */
          private XMLGrammarPool fGrammarPool;
  
          //
          // Constructors
          //
  
          /** Constructs a shadowed grammar pool. */
          public ShadowedGrammarPool(XMLGrammarPool grammarPool) {
              fGrammarPool = grammarPool;
          } // <init>(GrammarPool)
  
          //
          // GrammarPool methods
          //
  
          /**
           * Retrieve the initial set of grammars for the validator to work with.
           * REVISIT:  does this need to be synchronized since it's just reading?
           *
           * @param grammarType Type of the grammars to be retrieved.
           * @return            The initial grammar set the validator may place in its "bucket"
           */
          public Grammar [] retrieveInitialGrammarSet(String grammarType ) {
              Grammar [] grammars = super.retrieveInitialGrammarSet(grammarType);
              if (grammars != null) return grammars;
              return fGrammarPool.retrieveInitialGrammarSet(grammarType);
          } // retrieveInitialGrammarSet(String):  Grammar[]
  
          /**
           * Retrieve a particular grammar.
           * REVISIT:  does this need to be synchronized since it's just reading?
           *
           * @param gDesc Description of the grammar to be retrieved
           * @return      Grammar corresponding to gDesc, or null if none exists.
           */
          public Grammar retrieveGrammar(XMLGrammarDescription gDesc) {
              Grammar g = super.retrieveGrammar(gDesc);
              if(g != null) return g;
              return fGrammarPool.retrieveGrammar(gDesc);
          } // retrieveGrammar(XMLGrammarDesc):  Grammar
  
          /**
           * Give the grammarPool the option of caching these grammars.
           * This certainly must be synchronized.
           *
           * @param grammarType The type of the grammars to be cached.
           * @param grammars    The Grammars that may be cached (unordered, Grammars previously
           *                    given to the validator may be included).
           */
          public void cacheGrammars(String grammarType, Grammar[] grammars) {
             // better give both grammars a shot...
             super.cacheGrammars(grammarType, grammars);
             fGrammarPool.cacheGrammars(grammarType, grammars);
          } // cacheGrammars(grammarType, Grammar[]);
  
          /**
           * Returns the grammar associated to the specified description.
           *
           * @param desc The description of the grammar.
           */
          public Grammar getGrammar(XMLGrammarDescription desc) {
  
              if (super.containsGrammar(desc)) {
                  return super.getGrammar(desc);
              }
              return null;
  
          } // getGrammar(XMLGrammarDescription):Grammar
  
          /**
           * Returns true if the grammar pool contains a grammar associated
           * to the specified description.
           *
           * @param desc The description of the grammar.
           */
          public boolean containsGrammar(XMLGrammarDescription desc) {
              return super.containsGrammar(desc);
          } // containsGrammar(XMLGrammarDescription):boolean
  
      } // class ShadowedGrammarPool
  
  } // class CachingParserPool
  