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.phases;
021    
022    import com.google.common.collect.Lists;
023    import org.slf4j.Logger;
024    import org.slf4j.LoggerFactory;
025    import org.sonar.api.batch.SensorContext;
026    import org.sonar.api.resources.Project;
027    import org.sonar.batch.events.BatchStepEvent;
028    import org.sonar.batch.events.EventBus;
029    import org.sonar.batch.index.DefaultIndex;
030    import org.sonar.batch.index.PersistenceManager;
031    import org.sonar.batch.index.ScanPersister;
032    import org.sonar.batch.issue.ignore.scanner.IssueExclusionsLoader;
033    import org.sonar.batch.rule.QProfileVerifier;
034    import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem;
035    import org.sonar.batch.scan.filesystem.FileSystemLogger;
036    import org.sonar.batch.scan.maven.MavenPluginsConfigurator;
037    import org.sonar.batch.scan.report.JsonReport;
038    
039    import java.util.Collection;
040    
041    public final class PhaseExecutor {
042    
043      public static final Logger LOGGER = LoggerFactory.getLogger(PhaseExecutor.class);
044    
045      private final EventBus eventBus;
046      private final Phases phases;
047      private final DecoratorsExecutor decoratorsExecutor;
048      private final MavenPluginsConfigurator mavenPluginsConfigurator;
049      private final PostJobsExecutor postJobsExecutor;
050      private final InitializersExecutor initializersExecutor;
051      private final SensorsExecutor sensorsExecutor;
052      private final UpdateStatusJob updateStatusJob;
053      private final PersistenceManager persistenceManager;
054      private final SensorContext sensorContext;
055      private final DefaultIndex index;
056      private final ProjectInitializer pi;
057      private final ScanPersister[] persisters;
058      private final FileSystemLogger fsLogger;
059      private final JsonReport jsonReport;
060      private final DefaultModuleFileSystem fs;
061      private final QProfileVerifier profileVerifier;
062      private final IssueExclusionsLoader issueExclusionsLoader;
063    
064      public PhaseExecutor(Phases phases, DecoratorsExecutor decoratorsExecutor,
065        MavenPluginsConfigurator mavenPluginsConfigurator, InitializersExecutor initializersExecutor,
066        PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
067        PersistenceManager persistenceManager, SensorContext sensorContext, DefaultIndex index,
068        EventBus eventBus, UpdateStatusJob updateStatusJob, ProjectInitializer pi,
069        ScanPersister[] persisters, FileSystemLogger fsLogger, JsonReport jsonReport, DefaultModuleFileSystem fs, QProfileVerifier profileVerifier,
070        IssueExclusionsLoader issueExclusionsLoader) {
071        this.phases = phases;
072        this.decoratorsExecutor = decoratorsExecutor;
073        this.mavenPluginsConfigurator = mavenPluginsConfigurator;
074        this.postJobsExecutor = postJobsExecutor;
075        this.initializersExecutor = initializersExecutor;
076        this.sensorsExecutor = sensorsExecutor;
077        this.persistenceManager = persistenceManager;
078        this.sensorContext = sensorContext;
079        this.index = index;
080        this.eventBus = eventBus;
081        this.updateStatusJob = updateStatusJob;
082        this.pi = pi;
083        this.persisters = persisters;
084        this.fsLogger = fsLogger;
085        this.jsonReport = jsonReport;
086        this.fs = fs;
087        this.profileVerifier = profileVerifier;
088        this.issueExclusionsLoader = issueExclusionsLoader;
089      }
090    
091      public static Collection<Class> getPhaseClasses() {
092        return Lists.<Class>newArrayList(DecoratorsExecutor.class, MavenPluginsConfigurator.class,
093          PostJobsExecutor.class, SensorsExecutor.class,
094          InitializersExecutor.class, ProjectInitializer.class, UpdateStatusJob.class);
095      }
096    
097      /**
098       * Executed on each module
099       */
100      public void execute(Project module) {
101        pi.execute(module);
102    
103        eventBus.fireEvent(new ProjectAnalysisEvent(module, true));
104    
105        executeMavenPhase(module);
106    
107        executeInitializersPhase();
108    
109        if (phases.isEnabled(Phases.Phase.SENSOR)) {
110          // Index and lock the filesystem
111          fs.index();
112    
113          // Log detected languages and their profiles after FS is indexed and languages detected
114          profileVerifier.execute();
115    
116          // Initialize issue exclusions
117          issueExclusionsLoader.execute();
118    
119          sensorsExecutor.execute(sensorContext);
120        }
121    
122        if (phases.isEnabled(Phases.Phase.DECORATOR)) {
123          decoratorsExecutor.execute();
124        }
125    
126        if (module.isRoot()) {
127          jsonReport.execute();
128    
129          executePersisters();
130          updateStatusJob();
131          if (phases.isEnabled(Phases.Phase.POSTJOB)) {
132            postJobsExecutor.execute(sensorContext);
133          }
134        }
135        cleanMemory();
136        eventBus.fireEvent(new ProjectAnalysisEvent(module, false));
137      }
138    
139      private void executePersisters() {
140        LOGGER.info("Store results in database");
141        eventBus.fireEvent(new PersistersPhaseEvent(Lists.newArrayList(persisters), true));
142        for (ScanPersister persister : persisters) {
143          LOGGER.debug("Execute {}", persister.getClass().getName());
144          eventBus.fireEvent(new PersisterExecutionEvent(persister, true));
145          persister.persist();
146          eventBus.fireEvent(new PersisterExecutionEvent(persister, false));
147        }
148    
149        eventBus.fireEvent(new PersistersPhaseEvent(Lists.newArrayList(persisters), false));
150      }
151    
152      private void updateStatusJob() {
153        if (updateStatusJob != null) {
154          String stepName = "Update status job";
155          eventBus.fireEvent(new BatchStepEvent(stepName, true));
156          this.updateStatusJob.execute();
157          eventBus.fireEvent(new BatchStepEvent(stepName, false));
158        }
159      }
160    
161      private void executeInitializersPhase() {
162        if (phases.isEnabled(Phases.Phase.INIT)) {
163          initializersExecutor.execute();
164          fsLogger.log();
165        }
166      }
167    
168      private void executeMavenPhase(Project module) {
169        if (phases.isEnabled(Phases.Phase.MAVEN)) {
170          eventBus.fireEvent(new MavenPhaseEvent(true));
171          mavenPluginsConfigurator.execute(module);
172          eventBus.fireEvent(new MavenPhaseEvent(false));
173        }
174      }
175    
176      private void cleanMemory() {
177        String cleanMemory = "Clean memory";
178        eventBus.fireEvent(new BatchStepEvent(cleanMemory, true));
179        persistenceManager.clear();
180        index.clear();
181        eventBus.fireEvent(new BatchStepEvent(cleanMemory, false));
182      }
183    }