001: /*
002: * Copyright (c) 2002-2006 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.xwork;
006:
007: import java.io.BufferedReader;
008: import java.io.InputStream;
009: import java.io.InputStreamReader;
010:
011: import java.util.List;
012: import java.util.ArrayList;
013:
014: import java.net.URL;
015:
016: import com.opensymphony.xwork.util.location.Locatable;
017: import com.opensymphony.xwork.util.location.Location;
018: import com.opensymphony.xwork.util.location.LocationUtils;
019:
020: /**
021: * A generic runtime exception that optionally contains Location information
022: *
023: * @author Jason Carreira
024: */
025: public class XworkException extends RuntimeException implements
026: Locatable {
027:
028: private Location location;
029:
030: /**
031: * Constructs a <code>XworkException</code> with no detail message.
032: */
033: public XworkException() {
034: }
035:
036: /**
037: * Constructs a <code>XworkException</code> with the specified
038: * detail message.
039: *
040: * @param s the detail message.
041: */
042: public XworkException(String s) {
043: this (s, null, null);
044: }
045:
046: /**
047: * Constructs a <code>XworkException</code> with the specified
048: * detail message and target.
049: *
050: * @param s the detail message.
051: * @param target the target of the exception.
052: */
053: public XworkException(String s, Object target) {
054: this (s, (Throwable) null, target);
055: }
056:
057: /**
058: * Constructs a <code>XworkException</code> with the root cause
059: *
060: * @param cause The wrapped exception
061: */
062: public XworkException(Throwable cause) {
063: this (null, cause, null);
064: }
065:
066: /**
067: * Constructs a <code>XworkException</code> with the root cause and target
068: *
069: * @param cause The wrapped exception
070: * @param target The target of the exception
071: */
072: public XworkException(Throwable cause, Object target) {
073: this (null, cause, target);
074: }
075:
076: /**
077: * Constructs a <code>XworkException</code> with the specified
078: * detail message and exception cause.
079: *
080: * @param s the detail message.
081: * @param cause the wrapped exception
082: */
083: public XworkException(String s, Throwable cause) {
084: this (s, cause, null);
085: }
086:
087: /**
088: * Constructs a <code>XworkException</code> with the specified
089: * detail message, cause, and target
090: *
091: * @param s the detail message.
092: * @param cause The wrapped exception
093: * @param target The target of the exception
094: */
095: public XworkException(String s, Throwable cause, Object target) {
096: super (s, cause);
097:
098: this .location = LocationUtils.getLocation(target);
099: if (this .location == Location.UNKNOWN) {
100: this .location = LocationUtils.getLocation(cause);
101: }
102: }
103:
104: /**
105: * Gets the underlying cause
106: *
107: * @deprecated Use getCause()
108: */
109: public Throwable getThrowable() {
110: return getCause();
111: }
112:
113: /**
114: * Gets the location of the error, if available
115: */
116: public Location getLocation() {
117: return this .location;
118: }
119:
120: /**
121: * Gets a source code snippet with the default padding
122: */
123: public List getSnippet() {
124: return getSnippet(2);
125: }
126:
127: /**
128: * Gets a source code snippet with the default padding
129: *
130: * @param padding The amount of lines before and after the error to include
131: */
132: public List getSnippet(int padding) {
133: List snippet = new ArrayList();
134: if (location != null && location.getLineNumber() > 0) {
135: try {
136: InputStream in = new URL(location.getURI())
137: .openStream();
138: BufferedReader reader = new BufferedReader(
139: new InputStreamReader(in));
140:
141: int lineno = 0;
142: int errno = location.getLineNumber();
143: String line;
144: while ((line = reader.readLine()) != null) {
145: lineno++;
146: if (lineno >= errno - padding
147: && lineno <= errno + padding) {
148: snippet.add(line);
149: }
150: }
151: } catch (Exception ex) {
152: // ignoring as snippet not available isn't a big deal
153: }
154: }
155: return snippet;
156: }
157:
158: /**
159: * Returns a short description of this throwable object, including the
160: * location. If no detailed message is available, it will use the message
161: * of the underlying exception if available.
162: *
163: * @return a string representation of this <code>Throwable</code>.
164: */
165: public String toString() {
166: String msg = getMessage();
167: if (msg == null && getCause() != null) {
168: msg = getCause().getMessage();
169: }
170:
171: if (location != null) {
172: if (msg != null) {
173: return msg + " - " + location.toString();
174: } else {
175: return location.toString();
176: }
177: } else {
178: return msg;
179: }
180: }
181: }
|