/**************************************************************************************
* Copyright (C) 2008 EsperTech, Inc. All rights reserved. *
* http://esper.codehaus.org *
* http://www.espertech.com *
* ---------------------------------------------------------------------------------- *
* The software in this package is published under the terms of the GPL license *
* a copy of which has been included with this distribution in the license.txt file. *
**************************************************************************************/
package com.espertech.esper.epl.metric;
import com.espertech.esper.schedule.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.util.*;
/**
* Scheduling for metrics execution is handles=d by this service.
*/
public final class MetricScheduleService implements MetricTimeSource
{
private static final Log log = LogFactory.getLog(MetricScheduleService.class);
private final SortedMap<Long, List<MetricExec>> timeHandleMap;
// Current time - used for evaluation as well as for adding new handles
private volatile Long currentTime;
private volatile Long nearestTime;
/**
* Constructor.
*/
public MetricScheduleService()
{
this.timeHandleMap = new TreeMap<Long, List<MetricExec>>();
}
public long getCurrentTime()
{
return currentTime;
}
/**
* Clears the schedule.
*/
public void clear()
{
log.debug("Clearing scheduling service");
timeHandleMap.clear();
nearestTime = null;
}
/**
* Sets current time.
* @param currentTime to set
*/
public synchronized final void setTime(long currentTime)
{
this.currentTime = currentTime;
}
/**
* Adds an execution to the schedule.
* @param afterMSec offset to add at
* @param execution execution to add
*/
public synchronized final void add(long afterMSec, MetricExec execution)
{
if (execution == null)
{
throw new IllegalArgumentException("Unexpected parameters : null execution");
}
long triggerOnTime = currentTime + afterMSec;
List<MetricExec> handleSet = timeHandleMap.get(triggerOnTime);
if (handleSet == null)
{
handleSet = new ArrayList<MetricExec>();
timeHandleMap.put(triggerOnTime, handleSet);
}
handleSet.add(execution);
nearestTime = timeHandleMap.firstKey();
}
/**
* Evaluate the schedule and populates executions, if any.
* @param handles to populate
*/
public synchronized final void evaluate(Collection<MetricExec> handles)
{
SortedMap<Long, List<MetricExec>> headMap = timeHandleMap.headMap(currentTime + 1);
// First determine all triggers to shoot
List<Long> removeKeys = new LinkedList<Long>();
for (Map.Entry<Long, List<MetricExec>> entry : headMap.entrySet())
{
Long key = entry.getKey();
List<MetricExec> value = entry.getValue();
removeKeys.add(key);
for (MetricExec handle : value)
{
handles.add(handle);
}
}
// Remove all triggered msec values
for (Long key : removeKeys)
{
timeHandleMap.remove(key);
}
if (!timeHandleMap.isEmpty())
{
nearestTime = timeHandleMap.firstKey();
}
else
{
nearestTime = null;
}
}
/**
* Returns nearest scheduled time.
* @return nearest scheduled time, or null if none/empty schedule.
*/
public Long getNearestTime()
{
return nearestTime;
}
/**
* Remove from schedule an execution.
* @param metricExec to remove
*/
public void remove(MetricExec metricExec)
{
for (Map.Entry<Long, List<MetricExec>> entry : timeHandleMap.entrySet())
{
entry.getValue().remove(metricExec);
}
}
}