#101103: Prevent document leak by not reusing DOM parsers. reset() is flawed aand there's no reliable way around it. Test included for the brave that would like the cache back.
1.1 --- a/openide.util/src/org/openide/xml/XMLUtil.java Mon Jun 25 19:12:18 2007 +0000
1.2 +++ b/openide.util/src/org/openide/xml/XMLUtil.java Mon Jul 02 15:01:07 2007 +0000
1.3 @@ -13,7 +13,7 @@
1.4 * "Portions Copyrighted [year] [name of copyright owner]"
1.5 *
1.6 * The Original Software is NetBeans. The Initial Developer of the Original
1.7 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
1.8 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
1.9 * Microsystems, Inc. All Rights Reserved.
1.10 */
1.11
1.12 @@ -262,17 +262,6 @@
1.13 }
1.14
1.15 /**
1.16 - * Cache of DocumentBuilder instances per thread.
1.17 - * They are relatively expensive to create, so don't do it more than necessary.
1.18 - */
1.19 - @SuppressWarnings("unchecked")
1.20 - private static final ThreadLocal<DocumentBuilder>[] builderTL = new ThreadLocal[4];
1.21 - static {
1.22 - for (int i = 0; i < 4; i++) {
1.23 - builderTL[i] = new ThreadLocal<DocumentBuilder>();
1.24 - }
1.25 - }
1.26 - /**
1.27 * Create from factory a DocumentBuilder and let it create a org.w3c.dom.Document.
1.28 * This method takes InputSource. After successful finish the document tree is returned.
1.29 *
1.30 @@ -293,19 +282,15 @@
1.31 EntityResolver entityResolver
1.32 ) throws IOException, SAXException {
1.33
1.34 - int index = (validate ? 0 : 1) + (namespaceAware ? 0 : 2);
1.35 - DocumentBuilder builder = builderTL[index].get();
1.36 - if (builder == null) {
1.37 - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
1.38 - factory.setValidating(validate);
1.39 - factory.setNamespaceAware(namespaceAware);
1.40 + DocumentBuilder builder = null;
1.41 + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
1.42 + factory.setValidating(validate);
1.43 + factory.setNamespaceAware(namespaceAware);
1.44
1.45 - try {
1.46 - builder = factory.newDocumentBuilder();
1.47 - } catch (ParserConfigurationException ex) {
1.48 - throw new SAXException("Cannot create parser satisfying configuration parameters", ex); //NOI18N
1.49 - }
1.50 - builderTL[index].set(builder);
1.51 + try {
1.52 + builder = factory.newDocumentBuilder();
1.53 + } catch (ParserConfigurationException ex) {
1.54 + throw new SAXException("Cannot create parser satisfying configuration parameters", ex); //NOI18N
1.55 }
1.56
1.57 if (errorHandler != null) {
1.58 @@ -657,18 +642,16 @@
1.59 * @see "#62006"
1.60 */
1.61 private static Document normalize(Document orig) throws IOException {
1.62 - DocumentBuilder builder = builderTL[0].get();
1.63 - if (builder == null) {
1.64 - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
1.65 - factory.setValidating(false);
1.66 - factory.setNamespaceAware(false);
1.67 - try {
1.68 - builder = factory.newDocumentBuilder();
1.69 - } catch (ParserConfigurationException e) {
1.70 - throw (IOException) new IOException("Cannot create parser satisfying configuration parameters: " + e).initCause(e); //NOI18N
1.71 - }
1.72 - builderTL[0].set(builder);
1.73 + DocumentBuilder builder = null;
1.74 + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
1.75 + factory.setValidating(false);
1.76 + factory.setNamespaceAware(false);
1.77 + try {
1.78 + builder = factory.newDocumentBuilder();
1.79 + } catch (ParserConfigurationException e) {
1.80 + throw (IOException) new IOException("Cannot create parser satisfying configuration parameters: " + e).initCause(e); //NOI18N
1.81 }
1.82 +
1.83 DocumentType doctype = null;
1.84 NodeList nl = orig.getChildNodes();
1.85 for (int i = 0; i < nl.getLength(); i++) {
2.1 --- a/openide.util/test/unit/src/org/openide/xml/XMLUtilTest.java Mon Jun 25 19:12:18 2007 +0000
2.2 +++ b/openide.util/test/unit/src/org/openide/xml/XMLUtilTest.java Mon Jul 02 15:01:07 2007 +0000
2.3 @@ -13,7 +13,7 @@
2.4 * "Portions Copyrighted [year] [name of copyright owner]"
2.5 *
2.6 * The Original Software is NetBeans. The Initial Developer of the Original
2.7 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
2.8 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
2.9 * Microsystems, Inc. All Rights Reserved.
2.10 */
2.11
2.12 @@ -24,6 +24,7 @@
2.13 import java.io.CharConversionException;
2.14 import java.io.IOException;
2.15 import java.io.StringReader;
2.16 +import java.lang.ref.WeakReference;
2.17 import java.net.URL;
2.18 import java.net.URLClassLoader;
2.19 import javax.xml.parsers.DocumentBuilderFactory;
2.20 @@ -347,4 +348,14 @@
2.21 String data2 = baos.toString().replaceAll("\r\n", "\n");
2.22 assertEquals("identity replacement should not mess up significant whitespace", data, data2);
2.23 }
2.24 +
2.25 + public void testDocumentLeak() throws Exception {
2.26 + String data = "<foo xmlns='bar'><baz/></foo>";
2.27 + Document doc = XMLUtil.parse(new InputSource(new StringReader(data)), false, true, null, null);
2.28 +
2.29 + WeakReference<Document> wr = new WeakReference<Document>(doc);
2.30 + doc = null;
2.31 +
2.32 + assertGC("Document should be freed", wr);
2.33 + }
2.34 }