/* * qualinsight-plugins-sonarqube-smell * Copyright (c) 2015, QualInsight * http://www.qualinsight.com/ * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later version. * * This program 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, you can retrieve a copy * from <http://www.gnu.org/licenses/>. */ package com.qualinsight.plugins.sonarqube.smell.plugin.extension; import java.io.Serializable; import java.util.List; import com.google.common.base.Preconditions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.ce.measure.Component; import org.sonar.api.ce.measure.Component.Type; import org.sonar.api.ce.measure.Measure; import org.sonar.api.ce.measure.MeasureComputer; import org.sonar.api.measures.Metric; import org.sonar.api.measures.Metric.ValueType; /** * {@link MeasureComputer} that aggregates Smell measures at project level. * * @author Michel Pawlak */ abstract class AbstractSmellMeasureComputer implements MeasureComputer { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractSmellMeasureComputer.class); private final List<String> outputMetricsKeys; private final List<String> inputMetricsKeys; /** * {@link AbstractSmellMeasureComputer} IoC constructor. */ public AbstractSmellMeasureComputer(final List<String> inputMetricsKeys, final List<String> outputMetricsKeys) { this.inputMetricsKeys = inputMetricsKeys; this.outputMetricsKeys = outputMetricsKeys; } /** * Provides a {@link List} of {@link Metric} keys for which the {@link MeasureComputer} computes and writes measures. * * @return output metrics keys */ public List<String> getOutputMetricsKeys() { return this.outputMetricsKeys; } /** * Provides a {@link List} of {@link Metric} keys the {@link MeasureComputer} uses to compute measures. * * @return input metrics keys */ public List<String> getInputMetricsKeys() { return this.inputMetricsKeys; } @Override public MeasureComputerDefinition define(final MeasureComputerDefinitionContext definitionContext) { return definitionContext.newDefinitionBuilder() .setInputMetrics(this.inputMetricsKeys.toArray(new String[0])) .setOutputMetrics(this.outputMetricsKeys.toArray(new String[0])) .build(); } /** * Computes measure by summing all children measures. * * @param context {@link MeasureComputerContext} to which the measure has to be saved to. */ @Override public void compute(final MeasureComputerContext context) { final Component component = context.getComponent(); if (component.getType() != Type.FILE) { compute(component, context); } } private void compute(final Component component, final MeasureComputerContext context) { LOGGER.debug("Computing measures for component '{}' and level {})", component.getKey(), component.getType()); for (final String outputMetricKey : this.outputMetricsKeys) { final Aggregator computer = aggregator(context, outputMetricKey); LOGGER.debug("Computed measure '{}': {})", outputMetricKey, computer.getResult()); computer.addMeasureToContext(); } } /** * Retrieves an {@link Aggregator} able to aggregate {@link Measure}s. * * @param context {@link MeasureComputerContext} to which aggregated result has to be saved. * @param metricKey key of the {@link Metric} for which {@link Measure}s are aggregated. * @return {@link Aggregator} instance. */ protected Aggregator aggregator(final MeasureComputerContext context, final String metricKey) { final Aggregator aggregator = new Aggregator(context, metricKey); final Iterable<Measure> measures = context.getChildrenMeasures(metricKey); LOGGER.debug("current metric: '{}'", metricKey); if (measures != null) { for (final Measure measure : measures) { aggregator.aggregate(measure); } } return aggregator; } @Override public String toString() { return getClass().getSimpleName(); } /** * {@link Measure} aggregation class. * * @author Michel Pawlak */ class Aggregator { private Number value = 0; private String metricKey; private ValueType valueType; private MeasureComputerContext context; /** * {@link Aggregator} contructor. * * @param context {@link MeasureComputerContext} to which aggregated result has to be saved. * @param metricKey key of the {@link Metric} for which {@link Measure}s are aggregated. */ public Aggregator(final MeasureComputerContext context, final String metricKey) { this.context = context; this.metricKey = metricKey; final Metric<Serializable> metric = SmellMetrics.metricFor(metricKey); this.valueType = Preconditions.checkNotNull(metric, "No Metric could be found for metric key '{}'", metricKey) .getType(); switch (this.valueType) { case INT: this.value = Integer.valueOf(0); break; case WORK_DUR: this.value = Long.valueOf(0); break; default: throw new UnsupportedOperationException(); } } /** * Retrieves the result aggregated by this {@link Aggregator} * * @return aggregation result as a {@link Number} */ public Number getResult() { return this.value; } /** * Aggregates a {@link Measure} to the result held by the {@link Aggregator}. * * @param measure {@link Measure} from which the value to be aggregated has to be extracted. */ public void aggregate(final Measure measure) { switch (this.valueType) { case INT: this.value = this.value.intValue() + measure.getIntValue(); break; case WORK_DUR: this.value = this.value.longValue() + measure.getLongValue(); break; default: throw new UnsupportedOperationException(); } } /** * Saves the aggregation result to the {@link MeasureComputerContext}. */ public void addMeasureToContext() { switch (this.valueType) { case INT: this.context.addMeasure(this.metricKey, this.value.intValue()); break; case WORK_DUR: this.context.addMeasure(this.metricKey, this.value.longValue()); break; default: throw new UnsupportedOperationException(); } } } }