/*
* Copyright (c) 2005-2010 KOM – Multimedia Communications Lab
*
* This file is part of PeerfactSim.KOM.
*
* PeerfactSim.KOM is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* PeerfactSim.KOM 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PeerfactSim.KOM. If not, see .
*
*/
package de.tud.kom.p2psim.impl.analyzer.metric.filter;
import java.util.LinkedList;
import java.util.List;
import de.tudarmstadt.maki.simonstrator.api.Host;
import de.tudarmstadt.maki.simonstrator.api.Monitor;
import de.tudarmstadt.maki.simonstrator.api.Monitor.Level;
import de.tudarmstadt.maki.simonstrator.api.common.metric.AbstractMetric;
import de.tudarmstadt.maki.simonstrator.api.common.metric.ActiveMetric;
import de.tudarmstadt.maki.simonstrator.api.common.metric.ActiveMetric.ActiveMetricListener;
import de.tudarmstadt.maki.simonstrator.api.common.metric.Metric;
import de.tudarmstadt.maki.simonstrator.api.common.metric.Metric.MetricUnit;
import de.tudarmstadt.maki.simonstrator.api.common.metric.Metric.MetricValue;
import de.tudarmstadt.maki.simonstrator.api.common.metric.MetricFilter;
/**
* Base class of a {@link MetricFilter}
*
* @author Bjoern Richerzhagen
* @version 1.0, 08.08.2012
*/
public abstract class AbstractFilter>
implements MetricFilter {
private final String name;
private final LinkedList> incomingMetrics = new LinkedList>();
private final LinkedList> outgoingMetrics = new LinkedList>();
private final LinkedList outgoingActiveMetrics = new LinkedList();
private String[] blacklist = null;
private String[] whitelist = null;
public AbstractFilter(String name) {
this.name = name;
}
public AbstractFilter() {
this.name = getClass().getSimpleName();
}
protected boolean inFilter(Metric metric, String[] filter) {
for (int i = 0; i < filter.length; i++) {
String string = filter[i];
if (metric.getName().equals(string)) {
return true;
}
if (string.endsWith("*")) {
// prefix matching
String mName = metric.getName();
if (mName.startsWith(string.substring(0, string.length()-1))) {
return true;
}
}
if (string.startsWith("*")) {
// postfix matching
String mName = metric.getName();
if (mName.endsWith(string.substring(1, string.length()))) {
return true;
}
}
}
return false;
}
@Override
public final void initialize(List> metrics, List hosts) {
for (Metric metric : metrics) {
if (blacklist != null && inFilter(metric, blacklist)) {
continue;
}
if (whitelist != null && !inFilter(metric, whitelist)) {
continue;
}
incomingMetrics.add(metric);
}
if (incomingMetrics.isEmpty()) {
Monitor.log(getClass(), Level.WARN, "["+this.getName()+"] No incoming metrics configured! Available metrics are: "
+ metrics.toString(), this);
System.err.println("["+this.getName()+"] No incoming metrics configured! Available metrics are: "
+ metrics.toString() );
return;
}
onInitialize(incomingMetrics);
for (Metric> metric : outgoingMetrics) {
metric.initialize(hosts);
}
}
/**
* Called with the filtered list of metrics. Call createDerivedMetric once
* or multiple times in this method!
*
* @param incomingMetrics
*/
protected abstract void onInitialize(List> incomingMetrics);
/**
* Call this to create a derived metric out of the specified metrics
*
* @param incomingMetrics
* all incoming metrics that are used by the resulting metric
* @param isOverallMetric
* false, if this is a per-host metric
* @param unit
* Metric unit
* @param description
* @param isActiveMetric
* is this metric active, i.e. does the filter actively update
* the metric in defined intervals or on other defined actions
*/
protected void createDerivedMetric(List> incomingMetrics,
boolean isOverallMetric, MetricUnit unit, String description,
boolean isActiveMetric) {
DerivedMetric m = null;
if (isActiveMetric) {
DerivedActiveMetric am = new DerivedActiveMetric(this, description,
unit, isOverallMetric, incomingMetrics);
outgoingActiveMetrics.add(am);
m = am;
} else {
m = new DerivedMetric(this, description, unit, isOverallMetric,
incomingMetrics);
}
outgoingMetrics.add(m);
}
/**
* Create a derived metric out of a single incoming metric.
*
* @param incomingMetric
* @param isOverallMetric
* @param unit
* @param description
* @param isActiveMetric
* is this metric active, i.e. does the filter actively update
* the metric in defined intervals or on other defined actions
*/
protected void createDerivedMetric(Metric> incomingMetric,
boolean isOverallMetric, MetricUnit unit, String description,
boolean isActiveMetric) {
List> metrics = new LinkedList>();
metrics.add(incomingMetric);
createDerivedMetric(metrics, isOverallMetric, unit, description,
isActiveMetric);
}
@Override
public final List> getOutputMetrics() {
return outgoingMetrics;
}
@Override
public final List> getInputMetrics() {
return incomingMetrics;
}
@Override
public String getName() {
return name;
}
/**
* This is invoked once for overall metrics and multiple times for per-host
* metrics.
*
* @param derivedMetric
* the derived metric
* @param inputs
* @param host
* or null if it is an overall metric
* @return
*/
protected abstract M getDerivedMetricValueFor(Metric> derivedMetric,
List> inputs, Host host);
/**
* Class for a derived metric.
*
* @author Bjoern Richerzhagen
* @version 1.0, 08.08.2012
* @param
*/
private class DerivedMetric extends AbstractMetric {
private final List> incoming = new LinkedList>();
private final boolean isOverallMetric;
public DerivedMetric(AbstractFilter filter, String description,
MetricUnit unit, boolean isOverallMetric,
List> incomingMetrics) {
super(getNameForDerivedMetric(incomingMetrics), description, unit);
this.isOverallMetric = isOverallMetric;
incoming.addAll(incomingMetrics);
}
@Override
public void initialize(List hosts) {
if (isOverallMetric) {
M overall = getDerivedMetricValueFor(DerivedMetric.this,
incoming, null);
if (overall != null) {
setOverallMetric(overall);
}
} else {
for (Host host : hosts) {
M perHost = getDerivedMetricValueFor(DerivedMetric.this,
incoming, host);
if (perHost != null) {
addHost(host, perHost);
}
}
}
}
@Override
public boolean isOverallMetric() {
return isOverallMetric;
}
}
/**
* Class for a derived metric that implements the active metric interface
*
* @author Bjoern Richerzhagen
* @version 1.0, 13.08.2012
*/
private class DerivedActiveMetric extends DerivedMetric
implements ActiveMetric {
private final List listeners;
public DerivedActiveMetric(AbstractFilter filter, String description,
MetricUnit unit, boolean isOverallMetric,
List> incomingMetrics) {
super(filter, description, unit, isOverallMetric, incomingMetrics);
listeners = new LinkedList();
}
@Override
public void addActiveMetricListener(ActiveMetricListener listener) {
listeners.add(listener);
}
protected void notifyListenersOfUpdate() {
for (ActiveMetricListener listener : listeners) {
listener.onMetricUpdate(DerivedActiveMetric.this);
}
}
}
/**
* Call this to notify all {@link ActiveMetricListener}s of an update of one
* or many {@link ActiveMetric}s
*/
protected void notifyListenersOfUpdate() {
for (DerivedActiveMetric am : outgoingActiveMetrics) {
am.notifyListenersOfUpdate();
}
}
/**
* Use this to name your derived metric.
*
* @param inputs
* @return
*/
protected String getNameForDerivedMetric(List> inputs) {
String str = getName();
for (Metric metric : inputs) {
str += "_" + metric.getName();
}
return str;
}
/**
* List of Metrics
*
* @param blacklist
*/
public void setBlacklist(String blacklist) {
this.blacklist = blacklist.split(";|;\\n");
for (String string : this.blacklist)
string = string.replaceAll("\\s+", "");
}
public void setWhitelist(String whitelist) {
this.whitelist = whitelist.split(";|;\\n");
for (int i = 0; i < this.whitelist.length; i++)
this.whitelist[i] = this.whitelist[i].replaceAll("\\s+", "");
}
}