001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2011 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    }