# HG changeset patch # User joehw # Date 1452279094 28800 # Node ID cab976ee6f2113db83ad57c96785f3714142312c # Parent 80f67512daa15cf37b4825c1c62a675d524d7c49 8144967: javax.xml.transform.Source and org.xml.sax.InputSource can be empty Reviewed-by: darcy, rriggs diff -r 80f67512daa1 -r cab976ee6f21 jaxp/src/java.xml/share/classes/javax/xml/transform/Source.java --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/Source.java Wed Jul 05 21:12:04 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/Source.java Fri Jan 08 10:51:34 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,4 +52,17 @@ * if setSystemId was not called. */ public String getSystemId(); + + /** + * Indicates whether the {@code Source} object is empty. Empty means + * that there is no input available from this Source. + * + * @implSpec The default implementation of this method throws + * {@link UnsupportedOperationException}. + * + * @return true if the {@code Source} object is empty, false otherwise + */ + default boolean isEmpty() { + throw new UnsupportedOperationException("The isEmpty method is not supported."); + } } diff -r 80f67512daa1 -r cab976ee6f21 jaxp/src/java.xml/share/classes/javax/xml/transform/dom/DOMSource.java --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/dom/DOMSource.java Wed Jul 05 21:12:04 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/dom/DOMSource.java Fri Jan 08 10:51:34 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,6 +122,7 @@ * * @param systemID Base URL for this DOM tree. */ + @Override public void setSystemId(String systemID) { this.systemID = systemID; } @@ -132,7 +133,25 @@ * * @return Base URL for this DOM tree. */ + @Override public String getSystemId() { return this.systemID; } + + /** + * Indicates whether the {@code DOMSource} object is empty. Empty is + * defined as follows: + * + * + * @return true if the {@code DOMSource} object is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return systemID == null && (node == null || !node.hasChildNodes()); + } } diff -r 80f67512daa1 -r cab976ee6f21 jaxp/src/java.xml/share/classes/javax/xml/transform/sax/SAXSource.java --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/sax/SAXSource.java Wed Jul 05 21:12:04 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/sax/SAXSource.java Fri Jan 08 10:51:34 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -147,6 +147,7 @@ * * @param systemId The system identifier as a URI string. */ + @Override public void setSystemId(String systemId) { if (null == inputSource) { @@ -162,6 +163,7 @@ * * @return Base URL for the Source, or null. */ + @Override public String getSystemId() { if (inputSource == null) { @@ -207,4 +209,22 @@ return null; } } + + /** + * Indicates whether the {@code SAXSource} object is empty. Empty is + * defined as follows: + * + * + * @return true if the {@code SAXSource} object is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return getSystemId() == null && (inputSource == null || inputSource.isEmpty()); + } } diff -r 80f67512daa1 -r cab976ee6f21 jaxp/src/java.xml/share/classes/javax/xml/transform/stax/StAXSource.java --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/stax/StAXSource.java Wed Jul 05 21:12:04 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/stax/StAXSource.java Fri Jan 08 10:51:34 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -209,6 +209,7 @@ * @throws UnsupportedOperationException Is always * thrown by this method. */ + @Override public void setSystemId(final String systemId) { throw new UnsupportedOperationException( @@ -229,8 +230,21 @@ * * @return System identifier used by this StAXSource. */ + @Override public String getSystemId() { return systemId; } + + /** + * Indicates whether the {@code StAXSource} object is empty. Since a + * {@code StAXSource} object can never be empty, this method always returns + * false. + * + * @return unconditionally false + */ + @Override + public boolean isEmpty() { + return false; + } } diff -r 80f67512daa1 -r cab976ee6f21 jaxp/src/java.xml/share/classes/javax/xml/transform/stream/StreamSource.java --- a/jaxp/src/java.xml/share/classes/javax/xml/transform/stream/StreamSource.java Wed Jul 05 21:12:04 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/javax/xml/transform/stream/StreamSource.java Fri Jan 08 10:51:34 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,8 +26,10 @@ package javax.xml.transform.stream; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import javax.xml.transform.Result; import javax.xml.transform.Source; @@ -233,6 +235,7 @@ * * @param systemId The system identifier as a URL string. */ + @Override public void setSystemId(String systemId) { this.systemId = systemId; } @@ -243,6 +246,7 @@ * @return The system identifier that was set with setSystemId, or null * if setSystemId was not called. */ + @Override public String getSystemId() { return systemId; } @@ -259,6 +263,59 @@ this.systemId = f.toURI().toASCIIString(); } + /** + * Indicates whether the {@code StreamSource} object is empty. Empty is + * defined as follows: + * + *

+ * In case of error while checking the byte or character stream, the method + * will return false to allow the XML processor to handle the error. + * + * @return true if the {@code StreamSource} object is empty, false otherwise + */ + @Override + public boolean isEmpty() { + return (publicId == null && systemId == null && isStreamEmpty()); + } + + private boolean isStreamEmpty() { + boolean empty = true; + try { + if (inputStream != null) { + inputStream.reset(); + int bytesRead = inputStream.available(); + if (bytesRead > 0) { + return false; + } + } + + if (reader != null) { + reader.reset(); + int c = reader.read(); + reader.reset(); + if (c != -1) { + return false; + } + } + } catch (IOException ex) { + //in case of error, return false + return false; + } + + return empty; + } + ////////////////////////////////////////////////////////////////////// // Internal state. ////////////////////////////////////////////////////////////////////// diff -r 80f67512daa1 -r cab976ee6f21 jaxp/src/java.xml/share/classes/org/xml/sax/InputSource.java --- a/jaxp/src/java.xml/share/classes/org/xml/sax/InputSource.java Wed Jul 05 21:12:04 2017 +0200 +++ b/jaxp/src/java.xml/share/classes/org/xml/sax/InputSource.java Fri Jan 08 10:51:34 2016 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,6 +30,7 @@ package org.xml.sax; +import java.io.IOException; import java.io.Reader; import java.io.InputStream; @@ -343,8 +344,57 @@ return characterStream; } + /** + * Indicates whether the {@code InputSource} object is empty. Empty is + * defined as follows: + *

+ *

+ * In case of error while checking the byte or character stream, the method + * will return false to allow the XML processor to handle the error. + * + * @return true if the {@code InputSource} object is empty, false otherwise + */ + public boolean isEmpty() { + return (publicId == null && systemId == null && isStreamEmpty()); + } + private boolean isStreamEmpty() { + boolean empty = true; + try { + if (byteStream != null) { + byteStream.reset(); + int bytesRead = byteStream.available(); + if (bytesRead > 0) { + return false; + } + } + if (characterStream != null) { + characterStream.reset(); + int c = characterStream.read(); + characterStream.reset(); + if (c != -1) { + return false; + } + } + } catch (IOException ex) { + //in case of error, return false + return false; + } + + return empty; + } //////////////////////////////////////////////////////////////////// // Internal state. //////////////////////////////////////////////////////////////////// diff -r 80f67512daa1 -r cab976ee6f21 jaxp/test/javax/xml/jaxp/unittest/common/Sources.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jaxp/test/javax/xml/jaxp/unittest/common/Sources.java Fri Jan 08 10:51:34 2016 -0800 @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package common; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.transform.Source; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stax.StAXSource; +import javax.xml.transform.stream.StreamSource; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; + +/* + * @bug 8144967 + * @summary Tests related to the javax.xml.transform.Source + * and org.xml.sax.InputSource + */ +public class Sources { + + /** + * @bug 8144967 + * Tests whether a Source object is empty + * @param source the Source object + */ + @Test(dataProvider = "emptySources") + public void testIsEmpty(Source source) { + Assert.assertTrue(source.isEmpty(), "The source is not empty"); + } + + /** + * @bug 8144967 + * Tests that the source is not empty + * @param source the Source object + */ + @Test(dataProvider = "nonEmptySources") + public void testIsNotEmpty(Source source) { + Assert.assertTrue(!source.isEmpty(), "The source is empty"); + } + + /** + * @bug 8144967 + * Tests whether an InputSource object is empty + * @param source the InputSource object + */ + @Test(dataProvider = "emptyInputSource") + public void testISIsEmpty(InputSource source) { + Assert.assertTrue(source.isEmpty(), "The source is not empty"); + } + + /* + * DataProvider: sources that are empty + */ + @DataProvider(name = "emptySources") + Object[][] getSources() throws URISyntaxException { + + return new Object[][]{ + {new DOMSource()}, + {new DOMSource(getDocument())}, + {new SAXSource()}, + {new SAXSource(new InputSource(new StringReader("")))}, + {new SAXSource(getXMLReader(), new InputSource(new StringReader("")))}, + {new StreamSource()}, + {new StreamSource(new ByteArrayInputStream("".getBytes()))}, + {new StreamSource(new StringReader(""))}, + {new StreamSource(new StringReader(""), null)}, + {new StreamSource((String) null)} + }; + } + + /* + * DataProvider: sources that are not empty + */ + @DataProvider(name = "nonEmptySources") + Object[][] getSourcesEx() throws URISyntaxException { + StAXSource ss = null; + try { + ss = new StAXSource(getXMLEventReader()); + } catch (XMLStreamException ex) {} + + return new Object[][]{ + //This will set a non-null systemId on the resulting StreamSource + {new StreamSource(new File(""))}, + //Can't tell because XMLStreamReader is a pull parser, cursor advancement + //would have been required in order to examine the reader. + {new StAXSource(getXMLStreamReader())}, + {ss} + }; + } + + /* + * DataProvider: sources that are empty + */ + @DataProvider(name = "emptyInputSource") + Object[][] getInputSources() throws URISyntaxException { + byte[] utf8Bytes = null; + try { + utf8Bytes = "".getBytes("UTF8"); + } catch (UnsupportedEncodingException ex) { + throw new RuntimeException(ex.getMessage()); + } + return new Object[][]{ + {new InputSource()}, + {new InputSource(new ByteArrayInputStream(utf8Bytes))}, + {new InputSource(new StringReader(""))}, + {new InputSource((String) null)} + }; + } + + /** + * Returns an instance of Document. + * + * @return an instance of Document. + */ + private Document getDocument() { + Document doc = null; + try { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + doc = dbf.newDocumentBuilder().newDocument(); + } catch (ParserConfigurationException ex) {} + return doc; + } + + /** + * Returns an instance of XMLReader. + * + * @return an instance of XMLReader. + */ + private XMLReader getXMLReader() { + XMLReader reader = null; + try { + reader = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); + } catch (ParserConfigurationException | SAXException ex) {} + return reader; + } + + /** + * Returns an instance of XMLStreamReader. + * + * @return an instance of XMLStreamReader. + */ + private XMLStreamReader getXMLStreamReader() { + XMLStreamReader r = null; + try { + XMLInputFactory xif = XMLInputFactory.newInstance(); + r = xif.createXMLStreamReader(new ByteArrayInputStream("".getBytes())); + } catch (XMLStreamException ex) {} + + return r; + } + + /** + * Returns an instance of XMLEventReader. + * + * @return an instance of XMLEventReader. + */ + private XMLEventReader getXMLEventReader() { + XMLEventReader r = null; + try { + r = XMLInputFactory.newInstance().createXMLEventReader( + new ByteArrayInputStream("".getBytes())); + } catch (XMLStreamException ex) {} + + return r; + } +}