001    /*
002     * SonarQube, open source software quality management tool.
003     * Copyright (C) 2008-2014 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * SonarQube 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     * SonarQube 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 License
017     * along with this program; if not, write to the Free Software Foundation,
018     * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019     */
020    package org.sonar.batch.scan;
021    
022    import org.slf4j.Logger;
023    import org.slf4j.LoggerFactory;
024    import org.sonar.api.BatchComponent;
025    import org.sonar.api.batch.InstantiationStrategy;
026    import org.sonar.api.batch.bootstrap.ProjectDefinition;
027    import org.sonar.api.batch.rule.CheckFactory;
028    import org.sonar.api.platform.ComponentContainer;
029    import org.sonar.api.resources.Project;
030    import org.sonar.api.scan.filesystem.FileExclusions;
031    import org.sonar.batch.*;
032    import org.sonar.batch.bootstrap.BatchExtensionDictionnary;
033    import org.sonar.batch.bootstrap.ExtensionInstaller;
034    import org.sonar.batch.bootstrap.ExtensionMatcher;
035    import org.sonar.batch.bootstrap.ExtensionUtils;
036    import org.sonar.batch.components.TimeMachineConfiguration;
037    import org.sonar.batch.debt.*;
038    import org.sonar.batch.events.EventBus;
039    import org.sonar.batch.index.DefaultIndex;
040    import org.sonar.batch.index.ResourcePersister;
041    import org.sonar.batch.issue.IssuableFactory;
042    import org.sonar.batch.issue.IssueFilters;
043    import org.sonar.batch.issue.ModuleIssues;
044    import org.sonar.batch.issue.ignore.EnforceIssuesFilter;
045    import org.sonar.batch.issue.ignore.IgnoreIssuesFilter;
046    import org.sonar.batch.issue.ignore.pattern.IssueExclusionPatternInitializer;
047    import org.sonar.batch.issue.ignore.pattern.IssueInclusionPatternInitializer;
048    import org.sonar.batch.issue.ignore.scanner.IssueExclusionsLoader;
049    import org.sonar.batch.issue.ignore.scanner.IssueExclusionsRegexpScanner;
050    import org.sonar.batch.language.LanguageDistributionDecorator;
051    import org.sonar.batch.phases.PhaseExecutor;
052    import org.sonar.batch.phases.PhasesTimeProfiler;
053    import org.sonar.batch.qualitygate.GenerateQualityGateEvents;
054    import org.sonar.batch.qualitygate.QualityGateProvider;
055    import org.sonar.batch.qualitygate.QualityGateVerifier;
056    import org.sonar.batch.rule.*;
057    import org.sonar.batch.scan.filesystem.*;
058    import org.sonar.batch.scan.report.JsonReport;
059    import org.sonar.batch.scan2.AnalyzerOptimizer;
060    import org.sonar.core.component.ScanPerspectives;
061    import org.sonar.core.measure.MeasurementFilters;
062    
063    public class ModuleScanContainer extends ComponentContainer {
064      private static final Logger LOG = LoggerFactory.getLogger(ModuleScanContainer.class);
065      private final Project module;
066    
067      public ModuleScanContainer(ProjectScanContainer parent, Project module) {
068        super(parent);
069        this.module = module;
070      }
071    
072      @Override
073      protected void doBeforeStart() {
074        LOG.info("-------------  Scan {}", module.getName());
075        addCoreComponents();
076        addExtensions();
077      }
078    
079      private void addCoreComponents() {
080        ProjectDefinition moduleDefinition = getComponentByType(ProjectTree.class).getProjectDefinition(module);
081        add(
082          moduleDefinition,
083          module.getConfiguration(),
084          module,
085          ModuleSettings.class);
086    
087        // hack to initialize commons-configuration before ExtensionProviders
088        getComponentByType(ModuleSettings.class);
089    
090        add(
091          EventBus.class,
092          PhaseExecutor.class,
093          PhasesTimeProfiler.class,
094          PhaseExecutor.getPhaseClasses(),
095          moduleDefinition.getContainerExtensions(),
096    
097          // file system
098          ModuleInputFileCache.class,
099          FileExclusions.class,
100          ExclusionFilters.class,
101          DeprecatedFileFilters.class,
102          InputFileBuilderFactory.class,
103          StatusDetectionFactory.class,
104          LanguageDetectionFactory.class,
105          PreviousFileHashLoader.class,
106          FileIndexer.class,
107          ComponentIndexer.class,
108          LanguageVerifier.class,
109          FileSystemLogger.class,
110          DefaultProjectClasspath.class,
111          DefaultModuleFileSystem.class,
112          ModuleFileSystemInitializer.class,
113          ProjectFileSystemAdapter.class,
114          QProfileVerifier.class,
115    
116          AnalyzerOptimizer.class,
117    
118          // the Snapshot component will be removed when asynchronous measures are improved (required for AsynchronousMeasureSensor)
119          getComponentByType(ResourcePersister.class).getSnapshot(module),
120    
121          TimeMachineConfiguration.class,
122          DefaultSensorContext.class,
123          SensorContextAdaptor.class,
124          BatchExtensionDictionnary.class,
125          DefaultTimeMachine.class,
126          ViolationFilters.class,
127          IssueFilters.class,
128          MeasurementFilters.class,
129          ResourceFilters.class,
130    
131          // quality gates
132          new QualityGateProvider(),
133          QualityGateVerifier.class,
134          GenerateQualityGateEvents.class,
135    
136          // rules
137          ModuleQProfiles.class,
138          new ActiveRulesProvider(),
139          new RulesProfileProvider(),
140          QProfileSensor.class,
141          QProfileDecorator.class,
142          QProfileEventsDecorator.class,
143          CheckFactory.class,
144    
145          // report
146          JsonReport.class,
147    
148          // issues
149          IssuableFactory.class,
150          ModuleIssues.class,
151    
152          // issue exclusions
153          IssueInclusionPatternInitializer.class,
154          IssueExclusionPatternInitializer.class,
155          IssueExclusionsRegexpScanner.class,
156          IssueExclusionsLoader.class,
157          EnforceIssuesFilter.class,
158          IgnoreIssuesFilter.class,
159    
160          // language
161          LanguageDistributionDecorator.class,
162    
163          // Debt
164          IssueChangelogDebtCalculator.class,
165          DebtDecorator.class,
166          NewDebtDecorator.class,
167          SqaleRatingDecorator.class,
168          SqaleRatingSettings.class,
169    
170          ScanPerspectives.class);
171      }
172    
173      private void addExtensions() {
174        ExtensionInstaller installer = getComponentByType(ExtensionInstaller.class);
175        installer.install(this, new ExtensionMatcher() {
176          public boolean accept(Object extension) {
177            if (ExtensionUtils.isType(extension, BatchComponent.class) && ExtensionUtils.isInstantiationStrategy(extension, InstantiationStrategy.PER_PROJECT)) {
178              // Special use-case: the extension point ProjectBuilder is used in a Maven environment to define some
179              // new sub-projects without pom.
180              // Example : C# plugin adds sub-projects at runtime, even if they are not defined in root pom.
181              return !ExtensionUtils.isMavenExtensionOnly(extension) || module.getPom() != null;
182            }
183            return false;
184          }
185        });
186      }
187    
188      @Override
189      protected void doAfterStart() {
190        DefaultIndex index = getComponentByType(DefaultIndex.class);
191        index.setCurrentProject(module,
192          getComponentByType(ModuleIssues.class));
193    
194        getComponentByType(PhaseExecutor.class).execute(module);
195      }
196    
197    }