001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2009 SonarSource SA
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.squid.api;
021
022 import java.util.Set;
023 import java.util.SortedSet;
024 import java.util.TreeSet;
025
026 import org.sonar.squid.measures.Measurable;
027 import org.sonar.squid.measures.Measures;
028 import org.sonar.squid.measures.Metric;
029
030 public abstract class SourceCode implements Measurable, Comparable<SourceCode> {
031
032 private final String name;
033 private Measures measures = new Measures();
034 private final String key;
035 private int startAtLine = -1;
036 private int endAtLine = -1;
037 private SourceCode parent;
038 private SortedSet<SourceCode> children;
039 private SourceCodeIndexer indexer;
040
041 public SourceCode(String key) {
042 this(key, null);
043 }
044
045 public SourceCode(String key, String name) {
046 this.key = key;
047 this.name = name;
048 }
049
050 public String getKey() {
051 return key;
052 }
053
054 public int compareTo(SourceCode resource) {
055 return key.compareTo(resource.getKey());
056 }
057
058 public String getName() {
059 return name;
060 }
061
062 public final void setSourceCodeIndexer(SourceCodeIndexer indexer) {
063 this.indexer = indexer;
064 }
065
066 private void index(SourceCode sourceCode) {
067 if (indexer != null) {
068 indexer.index(sourceCode);
069 }
070 }
071
072 @Override
073 public boolean equals(Object obj) {
074 return (obj instanceof SourceCode) && key.equals(((SourceCode) obj).key);
075 }
076
077 @Override
078 public int hashCode() {
079 return key.hashCode();
080 }
081
082 @Override
083 public String toString() {
084 return getKey();
085 }
086
087 public final void computeMeasures() {
088 if (hasChildren()) {
089 for (SourceCode child : getChildren()) {
090 child.computeMeasures();
091 }
092 }
093 for (Metric metric : Metric.values()) {
094 if (!metric.aggregateIfThereIsAlreadyAValue() && getDouble(metric) != 0) {
095 continue;
096 }
097 if (hasChildren()) {
098 for (SourceCode child : getChildren()) {
099 if (!metric.isCalculatedMetric() && metric.isThereAggregationFormula()) {
100 add(metric, child);
101 }
102 }
103 }
104 }
105 }
106
107 public boolean isType(Class<? extends SourceCode> resourceType) {
108 return this.getClass() == resourceType;
109 }
110
111 /**
112 * {@inheritDoc}
113 */
114 public int getInt(Metric metric) {
115 return (int) getMeasure(metric);
116 }
117
118 /**
119 * {@inheritDoc}
120 */
121 public double getDouble(Metric metric) {
122 return getMeasure(metric);
123 }
124
125 public void add(Metric metric, SourceCode child) {
126 add(metric, child.getMeasure(metric));
127 }
128
129 public void add(Metric metric, double value) {
130 setMeasure(metric, getMeasure(metric) + value);
131 }
132
133 public void addData(Metric metric, Object data) {
134 measures.setData(metric, data);
135 }
136
137 public Object getData(Metric metric) {
138 return measures.getData(metric);
139 }
140
141 private double getMeasure(Metric metric) {
142 if (metric.isCalculatedMetric()) {
143 return metric.getCalculatedMetricFormula().calculate(this);
144 }
145 return measures.getValue(metric);
146 }
147
148 /**
149 * {@inheritDoc}
150 */
151 public void setMeasure(Metric metric, double measure) {
152 if (metric.isCalculatedMetric()) {
153 throw new IllegalStateException("It's not allowed to set the value of a calculated metric : " + metric.name());
154 }
155 measures.setValue(metric, measure);
156 }
157
158 /**
159 * {@inheritDoc}
160 */
161 public void setMeasure(Metric metric, int measure) {
162 setMeasure(metric, (double) measure);
163 }
164
165 public void removeMeasure(Metric metric) {
166 measures.removeMeasure(metric);
167 }
168
169 public void setStartAtLine(int startAtLine) {
170 this.startAtLine = startAtLine;
171 this.endAtLine = startAtLine;
172 }
173
174 public void setEndAtLine(int endAtLine) {
175 this.endAtLine = endAtLine;
176 }
177
178 public int getStartAtLine() {
179 return startAtLine;
180 }
181
182 public int getEndAtLine() {
183 return endAtLine;
184 }
185
186 public SourceCode addChild(SourceCode sourceCode) {
187 if (children == null) {
188 children = new TreeSet<SourceCode>();
189 }
190 sourceCode.setParent(this);
191 if (!children.contains(sourceCode)) {
192 children.add(sourceCode);
193 index(sourceCode);
194 }
195 return this;
196 }
197
198 public SourceCode getParent(Class<? extends SourceCode> sourceCode) {
199 if (parent == null) {
200 return null;
201 } else if (parent.getClass().equals(sourceCode)) {
202 return parent;
203 } else {
204 return parent.getParent(sourceCode);
205 }
206 }
207
208 public SourceCode getFirstChild() {
209 return !children.isEmpty() ? children.first() : null;
210 }
211
212 public SourceCode getLastChild() {
213 return !children.isEmpty() ? children.last() : null;
214 }
215
216 private void setParent(SourceCode parent) {
217 this.parent = parent;
218 }
219
220 public SourceCode getParent() {
221 return parent;
222 }
223
224 public Set<SourceCode> getChildren() {
225 return children;
226 }
227
228 public boolean hasChild(SourceCode squidUnit) {
229 if (!hasChildren()) {
230 return false;
231 }
232 if (children.contains(squidUnit)) {
233 return true;
234 }
235 for (SourceCode child : children) {
236 if (child.hasChild(squidUnit)) {
237 return true;
238 }
239 }
240 return false;
241 }
242
243 private boolean hasChildren() {
244 return children != null && children.size() != 0;
245 }
246
247 public boolean hasAmongParents(SourceCode expectedParent) {
248 if (parent == null) {
249 return false;
250 }
251 return parent.equals(expectedParent) || parent.hasAmongParents(expectedParent);
252 }
253 }