All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.anotheria.moskito.extensions.monitoring.metrics.GenericMetrics Maven / Gradle / Ivy

There is a newer version: 4.0.3
Show newest version
package net.anotheria.moskito.extensions.monitoring.metrics;

import net.anotheria.moskito.core.predefined.Constants;
import net.anotheria.moskito.core.stats.IValueHolderFactory;
import net.anotheria.moskito.core.stats.Interval;
import net.anotheria.moskito.core.stats.StatValue;
import net.anotheria.moskito.core.stats.StatValueTypes;
import net.anotheria.moskito.core.stats.TypeAwareStatValue;
import net.anotheria.moskito.core.stats.impl.SkipFirstDiffLongValueHolderFactory;
import net.anotheria.moskito.core.stats.impl.StatValueFactory;
import net.anotheria.moskito.core.stats.impl.TypeAwareStatValueImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Generic implementation of {@link IGenericMetrics} interface.
 *
 * @author dzhmud
 */
public abstract class GenericMetrics implements IGenericMetrics {

    /** Private registry of all created instances, mapped by their Class.*/
    private static final ConcurrentMap, List> registry = new ConcurrentHashMap<>();

    /**
     * Get all registered metrics of given Class.
     * @param type metrics of this class method should return.
     * @param  class type.
     * @return list of metrics of the desired type, or null if there are none.
     */
    protected static  List getMetricsOfType(Class type) {
        List metricsList = (List)registry.get(type);
        if (metricsList == null) {
            metricsList = new CopyOnWriteArrayList<>();
            List previous = (List)registry.putIfAbsent(type, metricsList);
            if (previous != null)
                metricsList = previous;
        }
        return metricsList;
    }

    /** Caption, short explanation and full explanation variables.*/
    private final String caption, shortExpl, explanation;

    /** ValueType of current metric. */
    private final StatValueTypes type;

    /** If true, value per second will be calculated. */
    private final boolean isRateMetric;

    /**
     * Shortest constructor of this class. ValueName param goes also to both explanations.
     * @param type type of the created StatValue
     * @param valueName valueName, used as caption in decorator, as metric name in MonitoringPluginConfig#metrics,
     *                  generally, as string ID of the metric.
     */
    protected GenericMetrics(StatValueTypes type, String valueName) {
        this(type, false, valueName, valueName);
    }

    /**
     * Constructor that allows adding custom explanation and short explanation.
     * @param type type of the created StatValue
     * @param valueName string ID of the metric.
     * @param strings first string goes to short explanation, second - to full explanation, next are ignored.
     */
    protected GenericMetrics(StatValueTypes type, String valueName, String ... strings ) {
        this(type, false, valueName, strings);
    }

    /**
     * Last constructor in chain. After assigning all instance variables register this instance in static registry.
     * @param type type of the created StatValue
     * @param isRateMetric boolean marker for 'rate' metrics, which means they will try to calculate value-per-second.
     * @param valueName string ID of the metric.
     * @param strings first string goes to short explanation, second - to full explanation, next are ignored.
     */
    protected GenericMetrics(StatValueTypes type, boolean isRateMetric, String valueName, String ... strings) {
        if (type == null || valueName == null)
            throw new IllegalArgumentException("StatValueType and valueName are both required!");
        this.type = type;
        this.isRateMetric = isRateMetric;
        this.caption = valueName;
        this.shortExpl = (strings == null || strings.length == 0) ? valueName : strings[0];
        this.explanation = (strings == null || strings.length < 2) ? shortExpl : strings[1];
        register(this);
    }

    private  void register(T metric) {
        Class clazz =  (Class)metric.getClass();
        if (clazz.isAnonymousClass()) {
            clazz = (Class)clazz.getSuperclass();
        }
        getMetricsOfType(clazz).add(metric);
    }

    @Override
    public StatValue createStatValue() {
        if (type != StatValueTypes.DIFFLONG) {
            return StatValueFactory.createStatValue(type, caption, Constants.getDefaultIntervals());
        } else {
            //for DIFFLONG type use upgraded diffLong value holders that ignore first interval.
            final IValueHolderFactory factory = SkipFirstDiffLongValueHolderFactory.INSTANCE;
            final TypeAwareStatValue statValue = new TypeAwareStatValueImpl(caption, type, factory);
            for (Interval interval : Constants.getDefaultIntervals()) {
                statValue.addInterval(interval);
            }
            return statValue;
        }
    }

    /**
     * Get logger for current class.
     * @return logger.
     */
    protected Logger getLogger() {
        return LoggerFactory.getLogger(getClass());
    }

    @Override
    public StatValueTypes getType() {
        return type;
    }

    @Override
    public String getCaption() {
        return caption;
    }

    @Override
    public String getExplanation() {
        return explanation;
    }

    @Override
    public String getShortExplanation() {
        return shortExpl;
    }

    @Override
    public boolean isRateMetric() {
        return isRateMetric;
    }

    @Override
    public boolean isDoubleValue() {
        return isRateMetric() || type == StatValueTypes.DOUBLE;
    }

    @Override
    public boolean isStringValue() {
        return !isRateMetric() && type == StatValueTypes.STRING;
    }

    @Override
    public boolean isIntegerValue() {
        return !isRateMetric() && type == StatValueTypes.INT;
    }

    @Override
    public boolean isLongValue() {
        return !isRateMetric() && (type == StatValueTypes.LONG || type == StatValueTypes.DIFFLONG || type == StatValueTypes.COUNTER);
    }

    @Override
    public Object parseValue(String value) {
        if (value == null) return null;
        Object result = null;
        try {
            switch (type) {
                case COUNTER:
                case DIFFLONG:
                case LONG: result = Long.parseLong(value); break;
                case INT: result = Integer.parseInt(value); break;
                case DOUBLE: result = Double.parseDouble(value); break;
                case STRING: result = value; break;
                default: result = value;
            }
        } catch (NumberFormatException nfe) {
            getLogger().warn("Failed to parse value '"+value+"'! Metric: " + this.toString(), nfe);
        }
        return result;
    }

    @Override
    public boolean isCorrectValue(Object value) {
        if (value == null)
            return true;
        final boolean result;
        switch (type) {
            case COUNTER:
            case DIFFLONG:
            case LONG: result = value instanceof Long; break;
            case INT: result = value instanceof Integer; break;
            case DOUBLE: result = value instanceof Double; break;
            case STRING: result = value instanceof String; break;
            default: result = false;
        }
        return result;
    }

    @Override
    public String toString() {
        return "GenericMetrics{" +
                "type=" + type +
                ", isRateMetric=" + isRateMetric +
                ", caption='" + caption + '\'' +
                ", shortExpl='" + shortExpl + '\'' +
                ", explanation='" + explanation + '\'' +
                '}';
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy