| /* |
| * reserved comment block |
| * DO NOT REMOVE OR ALTER! |
| */ |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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. |
| */ |
| |
| 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 |
| * @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. |
| * |
| * @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 b 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 b 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 b 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; |
| |
| } |