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 }