8228854: Default ErrorListener reports warnings and errors to the console

Reviewed-by: lancea
This commit is contained in:
Joe Wang 2019-09-05 17:26:38 +00:00
parent 675eecaacf
commit 77b3801f6c
16 changed files with 528 additions and 300 deletions

View File

@ -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)) {

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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.

View File

@ -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;

View File

@ -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

View File

@ -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. */

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}
/**

View File

@ -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();
}
/**

View File

@ -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

View File

@ -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;
/**
* <p>To provide customized error handling, implement this interface and
* use the <code>setErrorListener</code> method to register an instance of the
* implementation with the {@link javax.xml.transform.Transformer}. The
* <code>Transformer</code> then reports all errors and warnings through this
* interface.</p>
* 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.
*
* <p>If an application does <em>not</em> register its own custom
* <code>ErrorListener</code>, the default <code>ErrorListener</code>
* is used which reports all warnings and errors to <code>System.err</code>
* and does not throw any <code>Exception</code>s.
* Applications are <em>strongly</em> encouraged to register and use
* <code>ErrorListener</code>s that insure proper behavior for warnings and
* errors.</p>
* <p>
* 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.
*
* <p>For transformation errors, a <code>Transformer</code> must use this
* interface instead of throwing an <code>Exception</code>: it is up to the
* application to decide whether to throw an <code>Exception</code> for
* different types of errors and warnings. Note however that the
* <code>Transformer</code> is not required to continue with the transformation
* after a call to {@link #fatalError(TransformerException exception)}.</p>
* <p>
* 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)}.
*
* <p><code>Transformer</code>s may use this mechanism to report XML parsing
* errors as well as transformation errors.</p>
* <p>
* 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
*/

View File

@ -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 <code>ErrorListener</code>
* on both objects will always be valid and non-<code>null</code>, 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 <code>System.err</code> and does not throw any <code>Exception</code>s.
* Applications are <em>strongly</em> encouraged to register and use
* <code>ErrorListener</code>s that insure proper behavior for warnings and
* errors.
*
*
* <h2>Resolution of URIs within a transformation</h2>

View File

@ -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;
}
}

View File

@ -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 = "<?xml version=\"1.1\" encoding=\"UTF-8\"?>" +
"<xsl:stylesheet xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" version=\"1.0\">" +
" <xsl:import href=\"NOSUCHFILE.xsl\"/>" +
"</xsl:stylesheet>";
final private String VAR_UNDEFINED = "<?xml version=\"1.1\" encoding=\"ISO-8859-1\"?>" +
"<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">" +
" <xsl:template match=\"/\"> " +
" <test1><xsl:apply-templates select=\"$ids\"/></test1>" +
" <test2><xsl:apply-templates select=\"$dummy//ids/id\"/></test2>" +
" </xsl:template>" +
"</xsl:stylesheet>";
final private String XSL_DOC_FUNCTION = "<?xml version=\"1.1\" encoding=\"ISO-8859-1\"?>" +
"<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\">" +
" <xsl:output method=\"xml\" indent=\"yes\"/>" +
" <xsl:variable name=\"ids\" select=\"//ids//id\"/>" +
" <xsl:variable name=\"dummy\" select=\"document('NOSUCHFILE.xml')\"/>" +
" <xsl:template match=\"/\"> " +
" <test1><xsl:apply-templates select=\"$ids\"/></test1>" +
" <test2><xsl:apply-templates select=\"$dummy//ids/id\"/></test2>" +
" </xsl:template>" +
" <xsl:template match=\"id\">" +
" <xsl:variable name=\"entity\" select=\"id(@value)\"/> " +
" <must-be-one><xsl:value-of select=\"count($entity)\"/></must-be-one>" +
" </xsl:template>" +
"</xsl:stylesheet>";
final private String XML_DOC_FUNCTION = "<?xml version=\"1.1\" encoding=\"ISO-8859-1\" standalone=\"no\"?>" +
"<organization2>" +
" <company id=\"xca\" count=\"2\">" +
" <department id=\"xda\"/>" +
" </company>" +
" <company id=\"xcb\" count=\"0\"/>" +
" <company id=\"xcc\" count=\"5\"/>" +
" <ids>" +
" <id value=\"xca\"/>" +
" <id value=\"xcb\"/>" +
" </ids>" +
"</organization2>";
PrintStream originalErr, originalOut;
List<String> 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[][]{
{"<foo><bar></bar></foo>", false, ""},
{"<foo><bar></bar></foo>", 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", "<foo><bar></bar></foo>", 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();
}
}
}