/*
* JBoss, Home of Professional Open Source
* Copyright [2011], Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package org.modeshape.report;
import org.modeshape.jcr.perftests.OutputCfg;
import org.modeshape.jcr.perftests.output.CsvOutput;
import org.modeshape.jcr.perftests.util.DurationsConverter;
import org.reflections.Reflections;
import org.reflections.scanners.ResourcesScanner;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.reflections.util.FilterBuilder;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* Class which loads all the .csv files from the classpath which are expected to contain performance reports.
*
* @author Horia Chiorean
*/
public final class CsvReportDataAggregator {
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(CsvReportDataAggregator.class);
/**
* Loads all the performance data by scanning the classpath for csv files under the {@link org.modeshape.jcr.perftests.OutputCfg#testDataOutputPackage()} location.
* @return a map of the form - [test, [repository name, (duration ns 1, duration ns 2...)]]
*
*@param convertToUnit the unit to which the performance data should be converted
* @throws Exception if anything fails
*/
Map<String, Map<String, List<Double>>> loadPerformanceData(TimeUnit convertToUnit) throws Exception {
Map<String, Map<String, List<Long>>> testToRepositoryDurationsMap = new TreeMap<String, Map<String, List<Long>>>();
ConfigurationBuilder builder = new ConfigurationBuilder()
.setUrls(ClasspathHelper.forPackage(OutputCfg.testDataOutputPackage()))
.setScanners(new ResourcesScanner())
.useParallelExecutor();
Reflections reflections = new Reflections(builder);
Set<String> reportFiles = reflections.getResources(new FilterBuilder().include(".*\\.csv"));
for (String reportFileName : reportFiles) {
processReport(reportFileName, testToRepositoryDurationsMap);
}
return convertToTimeUnit(testToRepositoryDurationsMap, convertToUnit);
}
private void processReport( String reportFileName, Map<String, Map<String, List<Long>>> testToRepositoryDurationsMap ) throws IOException {
Properties reportProperties = new Properties();
reportProperties.load(getClass().getClassLoader().getResourceAsStream(reportFileName));
String repositoryName = reportProperties.getProperty(CsvOutput.REPOSITORY_PROPERTY);
if (repositoryName == null) {
LOGGER.warn(reportFileName + " is not a valid test data file. Ignoring it");
return;
}
for (String test : reportProperties.stringPropertyNames()) {
String durationsString = reportProperties.getProperty(test);
loadDataForTest(durationsString, repositoryName, test, testToRepositoryDurationsMap);
}
}
private void loadDataForTest( String durationsString, String repositoryName, String test,
Map<String, Map<String, List<Long>>> testToRepositoryDurationsMap ) {
if (test.equals(CsvOutput.REPOSITORY_PROPERTY)) {
return;
}
Map<String, List<Long>> repositoryDurationsMap = testToRepositoryDurationsMap.get(test);
if (repositoryDurationsMap == null) {
repositoryDurationsMap = new TreeMap<String, List<Long>>();
testToRepositoryDurationsMap.put(test, repositoryDurationsMap);
}
List<Long> durations = repositoryDurationsMap.get(repositoryName);
if (durations == null) {
durations = new ArrayList<Long>();
repositoryDurationsMap.put(repositoryName, durations);
}
for (String duration : durationsString.split(",")) {
durations.add(Long.valueOf(duration));
}
}
private Map<String, Map<String, List<Double>>> convertToTimeUnit( Map<String, Map<String, List<Long>>> aggregateDataMap, TimeUnit timeUnit ) {
Map<String, Map<String, List<Double>>> convertedMap = new TreeMap<String, Map<String, List<Double>>>();
for (String testName : aggregateDataMap.keySet()) {
Map<String, List<Long>> repositoriesValuesMap = aggregateDataMap.get(testName);
Map<String, List<Double>> convertedRepositoriesValuesMap = new TreeMap<String, List<Double>>();
for (String repositoryName : repositoriesValuesMap.keySet()) {
List<Double> convertedDurations = DurationsConverter.convertFromNanos(repositoriesValuesMap.get(repositoryName), timeUnit);
convertedRepositoriesValuesMap.put(repositoryName, convertedDurations);
}
convertedMap.put(testName, convertedRepositoriesValuesMap);
}
return convertedMap;
}
}