001: /***** BEGIN LICENSE BLOCK *****
002: * Version: CPL 1.0/GPL 2.0/LGPL 2.1
003: *
004: * The contents of this file are subject to the Common Public
005: * License Version 1.0 (the "License"); you may not use this file
006: * except in compliance with the License. You may obtain a copy of
007: * the License at http://www.eclipse.org/legal/cpl-v10.html
008: *
009: * Software distributed under the License is distributed on an "AS
010: * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
011: * implied. See the License for the specific language governing
012: * rights and limitations under the License.
013: *
014: * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
015: * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
016: * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
017: * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
018: * Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
019: * Copyright (C) 2004 Joey Gibson <joey@joeygibson.com>
020: * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
021: * Copyright (C) 2005 Charles O Nutter <headius@headius.com>
022: *
023: * Alternatively, the contents of this file may be used under the terms of
024: * either of the GNU General Public License Version 2 or later (the "GPL"),
025: * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
026: * in which case the provisions of the GPL or the LGPL are applicable instead
027: * of those above. If you wish to allow use of your version of this file only
028: * under the terms of either the GPL or the LGPL, and not to allow others to
029: * use your version of this file under the terms of the CPL, indicate your
030: * decision by deleting the provisions above and replace them with the notice
031: * and other provisions required by the GPL or the LGPL. If you do not delete
032: * the provisions above, a recipient may use your version of this file under
033: * the terms of any one of the CPL, the GPL or the LGPL.
034: ***** END LICENSE BLOCK *****/package org.jruby.exceptions;
035:
036: import java.io.ByteArrayOutputStream;
037: import java.io.PrintStream;
038: import java.io.PrintWriter;
039: import java.io.StringWriter;
040:
041: import org.jruby.*;
042: import org.jruby.runtime.Block;
043: import org.jruby.runtime.EventHook;
044: import org.jruby.runtime.MethodIndex;
045: import org.jruby.runtime.ThreadContext;
046: import org.jruby.runtime.builtin.IRubyObject;
047:
048: public class RaiseException extends JumpException {
049: private static final long serialVersionUID = -7612079169559973951L;
050:
051: private RubyException exception;
052:
053: public RaiseException(RubyException actException) {
054: this (actException, false);
055: }
056:
057: public RaiseException(Ruby runtime, RubyClass excptnClass,
058: String msg, boolean nativeException) {
059: super (msg, JumpType.RaiseJump);
060: if (msg == null) {
061: msg = "No message available";
062: }
063: setException((RubyException) excptnClass.callMethod(runtime
064: .getCurrentContext(), "new",
065: new IRubyObject[] { excptnClass.getRuntime().newString(
066: msg) }, Block.NULL_BLOCK), nativeException);
067: }
068:
069: public RaiseException(RubyException exception,
070: boolean isNativeException) {
071: super (JumpType.RaiseJump);
072: setException(exception, isNativeException);
073: }
074:
075: public static RaiseException createNativeRaiseException(
076: Ruby runtime, Throwable cause) {
077: NativeException nativeException = new NativeException(runtime,
078: runtime.getClass(NativeException.CLASS_NAME), cause);
079: return new RaiseException(cause, nativeException);
080: }
081:
082: private static String buildMessage(Throwable exception) {
083: StringBuffer sb = new StringBuffer();
084: StringWriter stackTrace = new StringWriter();
085: exception.printStackTrace(new PrintWriter(stackTrace));
086:
087: sb.append("Native Exception: '").append(exception.getClass())
088: .append("'; ");
089: sb.append("Message: ").append(exception.getMessage()).append(
090: "; ");
091: sb.append("StackTrace: ").append(
092: stackTrace.getBuffer().toString());
093:
094: return sb.toString();
095: }
096:
097: public RaiseException(Throwable cause,
098: NativeException nativeException) {
099: super (buildMessage(cause), cause, JumpType.RaiseJump);
100: setException(nativeException, false);
101: }
102:
103: /**
104: * Gets the exception
105: * @return Returns a RubyException
106: */
107: public RubyException getException() {
108: return exception;
109: }
110:
111: /**
112: * Sets the exception
113: * @param newException The exception to set
114: */
115: protected void setException(RubyException newException,
116: boolean nativeException) {
117: Ruby runtime = newException.getRuntime();
118: ThreadContext context = runtime.getCurrentContext();
119:
120: if (!context.isWithinDefined()) {
121: runtime.getGlobalVariables().set("$!", newException);
122: }
123:
124: if (runtime.hasEventHooks()) {
125: runtime.callEventHooks(context,
126: EventHook.RUBY_EVENT_RETURN, context.getPosition()
127: .getFile(), context.getPosition()
128: .getStartLine(), context.getFrameName(),
129: context.getFrameKlazz());
130: }
131:
132: this .exception = newException;
133:
134: if (runtime.getStackTraces() > 5) {
135: return;
136: }
137:
138: runtime.setStackTraces(runtime.getStackTraces() + 1);
139:
140: newException.setBacktraceFrames(context.createBacktrace(0,
141: nativeException));
142:
143: runtime.setStackTraces(runtime.getStackTraces() - 1);
144: }
145:
146: public Throwable fillInStackTrace() {
147: return originalFillInStackTrace();
148: }
149:
150: public void printStackTrace() {
151: printStackTrace(System.err);
152: }
153:
154: public void printStackTrace(PrintStream ps) {
155: StackTraceElement[] trace = getStackTrace();
156: int externalIndex = 0;
157: for (int i = trace.length - 1; i > 0; i--) {
158: if (trace[i].getClassName().indexOf("org.jruby.evaluator") >= 0) {
159: break;
160: }
161: externalIndex = i;
162: }
163: IRubyObject backtrace = exception.backtrace();
164: Ruby runtime = backtrace.getRuntime();
165: if (runtime.getNil() != backtrace) {
166: String firstLine = backtrace.callMethod(
167: runtime.getCurrentContext(), "first").callMethod(
168: runtime.getCurrentContext(), MethodIndex.TO_S,
169: "to_s").toString();
170: ps.print(firstLine + ": ");
171: }
172: ps.println(exception.message + " ("
173: + exception.getMetaClass().toString() + ")");
174: exception.printBacktrace(ps);
175: ps.println("\t...internal jruby stack elided...");
176: for (int i = externalIndex; i < trace.length; i++) {
177: ps.println("\tfrom " + trace[i].toString());
178: }
179: }
180:
181: public void printStackTrace(PrintWriter pw) {
182: ByteArrayOutputStream baos = new ByteArrayOutputStream();
183: printStackTrace(new PrintStream(baos));
184: pw.print(baos.toString());
185: }
186: }
|