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 com.google.common.annotations.VisibleForTesting;
023 import org.sonar.api.BatchComponent;
024 import org.sonar.api.CoreProperties;
025 import org.sonar.api.batch.InstantiationStrategy;
026 import org.sonar.api.batch.bootstrap.ProjectBootstrapper;
027 import org.sonar.api.batch.bootstrap.ProjectReactor;
028 import org.sonar.api.config.Settings;
029 import org.sonar.api.platform.ComponentContainer;
030 import org.sonar.api.resources.Languages;
031 import org.sonar.api.resources.Project;
032 import org.sonar.api.scan.filesystem.PathResolver;
033 import org.sonar.api.utils.SonarException;
034 import org.sonar.batch.DefaultFileLinesContextFactory;
035 import org.sonar.batch.DefaultResourceCreationLock;
036 import org.sonar.batch.ProjectConfigurator;
037 import org.sonar.batch.ProjectTree;
038 import org.sonar.batch.bootstrap.ExtensionInstaller;
039 import org.sonar.batch.bootstrap.ExtensionMatcher;
040 import org.sonar.batch.bootstrap.ExtensionUtils;
041 import org.sonar.batch.bootstrap.MetricProvider;
042 import org.sonar.batch.components.PeriodsDefinition;
043 import org.sonar.batch.debt.DebtModelProvider;
044 import org.sonar.batch.debt.IssueChangelogDebtCalculator;
045 import org.sonar.batch.duplication.BlockCache;
046 import org.sonar.batch.duplication.DuplicationCache;
047 import org.sonar.batch.index.Caches;
048 import org.sonar.batch.index.ComponentDataCache;
049 import org.sonar.batch.index.ComponentDataPersister;
050 import org.sonar.batch.index.DefaultIndex;
051 import org.sonar.batch.index.DefaultPersistenceManager;
052 import org.sonar.batch.index.DefaultResourcePersister;
053 import org.sonar.batch.index.DependencyPersister;
054 import org.sonar.batch.index.DuplicationPersister;
055 import org.sonar.batch.index.EventPersister;
056 import org.sonar.batch.index.LinkPersister;
057 import org.sonar.batch.index.MeasurePersister;
058 import org.sonar.batch.index.ResourceCache;
059 import org.sonar.batch.index.ResourceKeyMigration;
060 import org.sonar.batch.index.SnapshotCache;
061 import org.sonar.batch.index.SourcePersister;
062 import org.sonar.batch.issue.DefaultProjectIssues;
063 import org.sonar.batch.issue.DeprecatedViolations;
064 import org.sonar.batch.issue.IssueCache;
065 import org.sonar.batch.issue.IssuePersister;
066 import org.sonar.batch.issue.ScanIssueStorage;
067 import org.sonar.batch.languages.DefaultLanguagesReferential;
068 import org.sonar.batch.phases.GraphPersister;
069 import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
070 import org.sonar.batch.referential.ProjectReferentialsProvider;
071 import org.sonar.batch.rule.RulesProvider;
072 import org.sonar.batch.scan.filesystem.InputPathCache;
073 import org.sonar.batch.scan.maven.FakeMavenPluginExecutor;
074 import org.sonar.batch.scan.maven.MavenPluginExecutor;
075 import org.sonar.batch.scan.measure.MeasureCache;
076 import org.sonar.batch.source.HighlightableBuilder;
077 import org.sonar.batch.source.SymbolizableBuilder;
078 import org.sonar.core.component.ScanGraph;
079 import org.sonar.core.issue.IssueNotifications;
080 import org.sonar.core.issue.IssueUpdater;
081 import org.sonar.core.issue.workflow.FunctionExecutor;
082 import org.sonar.core.issue.workflow.IssueWorkflow;
083 import org.sonar.core.notification.DefaultNotificationManager;
084 import org.sonar.core.technicaldebt.DefaultTechnicalDebtModel;
085 import org.sonar.core.test.TestPlanBuilder;
086 import org.sonar.core.test.TestPlanPerspectiveLoader;
087 import org.sonar.core.test.TestableBuilder;
088 import org.sonar.core.test.TestablePerspectiveLoader;
089 import org.sonar.core.user.DefaultUserFinder;
090
091 public class ProjectScanContainer extends ComponentContainer {
092 public ProjectScanContainer(ComponentContainer taskContainer) {
093 super(taskContainer);
094 }
095
096 @Override
097 protected void doBeforeStart() {
098 projectBootstrap();
099 addBatchComponents();
100 fixMavenExecutor();
101 addBatchExtensions();
102 Settings settings = getComponentByType(Settings.class);
103 if (settings != null && settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)) {
104 add(PhasesSumUpTimeProfiler.class);
105 }
106 }
107
108 private void projectBootstrap() {
109 // Views pass a custom ProjectReactor
110 ProjectReactor reactor = getComponentByType(ProjectReactor.class);
111 if (reactor == null) {
112 // OK, not present, so look for a deprecated custom ProjectBootstrapper for old versions of SQ Runner
113 ProjectBootstrapper bootstrapper = getComponentByType(ProjectBootstrapper.class);
114 Settings settings = getComponentByType(Settings.class);
115 if (bootstrapper == null
116 // Starting from Maven plugin 2.3 then only DefaultProjectBootstrapper should be used.
117 || "true".equals(settings.getString("sonar.mojoUseRunner"))) {
118 // Use default SonarRunner project bootstrapper
119 ProjectReactorBuilder builder = getComponentByType(ProjectReactorBuilder.class);
120 reactor = builder.execute();
121 } else {
122 reactor = bootstrapper.bootstrap();
123 }
124 if (reactor == null) {
125 throw new SonarException(bootstrapper + " has returned null as ProjectReactor");
126 }
127 add(reactor);
128 }
129 }
130
131 private void addBatchComponents() {
132 add(
133 new ProjectReferentialsProvider(),
134 DefaultResourceCreationLock.class,
135 DefaultPersistenceManager.class,
136 DependencyPersister.class,
137 EventPersister.class,
138 LinkPersister.class,
139 MeasurePersister.class,
140 DuplicationPersister.class,
141 DefaultResourcePersister.class,
142 SourcePersister.class,
143 DefaultNotificationManager.class,
144 MetricProvider.class,
145 ProjectConfigurator.class,
146 DefaultIndex.class,
147 ResourceKeyMigration.class,
148 DefaultFileLinesContextFactory.class,
149 ProjectLock.class,
150 LastSnapshots.class,
151 Caches.class,
152 SnapshotCache.class,
153 ResourceCache.class,
154 ComponentDataCache.class,
155 ComponentDataPersister.class,
156 DefaultUserFinder.class,
157
158 // file system
159 InputPathCache.class,
160 PathResolver.class,
161
162 // issues
163 IssueUpdater.class,
164 FunctionExecutor.class,
165 IssueWorkflow.class,
166 DeprecatedViolations.class,
167 IssueCache.class,
168 ScanIssueStorage.class,
169 IssuePersister.class,
170 IssueNotifications.class,
171 DefaultProjectIssues.class,
172 IssueChangelogDebtCalculator.class,
173
174 // tests
175 TestPlanPerspectiveLoader.class,
176 TestablePerspectiveLoader.class,
177 TestPlanBuilder.class,
178 TestableBuilder.class,
179 ScanGraph.create(),
180 GraphPersister.class,
181
182 // lang
183 Languages.class,
184 DefaultLanguagesReferential.class,
185 HighlightableBuilder.class,
186 SymbolizableBuilder.class,
187
188 // technical debt
189 DefaultTechnicalDebtModel.class,
190
191 // Differential periods
192 PeriodsDefinition.class,
193
194 // Measures
195 MeasureCache.class,
196
197 // Rules
198 new RulesProvider(),
199 new DebtModelProvider(),
200
201 // Duplications
202 BlockCache.class,
203 DuplicationCache.class,
204
205 ProjectSettings.class);
206 }
207
208 private void fixMavenExecutor() {
209 if (getComponentByType(MavenPluginExecutor.class) == null) {
210 add(FakeMavenPluginExecutor.class);
211 }
212 }
213
214 private void addBatchExtensions() {
215 getComponentByType(ExtensionInstaller.class).install(this, new BatchExtensionFilter());
216 }
217
218 @Override
219 protected void doAfterStart() {
220 ProjectTree tree = getComponentByType(ProjectTree.class);
221 scanRecursively(tree.getRootProject());
222 }
223
224 private void scanRecursively(Project module) {
225 for (Project subModules : module.getModules()) {
226 scanRecursively(subModules);
227 }
228 scan(module);
229 }
230
231 @VisibleForTesting
232 void scan(Project module) {
233 new ModuleScanContainer(this, module).execute();
234 }
235
236 static class BatchExtensionFilter implements ExtensionMatcher {
237 public boolean accept(Object extension) {
238 return ExtensionUtils.isType(extension, BatchComponent.class)
239 && ExtensionUtils.isInstantiationStrategy(extension, InstantiationStrategy.PER_BATCH);
240 }
241 }
242 }