All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.plugins.php.cpd.PhpCpdResultParser Maven / Gradle / Ivy

Go to download

Sonar PHP Plugin is set of tools that brings PHP support to sonar. It relies on Sonar core, PHP Depend, PHPMD, PHP_CodeSniffer and PHPUnit

There is a newer version: 2.4.1
Show newest version
/*
 * Sonar PHP Plugin
 * Copyright (C) 2010 Codehaus Sonar Plugins
 * [email protected]
 *
 * 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, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
 */
package org.sonar.plugins.php.cpd;

import static org.sonar.api.measures.CoreMetrics.DUPLICATED_BLOCKS;
import static org.sonar.api.measures.CoreMetrics.DUPLICATED_FILES;
import static org.sonar.api.measures.CoreMetrics.DUPLICATED_LINES;
import static org.sonar.api.measures.CoreMetrics.DUPLICATIONS_DATA;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.BatchExtension;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.measures.Measure;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.utils.SonarException;
import org.sonar.plugins.php.cpd.xml.DuplicationNode;
import org.sonar.plugins.php.cpd.xml.FileNode;
import org.sonar.plugins.php.cpd.xml.PmdCpdNode;

import com.thoughtworks.xstream.XStream;

/**
 * Parses the php-cpd file to get xopy paste information metrics.
 * 
 * @author akram
 * 
 */
public class PhpCpdResultParser implements BatchExtension {

  private static final Logger LOG = LoggerFactory.getLogger(PhpCpdResultParser.class);
  /**
   * The context.
   */
  private SensorContext context;

  /**
   * The project.
   */
  private Project project;

  /**
   * @param project
   * @param context
   */
  public PhpCpdResultParser(Project project, SensorContext context) {
    this.project = project;
    this.context = context;
  }

  /**
   * Parses the report file.
   */
  public void parse(File file) {
    // If no files can be found, plugin will stop normally only logging the error
    if ( !file.exists()) {
      LOG.error("Result file not found : " + file.getAbsolutePath() + ". Plugin will stop");
      return;
    }
    try {
      LOG.info("Collecting measures...");
      parseFile(context, file, project);
    } catch (Exception e) {
      LOG.error("Report file is invalid or can't be found, plugin will stop.", e);
      throw new SonarException(e);
    }
  }

  /**
   * Parses the file.
   * 
   * @param context
   *          the context
   * @param file
   *          the coverage report file
   * @param project
   *          the project
   */
  private void parseFile(SensorContext context, File file, Project project) {
    List duplications = getDuplications(file);
    Map, ClassDuplicationData> duplicationsData = new HashMap, ClassDuplicationData>();

    for (DuplicationNode duplication : duplications) {
      List files = duplication.getFiles();
      FileNode fileA = files.get(0);
      FileNode fileB = files.get(1);
      processClassMeasure(context, duplicationsData, fileB, fileA, duplication, project);
      processClassMeasure(context, duplicationsData, fileA, fileB, duplication, project);
    }

    for (ClassDuplicationData data : duplicationsData.values()) {
      data.saveUsing(context);
    }
  }

  /**
   * @param context
   * @param duplicationsData
   * @param original
   * @param copied
   * @param duplication
   * @param project
   */
  private void processClassMeasure(SensorContext context, Map, ClassDuplicationData> duplicationsData, FileNode original,
      FileNode copied, DuplicationNode duplication, Project project) {
    org.sonar.api.resources.File file = org.sonar.api.resources.File.fromIOFile(new File(copied.getPath()), project);
    org.sonar.api.resources.File targetPhpClass = org.sonar.api.resources.File.fromIOFile(new File(original.getPath()), project);
    if (file != null) {
      ClassDuplicationData data = duplicationsData.get(file);
      if (data == null) {
        data = new ClassDuplicationData(file, context);
        duplicationsData.put(file, data);
      }
      data.cumulate(targetPhpClass, original.getLineNumber(), copied.getLineNumber(), duplication.getLines());
    }

  }

  /**
   * Gets the duplications.
   * 
   * @param reportFile
   *          the report file
   * @return the coverage
   */
  private List getDuplications(File reportFile) {
    InputStream inputStream = null;
    try {
      XStream xstream = new XStream();
      xstream.setClassLoader(getClass().getClassLoader());
      xstream.aliasSystemAttribute("classType", "class");
      xstream.processAnnotations(PmdCpdNode.class);
      xstream.processAnnotations(DuplicationNode.class);
      xstream.processAnnotations(FileNode.class);
      inputStream = new FileInputStream(reportFile);
      PmdCpdNode node = (PmdCpdNode) xstream.fromXML(inputStream);
      if (node.getDuplications() != null) {
        return node.getDuplications();
      }
    } catch (IOException e) {
      throw new SonarException("Can't read phpcpd report : " + reportFile.getName(), e);
    } finally {
      IOUtils.closeQuietly(inputStream);
    }
    return new ArrayList();
  }

  /**
   * Models duplication.
   * 
   * @author akram
   * 
   */
  private static final class ClassDuplicationData {

    private static final String SONAR_DUPLICATION_CLOSING_TAG = "\"/>";
    private static final String SONAR_TARGET_RESOURCE_ATTRIBUTE = "\" target-resource=\"";
    private static final String SONAR_DUPLICATION_DUPLICATION_LINES_TAG = " resource;
    private SensorContext context;
    private List duplicationXMLEntries = new ArrayList();

    /**
     * Constructor.
     * 
     * @param resource
     * @param context
     */
    private ClassDuplicationData(Resource resource, SensorContext context) {
      this.context = context;
      this.resource = resource;
    }

    /**
     * Build XML for sonar dashboard to display duplicated code.
     * 
     * @param target
     * @param targetDuplicationStartLine
     * @param duplicationStartLine
     * @param duplicatedLines
     */

    protected void cumulate(Resource target, Double targetDuplicationStartLine, Double duplicationStartLine, Double duplicatedLines) {
      Resource resolvedResource = context.getResource(target);
      if (resolvedResource != null) {
        StringBuilder xml = new StringBuilder(SONAR_DUPLICATION_DUPLICATION_LINES_TAG);
        xml.append(duplicatedLines.intValue()).append(SONAR_DUPLICATION_START_ATTRIBUTE).append(duplicationStartLine.intValue());
        xml.append(SONAR_DUPLICATION_TARGET_START_TAG).append(targetDuplicationStartLine.intValue());
        xml.append(SONAR_TARGET_RESOURCE_ATTRIBUTE).append(resolvedResource.getEffectiveKey()).append(SONAR_DUPLICATION_CLOSING_TAG);

        duplicationXMLEntries.add(xml);
        this.duplicatedLines += duplicatedLines;
        this.duplicatedBlocks++;
      }
    }

    /**
     * Save the metrics values and the duplicated code as XML.
     * 
     * @param context
     */
    protected void saveUsing(SensorContext context) {
      context.saveMeasure(resource, DUPLICATED_FILES, 1d);
      context.saveMeasure(resource, DUPLICATED_LINES, duplicatedLines);
      context.saveMeasure(resource, DUPLICATED_BLOCKS, duplicatedBlocks);
      context.saveMeasure(resource, new Measure(DUPLICATIONS_DATA, getDuplicationXMLData()));
    }

    private String getDuplicationXMLData() {
      StringBuilder duplicationXML = new StringBuilder(SONAR_DUPLICATION_START_TAG);
      for (StringBuilder xmlEntry : duplicationXMLEntries) {
        duplicationXML.append(xmlEntry);
      }
      duplicationXML.append(SONAR_DUPLICATIONS_END_TAG);
      return duplicationXML.toString();
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy