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 com.sun.org.apache.xalan.internal.utils.XMLSecurityManager;
  29 import java.util.HashMap;
  30 
  31 import javax.xml.XMLConstants;
  32 import javax.xml.parsers.FactoryConfigurationError;
  33 import javax.xml.parsers.ParserConfigurationException;
  34 import javax.xml.parsers.SAXParserFactory;
  35 import org.xml.sax.SAXException;
  36 import org.xml.sax.SAXNotRecognizedException;
  37 import org.xml.sax.XMLReader;
  38 import org.xml.sax.helpers.XMLReaderFactory;
  39 
  40 /**
  41  * Creates XMLReader objects and caches them for re-use.
  42  * This class follows the singleton pattern.
  43  */
  44 public class XMLReaderManager {
  45 
  46     private static final String NAMESPACES_FEATURE =
  47                              "http://xml.org/sax/features/namespaces";
  48     private static final String NAMESPACE_PREFIXES_FEATURE =
  49                              "http://xml.org/sax/features/namespace-prefixes";
  50     private static final XMLReaderManager m_singletonManager =
  51                                                      new XMLReaderManager();
  52     private static final String property = "org.xml.sax.driver";
  53     /**
  54      * Parser factory to be used to construct XMLReader objects
  55      */
  56     private static SAXParserFactory m_parserFactory;
  57 
  58     /**
  59      * Cache of XMLReader objects
  60      */
  61     private ThreadLocal m_readers;
  62 
  63     /**
  64      * Keeps track of whether an XMLReader object is in use.
  65      */
  66     private HashMap m_inUse;
  67 
  68     private boolean m_useServicesMechanism = true;
  69 
  70     private boolean _secureProcessing;
  71      /**
  72      * protocols allowed for external DTD references in source file and/or stylesheet.
  73      */
  74     private String _accessExternalDTD = XalanConstants.EXTERNAL_ACCESS_DEFAULT;
  75 
  76     private XMLSecurityManager _xmlSecurityManager;
  77 
  78     /**
  79      * Hidden constructor
  80      */
  81     private XMLReaderManager() {
  82     }
  83 
  84     /**
  85      * Retrieves the singleton reader manager
  86      */
  87     public static XMLReaderManager getInstance(boolean useServicesMechanism) {
  88         m_singletonManager.setServicesMechnism(useServicesMechanism);
  89         return m_singletonManager;
  90     }
  91 
  92     /**
  93      * Retrieves a cached XMLReader for this thread, or creates a new
  94      * XMLReader, if the existing reader is in use.  When the caller no
  95      * longer needs the reader, it must release it with a call to
  96      * {@link #releaseXMLReader}.
  97      */
  98     public synchronized XMLReader getXMLReader() throws SAXException {
  99         XMLReader reader;
 100 
 101         if (m_readers == null) {
 102             // When the m_readers.get() method is called for the first time
 103             // on a thread, a new XMLReader will automatically be created.
 104             m_readers = new ThreadLocal();
 105         }
 106 
 107         if (m_inUse == null) {
 108             m_inUse = new HashMap();
 109         }
 110 
 111         // If the cached reader for this thread is in use, construct a new
 112         // one; otherwise, return the cached reader unless it isn't an
 113         // instance of the class set in the 'org.xml.sax.driver' property
 114         reader = (XMLReader) m_readers.get();
 115         boolean threadHasReader = (reader != null);
 116         String factory = SecuritySupport.getSystemProperty(property);
 117         if (threadHasReader && m_inUse.get(reader) != Boolean.TRUE &&
 118                 ( factory == null || reader.getClass().getName().equals(factory))) {
 119             m_inUse.put(reader, Boolean.TRUE);
 120         } else {
 121             try {
 122                 try {
 123                     // According to JAXP 1.2 specification, if a SAXSource
 124                     // is created using a SAX InputSource the Transformer or
 125                     // TransformerFactory creates a reader via the
 126                     // XMLReaderFactory if setXMLReader is not used
 127                     reader = XMLReaderFactory.createXMLReader();
 128                     try {
 129                         reader.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, _secureProcessing);
 130                     } catch (SAXNotRecognizedException e) {
 131                         System.err.println("Warning:  " + reader.getClass().getName() + ": "
 132                                 + e.getMessage());
 133                     }
 134                 } catch (Exception e) {
 135                    try {
 136                         // If unable to create an instance, let's try to use
 137                         // the XMLReader from JAXP
 138                         if (m_parserFactory == null) {
 139                             m_parserFactory = FactoryImpl.getSAXFactory(m_useServicesMechanism);
 140                             m_parserFactory.setNamespaceAware(true);
 141                         }
 142 
 143                         reader = m_parserFactory.newSAXParser().getXMLReader();
 144                    } catch (ParserConfigurationException pce) {
 145                        throw pce;   // pass along pce
 146                    }
 147                 }
 148                 try {
 149                     reader.setFeature(NAMESPACES_FEATURE, true);
 150                     reader.setFeature(NAMESPACE_PREFIXES_FEATURE, false);
 151                 } catch (SAXException se) {
 152                     // Try to carry on if we've got a parser that
 153                     // doesn't know about namespace prefixes.
 154                 }
 155             } catch (ParserConfigurationException ex) {
 156                 throw new SAXException(ex);
 157             } catch (FactoryConfigurationError ex1) {
 158                 throw new SAXException(ex1.toString());
 159             } catch (NoSuchMethodError ex2) {
 160             } catch (AbstractMethodError ame) {
 161             }
 162 
 163             // Cache the XMLReader if this is the first time we've created
 164             // a reader for this thread.
 165             if (!threadHasReader) {
 166                 m_readers.set(reader);
 167                 m_inUse.put(reader, Boolean.TRUE);
 168             }
 169         }
 170 
 171         try {
 172             //reader is cached, but this property might have been reset
 173             reader.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, _accessExternalDTD);
 174         } catch (SAXException se) {
 175             System.err.println("Warning:  " + reader.getClass().getName() + ": "
 176                         + se.getMessage());
 177         }
 178 
 179         try {
 180             if (_xmlSecurityManager != null) {
 181                 for (XMLSecurityManager.Limit limit : XMLSecurityManager.Limit.values()) {
 182                     reader.setProperty(limit.apiProperty(),
 183                             _xmlSecurityManager.getLimitValueAsString(limit));
 184                 }
 185                 if (_xmlSecurityManager.printEntityCountInfo()) {
 186                     reader.setProperty(XalanConstants.JDK_ENTITY_COUNT_INFO, XalanConstants.JDK_YES);
 187                 }
 188             }
 189         } catch (SAXException se) {
 190             System.err.println("Warning:  " + reader.getClass().getName() + ": "
 191                         + se.getMessage());
 192         }
 193 
 194         return reader;
 195     }
 196 
 197     /**
 198      * Mark the cached XMLReader as available.  If the reader was not
 199      * actually in the cache, do nothing.
 200      *
 201      * @param reader The XMLReader that's being released.
 202      */
 203     public synchronized void releaseXMLReader(XMLReader reader) {
 204         // If the reader that's being released is the cached reader
 205         // for this thread, remove it from the m_isUse list.
 206         if (m_readers.get() == reader && reader != null) {
 207             m_inUse.remove(reader);
 208         }
 209     }
 210     /**
 211      * Return the state of the services mechanism feature.
 212      */
 213     public boolean useServicesMechnism() {
 214         return m_useServicesMechanism;
 215     }
 216 
 217     /**
 218      * Set the state of the services mechanism feature.
 219      */
 220     public void setServicesMechnism(boolean flag) {
 221         m_useServicesMechanism = flag;
 222     }
 223 
 224     /**
 225      * Set feature
 226      */
 227     public void setFeature(String name, boolean value) {
 228         if (name.equals(XMLConstants.FEATURE_SECURE_PROCESSING)) {
 229             _secureProcessing = value;
 230         }
 231     }
 232 
 233     /**
 234      * Get property value
 235      */
 236     public Object getProperty(String name) {
 237         if (name.equals(XMLConstants.ACCESS_EXTERNAL_DTD)) {
 238             return _accessExternalDTD;
 239         } else if (name.equals(XalanConstants.SECURITY_MANAGER)) {
 240             return _xmlSecurityManager;
 241         }
 242         return null;
 243     }
 244 
 245     /**
 246      * Set property.
 247      */
 248     public void setProperty(String name, Object value) {
 249         if (name.equals(XMLConstants.ACCESS_EXTERNAL_DTD)) {
 250             _accessExternalDTD = (String)value;
 251         } else if (name.equals(XalanConstants.SECURITY_MANAGER)) {
 252             _xmlSecurityManager = (XMLSecurityManager)value;
 253         }
 254     }
 255 }