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.util;
  
  import jaxp.sun.org.apache.xerces.internal.xni.grammars.Grammar;
  import jaxp.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
  import jaxp.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
  
  /**
   * Stores grammars in a pool associated to a specific key. This grammar pool
   * implementation stores two types of grammars: those keyed by the root element
   * name, and those keyed by the grammar's target namespace.
   *
   * This is the default implementation of the GrammarPool interface.
   * As we move forward, this will become more function-rich and robust.
   *
   * @author Jeffrey Rodriguez, IBM
   * @author Andy Clark, IBM
   * @author Neil Graham, IBM
   * @author Pavani Mukthipudi, Sun Microsystems
   * @author Neeraj Bajaj, SUN Microsystems
   *
   */
  public class XMLGrammarPoolImpl implements XMLGrammarPool {
  
      //
      // Constants
      //
  
      /** Default size. */
      protected static final int TABLE_SIZE = 11;
  
      //
      // Data
      //
  
      /** Grammars. */
      protected Entry[] fGrammars = null;
  
      // whether this pool is locked
      protected boolean fPoolIsLocked;
  
      // the number of grammars in the pool
      protected int fGrammarCount = 0;
  
      private static final boolean DEBUG = false ;
  
      //
      // Constructors
      //
  
      /** Constructs a grammar pool with a default number of buckets. */
      public XMLGrammarPoolImpl() {
          fGrammars = new Entry[TABLE_SIZE];
          fPoolIsLocked = false;
      } // <init>()
  
      /** Constructs a grammar pool with a specified number of buckets. */
      public XMLGrammarPoolImpl(int initialCapacity) {
          fGrammars = new Entry[initialCapacity];
          fPoolIsLocked = false;
      }
  
      //
      // XMLGrammarPool methods
      //
  
      /* <p> Retrieve the initial known set of grammars. This method is
       * called by a validator before the validation starts. The application
       * can provide an initial set of grammars available to the current
       * validation attempt. </p>
       *
       * @param grammarType The type of the grammar, from the
       *                    <code>com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription</code>
       *                    interface.
       * @return            The set of grammars the validator may put in its "bucket"
       */
      public Grammar [] retrieveInitialGrammarSet (String grammarType) {
          synchronized (fGrammars) {
              int grammarSize = fGrammars.length ;
              Grammar [] tempGrammars = new Grammar[fGrammarCount];
              int pos = 0;
              for (int i = 0; i < grammarSize; i++) {
                  for (Entry e = fGrammars[i]; e != null; e = e.next) {
                      if (e.desc.getGrammarType().equals(grammarType)) {
                          tempGrammars[pos++] = e.grammar;
                      }
                  }
              }
              Grammar[] toReturn = new Grammar[pos];
              System.arraycopy(tempGrammars, 0, toReturn, 0, pos);
              return toReturn;
          }
      } // retrieveInitialGrammarSet (String): Grammar[]
  
      /* <p> Return the final set of grammars that the validator ended up
       * with. This method is called after the validation finishes. The
       * application may then choose to cache some of the returned grammars.</p>
       * <p>In this implementation, we make our choice based on whether this object
       * is "locked"--that is, whether the application has instructed
       * us not to accept any new grammars.</p>
       *
       * @param grammarType The type of the grammars being returned;
       * @param grammars    An array containing the set of grammars being
       *                    returned; order is not significant.
       */
      public void cacheGrammars(String grammarType, Grammar[] grammars) {
          if(!fPoolIsLocked) {
              for (int i = 0; i < grammars.length; i++) {
                  if(DEBUG) {
                      System.out.println("CACHED GRAMMAR " + (i+1) ) ;
                      Grammar temp = grammars[i] ;
                      //print(temp.getGrammarDescription());
                  }
                  putGrammar(grammars[i]);
              }
          }
      } // cacheGrammars(String, Grammar[]);
  
      /* <p> This method requests that the application retrieve a grammar
       * corresponding to the given GrammarIdentifier from its cache.
       * If it cannot do so it must return null; the parser will then
       * call the EntityResolver. </p>
       * <strong>An application must not call its EntityResolver itself
       * from this method; this may result in infinite recursions.</strong>
       *
       * This implementation chooses to use the root element name to identify a DTD grammar
       * and the target namespace to identify a Schema grammar.
       *
       * @param desc The description of the Grammar being requested.
       * @return     The Grammar corresponding to this description or null if
       *             no such Grammar is known.
       */
      public Grammar retrieveGrammar(XMLGrammarDescription desc) {
          if(DEBUG){
              System.out.println("RETRIEVING GRAMMAR FROM THE APPLICATION WITH FOLLOWING DESCRIPTION :");
              //print(desc);
          }
          return getGrammar(desc);
      } // retrieveGrammar(XMLGrammarDescription):  Grammar
  
      //
      // Public methods
      //
  
      /**
       * Puts the specified grammar into the grammar pool and associates it to
       * its root element name or its target namespace.
       *
       * @param grammar The Grammar.
       */
      public void putGrammar(Grammar grammar) {
          if(!fPoolIsLocked) {
              synchronized (fGrammars) {
                  XMLGrammarDescription desc = grammar.getGrammarDescription();
                  int hash = hashCode(desc);
                  int index = (hash & 0x7FFFFFFF) % fGrammars.length;
                  for (Entry entry = fGrammars[index]; entry != null; entry = entry.next) {
                      if (entry.hash == hash && equals(entry.desc, desc)) {
                          entry.grammar = grammar;
                          return;
                      }
                  }
                  // create a new entry
                  Entry entry = new Entry(hash, desc, grammar, fGrammars[index]);
                  fGrammars[index] = entry;
                  fGrammarCount++;
              }
          }
      } // putGrammar(Grammar)
  
      /**
       * Returns the grammar associated to the specified grammar description.
       * Currently, the root element name is used as the key for DTD grammars
       * and the target namespace  is used as the key for Schema grammars.
       *
       * @param desc The Grammar Description.
       */
      public Grammar getGrammar(XMLGrammarDescription desc) {
          synchronized (fGrammars) {
              int hash = hashCode(desc);
          int index = (hash & 0x7FFFFFFF) % fGrammars.length;
          for (Entry entry = fGrammars[index] ; entry != null ; entry = entry.next) {
              if ((entry.hash == hash) && equals(entry.desc, desc)) {
                  return entry.grammar;
              }
          }
          return null;
      }
      } // getGrammar(XMLGrammarDescription):Grammar
  
      /**
       * Removes the grammar associated to the specified grammar description from the
       * grammar pool and returns the removed grammar. Currently, the root element name
       * is used as the key for DTD grammars and the target namespace  is used
       * as the key for Schema grammars.
       *
       * @param desc The Grammar Description.
       * @return     The removed grammar.
       */
      public Grammar removeGrammar(XMLGrammarDescription desc) {
          synchronized (fGrammars) {
              int hash = hashCode(desc);
          int index = (hash & 0x7FFFFFFF) % fGrammars.length;
          for (Entry entry = fGrammars[index], prev = null ; entry != null ; prev = entry, entry = entry.next) {
              if ((entry.hash == hash) && equals(entry.desc, desc)) {
                  if (prev != null) {
                          prev.next = entry.next;
              }
              else {
                  fGrammars[index] = entry.next;
              }
                  Grammar tempGrammar = entry.grammar;
                  entry.grammar = null;
                  fGrammarCount--;
                  return tempGrammar;
              }
          }
          return null;
          }
      } // removeGrammar(XMLGrammarDescription):Grammar
  
      /**
       * Returns true if the grammar pool contains a grammar associated
       * to the specified grammar description. Currently, the root element name
       * is used as the key for DTD grammars and the target namespace  is used
       * as the key for Schema grammars.
       *
       * @param desc The Grammar Description.
       */
      public boolean containsGrammar(XMLGrammarDescription desc) {
          synchronized (fGrammars) {
              int hash = hashCode(desc);
          int index = (hash & 0x7FFFFFFF) % fGrammars.length;
          for (Entry entry = fGrammars[index] ; entry != null ; entry = entry.next) {
              if ((entry.hash == hash) && equals(entry.desc, desc)) {
                  return true;
              }
          }
          return false;
      }
      } // containsGrammar(XMLGrammarDescription):boolean
  
      /* <p> Sets this grammar pool to a "locked" state--i.e.,
       * no new grammars will be added until it is "unlocked".
       */
      public void lockPool() {
          fPoolIsLocked = true;
      } // lockPool()
  
      /* <p> Sets this grammar pool to an "unlocked" state--i.e.,
       * new grammars will be added when putGrammar or cacheGrammars
       * are called.
       */
      public void unlockPool() {
          fPoolIsLocked = false;
      } // unlockPool()
  
      /*
       * <p>This method clears the pool-i.e., removes references
       * to all the grammars in it.</p>
       */
      public void clear() {
          for (int i=0; i<fGrammars.length; i++) {
              if(fGrammars[i] != null) {
                  fGrammars[i].clear();
                  fGrammars[i] = null;
              }
          }
          fGrammarCount = 0;
      } // clear()
  
      /**
       * This method checks whether two grammars are the same. Currently, we compare
       * the root element names for DTD grammars and the target namespaces for Schema grammars.
       * The application can override this behaviour and add its own logic.
       *
       * @param desc1 The grammar description
       * @param desc2 The grammar description of the grammar to be compared to
       * @return      True if the grammars are equal, otherwise false
       */
      public boolean equals(XMLGrammarDescription desc1, XMLGrammarDescription desc2) {
          return desc1.equals(desc2);
      }
  
      /**
       * Returns the hash code value for the given grammar description.
       *
       * @param desc The grammar description
       * @return     The hash code value
       */
      public int hashCode(XMLGrammarDescription desc) {
          return desc.hashCode();
      }
  
      /**
       * This class is a grammar pool entry. Each entry acts as a node
       * in a linked list.
       */
      protected static final class Entry {
          public int hash;
          public XMLGrammarDescription desc;
          public Grammar grammar;
          public Entry next;
  
          protected Entry(int hash, XMLGrammarDescription desc, Grammar grammar, Entry next) {
              this.hash = hash;
              this.desc = desc;
              this.grammar = grammar;
              this.next = next;
          }
  
          // clear this entry; useful to promote garbage collection
          // since reduces reference count of objects to be destroyed
          protected void clear () {
              desc = null;
              grammar = null;
              if(next != null) {
                  next.clear();
                  next = null;
              }
          } // clear()
      } // class Entry
  
      /* For DTD build we can't import here XSDDescription. Thus, this method is commented out.. */
      /* public void print(XMLGrammarDescription description){
          if(description.getGrammarType().equals(XMLGrammarDescription.XML_DTD)){
  
          }
          else if(description.getGrammarType().equals(XMLGrammarDescription.XML_SCHEMA)){
              XSDDescription schema = (XSDDescription)description ;
              System.out.println("Context = " + schema.getContextType());
              System.out.println("TargetNamespace = " + schema.getTargetNamespace());
              String [] temp = schema.getLocationHints();
  
              for (int i = 0 ; (temp != null && i < temp.length) ; i++){
                  System.out.println("LocationHint " + i + " = "+ temp[i]);
              }
  
              System.out.println("Triggering Component = " + schema.getTriggeringComponent());
              System.out.println("EnclosingElementName =" + schema.getEnclosingElementName());
  
          }
  
      }//print
      */
  
  } // class XMLGrammarPoolImpl
  