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 021package org.sonar.squid.api; 022 023import org.sonar.squid.measures.Measurable; 024import org.sonar.squid.measures.Measures; 025import org.sonar.squid.measures.Metric; 026import org.sonar.squid.measures.MetricDef; 027 028import java.util.HashSet; 029import java.util.Set; 030import java.util.SortedSet; 031import java.util.TreeSet; 032 033public 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}