content: /*
   *  This file is part of AndroidIDE.
   *
   *  AndroidIDE is free software: you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation, either version 3 of the License, or
   *  (at your option) any later version.
   *
   *  AndroidIDE 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 for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *   along with AndroidIDE.  If not, see <https://www.gnu.org/licenses/>.
   */
  
  /*
   * reserved comment block
   * DO NOT REMOVE OR ALTER!
   */
  /*
   * 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.2.4.1 2005/09/15 08:15:46 suresh_emailid Exp $
   */
  
  package jaxp.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 jaxp.xml.transform.ErrorListener;
  import jaxp.xml.transform.SourceLocator;
  import jaxp.xml.transform.TransformerException;
  
  import jaxp.sun.org.apache.xml.internal.res.XMLErrorResources;
  import jaxp.sun.org.apache.xml.internal.res.XMLMessages;
  
  import org.xml.sax.ErrorHandler;
  import org.xml.sax.SAXException;
  import org.xml.sax.SAXParseException;
  
  import jaxp.xml.transform.Transformer;
  
  
  /**
   * 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 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 TransformerException  only if
       * setThrowOnWarning is true.
       *
       * @see 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 TransformerException  only if
       * setThrowOnError is true.
       *
       * @see 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 TransformerException  only if
       * setThrowOnError is true.
       *
       * @see 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;
  
  }
  