001: /*
002: * PnutsException.java
003: *
004: * Copyright (c) 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * See the file "LICENSE.txt" for information on usage and redistribution
007: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
008: */
009: package pnuts.lang;
010:
011: import java.io.PrintStream;
012: import java.io.PrintWriter;
013: import java.io.StringWriter;
014: import java.util.Enumeration;
015: import java.util.Vector;
016:
017: /**
018: * This is a wrapper class for Exception to be thrown.
019: *
020: * @author Toyokazu Tomatsu
021: */
022: public class PnutsException extends RuntimeException {
023:
024: static final long serialVersionUID = -5567045200989654942L;
025:
026: /**
027: * @serial
028: */
029: protected int line;
030:
031: /**
032: * @serial
033: */
034: protected int column;
035:
036: /**
037: * @serial
038: */
039: protected Object file;
040:
041: /**
042: * @serial
043: */
044: protected Throwable throwable;
045:
046: /**
047: * @serial
048: */
049: protected String contextName;
050:
051: protected transient Vector trace;
052:
053: protected transient Object operation;
054:
055: /**
056: * Constructor
057: */
058: public PnutsException() {
059: this ("");
060: }
061:
062: /**
063: * Constructor
064: *
065: * @param msg
066: * the error message
067: */
068: public PnutsException(String msg) {
069: super (msg);
070: throwable = this ;
071: }
072:
073: /**
074: * Constructor
075: *
076: * @param msg
077: * the error message
078: * @param context
079: * the context in which the error occurs
080: */
081: public PnutsException(String msg, Context context) {
082: this (msg);
083:
084: // while (context.eval && context.parent != null) {
085: // context = context.parent;
086: // }
087: this .file = context.getScriptSource();
088: this .line = context.beginLine;
089: this .column = context.beginColumn;
090: this .contextName = context.getName();
091: }
092:
093: /**
094: * This constructor creates a PnutsException using i18n resources in
095: * pnuts.properties.
096: */
097: public PnutsException(String key, Object param[], Context context) {
098: this ("pnuts.lang.pnuts", key, param, context);
099: }
100:
101: /**
102: * This constructor creates a PnutsException using i18n resources in
103: * pnuts.properties.
104: */
105: public PnutsException(String bundleName, String key,
106: Object param[], Context context) {
107: this (Runtime.getMessage(bundleName, key, param), context);
108: }
109:
110: /**
111: * @deprecated replaced by PnutsException(Throwable, Context)
112: */
113: public PnutsException(Throwable t) {
114: this .throwable = t;
115: }
116:
117: /**
118: * Constructor
119: *
120: * @param t
121: * a Throwable
122: * @param context
123: * the context
124: */
125: public PnutsException(Throwable t, Context context) {
126: // while (context.eval && context.parent != null) {
127: // context = context.parent;
128: // }
129:
130: if (t instanceof PnutsException) {
131: PnutsException p = (PnutsException) t;
132: this .throwable = p.throwable;
133: this .trace = p.trace;
134: this .file = p.file;
135: this .line = p.line;
136: this .column = p.column;
137: } else if (t instanceof ParseException) {
138: this .throwable = t;
139: this .line = ((ParseException) t).getErrorLine();
140: this .column = ((ParseException) t).getErrorColumn();
141: this .file = context.getScriptSource();
142: } else {
143: this .throwable = t;
144: this .line = context.beginLine;
145: this .column = context.beginColumn;
146: this .file = context.getScriptSource();
147: }
148: this .contextName = context.getName();
149: }
150:
151: /**
152: * Constructor
153: *
154: * @deprecated
155: * @param t
156: * a Throwable
157: * @param operation
158: * a Method or a Constructor
159: * @param context
160: * the context
161: */
162: public PnutsException(Throwable t, Object operation, Context context) {
163:
164: // while (context.eval && context.parent != null) {
165: // context = context.parent;
166: // }
167:
168: if (t instanceof PnutsException) {
169: PnutsException p = (PnutsException) t;
170: this .throwable = p.throwable;
171: this .trace = p.trace;
172: this .file = p.file;
173: this .line = p.line;
174: this .column = p.column;
175: } else if (t instanceof ParseException) {
176: this .throwable = t;
177: this .line = ((ParseException) t).getErrorLine();
178: this .column = ((ParseException) t).getErrorColumn();
179: this .file = context.getScriptSource();
180: } else {
181: this .throwable = t;
182: this .line = context.beginLine;
183: this .column = context.beginColumn;
184: this .file = context.getScriptSource();
185: }
186: this .contextName = context.getName();
187: this .operation = operation;
188: }
189:
190: public String getMessage() {
191: if (throwable != null && throwable != this ) {
192: return throwable.getMessage();
193: } else {
194: return super .getMessage();
195: }
196: }
197:
198: /**
199: * Returns the root cause
200: */
201: public Throwable getThrowable() {
202: return throwable;
203: }
204:
205: String position() {
206: StringBuffer buf = new StringBuffer();
207: if (file != null || contextName != null) {
208: buf.append('[');
209: if (contextName != null) {
210: buf.append(contextName + ", ");
211: }
212: if (file != null) {
213: buf.append(file);
214: if (line > 0) {
215: buf.append(" line: " + line);
216: }
217: if (column > 0) {
218: buf.append(" column: " + column);
219: }
220: } else if (line > 0) {
221: buf.append("line: " + line);
222: if (column > 0) {
223: buf.append(" column: " + column);
224: }
225: }
226: buf.append(']');
227: }
228: if (buf.length() > 0) {
229: buf.append(":\n");
230: }
231: return buf.toString();
232: }
233:
234: /**
235: * Returns an enumeration of PnutsException.TraceInfo objects
236: */
237: public Enumeration getBackTrace() {
238: if (trace != null) {
239: return trace.elements();
240: } else {
241: return null;
242: }
243: }
244:
245: void printBackTrace(PrintWriter pw, String indent) {
246: for (Enumeration e = trace.elements(); e.hasMoreElements();) {
247: pw.print(indent);
248: Object elem = e.nextElement();
249: if (elem == this ) {
250: pw.println(getClass() + "@"
251: + System.identityHashCode(this ));
252: } else {
253: pw.println(elem);
254: }
255: }
256: }
257:
258: String trace() {
259: StringWriter sw = new StringWriter();
260: printBackTrace(new PrintWriter(sw), " ");
261: return sw.toString();
262: }
263:
264: public void printStackTrace(PrintWriter writer) {
265: if (throwable != null && throwable != this ) {
266: throwable.printStackTrace(writer);
267: } else {
268: super .printStackTrace(writer);
269: }
270: }
271:
272: public void printStackTrace(PrintStream ps) {
273: if (throwable != null && throwable != this ) {
274: throwable.printStackTrace(ps);
275: } else {
276: super .printStackTrace(ps);
277: }
278: }
279:
280: /**
281: * Returns the line number where the error occured.
282: */
283: public int getLine() {
284: return line;
285: }
286:
287: /**
288: * Returns the column number where the error occured.
289: * -1: unknown
290: */
291: public int getColumn() {
292: return column;
293: }
294:
295: /**
296: * Returns the script source (usually a URL) where the error occured.
297: */
298: public Object getScriptSource() {
299: return file;
300: }
301:
302: void backtrace(TraceInfo traceInfo) {
303: if (trace == null) {
304: trace = new Vector();
305: }
306: trace.addElement(traceInfo);
307: }
308:
309: public String toString() {
310: String s = position();
311: if (trace != null) {
312: s += trace();
313: }
314: if (operation != null) {
315: s += operation.toString() + "->";
316: }
317: return s + throwable.getClass().getName() + " : "
318: + throwable.getMessage();
319: }
320:
321: /**
322: * A node of a call-chain, which represents a position of a certain function
323: * call
324: */
325: public static class TraceInfo {
326: Object target;
327:
328: Object frame;
329:
330: Object[] arguments;
331:
332: Object scriptSource;
333:
334: int line;
335:
336: int column;
337:
338: protected TraceInfo() {
339: }
340:
341: /**
342: * Constructor
343: *
344: * @param frame the function's name or the class of the constructor
345: * @param args the arguments
346: * @param scriptSource the object from which the script was read
347: * @param line the line
348: * @param column the column
349: */
350: public TraceInfo(Object frame, Object[] args,
351: Object scriptSource, int line, int column) {
352: this (null, frame, args, scriptSource, line, column);
353: }
354:
355: /**
356: * Constructor
357: *
358: * @param target the target object
359: * @param methodName the method name
360: * @param args the arguments
361: * @param scriptSource the object from which the script was read
362: * @param line the line
363: * @param column the column
364: */
365: public TraceInfo(Object target, Object methodName,
366: Object[] args, Object scriptSource, int line, int column) {
367: this .target = target;
368: this .frame = methodName;
369: this .arguments = args;
370: this .scriptSource = scriptSource;
371: this .line = line;
372: this .column = column;
373: }
374:
375: /**
376: * Gets the source of the script where the function call was taken
377: * place. It is usually a URL object, though the script source could be
378: * any object.
379: */
380: public Object getScriptSource() {
381: return scriptSource;
382: }
383:
384: /**
385: * The actual arguments of the function call
386: */
387: public Object[] getArguments() {
388: return (Object[]) arguments.clone();
389: }
390:
391: /**
392: * The line number of the place where the function call was taken place.
393: */
394: public int getLine() {
395: return line;
396: }
397:
398: /**
399: * The column number of the place where the function call was taken place.
400: */
401: public int getColumn() {
402: return column;
403: }
404:
405: /**
406: * Gets the callee that throws an exception.
407: *
408: * @return either of a function name, method name, or Class object.
409: */
410: public Object getFrame() {
411: return frame;
412: }
413:
414: /**
415: * Gets the target object of the method call that causes an exception
416: *
417: * @return the target object of the method call that causes an exception
418: */
419: public Object getTargetObject() {
420: return target;
421: }
422:
423: public String toString() {
424: StringBuffer sbuf = new StringBuffer();
425: if (target != null) {
426: try {
427: sbuf.append(Pnuts.format(target));
428: } catch (Throwable t) {
429: sbuf.append("?");
430: }
431: sbuf.append(".");
432: }
433: sbuf.append(String.valueOf(frame));
434: try {
435: String args = Runtime.format(arguments, 64);
436: sbuf.append("(" + args.substring(1, args.length() - 1)
437: + ")");
438: } catch (Throwable tt) {
439: sbuf.append("(?)");
440: }
441: if (scriptSource != null) {
442: sbuf.append(" [");
443: sbuf.append(scriptSource);
444: sbuf.append(':');
445: sbuf.append(" line: " + line);
446: if (column >= 0) {
447: sbuf.append(" column: " + column);
448: }
449: sbuf.append(']');
450: }
451: return sbuf.toString();
452: }
453: }
454: }
|