View Javadoc
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 }