at.spardat.enterprise.exc.StackTrace Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2003, 2007 s IT Solutions AT Spardat GmbH .
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* s IT Solutions AT Spardat GmbH - initial API and implementation
*******************************************************************************/
// @(#) $Id: StackTrace.java 2093 2007-11-28 14:23:36Z s3460 $
package at.spardat.enterprise.exc;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.StringTokenizer;
/**
* This class provides methods that print stack traces as JDK1.4 does, i.e.,
* with a collapsed stack.
*
* @author YSD, 22.05.2003 22:19:08
*/
class StackTrace implements java.io.Serializable {
/**
* The frame lines of the stack trace. Is null, if the exception is not
* understood.
*/
private String [] lines_;
/**
* The first number of lines which does not comprise the stack frame information
*/
private int numHeaderLines_;
/**
* Indicates if this stack allows collapsing
*/
private boolean isWellFormed_;
/**
* Increase this if u make non compatible changes
*/
private static final long serialVersionUID = 1L;
/**
* Extracts the stacktrace from ex.
*/
public StackTrace (Throwable ex) {
this (getStackTraceLines(ex));
}
/**
* Constructs and checks if the provided stack trace lines are well formed.
* If this succeeds, {@link #isWellFormed} will return true and other
* methods may be called.
*/
public StackTrace (String [] lines) {
lines_ = new String[lines.length];
System.arraycopy(lines, 0, lines_, 0, lines.length);
analyze();
}
/**
* Prints the stacktrace of Throwable toPrint in a way as JDK1.4 does, i.e.,
* omitting outer frames that are in common with an enclosing exception.
*/
public void printStackTrace (PrintWriter s, StackTrace enclosing) {
if (enclosing != null) {
if (isWellFormed() && enclosing.isWellFormed()) {
// both are well formed so that we can do the smart print
String [] lines = getDifferentLines (enclosing);
for (int i=0; itoPrint in a way as JDK1.4 does, i.e.,
* omitting outer frames that are in common with an enclosing exception.
*/
public void printStackTrace (PrintStream s, StackTrace enclosing) {
if (enclosing != null) {
if (isWellFormed() && enclosing.isWellFormed()) {
// both are well formed so that we can do the smart print
String [] lines = getDifferentLines (enclosing);
for (int i=0; iwellFormed(). Returns the stack frames
* that should be printed with respect to the provided enclosing exception
* so that no stack frames are in common.
*
* @param enclosing StackFrames of the enclosing exception.
*/
private String [] getDifferentLines (StackTrace enclosing) {
if (!isWellFormed()) throw new IllegalStateException();
/**
* enclosing is not well formed, so return all lines of this
*/
if (enclosing == null || !enclosing.isWellFormed()) return lines_;
/**
* enclosing is well formed; return the lines of this but
* strip the tailing lines this has in common with enclosing.
*/
int inCommon = 0;
for (int i=lines_.length-1, j=enclosing.lines_.length-1; i >= 0 && j >= 0; i--, j--) {
if (lines_[i].equals(enclosing.lines_[j])) inCommon++;
else break;
}
if (inCommon == 0) return lines_;
else {
int different = lines_.length-inCommon;
String [] lines = new String[different+1];
System.arraycopy(lines_, 0, lines, 0, different);
lines[different] = "\t... " + inCommon + " more";
return lines;
}
}
/**
* Analyzes the lines and sets wellFormed to be true if the stack consists
* of at a block of consecutive header lines followed by a block of
* consecutive stack frame lines. Both blocks must consist of at least
* one line.
*/
private void analyze () {
boolean inStackFrameLineSection = true;
isWellFormed_ = true;
numHeaderLines_ = 0;
for (int i=lines_.length-1; i>=0; i--) {
String line = lines_[i];
if (inStackFrameLineSection) {
if (!isStackFrameLine(line)) {
// the first line bottom up which is not a frame line
inStackFrameLineSection = false;
numHeaderLines_ = i+1;
}
} else {
if (isStackFrameLine(line)) {
isWellFormed_ = false; break;
}
}
}
if (isWellFormed_) {
if (numHeaderLines_ <= 0 || numHeaderLines_ >= lines_.length) {
isWellFormed_ = false;
}
}
}
/**
* Returns true if the stack trace of the provided exception is
* well formed so that stack frames may be collapsed.
*/
public boolean isWellFormed () {
return isWellFormed_;
}
/**
* Returns the header lines. Must only be called if isWellFormed.
*/
public String [] getHeaderLines () {
if (!isWellFormed_) throw new IllegalStateException();
String [] result = new String[numHeaderLines_];
System.arraycopy(lines_, 0, result, 0, numHeaderLines_);
return result;
}
/**
* Replaces the header lines with new ones. Must only be called if isWellFormed.
*
* This method may result in this being not well formed after this call if
* the new header lines are badly formed.
*
* @param newHeader the new header lines. Array of minimum length 1.
*/
public void replaceHeaderLines (String [] newHeader) {
if (!isWellFormed_) throw new IllegalStateException();
if (newHeader.length == 0) throw new IllegalArgumentException();
String [] newLines = new String[lines_.length - numHeaderLines_ + newHeader.length];
System.arraycopy(newHeader, 0, newLines, 0, newHeader.length);
System.arraycopy(lines_, numHeaderLines_, newLines, newHeader.length, lines_.length-numHeaderLines_);
lines_ = newLines;
analyze();
}
/**
* Calls printStackTrace on ex and returns the result
* as String.
*/
public static String getStackTraceAsString (Throwable ex) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
ex.printStackTrace(pw);
pw.close();
return sw.toString();
}
/**
* Expects a string, splits the lines
* and returns an String[] with one entry per line.
*/
public static String [] splitLines (String stackTraceString) {
/**
* parse the string
*/
StringTokenizer tokizer = new StringTokenizer (stackTraceString, System.getProperty("line.separator"));
int lineCount = 0;
ArrayList lines = new ArrayList();
while (tokizer.hasMoreTokens()) {
String line = tokizer.nextToken();
lines.add(line);
lineCount++;
}
String [] linesArray = new String[lines.size()];
lines.toArray(linesArray);
return linesArray;
}
/**
* Calls printStackTrace on ex, splits the lines
* and returns them.
*/
public static String [] getStackTraceLines (Throwable ex) {
return splitLines(getStackTraceAsString(ex));
}
}