001/*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube 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 * SonarQube 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 License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019 */
020package org.sonar.api.batch.sensor.duplication;
021
022import com.google.common.annotations.Beta;
023import org.apache.commons.lang.builder.EqualsBuilder;
024import org.apache.commons.lang.builder.HashCodeBuilder;
025import org.apache.commons.lang.builder.ToStringBuilder;
026import org.apache.commons.lang.builder.ToStringStyle;
027import org.sonar.api.batch.sensor.SensorContext;
028
029import java.util.ArrayList;
030import java.util.List;
031
032/**
033 * Experimental, do not use.
034 * <p/>
035 * A {@link DuplicationGroup} is a list of duplicated {@link Block}s. One block
036 * is considered as the original code and all others are duplicates.
037 * Use {@link SensorContext#duplicationBuilder(org.sonar.api.batch.fs.InputFile)} and
038 * {@link SensorContext#saveDuplications(org.sonar.api.batch.fs.InputFile, List)}.
039 * @since 4.5
040 */
041@Beta
042public class DuplicationGroup {
043
044  public static class Block {
045    private final String resourceKey;
046    private final int startLine;
047    private final int length;
048
049    public Block(String resourceKey, int startLine, int length) {
050      this.resourceKey = resourceKey;
051      this.startLine = startLine;
052      this.length = length;
053    }
054
055    public String resourceKey() {
056      return resourceKey;
057    }
058
059    public int startLine() {
060      return startLine;
061    }
062
063    public int length() {
064      return length;
065    }
066
067    // Just for unit tests
068    @Override
069    public boolean equals(Object obj) {
070      if (obj == null) {
071        return false;
072      }
073      if (obj == this) {
074        return true;
075      }
076      if (obj.getClass() != getClass()) {
077        return false;
078      }
079      Block rhs = (Block) obj;
080      return new EqualsBuilder()
081        .append(resourceKey, rhs.resourceKey)
082        .append(startLine, rhs.startLine)
083        .append(length, rhs.length).isEquals();
084    }
085
086    @Override
087    public int hashCode() {
088      return new HashCodeBuilder(13, 43)
089        .append(resourceKey)
090        .append(startLine)
091        .append(length).toHashCode();
092    }
093
094    @Override
095    public String toString() {
096      return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).
097        append("resourceKey", resourceKey).
098        append("startLine", startLine).
099        append("length", length).
100        toString();
101    }
102  }
103
104  private final Block originBlock;
105  private List<Block> duplicates = new ArrayList<DuplicationGroup.Block>();
106
107  /**
108   * For unit test and internal use only.
109   */
110  public DuplicationGroup(Block originBlock) {
111    this.originBlock = originBlock;
112  }
113
114  /**
115   * For unit test and internal use only.
116   */
117  public void setDuplicates(List<Block> duplicates) {
118    this.duplicates = duplicates;
119  }
120
121  /**
122   * For unit test and internal use only.
123   */
124  public DuplicationGroup addDuplicate(Block anotherBlock) {
125    this.duplicates.add(anotherBlock);
126    return this;
127  }
128
129  public Block originBlock() {
130    return originBlock;
131  }
132
133  public List<Block> duplicates() {
134    return duplicates;
135  }
136
137  // Just for unit tests
138  @Override
139  public boolean equals(Object obj) {
140    if (obj == null) {
141      return false;
142    }
143    if (obj == this) {
144      return true;
145    }
146    if (obj.getClass() != getClass()) {
147      return false;
148    }
149    DuplicationGroup rhs = (DuplicationGroup) obj;
150    EqualsBuilder equalsBuilder = new EqualsBuilder()
151      .append(originBlock, rhs.originBlock)
152      .append(duplicates.size(), rhs.duplicates.size());
153    if (duplicates.size() == rhs.duplicates.size()) {
154      for (int i = 0; i < duplicates.size(); i++) {
155        equalsBuilder.append(duplicates.get(i), rhs.duplicates.get(i));
156      }
157    }
158    return equalsBuilder.isEquals();
159  }
160
161  @Override
162  public int hashCode() {
163    HashCodeBuilder hcBuilder = new HashCodeBuilder(17, 37)
164      .append(originBlock)
165      .append(duplicates.size());
166    for (int i = 0; i < duplicates.size(); i++) {
167      hcBuilder.append(duplicates.get(i));
168    }
169    return hcBuilder.toHashCode();
170  }
171
172  @Override
173  public String toString() {
174    return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).
175      append("origin", originBlock).
176      append("duplicates", duplicates, true).
177      toString();
178  }
179
180}