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.scan2;
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.ProjectDefinition;
028 import org.sonar.api.batch.bootstrap.ProjectReactor;
029 import org.sonar.api.config.Settings;
030 import org.sonar.api.platform.ComponentContainer;
031 import org.sonar.api.resources.Languages;
032 import org.sonar.api.scan.filesystem.PathResolver;
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.duplication.BlockCache;
037 import org.sonar.batch.duplication.DuplicationCache;
038 import org.sonar.batch.index.Caches;
039 import org.sonar.batch.index.ComponentDataCache;
040 import org.sonar.batch.languages.DefaultLanguagesReferential;
041 import org.sonar.batch.profiling.PhasesSumUpTimeProfiler;
042 import org.sonar.batch.referential.DefaultProjectReferentialsLoader;
043 import org.sonar.batch.referential.ProjectReferentialsLoader;
044 import org.sonar.batch.referential.ProjectReferentialsProvider;
045 import org.sonar.batch.scan.ProjectReactorBuilder;
046 import org.sonar.batch.scan.ProjectSettings;
047 import org.sonar.batch.scan.filesystem.InputPathCache;
048 import org.sonar.batch.scan.maven.FakeMavenPluginExecutor;
049 import org.sonar.batch.scan.maven.MavenPluginExecutor;
050
051 public class ProjectScanContainer extends ComponentContainer {
052 public ProjectScanContainer(ComponentContainer taskContainer) {
053 super(taskContainer);
054 }
055
056 @Override
057 protected void doBeforeStart() {
058 projectBootstrap();
059 addBatchComponents();
060 fixMavenExecutor();
061 addBatchExtensions();
062 Settings settings = getComponentByType(Settings.class);
063 if (settings != null && settings.getBoolean(CoreProperties.PROFILING_LOG_PROPERTY)) {
064 add(PhasesSumUpTimeProfiler.class);
065 }
066 }
067
068 private void projectBootstrap() {
069 ProjectReactor reactor;
070 ProjectBootstrapper bootstrapper = getComponentByType(ProjectBootstrapper.class);
071 Settings settings = getComponentByType(Settings.class);
072 if (bootstrapper == null
073 // Starting from Maven plugin 2.3 then only DefaultProjectBootstrapper should be used.
074 || "true".equals(settings.getString("sonar.mojoUseRunner"))) {
075 // Use default SonarRunner project bootstrapper
076 ProjectReactorBuilder builder = getComponentByType(ProjectReactorBuilder.class);
077 reactor = builder.execute();
078 } else {
079 reactor = bootstrapper.bootstrap();
080 }
081 if (reactor == null) {
082 throw new IllegalStateException(bootstrapper + " has returned null as ProjectReactor");
083 }
084 add(reactor);
085 if (getComponentByType(ProjectReferentialsLoader.class) == null) {
086 add(DefaultProjectReferentialsLoader.class);
087 }
088 }
089
090 private void addBatchComponents() {
091 add(
092 new ProjectReferentialsProvider(),
093 ProjectSettings.class,
094 Caches.class,
095
096 // lang
097 Languages.class,
098 DefaultLanguagesReferential.class,
099
100 // Measures
101 AnalyzerMeasureCache.class,
102
103 // file system
104 InputPathCache.class,
105 PathResolver.class,
106
107 // issues
108 AnalyzerIssueCache.class,
109
110 ComponentDataCache.class,
111
112 // Duplications
113 BlockCache.class,
114 DuplicationCache.class,
115
116 ScanTaskObservers.class);
117 }
118
119 private void fixMavenExecutor() {
120 if (getComponentByType(MavenPluginExecutor.class) == null) {
121 add(FakeMavenPluginExecutor.class);
122 }
123 }
124
125 private void addBatchExtensions() {
126 getComponentByType(ExtensionInstaller.class).install(this, new BatchExtensionFilter());
127 }
128
129 @Override
130 protected void doAfterStart() {
131 ProjectReactor tree = getComponentByType(ProjectReactor.class);
132 scanRecursively(tree.getRoot());
133
134 getComponentByType(ScanTaskObservers.class).notifyEndOfScanTask();
135 }
136
137 private void scanRecursively(ProjectDefinition module) {
138 for (ProjectDefinition subModules : module.getSubProjects()) {
139 scanRecursively(subModules);
140 }
141 scan(module);
142 }
143
144 @VisibleForTesting
145 void scan(ProjectDefinition module) {
146 new ModuleScanContainer(this, module).execute();
147 }
148
149 static class BatchExtensionFilter implements ExtensionMatcher {
150 public boolean accept(Object extension) {
151 return ExtensionUtils.isType(extension, BatchComponent.class)
152 && ExtensionUtils.isInstantiationStrategy(extension, InstantiationStrategy.PER_BATCH);
153 }
154 }
155 }