All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.grinder.scriptengine.jython.JythonScriptExecutionException Maven / Gradle / Ivy

The newest version!
// Copyright (C) 2000 - 2012 Philip Aston
// All rights reserved.
//
// This file is part of The Grinder software distribution. Refer to
// the file LICENSE which is part of The Grinder distribution for
// licensing details. The Grinder distribution is available on the
// Internet at http://grinder.sourceforge.net/
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
// OF THE POSSIBILITY OF SUCH DAMAGE.

package net.grinder.scriptengine.jython;

import net.grinder.scriptengine.ScriptExecutionException;

import org.python.core.Py;
import org.python.core.PyClass;
import org.python.core.PyException;
import org.python.core.PyTraceback;


/**
 * Exception that wraps errors encountered when invoking Jython
 * scripts.
 *
 * @author Philip Aston
 */
final class JythonScriptExecutionException extends ScriptExecutionException {

  private final String m_message;
  private final String m_shortMessage;

  /**
   * Constructor for exceptions arising from a problem with the script that
   * did not arise from some other exception.
   *
   * @param message
   */
  public JythonScriptExecutionException(final String message) {
    super(message);
    m_message = message;
    m_shortMessage = message;
  }

  /**
   * Creates a new JythonScriptExecutionException instance.
   *
   * @param doingWhat What we were doing.
   * @param e PyException that we caught.
   */
  public JythonScriptExecutionException(final String doingWhat,
                                        final PyException e) {
    super("");
    setStackTrace(new StackTraceElement[0]);

    final Object javaError = e.value.__tojava__(Throwable.class);

    if (javaError == null || javaError == Py.NoConversion) {
      // Duplicate logic from the package scope Py.formatException().
      final StringBuilder pyExceptionMessage = new StringBuilder();

      if (e.type instanceof PyClass) {
        pyExceptionMessage.append(((PyClass) e.type).__name__);
      }
      else {
        pyExceptionMessage.append(e.type.__str__());
      }

      if (e.value != Py.None) {
        pyExceptionMessage.append(": ");
        // The original Py.formatException check's if e.value's type is
        // Py.SyntaxError and if so treats it as a tuple. This is clearly wrong,
        // it should check whether e.type is Py.SyntaxError. We do something
        // simple instead.
        pyExceptionMessage.append(e.value.__str__());
      }

      m_shortMessage =
        "Jython exception, " + pyExceptionMessage +
        " [" + doingWhat + "]";
      m_message =
        tracebackToMessage(pyExceptionMessage.toString(), e.traceback);
      initCause(null);
    }
    else {
      m_shortMessage = "Java exception " + doingWhat;
      m_message = tracebackToMessage(m_shortMessage, e.traceback);
      initCause((Throwable)javaError);
    }
  }

  /**
   * A short message, without the Jython stack trace. We override
   * {@link #getMessage} to include the Jython stack trace; sometimes we don't
   * want the stack trace.
   *
   * @return A short message, without the Jython stack trace.
   */
  @Override
  public String getShortMessage() {
    return m_shortMessage;
  }

  /**
   * The detail message string for this throwable.
   *
   * @return The message.
   */
  @Override
  public String getMessage() {
    return m_message;
  }

  /**
   * Remove the class name from stack traces.
   *
   * @return A string representation of this instance.
   */
  @Override
  public String toString() {
    return getLocalizedMessage();
  }

  /**
   * We fix various following problems with PyTraceback.dumpStack() to make it
   * more suitable for incorporation with a Java stack trace.
   * 
    *
  • PyTraceback doesn't use platform specific line separators.
  • *
  • Stacks are printed with the innermost frame last.
  • *
  • The indentation style is different.
  • *
*/ private static String tracebackToMessage(final String prefix, final PyTraceback traceback) { final StringBuilder result = new StringBuilder(prefix); if (traceback != null) { final String[] frames = traceback.dumpStack().split("\n"); for (int i = frames.length - 1; i >= 1; --i) { result.append(System.getProperty("line.separator")); result.append("\t"); result.append(frames[i].trim()); } } return result.toString(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy