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.duplications.index;
021
022 import com.google.common.annotations.Beta;
023 import com.google.common.collect.ImmutableList;
024
025 import java.util.List;
026
027 /**
028 * Groups a set of related {@link ClonePart}s.
029 */
030 public class CloneGroup {
031
032 private final ClonePart originPart;
033 private final int cloneLength;
034 private final List<ClonePart> parts;
035
036 /**
037 * Cache for hash code.
038 */
039 private int hash;
040
041 /**
042 * @since 2.14
043 */
044 public static Builder builder() {
045 return new Builder();
046 }
047
048 /**
049 * @since 2.14
050 */
051 public static final class Builder {
052 private ClonePart origin;
053 private int length;
054 private int lengthInUnits;
055 private List<ClonePart> parts;
056
057 public Builder setLength(int length) {
058 this.length = length;
059 return this;
060 }
061
062 public Builder setOrigin(ClonePart origin) {
063 this.origin = origin;
064 return this;
065 }
066
067 public Builder setParts(List<ClonePart> parts) {
068 this.parts = ImmutableList.copyOf(parts);
069 return this;
070 }
071
072 public Builder setLengthInUnits(int length) {
073 this.lengthInUnits = length;
074 return this;
075 }
076
077 public CloneGroup build() {
078 return new CloneGroup(this);
079 }
080 }
081
082 private CloneGroup(Builder builder) {
083 this.cloneLength = builder.length;
084 this.originPart = builder.origin;
085 this.parts = builder.parts;
086 this.length = builder.lengthInUnits;
087 }
088
089 public ClonePart getOriginPart() {
090 return originPart;
091 }
092
093 private int length;
094
095 /**
096 * Length of duplication measured in original units, e.g. for token-based detection - in tokens.
097 *
098 * @since 2.14
099 */
100 @Beta
101 public int getLengthInUnits() {
102 return length;
103 }
104
105 /**
106 * @return clone length in {@link org.sonar.duplications.block.Block}s
107 */
108 public int getCloneUnitLength() {
109 return cloneLength;
110 }
111
112 public List<ClonePart> getCloneParts() {
113 return parts;
114 }
115
116 @Override
117 public String toString() {
118 StringBuilder builder = new StringBuilder();
119 for (ClonePart part : parts) {
120 builder.append(part).append(" - ");
121 }
122 builder.append(cloneLength);
123 return builder.toString();
124 }
125
126 /**
127 * Two groups are equal, if they have same length, same origins and contain same parts in same order.
128 */
129 @Override
130 public boolean equals(Object object) {
131 if (!(object instanceof CloneGroup)) {
132 return false;
133 }
134 CloneGroup another = (CloneGroup) object;
135 if (another.cloneLength != cloneLength || parts.size() != another.parts.size()) {
136 return false;
137 }
138 if (!originPart.equals(another.originPart)) {
139 return false;
140 }
141 boolean result = true;
142 for (int i = 0; i < parts.size(); i++) {
143 result &= another.parts.get(i).equals(parts.get(i));
144 }
145 return result;
146 }
147
148 @Override
149 public int hashCode() {
150 int h = hash;
151 if (h == 0 && cloneLength != 0) {
152 for (ClonePart part : parts) {
153 h = 31 * h + part.hashCode();
154 }
155 h = 31 * h + originPart.hashCode();
156 h = 31 * h + cloneLength;
157 hash = h;
158 }
159 return h;
160 }
161
162 }