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: XMLReaderManager.java,v 1.2 2004/02/17 04:21:14 minchau Exp $
  18. */
  19. package com.sun.org.apache.xml.internal.utils;
  20. import java.util.Hashtable;
  21. import javax.xml.parsers.FactoryConfigurationError;
  22. import javax.xml.parsers.ParserConfigurationException;
  23. import javax.xml.parsers.SAXParserFactory;
  24. import org.xml.sax.XMLReader;
  25. import org.xml.sax.helpers.XMLReaderFactory;
  26. import org.xml.sax.SAXException;
  27. /**
  28. * Creates XMLReader objects and caches them for re-use.
  29. * This class follows the singleton pattern.
  30. */
  31. public class XMLReaderManager {
  32. private static final String NAMESPACES_FEATURE =
  33. "http://xml.org/sax/features/namespaces";
  34. private static final String NAMESPACE_PREFIXES_FEATURE =
  35. "http://xml.org/sax/features/namespace-prefixes";
  36. private static final XMLReaderManager m_singletonManager =
  37. new XMLReaderManager();
  38. /**
  39. * Parser factory to be used to construct XMLReader objects
  40. */
  41. private static SAXParserFactory m_parserFactory;
  42. /**
  43. * Cache of XMLReader objects
  44. */
  45. private ThreadLocal m_readers;
  46. /**
  47. * Keeps track of whether an XMLReader object is in use.
  48. */
  49. private Hashtable m_inUse;
  50. /**
  51. * Hidden constructor
  52. */
  53. private XMLReaderManager() {
  54. }
  55. /**
  56. * Retrieves the singleton reader manager
  57. */
  58. public static XMLReaderManager getInstance() {
  59. return m_singletonManager;
  60. }
  61. /**
  62. * Retrieves a cached XMLReader for this thread, or creates a new
  63. * XMLReader, if the existing reader is in use. When the caller no
  64. * longer needs the reader, it must release it with a call to
  65. * {@link releaseXMLReader}.
  66. */
  67. public synchronized XMLReader getXMLReader() throws SAXException {
  68. XMLReader reader;
  69. boolean readerInUse;
  70. if (m_readers == null) {
  71. // When the m_readers.get() method is called for the first time
  72. // on a thread, a new XMLReader will automatically be created.
  73. m_readers = new ThreadLocal();
  74. }
  75. if (m_inUse == null) {
  76. m_inUse = new Hashtable();
  77. }
  78. // If the cached reader for this thread is in use, construct a new
  79. // one; otherwise, return the cached reader.
  80. reader = (XMLReader) m_readers.get();
  81. boolean threadHasReader = (reader != null);
  82. if (!threadHasReader || m_inUse.get(reader) == Boolean.TRUE) {
  83. try {
  84. try {
  85. // According to JAXP 1.2 specification, if a SAXSource
  86. // is created using a SAX InputSource the Transformer or
  87. // TransformerFactory creates a reader via the
  88. // XMLReaderFactory if setXMLReader is not used
  89. reader = XMLReaderFactory.createXMLReader();
  90. } catch (Exception e) {
  91. try {
  92. // If unable to create an instance, let's try to use
  93. // the XMLReader from JAXP
  94. if (m_parserFactory == null) {
  95. m_parserFactory = SAXParserFactory.newInstance();
  96. m_parserFactory.setNamespaceAware(true);
  97. }
  98. reader = m_parserFactory.newSAXParser().getXMLReader();
  99. } catch (ParserConfigurationException pce) {
  100. throw pce; // pass along pce
  101. }
  102. }
  103. try {
  104. reader.setFeature(NAMESPACES_FEATURE, true);
  105. reader.setFeature(NAMESPACE_PREFIXES_FEATURE, false);
  106. } catch (SAXException se) {
  107. // Try to carry on if we've got a parser that
  108. // doesn't know about namespace prefixes.
  109. }
  110. } catch (ParserConfigurationException ex) {
  111. throw new SAXException(ex);
  112. } catch (FactoryConfigurationError ex1) {
  113. throw new SAXException(ex1.toString());
  114. } catch (NoSuchMethodError ex2) {
  115. } catch (AbstractMethodError ame) {
  116. }
  117. // Cache the XMLReader if this is the first time we've created
  118. // a reader for this thread.
  119. if (!threadHasReader) {
  120. m_readers.set(reader);
  121. m_inUse.put(reader, Boolean.TRUE);
  122. }
  123. } else {
  124. m_inUse.put(reader, Boolean.TRUE);
  125. }
  126. return reader;
  127. }
  128. /**
  129. * Mark the cached XMLReader as available. If the reader was not
  130. * actually in the cache, do nothing.
  131. *
  132. * @param reader The XMLReader that's being released.
  133. */
  134. public synchronized void releaseXMLReader(XMLReader reader) {
  135. // If the reader that's being released is the cached reader
  136. // for this thread, mark it as no longer being in use.
  137. if (m_readers.get() == reader) {
  138. m_inUse.put(reader, Boolean.FALSE);
  139. }
  140. }
  141. }