Back
package com.futureshocked.classloader;
import java.util.HashMap;
import java.util.List;
import java.util.Iterator;
import java.util.ArrayList;
/**
* A contain for {@link InterceptedMethod}, which also has <tt>boolean</tt>
* methods that will let {@link DebuggerClassLoader} know if a class should
* be modified, and {@link DebuggerClassVisitor} know if a method should be
* modified.
*/
public class ClassTransforms {
/**
* A HashMap that contains <tt>String</tt> keys, consisting of class names,
* that map to <tt>List</tt> objects that hold {@link InterceptedMethod}.
*/
private HashMap classes;
/**
* Constructor that simply creates a new <tt>HashMap</tt> for
* <tt>this.classes</tt>.
*/
public ClassTransforms() {
classes = new HashMap();
}
/**
* Checks <tt>classes</tt> for a key equal to <tt>className</tt>. Since a
* <tt>HashMap</tt> is checked it should be the fastest way to check if
* a class needs to be modified, which is important since this will be
* called for every loaded class.
* @param className The name of the class about to be loaded.
* @return <tt>true</tt> if the class needs to be modified.
*/
public boolean modifyClass(String className) {
return classes.containsKey(className);
}
/**
* Checks to see if a method needs to be modified.
* @param className The name of the class the method belongs to.
* @param method The method being checked.
* @param desc The description of the method.
* @return <tt>true</tt> if the method needs to be modified.
*/
public boolean modifyMethod(String className, String method, String desc) {
return (getInterceptedMethod(className, method, desc) != null);
}
/**
* Returns an {@link InterceptedMethod} that matches <tt>className</tt>,
* <tt>method</tt>, and <tt>desc</tt>. See {@link InterceptedMethod} for
* information related to matching.
* @param className The name of the class the method belongs to.
* @param method The name of the method.
* @param desc The description of the method - see
* {@link ApplicationDebugger} for information about the format.
* @return <tt>null</tt> if the {@link InterceptedMethod} is not found, the
* correct object if it's found.
*/
public InterceptedMethod getInterceptedMethod(String className, String method,
String desc) {
InterceptedMethod im = null;
if (modifyClass(className)) {
List methods = getMethodsByClass(className);
if (methods != null) {
Iterator i = methods.iterator();
while ((i.hasNext()) && (im == null)) {
InterceptedMethod wantedIm = (InterceptedMethod) i.next();
// See InterceptedMethod.matches() for information on the matching
// algorithm
if (wantedIm.matches(className, method, desc))
im = wantedIm;
}
}
}
return im;
}
/**
* Returns all {@link InterceptedMethod} objects that belong to
* <tt>className</tt>.
* @param className The name of the class being queried.
* @return <tt>null</tt> if no methods are to be intercepted, a <tt>List</tt>
* of {@link InterceptedMethod} objects if any methods are to be
* intercepted.
*/
public List getMethodsByClass(String className) {
List methods = null;
if (classes.containsKey(className))
methods = (List) classes.get(className);
return methods;
}
/**
* Add a new method to be intercepted. Format should be:<br>
* <tt>java.lang.String testMethod(int arg1, com.user.package.Test arg2)</tt>
* @param code A code style method description.
* @return {@link InterceptedMethod} that will match the user specified
* method.
*/
public InterceptedMethod addCodeStyleInterceptedMethod(String code) {
MethodDescriptionUtil mdu = new MethodDescriptionUtil(code);
return addInterceptedMethod(mdu.getClassName(), mdu.getMethodName(),
mdu.getDescription());
}
/**
* Add a new method to be intercepted. This method should be used only if
* you understand the format for <tt>desc</tt>.
* @param className The name of the class the method belongs to.
* @param method The name of the method to be intercepted.
* @param desc The description of the method, see {@link ApplicationDebugger}
* for an example of the format, or the ASM documentation.
* @return {@link InterceptedMethod} that will match the user specified
* method.
*/
public InterceptedMethod addInterceptedMethod(String className, String method,
String desc) {
InterceptedMethod im = new InterceptedMethod(className, method, desc);
addInterceptedMethod(im);
return im;
}
/**
* Adds an already created {@link InterceptedMethod} object to this container.
* @param im {@link InterceptedMethod} object
*/
public void addInterceptedMethod(InterceptedMethod im) {
List methods = getMethodsByClass(im.getClassName());
if (methods == null) {
methods = new ArrayList();
}
methods.add(im);
classes.put(im.getClassName(), methods);
}
/**
* Removes an {@link InterceptedMethod} from this container.<br><br>
* This method matches using reference equality (==), rather than
* the <tt>InterceptedMethod.matches()</tt> method, so to remove an object
* the exact object should first be obtained from this container, rather
* than creating a new {@link InterceptedMethod} with the same values.
* @param im
*/
public void removeInterceptedMethod(InterceptedMethod im) {
List methods = getMethodsByClass(im.getClassName());
if (methods != null) {
Iterator i = methods.iterator();
while (i.hasNext()) {
InterceptedMethod matchedIm = (InterceptedMethod) i.next();
// maybe change this to matches()?
if (matchedIm == im)
methods.remove(matchedIm);
}
if (methods.size() < 1)
methods = null;
classes.put(im.getClassName(), methods);
}
}
}
Top |