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 } 052 053 public String getKey() { 054 return key; 055 } 056 057 public int compareTo(SourceCode resource) { 058 return key.compareTo(resource.getKey()); 059 } 060 061 public String getName() { 062 return name; 063 } 064 065 @Override 066 public boolean equals(Object obj) { 067 if (!(obj instanceof SourceCode)) { 068 return false; 069 } 070 return getKey().equals(((SourceCode) obj).getKey()); 071 } 072 073 @Override 074 public int hashCode() { 075 return key.hashCode(); 076 } 077 078 @Override 079 public String toString() { 080 StringBuilder sb = new StringBuilder(512); 081 sb.append(this.getClass().getSimpleName()).append(" : ").append(getKey()).append(IOUtils.LINE_SEPARATOR); 082 for (SourceCode child : getChildren()) { 083 String childTree = child.toString(); 084 StringTokenizer tokenizer = new StringTokenizer(childTree, IOUtils.LINE_SEPARATOR); 085 while (tokenizer.hasMoreTokens()) { 086 sb.append("-").append(tokenizer.nextToken()).append(IOUtils.LINE_SEPARATOR); 087 } 088 } 089 return sb.toString(); 090 } 091 092 public final void computeMeasures() { 093 for (SourceCode child : getChildren()) { 094 child.computeMeasures(); 095 } 096 for (Metric metric : Metric.values()) { 097 if (!metric.aggregateIfThereIsAlreadyAValue() && getDouble(metric) != 0) { 098 continue; 099 } 100 for (SourceCode child : getChildren()) { 101 if (!metric.isCalculatedMetric() && metric.isThereAggregationFormula()) { 102 add(metric, child); 103 } 104 } 105 106 } 107 } 108 109 /** 110 * {@inheritDoc} 111 */ 112 public void createEdgeWith(Node to, EdgeUsage link) { 113 createEdgeWith(to, link, null); 114 } 115 116 /** 117 * {@inheritDoc} 118 */ 119 public void createEdgeWith(Node to, EdgeUsage link, Edge rootEdge) { 120 if (equals(to)) { 121 throw new IllegalStateException("You can't create an edge from one node to itself. SquidUnit : " + getKey()); 122 } 123 if (getEdgeTo(to) != null) { 124 throw new IllegalStateException("Those two nodes are already linked. From : " + getKey() + ", To : " + to.getKey()); 125 } 126 Edge edge = new Edge(this, to, link, null); 127 edge.addRootEdge(rootEdge); 128 129 dependsUpon.put(to, edge); 130 ((SourceCode) to).dependedUpon.put(this, edge); 131 } 132 133 /** 134 * {@inheritDoc} 135 */ 136 public Edge getEdgeTo(Node to) { 137 return dependsUpon.get(to); 138 } 139 140 /** 141 * {@inheritDoc} 142 */ 143 public Edge getEdgeFrom(Node from) { 144 return dependedUpon.get(from); 145 } 146 147 /** 148 * {@inheritDoc} 149 */ 150 public EdgeUsage getUsageOf(Node to) { 151 Edge relation = dependsUpon.get(to); 152 if (relation == null) { 153 return EdgeUsage.NO_LINK; 154 } 155 return relation.getUsage(); 156 } 157 158 /** 159 * {@inheritDoc} 160 */ 161 public EdgeUsage getUsageBy(Node from) { 162 Edge edge = dependedUpon.get(from); 163 if (edge == null) { 164 return EdgeUsage.NO_LINK; 165 } 166 return edge.getUsage(); 167 } 168 169 /** 170 * {@inheritDoc} 171 */ 172 public Set<Node> dependedUpon() { 173 return dependedUpon.keySet(); 174 } 175 176 /** 177 * {@inheritDoc} 178 */ 179 public Set<Node> dependsUpon() { 180 return dependsUpon.keySet(); 181 } 182 183 public boolean isType(Class<? extends SourceCode> resourceType) { 184 return this.getClass() == resourceType; 185 } 186 187 /** 188 * {@inheritDoc} 189 */ 190 public int getInt(Metric metric) { 191 return getMeasure(metric).intValue(); 192 } 193 194 /** 195 * {@inheritDoc} 196 */ 197 public double getDouble(Metric metric) { 198 return getMeasure(metric).doubleValue(); 199 } 200 201 public void add(Metric metric, SourceCode child) { 202 add(metric, child.getMeasure(metric)); 203 } 204 205 public void add(Metric metric, double value) { 206 setMeasure(metric, getMeasure(metric) + value); 207 } 208 209 private Double getMeasure(Metric metric) { 210 if (metric.isCalculatedMetric()) { 211 return metric.getCalculatedMetricFormula().calculate(this); 212 } 213 if (measures.get(metric) == null) { 214 return (double) 0; 215 } 216 return measures.get(metric); 217 } 218 219 /** 220 * {@inheritDoc} 221 */ 222 public void setMeasure(Metric metric, double measure) { 223 if (metric.isCalculatedMetric()) { 224 throw new IllegalStateException("It's not allowed to set the value of a calculated metric : " + metric.name()); 225 } 226 measures.put(metric, measure); 227 } 228 229 /** 230 * {@inheritDoc} 231 */ 232 public void setMeasure(Metric metric, int measure) { 233 setMeasure(metric, (double) measure); 234 } 235 236 public void setStartAtLine(int startAtLine) { 237 this.startAtLine = startAtLine; 238 this.endAtLine = startAtLine; 239 } 240 241 public void setEndAtLine(int endAtLine) { 242 this.endAtLine = endAtLine; 243 } 244 245 public int getStartAtLine() { 246 return startAtLine; 247 } 248 249 public int getEndAtLine() { 250 return endAtLine; 251 } 252 }