Package ch.hortis.sonar.mvn.mc

Source Code of ch.hortis.sonar.mvn.mc.CPDCollector$CPDFileReportDataContainer

/*
* This program is copyright (c) 2007 Hortis-GRC SA.
*
* This file is part of Sonar.
* Sonar is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Sonar 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Sonar; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package ch.hortis.sonar.mvn.mc;

import ch.hortis.sonar.model.Collectable;
import ch.hortis.sonar.model.File;
import ch.hortis.sonar.model.FileMeasure;
import ch.hortis.sonar.model.Metric;
import ch.hortis.sonar.model.Metrics;
import ch.hortis.sonar.model.ProjectMeasure;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.xpath.XPathConstants;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class CPDCollector extends BaseMeasuresCollector {
  private Metric duplicationMetric;
  private Metric duplicatedLinesMetric;
  private Metric duplicatedTokensMetric;

  private XmlReportParser parser;
  private List sourcesDir;

  public boolean initialize(MavenProject project) {
    java.io.File cpdFile = findFileFromBuildDirectory(project, "cpd.xml");

    boolean ok = false;
    if (cpdFile != null) {
      String xml = readXmlWithoutEncodingErrors(cpdFile);
      parser = new XmlReportParser();
      parser.parse(xml);
      sourcesDir = project.getCompileSourceRoots();
      duplicationMetric = loadMetric(Metrics.PMD_DUPLICATION);
      duplicatedLinesMetric = loadMetric(Metrics.PMD_DUPLICATED_LINES);
      duplicatedTokensMetric = loadMetric(Metrics.PMD_DUPLICATED_TOKENS);
      ok = true;
    }
    return ok;
  }

  public List<Collectable> collect() throws MojoExecutionException {
    ArrayList<Collectable> result = new ArrayList<Collectable>();
    result.addAll(collectProjectMeasures());
    result.addAll(collectFileMeasures());
    return result;
  }

   protected String readXmlWithoutEncodingErrors(java.io.File file) {
     try {
       // First step : the file is read with system charset encoding. It should resolve the problem in most cases
       String xml = FileUtils.readFileToString(file);

       // second step : remove CDATA nodes that contain wrong characters. Those nodes are not needed by the collector.
       return removeCDataNodes(xml);
     } catch (IOException e) {
       throw new XmlParserException("can not read the file " + file.getAbsolutePath(), e);
     }
   }

  protected String removeCDataNodes(String xml) {
    String result = xml;
    String startNode = "<codefragment>";
    String endNode = "</codefragment>";
    String[] subs = StringUtils.substringsBetween(xml, startNode, endNode);
    if (subs!=null) {
      for (String sub:subs) {
        result = StringUtils.remove(result, startNode + sub + endNode);
      }
    }
    return result;
  }

  protected List<ProjectMeasure> collectProjectMeasures() throws MojoExecutionException {
    NodeList duplications = parser.executeXPathNodeList("/pmd-cpd/duplication");
    CPDReportDataContainer projectContainer = new CPDReportDataContainer();

    for (int i = 0; i < duplications.getLength(); i++) {
      Node duplication = duplications.item(i);
      Number lines = (Number) parser.executeXPath(duplication, XPathConstants.NUMBER, "@lines");
      Number tokens = (Number) parser.executeXPath(duplication, XPathConstants.NUMBER, "@tokens");
      projectContainer.cumulate(1, lines, tokens);
    }
    return projectContainer.asMeasures();
  }

  public List<FileMeasure> collectFileMeasures() throws MojoExecutionException {
    ArrayList<FileMeasure> result = new ArrayList<FileMeasure>();
    NodeList duplications = parser.executeXPathNodeList("/pmd-cpd/duplication");
    Map<String, CPDFileReportDataContainer> fileContainer = new HashMap<String, CPDFileReportDataContainer>();
    for (int i = 0; i < duplications.getLength(); i++) {
      Element duplication = (Element) duplications.item(i);

      NodeList files = parser.executeXPathNodeList(duplication, "file");
      processFileMeasure(fileContainer, (Element) files.item(0), duplication);
      processFileMeasure(fileContainer, (Element) files.item(1), duplication);
    }

    for (CPDFileReportDataContainer data : fileContainer.values()) {
      result.addAll(data.asMeasures());
    }
    return result;
  }

  private void processFileMeasure(Map<String, CPDFileReportDataContainer> fileContainer, Element fileEl, Element duplication) throws MojoExecutionException {
    String filePath = fileEl.getAttribute("path").replace('\\', '/');
    String fileName = StringUtils.substringAfterLast(filePath, "/");
    String packageName = StringUtils.substringBeforeLast(filePath, "/");
    if (sourcesDir != null) {
      for (Iterator<String> srcItr = sourcesDir.iterator(); srcItr.hasNext();) {
        String sourceDir = srcItr.next().replace('\\', '/');
        if (packageName.startsWith(sourceDir) || packageName.contains(sourceDir)) {
          if (!sourceDir.endsWith("/")) {
            sourceDir += "/";
          }
          packageName = StringUtils.substringAfter(packageName, sourceDir).replace('/', '.');
          packageName = packageName.replace('/', '.');

          CPDFileReportDataContainer data = fileContainer.get(packageName + fileName);
          if (data == null) {
            File file = getFilesRepository().getFile(packageName, fileName);
            if (file == null) {
              throw new MojoExecutionException("Unable to find file '" + fileName + "' in package '" + packageName + "'");
            }
            data = new CPDFileReportDataContainer(file);
            fileContainer.put(packageName + fileName, data);
          }

          try {
            data.cumulate(1, parseNumber(duplication.getAttribute("lines")), parseNumber(duplication.getAttribute("tokens")));
          } catch (ParseException e) {
            throw new MojoExecutionException("Number parsing exception", e);
          }
        }
      }
    }
  }

  private class CPDReportDataContainer {
    protected double duplication;
    protected double duplicatedLines;
    protected double duplicatedTokens;

    protected void cumulate(Number duplication, Number duplicatedLines, Number duplicatedTokens) {
      this.duplication += duplication.doubleValue();
      this.duplicatedLines += duplicatedLines.doubleValue();
      this.duplicatedTokens += duplicatedTokens.doubleValue();
    }

    private List<ProjectMeasure> asMeasures() {
      List<ProjectMeasure> measures = new ArrayList<ProjectMeasure>();
      ProjectMeasure measure = new ProjectMeasure();
      measure.setMetric(duplicationMetric);
      measure.setValue(duplication);
      measures.add(measure);

      measure = new ProjectMeasure();
      measure.setMetric(duplicatedLinesMetric);
      measure.setValue(duplicatedLines);
      measures.add(measure);

      measure = new ProjectMeasure();
      measure.setMetric(duplicatedTokensMetric);
      measure.setValue(duplicatedTokens);
      measures.add(measure);

      return measures;
    }
  }

  private class CPDFileReportDataContainer extends CPDReportDataContainer {
    private File file;

    private CPDFileReportDataContainer(File file) {
      this.file = file;
    }

    private Collection<FileMeasure> asMeasures() {
      Collection<FileMeasure> measures = new ArrayList<FileMeasure>();
      FileMeasure measure = new FileMeasure();
      measure.setMetric(duplicationMetric);
      measure.setFile(file);
      measure.setValue(duplication);
      measures.add(measure);

      measure = new FileMeasure();
      measure.setMetric(duplicatedLinesMetric);
      measure.setFile(file);
      measure.setValue(duplicatedLines);
      measures.add(measure);

      measure = new FileMeasure();
      measure.setMetric(duplicatedTokensMetric);
      measure.setFile(file);
      measure.setValue(duplicatedTokens);
      measures.add(measure);

      return measures;
    }
  }
}
TOP

Related Classes of ch.hortis.sonar.mvn.mc.CPDCollector$CPDFileReportDataContainer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.