package rocks.inspectit.ui.rcp.editor.graph.plot;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.collections.CollectionUtils;
import org.eclipse.swt.widgets.Display;
import rocks.inspectit.shared.all.cmr.model.MethodIdent;
import rocks.inspectit.shared.all.cmr.service.ICachedDataService;
import rocks.inspectit.shared.all.communication.DefaultData;
import rocks.inspectit.shared.all.communication.data.TimerData;
import rocks.inspectit.shared.cs.cmr.service.IGlobalDataAccessService;
import rocks.inspectit.shared.cs.cmr.service.IHttpTimerDataAccessService;
import rocks.inspectit.shared.cs.cmr.service.cache.CachedDataService;
import rocks.inspectit.shared.cs.indexing.aggregation.IAggregator;
import rocks.inspectit.shared.cs.indexing.aggregation.impl.TimerDataAggregator;
import rocks.inspectit.ui.rcp.editor.inputdefinition.InputDefinition;
import rocks.inspectit.ui.rcp.editor.inputdefinition.extra.InputDefinitionExtrasMarkerFactory;
import rocks.inspectit.ui.rcp.editor.inputdefinition.extra.TimerDataChartingInputDefinitionExtra;
import rocks.inspectit.ui.rcp.formatter.TextFormatter;
/**
* {@link PlotController} for displaying many Http requests in the graph.
*
* @author Ivan Senic
*
*/
public class TimerPlotController extends AbstractTimerDataPlotController<TimerData> {
/**
* Templates that will be used for data display. Every template is one line in line chart.
*/
private List<TimerData> templates;
/**
* {@link IHttpTimerDataAccessService}.
*/
private IGlobalDataAccessService dataAccessService;
/**
* {@link CachedDataService}.
*/
private ICachedDataService cachedDataService;
/**
* {@link IAggregator}.
*/
private IAggregator<TimerData> aggregator;
/**
* List of displayed data.
*/
List<TimerData> displayedData = Collections.emptyList();
/**
* Date to display data to.
*/
Date toDate = new Date(0);
/**
* Date to display data from.
*/
Date fromDate = new Date(Long.MAX_VALUE);
/**
* Date that mark the last displayed data on the graph.
*/
Date latestDataDate = new Date(0);
/**
* {@inheritDoc}
*/
@Override
public void setInputDefinition(InputDefinition inputDefinition) {
super.setInputDefinition(inputDefinition);
if (inputDefinition.hasInputDefinitionExtra(InputDefinitionExtrasMarkerFactory.TIMER_DATA_CHARTING_EXTRAS_MARKER)) {
TimerDataChartingInputDefinitionExtra inputDefinitionExtra = inputDefinition.getInputDefinitionExtra(InputDefinitionExtrasMarkerFactory.TIMER_DATA_CHARTING_EXTRAS_MARKER);
templates = inputDefinitionExtra.getTemplates();
} else {
TimerData template = new TimerData();
template.setPlatformIdent(inputDefinition.getIdDefinition().getPlatformId());
template.setSensorTypeIdent(inputDefinition.getIdDefinition().getSensorTypeId());
template.setMethodIdent(inputDefinition.getIdDefinition().getMethodId());
template.setId(-1L);
templates = Collections.singletonList(template);
}
aggregator = new TimerDataAggregator();
dataAccessService = inputDefinition.getRepositoryDefinition().getGlobalDataAccessService();
cachedDataService = inputDefinition.getRepositoryDefinition().getCachedDataService();
}
/**
* {@inheritDoc}
*/
@Override
public boolean showLegend() {
return templates.size() > 1;
}
/**
* {@inheritDoc}
*/
@SuppressWarnings("unchecked")
@Override
public void update(Date from, Date to) {
List<DefaultData> templates = new ArrayList<DefaultData>(this.templates);
// complete load if we have no data, or wanted time range is completely outside the current
boolean completeLoad = CollectionUtils.isEmpty(displayedData) || fromDate.after(to) || toDate.before(from);
// left append if currently displayed from date is after the new from date
boolean leftAppend = fromDate.after(from);
// right append if the currently displayed to date is before new to date or the date of the
// last data is before new date
boolean rightAppend = toDate.before(to) || latestDataDate.before(to);
if (completeLoad) {
List<TimerData> timerDatas = (List<TimerData>) dataAccessService.getTemplatesDataObjectsFromToDate(templates, from, to);
if (CollectionUtils.isNotEmpty(timerDatas)) {
fromDate = (Date) from.clone();
toDate = (Date) to.clone();
}
displayedData = timerDatas;
} else {
if (rightAppend) {
Date startingFrom = new Date(latestDataDate.getTime() + 1);
List<TimerData> timerDatas = (List<TimerData>) dataAccessService.getTemplatesDataObjectsFromToDate(templates, startingFrom, to);
if (CollectionUtils.isNotEmpty(timerDatas)) {
displayedData.addAll(timerDatas);
toDate = (Date) to.clone();
}
}
if (leftAppend) {
Date endingTo = new Date(fromDate.getTime() - 1);
List<TimerData> timerDatas = (List<TimerData>) dataAccessService.getTemplatesDataObjectsFromToDate(templates, from, endingTo);
if (CollectionUtils.isNotEmpty(timerDatas)) {
displayedData.addAll(0, timerDatas);
fromDate = (Date) from.clone();
}
}
}
// update the last displayed data
if (CollectionUtils.isNotEmpty(displayedData)) {
latestDataDate = new Date(displayedData.get(displayedData.size() - 1).getTimeStamp().getTime());
}
Map<Object, List<TimerData>> map = new HashMap<>();
for (TimerData data : displayedData) {
List<TimerData> list = map.get(getSeriesKey(data));
if (null == list) {
list = new ArrayList<>();
map.put(getSeriesKey(data), list);
}
list.add(data);
}
for (Entry<Object, List<TimerData>> entry : map.entrySet()) {
entry.setValue(adjustSamplingRate(entry.getValue(), from, to, aggregator));
}
// update plots in UI thread
final Map<Object, List<TimerData>> finalMap = map;
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
setDurationPlotData(finalMap);
setCountPlotData(finalMap);
// if we have only one list then we pass it to the root editor so that sub-views can
// set it
if (1 == finalMap.size()) {
final List<? extends DefaultData> datas = finalMap.entrySet().iterator().next().getValue();
getRootEditor().setDataInput(datas);
} else {
getRootEditor().setDataInput(Collections.<DefaultData> emptyList());
}
}
});
}
/**
* {@inheritDoc}
*/
@Override
protected Comparable<?> getSeriesKey(TimerData template) {
MethodIdent methodIdent = cachedDataService.getMethodIdentForId(template.getMethodIdent());
return TextFormatter.getMethodString(methodIdent);
}
/**
* {@inheritDoc}
*/
@Override
protected List<TimerData> getTemplates() {
return templates;
}
}