1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 1999-2004 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *     http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 /*
  21  * $Id: XMLReaderManager.java,v 1.2.4.1 2005/09/15 08:16:02 suresh_emailid Exp $
  22  */
  23 package com.sun.org.apache.xml.internal.utils;
  24 
  25 import com.sun.org.apache.xalan.internal.XalanConstants;
  26 import com.sun.org.apache.xalan.internal.utils.FactoryImpl;
  27 import com.sun.org.apache.xalan.internal.utils.SecuritySupport;
  28 import java.util.HashMap;
  29 import javax.xml.XMLConstants;
  30 import javax.xml.parsers.FactoryConfigurationError;
  31 import javax.xml.parsers.ParserConfigurationException;
  32 import javax.xml.parsers.SAXParserFactory;
  33 import org.xml.sax.SAXException;
  34 import org.xml.sax.XMLReader;
  35 import org.xml.sax.helpers.XMLReaderFactory;
  36 
  37 /**
  38  * Creates XMLReader objects and caches them for re-use.
  39  * This class follows the singleton pattern.
  40  */
  41 public class XMLReaderManager {
  42 
  43     private static final String NAMESPACES_FEATURE =
  44                              "http://xml.org/sax/features/namespaces";
  45     private static final String NAMESPACE_PREFIXES_FEATURE =
  46                              "http://xml.org/sax/features/namespace-prefixes";
  47     private static final XMLReaderManager m_singletonManager =
  48                                                      new XMLReaderManager();
  49     private static final String property = "org.xml.sax.driver";
  50     /**
  51      * Parser factory to be used to construct XMLReader objects
  52      */
  53     private static SAXParserFactory m_parserFactory;
  54 
  55     /**
  56      * Cache of XMLReader objects
  57      */
  58     private ThreadLocal m_readers;
  59 
  60     /**
  61      * Keeps track of whether an XMLReader object is in use.
  62      */
  63     private HashMap m_inUse;
  64 
  65     private boolean m_useServicesMechanism = true;
  66      /**
  67      * protocols allowed for external DTD references in source file and/or stylesheet.
  68      */
  69     private String _accessExternalDTD = XalanConstants.EXTERNAL_ACCESS_DEFAULT;
  70 
  71     /**
  72      * Hidden constructor
  73      */
  74     private XMLReaderManager() {
  75     }
  76 
  77     /**
  78      * Retrieves the singleton reader manager
  79      */
  80     public static XMLReaderManager getInstance(boolean useServicesMechanism) {
  81         m_singletonManager.setServicesMechnism(useServicesMechanism);
  82         return m_singletonManager;
  83     }
  84 
  85     /**
  86      * Retrieves a cached XMLReader for this thread, or creates a new
  87      * XMLReader, if the existing reader is in use.  When the caller no
  88      * longer needs the reader, it must release it with a call to
  89      * {@link #releaseXMLReader}.
  90      */
  91     public synchronized XMLReader getXMLReader() throws SAXException {
  92         XMLReader reader;
  93 
  94         if (m_readers == null) {
  95             // When the m_readers.get() method is called for the first time
  96             // on a thread, a new XMLReader will automatically be created.
  97             m_readers = new ThreadLocal();
  98         }
  99 
 100         if (m_inUse == null) {
 101             m_inUse = new HashMap();
 102         }
 103 
 104         // If the cached reader for this thread is in use, construct a new
 105         // one; otherwise, return the cached reader unless it isn't an
 106         // instance of the class set in the 'org.xml.sax.driver' property
 107         reader = (XMLReader) m_readers.get();
 108         boolean threadHasReader = (reader != null);
 109         String factory = SecuritySupport.getSystemProperty(property);
 110         if (threadHasReader && m_inUse.get(reader) != Boolean.TRUE &&
 111                 ( factory == null || reader.getClass().getName().equals(factory))) {
 112             m_inUse.put(reader, Boolean.TRUE);
 113         } else {
 114             try {
 115                 try {
 116                     // According to JAXP 1.2 specification, if a SAXSource
 117                     // is created using a SAX InputSource the Transformer or
 118                     // TransformerFactory creates a reader via the
 119                     // XMLReaderFactory if setXMLReader is not used
 120                     reader = XMLReaderFactory.createXMLReader();
 121 
 122                 } catch (Exception e) {
 123                    try {
 124                         // If unable to create an instance, let's try to use
 125                         // the XMLReader from JAXP
 126                         if (m_parserFactory == null) {
 127                             m_parserFactory = FactoryImpl.getSAXFactory(m_useServicesMechanism);
 128                             m_parserFactory.setNamespaceAware(true);
 129                         }
 130 
 131                         reader = m_parserFactory.newSAXParser().getXMLReader();
 132                    } catch (ParserConfigurationException pce) {
 133                        throw pce;   // pass along pce
 134                    }
 135                 }
 136                 try {
 137                     reader.setFeature(NAMESPACES_FEATURE, true);
 138                     reader.setFeature(NAMESPACE_PREFIXES_FEATURE, false);
 139                     reader.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, _accessExternalDTD);
 140                 } catch (SAXException se) {
 141                     // Try to carry on if we've got a parser that
 142                     // doesn't know about namespace prefixes.
 143                 }
 144             } catch (ParserConfigurationException ex) {
 145                 throw new SAXException(ex);
 146             } catch (FactoryConfigurationError ex1) {
 147                 throw new SAXException(ex1.toString());
 148             } catch (NoSuchMethodError ex2) {
 149             } catch (AbstractMethodError ame) {
 150             }
 151 
 152             // Cache the XMLReader if this is the first time we've created
 153             // a reader for this thread.
 154             if (!threadHasReader) {
 155                 m_readers.set(reader);
 156                 m_inUse.put(reader, Boolean.TRUE);
 157             }
 158         }
 159 
 160         return reader;
 161     }
 162 
 163     /**
 164      * Mark the cached XMLReader as available.  If the reader was not
 165      * actually in the cache, do nothing.
 166      *
 167      * @param reader The XMLReader that's being released.
 168      */
 169     public synchronized void releaseXMLReader(XMLReader reader) {
 170         // If the reader that's being released is the cached reader
 171         // for this thread, remove it from the m_isUse list.
 172         if (m_readers.get() == reader && reader != null) {
 173             m_inUse.remove(reader);
 174         }
 175     }
 176     /**
 177      * Return the state of the services mechanism feature.
 178      */
 179     public boolean useServicesMechnism() {
 180         return m_useServicesMechanism;
 181     }
 182 
 183     /**
 184      * Set the state of the services mechanism feature.
 185      */
 186     public void setServicesMechnism(boolean flag) {
 187         m_useServicesMechanism = flag;
 188     }
 189 
 190     /**
 191      * Get property value
 192      */
 193     public String getProperty(String name) {
 194         if (name.equals(XMLConstants.ACCESS_EXTERNAL_DTD)) {
 195             return _accessExternalDTD;
 196         }
 197         return null;
 198     }
 199 
 200     /**
 201      * Set property.
 202      */
 203     public void setProperty(String name, String value) {
 204         if (name.equals(XMLConstants.ACCESS_EXTERNAL_DTD)) {
 205             _accessExternalDTD = (String)value;
 206         }
 207     }
 208 }