/* * Sonar SonarJ Plugin * Copyright (C) 2009, 2010 hello2morrow GmbH * mailto: info AT hello2morrow DOT com * * 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 com.hello2morrow.sonarplugin; import java.util.Arrays; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.batch.AbstractSumChildrenDecorator; import org.sonar.api.batch.DecoratorContext; import org.sonar.api.batch.DependedUpon; import org.sonar.api.measures.Measure; import org.sonar.api.measures.Metric; import org.sonar.api.resources.Resource; public final class SonarJMetricAggregator extends AbstractSumChildrenDecorator { private static final Logger LOG = LoggerFactory.getLogger(SonarJMetricAggregator.class); @Override @DependedUpon public List<Metric> generatesMetrics() { return Arrays.asList(SonarJMetrics.VIOLATING_TYPES, SonarJMetrics.EROSION_INDEX, SonarJMetrics.CYCLIC_PACKAGES, SonarJMetrics.CYCLICITY, SonarJMetrics.EROSION_COST, SonarJMetrics.EROSION_REFS, SonarJMetrics.EROSION_TYPES, SonarJMetrics.IGNORED_VIOLATONS, SonarJMetrics.IGNORED_WARNINGS, SonarJMetrics.INSTRUCTIONS, SonarJMetrics.INTERNAL_PACKAGES, SonarJMetrics.INTERNAL_TYPES, SonarJMetrics.JAVA_FILES, SonarJMetrics.TASKS, SonarJMetrics.TASK_REFS, SonarJMetrics.THRESHOLD_WARNINGS, SonarJMetrics.DUPLICATE_WARNINGS, SonarJMetrics.ALL_WARNINGS, SonarJMetrics.CYCLE_WARNINGS, SonarJMetrics.WORKSPACE_WARNINGS, SonarJMetrics.TYPE_DEPENDENCIES, SonarJMetrics.VIOLATING_DEPENDENCIES, SonarJMetrics.ARCHITECTURE_VIOLATIONS, SonarJMetrics.UNASSIGNED_TYPES); } @Override protected boolean shouldSaveZeroIfNoChildMeasures() { return false; } @SuppressWarnings("unchecked") @Override public void decorate(Resource resource, DecoratorContext context) { if (!shouldDecorateResource(resource)) { return; } if (context.getChildrenMeasures(SonarJMetrics.INSTRUCTIONS).size() == 0) { return; } super.decorate(resource, context); double biggestCycleGroupSize = -1.0; double highestACD = -1.0; double highestNCCD = -1.0; for (DecoratorContext childContext : context.getChildren()) { Measure cycleGroup = childContext.getMeasure(SonarJMetrics.BIGGEST_CYCLE_GROUP); Measure acd = childContext.getMeasure(SonarJMetrics.ACD); Measure nccd = childContext.getMeasure(SonarJMetrics.NCCD); Measure localHighestACD = childContext.getMeasure(SonarJMetrics.HIGHEST_ACD); Measure localHighestNCCD = childContext.getMeasure(SonarJMetrics.HIGHEST_NCCD); if (cycleGroup != null && cycleGroup.getValue() > biggestCycleGroupSize) { biggestCycleGroupSize = cycleGroup.getValue(); } if (acd != null && acd.getValue() > highestACD) { highestACD = acd.getValue(); } else if (localHighestACD != null && localHighestACD.getValue() > highestACD) { highestACD = localHighestACD.getValue(); } if (nccd != null && nccd.getValue() > highestNCCD) { highestNCCD = nccd.getValue(); } else if (localHighestNCCD != null && localHighestNCCD.getValue() > highestNCCD) { highestNCCD = localHighestNCCD.getValue(); } } if (biggestCycleGroupSize >= 0.0 && context.getMeasure(SonarJMetrics.BIGGEST_CYCLE_GROUP) == null) { context.saveMeasure(SonarJMetrics.BIGGEST_CYCLE_GROUP, biggestCycleGroupSize); } if (highestACD >= 0.0 && context.getMeasure(SonarJMetrics.HIGHEST_ACD) == null) { context.saveMeasure(SonarJMetrics.HIGHEST_ACD, highestACD); } if (highestNCCD >= 0.0 && context.getMeasure(SonarJMetrics.HIGHEST_NCCD) == null) { context.saveMeasure(SonarJMetrics.HIGHEST_NCCD, highestNCCD); } Measure cyclicity = context.getMeasure(SonarJMetrics.CYCLICITY); Measure packages = context.getMeasure(SonarJMetrics.INTERNAL_PACKAGES); Measure cyclicPackages = context.getMeasure(SonarJMetrics.CYCLIC_PACKAGES); if (cyclicity == null || packages == null || cyclicPackages == null) { LOG.error("Problem in aggregator on project: " + context.getProject().getKey()); } else { double relCyclicity = 100.0 * Math.sqrt(cyclicity.getValue()) / packages.getValue(); double relCyclicPackages = 100.0 * cyclicPackages.getValue() / packages.getValue(); context.saveMeasure(SonarJMetrics.RELATIVE_CYCLICITY, relCyclicity); context.saveMeasure(SonarJMetrics.CYCLIC_PACKAGES_PERCENT, relCyclicPackages); } Measure violatingTypes = context.getMeasure(SonarJMetrics.VIOLATING_TYPES); Measure internalTypes = context.getMeasure(SonarJMetrics.INTERNAL_TYPES); Measure unassignedTypes = context.getMeasure(SonarJMetrics.UNASSIGNED_TYPES); if (internalTypes != null && internalTypes.getValue() > 0) { if (violatingTypes != null) { context.saveMeasure(SonarJMetrics.VIOLATING_TYPES_PERCENT, 100.0 * violatingTypes.getValue() / internalTypes.getValue()); } if (unassignedTypes != null) { context.saveMeasure(SonarJMetrics.UNASSIGNED_TYPES_PERCENT, 100 * unassignedTypes.getValue() / internalTypes.getValue()); } } AlertDecorator.setAlertLevels(new DecoratorProjectContext(context)); } @SuppressWarnings("unchecked") @Override public boolean shouldDecorateResource(Resource resource) { return Arrays.asList(Resource.QUALIFIER_PROJECT, Resource.QUALIFIER_MODULE, Resource.QUALIFIER_VIEW, Resource.QUALIFIER_SUBVIEW).contains( resource.getQualifier()); } }