001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2012 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 com.google.common.collect.Lists;
023    import com.google.common.collect.Sets;
024    import org.sonar.api.batch.SensorContext;
025    import org.sonar.api.measures.CoreMetrics;
026    import org.sonar.api.measures.Measure;
027    import org.sonar.api.measures.PersistenceMode;
028    import org.sonar.api.resources.Resource;
029    
030    import java.util.Collections;
031    import java.util.Comparator;
032    import java.util.List;
033    import java.util.Set;
034    
035    public class DuplicationsData {
036    
037      private final String resourceKey;
038      private final Set<Integer> duplicatedLines = Sets.newHashSet();
039      private final List<XmlEntry> duplicationXMLEntries = Lists.newArrayList();
040    
041      private double duplicatedBlocks;
042    
043      public DuplicationsData(String resourceKey) {
044        this.resourceKey = resourceKey;
045      }
046    
047      public void cumulate(String targetResourceKey, int targetDuplicationStartLine, int duplicationStartLine, int duplicatedLines) {
048        duplicationXMLEntries.add(new XmlEntry(targetResourceKey, targetDuplicationStartLine, duplicationStartLine, duplicatedLines));
049        for (int duplicatedLine = duplicationStartLine; duplicatedLine < duplicationStartLine + duplicatedLines; duplicatedLine++) {
050          this.duplicatedLines.add(duplicatedLine);
051        }
052      }
053    
054      public void incrementDuplicatedBlock() {
055        duplicatedBlocks++;
056      }
057    
058      public void save(SensorContext context, Resource resource) {
059        context.saveMeasure(resource, CoreMetrics.DUPLICATED_FILES, 1d);
060        context.saveMeasure(resource, CoreMetrics.DUPLICATED_LINES, (double) duplicatedLines.size());
061        context.saveMeasure(resource, CoreMetrics.DUPLICATED_BLOCKS, duplicatedBlocks);
062    
063        Measure data = new Measure(CoreMetrics.DUPLICATIONS_DATA, getDuplicationXMLData())
064            .setPersistenceMode(PersistenceMode.DATABASE);
065        context.saveMeasure(resource, data);
066      }
067    
068      private String getDuplicationXMLData() {
069        Collections.sort(duplicationXMLEntries, COMPARATOR);
070        StringBuilder duplicationXML = new StringBuilder("<duplications>");
071        for (XmlEntry xmlEntry : duplicationXMLEntries) {
072          duplicationXML.append(xmlEntry.toString());
073        }
074        duplicationXML.append("</duplications>");
075        return duplicationXML.toString();
076      }
077    
078      private static final Comparator<XmlEntry> COMPARATOR = new Comparator<XmlEntry>() {
079        public int compare(XmlEntry o1, XmlEntry o2) {
080          if (o1.startLine == o2.startLine) {
081            return o1.lines - o2.lines;
082          }
083          return o1.startLine - o2.startLine;
084        }
085      };
086    
087      private final class XmlEntry {
088        private final String target;
089        private final int targetStartLine;
090        private final int startLine;
091        private final int lines;
092    
093        private XmlEntry(String target, int targetStartLine, int startLine, int lines) {
094          this.target = target;
095          this.targetStartLine = targetStartLine;
096          this.startLine = startLine;
097          this.lines = lines;
098        }
099    
100        @Override
101        public String toString() {
102          return new StringBuilder()
103              .append("<g>")
104              .append("<b s=\"").append(startLine).append("\" l=\"").append(lines).append("\" r=\"").append(resourceKey).append("\" />")
105              .append("<b s=\"").append(targetStartLine).append("\" l=\"").append(lines).append("\" r=\"").append(target).append("\" />")
106              .append("</g>")
107              .toString();
108        }
109      }
110    
111    }