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    }