001: /*
002: * Copyright 1999-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: /*
017: * $Id: XMLReaderManager.java,v 1.5 2005/04/26 06:04:29 minchau Exp $
018: */
019: package org.apache.xml.utils;
020:
021: import java.util.Hashtable;
022:
023: import javax.xml.parsers.FactoryConfigurationError;
024: import javax.xml.parsers.ParserConfigurationException;
025: import javax.xml.parsers.SAXParserFactory;
026:
027: import org.xml.sax.XMLReader;
028: import org.xml.sax.helpers.XMLReaderFactory;
029: import org.xml.sax.SAXException;
030:
031: /**
032: * Creates XMLReader objects and caches them for re-use.
033: * This class follows the singleton pattern.
034: */
035: public class XMLReaderManager {
036:
037: private static final String NAMESPACES_FEATURE = "http://xml.org/sax/features/namespaces";
038: private static final String NAMESPACE_PREFIXES_FEATURE = "http://xml.org/sax/features/namespace-prefixes";
039: private static final XMLReaderManager m_singletonManager = new XMLReaderManager();
040:
041: /**
042: * Parser factory to be used to construct XMLReader objects
043: */
044: private static SAXParserFactory m_parserFactory;
045:
046: /**
047: * Cache of XMLReader objects
048: */
049: private ThreadLocal m_readers;
050:
051: /**
052: * Keeps track of whether an XMLReader object is in use.
053: */
054: private Hashtable m_inUse;
055:
056: /**
057: * Hidden constructor
058: */
059: private XMLReaderManager() {
060: }
061:
062: /**
063: * Retrieves the singleton reader manager
064: */
065: public static XMLReaderManager getInstance() {
066: return m_singletonManager;
067: }
068:
069: /**
070: * Retrieves a cached XMLReader for this thread, or creates a new
071: * XMLReader, if the existing reader is in use. When the caller no
072: * longer needs the reader, it must release it with a call to
073: * {@link #releaseXMLReader}.
074: */
075: public synchronized XMLReader getXMLReader() throws SAXException {
076: XMLReader reader;
077: boolean readerInUse;
078:
079: if (m_readers == null) {
080: // When the m_readers.get() method is called for the first time
081: // on a thread, a new XMLReader will automatically be created.
082: m_readers = new ThreadLocal();
083: }
084:
085: if (m_inUse == null) {
086: m_inUse = new Hashtable();
087: }
088:
089: // If the cached reader for this thread is in use, construct a new
090: // one; otherwise, return the cached reader.
091: reader = (XMLReader) m_readers.get();
092: boolean threadHasReader = (reader != null);
093: if (!threadHasReader || m_inUse.get(reader) == Boolean.TRUE) {
094: try {
095: try {
096: // According to JAXP 1.2 specification, if a SAXSource
097: // is created using a SAX InputSource the Transformer or
098: // TransformerFactory creates a reader via the
099: // XMLReaderFactory if setXMLReader is not used
100: reader = XMLReaderFactory.createXMLReader();
101: } catch (Exception e) {
102: try {
103: // If unable to create an instance, let's try to use
104: // the XMLReader from JAXP
105: if (m_parserFactory == null) {
106: m_parserFactory = SAXParserFactory
107: .newInstance();
108: m_parserFactory.setNamespaceAware(true);
109: }
110:
111: reader = m_parserFactory.newSAXParser()
112: .getXMLReader();
113: } catch (ParserConfigurationException pce) {
114: throw pce; // pass along pce
115: }
116: }
117: try {
118: reader.setFeature(NAMESPACES_FEATURE, true);
119: reader
120: .setFeature(NAMESPACE_PREFIXES_FEATURE,
121: false);
122: } catch (SAXException se) {
123: // Try to carry on if we've got a parser that
124: // doesn't know about namespace prefixes.
125: }
126: } catch (ParserConfigurationException ex) {
127: throw new SAXException(ex);
128: } catch (FactoryConfigurationError ex1) {
129: throw new SAXException(ex1.toString());
130: } catch (NoSuchMethodError ex2) {
131: } catch (AbstractMethodError ame) {
132: }
133:
134: // Cache the XMLReader if this is the first time we've created
135: // a reader for this thread.
136: if (!threadHasReader) {
137: m_readers.set(reader);
138: m_inUse.put(reader, Boolean.TRUE);
139: }
140: } else {
141: m_inUse.put(reader, Boolean.TRUE);
142: }
143:
144: return reader;
145: }
146:
147: /**
148: * Mark the cached XMLReader as available. If the reader was not
149: * actually in the cache, do nothing.
150: *
151: * @param reader The XMLReader that's being released.
152: */
153: public synchronized void releaseXMLReader(XMLReader reader) {
154: // If the reader that's being released is the cached reader
155: // for this thread, remove it from the m_isUse list.
156: if (m_readers.get() == reader && reader != null) {
157: m_inUse.remove(reader);
158: }
159: }
160: }
|