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 }