import java.text.SimpleDateFormat; | import java.text.SimpleDateFormat; | ||||
import java.util.Collection; | import java.util.Collection; | ||||
import java.util.Date; | import java.util.Date; | ||||
import java.util.regex.Pattern; | |||||
import org.aspectj.bridge.IMessage.Kind; | import org.aspectj.bridge.IMessage.Kind; | ||||
public abstract class AbstractTrace implements Trace { | public abstract class AbstractTrace implements Trace { | ||||
protected Class tracedClass; | |||||
private static final Pattern packagePrefixPattern = Pattern.compile("([^.])[^.]*(\\.)"); | |||||
protected Class<?> tracedClass; | |||||
private static SimpleDateFormat timeFormat; | private static SimpleDateFormat timeFormat; | ||||
message.append(formatDate(now)).append(" "); | message.append(formatDate(now)).append(" "); | ||||
message.append(Thread.currentThread().getName()).append(" "); | message.append(Thread.currentThread().getName()).append(" "); | ||||
message.append(kind).append(" "); | message.append(kind).append(" "); | ||||
message.append(className); | |||||
message.append(formatClassName(className)); | |||||
message.append(".").append(methodName); | message.append(".").append(methodName); | ||||
if (thiz != null) message.append(" ").append(formatObj(thiz)); | if (thiz != null) message.append(" ").append(formatObj(thiz)); | ||||
if (args != null) message.append(" ").append(formatArgs(args)); | if (args != null) message.append(" ").append(formatArgs(args)); | ||||
return message.toString(); | return message.toString(); | ||||
} | } | ||||
/** | |||||
* @param className full dotted class name | |||||
* @return short version of class name with package collapse to initials | |||||
*/ | |||||
private String formatClassName(String className) { | |||||
return packagePrefixPattern.matcher(className).replaceAll("$1."); | |||||
} | |||||
protected String formatMessage(String kind, String text, Throwable th) { | protected String formatMessage(String kind, String text, Throwable th) { | ||||
StringBuffer message = new StringBuffer(); | StringBuffer message = new StringBuffer(); | ||||
Date now = new Date(); | Date now = new Date(); | ||||
* NullPointerExceptions or highly verbose results. | * NullPointerExceptions or highly verbose results. | ||||
* | * | ||||
* @param obj parameter to be formatted | * @param obj parameter to be formatted | ||||
* @return the formated parameter | |||||
* @return the formatted parameter | |||||
*/ | */ | ||||
protected Object formatObj(Object obj) { | protected Object formatObj(Object obj) { | ||||
} | } | ||||
else try { | else try { | ||||
/* Classes can provide an alternative implementation of toString() */ | |||||
// Classes can provide an alternative implementation of toString() | |||||
if (obj instanceof Traceable) { | if (obj instanceof Traceable) { | ||||
Traceable t = (Traceable)obj; | |||||
return t.toTraceString(); | |||||
return ((Traceable)obj).toTraceString(); | |||||
} | } | ||||
/* Use classname@hashcode */ | |||||
else return obj.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(obj)); | |||||
// classname@hashcode | |||||
else return formatClassName(obj.getClass().getName()) + "@" + Integer.toHexString(System.identityHashCode(obj)); | |||||
/* Object.hashCode() can be override and may thow an exception */ | /* Object.hashCode() can be override and may thow an exception */ | ||||
} catch (Exception ex) { | } catch (Exception ex) { |
import java.io.PrintStream; | import java.io.PrintStream; | ||||
public class DefaultTrace extends AbstractTrace { | public class DefaultTrace extends AbstractTrace { | ||||
private boolean traceEnabled = false; | private boolean traceEnabled = false; | ||||
private PrintStream print = System.err; | private PrintStream print = System.err; | ||||
public DefaultTrace (Class clazz) { | |||||
public DefaultTrace(Class clazz) { | |||||
super(clazz); | super(clazz); | ||||
} | } | ||||
public boolean isTraceEnabled () { | |||||
public boolean isTraceEnabled() { | |||||
return traceEnabled; | return traceEnabled; | ||||
} | } | ||||
public void setTraceEnabled (boolean b) { | |||||
public void setTraceEnabled(boolean b) { | |||||
traceEnabled = b; | traceEnabled = b; | ||||
} | } | ||||
public void enter (String methodName, Object thiz, Object[] args) { | |||||
public void enter(String methodName, Object thiz, Object[] args) { | |||||
if (traceEnabled) { | if (traceEnabled) { | ||||
println(formatMessage(">",tracedClass.getName(),methodName,thiz, args)); | |||||
println(formatMessage(">", tracedClass.getName(), methodName, thiz, args)); | |||||
} | } | ||||
} | } | ||||
public void enter (String methodName, Object thiz) { | |||||
public void enter(String methodName, Object thiz) { | |||||
if (traceEnabled) { | if (traceEnabled) { | ||||
println(formatMessage(">",tracedClass.getName(),methodName,thiz, null)); | |||||
println(formatMessage(">", tracedClass.getName(), methodName, thiz, null)); | |||||
} | } | ||||
} | } | ||||
public void exit (String methodName, Object ret) { | |||||
public void exit(String methodName, Object ret) { | |||||
if (traceEnabled) { | if (traceEnabled) { | ||||
println(formatMessage("<",tracedClass.getName(),methodName,ret, null)); | |||||
println(formatMessage("<", tracedClass.getName(), methodName, ret, null)); | |||||
} | } | ||||
} | } | ||||
public void exit (String methodName) { | |||||
public void exit(String methodName) { | |||||
if (traceEnabled) { | if (traceEnabled) { | ||||
println(formatMessage("<",tracedClass.getName(),methodName,null, null)); | |||||
println(formatMessage("<", tracedClass.getName(), methodName, null, null)); | |||||
} | } | ||||
} | } | ||||
public void exit(String methodName, Throwable th) { | public void exit(String methodName, Throwable th) { | ||||
if (traceEnabled) { | if (traceEnabled) { | ||||
println(formatMessage("<",tracedClass.getName(),methodName,th, null)); | |||||
println(formatMessage("<", tracedClass.getName(), methodName, th, null)); | |||||
} | } | ||||
} | } | ||||
public void event(String methodName, Object thiz, Object[] args) { | public void event(String methodName, Object thiz, Object[] args) { | ||||
if (traceEnabled) { | if (traceEnabled) { | ||||
println(formatMessage("-",tracedClass.getName(),methodName,thiz, args)); | |||||
println(formatMessage("-", tracedClass.getName(), methodName, thiz, args)); | |||||
} | } | ||||
} | } | ||||
public void event(String methodName) { | public void event(String methodName) { | ||||
if (traceEnabled) { | if (traceEnabled) { | ||||
println(formatMessage("-",tracedClass.getName(),methodName,null,null)); | |||||
println(formatMessage("-", tracedClass.getName(), methodName, null, null)); | |||||
} | } | ||||
} | } | ||||
public void debug (String message) { | |||||
println(formatMessage("?",message,null)); | |||||
public void debug(String message) { | |||||
println(formatMessage("?", message, null)); | |||||
} | } | ||||
public void info(String message) { | public void info(String message) { | ||||
println(formatMessage("I",message,null)); | |||||
println(formatMessage("I", message, null)); | |||||
} | } | ||||
public void warn (String message, Throwable th) { | |||||
println(formatMessage("W",message,th)); | |||||
if (th != null) th.printStackTrace(); | |||||
public void warn(String message, Throwable th) { | |||||
println(formatMessage("W", message, th)); | |||||
if (th != null) | |||||
th.printStackTrace(); | |||||
} | } | ||||
public void error (String message, Throwable th) { | |||||
println(formatMessage("E",message,th)); | |||||
if (th != null) th.printStackTrace(); | |||||
public void error(String message, Throwable th) { | |||||
println(formatMessage("E", message, th)); | |||||
if (th != null) | |||||
th.printStackTrace(); | |||||
} | } | ||||
public void fatal (String message, Throwable th) { | |||||
println(formatMessage("X",message,th)); | |||||
if (th != null) th.printStackTrace(); | |||||
public void fatal(String message, Throwable th) { | |||||
println(formatMessage("X", message, th)); | |||||
if (th != null) | |||||
th.printStackTrace(); | |||||
} | } | ||||
/** | /** | ||||
* Template method that allows choice of destination for output | * Template method that allows choice of destination for output | ||||
* | * | ||||
* @param s message to be traced | |||||
* @param s | |||||
* message to be traced | |||||
*/ | */ | ||||
protected void println (String s) { | |||||
protected void println(String s) { | |||||
print.println(s); | print.println(s); | ||||
} | } | ||||
public void setPrintStream (PrintStream printStream) { | |||||
public void setPrintStream(PrintStream printStream) { | |||||
this.print = printStream; | this.print = printStream; | ||||
} | } | ||||
// private static boolean isTracingEnabled = getBoolean("org.aspectj.weaver.tools.tracing",false); | |||||
// | |||||
// private static boolean getBoolean (String name, boolean def) { | |||||
// String defaultValue = String.valueOf(def); | |||||
// String value = System.getProperty(name,defaultValue); | |||||
// return Boolean.valueOf(value).booleanValue(); | |||||
// } | |||||
// private static boolean isTracingEnabled = | |||||
// getBoolean("org.aspectj.weaver.tools.tracing",false); | |||||
// | |||||
// private static boolean getBoolean (String name, boolean def) { | |||||
// String defaultValue = String.valueOf(def); | |||||
// String value = System.getProperty(name,defaultValue); | |||||
// return Boolean.valueOf(value).booleanValue(); | |||||
// } | |||||
} | } |
public interface Trace { | public interface Trace { | ||||
public void enter (String methodName, Object thiz, Object[] args); | |||||
public void enter(String methodName, Object thiz, Object[] args); | |||||
public void enter (String methodName, Object thiz); | |||||
public void enter(String methodName, Object thiz); | |||||
public void exit (String methodName, Object ret); | |||||
public void exit(String methodName, Object ret); | |||||
public void exit (String methodName, Throwable th); | |||||
public void exit(String methodName, Throwable th); | |||||
public void exit (String methodName); | |||||
public void exit(String methodName); | |||||
public void event (String methodName); | |||||
public void event(String methodName); | |||||
public void event (String methodName, Object thiz, Object[] args); | |||||
public void debug (String message); | |||||
public void info (String message); | |||||
public void event(String methodName, Object thiz, Object[] args); | |||||
public void warn (String message); | |||||
public void debug(String message); | |||||
public void warn (String message, Throwable th); | |||||
public void info(String message); | |||||
public void error (String message); | |||||
public void warn(String message); | |||||
public void error (String message, Throwable th); | |||||
public void warn(String message, Throwable th); | |||||
public void fatal (String message); | |||||
public void error(String message); | |||||
public void fatal (String message, Throwable th); | |||||
/* | |||||
* Convenience methods | |||||
*/ | |||||
public void enter (String methodName, Object thiz, Object arg); | |||||
public void error(String message, Throwable th); | |||||
public void enter (String methodName, Object thiz, boolean z); | |||||
public void fatal(String message); | |||||
public void exit (String methodName, boolean b); | |||||
public void fatal(String message, Throwable th); | |||||
public void exit (String methodName, int i); | |||||
public void enter(String methodName, Object thiz, Object arg); | |||||
public void event (String methodName, Object thiz, Object arg); | |||||
public boolean isTraceEnabled (); | |||||
public void enter(String methodName, Object thiz, boolean z); | |||||
public void setTraceEnabled (boolean b); | |||||
public void exit(String methodName, boolean b); | |||||
public void exit(String methodName, int i); | |||||
public void event(String methodName, Object thiz, Object arg); | |||||
public boolean isTraceEnabled(); | |||||
public void setTraceEnabled(boolean b); | |||||
} | } |
return javaClass; | return javaClass; | ||||
} | } | ||||
/** | |||||
* @return true if built from bytes obtained from somewhere. False if built from bytes retrieved from disk. | |||||
*/ | |||||
public boolean isArtificial() { | public boolean isArtificial() { | ||||
return artificial; | return artificial; | ||||
} | } |
if (file == null) { | if (file == null) { | ||||
return null; | return null; | ||||
} | } | ||||
ClassParser parser = new ClassParser(file.getInputStream(), file.getPath()); | ClassParser parser = new ClassParser(file.getInputStream(), file.getPath()); | ||||
JavaClass jc = parser.parse(); | JavaClass jc = parser.parse(); | ||||
return jc; | return jc; | ||||
} catch (IOException ioe) { | } catch (IOException ioe) { | ||||
if (trace.isTraceEnabled()) { | |||||
trace.error("IOException whilst processing class",ioe); | |||||
} | |||||
return null; | return null; | ||||
} finally { | } finally { | ||||
if (file != null) { | if (file != null) { | ||||
} | } | ||||
} | } | ||||
// public BcelObjectType addSourceObjectType(JavaClass jc) { | |||||
// return addSourceObjectType(jc.getClassName(), jc, -1); | |||||
// } | |||||
public BcelObjectType addSourceObjectType(JavaClass jc, boolean artificial) { | public BcelObjectType addSourceObjectType(JavaClass jc, boolean artificial) { | ||||
return addSourceObjectType(jc.getClassName(), jc, artificial); | return addSourceObjectType(jc.getClassName(), jc, artificial); | ||||
} | } | ||||
} | } | ||||
String signature = UnresolvedType.forName(jc.getClassName()).getSignature(); | String signature = UnresolvedType.forName(jc.getClassName()).getSignature(); | ||||
ResolvedType fromTheMap = typeMap.get(signature); | |||||
ResolvedType resolvedTypeFromTypeMap = typeMap.get(signature); | |||||
if (fromTheMap != null && !(fromTheMap instanceof ReferenceType)) { | |||||
if (resolvedTypeFromTypeMap != null && !(resolvedTypeFromTypeMap instanceof ReferenceType)) { | |||||
// what on earth is it then? See pr 112243 | // what on earth is it then? See pr 112243 | ||||
StringBuffer exceptionText = new StringBuffer(); | StringBuffer exceptionText = new StringBuffer(); | ||||
exceptionText.append("Found invalid (not a ReferenceType) entry in the type map. "); | exceptionText.append("Found invalid (not a ReferenceType) entry in the type map. "); | ||||
exceptionText.append("Signature=[" + signature + "] Found=[" + fromTheMap + "] Class=[" + fromTheMap.getClass() + "]"); | |||||
exceptionText.append("Signature=[" + signature + "] Found=[" + resolvedTypeFromTypeMap + "] Class=[" + resolvedTypeFromTypeMap.getClass() + "]"); | |||||
throw new BCException(exceptionText.toString()); | throw new BCException(exceptionText.toString()); | ||||
} | } | ||||
ReferenceType nameTypeX = (ReferenceType) fromTheMap; | |||||
ReferenceType referenceTypeFromTypeMap = (ReferenceType) resolvedTypeFromTypeMap; | |||||
if (nameTypeX == null) { | |||||
if (referenceTypeFromTypeMap == null) { | |||||
if (jc.isGeneric() && isInJava5Mode()) { | if (jc.isGeneric() && isInJava5Mode()) { | ||||
ReferenceType rawType = ReferenceType.fromTypeX(UnresolvedType.forRawTypeName(jc.getClassName()), this); | ReferenceType rawType = ReferenceType.fromTypeX(UnresolvedType.forRawTypeName(jc.getClassName()), this); | ||||
ret = buildBcelDelegate(rawType, jc, artificial, true); | ret = buildBcelDelegate(rawType, jc, artificial, true); | ||||
rawType.setGenericType(genericRefType); | rawType.setGenericType(genericRefType); | ||||
typeMap.put(signature, rawType); | typeMap.put(signature, rawType); | ||||
} else { | } else { | ||||
nameTypeX = new ReferenceType(signature, this); | |||||
ret = buildBcelDelegate(nameTypeX, jc, artificial, true); | |||||
typeMap.put(signature, nameTypeX); | |||||
referenceTypeFromTypeMap = new ReferenceType(signature, this); | |||||
ret = buildBcelDelegate(referenceTypeFromTypeMap, jc, artificial, true); | |||||
typeMap.put(signature, referenceTypeFromTypeMap); | |||||
} | } | ||||
} else { | } else { | ||||
ret = buildBcelDelegate(nameTypeX, jc, artificial, true); | |||||
ret = buildBcelDelegate(referenceTypeFromTypeMap, jc, artificial, true); | |||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
public BcelObjectType addSourceObjectType(String classname, byte[] bytes, boolean artificial) { | public BcelObjectType addSourceObjectType(String classname, byte[] bytes, boolean artificial) { | ||||
BcelObjectType ret = null; | |||||
BcelObjectType retval = null; | |||||
String signature = UnresolvedType.forName(classname).getSignature(); | String signature = UnresolvedType.forName(classname).getSignature(); | ||||
ResolvedType fromTheMap = typeMap.get(signature); | |||||
ResolvedType resolvedTypeFromTypeMap = typeMap.get(signature); | |||||
if (fromTheMap != null && !(fromTheMap instanceof ReferenceType)) { | |||||
if (resolvedTypeFromTypeMap != null && !(resolvedTypeFromTypeMap instanceof ReferenceType)) { | |||||
// what on earth is it then? See pr 112243 | // what on earth is it then? See pr 112243 | ||||
StringBuffer exceptionText = new StringBuffer(); | StringBuffer exceptionText = new StringBuffer(); | ||||
exceptionText.append("Found invalid (not a ReferenceType) entry in the type map. "); | exceptionText.append("Found invalid (not a ReferenceType) entry in the type map. "); | ||||
exceptionText.append("Signature=[" + signature + "] Found=[" + fromTheMap + "] Class=[" + fromTheMap.getClass() + "]"); | |||||
exceptionText.append("Signature=[" + signature + "] Found=[" + resolvedTypeFromTypeMap + "] Class=[" + resolvedTypeFromTypeMap.getClass() + "]"); | |||||
throw new BCException(exceptionText.toString()); | throw new BCException(exceptionText.toString()); | ||||
} | } | ||||
ReferenceType nameTypeX = (ReferenceType) fromTheMap; | |||||
ReferenceType referenceTypeFromTypeMap = (ReferenceType) resolvedTypeFromTypeMap; | |||||
if (nameTypeX == null) { | |||||
if (referenceTypeFromTypeMap == null) { | |||||
JavaClass jc = Utility.makeJavaClass(classname, bytes); | JavaClass jc = Utility.makeJavaClass(classname, bytes); | ||||
if (jc.isGeneric() && isInJava5Mode()) { | if (jc.isGeneric() && isInJava5Mode()) { | ||||
nameTypeX = ReferenceType.fromTypeX(UnresolvedType.forRawTypeName(jc.getClassName()), this); | |||||
ret = buildBcelDelegate(nameTypeX, jc, artificial, true); | |||||
referenceTypeFromTypeMap = ReferenceType.fromTypeX(UnresolvedType.forRawTypeName(jc.getClassName()), this); | |||||
retval = buildBcelDelegate(referenceTypeFromTypeMap, jc, artificial, true); | |||||
ReferenceType genericRefType = new ReferenceType(UnresolvedType.forGenericTypeSignature(signature, | ReferenceType genericRefType = new ReferenceType(UnresolvedType.forGenericTypeSignature(signature, | ||||
ret.getDeclaredGenericSignature()), this); | |||||
nameTypeX.setDelegate(ret); | |||||
genericRefType.setDelegate(ret); | |||||
nameTypeX.setGenericType(genericRefType); | |||||
typeMap.put(signature, nameTypeX); | |||||
retval.getDeclaredGenericSignature()), this); | |||||
referenceTypeFromTypeMap.setDelegate(retval); | |||||
genericRefType.setDelegate(retval); | |||||
referenceTypeFromTypeMap.setGenericType(genericRefType); | |||||
typeMap.put(signature, referenceTypeFromTypeMap); | |||||
} else { | } else { | ||||
nameTypeX = new ReferenceType(signature, this); | |||||
ret = buildBcelDelegate(nameTypeX, jc, artificial, true); | |||||
typeMap.put(signature, nameTypeX); | |||||
referenceTypeFromTypeMap = new ReferenceType(signature, this); | |||||
retval = buildBcelDelegate(referenceTypeFromTypeMap, jc, artificial, true); | |||||
typeMap.put(signature, referenceTypeFromTypeMap); | |||||
} | } | ||||
} else { | } else { | ||||
Object o = nameTypeX.getDelegate(); | |||||
if (!(o instanceof BcelObjectType)) { | |||||
throw new IllegalStateException("For " + classname + " should be BcelObjectType, but is " + o.getClass()); | |||||
} | |||||
ret = (BcelObjectType) o; | |||||
// byte[] bs = ret.javaClass.getBytes(); | |||||
// if (bs.length != bytes.length) { | |||||
// throw new RuntimeException(""); | |||||
// } | |||||
// If the type is already exposed to the weaver (ret.isExposedToWeaver()) then this is likely | |||||
// to be a hotswap reweave so build a new delegate, dont accidentally use the old data | |||||
if (ret.isArtificial() || ret.isExposedToWeaver()) { | |||||
// System.out.println("Rebuilding " + nameTypeX.getName()); | |||||
ret = buildBcelDelegate(nameTypeX, Utility.makeJavaClass(classname, bytes), artificial, true); | |||||
} else { | |||||
ret.setExposedToWeaver(true); | |||||
ReferenceTypeDelegate existingDelegate = referenceTypeFromTypeMap.getDelegate(); | |||||
if (!(existingDelegate instanceof BcelObjectType)) { | |||||
throw new IllegalStateException("For " + classname + " should be BcelObjectType, but is " + existingDelegate.getClass()); | |||||
} | } | ||||
retval = (BcelObjectType) existingDelegate; | |||||
// Note1: If the type is already exposed to the weaver (retval.isExposedToWeaver()) then this is likely | |||||
// to be a hotswap reweave so build a new delegate, don't accidentally use the old data. | |||||
// Note2: Also seen when LTW and another agent precedes the AspectJ agent. Earlier in LTW | |||||
// a type is resolved (and ends up in the typemap but not exposed to the weaver at that time) | |||||
// then later LTW actually is attempted on this type. We end up here with different | |||||
// bytes to the current delegate if the earlier agent has modified them. See PR488216 | |||||
// if (retval.isArtificial() || retval.isExposedToWeaver()) { | |||||
retval = buildBcelDelegate(referenceTypeFromTypeMap, Utility.makeJavaClass(classname, bytes), artificial, true); | |||||
// } | |||||
} | } | ||||
return ret; | |||||
return retval; | |||||
} | } | ||||
void deleteSourceObjectType(UnresolvedType ty) { | void deleteSourceObjectType(UnresolvedType ty) { |