1. /*
  2. * Copyright 1999-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /*
  17. * $Id: ExpandedNameTable.java,v 1.13 2004/02/16 23:06:11 minchau Exp $
  18. */
  19. package com.sun.org.apache.xml.internal.dtm.ref;
  20. import com.sun.org.apache.xml.internal.dtm.DTM;
  21. /**
  22. * This is a default implementation of a table that manages mappings from
  23. * expanded names to expandedNameIDs.
  24. *
  25. * %OPT% The performance of the getExpandedTypeID() method is very important
  26. * to DTM building. To get the best performance out of this class, we implement
  27. * a simple hash algorithm directly into this class, instead of using the
  28. * inefficient java.util.Hashtable. The code for the get and put operations
  29. * are combined in getExpandedTypeID() method to share the same hash calculation
  30. * code. We only need to implement the rehash() interface which is used to
  31. * expand the hash table.
  32. */
  33. public class ExpandedNameTable
  34. {
  35. /** Array of extended types for this document */
  36. private ExtendedType[] m_extendedTypes;
  37. /** The initial size of the m_extendedTypes array */
  38. private static int m_initialSize = 128;
  39. /** Next available extended type */
  40. // %REVIEW% Since this is (should be) always equal
  41. // to the length of m_extendedTypes, do we need this?
  42. private int m_nextType;
  43. // These are all the types prerotated, for caller convenience.
  44. public static final int ELEMENT = ((int)DTM.ELEMENT_NODE) ;
  45. public static final int ATTRIBUTE = ((int)DTM.ATTRIBUTE_NODE) ;
  46. public static final int TEXT = ((int)DTM.TEXT_NODE) ;
  47. public static final int CDATA_SECTION = ((int)DTM.CDATA_SECTION_NODE) ;
  48. public static final int ENTITY_REFERENCE = ((int)DTM.ENTITY_REFERENCE_NODE) ;
  49. public static final int ENTITY = ((int)DTM.ENTITY_NODE) ;
  50. public static final int PROCESSING_INSTRUCTION = ((int)DTM.PROCESSING_INSTRUCTION_NODE) ;
  51. public static final int COMMENT = ((int)DTM.COMMENT_NODE) ;
  52. public static final int DOCUMENT = ((int)DTM.DOCUMENT_NODE) ;
  53. public static final int DOCUMENT_TYPE = ((int)DTM.DOCUMENT_TYPE_NODE) ;
  54. public static final int DOCUMENT_FRAGMENT =((int)DTM.DOCUMENT_FRAGMENT_NODE) ;
  55. public static final int NOTATION = ((int)DTM.NOTATION_NODE) ;
  56. public static final int NAMESPACE = ((int)DTM.NAMESPACE_NODE) ;
  57. /** Workspace for lookup. NOT THREAD SAFE!
  58. * */
  59. ExtendedType hashET = new ExtendedType(-1, "", "");
  60. /** The array to store the default extended types. */
  61. private static ExtendedType[] m_defaultExtendedTypes;
  62. /**
  63. * The default load factor of the Hashtable.
  64. * This is used to calcualte the threshold.
  65. */
  66. private static float m_loadFactor = 0.75f;
  67. /**
  68. * The initial capacity of the hash table. Use a bigger number
  69. * to avoid the cost of expanding the table.
  70. */
  71. private static int m_initialCapacity = 203;
  72. /**
  73. * The capacity of the hash table, i.e. the size of the
  74. * internal HashEntry array.
  75. */
  76. private int m_capacity;
  77. /**
  78. * The threshold of the hash table, which is equal to capacity * loadFactor.
  79. * If the number of entries in the hash table is bigger than the threshold,
  80. * the hash table needs to be expanded.
  81. */
  82. private int m_threshold;
  83. /**
  84. * The internal array to store the hash entries.
  85. * Each array member is a slot for a hash bucket.
  86. */
  87. private HashEntry[] m_table;
  88. /**
  89. * Init default values
  90. */
  91. static {
  92. m_defaultExtendedTypes = new ExtendedType[DTM.NTYPES];
  93. for (int i = 0; i < DTM.NTYPES; i++)
  94. {
  95. m_defaultExtendedTypes[i] = new ExtendedType(i, "", "");
  96. }
  97. }
  98. /**
  99. * Create an expanded name table.
  100. */
  101. public ExpandedNameTable()
  102. {
  103. m_capacity = m_initialCapacity;
  104. m_threshold = (int)(m_capacity * m_loadFactor);
  105. m_table = new HashEntry[m_capacity];
  106. initExtendedTypes();
  107. }
  108. /**
  109. * Initialize the vector of extended types with the
  110. * basic DOM node types.
  111. */
  112. private void initExtendedTypes()
  113. {
  114. m_extendedTypes = new ExtendedType[m_initialSize];
  115. for (int i = 0; i < DTM.NTYPES; i++) {
  116. m_extendedTypes[i] = m_defaultExtendedTypes[i];
  117. m_table[i] = new HashEntry(m_defaultExtendedTypes[i], i, i, null);
  118. }
  119. m_nextType = DTM.NTYPES;
  120. }
  121. /**
  122. * Given an expanded name represented by namespace, local name and node type,
  123. * return an ID. If the expanded-name does not exist in the internal tables,
  124. * the entry will be created, and the ID will be returned. Any additional
  125. * nodes that are created that have this expanded name will use this ID.
  126. *
  127. * @param namespace The namespace
  128. * @param localName The local name
  129. * @param type The node type
  130. *
  131. * @return the expanded-name id of the node.
  132. */
  133. public int getExpandedTypeID(String namespace, String localName, int type)
  134. {
  135. return getExpandedTypeID(namespace, localName, type, false);
  136. }
  137. /**
  138. * Given an expanded name represented by namespace, local name and node type,
  139. * return an ID. If the expanded-name does not exist in the internal tables,
  140. * the entry will be created, and the ID will be returned. Any additional
  141. * nodes that are created that have this expanded name will use this ID.
  142. * <p>
  143. * If searchOnly is true, we will return -1 if the name is not found in the
  144. * table, otherwise the name is added to the table and the expanded name id
  145. * of the new entry is returned.
  146. *
  147. * @param namespace The namespace
  148. * @param localName The local name
  149. * @param type The node type
  150. * @param searchOnly If it is true, we will only search for the expanded name.
  151. * -1 is return is the name is not found.
  152. *
  153. * @return the expanded-name id of the node.
  154. */
  155. public int getExpandedTypeID(String namespace, String localName, int type, boolean searchOnly)
  156. {
  157. if (null == namespace)
  158. namespace = "";
  159. if (null == localName)
  160. localName = "";
  161. // Calculate the hash code
  162. int hash = type + namespace.hashCode() + localName.hashCode();
  163. // Redefine the hashET object to represent the new expanded name.
  164. hashET.redefine(type, namespace, localName, hash);
  165. // Calculate the index into the HashEntry table.
  166. int index = hash % m_capacity;
  167. if (index < 0)
  168. index = -index;
  169. // Look up the expanded name in the hash table. Return the id if
  170. // the expanded name is already in the hash table.
  171. for (HashEntry e = m_table[index]; e != null; e = e.next)
  172. {
  173. if (e.hash == hash && e.key.equals(hashET))
  174. return e.value;
  175. }
  176. if (searchOnly)
  177. {
  178. return DTM.NULL;
  179. }
  180. // Expand the internal HashEntry array if necessary.
  181. if (m_nextType > m_threshold) {
  182. rehash();
  183. index = hash % m_capacity;
  184. if (index < 0)
  185. index = -index;
  186. }
  187. // Create a new ExtendedType object
  188. ExtendedType newET = new ExtendedType(type, namespace, localName, hash);
  189. // Expand the m_extendedTypes array if necessary.
  190. if (m_extendedTypes.length == m_nextType) {
  191. ExtendedType[] newArray = new ExtendedType[m_extendedTypes.length * 2];
  192. System.arraycopy(m_extendedTypes, 0, newArray, 0,
  193. m_extendedTypes.length);
  194. m_extendedTypes = newArray;
  195. }
  196. m_extendedTypes[m_nextType] = newET;
  197. // Create a new hash entry for the new ExtendedType and put it into
  198. // the table.
  199. HashEntry entry = new HashEntry(newET, m_nextType, hash, m_table[index]);
  200. m_table[index] = entry;
  201. return m_nextType++;
  202. }
  203. /**
  204. * Increases the capacity of and internally reorganizes the hashtable,
  205. * in order to accommodate and access its entries more efficiently.
  206. * This method is called when the number of keys in the hashtable exceeds
  207. * this hashtable's capacity and load factor.
  208. */
  209. private void rehash()
  210. {
  211. int oldCapacity = m_capacity;
  212. HashEntry[] oldTable = m_table;
  213. int newCapacity = 2 * oldCapacity + 1;
  214. m_capacity = newCapacity;
  215. m_threshold = (int)(newCapacity * m_loadFactor);
  216. m_table = new HashEntry[newCapacity];
  217. for (int i = oldCapacity-1; i >=0 ; i--)
  218. {
  219. for (HashEntry old = oldTable[i]; old != null; )
  220. {
  221. HashEntry e = old;
  222. old = old.next;
  223. int newIndex = e.hash % newCapacity;
  224. if (newIndex < 0)
  225. newIndex = -newIndex;
  226. e.next = m_table[newIndex];
  227. m_table[newIndex] = e;
  228. }
  229. }
  230. }
  231. /**
  232. * Given a type, return an expanded name ID.Any additional nodes that are
  233. * created that have this expanded name will use this ID.
  234. *
  235. * @param namespace
  236. * @param localName
  237. *
  238. * @return the expanded-name id of the node.
  239. */
  240. public int getExpandedTypeID(int type)
  241. {
  242. return type;
  243. }
  244. /**
  245. * Given an expanded-name ID, return the local name part.
  246. *
  247. * @param ExpandedNameID an ID that represents an expanded-name.
  248. * @return String Local name of this node, or null if the node has no name.
  249. */
  250. public String getLocalName(int ExpandedNameID)
  251. {
  252. return m_extendedTypes[ExpandedNameID].getLocalName();
  253. }
  254. /**
  255. * Given an expanded-name ID, return the local name ID.
  256. *
  257. * @param ExpandedNameID an ID that represents an expanded-name.
  258. * @return The id of this local name.
  259. */
  260. public final int getLocalNameID(int ExpandedNameID)
  261. {
  262. // ExtendedType etype = m_extendedTypes[ExpandedNameID];
  263. if (m_extendedTypes[ExpandedNameID].getLocalName().equals(""))
  264. return 0;
  265. else
  266. return ExpandedNameID;
  267. }
  268. /**
  269. * Given an expanded-name ID, return the namespace URI part.
  270. *
  271. * @param ExpandedNameID an ID that represents an expanded-name.
  272. * @return String URI value of this node's namespace, or null if no
  273. * namespace was resolved.
  274. */
  275. public String getNamespace(int ExpandedNameID)
  276. {
  277. String namespace = m_extendedTypes[ExpandedNameID].getNamespace();
  278. return (namespace.equals("") ? null : namespace);
  279. }
  280. /**
  281. * Given an expanded-name ID, return the namespace URI ID.
  282. *
  283. * @param ExpandedNameID an ID that represents an expanded-name.
  284. * @return The id of this namespace.
  285. */
  286. public final int getNamespaceID(int ExpandedNameID)
  287. {
  288. //ExtendedType etype = m_extendedTypes[ExpandedNameID];
  289. if (m_extendedTypes[ExpandedNameID].getNamespace().equals(""))
  290. return 0;
  291. else
  292. return ExpandedNameID;
  293. }
  294. /**
  295. * Given an expanded-name ID, return the local name ID.
  296. *
  297. * @param ExpandedNameID an ID that represents an expanded-name.
  298. * @return The id of this local name.
  299. */
  300. public final short getType(int ExpandedNameID)
  301. {
  302. //ExtendedType etype = m_extendedTypes[ExpandedNameID];
  303. return (short)m_extendedTypes[ExpandedNameID].getNodeType();
  304. }
  305. /**
  306. * Return the size of the ExpandedNameTable
  307. *
  308. * @return The size of the ExpandedNameTable
  309. */
  310. public int getSize()
  311. {
  312. return m_nextType;
  313. }
  314. /**
  315. * Return the array of extended types
  316. *
  317. * @return The array of extended types
  318. */
  319. public ExtendedType[] getExtendedTypes()
  320. {
  321. return m_extendedTypes;
  322. }
  323. /**
  324. * Inner class which represents a hash table entry.
  325. * The field next points to the next entry which is hashed into
  326. * the same bucket in the case of "hash collision".
  327. */
  328. private static final class HashEntry
  329. {
  330. ExtendedType key;
  331. int value;
  332. int hash;
  333. HashEntry next;
  334. protected HashEntry(ExtendedType key, int value, int hash, HashEntry next)
  335. {
  336. this.key = key;
  337. this.value = value;
  338. this.hash = hash;
  339. this.next = next;
  340. }
  341. }
  342. }