/*
* Copyright (C) 2001 Mika Riekkinen, Joni Suominen
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package alt.jiapi.instrumentor;
import java.util.HashMap;
import org.apache.log4j.Category;
import alt.jiapi.reflect.InstructionList;
import alt.jiapi.reflect.JiapiClass;
import alt.jiapi.reflect.JiapiMethod;
/**
* This abstract class is the base class for all the instrumentors
* used by jiapi code.
*
* @author Mika Riekkinen
* @author Joni Suominen
* @version $Revision: 1.1 $ $Date: 2004/03/15 14:45:06 $
*/
public abstract class AbstractInstrumentor implements ChainInstrumentor {
private Instrumentation instrumentation;
private static Category log = alt.jiapi.Runtime.getLogCategory(AbstractInstrumentor.class);
private AbstractInstrumentor child;
/**
* Gets an InstrumentorChain, that needs to be processed before
* current Instrumentor. If an Instrumentor realizes, that in
* order for its instrumented code to work it needs some other
* instrumentation support, it may override this method to provide
* such extra needs.
*
* @return A chain, that is to be processed before current Instrumentor,
* or null if there is no need for such pre-processing.
* @see InstrumentorChain
*/
public InstrumentorChain preInstrument() {
return null;
}
/**
* Gets an InstrumentorChain, that needs to be processed after
* current Instrumentor. Instrumentor may do post-instrumentation
* to clean up or finalize instrumented code. This method is often
* called in conjunction with preInstrument().
*
* @return A chain, that is to be processed after current Instrumentor,
* or null if there is no need for such post-processing.
* @see InstrumentorChain
*/
public InstrumentorChain postInstrument() {
return null;
}
/**
* Instruments given InstructionList. Instrumentor is free to modify
* InstructionList anyway it sees fit. As long as resulting InstructionList
* is consistent with all the Java Virtual Machine constraints.<p>
*
* Some Instrumentors do not modify given InstructionList, but
* selects a smaller part, splits it into peaces, and forwards them
* one by one to the next Instrumentor in chain.<p>
*
* Once this method returns, control is transferred back to previous
* Instrumentor in chain.
*
* @see #forward(InstructionList)
*/
public abstract void instrument(InstructionList il);
/**
* This method has a package access. It is called by AbstractInstrumentor
* itself to forward a chain with given Instrumentation.
*/
void instrument(InstructionList il, Instrumentation i) {
log.info("Instrumenting with " + this);
this.instrumentation = i;
if (i == null) {
log.error("Got null instrumentation");
}
instrument(il);
}
public String toString() {
return this.getClass().getName();
}
// private HashMap preInstrumentations = new HashMap();
// private HashMap postInstrumentations = new HashMap();
/**
* Forwards given InstructionList to next Instrumentor in chain.
*
* @param il InstructionList to forward
*/
protected void forward(InstructionList il) {
if (child != null) {
JiapiClass jc = getCurrentClass();
child.setCurrentClass(jc);
InstrumentorChain pre = child.preInstrument();
if (pre != null) {
// if (preInstrumentations.get(jc.getName()) == null) {
log.debug("Pre instrumenting with " + pre);
//System.out.println(pre + ", " + il.getDeclaringMethod());
pre.instrument(jc);
// preInstrumentations.put(jc.getName(), jc);
// }
}
else {
log.debug(child + " has no need for pre-instrumentation");
}
child.instrument(il, instrumentation);
InstrumentorChain post = child.postInstrument();
if (post != null) {
// if (postInstrumentations.get(jc.getName()) == null) {
log.debug("Post instrumenting with " + post);
post.instrument(jc);
// postInstrumentations.put(jc.getName(), jc);
// }
}
else {
log.debug(child + " has no need for post-instrumentation");
}
}
}
private JiapiClass currentClass;
/**
* Gets the current JiapiClass, that instrumentation applies to.
*
* @return current class
*/
protected JiapiClass getCurrentClass() {
return currentClass;
}
/**
* Sets the current JiapiClass, that instrumentation applies to.
* This method is used internally by Jiapi framework.
* @param clazz A JiapiClass to set
*/
void setCurrentClass(JiapiClass clazz) {
this.currentClass = clazz;
}
// package access, called by chain
// void setInstrumentation(Instrumentation i) {
// this.instrumentation = i;
// }
/**
* Gets an instance of Instrumentation related to this chain.
* This method should only be called from instrument(InstructionList)
* method.
* @return Instrumentation or null, if Instrumentation has not been
* triggered.
*/
public Instrumentation getInstrumentation() {
// if(instrumentation == null) {
// instrumentation = new Instrumentation();
// }
if(instrumentation == null) {
log.warn("Instrumentation is null: " + this.getClass());
}
return instrumentation;
}
// package access for now. Purpose of these methods is to provide
// all the subsequent instrumentors in same descriptor some data
// this instrumentor is doing. Like 'just grepped 'test.Foo.foo()'
void setDescriptorData() {
}
Object/*SomeDataType*/ getDescriptorData() {
return null;
}
// package access for now. Purpose of these methods is to provide
// all the subsequent instrumentors within same context some data
// this instrumentor is doing. Like 'just grepped 'test.Foo.foo()'
void setContexData() {
}
Object/*SomeDataType*/ getContextData() {
return null;
}
// Package access - used to set/get parent-child relations
void setChild(AbstractInstrumentor i) {
this.child = i;
}
/**
* Gets the next Instrumentor in chain.
*/
ChainInstrumentor getChild() {
return child;
}
}