001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2011 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.plugins.cpd;
021    
022    import java.util.ArrayList;
023    import java.util.Collections;
024    import java.util.Comparator;
025    import java.util.HashSet;
026    import java.util.List;
027    import java.util.Set;
028    
029    import org.sonar.api.batch.SensorContext;
030    import org.sonar.api.measures.CoreMetrics;
031    import org.sonar.api.measures.Measure;
032    import org.sonar.api.resources.Resource;
033    
034    public class DuplicationsData {
035    
036      private Resource resource;
037      private Set<Integer> duplicatedLines = new HashSet<Integer>();
038      private double duplicatedBlocks;
039      private List<XmlEntry> duplicationXMLEntries = new ArrayList<XmlEntry>();
040    
041      private SensorContext context;
042    
043      public DuplicationsData(Resource resource, SensorContext context) {
044        this.resource = resource;
045        this.context = context;
046      }
047    
048      public void cumulate(String targetResource, int targetDuplicationStartLine, int duplicationStartLine, int duplicatedLines) {
049        duplicationXMLEntries.add(new XmlEntry(targetResource, targetDuplicationStartLine, duplicationStartLine, duplicatedLines));
050        for (int duplicatedLine = duplicationStartLine; duplicatedLine < duplicationStartLine + duplicatedLines; duplicatedLine++) {
051          this.duplicatedLines.add(duplicatedLine);
052        }
053      }
054    
055      public void cumulate(Resource targetResource, int targetDuplicationStartLine, int duplicationStartLine, int duplicatedLines) {
056        cumulate(context.saveResource(targetResource), targetDuplicationStartLine, duplicationStartLine, duplicatedLines);
057      }
058    
059      public void incrementDuplicatedBlock() {
060        duplicatedBlocks++;
061      }
062    
063      public void save() {
064        context.saveMeasure(resource, CoreMetrics.DUPLICATED_FILES, 1d);
065        context.saveMeasure(resource, CoreMetrics.DUPLICATED_LINES, (double) duplicatedLines.size());
066        context.saveMeasure(resource, CoreMetrics.DUPLICATED_BLOCKS, duplicatedBlocks);
067        context.saveMeasure(resource, new Measure(CoreMetrics.DUPLICATIONS_DATA, getDuplicationXMLData()));
068      }
069    
070      private String getDuplicationXMLData() {
071        Collections.sort(duplicationXMLEntries, COMPARATOR);
072        StringBuilder duplicationXML = new StringBuilder("<duplications>");
073        for (XmlEntry xmlEntry : duplicationXMLEntries) {
074          duplicationXML.append(xmlEntry.toString());
075        }
076        duplicationXML.append("</duplications>");
077        return duplicationXML.toString();
078      }
079    
080      private static final Comparator<XmlEntry> COMPARATOR = new Comparator<XmlEntry>() {
081        public int compare(XmlEntry o1, XmlEntry o2) {
082          if (o1.startLine == o2.startLine) {
083            return o1.lines - o2.lines;
084          }
085          return o1.startLine - o2.startLine;
086        }
087      };
088    
089      private static final class XmlEntry {
090        private String target;
091        private int targetStartLine;
092        private int startLine;
093        private int lines;
094    
095        private XmlEntry(String target, int targetStartLine, int startLine, int lines) {
096          this.target = target;
097          this.targetStartLine = targetStartLine;
098          this.startLine = startLine;
099          this.lines = lines;
100        }
101    
102        @Override
103        public String toString() {
104          return new StringBuilder().append("<duplication lines=\"").append(lines)
105              .append("\" start=\"").append(startLine)
106              .append("\" target-start=\"").append(targetStartLine)
107              .append("\" target-resource=\"").append(target).append("\"/>")
108              .toString();
109        }
110      }
111    
112    }