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.HashMap;
023 import java.util.Map;
024 import java.util.Set;
025 import java.util.StringTokenizer;
026
027 import org.apache.commons.io.IOUtils;
028 import org.sonar.squid.graph.Edge;
029 import org.sonar.squid.graph.EdgeUsage;
030 import org.sonar.squid.graph.Node;
031 import org.sonar.squid.measures.Measurable;
032 import org.sonar.squid.measures.Metric;
033
034 public abstract class SourceCode extends TreeNode<SourceCode> implements Node, Measurable, Comparable<SourceCode> {
035
036 private final String name;
037 private Map<Metric, Double> measures = new HashMap<Metric, Double>();
038 private final String key;
039 private Map<Node, Edge> dependedUpon = new HashMap<Node, Edge>();
040 private Map<Node, Edge> dependsUpon = new HashMap<Node, Edge>();
041 private int startAtLine = -1;
042 private int endAtLine = -1;
043
044 public SourceCode(String key) {
045 this(key, null);
046 }
047
048 public SourceCode(String key, String name) {
049 this.name = name;
050 this.key = key;
051 initializeMeasures();
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 @Override
067 public boolean equals(Object obj) {
068 if (!(obj instanceof SourceCode)) {
069 return false;
070 }
071 return getKey().equals(((SourceCode) obj).getKey());
072 }
073
074 @Override
075 public int hashCode() {
076 return key.hashCode();
077 }
078
079 @Override
080 public String toString() {
081 StringBuilder sb = new StringBuilder(512);
082 sb.append(this.getClass().getSimpleName()).append(" : ").append(getKey()).append(IOUtils.LINE_SEPARATOR);
083 for (SourceCode child : getChildren()) {
084 String childTree = child.toString();
085 StringTokenizer tokenizer = new StringTokenizer(childTree, IOUtils.LINE_SEPARATOR);
086 while (tokenizer.hasMoreTokens()) {
087 sb.append("-").append(tokenizer.nextToken()).append(IOUtils.LINE_SEPARATOR);
088 }
089 }
090 return sb.toString();
091 }
092
093 public final void computeMeasures() {
094 for (SourceCode child : getChildren()) {
095 child.computeMeasures();
096 }
097 for (Metric metric : Metric.values()) {
098 if (!metric.aggregateIfThereIsAlreadyAValue() && getDouble(metric) != 0) {
099 continue;
100 }
101 for (SourceCode child : getChildren()) {
102 if (!metric.isCalculatedMetric() && metric.isThereAggregationFormula()) {
103 add(metric, child);
104 }
105 }
106
107 }
108 updateMeasuresAfterConsolidation();
109 }
110
111 public void createEdgeWith(Node to, EdgeUsage link) {
112 createEdgeWith(to, link, (Edge) null);
113 }
114
115 public void createEdgeWith(Node to, EdgeUsage link, Edge rootEdge) {
116 if (equals(to)) {
117 throw new IllegalStateException("You can't create an edge from one node to itself. SquidUnit : " + getKey());
118 }
119 if (getEdgeTo(to) != null) {
120 throw new IllegalStateException("Those two nodes are already linked. From : " + getKey() + ", To : " + to.getKey());
121 }
122 Edge edge = new Edge(this, to, link, null);
123 edge.addRootEdge(rootEdge);
124
125 dependsUpon.put(to, edge);
126 ((SourceCode) to).dependedUpon.put(this, edge);
127 }
128
129 public Edge getEdgeTo(Node to) {
130 return dependsUpon.get(to);
131 }
132
133 public Edge getEdgeFrom(Node from) {
134 return dependedUpon.get(from);
135 }
136
137 public EdgeUsage getUsageOf(Node to) {
138 Edge relation = dependsUpon.get(to);
139 if (relation == null) {
140 return EdgeUsage.NO_LINK;
141 }
142 return relation.getUsage();
143 }
144
145 public EdgeUsage getUsageBy(Node from) {
146 Edge edge = dependedUpon.get(from);
147 if (edge == null) {
148 return EdgeUsage.NO_LINK;
149 }
150 return edge.getUsage();
151 }
152
153 public Set<Node> dependedUpon() {
154 return dependedUpon.keySet();
155 }
156
157 public Set<Node> dependsUpon() {
158 return dependsUpon.keySet();
159 }
160
161 public boolean isType(Class<? extends SourceCode> resourceType) {
162 return this.getClass() == resourceType;
163 }
164
165 public int getInt(Metric metric) {
166 return getMeasure(metric).intValue();
167 }
168
169 public double getDouble(Metric metric) {
170 return getMeasure(metric).doubleValue();
171 }
172
173 public void add(Metric metric, SourceCode child) {
174 add(metric, child.getMeasure(metric));
175 }
176
177 public void add(Metric metric, double value) {
178 setMeasure(metric, getMeasure(metric) + value);
179 }
180
181 private Double getMeasure(Metric metric) {
182 if (metric.isCalculatedMetric()) {
183 return metric.getCalculatedMetricFormula().calculate(this);
184 }
185 if (measures.get(metric) == null) {
186 return (double) 0;
187 }
188 return measures.get(metric);
189 }
190
191 public void setMeasure(Metric metric, double measure) {
192 if (metric.isCalculatedMetric()) {
193 throw new IllegalStateException("It's not allowed to set the value of a calculated metric : " + metric.name());
194 }
195 measures.put(metric, measure);
196 }
197
198 public void setMeasure(Metric metric, int measure) {
199 setMeasure(metric, (double) measure);
200 }
201
202 protected abstract void initializeMeasures();
203
204 protected abstract void updateMeasuresAfterConsolidation();
205
206 public void setStartAtLine(int startAtLine) {
207 this.startAtLine = startAtLine;
208 this.endAtLine = startAtLine;
209 }
210
211 public void setEndAtLine(int endAtLine) {
212 this.endAtLine = endAtLine;
213 }
214
215 public int getStartAtLine() {
216 return startAtLine;
217 }
218
219 public int getEndAtLine() {
220 return endAtLine;
221 }
222 }