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.internal;
021
022import org.sonar.api.batch.sensor.internal.SensorStorage;
023
024import com.google.common.base.Preconditions;
025import org.apache.commons.lang.builder.EqualsBuilder;
026import org.apache.commons.lang.builder.HashCodeBuilder;
027import org.apache.commons.lang.builder.ToStringBuilder;
028import org.apache.commons.lang.builder.ToStringStyle;
029import org.sonar.api.batch.fs.InputFile;
030import org.sonar.api.batch.fs.internal.DefaultInputFile;
031import org.sonar.api.batch.sensor.duplication.Duplication;
032import org.sonar.api.batch.sensor.duplication.NewDuplication;
033import org.sonar.api.batch.sensor.internal.DefaultStorable;
034
035import javax.annotation.Nullable;
036
037import java.util.LinkedList;
038import java.util.List;
039
040public class DefaultDuplication extends DefaultStorable implements NewDuplication, Duplication {
041
042  private Block originBlock;
043  private List<Block> duplicates = new LinkedList<Duplication.Block>();
044
045  public DefaultDuplication() {
046    super();
047  }
048
049  public DefaultDuplication(@Nullable SensorStorage storage) {
050    super(storage);
051  }
052
053  @Override
054  public DefaultDuplication originBlock(InputFile inputFile, int startLine, int endLine) {
055    Preconditions.checkArgument(inputFile != null, "InputFile can't be null");
056    validateLineArgument(inputFile, startLine, "startLine");
057    validateLineArgument(inputFile, endLine, "endLine");
058    originBlock = new Duplication.Block(((DefaultInputFile) inputFile).key(), startLine, endLine - startLine + 1);
059    return this;
060  }
061
062  @Override
063  public DefaultDuplication isDuplicatedBy(InputFile sameOrOtherFile, int startLine, int endLine) {
064    Preconditions.checkArgument(sameOrOtherFile != null, "InputFile can't be null");
065    validateLineArgument(sameOrOtherFile, startLine, "startLine");
066    validateLineArgument(sameOrOtherFile, endLine, "endLine");
067    return isDuplicatedBy(((DefaultInputFile) sameOrOtherFile).key(), startLine, endLine);
068  }
069
070  /**
071   * For internal use. Global duplications are referencing files outside of current project so
072   * no way to manipulate an InputFile.
073   */
074  public DefaultDuplication isDuplicatedBy(String fileKey, int startLine, int endLine) {
075    Preconditions.checkNotNull(originBlock, "Call originBlock() first");
076    duplicates.add(new Duplication.Block(fileKey, startLine, endLine - startLine + 1));
077    return this;
078  }
079
080  @Override
081  public void doSave() {
082    Preconditions.checkNotNull(originBlock, "Call originBlock() first");
083    Preconditions.checkState(!duplicates.isEmpty(), "No duplicates. Call isDuplicatedBy()");
084    storage.store(this);
085  }
086
087  @Override
088  public Block originBlock() {
089    return originBlock;
090  }
091
092  public DefaultDuplication setOriginBlock(Block originBlock) {
093    this.originBlock = originBlock;
094    return this;
095  }
096
097  @Override
098  public List<Block> duplicates() {
099    return duplicates;
100  }
101
102  // Just for unit tests
103  @Override
104  public boolean equals(Object obj) {
105    if (obj == null) {
106      return false;
107    }
108    if (obj == this) {
109      return true;
110    }
111    if (obj.getClass() != getClass()) {
112      return false;
113    }
114    DefaultDuplication rhs = (DefaultDuplication) obj;
115    EqualsBuilder equalsBuilder = new EqualsBuilder()
116      .append(originBlock, rhs.originBlock)
117      .append(duplicates.size(), rhs.duplicates.size());
118    if (duplicates.size() == rhs.duplicates.size()) {
119      for (int i = 0; i < duplicates.size(); i++) {
120        equalsBuilder.append(duplicates.get(i), rhs.duplicates.get(i));
121      }
122    }
123    return equalsBuilder.isEquals();
124  }
125
126  @Override
127  public int hashCode() {
128    HashCodeBuilder hcBuilder = new HashCodeBuilder(17, 37)
129      .append(originBlock)
130      .append(duplicates.size());
131    for (int i = 0; i < duplicates.size(); i++) {
132      hcBuilder.append(duplicates.get(i));
133    }
134    return hcBuilder.toHashCode();
135  }
136
137  @Override
138  public String toString() {
139    return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).
140      append("origin", originBlock).
141      append("duplicates", duplicates, true).
142      toString();
143  }
144
145}