/*
* 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.event;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import alt.jiapi.InstrumentationContext;
import alt.jiapi.InstrumentationDescriptor;
import alt.jiapi.instrumentor.ChainInstrumentor;
import alt.jiapi.instrumentor.InstrumentorChain;
import alt.jiapi.instrumentor.FieldAccessStrategy;
import alt.jiapi.instrumentor.HeadInstrumentor;
import alt.jiapi.instrumentor.Hook;
import alt.jiapi.instrumentor.MethodDispatcherInstrumentor;
import alt.jiapi.instrumentor.MethodCallInstrumentor;
import alt.jiapi.instrumentor.GrepInstrumentor;
import alt.jiapi.instrumentor.TailInstrumentor;
/**
* This class registers itself to Jiapi runtime and tracks field
* accesses. That is, gets and sets. When either event happens it will
* notify each listeners that has been registered.
*
* @author Mika Riekkinen
* @author Joni Suominen
* @version $Revision: 1.10 $ $Date: 2004/03/21 12:50:07 $
*/
public class FieldEventProducer extends EventProducer {
private List listeners = new ArrayList();
/**
* Constructor. Resolution is set to '*', which indicates all field
* accesses are trapped.
*
* @param id Instrumentation decsriptor, that this FieldEventProducer
* registers itself to.
*/
public FieldEventProducer(InstrumentationDescriptor id) {
this(id, "*");
}
/**
* Constructor. Given resolution is compared to name of the field,
* and if it matches, a FieldEvent is produced.
*
* @param id Instrumentation decsriptor, that this FieldEventProducer
* registers itself to.
* @param resolution Resolution that is used in deciding whether or not
* an event should be produced.
*/
public FieldEventProducer(InstrumentationDescriptor id, String resolution) {
super(resolution);
id.addInstrumentor(new FieldEventInstrumentor(this));
if (true) {
return;
}
try {
// InstrumentationContext ctx = new InstrumentationContext();
ChainInstrumentor setDispatcher = new MethodDispatcherInstrumentor();
GrepInstrumentor grepWriteAccess =
// Following line fixes bug that we instrument
// on field accesses that were synthesized by Jiapi itself.
new GrepInstrumentor(new FieldAccessStrategy("*__jiapi_field*", true, FieldAccessStrategy.WRITE_ACCESS));
grepWriteAccess.setResolutions(getResolutions());
ChainInstrumentor afterSet = new TailInstrumentor();
ChainInstrumentor callFieldSet =
new MethodCallInstrumentor(new FieldSetHook(this));
InstrumentorChain setChain = new InstrumentorChain();
setChain.add(setDispatcher);
setChain.add(grepWriteAccess);
setChain.add(afterSet);
setChain.add(callFieldSet);
ChainInstrumentor getDispatcher = new MethodDispatcherInstrumentor();
GrepInstrumentor grepReadAccess =
// Following commented line fixes bug that we instrument
// on field accesses that were synthesized by Jiapi itself.
new GrepInstrumentor(new FieldAccessStrategy("*__jiapi_field*", true, FieldAccessStrategy.READ_ACCESS));
grepReadAccess.setResolutions(getResolutions());
ChainInstrumentor beforeRead = new HeadInstrumentor();
ChainInstrumentor callFieldGet =
new MethodCallInstrumentor(new FieldGetHook(this));
InstrumentorChain getChain = new InstrumentorChain();
getChain.add(getDispatcher);
getChain.add(grepReadAccess);
getChain.add(beforeRead);
getChain.add(callFieldGet);
id.addInstrumentor(getChain);
id.addInstrumentor(setChain);
} catch (Exception e) {
// NOTE! Fix exception handling.
e.printStackTrace();
}
}
/**
* Adds a FieldListener.
* @param fl a FieldListener
*/
public synchronized void addFieldListener(FieldListener fl) {
listeners.add(fl);
}
/**
* Removes a FieldListener.
* @param fl a FieldListener
*/
public synchronized void removeFieldListener(FieldListener fl) {
listeners.remove(fl);
}
/**
* This method is called by the Jiapi runtime. It should not be called
* by others.
*/
public void fieldGet(Object sourceObject, String fieldName) {
if (!isProtected(sourceObject)) {
fireFieldGetEvent(sourceObject, fieldName);
}
}
/**
* This method is called by the Jiapi runtime. It should not be called
* by others.
*/
public void fieldSet(Object sourceObject, String fieldName) {
if (!isProtected(sourceObject)) {
fireFieldSetEvent(sourceObject, fieldName);
}
}
/**
* Fires an event when a field has been accessed(set).
*
* @param sourceObject
* @param fieldName Name of the field
*/
protected synchronized void fireFieldSetEvent(Object sourceObject,
String fieldName) {
Iterator i = listeners.iterator();
FieldEvent event = new FieldEvent(this, sourceObject, fieldName,
FieldEvent.FIELD_SET);
while (i.hasNext()) {
FieldListener fl = (FieldListener)i.next();
fl.fieldSet(event);
}
}
/**
* Fires an event when a field has been accessed(get).
*
* @param sourceObject
* @param fieldName Name of the field
*/
protected synchronized void fireFieldGetEvent(Object sourceObject,
String fieldName) {
Iterator i = listeners.iterator();
FieldEvent event = new FieldEvent(this, sourceObject, fieldName,
FieldEvent.FIELD_GET);
while (i.hasNext()) {
FieldListener fl = (FieldListener)i.next();
fl.fieldGet(event);
}
}
}