com.hello2morrow.sonarplugin.SonargraphSensor.java Source code

Java tutorial

Introduction

Here is the source code for com.hello2morrow.sonarplugin.SonargraphSensor.java

Source

/*
 * Sonar Sonargraph Plugin
 * Copyright (C) 2009, 2010, 2011 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 com.hello2morrow.sonarplugin.xsd.ReportContext;
import com.hello2morrow.sonarplugin.xsd.XsdArchitectureViolation;
import com.hello2morrow.sonarplugin.xsd.XsdAttribute;
import com.hello2morrow.sonarplugin.xsd.XsdAttributeCategory;
import com.hello2morrow.sonarplugin.xsd.XsdAttributeRoot;
import com.hello2morrow.sonarplugin.xsd.XsdBuildUnits;
import com.hello2morrow.sonarplugin.xsd.XsdCycleGroup;
import com.hello2morrow.sonarplugin.xsd.XsdCycleGroups;
import com.hello2morrow.sonarplugin.xsd.XsdCyclePath;
import com.hello2morrow.sonarplugin.xsd.XsdPosition;
import com.hello2morrow.sonarplugin.xsd.XsdTask;
import com.hello2morrow.sonarplugin.xsd.XsdTasks;
import com.hello2morrow.sonarplugin.xsd.XsdTypeRelation;
import com.hello2morrow.sonarplugin.xsd.XsdViolations;
import com.hello2morrow.sonarplugin.xsd.XsdWarning;
import com.hello2morrow.sonarplugin.xsd.XsdWarnings;
import com.hello2morrow.sonarplugin.xsd.XsdWarningsByAttribute;
import com.hello2morrow.sonarplugin.xsd.XsdWarningsByAttributeGroup;
import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.Metric;
import org.sonar.api.resources.JavaFile;
import org.sonar.api.resources.JavaPackage;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RulePriority;
import org.sonar.api.rules.Violation;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public final class SonargraphSensor implements Sensor {
    private static final Logger LOG = LoggerFactory.getLogger(SonargraphSensor.class);

    private static final String REPORT_DIR = "sonargraph-sonar-plugin";
    private static final String REPORT_NAME = "sonargraph-sonar-report.xml";

    private static final String ACD = "AverageComponentDependency";
    private static final String NCCD = "NormalizedCumulativeComponentDependency";
    private static final String INTERNAL_PACKAGES = "NumberOfInternalNamespaces";
    private static final String INSTRUCTIONS = "NumberOfInstructions";
    private static final String UNASSIGNED_TYPES = "NumberOfNotAssignedTypes";
    private static final String VIOLATING_DEPENDENCIES = "NumberOfViolations";
    private static final String VIOLATING_TYPES = "NumberOfViolatingTypes";
    private static final String TYPE_DEPENDENCIES = "OverallNumberOfTypeDependencies";
    private static final String JAVA_FILES = "NumberOfSourceFiles";
    private static final String IGNORED_VIOLATIONS = "NumberOfIgnoredViolations";
    private static final String IGNORED_WARNINGS = "NumberOfIgnoredWarnings";
    private static final String TASKS = "NumberOfTasks";
    private static final String ALL_WARNINGS = "NumberOfWarnings";
    private static final String CYCLE_WARNINGS = "NumberOfCyclicWarnings";
    private static final String THRESHOLD_WARNINGS = "NumberOfMetricWarnings";
    private static final String WORKSPACE_WARNINGS = "NumberOfWorkspaceWarnings";
    private static final String DUPLICATE_WARNINGS = "NumberOfDuplicateCodeBlocksWarnings";
    private static final String EROSION_REFS = "StructuralErosionReferenceLevel";
    private static final String EROSION_TYPES = "StructuralErosionTypeLevel";
    private static final String INTERNAL_TYPES = "NumberOfInternalTypes";
    private static final String STUCTURAL_DEBT_INDEX = "StructuralDebtIndex";

    private final Map<String, Number> buildUnitMetrics = new HashMap<String, Number>();
    private SensorContext sensorContext;
    private final RuleFinder ruleFinder;
    private double indexCost = SonargraphPluginBase.COST_PER_INDEX_POINT_DEFAULT;

    protected static ReportContext readSonargraphReport(String fileName, String packaging) {
        ReportContext result = null;
        InputStream input = null;
        ClassLoader defaultClassLoader = Thread.currentThread().getContextClassLoader();

        try {
            Thread.currentThread().setContextClassLoader(SonargraphSensor.class.getClassLoader());
            JAXBContext context = JAXBContext.newInstance("com.hello2morrow.sonarplugin.xsd");
            Unmarshaller u = context.createUnmarshaller();

            input = new FileInputStream(fileName);
            result = (ReportContext) u.unmarshal(input);
        } catch (JAXBException e) {
            LOG.error("JAXB Problem in " + fileName, e);
        } catch (FileNotFoundException e) {
            if (!packaging.equalsIgnoreCase("pom")) {
                LOG.warn("Cannot open Sonargraph report: " + fileName + ".");
                LOG.warn(
                        "  Did you run the maven sonargraph goal before with the POM option <prepareForSonar>true</prepareForSonar> "
                                + "or with the commandline option -Dsonargraph.prepareForSonar=true?");
                LOG.warn("  Is the project part of the Sonargraph architecture description?");
                LOG.warn("  Did you set the 'aggregate' to true (must be false)?");
            }
        } finally {
            Thread.currentThread().setContextClassLoader(defaultClassLoader);
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    LOG.error("Cannot close " + fileName, e);
                }
            }
        }
        return result;
    }

    public SonargraphSensor(RuleFinder ruleFinder) {
        this.ruleFinder = ruleFinder;
        if (ruleFinder == null) {
            LOG.warn("No RulesManager provided to sensor");
        }
    }

    public boolean shouldExecuteOnProject(Project project) {
        return true;
    }

    private void readAttributes(XsdAttributeRoot root) {
        buildUnitMetrics.clear();

        for (XsdAttributeCategory cat : root.getAttributeCategory()) {
            for (XsdAttribute attr : cat.getAttribute()) {
                String attrName = attr.getStandardName();
                String value = attr.getValue();

                try {
                    if (value.contains(".")) {
                        buildUnitMetrics.put(attrName, SonargraphPluginBase.FLOAT_FORMAT.parse(value));
                    } else {
                        buildUnitMetrics.put(attrName, SonargraphPluginBase.INTEGER_FORMAT.parse(value));
                    }
                } catch (ParseException e) {
                    // Ignore this value
                }
            }
        }
    }

    private boolean hasBuildUnitMetric(String key) {
        return buildUnitMetrics.get(key) != null;
    }

    private double getBuildUnitMetric(String key) {
        Number num = buildUnitMetrics.get(key);

        if (num == null) {
            LOG.error("Cannot find metric <" + key + "> in generated report");
            return 0.0;
        }
        return num.doubleValue();
    }

    private Measure saveMeasure(String key, Metric metric, int precision) {
        double value = getBuildUnitMetric(key);

        return saveMeasure(metric, value, precision);
    }

    private Measure saveMeasure(Metric metric, double value, int precision) {
        Measure m = new Measure(metric, value, precision);

        sensorContext.saveMeasure(m);
        return m;
    }

    private String getAttribute(List<XsdAttribute> map, String name) {
        String value = null;

        for (XsdAttribute attr : map) {
            if (attr.getName().equals(name)) {
                value = attr.getValue();
                break;
            }
        }
        return value;
    }

    private void analyseCycleGroups(ReportContext report, Number internalPackages, String buildUnitName) {
        XsdCycleGroups cycleGroups = report.getCycleGroups();
        double cyclicity = 0;
        double biggestCycleGroupSize = 0;
        double cyclicPackages = 0;

        for (XsdCycleGroup group : cycleGroups.getCycleGroup()) {
            if (group.getNamedElementGroup().equals("Physical package")
                    && getBuildUnitName(group).equals(buildUnitName)) {
                int groupSize = group.getCyclePath().size();
                cyclicPackages += groupSize;
                cyclicity += groupSize * groupSize;
                if (groupSize > biggestCycleGroupSize) {
                    biggestCycleGroupSize = groupSize;
                }
                handlePackageCycleGroup(group);
            }
        }
        saveMeasure(SonargraphMetrics.BIGGEST_CYCLE_GROUP, biggestCycleGroupSize, 0);
        saveMeasure(SonargraphMetrics.CYCLICITY, cyclicity, 0);
        saveMeasure(SonargraphMetrics.CYCLIC_PACKAGES, cyclicPackages, 0);

        double relativeCyclicity = 100.0 * Math.sqrt(cyclicity) / internalPackages.doubleValue();
        double relativeCyclicPackages = 100.0 * cyclicPackages / internalPackages.doubleValue();

        saveMeasure(SonargraphMetrics.RELATIVE_CYCLICITY, relativeCyclicity, 1);
        saveMeasure(SonargraphMetrics.INTERNAL_PACKAGES, internalPackages.doubleValue(), 0);
        saveMeasure(SonargraphMetrics.CYCLIC_PACKAGES_PERCENT, relativeCyclicPackages, 1);
    }

    @SuppressWarnings("unchecked")
    private void saveViolation(Rule rule, RulePriority priority, String fqName, int line, String msg) {
        Resource javaFile = sensorContext.getResource(new JavaFile(fqName));

        if (javaFile == null) {
            LOG.error("Cannot obtain resource " + fqName);
        } else {
            Violation v = Violation.create(rule, javaFile);

            v.setMessage(msg);
            v.setLineId(line);
            if (priority != null) {
                v.setSeverity(priority);
            }
            sensorContext.saveViolation(v);
        }
    }

    private String getBuildUnitName(XsdCycleGroup group) {
        if (group.getParent().equals("(Default Build Unit)")) {
            return group.getElementScope();
        }
        return group.getParent();
    }

    private String getBuildUnitName(String fqName) {
        String buName = "<UNKNOWN>";

        if (fqName != null) {
            int colonPos = fqName.indexOf("::");

            if (colonPos != -1) {
                buName = fqName.substring(colonPos + 2);
                if (buName.equals("(Default Build Unit)")) {
                    // Compatibility with old SonarJ versions
                    buName = fqName.substring(0, colonPos);
                }
            }
        }
        return buName;
    }

    private static String relativeFileNameToFqName(String fileName) {
        int lastDot = fileName.lastIndexOf('.');

        return fileName.substring(0, lastDot).replace('/', '.');
    }

    @SuppressWarnings("unchecked")
    private void handlePackageCycleGroup(XsdCycleGroup group) {
        Rule rule = ruleFinder.findByKey(SonargraphPluginBase.PLUGIN_KEY,
                SonargraphPluginBase.CYCLE_GROUP_RULE_KEY);

        if (rule != null) {
            for (XsdCyclePath pathElement : group.getCyclePath()) {
                String fqName = pathElement.getParent();
                Resource<JavaPackage> javaPackage = sensorContext.getResource(new JavaPackage(fqName));

                if (javaPackage == null) {
                    LOG.error("Cannot obtain resource " + fqName);
                } else {
                    Violation v = Violation.create(rule, javaPackage);

                    v.setMessage("Package participates in a cycle group");
                    v.setLineId(1);
                    sensorContext.saveViolation(v);
                }
            }
        }
    }

    private int handleArchitectureViolations(XsdViolations violations, String buildUnitName) {
        Rule rule = ruleFinder.findByKey(SonargraphPluginBase.PLUGIN_KEY, SonargraphPluginBase.ARCH_RULE_KEY);
        int count = 0;

        for (XsdArchitectureViolation violation : violations.getArchitectureViolations()) {
            String toName = getAttribute(violation.getArchitectureViolation().getAttribute(), "To");
            String toElemType = getAttribute(violation.getArchitectureViolation().getAttribute(), "To element type")
                    .toLowerCase();
            String target = toElemType + ' ' + toName;

            for (XsdTypeRelation rel : violation.getTypeRelation()) {
                String toType = getAttribute(rel.getAttribute(), "To");
                String msg = "Type " + toType + " from " + target + " must not be used from here";
                String bu = getAttribute(rel.getAttribute(), "From build unit");

                bu = getBuildUnitName(bu);
                if (bu.equals(buildUnitName)) {
                    for (XsdPosition pos : rel.getPosition()) {
                        if (rule != null) {
                            String relFileName = pos.getFile();

                            if (relFileName != null) {
                                String fqName = relativeFileNameToFqName(relFileName);
                                saveViolation(rule, null, fqName, Integer.valueOf(pos.getLine()), msg);
                            }
                        }
                        count++;
                    }
                }
            }

        }
        if (rule == null) {
            LOG.error("Sonargraph architecture rule not found");
        }
        return count;
    }

    private String getRuleKey(String attributeGroup) {
        if (attributeGroup.equals("Duplicate code")) {
            return SonargraphPluginBase.DUPLICATE_RULE_KEY;
        }
        if (attributeGroup.equals("Workspace")) {
            return SonargraphPluginBase.WORKSPACE_RULE_KEY;
        }
        if (attributeGroup.equals("Threshold")) {
            return SonargraphPluginBase.THRESHOLD_RULE_KEY;
        }
        return null;
    }

    private void handleWarnings(XsdWarnings warnings, String buildUnitName) {
        for (XsdWarningsByAttributeGroup warningGroup : warnings.getWarningsByAttributeGroup()) {
            String key = getRuleKey(warningGroup.getAttributeGroup());
            if (key == null) {
                continue;
            }
            Rule rule = ruleFinder.findByKey(SonargraphPluginBase.PLUGIN_KEY, key);
            if (rule == null) {
                LOG.error("Sonargraph threshold rule not found");
                continue;
            }
            for (XsdWarningsByAttribute warningByAttribute : warningGroup.getWarningsByAttribute()) {
                String attrName = warningByAttribute.getAttributeName();

                for (XsdWarning warning : warningByAttribute.getWarning()) {
                    String msg = attrName + "=" + getAttribute(warning.getAttribute(), "Attribute value");
                    String bu = getAttribute(warning.getAttribute(), "Build unit");

                    bu = getBuildUnitName(bu);
                    if (bu.equals(buildUnitName)) {
                        if (warning.getPosition().size() > 0) {
                            for (XsdPosition pos : warning.getPosition()) {
                                String relFileName = pos.getFile();

                                if (relFileName != null) {
                                    String fqName = relativeFileNameToFqName(relFileName);

                                    saveViolation(rule, null, fqName, Integer.valueOf(pos.getLine()), msg);
                                }
                            }
                        } else {
                            String elemType = getAttribute(warning.getAttribute(), "Element type");

                            if (elemType.equals("Class file") || elemType.equals("Source file")) {
                                // Attach a violation at line 1
                                String fileName = getAttribute(warning.getAttribute(), "Element");
                                String fqName = fileName.substring(0, fileName.lastIndexOf('.')).replace('/', '.');

                                saveViolation(rule, null, fqName, 1, msg);
                            }
                        }
                    }
                }
            }
        }
    }

    private String handleDescription(String descr) {
        if (descr.startsWith("Fix warning")) {
            // TODO: handle ascending metrics correctly (99% are descending)
            return "Reduce" + descr.substring(descr.indexOf(':') + 1).toLowerCase();
        }
        if (descr.startsWith("Cut type")) {
            String toType = descr.substring(descr.indexOf("to "));

            return "Cut dependency " + toType;
        }
        if (descr.startsWith("Move type")) {
            String to = descr.substring(descr.indexOf("to "));

            return "Move " + to;
        }
        return descr;
    }

    private int handleTasks(XsdTasks tasks, String buildUnitName) {
        Map<String, RulePriority> priorityMap = new HashMap<String, RulePriority>();

        Rule rule = ruleFinder.findByKey(SonargraphPluginBase.PLUGIN_KEY, SonargraphPluginBase.TASK_RULE_KEY);
        int count = 0;

        if (rule == null) {
            LOG.error("Sonargraph task rule not found");
            return 0;
        }

        priorityMap.put("Low", RulePriority.INFO);
        priorityMap.put("Medium", RulePriority.MINOR);
        priorityMap.put("High", RulePriority.MAJOR);

        for (XsdTask task : tasks.getTask()) {
            String bu = getAttribute(task.getAttribute(), "Build unit");

            bu = getBuildUnitName(bu);
            if (bu.equals(buildUnitName)) {
                String priority = getAttribute(task.getAttribute(), "Priority");
                String description = getAttribute(task.getAttribute(), "Description");
                String assignedTo = getAttribute(task.getAttribute(), "Assigned to");

                description = handleDescription(description); // This should not
                // be needed,
                // but the
                // current
                // description
                // sucks

                int index = description.indexOf(" package");

                if (index > 0 && index < 8) {
                    // Package refactorings won't get markers - this would
                    // create to many non relevant markers
                    count++;
                } else {
                    if (assignedTo != null) {
                        assignedTo = '[' + assignedTo.trim() + ']';
                        if (assignedTo.length() > 2) {
                            description += ' ' + assignedTo;
                        }
                    }
                    for (XsdPosition pos : task.getPosition()) {
                        String relFileName = pos.getFile();

                        if (relFileName != null) {
                            String fqName = relativeFileNameToFqName(relFileName);
                            int line = Integer.valueOf(pos.getLine());

                            if (line == 0) {
                                line = 1;
                            }
                            saveViolation(rule, priorityMap.get(priority), fqName, line, description);
                        }
                        count++;
                    }
                }
            }
        }
        return count;
    }

    private void addArchitectureMeasures(ReportContext report, String buildUnitName) {
        double types = saveMeasure(INTERNAL_TYPES, SonargraphMetrics.INTERNAL_TYPES, 0).getValue();
        Measure unassignedTypes = saveMeasure(UNASSIGNED_TYPES, SonargraphMetrics.UNASSIGNED_TYPES, 0);
        Measure violatingTypes = saveMeasure(VIOLATING_TYPES, SonargraphMetrics.VIOLATING_TYPES, 0);
        saveMeasure(VIOLATING_DEPENDENCIES, SonargraphMetrics.VIOLATING_DEPENDENCIES, 0);
        saveMeasure(TASKS, SonargraphMetrics.TASKS, 0);
        if (hasBuildUnitMetric(THRESHOLD_WARNINGS)) {
            saveMeasure(THRESHOLD_WARNINGS, SonargraphMetrics.THRESHOLD_WARNINGS, 0);
        }
        saveMeasure(WORKSPACE_WARNINGS, SonargraphMetrics.WORKSPACE_WARNINGS, 0);
        saveMeasure(IGNORED_VIOLATIONS, SonargraphMetrics.IGNORED_VIOLATONS, 0);
        saveMeasure(IGNORED_WARNINGS, SonargraphMetrics.IGNORED_WARNINGS, 0);
        if (hasBuildUnitMetric(DUPLICATE_WARNINGS)) {
            saveMeasure(DUPLICATE_WARNINGS, SonargraphMetrics.DUPLICATE_WARNINGS, 0);
        }
        saveMeasure(CYCLE_WARNINGS, SonargraphMetrics.CYCLE_WARNINGS, 0);
        saveMeasure(ALL_WARNINGS, SonargraphMetrics.ALL_WARNINGS, 0);

        assert types >= 1.0 : "Project must not be empty !";

        double violatingTypesPercent = 100.0 * violatingTypes.getValue() / types;
        double unassignedTypesPercent = 100.0 * unassignedTypes.getValue() / types;

        saveMeasure(SonargraphMetrics.VIOLATING_TYPES_PERCENT, violatingTypesPercent, 1);
        saveMeasure(SonargraphMetrics.UNASSIGNED_TYPES_PERCENT, unassignedTypesPercent, 1);

        XsdViolations violations = report.getViolations();

        double violatingRefs = 0;
        double taskRefs = 0;

        if (ruleFinder != null) {
            violatingRefs = handleArchitectureViolations(violations, buildUnitName);
            handleWarnings(report.getWarnings(), buildUnitName);
            taskRefs = handleTasks(report.getTasks(), buildUnitName);
        }
        saveMeasure(SonargraphMetrics.ARCHITECTURE_VIOLATIONS, violatingRefs, 0);
        saveMeasure(SonargraphMetrics.TASK_REFS, taskRefs, 0);
    }

    private void analyse(IProject project, XsdAttributeRoot xsdBuildUnit, String buildUnitName,
            ReportContext report) {
        LOG.info("Adding measures for " + project.getName());

        readAttributes(xsdBuildUnit);

        Number internalPackages = getBuildUnitMetric(INTERNAL_PACKAGES);

        if (internalPackages.intValue() == 0) {
            LOG.warn("No packages found in project " + project.getName());
            return;
        }

        saveMeasure(ACD, SonargraphMetrics.ACD, 1);
        saveMeasure(NCCD, SonargraphMetrics.NCCD, 1);
        saveMeasure(INSTRUCTIONS, SonargraphMetrics.INSTRUCTIONS, 0);
        saveMeasure(JAVA_FILES, SonargraphMetrics.JAVA_FILES, 0);
        saveMeasure(TYPE_DEPENDENCIES, SonargraphMetrics.TYPE_DEPENDENCIES, 0);
        saveMeasure(EROSION_REFS, SonargraphMetrics.EROSION_REFS, 0);
        saveMeasure(EROSION_TYPES, SonargraphMetrics.EROSION_TYPES, 0);
        Number structuralDebtIndex = saveMeasure(STUCTURAL_DEBT_INDEX, SonargraphMetrics.EROSION_INDEX, 0)
                .getValue();

        if (indexCost > 0) {
            double structuralDebtCost = structuralDebtIndex.doubleValue() * indexCost;
            saveMeasure(SonargraphMetrics.EROSION_COST, structuralDebtCost, 0);
        }
        analyseCycleGroups(report, internalPackages, buildUnitName);
        if (hasBuildUnitMetric(UNASSIGNED_TYPES)) {
            LOG.info("Adding architecture measures for " + project.getName());
            addArchitectureMeasures(report, buildUnitName);
        }
        AlertDecorator.setAlertLevels(new SensorProjectContext(sensorContext));
    }

    void analyse(IProject project, SensorContext sensorContext, ReportContext report) {
        this.sensorContext = sensorContext;
        Configuration configuration = project.getConfiguration();
        this.indexCost = configuration.getDouble(SonargraphPluginBase.COST_PER_INDEX_POINT,
                SonargraphPluginBase.COST_PER_INDEX_POINT_DEFAULT);

        XsdBuildUnits buildUnits = report.getBuildUnits();
        List<XsdAttributeRoot> buildUnitList = buildUnits.getBuildUnit();

        if (buildUnitList.size() == 1) {
            XsdAttributeRoot sonarBuildUnit = buildUnitList.get(0);
            String buName = getBuildUnitName(sonarBuildUnit.getName());

            analyse(project, sonarBuildUnit, buName, report);
        } else if (buildUnitList.size() > 1) {
            boolean foundMatchingBU = false;
            for (XsdAttributeRoot sonarBuildUnit : buildUnitList) {
                String buName = getBuildUnitName(sonarBuildUnit.getName());
                if (buildUnitMatchesAnalyzedProject(buName, project)) {
                    analyse(project, sonarBuildUnit, buName, report);
                    foundMatchingBU = true;
                    break;
                }
            }
            if (!foundMatchingBU) {
                LOG.warn("Project " + project.getName()
                        + " could not be mapped to a build unit. The project will not be analyzed. Check the build unit configuration of your Sonargraph system.");
            }
        } else {
            LOG.error("No build units found in report file!");
        }
    }

    private boolean buildUnitMatchesAnalyzedProject(String buName, IProject project) {
        final String artifactId = project.getArtifactId();
        final String groupId = project.getGroupId();
        final String longName = artifactId + "[" + groupId + "]";
        final String longName2 = groupId + ':' + artifactId;

        return buName.equals(artifactId) || buName.equals(longName) || buName.equals(longName2)
                || (buName.startsWith("...") && longName2.endsWith(buName.substring(2)));
    }

    public void analyse(Project project, SensorContext sensorContext) {
        LOG.info("------------------------------------------------------------------------");
        LOG.info("Execute sonar-sonargraph-plugin for " + project.getName());
        LOG.info("------------------------------------------------------------------------");

        ReportContext report = readSonargraphReport(getReportFileName(project), project.getPackaging());

        if (report != null) {
            analyse(new ProjectDelegate(project), sensorContext, report);
        }
    }

    public String getReportFileName(Project project) {
        return project.getFileSystem().getBuildDir().getPath() + '/' + REPORT_DIR + '/' + REPORT_NAME;
    }
}