diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java index 27fab8c0348..62c786b03ae 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -54,7 +54,7 @@ import org.w3c.dom.Document; * @author Morten Jorgensen * @author G. Todd Miller * @author John Howard, JohnH@schemasoft.com - * @LastModified: Oct 2017 + * @LastModified: Aug 2019 */ public abstract class AbstractTranslet implements Translet { @@ -558,8 +558,8 @@ public abstract class AbstractTranslet implements Translet { throws TransletException { try { - final TransletOutputHandlerFactory factory - = TransletOutputHandlerFactory.newInstance(_overrideDefaultParser); + final TransletOutputHandlerFactory factory = TransletOutputHandlerFactory + .newInstance(_overrideDefaultParser, _msgHandler.getErrorListener()); String dirStr = new File(filename).getParent(); if ((null != dirStr) && (dirStr.length() > 0)) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/MessageHandler.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/MessageHandler.java index f7b47713a6c..f6faf2a625c 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/MessageHandler.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/MessageHandler.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -21,11 +20,18 @@ package com.sun.org.apache.xalan.internal.xsltc.runtime; +import javax.xml.transform.ErrorListener; + /** * @author Morten Jorgensen + * @LastModified: Aug 2019 */ public class MessageHandler { public void displayMessage(String msg) { System.err.println(msg); } + + public ErrorListener getErrorListener() { + return null; + } } diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/TransletOutputHandlerFactory.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/TransletOutputHandlerFactory.java index 0973fccb42c..c50f6bd6160 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/TransletOutputHandlerFactory.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/TransletOutputHandlerFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -41,6 +41,7 @@ import com.sun.org.apache.xml.internal.serializer.ToUnknownStream; import com.sun.org.apache.xml.internal.serializer.ToXMLSAXHandler; import com.sun.org.apache.xml.internal.serializer.ToXMLStream; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; +import javax.xml.transform.ErrorListener; import org.w3c.dom.Node; import org.xml.sax.ContentHandler; @@ -48,7 +49,7 @@ import org.xml.sax.ext.LexicalHandler; /** * @author Santiago Pericas-Geertsen - * @LastModified: Oct 2017 + * @LastModified: Aug 2019 */ public class TransletOutputHandlerFactory { @@ -71,16 +72,17 @@ public class TransletOutputHandlerFactory { private LexicalHandler _lexHandler = null; private boolean _overrideDefaultParser; + private ErrorListener _errListener; - static public TransletOutputHandlerFactory newInstance() { - return new TransletOutputHandlerFactory(true); - } - static public TransletOutputHandlerFactory newInstance(boolean overrideDefaultParser) { - return new TransletOutputHandlerFactory(overrideDefaultParser); + static public TransletOutputHandlerFactory newInstance(boolean overrideDefaultParser, + ErrorListener errListener) { + return new TransletOutputHandlerFactory(overrideDefaultParser, errListener); } - public TransletOutputHandlerFactory(boolean overrideDefaultParser) { + public TransletOutputHandlerFactory(boolean overrideDefaultParser, + ErrorListener errListener) { _overrideDefaultParser = overrideDefaultParser; + _errListener = errListener; } public void setOutputType(int outputType) { _outputType = outputType; @@ -156,24 +158,24 @@ public class TransletOutputHandlerFactory { if (_method == null) { - result = new ToUnknownStream(); + result = new ToUnknownStream(_errListener); } else if (_method.equalsIgnoreCase("xml")) { - result = new ToXMLStream(); + result = new ToXMLStream(_errListener); } else if (_method.equalsIgnoreCase("html")) { - result = new ToHTMLStream(); + result = new ToHTMLStream(_errListener); } else if (_method.equalsIgnoreCase("text")) { - result = new ToTextStream(); + result = new ToTextStream(_errListener); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java index cdbaa285a63..cc3bfcb5212 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java @@ -74,6 +74,7 @@ import javax.xml.transform.stream.StreamSource; import jdk.xml.internal.JdkXmlFeatures; import jdk.xml.internal.JdkXmlUtils; import jdk.xml.internal.SecuritySupport; +import jdk.xml.internal.TransformErrorListener; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLFilter; @@ -84,10 +85,10 @@ import org.xml.sax.XMLReader; * @author G. Todd Miller * @author Morten Jorgensen * @author Santiago Pericas-Geertsen - * @LastModified: July 2019 + * @LastModified: Aug 2019 */ public class TransformerFactoryImpl - extends SAXTransformerFactory implements SourceLoader, ErrorListener + extends SAXTransformerFactory implements SourceLoader { // Public constants for attributes supported by the XSLTC TransformerFactory. public final static String TRANSLET_NAME = "translet-name"; @@ -101,11 +102,16 @@ public class TransformerFactoryImpl public final static String ENABLE_INLINING = "enable-inlining"; public final static String INDENT_NUMBER = "indent-number"; + /** + * Default error listener + */ + private final ErrorListener _defaultListener = new TransformErrorListener(); + /** * This error listener is used only for this factory and is not passed to * the Templates or Transformer objects that we create. */ - private ErrorListener _errorListener = this; + private ErrorListener _errorListener = _defaultListener; // flag indicating whether there's an user's ErrorListener private boolean _hasUserErrListener; @@ -1222,90 +1228,6 @@ public class TransformerFactoryImpl } } - /** - * Receive notification of a recoverable error. - * The transformer must continue to provide normal parsing events after - * invoking this method. It should still be possible for the application - * to process the document through to the end. - * - * @param e The warning information encapsulated in a transformer - * exception. - * @throws TransformerException if the application chooses to discontinue - * the transformation (always does in our case). - */ - @Override - public void error(TransformerException e) - throws TransformerException - { - Throwable wrapped = e.getException(); - if (wrapped != null) { - System.err.println(new ErrorMsg(ErrorMsg.ERROR_PLUS_WRAPPED_MSG, - e.getMessageAndLocation(), - wrapped.getMessage())); - } else { - System.err.println(new ErrorMsg(ErrorMsg.ERROR_MSG, - e.getMessageAndLocation())); - } - throw e; - } - - /** - * Receive notification of a non-recoverable error. - * The application must assume that the transformation cannot continue - * after the Transformer has invoked this method, and should continue - * (if at all) only to collect addition error messages. In fact, - * Transformers are free to stop reporting events once this method has - * been invoked. - * - * @param e warning information encapsulated in a transformer - * exception. - * @throws TransformerException if the application chooses to discontinue - * the transformation (always does in our case). - */ - @Override - public void fatalError(TransformerException e) - throws TransformerException - { - Throwable wrapped = e.getException(); - if (wrapped != null) { - System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_PLUS_WRAPPED_MSG, - e.getMessageAndLocation(), - wrapped.getMessage())); - } else { - System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_MSG, - e.getMessageAndLocation())); - } - throw e; - } - - /** - * Receive notification of a warning. - * Transformers can use this method to report conditions that are not - * errors or fatal errors. The default behaviour is to take no action. - * After invoking this method, the Transformer must continue with the - * transformation. It should still be possible for the application to - * process the document through to the end. - * - * @param e The warning information encapsulated in a transformer - * exception. - * @throws TransformerException if the application chooses to discontinue - * the transformation (never does in our case). - */ - @Override - public void warning(TransformerException e) - throws TransformerException - { - Throwable wrapped = e.getException(); - if (wrapped != null) { - System.err.println(new ErrorMsg(ErrorMsg.WARNING_PLUS_WRAPPED_MSG, - e.getMessageAndLocation(), - wrapped.getMessage())); - } else { - System.err.println(new ErrorMsg(ErrorMsg.WARNING_MSG, - e.getMessageAndLocation())); - } - } - /** * This method implements XSLTC's SourceLoader interface. It is used to * glue a TrAX URIResolver to the XSLTC compiler's Input and Import classes. diff --git a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java index c23477f3040..ce092f0e9f2 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerImpl.java @@ -83,6 +83,7 @@ import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import jdk.xml.internal.JdkXmlFeatures; import jdk.xml.internal.JdkXmlUtils; +import jdk.xml.internal.TransformErrorListener; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -93,10 +94,10 @@ import org.xml.sax.ext.LexicalHandler; * @author Morten Jorgensen * @author G. Todd Miller * @author Santiago Pericas-Geertsen - * @LastModified: Feb 2019 + * @LastModified: Aug 2019 */ public final class TransformerImpl extends Transformer - implements DOMCache, ErrorListener + implements DOMCache { private final static String LEXICAL_HANDLER_PROPERTY = @@ -128,10 +129,15 @@ public final class TransformerImpl extends Transformer */ private String _sourceSystemId = null; + /** + * Default error listener + */ + private final ErrorListener _defaultListener = new TransformErrorListener(); + /** * An error listener for runtime errors. */ - private ErrorListener _errorListener = this; + private ErrorListener _errorListener = _defaultListener; /** * A reference to a URI resolver for calls to document(). @@ -250,6 +256,10 @@ public final class TransformerImpl extends Transformer } } } + + public ErrorListener getErrorListener() { + return _errorListener; + } } protected TransformerImpl(Properties outputProperties, int indentNumber, @@ -264,6 +274,9 @@ public final class TransformerImpl extends Transformer int indentNumber, TransformerFactoryImpl tfactory) { _translet = (AbstractTranslet) translet; + if (_translet != null) { + _translet.setMessageHandler(new MessageHandler(_errorListener)); + } _properties = createOutputProperties(outputProperties); _propertiesClone = (Properties) _properties.clone(); _indentNumber = indentNumber; @@ -400,7 +413,8 @@ public final class TransformerImpl extends Transformer // Get encoding using getProperty() to use defaults _encoding = _properties.getProperty(OutputKeys.ENCODING); - _tohFactory = TransletOutputHandlerFactory.newInstance(_overrideDefaultParser); + _tohFactory = TransletOutputHandlerFactory + .newInstance(_overrideDefaultParser, _errorListener); _tohFactory.setEncoding(_encoding); if (_method != null) { _tohFactory.setOutputMethod(_method); @@ -829,8 +843,8 @@ public final class TransformerImpl extends Transformer _errorListener = listener; // Register a message handler to report xsl:messages - if (_translet != null) - _translet.setMessageHandler(new MessageHandler(_errorListener)); + if (_translet != null) + _translet.setMessageHandler(new MessageHandler(_errorListener)); } /** @@ -1352,90 +1366,6 @@ public final class TransformerImpl extends Transformer } } - /** - * Receive notification of a recoverable error. - * The transformer must continue to provide normal parsing events after - * invoking this method. It should still be possible for the application - * to process the document through to the end. - * - * @param e The warning information encapsulated in a transformer - * exception. - * @throws TransformerException if the application chooses to discontinue - * the transformation (always does in our case). - */ - @Override - public void error(TransformerException e) - throws TransformerException - { - Throwable wrapped = e.getException(); - if (wrapped != null) { - System.err.println(new ErrorMsg(ErrorMsg.ERROR_PLUS_WRAPPED_MSG, - e.getMessageAndLocation(), - wrapped.getMessage())); - } else { - System.err.println(new ErrorMsg(ErrorMsg.ERROR_MSG, - e.getMessageAndLocation())); - } - throw e; - } - - /** - * Receive notification of a non-recoverable error. - * The application must assume that the transformation cannot continue - * after the Transformer has invoked this method, and should continue - * (if at all) only to collect addition error messages. In fact, - * Transformers are free to stop reporting events once this method has - * been invoked. - * - * @param e The warning information encapsulated in a transformer - * exception. - * @throws TransformerException if the application chooses to discontinue - * the transformation (always does in our case). - */ - @Override - public void fatalError(TransformerException e) - throws TransformerException - { - Throwable wrapped = e.getException(); - if (wrapped != null) { - System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_PLUS_WRAPPED_MSG, - e.getMessageAndLocation(), - wrapped.getMessage())); - } else { - System.err.println(new ErrorMsg(ErrorMsg.FATAL_ERR_MSG, - e.getMessageAndLocation())); - } - throw e; - } - - /** - * Receive notification of a warning. - * Transformers can use this method to report conditions that are not - * errors or fatal errors. The default behaviour is to take no action. - * After invoking this method, the Transformer must continue with the - * transformation. It should still be possible for the application to - * process the document through to the end. - * - * @param e The warning information encapsulated in a transformer - * exception. - * @throws TransformerException if the application chooses to discontinue - * the transformation (never does in our case). - */ - @Override - public void warning(TransformerException e) - throws TransformerException - { - Throwable wrapped = e.getException(); - if (wrapped != null) { - System.err.println(new ErrorMsg(ErrorMsg.WARNING_PLUS_WRAPPED_MSG, - e.getMessageAndLocation(), - wrapped.getMessage())); - } else { - System.err.println(new ErrorMsg(ErrorMsg.WARNING_MSG, - e.getMessageAndLocation())); - } - } - /** * This method resets the Transformer to its original configuration * Transformer code is reset to the same state it was when it was @@ -1448,7 +1378,7 @@ public final class TransformerImpl extends Transformer _method = null; _encoding = null; _sourceSystemId = null; - _errorListener = this; + _errorListener = _defaultListener; _uriResolver = null; _dom = null; _parameters = null; diff --git a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java index c3ee8d40b9a..ea6ed48a23f 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/SerializerBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -25,7 +25,7 @@ import com.sun.org.apache.xml.internal.serializer.utils.Utils; import java.io.IOException; import java.util.HashMap; import java.util.Set; -import java.util.ArrayList; +import javax.xml.transform.ErrorListener; import javax.xml.transform.OutputKeys; import javax.xml.transform.SourceLocator; import javax.xml.transform.Transformer; @@ -42,10 +42,12 @@ import org.xml.sax.ext.Locator2; * It contains a number of common fields and methods. * * @xsl.usage internal + * @LastModified: Aug 2019 */ public abstract class SerializerBase implements SerializationHandler, SerializerConstants { + protected ErrorListener m_errListener; /** * To fire off the end element trace event diff --git a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java index fd14160bce7..042d8bc686b 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToHTMLStream.java @@ -30,6 +30,7 @@ import org.xml.sax.SAXException; import com.sun.org.apache.xml.internal.serializer.utils.MsgKey; import com.sun.org.apache.xml.internal.serializer.utils.Utils; +import javax.xml.transform.ErrorListener; /** * This serializer takes a series of SAX or @@ -40,7 +41,7 @@ import com.sun.org.apache.xml.internal.serializer.utils.Utils; * because it is used from another package. * * @xsl.usage internal - * @LastModified: July 2019 + * @LastModified: Aug 2019 */ public final class ToHTMLStream extends ToStream { @@ -638,12 +639,15 @@ public final class ToHTMLStream extends ToStream */ public ToHTMLStream() { + this(null); + } - super(); + public ToHTMLStream(ErrorListener l) + { + super(l); m_charInfo = m_htmlcharInfo; // initialize namespaces m_prefixMap = new NamespaceMappings(); - } /** The name of the current element. */ diff --git a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java index e52138b4cbe..9b07cc5a4f7 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToStream.java @@ -51,7 +51,7 @@ import org.xml.sax.SAXException; * serializers (xml, html, text ...) that write output to a stream. * * @xsl.usage internal - * @LastModified: July 2019 + * @LastModified: Aug 2019 */ abstract public class ToStream extends SerializerBase { @@ -198,7 +198,13 @@ abstract public class ToStream extends SerializerBase { /** * Default constructor */ - public ToStream() { } + public ToStream() { + this(null); + } + + public ToStream(ErrorListener l) { + m_errListener = l; + } /** * This helper method to writes out "]]>" when closing a CDATA section. @@ -422,45 +428,30 @@ abstract public class ToStream extends SerializerBase { // from what it was EncodingInfo encodingInfo = Encodings.getEncodingInfo(newEncoding); - if (newEncoding != null && encodingInfo.name == null) { - // We tried to get an EncodingInfo for Object for the given - // encoding, but it came back with an internall null name - // so the encoding is not supported by the JDK, issue a message. - final String msg = Utils.messages.createMessage( - MsgKey.ER_ENCODING_NOT_SUPPORTED,new Object[]{ newEncoding }); + if (encodingInfo.name == null) { + // We tried to get an EncodingInfo for Object for the given + // encoding, but it came back with an internall null name + // so the encoding is not supported by the JDK, issue a message. + final String msg = Utils.messages.createMessage( + MsgKey.ER_ENCODING_NOT_SUPPORTED,new Object[]{ newEncoding }); - final String msg2 = - "Warning: encoding \"" + newEncoding + "\" not supported, using " - + Encodings.DEFAULT_MIME_ENCODING; - try { - // Prepare to issue the warning message - final Transformer tran = super.getTransformer(); - if (tran != null) { - final ErrorListener errHandler = tran - .getErrorListener(); - // Issue the warning message - if (null != errHandler - && m_sourceLocator != null) { - errHandler - .warning(new TransformerException( - msg, m_sourceLocator)); - errHandler - .warning(new TransformerException( - msg2, m_sourceLocator)); - } else { - System.out.println(msg); - System.out.println(msg2); - } - } else { - System.out.println(msg); - System.out.println(msg2); + final String msg2 = + "Warning: encoding \"" + newEncoding + "\" not supported, using " + + Encodings.DEFAULT_MIME_ENCODING; + try { + // refer to JDK-8229005, should throw Exception instead of warning and + // then falling back to the default encoding. Keep it for now. + if (m_errListener != null) { + m_errListener.warning(new TransformerException(msg, m_sourceLocator)); + m_errListener.warning(new TransformerException(msg2, m_sourceLocator)); } } catch (Exception e) { } // We said we are using UTF-8, so use it newEncoding = Encodings.DEFAULT_MIME_ENCODING; - val = Encodings.DEFAULT_MIME_ENCODING; // to store the modified value into the properties a little later + // to store the modified value into the properties a little later + val = Encodings.DEFAULT_MIME_ENCODING; encodingInfo = Encodings.getEncodingInfo(newEncoding); } // The encoding was good, or was forced to UTF-8 above diff --git a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToTextStream.java b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToTextStream.java index a4910afeee4..afeac9f3d9a 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToTextStream.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToTextStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -24,6 +24,7 @@ import java.io.IOException; import com.sun.org.apache.xml.internal.serializer.utils.MsgKey; import com.sun.org.apache.xml.internal.serializer.utils.Utils; +import javax.xml.transform.ErrorListener; import org.xml.sax.Attributes; import org.xml.sax.SAXException; @@ -33,7 +34,7 @@ import org.xml.sax.SAXException; * This class converts SAX or SAX-like calls to a * serialized document for xsl:output method of "text". * @xsl.usage internal - * @LastModified: Sept 2018 + * @LastModified: Aug 2019 */ public final class ToTextStream extends ToStream { @@ -44,7 +45,12 @@ public final class ToTextStream extends ToStream */ public ToTextStream() { - super(); + this(null); + } + + public ToTextStream(ErrorListener l) + { + super(l); } diff --git a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToUnknownStream.java b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToUnknownStream.java index ffcfa2c21fe..8153ba084af 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToUnknownStream.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToUnknownStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -26,6 +26,7 @@ import java.io.Writer; import java.util.ArrayList; import java.util.List; import java.util.Properties; +import javax.xml.transform.ErrorListener; import javax.xml.transform.SourceLocator; import javax.xml.transform.Transformer; import org.w3c.dom.Node; @@ -48,7 +49,7 @@ import org.xml.sax.SAXException; * * This class is not a public API, it is public because it is used within Xalan. * @xsl.usage internal - * @LastModified: Oct 2017 + * @LastModified: Aug 2019 */ public final class ToUnknownStream extends SerializerBase { @@ -116,7 +117,11 @@ public final class ToUnknownStream extends SerializerBase * That may change later to an HTML Stream object. */ public ToUnknownStream() { - m_handler = new ToXMLStream(); + this(null); + } + + public ToUnknownStream(ErrorListener l) { + m_handler = new ToXMLStream(l); } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java index 106a8f7ddd9..9633b4ade2d 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/ToXMLStream.java @@ -40,7 +40,7 @@ import org.xml.sax.SAXException; * be viewed as internal or package private, this is not an API. * * @xsl.usage internal - * @LastModified: July 2019 + * @LastModified: Aug 2019 */ public final class ToXMLStream extends ToStream { @@ -64,12 +64,20 @@ public final class ToXMLStream extends ToStream */ public ToXMLStream() { + this(null); + } + + /** + * Default constructor. + */ + public ToXMLStream(ErrorListener l) + { + super(l); m_charInfo = m_xmlcharInfo; initCDATA(); // initialize namespaces m_prefixMap = new NamespaceMappings(); - } /** diff --git a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/LSSerializerImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/LSSerializerImpl.java index 897ef03ef7e..66f12cc18fa 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/LSSerializerImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xml/internal/serializer/dom3/LSSerializerImpl.java @@ -1,6 +1,5 @@ /* - * reserved comment block - * DO NOT REMOVE OR ALTER! + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one @@ -68,6 +67,7 @@ import org.w3c.dom.ls.LSSerializerFilter; * @version $Id: * * @xsl.usage internal + * @LastModified: Aug 2019 */ final public class LSSerializerImpl implements DOMConfiguration, LSSerializer { @@ -220,7 +220,7 @@ final public class LSSerializerImpl implements DOMConfiguration, LSSerializer { // Get a serializer that seriailizes according to the properties, // which in this case is to xml - fXMLSerializer = new ToXMLStream(); + fXMLSerializer = new ToXMLStream(null); fXMLSerializer.setOutputFormat(configProps); // Initialize Serializer diff --git a/src/java.xml/share/classes/javax/xml/transform/ErrorListener.java b/src/java.xml/share/classes/javax/xml/transform/ErrorListener.java index 5d8d82c3662..6d7020e55dd 100644 --- a/src/java.xml/share/classes/javax/xml/transform/ErrorListener.java +++ b/src/java.xml/share/classes/javax/xml/transform/ErrorListener.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2019, 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,29 +26,39 @@ package javax.xml.transform; /** - *

To provide customized error handling, implement this interface and - * use the setErrorListener method to register an instance of the - * implementation with the {@link javax.xml.transform.Transformer}. The - * Transformer then reports all errors and warnings through this - * interface.

+ * The listener interface used by a {@link TransformerFactory} or {@link Transformer} + * to notify callers of error messages that occur during a transformation process. + * An ErrorListener receives three levels of messages: warnings, errors and fatal + * errors as classified by their severity. Each of them is handled as described + * in their respective method. * - *

If an application does not register its own custom - * ErrorListener, the default ErrorListener - * is used which reports all warnings and errors to System.err - * and does not throw any Exceptions. - * Applications are strongly encouraged to register and use - * ErrorListeners that insure proper behavior for warnings and - * errors.

+ *

+ * An ErrorListener instance can be registered to a {@link TransformerFactory} + * or {@link Transformer} through + * the {@link TransformerFactory#setErrorListener(ErrorListener)} + * or {@link Transformer#setErrorListener(ErrorListener)} + * method to receive errors and warnings reported by the TransformerFactory + * or Transformer. * - *

For transformation errors, a Transformer must use this - * interface instead of throwing an Exception: it is up to the - * application to decide whether to throw an Exception for - * different types of errors and warnings. Note however that the - * Transformer is not required to continue with the transformation - * after a call to {@link #fatalError(TransformerException exception)}.

+ *

+ * When a listener is registered, the {@link TransformerFactory} or {@link Transformer} + * must use this interface to pass on all warnings and errors to the listener + * and let the application decide how to handle them. + * Note that the {@code TransformerFactory} or {@code Transformer} is not + * required to continue with the transformation after a call to + * {@link #fatalError(TransformerException exception)}. * - *

Transformers may use this mechanism to report XML parsing - * errors as well as transformation errors.

+ *

+ * If an application does not provide a listener, the {@link TransformerFactory} + * or {@link Transformer} shall create one on its own. The default {@code ErrorListener} + * may take no action for warnings and recoverable errors, and allow the + * transformation to continue. + * However, the {@code TransformerFactory} or {@code Transformer} may still throw + * {@code TransformerException} when it decides it can not continue processing. + * + * @apiNote It is recommended that applications register and use their own + * {@code ErrorListener} to override the default behavior in order to ensure + * proper handling of warnings and errors. * * @since 1.4 */ diff --git a/src/java.xml/share/classes/javax/xml/transform/package-info.java b/src/java.xml/share/classes/javax/xml/transform/package-info.java index c3c0827a555..1345258f64e 100644 --- a/src/java.xml/share/classes/javax/xml/transform/package-info.java +++ b/src/java.xml/share/classes/javax/xml/transform/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2019, 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 @@ -183,11 +183,6 @@ * to report errors that occur during the transformation. The ErrorListener * on both objects will always be valid and non-null, whether set by * the application or a default implementation provided by the processor. - * The default implementation provided by the processor will report all warnings - * and errors to System.err and does not throw any Exceptions. - * Applications are strongly encouraged to register and use - * ErrorListeners that insure proper behavior for warnings and - * errors. * * *

Resolution of URIs within a transformation

diff --git a/src/java.xml/share/classes/jdk/xml/internal/TransformErrorListener.java b/src/java.xml/share/classes/jdk/xml/internal/TransformErrorListener.java new file mode 100644 index 00000000000..0b2f0ac0088 --- /dev/null +++ b/src/java.xml/share/classes/jdk/xml/internal/TransformErrorListener.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2019, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 jdk.xml.internal; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.TransformerException; + +/** + * Implements an ErrorListener for use by the JDK as the default ErrorListener. + * For compatibility, this implementation retains the behavior as was implemented + * by TransformerFactoryImpl and TransformerImpl where both the error and + * fatalError methods re-throw the exception. + */ +public class TransformErrorListener implements ErrorListener { + /** + * Receives notification of a warning. + * + * @param e The warning information encapsulated in a TransformerException. + * @throws TransformerException not thrown in this implementation + */ + @Override + public void warning(TransformerException e) + throws TransformerException + { + // no op + } + + /** + * Receives notification of an error. + * The transformer may continue the process if the error is recoverable. + * It may decide not to if it can not continue after the error. + * + * @param e The error information encapsulated in a TransformerException. + * @throws TransformerException re-throws the exception. + */ + @Override + public void error(TransformerException e) + throws TransformerException + { + throw e; + } + + /** + * Receives notification of a fatal error. + * + * @param e The error information encapsulated in a TransformerException. + * @throws TransformerException re-throws the exception. + */ + @Override + public void fatalError(TransformerException e) + throws TransformerException + { + throw e; + } +} diff --git a/test/jaxp/javax/xml/jaxp/unittest/transform/ErrorListenerTest.java b/test/jaxp/javax/xml/jaxp/unittest/transform/ErrorListenerTest.java index 767368b1370..dbe1dcfe00f 100644 --- a/test/jaxp/javax/xml/jaxp/unittest/transform/ErrorListenerTest.java +++ b/test/jaxp/javax/xml/jaxp/unittest/transform/ErrorListenerTest.java @@ -27,92 +27,361 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.PrintStream; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; import javax.xml.transform.ErrorListener; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import org.xml.sax.InputSource; /* * @test - * @bug 8157830 + * @bug 8157830 8228854 * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest * @run testng/othervm transform.ErrorListenerTest * @summary Verifies that ErrorListeners are handled properly */ public class ErrorListenerTest { + static final int SYSTEM_ERR = 1; + static final int SYSTEM_OUT = 2; + static final String ERR_STDERR = "Msg sent to stderr"; + static final String ERR_STDOUT = "Msg sent to stdout"; static final private String INVALID_STYLESHEET = "xxx"; static final private String SYSTEM_ID = "http://openjdk_java_net/xsl/dummy.xsl"; - PrintStream original; + final private String INCLUDE_NOT_EXIST = "" + + "" + + " " + + ""; + + final private String VAR_UNDEFINED = "" + + "" + + " " + + " " + + " " + + " " + + ""; + final private String XSL_DOC_FUNCTION = "" + + "" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + ""; + final private String XML_DOC_FUNCTION = "" + + "" + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + " " + + ""; + + PrintStream originalErr, originalOut; + List testMsgs = new ArrayList<>(); @BeforeClass public void setUpClass() throws Exception { // save the PrintStream - original = System.err; + originalErr = System.err; + originalOut = System.out; } @AfterClass protected void tearDown() throws Exception { // set back to the original - System.setErr(original); + System.setErr(originalErr); + System.setOut(originalOut); + // print out test messages + testMsgs.stream().forEach((msg) -> { + System.out.println(msg); + }); + } + + /* + DataProvider: for ErrorListenner tests + Data: xsl, xml, setListener(true/false), output channel(stderr/stdout), + expected console output, expected listener output + */ + @DataProvider(name = "testCreatingTransformer") + public Object[][] getTransformer() { + return new Object[][]{ + /* + * Verifies that the default implementation does not print out + * warnings and errors to stderr. + */ + {INCLUDE_NOT_EXIST, false, ""}, + {VAR_UNDEFINED, false, ""}, + /* + * Verifies that the registered listener is used. + */ + {INCLUDE_NOT_EXIST, true, "NOSUCHFILE.xsl"}, + {VAR_UNDEFINED, true, "'ids' is undefined"}, + /* + * The original test for JDK8157830 + * Verifies that when an ErrorListener is registered, parser errors + * are passed onto the listener without other output. + */ + {INVALID_STYLESHEET, true, "Content is not allowed in prolog"}, + }; + } + /* + DataProvider: for ErrorListenner tests + Data: xsl, xml, setListener(true/false), output channel(stderr/stdout), + expected console output, expected listener output + */ + @DataProvider(name = "testTransform") + public Object[][] getTransform() { + return new Object[][]{ + /* + * Verifies that the default implementation does not print out + * warnings and errors to stderr. + */ + {XSL_DOC_FUNCTION, XML_DOC_FUNCTION, false, ""}, + /* + * Verifies that the default implementation does not print out + * warnings and errors to stderr. + */ + {XSL_DOC_FUNCTION, XML_DOC_FUNCTION, true, "NOSUCHFILE.xml"} + }; + } + + /* + DataProvider: for ErrorListenner tests + Data: xsl, xml, setListener(true/false), expected listener output + */ + @DataProvider(name = "testEncoding") + public Object[][] getData() { + return new Object[][]{ + {"", false, ""}, + {"", true, "'dummy' is not supported"} + }; } /** - * Verifies that when an ErrorListener is registered, parser errors are passed - * onto the listener without other output. + * Verifies that ErrorListeners are properly set and propagated, or the + * default ErrorListener does not send messages to stderr/stdout. * + * @param xsl the stylesheet + * @param setListener a flag indicating whether a listener should be set + * @param msgL the expected listener output + * @throws Exception if the test fails + */ + @Test(dataProvider = "testCreatingTransformer") + public void testTransformer(String xsl, boolean setListener, String msgL) + throws Exception { + ErrListener listener = setListener ? new ErrListener("test") : null; + String msgConsole = getTransformerErr("testTransformer", xsl, listener); + evalResult(listener, msgConsole, setListener, msgL); + } + + /** + * Verifies that ErrorListeners are properly set and propagated, or the + * default ErrorListener does not send messages to stderr/stdout. + * + * @param xsl the stylesheet + * @param xml the XML + * @param setListener a flag indicating whether a listener should be set + * @param msgL the expected listener output + * @throws Exception if the test fails + */ + //@Test(dataProvider = "testTransform") + public void testTransform(String xsl, String xml, boolean setListener, String msgL) + throws Exception { + ErrListener listener = setListener ? new ErrListener("test") : null; + Transformer t = getTransformer("testDocFunc", xsl, listener); + String msgConsole = transform("testDocFunc", xml, t); + evalResult(listener, msgConsole, setListener, msgL); + } + + /** + * Verifies that the default implementation does not print out warnings and + * errors to the console when an invalid encoding is set. + * + * @throws Exception if the test fails + */ + //@Test(dataProvider = "testEncoding") + public void testEncoding(String xml, boolean setListener, String msgL) + throws Exception { + ErrListener listener = setListener ? new ErrListener("test") : null; + Transformer t = TransformerFactory.newInstance().newTransformer(); + if (setListener) { + t.setErrorListener(listener); + } + t.setOutputProperty(OutputKeys.ENCODING, "dummy"); + String msgConsole = transform("testEncoding", "", t); + evalResult(listener, msgConsole, setListener, msgL); + } + + private void evalResult(ErrListener l, String m, boolean setListener, String msgL) + throws Exception{ + Assert.assertTrue(!m.contains(ERR_STDERR), "no output to stderr"); + Assert.assertTrue(!m.contains(ERR_STDOUT), "no output to stdout"); + if (setListener) { + testMsgs.add("l.errMsg=" + l.errMsg); + testMsgs.add("evalResult.msgL=" + msgL); + Assert.assertTrue(l.errMsg.contains(msgL), + "The registered listener shall be used."); + } + } + + /** + * Obtains a Transformer. + * + * @param test the name of the test + * @param xsl the stylesheet + * @param setListener a flag indicating whether to set a listener + * @return the Transformer, null if error occurs * @throws Exception */ - @Test - public void test() throws Exception { - InputStream is = new ByteArrayInputStream(INVALID_STYLESHEET.getBytes()); - InputSource source = new InputSource(is); - source.setSystemId(SYSTEM_ID); + private Transformer getTransformer(String test, String xsl, ErrorListener listener) + throws Exception { + Transformer f = null; + InputSource source = new InputSource(new ByteArrayInputStream(xsl.getBytes())); + TransformerFactory factory = TransformerFactory.newInstance(); + if (listener != null) { + factory.setErrorListener(listener); + } - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintStream ps = new PrintStream(baos); - System.setErr(ps); + try { + f = factory.newTransformer(new SAXSource(source)); + if (listener != null) { + f.setErrorListener(listener); + } + } catch (TransformerConfigurationException e) { + testMsgs.add(test + "::catch: " + e.getMessage()); + } + + return f; + } + + /** + * Attempts to capture messages sent to stderr/stdout during the creation + * of a Transformer. + * + * @param test the name of the test + * @param xsl the stylesheet + * @param setListener a flag indicating whether to set a listener + * @return message sent to stderr/stdout, null if none + * @throws Exception + */ + private String getTransformerErr(String test, String xsl, ErrorListener listener) + throws Exception { + InputStream is = new ByteArrayInputStream(xsl.getBytes()); + InputSource source = new InputSource(is); + + ByteArrayOutputStream baos1 = setOutput(SYSTEM_ERR); + ByteArrayOutputStream baos2 = setOutput(SYSTEM_OUT); TransformerFactory factory = TransformerFactory.newInstance(); - factory.setErrorListener(new ErrListener()); + if (listener != null) { + factory.setErrorListener(listener); + } try { factory.newTransformer(new SAXSource(source)); } catch (TransformerConfigurationException e) { - // nothing + testMsgs.add(test + "::catch: " + e.getMessage()); } + reset(); + String msg = !"".equals(baos1.toString()) ? ERR_STDERR : ""; + msg = !"".equals(baos2.toString()) ? msg + ERR_STDOUT : msg; + return msg; + } - // all errors are handled by the ErrorListener, no other output - Assert.assertEquals(baos.toString(), ""); + /** + * Transforms an XML file. Attempts to capture stderr/stdout as the Transformer + * may direct messages to stdout. + * + * @param test the name of the test + * @param xml the XML file + * @param t the Transformer + * @param type the flag indicating which output channel to capture + * @return message sent to stdout, null if none + * @throws Exception + */ + private String transform(String test, String xml, Transformer t) + throws Exception { + StreamSource source = new StreamSource(new StringReader(xml)); + StreamResult result = new StreamResult(new StringWriter()); + ByteArrayOutputStream baos1 = setOutput(SYSTEM_ERR); + ByteArrayOutputStream baos2 = setOutput(SYSTEM_OUT); + try { + t.transform(source, result); + } catch (Exception e) { + testMsgs.add(test + "::catch: " + e.getMessage()); + } + reset(); + String msg = !"".equals(baos1.toString()) ? ERR_STDERR : ""; + msg = !"".equals(baos2.toString()) ? msg + ERR_STDOUT : msg; + return msg; + } + private ByteArrayOutputStream setOutput(int type) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos); + if (type == SYSTEM_ERR) { + System.setErr(ps); + } else { + System.setOut(ps); + } + return baos; + } + + private void reset() { + System.setErr(originalErr); + System.setOut(originalOut); } class ErrListener implements ErrorListener { - - @Override - public void error(TransformerException exception) - throws TransformerException { - System.out.println("Correctly handled error: " + exception.getMessage()); + String testName; + String errMsg = ""; + ErrListener(String test) { + testName = test; } @Override - public void fatalError(TransformerException exception) + public void error(TransformerException e) throws TransformerException { - System.out.println("Correctly handled fatal: " + exception.getMessage()); + errMsg = errMsg + "#error: " + e.getMessage(); } @Override - public void warning(TransformerException exception) + public void fatalError(TransformerException e) throws TransformerException { - System.out.println("Correctly handled warning: " + exception.getMessage()); + errMsg = errMsg + "#fatalError: " + e.getMessage(); + } + + @Override + public void warning(TransformerException e) + throws TransformerException { + errMsg = errMsg + "#warning: " + e.getMessage(); } } }