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