- /*
- * Copyright 2000-2004 The Apache Software Foundation.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /*
- * $Id: ListingErrorHandler.java,v 1.7 2004/02/17 04:21:14 minchau Exp $
- */
-
- package com.sun.org.apache.xml.internal.utils;
-
- import java.io.BufferedReader;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.PrintWriter;
- import java.net.URL;
- import java.net.URLConnection;
-
- import javax.xml.transform.ErrorListener;
- import javax.xml.transform.SourceLocator;
- import javax.xml.transform.TransformerException;
-
- import com.sun.org.apache.xml.internal.res.XMLErrorResources;
- import com.sun.org.apache.xml.internal.res.XMLMessages;
-
- import org.xml.sax.ErrorHandler;
- import org.xml.sax.SAXException;
- import org.xml.sax.SAXParseException;
-
-
- /**
- * Sample implementation of similar SAX ErrorHandler and JAXP ErrorListener.
- *
- * <p>This implementation is suitable for various use cases, and
- * provides some basic configuration API's as well to control
- * when we re-throw errors, etc.</p>
- *
- * @author shane_curcuru@us.ibm.com
- * @version $Id: ListingErrorHandler.java,v 1.7 2004/02/17 04:21:14 minchau Exp $
- * @xsl.usage general
- */
- public class ListingErrorHandler implements ErrorHandler, ErrorListener
- {
- protected PrintWriter m_pw = null;
-
-
- /**
- * Constructor ListingErrorHandler; user-supplied PrintWriter.
- */
- public ListingErrorHandler(PrintWriter pw)
- {
- if (null == pw)
- throw new NullPointerException(XMLMessages.createXMLMessage(XMLErrorResources.ER_ERRORHANDLER_CREATED_WITH_NULL_PRINTWRITER, null));
- // "ListingErrorHandler created with null PrintWriter!");
-
- m_pw = pw;
- }
-
- /**
- * Constructor ListingErrorHandler; uses System.err.
- */
- public ListingErrorHandler()
- {
- m_pw = new PrintWriter(System.err, true);
- }
-
-
- /* ======== Implement org.xml.sax.ErrorHandler ======== */
- /**
- * Receive notification of a warning.
- *
- * <p>SAX parsers will use this method to report conditions that
- * are not errors or fatal errors as defined by the XML 1.0
- * recommendation. The default behaviour is to take no action.</p>
- *
- * <p>The SAX parser 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.</p>
- *
- * <p>Filters may use this method to report other, non-XML warnings
- * as well.</p>
- *
- * @param exception The warning information encapsulated in a
- * SAX parse exception.
- * @exception org.xml.sax.SAXException Any SAX exception, possibly
- * wrapping another exception; only if setThrowOnWarning is true.
- * @see org.xml.sax.SAXParseException
- */
- public void warning (SAXParseException exception)
- throws SAXException
- {
- logExceptionLocation(m_pw, exception);
- // Note: should we really call .toString() below, since
- // sometimes the message is not properly set?
- m_pw.println("warning: " + exception.getMessage());
- m_pw.flush();
-
- if (getThrowOnWarning())
- throw exception;
- }
-
-
- /**
- * Receive notification of a recoverable error.
- *
- * <p>This corresponds to the definition of "error" in section 1.2
- * of the W3C XML 1.0 Recommendation. For example, a validating
- * parser would use this callback to report the violation of a
- * validity constraint. The default behaviour is to take no
- * action.</p>
- *
- * <p>The SAX parser 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. If the
- * application cannot do so, then the parser should report a fatal
- * error even if the XML 1.0 recommendation does not require it to
- * do so.</p>
- *
- * <p>Filters may use this method to report other, non-XML errors
- * as well.</p>
- *
- * @param exception The error information encapsulated in a
- * SAX parse exception.
- * @exception org.xml.sax.SAXException Any SAX exception, possibly
- * wrapping another exception; only if setThrowOnErroris true.
- * @see org.xml.sax.SAXParseException
- */
- public void error (SAXParseException exception)
- throws SAXException
- {
- logExceptionLocation(m_pw, exception);
- m_pw.println("error: " + exception.getMessage());
- m_pw.flush();
-
- if (getThrowOnError())
- throw exception;
- }
-
-
- /**
- * Receive notification of a non-recoverable error.
- *
- * <p>This corresponds to the definition of "fatal error" in
- * section 1.2 of the W3C XML 1.0 Recommendation. For example, a
- * parser would use this callback to report the violation of a
- * well-formedness constraint.</p>
- *
- * <p>The application must assume that the document is unusable
- * after the parser has invoked this method, and should continue
- * (if at all) only for the sake of collecting addition error
- * messages: in fact, SAX parsers are free to stop reporting any
- * other events once this method has been invoked.</p>
- *
- * @param exception The error information encapsulated in a
- * SAX parse exception.
- * @exception org.xml.sax.SAXException Any SAX exception, possibly
- * wrapping another exception; only if setThrowOnFatalError is true.
- * @see org.xml.sax.SAXParseException
- */
- public void fatalError (SAXParseException exception)
- throws SAXException
- {
- logExceptionLocation(m_pw, exception);
- m_pw.println("fatalError: " + exception.getMessage());
- m_pw.flush();
-
- if (getThrowOnFatalError())
- throw exception;
- }
-
-
- /* ======== Implement javax.xml.transform.ErrorListener ======== */
-
- /**
- * Receive notification of a warning.
- *
- * <p>{@link javax.xml.transform.Transformer} can use this method to report
- * conditions that are not errors or fatal errors. The default behaviour
- * is to take no action.</p>
- *
- * <p>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.</p>
- *
- * @param exception The warning information encapsulated in a
- * transformer exception.
- *
- * @throws javax.xml.transform.TransformerException only if
- * setThrowOnWarning is true.
- *
- * @see javax.xml.transform.TransformerException
- */
- public void warning(TransformerException exception)
- throws TransformerException
- {
- logExceptionLocation(m_pw, exception);
- m_pw.println("warning: " + exception.getMessage());
- m_pw.flush();
-
- if (getThrowOnWarning())
- throw exception;
- }
-
- /**
- * Receive notification of a recoverable error.
- *
- * <p>The transformer must continue to try and provide normal transformation
- * after invoking this method. It should still be possible for the
- * application to process the document through to the end if no other errors
- * are encountered.</p>
- *
- * @param exception The error information encapsulated in a
- * transformer exception.
- *
- * @throws javax.xml.transform.TransformerException only if
- * setThrowOnError is true.
- *
- * @see javax.xml.transform.TransformerException
- */
- public void error(TransformerException exception)
- throws TransformerException
- {
- logExceptionLocation(m_pw, exception);
- m_pw.println("error: " + exception.getMessage());
- m_pw.flush();
-
- if (getThrowOnError())
- throw exception;
- }
-
- /**
- * Receive notification of a non-recoverable error.
- *
- * <p>The transformer must continue to try and provide normal transformation
- * after invoking this method. It should still be possible for the
- * application to process the document through to the end if no other errors
- * are encountered, but there is no guarantee that the output will be
- * useable.</p>
- *
- * @param exception The error information encapsulated in a
- * transformer exception.
- *
- * @throws javax.xml.transform.TransformerException only if
- * setThrowOnError is true.
- *
- * @see javax.xml.transform.TransformerException
- */
- public void fatalError(TransformerException exception)
- throws TransformerException
- {
- logExceptionLocation(m_pw, exception);
- m_pw.println("error: " + exception.getMessage());
- m_pw.flush();
-
- if (getThrowOnError())
- throw exception;
- }
-
-
-
- /* ======== Implement worker methods ======== */
-
-
- /**
- * Print out location information about the exception.
- *
- * Cribbed from DefaultErrorHandler.printLocation()
- * @param pw PrintWriter to send output to
- * @param exception TransformerException or SAXParseException
- * to log information about
- */
- public static void logExceptionLocation(PrintWriter pw, Throwable exception)
- {
- if (null == pw)
- pw = new PrintWriter(System.err, true);
-
- SourceLocator locator = null;
- Throwable cause = exception;
-
- // Try to find the locator closest to the cause.
- do
- {
- // Find the current locator, if one present
- if(cause instanceof SAXParseException)
- {
- // A SAXSourceLocator is a Xalan helper class
- // that implements both a SourceLocator and a SAX Locator
- //@todo check that the new locator actually has
- // as much or more information as the
- // current one already does
- locator = new SAXSourceLocator((SAXParseException)cause);
- }
- else if (cause instanceof TransformerException)
- {
- SourceLocator causeLocator = ((TransformerException)cause).getLocator();
- if(null != causeLocator)
- {
- locator = causeLocator;
- }
- }
-
- // Then walk back down the chain of exceptions
- if(cause instanceof TransformerException)
- cause = ((TransformerException)cause).getCause();
- else if(cause instanceof WrappedRuntimeException)
- cause = ((WrappedRuntimeException)cause).getException();
- else if(cause instanceof SAXException)
- cause = ((SAXException)cause).getException();
- else
- cause = null;
- }
- while(null != cause);
-
- // Formatting note: mimic javac-like errors:
- // path\filename:123: message-here
- // systemId:L=1;C=2: message-here
- if(null != locator)
- {
- String id = (locator.getPublicId() != locator.getPublicId())
- ? locator.getPublicId()
- : (null != locator.getSystemId())
- ? locator.getSystemId() : "SystemId-Unknown";
-
- pw.print(id + ":Line=" + locator.getLineNumber()
- + ";Column=" + locator.getColumnNumber()+": ");
- pw.println("exception:" + exception.getMessage());
- pw.println("root-cause:"
- + ((null != cause) ? cause.getMessage() : "null"));
- logSourceLine(pw, locator);
- }
- else
- {
- pw.print("SystemId-Unknown:locator-unavailable: ");
- pw.println("exception:" + exception.getMessage());
- pw.println("root-cause:"
- + ((null != cause) ? cause.getMessage() : "null"));
- }
- }
-
-
- /**
- * Print out the specific source line that caused the exception,
- * if possible to load it.
- *
- * @author shane_curcuru@us.ibm.com
- * @param pw PrintWriter to send output to
- * @param locator Xalan wrapper for either a JAXP or a SAX
- * source location object
- */
- public static void logSourceLine(PrintWriter pw, SourceLocator locator)
- {
- if (null == locator)
- return;
-
- if (null == pw)
- pw = new PrintWriter(System.err, true);
-
- String url = locator.getSystemId();
- // Bail immediately if we get SystemId-Unknown
- //@todo future improvement: attempt to get resource
- // from a publicId if possible
- if (null == url)
- {
- pw.println("line: (No systemId; cannot read file)");
- pw.println();
- return;
- }
-
- //@todo attempt to get DOM backpointer or other ids
-
- try
- {
- int line = locator.getLineNumber();
- int column = locator.getColumnNumber();
- pw.println("line: " + getSourceLine(url, line));
- StringBuffer buf = new StringBuffer("line: ");
- for (int i = 1; i < column; i++)
- {
- buf.append(' ');
- }
- buf.append('^');
- pw.println(buf.toString());
- }
- catch (Exception e)
- {
- pw.println("line: logSourceLine unavailable due to: " + e.getMessage());
- pw.println();
- }
- }
-
-
- /**
- * Return the specific source line that caused the exception,
- * if possible to load it; allow exceptions to be thrown.
- *
- * @author shane_curcuru@us.ibm.com
- */
- protected static String getSourceLine(String sourceUrl, int lineNum)
- throws Exception
- {
- URL url = null;
- // Get a URL from the sourceUrl
- try
- {
- // Try to get a URL from it as-is
- url = new URL(sourceUrl);
- }
- catch (java.net.MalformedURLException mue)
- {
- int indexOfColon = sourceUrl.indexOf(':');
- int indexOfSlash = sourceUrl.indexOf('/');
-
- if ((indexOfColon != -1)
- && (indexOfSlash != -1)
- && (indexOfColon < indexOfSlash))
- {
- // The url is already absolute, but we could not get
- // the system to form it, so bail
- throw mue;
- }
- else
- {
- // The url is relative, so attempt to get absolute
- url = new URL(SystemIDResolver.getAbsoluteURI(sourceUrl));
- // If this fails, allow the exception to propagate
- }
- }
-
- String line = null;
- InputStream is = null;
- BufferedReader br = null;
- try
- {
- // Open the URL and read to our specified line
- URLConnection uc = url.openConnection();
- is = uc.getInputStream();
- br = new BufferedReader(new InputStreamReader(is));
-
- // Not the most efficient way, but it works
- // (Feel free to patch to seek to the appropriate line)
- for (int i = 1; i <= lineNum; i++)
- {
- line = br.readLine();
- }
-
- }
- // Allow exceptions to propagate from here, but ensure
- // streams are closed!
- finally
- {
- br.close();
- is.close();
- }
-
- // Return whatever we found
- return line;
- }
-
-
- /* ======== Implement settable properties ======== */
-
- /**
- * User-settable behavior: when to re-throw exceptions.
- *
- * <p>This allows per-instance configuration of
- * ListingErrorHandlers. You can ask us to either throw
- * an exception when we're called for various warning /
- * error / fatalErrors, or simply log them and continue.</p>
- *
- * @param t if we should throw an exception on warnings
- */
- public void setThrowOnWarning(boolean b)
- {
- throwOnWarning = b;
- }
-
- /**
- * User-settable behavior: when to re-throw exceptions.
- *
- * @return if we throw an exception on warnings
- */
- public boolean getThrowOnWarning()
- {
- return throwOnWarning;
- }
-
- /** If we should throw exception on warnings; default:false. */
- protected boolean throwOnWarning = false;
-
-
- /**
- * User-settable behavior: when to re-throw exceptions.
- *
- * <p>This allows per-instance configuration of
- * ListingErrorHandlers. You can ask us to either throw
- * an exception when we're called for various warning /
- * error / fatalErrors, or simply log them and continue.</p>
- *
- * <p>Note that the behavior of many parsers/transformers
- * after an error is not necessarily defined!</p>
- *
- * @param t if we should throw an exception on errors
- */
- public void setThrowOnError(boolean b)
- {
- throwOnError = b;
- }
-
- /**
- * User-settable behavior: when to re-throw exceptions.
- *
- * @return if we throw an exception on errors
- */
- public boolean getThrowOnError()
- {
- return throwOnError;
- }
-
- /** If we should throw exception on errors; default:true. */
- protected boolean throwOnError = true;
-
-
- /**
- * User-settable behavior: when to re-throw exceptions.
- *
- * <p>This allows per-instance configuration of
- * ListingErrorHandlers. You can ask us to either throw
- * an exception when we're called for various warning /
- * error / fatalErrors, or simply log them and continue.</p>
- *
- * <p>Note that the behavior of many parsers/transformers
- * after a fatalError is not necessarily defined, most
- * products will probably barf if you continue.</p>
- *
- * @param t if we should throw an exception on fatalErrors
- */
- public void setThrowOnFatalError(boolean b)
- {
- throwOnFatalError = b;
- }
-
- /**
- * User-settable behavior: when to re-throw exceptions.
- *
- * @return if we throw an exception on fatalErrors
- */
- public boolean getThrowOnFatalError()
- {
- return throwOnFatalError;
- }
-
- /** If we should throw exception on fatalErrors; default:true. */
- protected boolean throwOnFatalError = true;
-
- }