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 */
020package org.sonar.duplications.block;
021
022import com.google.common.annotations.Beta;
023import org.sonar.duplications.CodeFragment;
024
025/**
026 * Represents part of source code between two lines.
027 * If two blocks have the same {@link #getBlockHash() hash}, then we assume that there is a duplication in a code, which they represent.
028 */
029public final class Block implements CodeFragment {
030
031  private final String resourceId;
032  private final ByteArray blockHash;
033  private final int indexInFile;
034
035  private final int startLine;
036  private final int endLine;
037
038  private int startUnit;
039  private int endUnit;
040
041  /**
042   * Cache for hash code.
043   */
044  private int hash;
045
046  /**
047   * @since 2.14
048   */
049  public static Builder builder() {
050    return new Builder();
051  }
052
053  /**
054   * <p>Instances can be reused - it is safe to call {@link #build}
055   * multiple times to build multiple blocks in series.</p>
056   *
057   * @since 2.14
058   */
059  public static final class Builder {
060
061    private String resourceId;
062    private ByteArray blockHash;
063    private int indexInFile;
064
065    private int startLine;
066    private int endLine;
067
068    private int startUnit;
069    private int endUnit;
070
071    public Builder setResourceId(String resourceId) {
072      this.resourceId = resourceId;
073      return this;
074    }
075
076    public Builder setBlockHash(ByteArray blockHash) {
077      this.blockHash = blockHash;
078      return this;
079    }
080
081    public Builder setIndexInFile(int index) {
082      this.indexInFile = index;
083      return this;
084    }
085
086    public Builder setLines(int start, int end) {
087      this.startLine = start;
088      this.endLine = end;
089      return this;
090    }
091
092    @Beta
093    public Builder setUnit(int start, int end) {
094      this.startUnit = start;
095      this.endUnit = end;
096      return this;
097    }
098
099    public Block build() {
100      return new Block(this);
101    }
102  }
103
104  private Block(Builder builder) {
105    this.resourceId = builder.resourceId;
106    this.blockHash = builder.blockHash;
107    this.indexInFile = builder.indexInFile;
108
109    this.startLine = builder.startLine;
110    this.endLine = builder.endLine;
111
112    this.startUnit = builder.startUnit;
113    this.endUnit = builder.endUnit;
114  }
115
116  public String getHashHex() {
117    return getBlockHash().toString();
118  }
119
120  public String getResourceId() {
121    return resourceId;
122  }
123
124  public ByteArray getBlockHash() {
125    return blockHash;
126  }
127
128  public int getIndexInFile() {
129    return indexInFile;
130  }
131
132  public int getStartLine() {
133    return startLine;
134  }
135
136  public int getEndLine() {
137    return endLine;
138  }
139
140  /**
141   * @since 2.14
142   */
143  @Beta
144  public int getStartUnit() {
145    return startUnit;
146  }
147
148  /**
149   * @since 2.14
150   */
151  @Beta
152  public int getEndUnit() {
153    return endUnit;
154  }
155
156  @Override
157  public boolean equals(Object obj) {
158    if (!(obj instanceof Block)) {
159      return false;
160    }
161    Block other = (Block) obj;
162    return resourceId.equals(other.resourceId)
163      && blockHash.equals(other.blockHash)
164      && indexInFile == other.indexInFile
165      && startLine == other.startLine
166      && endLine == other.endLine;
167  }
168
169  @Override
170  public int hashCode() {
171    int h = hash;
172    if (h == 0) {
173      h = resourceId.hashCode();
174      h = 31 * h + blockHash.hashCode();
175      h = 31 * h + indexInFile;
176      h = 31 * h + startLine;
177      h = 31 * h + endLine;
178      hash = h;
179    }
180    return h;
181  }
182
183  @Override
184  public String toString() {
185    return "'" + resourceId + "'[" + indexInFile + "|" + startLine + "-" + endLine + "]:" + blockHash;
186  }
187
188}