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 }