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
021 package org.sonar.squid;
022
023 import java.util.Collection;
024 import java.util.HashSet;
025 import java.util.List;
026 import java.util.Set;
027
028 import org.picocontainer.MutablePicoContainer;
029 import org.picocontainer.containers.TransientPicoContainer;
030 import org.sonar.graph.DirectedGraph;
031 import org.sonar.graph.DirectedGraphAccessor;
032 import org.sonar.squid.api.CodeScanner;
033 import org.sonar.squid.api.CodeVisitor;
034 import org.sonar.squid.api.Query;
035 import org.sonar.squid.api.SourceCode;
036 import org.sonar.squid.api.SourceCodeEdge;
037 import org.sonar.squid.api.SourceCodeSearchEngine;
038 import org.sonar.squid.api.SourceCodeTreeDecorator;
039 import org.sonar.squid.api.SourceProject;
040 import org.sonar.squid.api.SquidConfiguration;
041 import org.sonar.squid.indexer.SquidIndex;
042 import org.sonar.squid.measures.Metric;
043 import org.sonar.squid.measures.MetricDef;
044
045 public 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 }