package org.jactr.tools.grapher.core;
/*
* default logging
*/
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.Executor;
import javolution.util.FastList;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jactr.core.concurrent.ExecutorServices;
import org.jactr.core.model.IModel;
import org.jactr.core.model.event.ModelEvent;
import org.jactr.core.model.event.ModelListenerAdaptor;
import org.jactr.core.utils.parameter.IParameterized;
import org.jactr.tools.grapher.core.container.IProbeContainer;
import org.jactr.tools.grapher.core.message.NetworkPackager;
import org.jactr.tools.grapher.core.parser.Parser;
import org.jactr.tools.grapher.core.probe.IPollingProbe;
import org.jactr.tools.grapher.core.probe.IProbe;
import org.jactr.tools.grapher.core.selector.ModelSelector;
import org.jactr.tools.tracer.ITraceSink;
import org.jactr.tools.tracer.listeners.ITraceListener;
import org.jactr.tools.tracer.transformer.ITransformedEvent;
public class GeneralProbe implements ITraceListener, IParameterized
{
/**
* Logger definition
*/
static private final transient Log LOGGER = LogFactory
.getLog(GeneralProbe.class);
static public final String CONFIG = "ConfigFile";
private Collection<ModelSelector> _modelSelectors;
private Map<IModel, Collection<IProbeContainer>> _topLevelContainers;
private double _timeWindow = 1;
private NetworkPackager _packager;
private ITraceSink _sink;
public GeneralProbe()
{
_modelSelectors = new ArrayList<ModelSelector>();
_topLevelContainers = new HashMap<IModel, Collection<IProbeContainer>>();
_packager = new NetworkPackager();
}
public void setTraceSink(ITraceSink sink)
{
_sink = sink;
}
public void install(IModel model, Executor executor)
{
// we ignore the recommended executor and use inline
for (ModelSelector selector : _modelSelectors)
if (selector.matches(model))
{
IProbeContainer container = selector.install(model, null);
Collection<IProbeContainer> probeContainers = _topLevelContainers
.get(model);
if (probeContainers == null)
{
probeContainers = new ArrayList<IProbeContainer>();
_topLevelContainers.put(model, probeContainers);
}
probeContainers.add(container);
// we need to poll/process inline
model.addListener(new ProbeProcessor(container),
ExecutorServices.INLINE_EXECUTOR);
}
}
public void uninstall(IModel model)
{
}
protected void processProbes(IProbeContainer topLevelContainer, double when)
{
Map<String, Object> data = new TreeMap<String, Object>();
processContainer(topLevelContainer, data);
if (LOGGER.isDebugEnabled()) LOGGER.debug("ProcessedData : " + data);
final Collection<ITransformedEvent> events = new FastList<ITransformedEvent>();
events.addAll(_packager.process(topLevelContainer.getName(), data, when,
_timeWindow));
/*
* push the networking onto the background..
*/
if (events.size() > 0)
ExecutorServices.getExecutor(ExecutorServices.BACKGROUND).execute(
new Runnable() {
public void run()
{
for (ITransformedEvent event : events)
_sink.add(event);
}
});
}
protected void processContainer(IProbeContainer container,
Map<String, Object> data)
{
String name = container.getName();
Map<String, Object> myData = new TreeMap<String, Object>();
data.put(name, myData);
if (LOGGER.isDebugEnabled()) LOGGER.debug("Processing probes " + name);
Set<String> additions = new TreeSet<String>();
Set<String> removed = new TreeSet<String>();
FastList<IProbe> probes = FastList.newInstance();
/*
* take care of the top probes first
*/
for (IProbe probe : container.getProbes(probes))
{
if (LOGGER.isDebugEnabled())
LOGGER.debug("Processing probe " + probe.getTrackedName());
if (probe instanceof IPollingProbe) ((IPollingProbe) probe).update();
Map<String, Object> changes = new TreeMap<String, Object>();
if (probe.getChanges(additions, changes, removed))
{
myData.put(probe.getTrackedName(), changes);
additions.clear();
removed.clear();
}
}
FastList.recycle(probes);
FastList<IProbeContainer> children = FastList.newInstance();
/*
* descend
*/
for (IProbeContainer child : container.getChildren(children))
processContainer(child, myData);
FastList.recycle(children);
}
public String getParameter(String key)
{
return null;
}
public Collection<String> getPossibleParameters()
{
return getSetableParameters();
}
public Collection<String> getSetableParameters()
{
return Collections.singleton(CONFIG);
}
public void setParameter(String key, String value)
{
if (CONFIG.equalsIgnoreCase(key))
try
{
URL resource = getClass().getClassLoader().getResource(value);
if (resource == null)
throw new IllegalArgumentException(
"Could not find file on classpath " + value);
Parser parser = new Parser(resource);
_timeWindow = parser.getTimeWindow();
_modelSelectors = parser.buildModelSelectors();
}
catch (Exception e)
{
LOGGER.error("Could not configure general probe ", e);
_timeWindow = 1;
_modelSelectors.clear();
_topLevelContainers.clear();
}
}
private class ProbeProcessor extends ModelListenerAdaptor
{
private double _nextCheckTime = Double.MIN_VALUE;
public IProbeContainer _container;
public ProbeProcessor(IProbeContainer container)
{
_container = container;
}
@Override
public void cycleStopped(ModelEvent event)
{
double time = event.getSimulationTime();
if (time < _nextCheckTime) return;
processProbes(_container, time);
_nextCheckTime = time + _timeWindow;
}
@Override
public void modelStopped(ModelEvent event)
{
processProbes(_container, event.getSimulationTime());
}
}
}