KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyException


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
15  * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
16  * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
17  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
18  * Copyright (C) 2002-2006 Thomas E Enebo <enebo@acm.org>
19  * Copyright (C) 2004 Joey Gibson <joey@joeygibson.com>
20  * Copyright (C) 2004-2005 Charles O Nutter <headius@headius.com>
21  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
22  * Copyright (C) 2005 David Corbin <dcorbin@users.sf.net>
23  * Copyright (C) 2006 Michael Studman <codehaus@michaelstudman.com>
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either of the GNU General Public License Version 2 or later (the "GPL"),
27  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the CPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the CPL, the GPL or the LGPL.
36  ***** END LICENSE BLOCK *****/

37 package org.jruby;
38
39 import java.io.PrintStream JavaDoc;
40
41 import org.jruby.runtime.Block;
42 import org.jruby.runtime.CallbackFactory;
43 import org.jruby.runtime.ObjectAllocator;
44 import org.jruby.runtime.builtin.IRubyObject;
45
46 /**
47  *
48  * @author jpetersen
49  */

50 public class RubyException extends RubyObject {
51
52     private RubyArray backtrace;
53     public IRubyObject message;
54     public static final int TRACE_HEAD = 8;
55     public static final int TRACE_TAIL = 4;
56     public static final int TRACE_MAX = TRACE_HEAD + TRACE_TAIL + 6;
57
58     protected RubyException(Ruby runtime, RubyClass rubyClass) {
59         this(runtime, rubyClass, null);
60     }
61
62     public RubyException(Ruby runtime, RubyClass rubyClass, String JavaDoc message) {
63         super(runtime, rubyClass);
64         
65         this.message = message == null ? runtime.getNil() : runtime.newString(message);
66     }
67     
68     private static ObjectAllocator EXCEPTION_ALLOCATOR = new ObjectAllocator() {
69         public IRubyObject allocate(Ruby runtime, RubyClass klass) {
70             RubyException instance = new RubyException(runtime, klass);
71             
72             // for future compatibility as constructors move toward not accepting metaclass?
73
instance.setMetaClass(klass);
74             
75             return instance;
76         }
77     };
78
79     public static RubyClass createExceptionClass(Ruby runtime) {
80         RubyClass exceptionClass = runtime.defineClass("Exception", runtime.getObject(), EXCEPTION_ALLOCATOR);
81
82         CallbackFactory callbackFactory = runtime.callbackFactory(RubyException.class);
83         CallbackFactory classCB = runtime.callbackFactory(RubyClass.class);
84         // TODO: could this just be an alias for new?
85
exceptionClass.getMetaClass().defineMethod("exception", classCB.getOptMethod("newInstance"));
86         exceptionClass.defineMethod("initialize", callbackFactory.getOptMethod("initialize"));
87         exceptionClass.defineFastMethod("exception", callbackFactory.getFastOptMethod("exception"));
88         exceptionClass.defineFastMethod("to_s", callbackFactory.getFastMethod("to_s"));
89         exceptionClass.defineFastMethod("to_str", callbackFactory.getFastMethod("to_s"));
90         exceptionClass.defineFastMethod("message", callbackFactory.getFastMethod("to_s"));
91         exceptionClass.defineFastMethod("inspect", callbackFactory.getFastMethod("inspect"));
92         exceptionClass.defineFastMethod("backtrace", callbackFactory.getFastMethod("backtrace"));
93         exceptionClass.defineFastMethod("set_backtrace", callbackFactory.getFastMethod("set_backtrace", RubyKernel.IRUBY_OBJECT));
94
95         return exceptionClass;
96     }
97
98     public static RubyException newException(Ruby runtime, RubyClass excptnClass, String JavaDoc msg) {
99         return new RubyException(runtime, excptnClass, msg);
100     }
101
102     public IRubyObject initialize(IRubyObject[] args, Block block) {
103         if (args.length > 0) {
104             message = args[0];
105         }
106         return this;
107     }
108
109     public IRubyObject backtrace() {
110         return backtrace == null ? getRuntime().getNil() : backtrace;
111     }
112
113     public IRubyObject set_backtrace(IRubyObject obj) {
114         if (obj.isNil()) {
115             backtrace = null;
116         } else if (!isArrayOfStrings(obj)) {
117             throw getRuntime().newTypeError("backtrace must be Array of String");
118         } else {
119             backtrace = (RubyArray) obj;
120         }
121         return backtrace();
122     }
123     
124     public RubyException exception(IRubyObject[] args) {
125         switch (args.length) {
126             case 0 :
127                 return this;
128             case 1 :
129                 if(args[0] == this) {
130                     return this;
131                 }
132                 RubyException ret = (RubyException)rbClone();
133                 ret.initialize(args, Block.NULL_BLOCK); // This looks wrong, but it's the way MRI does it.
134
return ret;
135             default :
136                 throw getRuntime().newArgumentError("Wrong argument count");
137         }
138     }
139
140     public IRubyObject to_s() {
141         if (message.isNil()) {
142             return getRuntime().newString(getMetaClass().getName());
143         }
144         message.setTaint(isTaint());
145         return (RubyString) message.callMethod(getRuntime().getCurrentContext(), "to_s");
146     }
147
148     /** inspects an object and return a kind of debug information
149      *
150      *@return A RubyString containing the debug information.
151      */

152     public IRubyObject inspect() {
153         RubyModule rubyClass = getMetaClass();
154         RubyString exception = RubyString.stringValue(this);
155
156         if (exception.getValue().length() == 0) {
157             return getRuntime().newString(rubyClass.getName());
158         }
159         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("#<");
160         sb.append(rubyClass.getName()).append(": ").append(exception.getValue()).append(">");
161         return getRuntime().newString(sb.toString());
162     }
163
164     public void printBacktrace(PrintStream JavaDoc errorStream) {
165         IRubyObject backtrace = callMethod(getRuntime().getCurrentContext(), "backtrace");
166         if (!backtrace.isNil() && backtrace instanceof RubyArray) {
167             IRubyObject[] elements = ((RubyArray)backtrace.convertToArray()).toJavaArray();
168     
169             for (int i = 1; i < elements.length; i++) {
170                 IRubyObject stackTraceLine = elements[i];
171                 if (stackTraceLine instanceof RubyString) {
172                     printStackTraceLine(errorStream, stackTraceLine);
173                 }
174     
175                 if (i == RubyException.TRACE_HEAD && elements.length > RubyException.TRACE_MAX) {
176                     int hiddenLevels = elements.length - RubyException.TRACE_HEAD - RubyException.TRACE_TAIL;
177                     errorStream.print("\t ... " + hiddenLevels + " levels...\n");
178                     i = elements.length - RubyException.TRACE_TAIL;
179                 }
180             }
181         }
182     }
183
184     private void printStackTraceLine(PrintStream JavaDoc errorStream, IRubyObject stackTraceLine) {
185         errorStream.print("\tfrom " + stackTraceLine + '\n');
186     }
187     
188     private boolean isArrayOfStrings(IRubyObject backtrace) {
189         if (!(backtrace instanceof RubyArray)) return false;
190             
191         IRubyObject[] elements = ((RubyArray) backtrace).toJavaArray();
192         
193         for (int i = 0 ; i < elements.length ; i++) {
194             if (!(elements[i] instanceof RubyString)) return false;
195         }
196             
197         return true;
198     }
199
200     protected IRubyObject doClone() {
201         IRubyObject newObject = new RubyException(getRuntime(),getMetaClass().getRealClass());
202         if (newObject.getType() != getMetaClass().getRealClass()) {
203             throw getRuntime().newTypeError("wrong instance allocation");
204         }
205         return newObject;
206     }
207 }
208
Popular Tags