com.sourcemeter.analyzer.cpp.batch.SourceMeterCppSensor.java Source code

Java tutorial

Introduction

Here is the source code for com.sourcemeter.analyzer.cpp.batch.SourceMeterCppSensor.java

Source

/**
 * Copyright (c) 2014-2015, FrontEndART Software Ltd.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    This product includes software developed by FrontEndART Software Ltd.
 * 4. Neither the name of FrontEndART Software Ltd. nor the
 *    names of its contributors may be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY FrontEndART Software Ltd. ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL FrontEndART Software Ltd. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.sourcemeter.analyzer.cpp.batch;

import graphlib.Graph;
import graphlib.GraphlibException;
import graphlib.Node;
import graphlib.Node.NodeType;
import graphlib.VisitorException;

import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.component.ResourcePerspectives;
import org.sonar.api.config.Settings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.Metric;
import org.sonar.api.profiles.RulesProfile;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.scan.filesystem.ModuleFileSystem;
import org.sonar.api.utils.SonarException;

import com.google.gson.Gson;
import com.sourcemeter.analyzer.base.batch.SourceMeterSensor;
import com.sourcemeter.analyzer.base.core.resources.ClassData;
import com.sourcemeter.analyzer.base.helper.FileHelper;
import com.sourcemeter.analyzer.base.helper.GraphHelper;
import com.sourcemeter.analyzer.base.visitor.NodeCounterVisitor;
import com.sourcemeter.analyzer.cpp.SourceMeterCppMetrics;
import com.sourcemeter.analyzer.cpp.visitor.CloneTreeLoaderVisitorCpp;
import com.sourcemeter.analyzer.cpp.visitor.ComponentTreeLoaderVisitorCpp;
import com.sourcemeter.analyzer.cpp.visitor.LogicalTreeLoaderVisitorCpp;
import com.sourcemeter.analyzer.cpp.visitor.PhysicalTreeLoaderVisitorCpp;

public class SourceMeterCppSensor extends SourceMeterSensor {

    private final Project project;
    private final SensorContext sensorContext;

    public SourceMeterCppSensor(ModuleFileSystem moduleFileSystem, FileSystem fileSystem,
            ResourcePerspectives perspectives, Project project, SensorContext sensorContext, Settings settings,
            RulesProfile rulesProfile) {

        super(moduleFileSystem, fileSystem, settings, perspectives, rulesProfile);

        this.project = project;
        this.sensorContext = sensorContext;
    }

    @Override
    public void analyse(Project module, SensorContext context) {
        String analyseMode = this.settings.getString("sonar.analysis.mode");
        this.projectName = settings.getString("sonar.projectKey");
        this.projectName = StringUtils.replace(projectName, ":", "_");

        if ("incremental".equals(analyseMode)) {
            LOG.warn("Incremental mode is on. There are no metric based (INFO level) issues in this mode.");
            this.isIncrementalMode = true;
        }

        this.resultGraph = FileHelper.getSMSourcePath(settings, fileSystem, '-') + File.separator + projectName
                + ".graph";

        long startTime = System.currentTimeMillis();
        LOG.info("      Graph: " + resultGraph);

        try {
            loadDataFromGraphBin(this.resultGraph, project, sensorContext);
        } catch (GraphlibException e) {
            throw new SonarException("Error during graph loading!", e);
        }

        LOG.info("    Load data from graph bin and save resources and metrics done: "
                + (System.currentTimeMillis() - startTime) + MS);
    }

    /**
     * Load result graph binary
     *
     * @param filename
     * @param project
     * @param sensorContext
     * @throws GraphlibException
     */
    @Override
    protected void loadDataFromGraphBin(String filename, Project project, SensorContext sensorContext)
            throws GraphlibException {
        Graph graph = new Graph();
        graph.loadBinary(filename);

        saveLicense(graph, sensorContext);

        Node componentRoot = null;
        ComponentTreeLoaderVisitorCpp componentVisitor = null;
        NodeCounterVisitor nodeCounter = null;

        List<Node> components = graph.findNodes(new NodeType("Component"));
        for (Node component : components) {
            String name = GraphHelper.getNodeNameAttribute(component);
            if (name != null && name.equals("<System>")) {
                componentRoot = component;
                break;
            }
        }

        try {
            LOG.info("      * Initialization...");
            long startTime = System.currentTimeMillis();

            if (componentRoot != null) {
                nodeCounter = new NodeCounterVisitor();
                GraphHelper.processGraph(graph, componentRoot, "ComponentTree", nodeCounter);
                componentVisitor = new ComponentTreeLoaderVisitorCpp(this.perspectives, this.project,
                        this.sensorContext, this.fileSystem, nodeCounter.getNumberOfNodes());
            }

            nodeCounter = new NodeCounterVisitor();
            GraphHelper.processGraph(graph, "__LogicalRoot__", "LogicalTree", nodeCounter);
            LogicalTreeLoaderVisitorCpp logicalVisitor = new LogicalTreeLoaderVisitorCpp(this.fileSystem,
                    this.settings, this.perspectives, project, sensorContext, nodeCounter.getNumberOfNodes());

            nodeCounter = new NodeCounterVisitor();
            GraphHelper.processGraph(graph, "__PhysicalRoot__", "PhysicalTree", nodeCounter);
            PhysicalTreeLoaderVisitorCpp physicalVisitor = new PhysicalTreeLoaderVisitorCpp(fileSystem,
                    this.perspectives, this.project, this.sensorContext, nodeCounter.getNumberOfNodes());

            LOG.info("      * Initialization done: " + (System.currentTimeMillis() - startTime) + MS);

            if (componentVisitor != null) {
                LOG.info("      * Start processing ComponentTree...");
                GraphHelper.processGraph(graph, componentRoot, "ComponentTree", componentVisitor);
                LOG.info("      * ComponentTree processing time: " + componentVisitor.getComponentTime() + MS);
                componentVisitor = null;
            }

            LOG.info("      * Processing LogicalTree...");
            GraphHelper.processGraph(graph, "__LogicalRoot__", "LogicalTree", logicalVisitor);
            saveClassesInFilesMetric(logicalVisitor.getClassesInFiles(), SourceMeterCppMetrics.CLASSES_IN_FILE);
            saveClassesInFilesMetric(logicalVisitor.getMethodsInFiles(), SourceMeterCppMetrics.METHODS_IN_FILE);
            saveClassesInFilesMetric(logicalVisitor.getFilePathsForClasses(), SourceMeterCppMetrics.FILE_PATHS);
            saveClassesInFilesMetric(logicalVisitor.getFilePathsForMethods(), SourceMeterCppMetrics.FILE_PATHS);
            LOG.info("      * Processing LogicalTree done: " + logicalVisitor.getLogicalTime() + MS);
            logicalVisitor = null;

            LOG.info("      * Processing PhysicalTree...");
            GraphHelper.processGraph(graph, "__PhysicalRoot__", "PhysicalTree", physicalVisitor);
            LOG.info("      * Processing PhysicalTree done: " + physicalVisitor.getFileTime() + MS);
            physicalVisitor = null;

            CloneTreeLoaderVisitorCpp cloneVisitor = null;
            if (!this.isIncrementalMode) {
                nodeCounter = new NodeCounterVisitor();
                GraphHelper.processGraph(graph, "__CloneRoot__", "CloneTree", nodeCounter);
                cloneVisitor = new CloneTreeLoaderVisitorCpp(this.fileSystem, this.perspectives, project,
                        sensorContext, nodeCounter.getNumberOfNodes());
            }

            if (!this.isIncrementalMode) {
                LOG.info("      * Start processing CloneTree...");
                GraphHelper.processGraph(graph, "__CloneRoot__", "CloneTree", cloneVisitor);
                LOG.info("      * CloneTree processing time: " + cloneVisitor.getCloneTime() + MS);

                // Save duplications
                startTime = System.currentTimeMillis();
                LOG.info("    Save duplications...");

                Iterator<Entry<Resource, Set<String>>> dupIt = cloneVisitor.getDuplicationsMap().entrySet()
                        .iterator();
                while (dupIt.hasNext()) {
                    Map.Entry<Resource, Set<String>> pairs = dupIt.next();
                    Set<String> set = pairs.getValue();
                    StringBuffer tmp = new StringBuffer("<duplications>");
                    for (String cloneClass : set) {
                        tmp.append(cloneClass);
                    }
                    tmp.append("</duplications>");
                    sensorContext.saveMeasure(pairs.getKey(),
                            new Measure(CoreMetrics.DUPLICATIONS_DATA, tmp.toString()));
                    dupIt.remove(); // avoids a ConcurrentModificationException
                }
                LOG.info("    Save duplications done: " + (System.currentTimeMillis() - startTime) + MS);
                cloneVisitor = null;
            }
        } catch (VisitorException e) {
            throw (SonarException) new SonarException(e.getMessage()).initCause(e);
        } finally {
            graph = null;
        }
    }

    private void saveLicense(Graph graph, SensorContext sensorContext) {
        Map<String, String> headerLicenseInformations = new HashMap<String, String>();
        headerLicenseInformations.put("FaultHunterCPP", "FaultHunter");
        headerLicenseInformations.put("MetricHunter", "MetricHunter");
        headerLicenseInformations.put("DuplicatedCodeFinder", "Duplicated Code");
        headerLicenseInformations.put("LIM2Metrics", "Metrics");
        headerLicenseInformations.put("Cppcheck2Graph", "CPPCheck");

        super.saveLicense(graph, sensorContext, headerLicenseInformations, SourceMeterCppMetrics.CPP_LICENSE);
    }

    /**
     * Saves ClassData list for resources to the given metric.
     *
     * @param classData
     * @param metric
     */
    private void saveClassesInFilesMetric(Map<Resource, List<ClassData>> classData, Metric metric) {
        Gson gson = new Gson();
        Iterator<Entry<Resource, List<ClassData>>> iterator = classData.entrySet().iterator();
        while (iterator.hasNext()) {
            Entry<Resource, List<ClassData>> entry = iterator.next();
            String jsonClassesList = gson.toJson(entry.getValue()).toString();
            Measure measure = new Measure(metric);
            measure.setData(jsonClassesList);
            this.sensorContext.saveMeasure(entry.getKey(), measure);
        }
    }

}