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