All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fitnesse.slim.StackTraceEnricher Maven / Gradle / Ivy

The newest version!
package fitnesse.slim;

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.security.CodeSource;
import java.util.HashMap;
import java.util.Map;

import static util.FileUtil.CHARENCODING;

public class StackTraceEnricher {
  private Map elementInformation;

  public StackTraceEnricher() {
    this.elementInformation = new HashMap<>();
  }

  public void printStackTrace(Throwable throwable) {
    try {
      printStackTrace(throwable, System.err);
    } catch (IOException ioe) {
      // Ignore.
    }
  }

  public void printStackTrace(Throwable throwable, OutputStream stream) throws IOException {
    stream.write(getStackTraceAsString(throwable).getBytes(CHARENCODING));
    stream.flush();
  }

  public void printStackTrace(Throwable throwable, Writer writer) throws IOException {
    writer.write(getStackTraceAsString(throwable));
    writer.flush();
  }

  public String getStackTraceAsString(Throwable throwable) {
    StringBuilder sb = new StringBuilder();
    Throwable t = throwable;
    if (throwable.getStackTrace() == null || throwable.getStackTrace().length == 0) {
      t = throwable.fillInStackTrace();
    }
    for (StackTraceElement ste : t.getStackTrace()) {
      sb.append("\n\tat ").append(ste.toString());
      ClassMetaInformation cmi = getMetaInformation(ste);
      sb.append(" [");
      sb.append(cmi.getLocation());
      if (!cmi.getVersion().equals(ClassMetaInformation.UNKNOWN)) {
        sb.append(":").append(cmi.getVersion());
      }
      sb.append("]");
    }
    if (throwable.getCause() != null) {
      Throwable cause = throwable.getCause();
      sb.append("\nCaused by: ").append(cause.getClass().getName()).append(": ").append(cause.getMessage());
      sb.append(getStackTraceAsString(cause));
    }
    return sb.toString();
  }

  public String getVersion(Class clazz) {
    return getMetaInformation(clazz).getVersion();
  }

  public String getVersion(StackTraceElement element) {
    return getMetaInformation(element).getVersion();
  }

  public String getLocation(Class clazz) {
    return getMetaInformation(clazz).getLocation();
  }

  public String getLocation(StackTraceElement element) {
    return getMetaInformation(element).getLocation();
  }

  private ClassMetaInformation getMetaInformation(Class clazz) {
    ClassMetaInformation information;
    if (elementInformation.containsKey(clazz.getName())) {
      information = elementInformation.get(clazz.getName());
    } else {
      information = new ClassMetaInformation(clazz);
      elementInformation.put(clazz.getName(), information);
    }
    return information;
  }

  private ClassMetaInformation getMetaInformation(StackTraceElement element) {
    ClassMetaInformation information;
    if (elementInformation.containsKey(element.getClassName())) {
      information = elementInformation.get(element.getClassName());
    } else {
      information = new ClassMetaInformation(element);
      elementInformation.put(element.getClassName(), information);
    }
    return information;
  }

  private static class ClassMetaInformation {
    private static final String UNKNOWN = "n/a";
    private static final String[] PACKAGE_PREFIXES_RTJAR = {"java.", "javax.", "sun.", "sunw.", "javafx.", "com.sun."};
    private String version = UNKNOWN;
    private String location = UNKNOWN;
    private String className = UNKNOWN;
    private String file = UNKNOWN;

    public ClassMetaInformation(Class clazz) {
      analyse(clazz.getName());
    }

    public ClassMetaInformation(StackTraceElement ste) {
      file = ste.getFileName();
      analyse(ste.getClassName());
    }

    private void analyse(String className) {
      try {
        Class elementClass = loadClass(className, ClassLoader.getSystemClassLoader());
        analyse(elementClass);
      } catch (ClassNotFoundException cnfe) {
        this.className = className;
      }
    }

    private void analyse(Class clazz) {
      className = clazz.getName();
      version = getVersion(clazz);
      location = getLocation(clazz);
    }

    public String getVersion() {
      return version;
    }

    public String getLocation() {
      return location;
    }

    private static Class loadClass(String className, ClassLoader classLoader) throws ClassNotFoundException {
      if (className == null || className.isEmpty()) {
        throw new ClassNotFoundException("Unable to load a class with an empty or null name.");
      }
      Class resolvedClass = null;
      if (classLoader != null) {
        try {
          resolvedClass = classLoader.loadClass(className);
        } catch (ClassNotFoundException e) {
          // Ignore, try to resolve the class via other class loaders.
        }
      }
      if (resolvedClass == null) {
        ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
        if (contextClassLoader != null) {
          resolvedClass = contextClassLoader.loadClass(className);
        } else {
          resolvedClass = StackTraceEnricher.class.getClassLoader().loadClass(className);
        }
      }
      return resolvedClass;
    }

    private static String getLocation(Class clazz) {
      String location = UNKNOWN;
      if (clazz != null) {
        try {
          CodeSource codeSource = clazz.getProtectionDomain().getCodeSource();
          if (codeSource != null) {
            String fullLocation = codeSource.getLocation().toString();
            if (isDirectory(fullLocation)) {
              location = fullLocation;
            } else {
              location = removeParentDirectories(fullLocation);
            }
          } else {
            for (String rtPackage : PACKAGE_PREFIXES_RTJAR) {
              if (clazz.getName().startsWith(rtPackage)) {
                location = "rt.jar";
                break;
              }
            }
          }
        } catch (Exception e) {
          // Ignore.
        }
      }
      return location;
    }

    private static String getVersion(Class clazz) {
      String version = UNKNOWN;
      if (clazz != null) {
        try {
          Package pack = clazz.getPackage();
          if (pack != null) {
            if (pack.getImplementationVersion() != null) {
              version = pack.getImplementationVersion();
            } else if (pack.getSpecificationVersion() != null) {
              version = pack.getSpecificationVersion();
            }
          }
        } catch (Exception e) {
          // Ignore.
        }
      }
      return version;
    }

    private static String removeParentDirectories(String path) {
      String parsedPath = path;
      if (path.contains("/")) {
        parsedPath = removeParentDirectories(path, "/");
      } else if (path.contains("\\")) {
        parsedPath = removeParentDirectories(path, "\\");
      }
      return parsedPath;
    }

    private static String removeParentDirectories(String path, String separator) {
      String parsedPath = path;
      if (path.contains(separator) && !path.endsWith(separator) || (path.indexOf(separator) < path.lastIndexOf
          (separator))) {
        parsedPath = parsedPath.substring(parsedPath.indexOf(separator) + 1);
        parsedPath = removeParentDirectories(parsedPath, separator);
      }
      return parsedPath;
    }

    private static boolean isDirectory(String path) {
      return path != null && (path.endsWith("/") || (path.endsWith("\\")));
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy