001: /* Copyright (C) 2004 - 2007 db4objects Inc. http://www.db4o.com
002:
003: This file is part of the db4o open source object database.
004:
005: db4o is free software; you can redistribute it and/or modify it under
006: the terms of version 2 of the GNU General Public License as published
007: by the Free Software Foundation and as clarified by db4objects' GPL
008: interpretation policy, available at
009: http://www.db4o.com/about/company/legalpolicies/gplinterpretation/
010: Alternatively you can write to db4objects, Inc., 1900 S Norfolk Street,
011: Suite 350, San Mateo, CA 94403, USA.
012:
013: db4o is distributed in the hope that it will be useful, but WITHOUT ANY
014: WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: for more details.
017:
018: You should have received a copy of the GNU General Public License along
019: with this program; if not, write to the Free Software Foundation, Inc.,
020: 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
021: package com.db4o.test.util;
022:
023: import java.io.*;
024:
025: import com.db4o.foundation.*;
026:
027: /**
028: * simple annotated stack trace for debugging
029: *
030: * @exclude
031: */
032: public class StackTrace {
033: // ignore top 2 lines: exception name and 'StackTrace#<init>'
034: private static final int IGNORELINES = 2;
035: // 0: trace line, 1: case info (or null)
036: private String[][] _trace;
037: // cache hashcode for faster equals()
038: private int _hash;
039:
040: public StackTrace(int exclude, String caseInfo, StackTrace old) {
041: String traceStr = readStackTrace(new Throwable());
042: Collection4 split = parseStackTrace(exclude, traceStr);
043: _trace = buildStackTrace(split, caseInfo);
044: copyCaseInfo(old);
045: }
046:
047: private void copyCaseInfo(StackTrace old) {
048: if (old == null) {
049: return;
050: }
051: int length = (_trace.length < old._trace.length ? _trace.length
052: : old._trace.length);
053: for (int idx = 0; idx < length; idx++) {
054: if (!trace(idx).equals(old.trace(idx))) {
055: break;
056: }
057: if (old.caseInfo(idx) != null && caseInfo(idx) == null) {
058: _trace[idx][1] = old.caseInfo(idx);
059: }
060: }
061: }
062:
063: public boolean equals(Object obj) {
064: if (this == obj) {
065: return true;
066: }
067: if (obj == null || getClass() != obj.getClass()) {
068: return false;
069: }
070: StackTrace casted = (StackTrace) obj;
071: if (hashCode() != casted.hashCode()) {
072: return false;
073: }
074: if (_trace.length != casted._trace.length) {
075: return false;
076: }
077: for (int idx = 0; idx < _trace.length; idx++) {
078: if (!trace(idx).equals(casted.trace(idx))) {
079: return false;
080: }
081: if ((caseInfo(idx) != null)
082: ^ (casted.caseInfo(idx) != null)) {
083: return false;
084: }
085: if (caseInfo(idx) != null
086: && !caseInfo(idx).equals(casted.caseInfo(idx))) {
087: return false;
088: }
089: }
090: return true;
091: }
092:
093: public int hashCode() {
094: if (_hash != 0) {
095: return _hash;
096: }
097: int hash = 0;
098: for (int idx = 0; idx < _trace.length; idx++) {
099: hash = 29 * hash + trace(idx).hashCode();
100: if (caseInfo(idx) != null) {
101: hash = 29 * hash + caseInfo(idx).hashCode();
102: }
103: }
104: _hash = hash;
105: return hash;
106: }
107:
108: public String toString() {
109: StringBuffer buf = new StringBuffer();
110: for (int idx = 0; idx < _trace.length; idx++) {
111: if (idx > 0) {
112: buf.append('\n');
113: }
114: buf.append(trace(idx));
115: if (caseInfo(idx) != null) {
116: buf.append('\n');
117: buf.append("[" + caseInfo(idx) + "]");
118: }
119: }
120: return buf.toString();
121: }
122:
123: private String trace(int idx) {
124: return _trace[idx][0];
125: }
126:
127: private String caseInfo(int idx) {
128: return _trace[idx][1];
129: }
130:
131: private String readStackTrace(Throwable exc) {
132: StringWriter writer = new StringWriter();
133: exc.printStackTrace(new PrintWriter(writer));
134: return writer.toString();
135: }
136:
137: private Collection4 parseStackTrace(int exclude, String traceStr) {
138: Collection4 split = new Collection4();
139: int nlIdx = traceStr.indexOf('\n');
140: for (int i = 0; i < (IGNORELINES + exclude); i++) {
141: traceStr = traceStr.substring(nlIdx + 1);
142: nlIdx = traceStr.indexOf('\n');
143: if (nlIdx < 0) {
144: break;
145: }
146: }
147: while (nlIdx > -1) {
148: String cur = traceStr.substring(0, nlIdx);
149: split.add(cleanUpTraceLine(cur));
150: traceStr = traceStr.substring(nlIdx + 1);
151: nlIdx = traceStr.indexOf('\n');
152: }
153: // last one is empty (trailing newline)
154: return split;
155: }
156:
157: private String[][] buildStackTrace(Collection4 split,
158: String caseInfo) {
159: String[][] trace = new String[split.size()][2];
160: Iterator4 iter = split.iterator();
161: for (int idx = 0; idx < trace.length; idx++) {
162: iter.moveNext();
163: trace[idx][0] = (String) iter.current();
164: }
165: trace[trace.length - 1][1] = caseInfo;
166: return trace;
167: }
168:
169: private String cleanUpTraceLine(String str) {
170: int atIdx = str.indexOf("at ");
171: if (atIdx >= 0) {
172: str = str.substring(atIdx + 3);
173: }
174: int colonIdx = str.lastIndexOf(':');
175: if (colonIdx >= 0) {
176: str = str.substring(0, colonIdx) + ')';
177: }
178: return str;
179: }
180: }
|