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 }