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;
022
023import java.util.Collection;
024import java.util.HashSet;
025import java.util.List;
026import java.util.Set;
027
028import org.picocontainer.MutablePicoContainer;
029import org.picocontainer.containers.TransientPicoContainer;
030import org.sonar.graph.DirectedGraph;
031import org.sonar.graph.DirectedGraphAccessor;
032import org.sonar.squid.api.CodeScanner;
033import org.sonar.squid.api.CodeVisitor;
034import org.sonar.squid.api.Query;
035import org.sonar.squid.api.SourceCode;
036import org.sonar.squid.api.SourceCodeEdge;
037import org.sonar.squid.api.SourceCodeSearchEngine;
038import org.sonar.squid.api.SourceCodeTreeDecorator;
039import org.sonar.squid.api.SourceProject;
040import org.sonar.squid.api.SquidConfiguration;
041import org.sonar.squid.indexer.SquidIndex;
042import org.sonar.squid.measures.Metric;
043import org.sonar.squid.measures.MetricDef;
044
045public class Squid implements DirectedGraphAccessor<SourceCode, SourceCodeEdge>, SourceCodeSearchEngine {
046
047  private MutablePicoContainer pico;
048  private SourceProject project;
049  private SquidIndex squidIndex;
050  private DirectedGraph<SourceCode, SourceCodeEdge> graph = new DirectedGraph<SourceCode, SourceCodeEdge>();
051  private Set<CodeVisitor> externalCodeVisitors = new HashSet<CodeVisitor>();
052
053  public Squid(SquidConfiguration conf) {
054    pico = new TransientPicoContainer();
055    pico.addComponent(conf);
056    project = new SourceProject("Project");
057    squidIndex = new SquidIndex();
058    squidIndex.index(project);
059    pico.addComponent(squidIndex);
060    pico.addComponent(project);
061    pico.addComponent(graph);
062  }
063
064  public Squid() {
065    this(new SquidConfiguration());
066  }
067
068  public void registerVisitor(CodeVisitor visitor) {
069    externalCodeVisitors.add(visitor);
070  }
071
072  public void registerVisitor(Class<? extends CodeVisitor> visitor) {
073    addToPicocontainer(visitor);
074    externalCodeVisitors.add(pico.getComponent(visitor));
075  }
076
077  public <SCANNER extends CodeScanner> SCANNER register(Class<SCANNER> scannerClass) {
078    if(pico.getComponent(scannerClass) != null){
079      throw new IllegalStateException("The Squid SCANNER '" + scannerClass.getName() + "' can't be registered multiple times.");
080    }
081    addToPicocontainer(scannerClass);
082    SCANNER scanner = pico.getComponent(scannerClass);
083    for (Object clazz : scanner.getVisitorClasses()) {
084      addToPicocontainer((Class) clazz);
085      scanner.accept(pico.<CodeVisitor> getComponent((Class) clazz));
086    }
087    for (CodeVisitor externalVisitor : externalCodeVisitors) {
088      scanner.accept(externalVisitor);
089    }
090    return scanner;
091  }
092
093  /**
094   * @deprecated use {@link #decorateSourceCodeTreeWith(MetricDef...)} instead
095   */
096  @Deprecated
097  public SourceProject aggregate() {
098    return decorateSourceCodeTreeWith(Metric.values());
099  }
100
101  public SourceProject decorateSourceCodeTreeWith(MetricDef... metrics) {
102    SourceCodeTreeDecorator decorator = new SourceCodeTreeDecorator(project);
103    decorator.decorateWith(metrics);
104    return project;
105  }
106
107  public SourceProject getProject() {
108    return project;
109  }
110
111  private void addToPicocontainer(Class classToExpose) {
112    if (pico.getComponent(classToExpose) == null) {
113      pico.addComponent(classToExpose);
114    }
115  }
116
117  public SourceCode search(String key) {
118    return squidIndex.search(key);
119  }
120
121  public Collection<SourceCode> search(Query... query) {
122    return squidIndex.search(query);
123  }
124
125  public SourceCodeEdge getEdge(SourceCode from, SourceCode to) {
126    return graph.getEdge(from, to);
127  }
128
129  public Collection<SourceCodeEdge> getIncomingEdges(SourceCode to) {
130    return graph.getIncomingEdges(to);
131  }
132
133  public Collection<SourceCodeEdge> getOutgoingEdges(SourceCode from) {
134    return graph.getOutgoingEdges(from);
135  }
136
137  public Set<SourceCode> getVertices() {
138    return graph.getVertices();
139  }
140
141  public List<SourceCodeEdge> getEdges(Collection<SourceCode> vertices) {
142    return graph.getEdges(vertices);
143  }
144
145  public boolean hasEdge(SourceCode from, SourceCode to) {
146    return graph.hasEdge(from, to);
147  }
148
149  public void flush() {
150    graph = null;
151    pico = null;
152  }
153}