Java tutorial
/** * This file is part of SAMM. * * SAMM 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 * (at your option) any later version. * * SAMM 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 SAMM. If not, see <http://www.gnu.org/licenses/>. */ package pl.edu.agh.samm.metrics; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.commons.math.stat.correlation.PearsonsCorrelation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import pl.edu.agh.samm.api.db.IStorageService; import pl.edu.agh.samm.api.impl.CombinationGenerator; import pl.edu.agh.samm.api.metrics.IMetric; /** * @author Pawel Koperek <pkoperek@gmail.com> * @author Mateusz Kupisz <mkupisz@gmail.com> * */ public class SuggestedMetricsComputationEngineImpl implements ISuggestedMetricsComputationEngine, Runnable { private static final int SUGGESTED_METRICS_COUNT = 3; private static final Logger log = LoggerFactory.getLogger(SuggestedMetricsComputationEngineImpl.class); private Map<IMetric, Map<IMetric, Number>> suggestionCache = new HashMap<IMetric, Map<IMetric, Number>>(); private Map<IMetric, SortedSet<MetricWithCorrelation>> metricsWithCorrelation = new HashMap<IMetric, SortedSet<MetricWithCorrelation>>(); private ReadWriteLock cacheLock = new ReentrantReadWriteLock(); private ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1); private IStorageService storageService; /** * in minutes */ private long cacheRefreshRate; private static double[] convertValues(List<Number> values, int count) { double ret[] = new double[count]; int index = 0; for (Number value : values) { ret[index++] = value.doubleValue(); if (index == count) break; } return ret; } public void init() { scheduledExecutorService.scheduleWithFixedDelay(this, 0, cacheRefreshRate, TimeUnit.MINUTES); } public void destroy() { scheduledExecutorService.shutdownNow(); } @Override public Map<IMetric, Number> getMetricsSuggestedToStart(IMetric metric) { cacheLock.readLock().lock(); try { Map<IMetric, Number> suggestion = suggestionCache.get(metric); return suggestion; } finally { cacheLock.readLock().unlock(); } } @Override public void run() { try { metricsWithCorrelation.clear(); List<IMetric> allMetrics = storageService.getAllKnownMetrics(); IMetric[] metrics = allMetrics.toArray(new IMetric[0]); if (metrics.length < 2) { return; } if (metrics.length > 1) { // correlation relation is symmetrical // we will count correlation between all pairs CombinationGenerator combinationGenerator = new CombinationGenerator(metrics.length, 2); while (combinationGenerator.hasMore()) { int[] combination = combinationGenerator.getNext(); IMetric metricOne = metrics[combination[0]]; IMetric metricTwo = metrics[combination[1]]; // get historical data List<Number> metricOneValues = storageService .getHistoricalMetricValues(metricOne.getMetricURI(), metricOne.getResourceURI()); List<Number> metricTwoValues = storageService .getHistoricalMetricValues(metricTwo.getMetricURI(), metricTwo.getResourceURI()); int min = metricOneValues.size() > metricTwoValues.size() ? metricTwoValues.size() : metricOneValues.size(); PearsonsCorrelation pearsonsCorrelation = new PearsonsCorrelation(); double correlation = pearsonsCorrelation.correlation(convertValues(metricOneValues, min), convertValues(metricTwoValues, min)); if (!Double.isNaN(correlation)) { addCorrelation(metricOne, metricTwo, correlation); addCorrelation(metricTwo, metricOne, correlation); } } } updateCache(); } catch (Exception e) { log.error("Error during computing correlation", e); } } private void updateCache() { cacheLock.writeLock().lock(); try { suggestionCache.clear(); for (IMetric metric : metricsWithCorrelation.keySet()) { SortedSet<MetricWithCorrelation> suggestedMetricsWithCorrelation = metricsWithCorrelation .get(metric); Map<IMetric, Number> suggestion = new HashMap<IMetric, Number>(); for (MetricWithCorrelation suggestedMetric : suggestedMetricsWithCorrelation) { suggestion.put(suggestedMetric.getCorrelatingMetric(), suggestedMetric.getCorrelation()); } suggestionCache.put(metric, suggestion); } } finally { cacheLock.writeLock().unlock(); } } private void addCorrelation(IMetric metricOne, IMetric metricTwo, double correlation) { if (!metricsWithCorrelation.containsKey(metricOne)) { metricsWithCorrelation.put(metricOne, new TreeSet<MetricWithCorrelation>()); } SortedSet<MetricWithCorrelation> set = metricsWithCorrelation.get(metricOne); set.add(new MetricWithCorrelation(metricOne, metricTwo, correlation)); if (set.size() > SUGGESTED_METRICS_COUNT) { set.remove(set.first()); } } /** * @param storageService * the storageService to set */ public void setStorageService(IStorageService storageService) { this.storageService = storageService; } public void setCacheRefreshRate(long cacheRefreshRate) { this.cacheRefreshRate = cacheRefreshRate; } }