001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.core.transaction;
017:
018: import java.io.PrintStream;
019: import java.io.PrintWriter;
020:
021: /**
022: * Subclass of javax.transaction.TransactionRolledbackException which adds init cause to the exception.
023: */
024: public class TransactionRolledbackException extends
025: javax.transaction.TransactionRolledbackException {
026: private Throwable cause = this ;
027:
028: public TransactionRolledbackException() {
029: super ();
030: fillInStackTrace();
031: }
032:
033: public TransactionRolledbackException(String detailMessage) {
034: super (detailMessage);
035: }
036:
037: /**
038: * Constructs a new instance of this class with its walkback, message and
039: * cause filled in.
040: *
041: * @param detailMessage String The detail message for the exception.
042: * @param throwable The cause of this Throwable
043: */
044: public TransactionRolledbackException(String detailMessage,
045: Throwable throwable) {
046: super (detailMessage);
047: cause = throwable;
048: }
049:
050: public TransactionRolledbackException(Throwable throwable) {
051: super (throwable == null ? null : throwable.toString());
052: cause = throwable;
053: }
054:
055: /**
056: * Answers the extra information message which was provided when the
057: * throwable was created. If no message was provided at creation time, then
058: * answer null. Subclasses may override this method to answer localized text
059: * for the message.
060: *
061: * @return String The receiver's message.
062: */
063: public String getLocalizedMessage() {
064: return getMessage();
065: }
066:
067: /**
068: * Outputs a printable representation of the receiver's walkback on the
069: * System.err stream.
070: */
071: public void printStackTrace() {
072: printStackTrace(System.err);
073: }
074:
075: /**
076: * Count the number of duplicate stack frames, starting from
077: * the end of the stack.
078: *
079: * @param currentStack a stack to compare
080: * @param parentStack a stack to compare
081: * @return the number of duplicate stack frames.
082: */
083: private static int countDuplicates(
084: StackTraceElement[] currentStack,
085: StackTraceElement[] parentStack) {
086: int duplicates = 0;
087: int parentIndex = parentStack.length;
088: for (int i = currentStack.length; --i >= 0
089: && --parentIndex >= 0;) {
090: StackTraceElement parentFrame = parentStack[parentIndex];
091: if (parentFrame.equals(currentStack[i])) {
092: duplicates++;
093: } else {
094: break;
095: }
096: }
097: return duplicates;
098: }
099:
100: /**
101: * Outputs a printable representation of the receiver's walkback on the
102: * stream specified by the argument.
103: *
104: * @param err PrintStream The stream to write the walkback on.
105: */
106: public void printStackTrace(PrintStream err) {
107: err.println(toString());
108: // Don't use getStackTrace() as it calls clone()
109: // Get stackTrace, in case stackTrace is reassigned
110: StackTraceElement[] stack = getStackTrace();
111: for (int i = 0; i < stack.length; i++) {
112: err.println("\tat " + stack[i]);
113: }
114:
115: StackTraceElement[] parentStack = stack;
116: Throwable throwable = getCause();
117: while (throwable != null) {
118: err.print("Caused by: ");
119: err.println(throwable);
120: StackTraceElement[] currentStack = throwable
121: .getStackTrace();
122: int duplicates = countDuplicates(currentStack, parentStack);
123: for (int i = 0; i < currentStack.length - duplicates; i++) {
124: err.println("\tat " + currentStack[i]);
125: }
126: if (duplicates > 0) {
127: err.println("\t... " + duplicates + " more");
128: }
129: parentStack = currentStack;
130: throwable = throwable.getCause();
131: }
132: }
133:
134: /**
135: * Outputs a printable representation of the receiver's walkback on the
136: * writer specified by the argument.
137: *
138: * @param err PrintWriter The writer to write the walkback on.
139: */
140: public void printStackTrace(PrintWriter err) {
141: err.println(toString());
142: // Don't use getStackTrace() as it calls clone()
143: // Get stackTrace, in case stackTrace is reassigned
144: StackTraceElement[] stack = getStackTrace();
145: for (int i = 0; i < stack.length; i++) {
146: err.println("\tat " + stack[i]);
147: }
148:
149: StackTraceElement[] parentStack = stack;
150: Throwable throwable = getCause();
151: while (throwable != null) {
152: err.print("Caused by: ");
153: err.println(throwable);
154: StackTraceElement[] currentStack = throwable
155: .getStackTrace();
156: int duplicates = countDuplicates(currentStack, parentStack);
157: for (int i = 0; i < currentStack.length - duplicates; i++) {
158: err.println("\tat " + currentStack[i]);
159: }
160: if (duplicates > 0) {
161: err.println("\t... " + duplicates + " more");
162: }
163: parentStack = currentStack;
164: throwable = throwable.getCause();
165: }
166: }
167:
168: /**
169: * Answers a string containing a concise, human-readable description of the
170: * receiver.
171: *
172: * @return String a printable representation for the receiver.
173: */
174: public String toString() {
175: String msg = getLocalizedMessage();
176: String name = getClass().getName();
177: if (msg == null) {
178: return name;
179: }
180: return new StringBuffer(name.length() + 2 + msg.length())
181: .append(name).append(": ").append(msg).toString();
182: }
183:
184: /**
185: * Initialize the cause of the receiver. The cause cannot be reassigned.
186: *
187: * @param throwable The cause of this Throwable
188: * @return the receiver.
189: * @throws IllegalArgumentException when the cause is the receiver
190: * @throws IllegalStateException when the cause has already been initialized
191: */
192: public synchronized TransactionRolledbackException initCause(
193: Throwable throwable) {
194: cause = throwable;
195: return this ;
196: }
197:
198: /**
199: * Answers the cause of this Throwable, or null if there is no cause.
200: *
201: * @return Throwable The receiver's cause.
202: */
203: public Throwable getCause() {
204: if (cause == this) {
205: return null;
206: }
207: return cause;
208: }
209: }
|