--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.events;
+
+/**
+ * Generic event for some steps of project scan.
+ * @since 3.7
+ *
+ */
+public class BatchStepEvent extends BatchEvent<BatchStepHandler>
+ implements BatchStepHandler.BatchStepEvent {
+
+ private final boolean start;
+
+ private String stepName;
+
+ public BatchStepEvent(String stepName, boolean start) {
+ this.start = start;
+ this.stepName = stepName;
+ }
+
+ @Override
+ public String stepName() {
+ return stepName;
+ }
+
+ public final boolean isStart() {
+ return start;
+ }
+
+ public final boolean isEnd() {
+ return !start;
+ }
+
+ @Override
+ protected void dispatch(BatchStepHandler handler) {
+ handler.onBatchStep(this);
+ }
+
+ @Override
+ protected Class getType() {
+ return BatchStepHandler.class;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.events;
+
+import org.sonar.api.batch.events.EventHandler;
+
+/**
+ * @since 3.7
+ */
+public interface BatchStepHandler extends EventHandler {
+
+ /**
+ * This interface is not intended to be implemented by clients.
+ */
+ interface BatchStepEvent {
+
+ String stepName();
+
+ boolean isStart();
+
+ boolean isEnd();
+
+ }
+
+ /**
+ * Called before and after execution of each final step of project analysis
+ */
+ void onBatchStep(BatchStepEvent event);
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.phases;
+
+import org.sonar.api.batch.Initializer;
+import org.sonar.api.batch.events.InitializerExecutionHandler;
+
+class InitializerExecutionEvent extends AbstractPhaseEvent<InitializerExecutionHandler>
+ implements org.sonar.api.batch.events.InitializerExecutionHandler.InitializerExecutionEvent {
+
+ private final Initializer initializer;
+
+ InitializerExecutionEvent(Initializer initializer, boolean start) {
+ super(start);
+ this.initializer = initializer;
+ }
+
+ public Initializer getInitializer() {
+ return initializer;
+ }
+
+ @Override
+ public void dispatch(InitializerExecutionHandler handler) {
+ handler.onInitializerExecution(this);
+ }
+
+ @Override
+ public Class getType() {
+ return InitializerExecutionHandler.class;
+ }
+
+}
*/
package org.sonar.batch.phases;
+import com.google.common.collect.Lists;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.maven.MavenPluginHandler;
import org.sonar.api.resources.Project;
import org.sonar.api.utils.TimeProfiler;
-import org.sonar.batch.scan.maven.MavenPluginExecutor;
+import org.sonar.batch.events.EventBus;
import org.sonar.batch.scan.filesystem.DefaultModuleFileSystem;
+import org.sonar.batch.scan.maven.MavenPluginExecutor;
import java.util.Collection;
private DefaultModuleFileSystem fs;
private Project project;
private BatchExtensionDictionnary selector;
+ private EventBus eventBus;
- public InitializersExecutor(BatchExtensionDictionnary selector, Project project, DefaultModuleFileSystem fs, MavenPluginExecutor mavenExecutor) {
+ public InitializersExecutor(BatchExtensionDictionnary selector, Project project, DefaultModuleFileSystem fs, MavenPluginExecutor mavenExecutor, EventBus eventBus) {
this.selector = selector;
this.mavenExecutor = mavenExecutor;
this.project = project;
this.fs = fs;
+ this.eventBus = eventBus;
}
public void execute() {
Collection<Initializer> initializers = selector.select(Initializer.class, project, true);
+ eventBus.fireEvent(new InitializersPhaseEvent(Lists.newArrayList(initializers), true));
if (LOG.isDebugEnabled()) {
LOG.debug("Initializers : {}", StringUtils.join(initializers, " -> "));
}
for (Initializer initializer : initializers) {
+ eventBus.fireEvent(new InitializerExecutionEvent(initializer, true));
executeMavenPlugin(initializer);
TimeProfiler profiler = new TimeProfiler(LOG).start("Initializer " + initializer);
initializer.execute(project);
profiler.stop();
+ eventBus.fireEvent(new InitializerExecutionEvent(initializer, false));
}
+
+ eventBus.fireEvent(new InitializersPhaseEvent(Lists.newArrayList(initializers), false));
}
private void executeMavenPlugin(Initializer sensor) {
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.phases;
+
+import org.sonar.api.batch.Initializer;
+import org.sonar.api.batch.events.InitializersPhaseHandler;
+
+import java.util.List;
+
+class InitializersPhaseEvent extends AbstractPhaseEvent<InitializersPhaseHandler>
+ implements org.sonar.api.batch.events.InitializersPhaseHandler.InitializersPhaseEvent {
+
+ private final List<Initializer> initializers;
+
+ InitializersPhaseEvent(List<Initializer> initializers, boolean start) {
+ super(start);
+ this.initializers = initializers;
+ }
+
+ public List<Initializer> getInitializers() {
+ return initializers;
+ }
+
+ @Override
+ protected void dispatch(InitializersPhaseHandler handler) {
+ handler.onInitializersPhase(this);
+ }
+
+ @Override
+ protected Class getType() {
+ return InitializersPhaseHandler.class;
+ }
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.batch.phases;
+
+import org.sonar.api.batch.events.MavenPhaseHandler;
+
+class MavenPhaseEvent extends AbstractPhaseEvent<MavenPhaseHandler>
+ implements org.sonar.api.batch.events.MavenPhaseHandler.MavenPhaseEvent {
+
+ MavenPhaseEvent(boolean start) {
+ super(start);
+ }
+
+ @Override
+ protected void dispatch(MavenPhaseHandler handler) {
+ handler.onMavenPhase(this);
+ }
+
+ @Override
+ protected Class getType() {
+ return MavenPhaseHandler.class;
+ }
+
+}
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.resources.Project;
+import org.sonar.batch.events.BatchStepEvent;
import org.sonar.batch.events.EventBus;
import org.sonar.batch.index.DefaultIndex;
import org.sonar.batch.index.PersistenceManager;
public static final Logger LOGGER = LoggerFactory.getLogger(PhaseExecutor.class);
public static Collection<Class> getPhaseClasses() {
- return Lists.<Class>newArrayList(DecoratorsExecutor.class, MavenPhaseExecutor.class, MavenPluginsConfigurator.class,
- PostJobsExecutor.class, SensorsExecutor.class,
- InitializersExecutor.class, ProjectInitializer.class, UpdateStatusJob.class);
+ return Lists.<Class> newArrayList(DecoratorsExecutor.class, MavenPhaseExecutor.class, MavenPluginsConfigurator.class,
+ PostJobsExecutor.class, SensorsExecutor.class,
+ InitializersExecutor.class, ProjectInitializer.class, UpdateStatusJob.class);
}
private EventBus eventBus;
private final JsonReport jsonReport;
public PhaseExecutor(Phases phases, DecoratorsExecutor decoratorsExecutor, MavenPhaseExecutor mavenPhaseExecutor,
- MavenPluginsConfigurator mavenPluginsConfigurator, InitializersExecutor initializersExecutor,
- PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
- PersistenceManager persistenceManager, SensorContext sensorContext, DefaultIndex index,
- EventBus eventBus, UpdateStatusJob updateStatusJob, ProjectInitializer pi,
- ScanPersister[] persisters, FileSystemLogger fsLogger, JsonReport jsonReport) {
+ MavenPluginsConfigurator mavenPluginsConfigurator, InitializersExecutor initializersExecutor,
+ PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
+ PersistenceManager persistenceManager, SensorContext sensorContext, DefaultIndex index,
+ EventBus eventBus, UpdateStatusJob updateStatusJob, ProjectInitializer pi,
+ ScanPersister[] persisters, FileSystemLogger fsLogger, JsonReport jsonReport) {
this.phases = phases;
this.decoratorsExecutor = decoratorsExecutor;
this.mavenPhaseExecutor = mavenPhaseExecutor;
}
public PhaseExecutor(Phases phases, DecoratorsExecutor decoratorsExecutor, MavenPhaseExecutor mavenPhaseExecutor,
- MavenPluginsConfigurator mavenPluginsConfigurator, InitializersExecutor initializersExecutor,
- PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
- PersistenceManager persistenceManager, SensorContext sensorContext, DefaultIndex index,
- EventBus eventBus, ProjectInitializer pi, ScanPersister[] persisters, FileSystemLogger fsLogger, JsonReport jsonReport) {
+ MavenPluginsConfigurator mavenPluginsConfigurator, InitializersExecutor initializersExecutor,
+ PostJobsExecutor postJobsExecutor, SensorsExecutor sensorsExecutor,
+ PersistenceManager persistenceManager, SensorContext sensorContext, DefaultIndex index,
+ EventBus eventBus, ProjectInitializer pi, ScanPersister[] persisters, FileSystemLogger fsLogger, JsonReport jsonReport) {
this(phases, decoratorsExecutor, mavenPhaseExecutor, mavenPluginsConfigurator, initializersExecutor, postJobsExecutor,
- sensorsExecutor, persistenceManager, sensorContext, index, eventBus, null, pi, persisters, fsLogger, jsonReport);
+ sensorsExecutor, persistenceManager, sensorContext, index, eventBus, null, pi, persisters, fsLogger, jsonReport);
}
/**
*/
public void execute(Project module) {
pi.execute(module);
+
eventBus.fireEvent(new ProjectAnalysisEvent(module, true));
- if (phases.isEnabled(Phases.Phase.MAVEN)) {
- mavenPluginsConfigurator.execute(module);
- mavenPhaseExecutor.execute(module);
- }
- if (phases.isEnabled(Phases.Phase.INIT)) {
- initializersExecutor.execute();
- fsLogger.log();
- }
+
+ executeMavenPhase(module);
+
+ executeInitializersPhase();
persistenceManager.setDelayedMode(true);
+
if (phases.isEnabled(Phases.Phase.SENSOR)) {
sensorsExecutor.execute(sensorContext);
}
+
if (phases.isEnabled(Phases.Phase.DECORATOR)) {
decoratorsExecutor.execute();
}
+
+ eventBus.fireEvent(new BatchStepEvent("Save measures", true));
persistenceManager.dump();
+ eventBus.fireEvent(new BatchStepEvent("Save measures", false));
persistenceManager.setDelayedMode(false);
if (module.isRoot()) {
jsonReport.execute();
- LOGGER.info("Store results in database");
- for (ScanPersister persister : persisters) {
- LOGGER.debug("Execute {}", persister.getClass().getName());
- persister.persist();
- }
- if (updateStatusJob != null) {
- updateStatusJob.execute();
- }
+ executePersisters();
+ updateStatusJob();
if (phases.isEnabled(Phases.Phase.POSTJOB)) {
postJobsExecutor.execute(sensorContext);
}
eventBus.fireEvent(new ProjectAnalysisEvent(module, false));
}
+ private void executePersisters() {
+ LOGGER.info("Store results in database");
+ eventBus.fireEvent(new BatchStepEvent("Persisters", true));
+ for (ScanPersister persister : persisters) {
+ LOGGER.debug("Execute {}", persister.getClass().getName());
+ persister.persist();
+ }
+ eventBus.fireEvent(new BatchStepEvent("Persisters", false));
+ }
+
+ private void updateStatusJob() {
+ if (updateStatusJob != null) {
+ eventBus.fireEvent(new BatchStepEvent("Update status job", true));
+ updateStatusJob.execute();
+ eventBus.fireEvent(new BatchStepEvent("Update status job", false));
+ }
+ }
+
+ private void executeInitializersPhase() {
+ if (phases.isEnabled(Phases.Phase.INIT)) {
+ initializersExecutor.execute();
+ fsLogger.log();
+ }
+ }
+
+ private void executeMavenPhase(Project module) {
+ if (phases.isEnabled(Phases.Phase.MAVEN)) {
+ eventBus.fireEvent(new MavenPhaseEvent(true));
+ mavenPluginsConfigurator.execute(module);
+ mavenPhaseExecutor.execute(module);
+ eventBus.fireEvent(new MavenPhaseEvent(false));
+ }
+ }
+
private void cleanMemory() {
+ eventBus.fireEvent(new BatchStepEvent("Clean memory", true));
persistenceManager.clear();
index.clear();
+ eventBus.fireEvent(new BatchStepEvent("Clean memory", false));
}
}
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
+import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
public abstract class AbstractTimeProfiling {
this.setTotalTime(this.totalTime() + other.totalTime());
}
- static <G extends AbstractTimeProfiling> List<G> sortByDescendingTotalTime(Collection<G> unsorted) {
- List<G> result = new ArrayList<G>(unsorted.size());
- result.addAll(unsorted);
- Collections.sort(result, new Comparator<G>() {
+ static <G extends AbstractTimeProfiling> Map<Object, G> sortByDescendingTotalTime(Map<?, G> unsorted) {
+ List<Map.Entry<?, G>> entries =
+ new ArrayList<Map.Entry<?, G>>(unsorted.entrySet());
+ Collections.sort(entries, new Comparator<Map.Entry<?, G>>() {
@Override
- public int compare(G o1, G o2) {
- return Long.valueOf(o2.totalTime()).compareTo(o1.totalTime());
+ public int compare(Map.Entry<?, G> o1, Map.Entry<?, G> o2) {
+ return Long.valueOf(o2.getValue().totalTime()).compareTo(o1.getValue().totalTime());
}
});
- return result;
+ Map<Object, G> sortedMap = new LinkedHashMap<Object, G>();
+ for (Map.Entry<?, G> entry : entries) {
+ sortedMap.put(entry.getKey(), entry.getValue());
+ }
+ return sortedMap;
}
static <G extends AbstractTimeProfiling> List<G> truncate(Collection<G> sortedList) {
PhasesSumUpTimeProfiler.println(msg);
}
+ protected void println(String text, Double percent, AbstractTimeProfiling phaseProfiling) {
+ PhasesSumUpTimeProfiler.println(text, percent, phaseProfiling);
+ }
+
+ protected void println(String text, AbstractTimeProfiling phaseProfiling) {
+ println(text, null, phaseProfiling);
+ }
+
}
*/
package org.sonar.batch.profiling;
+import com.google.common.collect.Maps;
import org.sonar.api.resources.Project;
-import org.sonar.api.utils.TimeUtils;
import org.sonar.batch.phases.Phases;
import org.sonar.batch.phases.Phases.Phase;
import javax.annotation.CheckForNull;
import java.util.HashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
public class ModuleProfiling extends AbstractTimeProfiling {
private Map<Phases.Phase, PhaseProfiling> profilingPerPhase = new HashMap<Phases.Phase, PhaseProfiling>();
+ private Map<String, ItemProfiling> profilingPerBatchStep = new LinkedHashMap<String, ItemProfiling>();
private Clock clock;
private Project module;
return profilingPerPhase.get(phase);
}
+ public ItemProfiling getProfilingPerBatchStep(String stepName) {
+ return profilingPerBatchStep.get(stepName);
+ }
+
public void addPhaseProfiling(Phase phase) {
profilingPerPhase.put(phase, PhaseProfiling.create(clock, phase));
}
+ public void addBatchStepProfiling(String stepName) {
+ profilingPerBatchStep.put(stepName, new ItemProfiling(clock, stepName));
+ }
+
public void dump() {
double percent = this.totalTime() / 100.0;
- for (PhaseProfiling phaseProfiling : sortByDescendingTotalTime(profilingPerPhase.values())) {
- StringBuilder sb = new StringBuilder();
- sb.append(" * ").append(phaseProfiling.phase()).append(" execution time: ").append(phaseProfiling.totalTimeAsString())
- .append(" (").append((int) (phaseProfiling.totalTime() / percent)).append("%)");
- println(sb.toString());
+ Map<Object, AbstractTimeProfiling> categories = Maps.newLinkedHashMap();
+ categories.putAll(profilingPerPhase);
+ categories.putAll(profilingPerBatchStep);
+
+ for (Map.Entry<Object, AbstractTimeProfiling> batchStep : sortByDescendingTotalTime(categories).entrySet()) {
+ println(" * " + batchStep.getKey() + " execution time: ", percent, batchStep.getValue());
}
+ // Breakdown per phase
for (Phase phase : Phases.Phase.values()) {
- if (profilingPerPhase.containsKey(phase)) {
- StringBuilder sb = new StringBuilder();
- sb.append("\n * ").append(phase).append(" execution time breakdown: ")
- .append(TimeUtils.formatDuration(getProfilingPerPhase(phase).totalTime()));
- println(sb.toString());
+ if (profilingPerPhase.containsKey(phase) && getProfilingPerPhase(phase).hasItems()) {
+ println("");
+ println(" * " + phase + " execution time breakdown: ", getProfilingPerPhase(phase));
getProfilingPerPhase(phase).dump();
}
}
}
this.getProfilingPerPhase(entry.getKey()).merge(entry.getValue());
}
+ for (Map.Entry<String, ItemProfiling> entry : other.profilingPerBatchStep.entrySet()) {
+ if (!this.profilingPerBatchStep.containsKey(entry.getKey())) {
+ profilingPerBatchStep.put(entry.getKey(), new ItemProfiling(clock, entry.getKey()));
+ }
+ this.getProfilingPerBatchStep(entry.getKey()).add(entry.getValue());
+ }
}
}
return phase;
}
+ public boolean hasItems() {
+ return !profilingPerItem.isEmpty();
+ }
+
public ItemProfiling getProfilingPerItem(Object item) {
String stringOrSimpleName = toStringOrSimpleName(item);
return profilingPerItem.get(stringOrSimpleName);
public void dump() {
double percent = this.totalTime() / 100.0;
- for (ItemProfiling itemProfiling : truncate(sortByDescendingTotalTime(profilingPerItem.values()))) {
- StringBuilder sb = new StringBuilder();
- sb.append(" o ").append(itemProfiling.itemName()).append(": ").append(itemProfiling.totalTimeAsString())
- .append(" (").append((int) (itemProfiling.totalTime() / percent)).append("%)");
- println(sb.toString());
+ for (ItemProfiling itemProfiling : truncate(sortByDescendingTotalTime(profilingPerItem).values())) {
+ println(" o " + itemProfiling.itemName() + ": ", percent, itemProfiling);
}
}
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
+import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.Decorator;
import org.sonar.api.batch.events.DecoratorExecutionHandler;
import org.sonar.api.batch.events.DecoratorsPhaseHandler;
+import org.sonar.api.batch.events.InitializerExecutionHandler;
+import org.sonar.api.batch.events.InitializersPhaseHandler;
+import org.sonar.api.batch.events.MavenPhaseHandler;
import org.sonar.api.batch.events.PostJobExecutionHandler;
import org.sonar.api.batch.events.PostJobsPhaseHandler;
import org.sonar.api.batch.events.ProjectAnalysisHandler;
import org.sonar.api.batch.events.SensorsPhaseHandler;
import org.sonar.api.resources.Project;
import org.sonar.api.utils.TimeUtils;
+import org.sonar.batch.events.BatchStepHandler;
import org.sonar.batch.phases.Phases;
-import java.util.ArrayList;
+import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import static org.sonar.batch.profiling.AbstractTimeProfiling.truncate;
public class PhasesSumUpTimeProfiler implements ProjectAnalysisHandler, SensorExecutionHandler, DecoratorExecutionHandler, PostJobExecutionHandler, DecoratorsPhaseHandler,
- SensorsPhaseHandler, PostJobsPhaseHandler {
+ SensorsPhaseHandler, PostJobsPhaseHandler, MavenPhaseHandler, InitializersPhaseHandler, InitializerExecutionHandler, BatchStepHandler {
static Logger LOG = LoggerFactory.getLogger(PhasesSumUpTimeProfiler.class);
+ private static final int TEXT_RIGHT_PAD = 60;
+ private static final int TIME_LEFT_PAD = 10;
@VisibleForTesting
ModuleProfiling currentModuleProfiling;
@VisibleForTesting
ModuleProfiling totalProfiling;
- private List<ModuleProfiling> modulesProfilings = new ArrayList<ModuleProfiling>();
+ private Map<Project, ModuleProfiling> modulesProfilings = new HashMap<Project, ModuleProfiling>();
private DecoratorsProfiler decoratorsProfiler;
private Clock clock;
LOG.info(msg);
}
+ static void println(String text, Double percent, AbstractTimeProfiling phaseProfiling) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(StringUtils.rightPad(text, TEXT_RIGHT_PAD)).append(StringUtils.leftPad(phaseProfiling.totalTimeAsString(), TIME_LEFT_PAD));
+ if (percent != null) {
+ sb.append(" (").append((int) (phaseProfiling.totalTime() / percent)).append("%)");
+ }
+ println(sb.toString());
+ }
+
@VisibleForTesting
PhasesSumUpTimeProfiler(Clock clock) {
this.clock = clock;
}
else {
currentModuleProfiling.stop();
- modulesProfilings.add(currentModuleProfiling);
+ modulesProfilings.put(module, currentModuleProfiling);
long moduleTotalTime = currentModuleProfiling.totalTime();
- println("\n -------- Profiling of module " + module.getName() + ": " + TimeUtils.formatDuration(moduleTotalTime) + " --------\n");
+ println("");
+ println(" -------- Profiling of module " + module.getName() + ": " + TimeUtils.formatDuration(moduleTotalTime) + " --------");
+ println("");
currentModuleProfiling.dump();
- println("\n -------- End of profiling of module " + module.getName() + " --------\n");
+ println("");
+ println(" -------- End of profiling of module " + module.getName() + " --------");
+ println("");
totalProfiling.merge(currentModuleProfiling);
if (module.isRoot() && !module.getModules().isEmpty()) {
dumpTotalExecutionSummary();
private void dumpTotalExecutionSummary() {
totalProfiling.stop();
long totalTime = totalProfiling.totalTime();
- println("\n ======== Profiling of total execution: " + TimeUtils.formatDuration(totalTime) + " ========\n");
+ println("");
+ println(" ======== Profiling of total execution: " + TimeUtils.formatDuration(totalTime) + " ========");
+ println("");
println(" * Module execution time breakdown: ");
double percent = totalTime / 100.0;
- for (ModuleProfiling modulesProfiling : truncate(sortByDescendingTotalTime(modulesProfilings))) {
- StringBuilder sb = new StringBuilder();
- sb.append(" o ").append(modulesProfiling.moduleName()).append(" execution time: ").append(modulesProfiling.totalTimeAsString())
- .append(" (").append((int) (modulesProfiling.totalTime() / percent)).append("%)");
- println(sb.toString());
+ for (ModuleProfiling modulesProfiling : truncate(sortByDescendingTotalTime(modulesProfilings).values())) {
+ println(" o " + modulesProfiling.moduleName() + " execution time: ", percent, modulesProfiling);
}
println("");
totalProfiling.dump();
- println("\n ======== End of profiling of total execution ========\n");
+ println("");
+ println(" ======== End of profiling of total execution ========");
+ println("");
}
public void onSensorsPhase(SensorsPhaseEvent event) {
}
}
+ @Override
+ public void onMavenPhase(MavenPhaseEvent event) {
+ if (event.isStart()) {
+ currentModuleProfiling.addPhaseProfiling(Phases.Phase.MAVEN);
+ }
+ else {
+ currentModuleProfiling.getProfilingPerPhase(Phases.Phase.MAVEN).stop();
+ }
+ }
+
+ @Override
+ public void onInitializersPhase(InitializersPhaseEvent event) {
+ if (event.isStart()) {
+ currentModuleProfiling.addPhaseProfiling(Phases.Phase.INIT);
+ }
+ else {
+ currentModuleProfiling.getProfilingPerPhase(Phases.Phase.INIT).stop();
+ }
+ }
+
+ @Override
+ public void onInitializerExecution(InitializerExecutionEvent event) {
+ PhaseProfiling profiling = currentModuleProfiling.getProfilingPerPhase(Phases.Phase.INIT);
+ if (event.isStart()) {
+ profiling.newItemProfiling(event.getInitializer());
+ } else {
+ profiling.getProfilingPerItem(event.getInitializer()).stop();
+ }
+ }
+
+ @Override
+ public void onBatchStep(BatchStepEvent event) {
+ if (event.isStart()) {
+ currentModuleProfiling.addBatchStepProfiling(event.stepName());
+ }
+ else {
+ currentModuleProfiling.getProfilingPerBatchStep(event.stepName()).stop();
+ }
+ }
+
class DecoratorsProfiler {
List<Decorator> decorators = Lists.newArrayList();
Map<Decorator, Long> durations = new IdentityHashMap<Decorator, Long>();
import org.sonar.api.scan.filesystem.ModuleFileSystem;
import org.sonar.api.utils.DateUtils;
import org.sonar.api.utils.SonarException;
+import org.sonar.batch.events.BatchStepEvent;
+import org.sonar.batch.events.EventBus;
import org.sonar.batch.issue.IssueCache;
import org.sonar.core.i18n.RuleI18nManager;
-import java.io.*;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
import java.util.Locale;
import java.util.Set;
private final Server server;
private final RuleI18nManager ruleI18nManager;
private final IssueCache issueCache;
+ private EventBus eventBus;
- public JsonReport(Settings settings, ModuleFileSystem fileSystem, Server server, RuleI18nManager ruleI18nManager, IssueCache issueCache) {
+ public JsonReport(Settings settings, ModuleFileSystem fileSystem, Server server, RuleI18nManager ruleI18nManager, IssueCache issueCache, EventBus eventBus) {
this.settings = settings;
this.fileSystem = fileSystem;
this.server = server;
this.ruleI18nManager = ruleI18nManager;
this.issueCache = issueCache;
+ this.eventBus = eventBus;
}
public void execute() {
if (settings.getBoolean(CoreProperties.DRY_RUN)) {
+ eventBus.fireEvent(new BatchStepEvent("JSON report", true));
exportResults();
+ eventBus.fireEvent(new BatchStepEvent("JSON report", false));
}
}
for (DefaultIssue issue : getIssues()) {
if (issue.resolution() == null) {
json
- .beginObject()
- .name("key").value(issue.key())
- .name("component").value(issue.componentKey())
- .name("line").value(issue.line())
- .name("message").value(issue.message())
- .name("severity").value(issue.severity())
- .name("rule").value(issue.ruleKey().toString())
- .name("status").value(issue.status())
- .name("resolution").value(issue.resolution())
- .name("isNew").value(issue.isNew())
- .name("reporter").value(issue.reporter())
- .name("assignee").value(issue.assignee())
- .name("effortToFix").value(issue.effortToFix());
+ .beginObject()
+ .name("key").value(issue.key())
+ .name("component").value(issue.componentKey())
+ .name("line").value(issue.line())
+ .name("message").value(issue.message())
+ .name("severity").value(issue.severity())
+ .name("rule").value(issue.ruleKey().toString())
+ .name("status").value(issue.status())
+ .name("resolution").value(issue.resolution())
+ .name("isNew").value(issue.isNew())
+ .name("reporter").value(issue.reporter())
+ .name("assignee").value(issue.assignee())
+ .name("effortToFix").value(issue.effortToFix());
if (issue.creationDate() != null) {
json.name("creationDate").value(DateUtils.formatDateTime(issue.creationDate()));
}
json.name("components").beginArray();
for (String componentKey : componentKeys) {
json
- .beginObject()
- .name("key").value(componentKey)
- .endObject();
+ .beginObject()
+ .name("key").value(componentKey)
+ .endObject();
}
json.endArray();
}
json.name("rules").beginArray();
for (RuleKey ruleKey : ruleKeys) {
json
- .beginObject()
- .name("key").value(ruleKey.toString())
- .name("rule").value(ruleKey.rule())
- .name("repository").value(ruleKey.repository())
- .name("name").value(getRuleName(ruleKey))
- .endObject();
+ .beginObject()
+ .name("key").value(ruleKey.toString())
+ .name("rule").value(ruleKey.rule())
+ .name("repository").value(ruleKey.repository())
+ .name("name").value(getRuleName(ruleKey))
+ .endObject();
}
json.endArray();
}
import org.junit.Test;
import org.sonar.api.batch.Decorator;
import org.sonar.api.batch.DecoratorContext;
+import org.sonar.api.batch.Initializer;
import org.sonar.api.batch.PostJob;
import org.sonar.api.batch.Sensor;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.events.DecoratorExecutionHandler;
import org.sonar.api.batch.events.DecoratorsPhaseHandler;
+import org.sonar.api.batch.events.InitializerExecutionHandler;
+import org.sonar.api.batch.events.InitializersPhaseHandler;
+import org.sonar.api.batch.events.MavenPhaseHandler;
import org.sonar.api.batch.events.PostJobExecutionHandler;
import org.sonar.api.batch.events.PostJobsPhaseHandler;
import org.sonar.api.batch.events.ProjectAnalysisHandler;
import org.sonar.api.batch.events.SensorsPhaseHandler.SensorsPhaseEvent;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
+import org.sonar.batch.events.BatchStepHandler;
import org.sonar.batch.phases.Phases.Phase;
import java.util.Arrays;
fakeAnalysis(profiler, project);
+ assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.MAVEN).totalTime()).isEqualTo(4L);
+ assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.INIT).getProfilingPerItem(new FakeInitializer()).totalTime()).isEqualTo(7L);
assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.SENSOR).getProfilingPerItem(new FakeSensor()).totalTime()).isEqualTo(10L);
assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator1()).totalTime()).isEqualTo(20L);
assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.POSTJOB).getProfilingPerItem(new FakePostJob()).totalTime()).isEqualTo(30L);
fakeAnalysis(profiler, moduleB);
fakeAnalysis(profiler, project);
+ assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.MAVEN).totalTime()).isEqualTo(4L);
+ assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.INIT).getProfilingPerItem(new FakeInitializer()).totalTime()).isEqualTo(7L);
assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.SENSOR).getProfilingPerItem(new FakeSensor()).totalTime()).isEqualTo(10L);
assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator1()).totalTime()).isEqualTo(20L);
assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator2()).totalTime()).isEqualTo(10L);
assertThat(profiler.currentModuleProfiling.getProfilingPerPhase(Phase.POSTJOB).getProfilingPerItem(new FakePostJob()).totalTime()).isEqualTo(30L);
+ assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.MAVEN).totalTime()).isEqualTo(12L);
+ assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.INIT).getProfilingPerItem(new FakeInitializer()).totalTime()).isEqualTo(21L);
assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.SENSOR).getProfilingPerItem(new FakeSensor()).totalTime()).isEqualTo(30L);
assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator1()).totalTime()).isEqualTo(60L);
assertThat(profiler.totalProfiling.getProfilingPerPhase(Phase.DECORATOR).getProfilingPerItem(new FakeDecorator2()).totalTime()).isEqualTo(30L);
private void fakeAnalysis(PhasesSumUpTimeProfiler profiler, final Project module) throws InterruptedException {
// Start of moduleA
profiler.onProjectAnalysis(projectEvent(module, true));
+ mavenPhase(profiler);
+ initializerPhase(profiler);
sensorPhase(profiler);
decoratorPhase(profiler);
postJobPhase(profiler);
+ batchStep(profiler);
// End of moduleA
profiler.onProjectAnalysis(projectEvent(module, false));
}
profiler.onDecoratorsPhase(decoratorsEvent(false));
}
+ private void batchStep(PhasesSumUpTimeProfiler profiler) throws InterruptedException {
+ // Start of batch step
+ profiler.onBatchStep(batchStepEvent(true, "Free memory"));
+ clock.sleep(9);
+ // End of batch step
+ profiler.onBatchStep(batchStepEvent(false, "Free memory"));
+ }
+
+ private void mavenPhase(PhasesSumUpTimeProfiler profiler) throws InterruptedException {
+ // Start of maven phase
+ profiler.onMavenPhase(mavenEvent(true));
+ clock.sleep(4);
+ // End of maven phase
+ profiler.onMavenPhase(mavenEvent(false));
+ }
+
+ private void initializerPhase(PhasesSumUpTimeProfiler profiler) throws InterruptedException {
+ Initializer initializer = new FakeInitializer();
+ // Start of initializer phase
+ profiler.onInitializersPhase(initializersEvent(true));
+ // Start of an initializer
+ profiler.onInitializerExecution(initializerEvent(initializer, true));
+ clock.sleep(7);
+ // End of an initializer
+ profiler.onInitializerExecution(initializerEvent(initializer, false));
+ // End of initializer phase
+ profiler.onInitializersPhase(initializersEvent(false));
+ }
+
private void sensorPhase(PhasesSumUpTimeProfiler profiler) throws InterruptedException {
Sensor sensor = new FakeSensor();
// Start of sensor phase
};
}
+ private InitializerExecutionHandler.InitializerExecutionEvent initializerEvent(final Initializer initializer, final boolean start) {
+ return new InitializerExecutionHandler.InitializerExecutionEvent() {
+
+ @Override
+ public boolean isStart() {
+ return start;
+ }
+
+ @Override
+ public boolean isEnd() {
+ return !start;
+ }
+
+ @Override
+ public Initializer getInitializer() {
+ return initializer;
+ }
+ };
+ }
+
private DecoratorExecutionHandler.DecoratorExecutionEvent decoratorEvent(final Decorator decorator, final boolean start) {
return new DecoratorExecutionHandler.DecoratorExecutionEvent() {
};
}
+ private BatchStepHandler.BatchStepEvent batchStepEvent(final boolean start, final String stepName) {
+ return new BatchStepHandler.BatchStepEvent() {
+
+ @Override
+ public boolean isStart() {
+ return start;
+ }
+
+ @Override
+ public boolean isEnd() {
+ return !start;
+ }
+
+ @Override
+ public String stepName() {
+ return stepName;
+ }
+ };
+ }
+
+ private MavenPhaseHandler.MavenPhaseEvent mavenEvent(final boolean start) {
+ return new MavenPhaseHandler.MavenPhaseEvent() {
+
+ @Override
+ public boolean isStart() {
+ return start;
+ }
+
+ @Override
+ public boolean isEnd() {
+ return !start;
+ }
+ };
+ }
+
+ private InitializersPhaseHandler.InitializersPhaseEvent initializersEvent(final boolean start) {
+ return new InitializersPhaseHandler.InitializersPhaseEvent() {
+
+ @Override
+ public boolean isStart() {
+ return start;
+ }
+
+ @Override
+ public boolean isEnd() {
+ return !start;
+ }
+
+ @Override
+ public List<Initializer> getInitializers() {
+ return null;
+ }
+ };
+ }
+
private PostJobsPhaseHandler.PostJobsPhaseEvent postJobsEvent(final boolean start) {
return new PostJobsPhaseHandler.PostJobsPhaseEvent() {
public void analyse(Project project, SensorContext context) {
}
+ @Override
+ public boolean shouldExecuteOnProject(Project project) {
+ return true;
+ }
+ }
+
+ public class FakeInitializer extends Initializer {
+ @Override
+ public void execute(Project project) {
+ }
+
+ @Override
public boolean shouldExecuteOnProject(Project project) {
return true;
}
}
public class FakeDecorator1 implements Decorator {
+ @Override
public void decorate(Resource resource, DecoratorContext context) {
}
+ @Override
public boolean shouldExecuteOnProject(Project project) {
return true;
}
}
public class FakeDecorator2 implements Decorator {
+ @Override
public void decorate(Resource resource, DecoratorContext context) {
}
+ @Override
public boolean shouldExecuteOnProject(Project project) {
return true;
}
import org.sonar.api.rules.Rule;
import org.sonar.api.scan.filesystem.ModuleFileSystem;
import org.sonar.api.utils.DateUtils;
+import org.sonar.batch.events.EventBus;
import org.sonar.batch.issue.IssueCache;
import org.sonar.core.i18n.RuleI18nManager;
import org.sonar.test.TestUtils;
settings = new Settings();
settings.setProperty(CoreProperties.DRY_RUN, true);
- jsonReport = new JsonReport(settings, fileSystem, server, ruleI18nManager, issueCache);
+ jsonReport = new JsonReport(settings, fileSystem, server, ruleI18nManager, issueCache, mock(EventBus.class));
}
@Test
public void should_write_json() throws JSONException {
DefaultIssue issue = new DefaultIssue()
- .setKey("200")
- .setComponentKey("struts:org.apache.struts.Action")
- .setRuleKey(RuleKey.of("squid", "AvoidCycles"))
- .setMessage("There are 2 cycles")
- .setSeverity("MINOR")
- .setStatus(Issue.STATUS_OPEN)
- .setResolution(null)
- .setLine(1)
- .setEffortToFix(3.14)
- .setReporter("julien")
- .setAssignee("simon")
- .setCreationDate(DateUtils.parseDate("2013-04-24"))
- .setUpdateDate(DateUtils.parseDate("2013-04-25"))
- .setNew(false);
+ .setKey("200")
+ .setComponentKey("struts:org.apache.struts.Action")
+ .setRuleKey(RuleKey.of("squid", "AvoidCycles"))
+ .setMessage("There are 2 cycles")
+ .setSeverity("MINOR")
+ .setStatus(Issue.STATUS_OPEN)
+ .setResolution(null)
+ .setLine(1)
+ .setEffortToFix(3.14)
+ .setReporter("julien")
+ .setAssignee("simon")
+ .setCreationDate(DateUtils.parseDate("2013-04-24"))
+ .setUpdateDate(DateUtils.parseDate("2013-04-25"))
+ .setNew(false);
when(ruleI18nManager.getName("squid", "AvoidCycles", Locale.getDefault())).thenReturn("Avoid Cycles");
- when(jsonReport.getIssues()).thenReturn(Lists.<DefaultIssue>newArrayList(issue));
+ when(jsonReport.getIssues()).thenReturn(Lists.<DefaultIssue> newArrayList(issue));
StringWriter writer = new StringWriter();
jsonReport.writeJson(writer);
JSONAssert.assertEquals(TestUtils.getResourceContent("/org/sonar/batch/scan/JsonReportTest/report.json"),
- writer.toString(), false);
+ writer.toString(), false);
}
@Test
public void should_exclude_resolved_issues() throws JSONException {
DefaultIssue issue = new DefaultIssue()
- .setKey("200")
- .setComponentKey("struts:org.apache.struts.Action")
- .setRuleKey(RuleKey.of("squid", "AvoidCycles"))
- .setStatus(Issue.STATUS_CLOSED)
- .setResolution(Issue.RESOLUTION_FIXED)
- .setCreationDate(DateUtils.parseDate("2013-04-24"))
- .setUpdateDate(DateUtils.parseDate("2013-04-25"))
- .setCloseDate(DateUtils.parseDate("2013-04-26"))
- .setNew(false);
+ .setKey("200")
+ .setComponentKey("struts:org.apache.struts.Action")
+ .setRuleKey(RuleKey.of("squid", "AvoidCycles"))
+ .setStatus(Issue.STATUS_CLOSED)
+ .setResolution(Issue.RESOLUTION_FIXED)
+ .setCreationDate(DateUtils.parseDate("2013-04-24"))
+ .setUpdateDate(DateUtils.parseDate("2013-04-25"))
+ .setCloseDate(DateUtils.parseDate("2013-04-26"))
+ .setNew(false);
when(ruleI18nManager.getName("squid", "AvoidCycles", Locale.getDefault())).thenReturn("Avoid Cycles");
- when(jsonReport.getIssues()).thenReturn(Lists.<DefaultIssue>newArrayList(issue));
+ when(jsonReport.getIssues()).thenReturn(Lists.<DefaultIssue> newArrayList(issue));
StringWriter writer = new StringWriter();
jsonReport.writeJson(writer);
JSONAssert.assertEquals(TestUtils.getResourceContent("/org/sonar/batch/scan/JsonReportTest/report-without-resolved-issues.json"),
- writer.toString(), false);
+ writer.toString(), false);
}
@Test
public void should_ignore_components_without_issue() throws JSONException {
- when(jsonReport.getIssues()).thenReturn(Collections.<DefaultIssue>emptyList());
+ when(jsonReport.getIssues()).thenReturn(Collections.<DefaultIssue> emptyList());
StringWriter writer = new StringWriter();
jsonReport.writeJson(writer);
Rule rule = Rule.create("squid", "AvoidCycles");
when(ruleI18nManager.getName(rule, Locale.getDefault())).thenReturn("Avoid Cycles");
- when(jsonReport.getIssues()).thenReturn(Collections.<DefaultIssue>emptyList());
+ when(jsonReport.getIssues()).thenReturn(Collections.<DefaultIssue> emptyList());
settings.setProperty("sonar.report.export.path", "output.json");
when(fileSystem.workingDir()).thenReturn(sonarDirectory);
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.events;
+
+import org.sonar.api.batch.Initializer;
+
+/**
+ * @since 3.7
+ */
+public interface InitializerExecutionHandler extends EventHandler {
+
+ /**
+ * This interface is not intended to be implemented by clients.
+ */
+ interface InitializerExecutionEvent {
+
+ Initializer getInitializer();
+
+ boolean isStart();
+
+ boolean isEnd();
+
+ }
+
+ /**
+ * Called before and after execution of {@link Initializer}.
+ */
+ void onInitializerExecution(InitializerExecutionEvent event);
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.events;
+
+import org.sonar.api.batch.Initializer;
+
+import java.util.List;
+
+/**
+ * @since 3.7
+ */
+public interface InitializersPhaseHandler extends EventHandler {
+
+ /**
+ * This interface is not intended to be implemented by clients.
+ */
+ interface InitializersPhaseEvent {
+
+ /**
+ * @return list of Initializers in the order of execution
+ */
+ List<Initializer> getInitializers();
+
+ boolean isStart();
+
+ boolean isEnd();
+
+ }
+
+ /**
+ * Called before and after execution of all {@link Initializers}s.
+ */
+ void onInitializersPhase(InitializersPhaseEvent event);
+
+}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2013 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.api.batch.events;
+
+
+/**
+ * @since 3.7
+ */
+public interface MavenPhaseHandler extends EventHandler {
+
+ /**
+ * This interface is not intended to be implemented by clients.
+ */
+ interface MavenPhaseEvent {
+
+ boolean isStart();
+
+ boolean isEnd();
+
+ }
+
+ /**
+ * Called before and after execution Maven phase (-Dsonar.phase=xxx).
+ */
+ void onMavenPhase(MavenPhaseEvent event);
+
+}