com.caucho.java.ScriptStackTrace Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of resin-kernel Show documentation
Show all versions of resin-kernel Show documentation
Kernel for Resin Java Application Server
The newest version!
/*
* Copyright (c) 1998-2012 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.java;
import com.caucho.bytecode.Attribute;
import com.caucho.bytecode.ByteCodeParser;
import com.caucho.bytecode.JavaClass;
import com.caucho.bytecode.OpaqueAttribute;
import com.caucho.loader.SimpleLoader;
import com.caucho.util.L10N;
import com.caucho.util.Log;
import com.caucho.vfs.ReadStream;
import com.caucho.vfs.Vfs;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.WeakHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Prints a stack trace using JSR-45
*/
public class ScriptStackTrace {
private static final L10N L = new L10N(ScriptStackTrace.class);
private static final Logger log = Log.open(ScriptStackTrace.class);
private static WeakHashMap _scriptMap
= new WeakHashMap();
/**
* Filter a stack trace, replacing names.
*/
public static void printStackTrace(Throwable e, PrintWriter out)
{
StackTraceElement lastHead = null;
ClassLoader loader = SimpleLoader.create(WorkDir.getLocalWorkDir());
while (true) {
if (e.getMessage() != null)
out.println(e.getClass().getName() + ": " + e.getMessage());
else
out.println(e.getClass().getName());
StackTraceElement []trace = e.getStackTrace();
StackTraceElement nextHead = trace.length > 0 ? trace[0] : null;
for (int i = 0; i < trace.length; i++) {
if (trace[i].equals(lastHead))
break;
out.print("\tat ");
printStackTraceElement(trace[i], out, loader);
}
lastHead = nextHead;
Throwable cause = e.getCause();
if (cause != null) {
out.print("Caused by: ");
e = cause;
}
else
break;
}
}
/**
* Prints a single stack trace element.
*/
private static void printStackTraceElement(StackTraceElement trace,
PrintWriter out,
ClassLoader loader)
{
try {
LineMap map = getScriptLineMap(trace.getClassName(), loader);
if (map != null) {
LineMap.Line line = map.getLine(trace.getLineNumber());
if (line != null) {
out.print(trace.getClassName() + "." + trace.getMethodName());
out.print("(" + line.getSourceFilename() + ":");
out.println(line.getSourceLine(trace.getLineNumber()) + ")");
return;
}
}
} catch (Throwable e) {
}
out.println(trace);
}
/**
* Loads the local line map for a class.
*/
public static LineMap getScriptLineMap(String className, ClassLoader loader)
{
try {
Class cl = loader.loadClass(className);
LineMap map = _scriptMap.get(cl);
if (map == null) {
map = loadScriptMap(cl);
_scriptMap.put(cl, map);
}
return map;
} catch (Throwable e) {
return null;
}
}
/**
* Loads the script map for a class
*/
private static LineMap loadScriptMap(Class cl)
{
ClassLoader loader = cl.getClassLoader();
if (loader == null)
return new LineMap(); // null map
try {
String pathName = cl.getName().replace('.', '/') + ".class";
InputStream is = loader.getResourceAsStream(pathName);
if (is == null)
return null;
try {
JavaClass jClass = new ByteCodeParser().parse(is);
Attribute attr = jClass.getAttribute("SourceDebugExtension");
if (attr == null) {
int p = cl.getName().indexOf('$');
if (p > 0) {
String className = cl.getName().substring(0, p);
return loadScriptMap(loader.loadClass(className));
}
return new LineMap();
}
else if (attr instanceof OpaqueAttribute) {
byte []value = ((OpaqueAttribute) attr).getValue();
ByteArrayInputStream bis = new ByteArrayInputStream(value);
ReadStream rs = Vfs.openRead(bis);
rs.setEncoding("UTF-8");
try {
return parseSmap(rs);
} finally {
rs.close();
}
}
else
throw new IllegalStateException(L.l("Expected opaque attribute at '{0}'",
attr));
} finally {
if (is != null)
is.close();
}
} catch (Throwable e) {
log.log(Level.FINER, e.toString(), e);
return new LineMap(); // null map
}
}
/**
* Parses the SMAP file.
*/
private static LineMap parseSmap(ReadStream is)
throws IOException
{
String smap = is.readln();
if (! smap.equals("SMAP"))
throw new IOException(L.l("Illegal header"));
String outputFile = is.readln().trim();
String defaultStratum = is.readln().trim();
String stratum = defaultStratum;
HashMap fileMap = new HashMap();
LineMap lineMap = new LineMap(outputFile);
loop:
while (true) {
int ch = is.read();
if (ch < 0)
break;
if (ch != '*')
throw new IOException(L.l("unexpected character '{0}'",
String.valueOf((char) ch)));
int code = is.read();
String value = is.readln();
switch (code) {
case 'E':
break loop;
case 'S':
stratum = value.trim();
break;
case 'F':
while ((ch = is.read()) > 0 && ch != '*') {
if (ch == '+') {
String first = is.readln().trim();
String second = is.readln().trim();
int p = first.indexOf(' ');
String key = first.substring(0, p);
String file = first.substring(p + 1).trim();
if (fileMap.size() == 0)
fileMap.put("", second);
fileMap.put(key, second);
}
else {
String first = is.readln().trim();
int p = first.indexOf(' ');
String key = first.substring(0, p);
String file = first.substring(p + 1).trim();
if (fileMap.size() == 0)
fileMap.put("", file);
fileMap.put(key, file);
}
}
if (ch == '*')
is.unread();
break;
case 'L':
while ((ch = is.read()) != '*' && ch > 0) {
is.unread();
String line = is.readln().trim();
addMap(line, fileMap, lineMap);
}
if (ch == '*')
is.unread();
break;
default:
while ((ch = is.read()) != '*') {
is.readln();
}
if (ch == '*')
is.unread();
break;
}
}
return lineMap;
}
private static void addMap(String line,
HashMap fileMap,
LineMap lineMap)
{
int colon = line.indexOf(':');
if (colon < 0)
return;
int hash = line.indexOf('#');
int startLine = 0;
String fileId = "";
int repeatCount = 1;
if (hash < 0)
startLine = Integer.parseInt(line.substring(0, colon));
else {
startLine = Integer.parseInt(line.substring(0, hash));
int comma = line.indexOf(',', hash);
if (comma > 0 && comma < colon) {
fileId = line.substring(hash + 1, comma).trim();
repeatCount = Integer.parseInt(line.substring(comma + 1, colon));
}
else
fileId = line.substring(hash + 1, colon).trim();
}
int outputLine = -1;
int outputIncrement = 1;
int comma = line.indexOf(',', colon);
if (comma > 0) {
outputLine = Integer.parseInt(line.substring(colon + 1, comma));
outputIncrement = Integer.parseInt(line.substring(comma + 1));
}
else
outputLine = Integer.parseInt(line.substring(colon + 1));
String file = fileMap.get(fileId);
lineMap.addLine(startLine, file, repeatCount, outputLine, outputIncrement);
}
}