*/
package org.sonar.batch;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+
import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.batch.bootstrap.BootstrapClassLoader;
import org.sonar.batch.bootstrap.ExtensionDownloader;
import org.sonar.batch.bootstrap.TempDirectories;
-import org.sonar.batch.components.*;
-import org.sonar.batch.index.*;
+import org.sonar.batch.components.PastMeasuresLoader;
+import org.sonar.batch.components.PastSnapshotFinder;
+import org.sonar.batch.components.PastSnapshotFinderByDate;
+import org.sonar.batch.components.PastSnapshotFinderByDays;
+import org.sonar.batch.components.PastSnapshotFinderByPreviousAnalysis;
+import org.sonar.batch.components.PastSnapshotFinderByVersion;
+import org.sonar.batch.events.EventBus;
+import org.sonar.batch.index.DefaultIndex;
+import org.sonar.batch.index.DefaultPersistenceManager;
+import org.sonar.batch.index.DefaultResourcePersister;
+import org.sonar.batch.index.DependencyPersister;
+import org.sonar.batch.index.EventPersister;
+import org.sonar.batch.index.LinkPersister;
+import org.sonar.batch.index.MeasurePersister;
+import org.sonar.batch.index.MemoryOptimizer;
+import org.sonar.batch.index.SourcePersister;
+import org.sonar.batch.index.ViolationPersister;
import org.sonar.core.components.CacheMetricFinder;
import org.sonar.core.components.CacheRuleFinder;
import org.sonar.core.plugin.JpaPluginDao;
import org.sonar.jpa.session.DriverDatabaseConnector;
import org.sonar.jpa.session.ThreadLocalDatabaseSessionFactory;
-import java.net.URLClassLoader;
-import java.util.Arrays;
-
public class Batch {
private static final Logger LOG = LoggerFactory.getLogger(Batch.class);
addComponent(EventPersister.class);
addComponent(LinkPersister.class);
addComponent(MeasurePersister.class);
+ addComponent(EventBus.class);
addComponent(MemoryOptimizer.class);
addComponent(DefaultResourcePersister.class);
addComponent(SourcePersister.class);
import org.sonar.batch.index.DefaultIndex;
import org.sonar.batch.index.DefaultResourcePersister;
import org.sonar.batch.phases.Phases;
+import org.sonar.batch.phases.PhasesTimeProfiler;
import org.sonar.core.components.DefaultModelFinder;
import org.sonar.jpa.dao.AsyncMeasuresDao;
import org.sonar.jpa.dao.AsyncMeasuresService;
@Override
protected void configure() {
addComponent(Phases.class);
+ addComponent(PhasesTimeProfiler.class);
for (Class clazz : Phases.getPhaseClasses()) {
addComponent(clazz);
}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.events;
+
+import org.sonar.api.batch.Decorator;
+
+/**
+ * Fired on each execution of {@link Decorator} on start and on finish.
+ */
+public class DecoratorExecutionEvent extends SonarEvent<DecoratorExecutionHandler> {
+
+ private Decorator decorator;
+ private boolean start;
+
+ public DecoratorExecutionEvent(Decorator decorator, boolean start) {
+ this.decorator = decorator;
+ this.start = start;
+ }
+
+ public Decorator getDecorator() {
+ return decorator;
+ }
+
+ public boolean isStartExecution() {
+ return start;
+ }
+
+ public boolean isDoneExecution() {
+ return !start;
+ }
+
+ @Override
+ public void dispatch(DecoratorExecutionHandler handler) {
+ handler.onDecoratorExecution(this);
+ }
+
+ @Override
+ public Class getType() {
+ return DecoratorExecutionHandler.class;
+ }
+
+}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.events;
+
+public interface DecoratorExecutionHandler extends EventHandler {
+
+ void onDecoratorExecution(DecoratorExecutionEvent event);
+
+}
--- /dev/null
+package org.sonar.batch.events;
+
+import org.sonar.api.batch.Decorator;
+
+import java.util.Collection;
+
+/**
+ * Fired before execution of {@link Decorator}s and after.
+ */
+public class DecoratorsPhaseEvent extends SonarEvent<DecoratorsPhaseHandler> {
+
+ private Collection<Decorator> decorators;
+ private boolean start;
+
+ public DecoratorsPhaseEvent(Collection<Decorator> decorators, boolean start) {
+ this.decorators = decorators;
+ this.start = start;
+ }
+
+ public Collection<Decorator> getDecorators() {
+ return decorators;
+ }
+
+ public boolean isPhaseStart() {
+ return start;
+ }
+
+ public boolean isPhaseDone() {
+ return !start;
+ }
+
+ @Override
+ protected void dispatch(DecoratorsPhaseHandler handler) {
+ handler.onDecoratorsPhase(this);
+ }
+
+ @Override
+ protected Class getType() {
+ return DecoratorsPhaseHandler.class;
+ }
+
+}
--- /dev/null
+package org.sonar.batch.events;
+
+public interface DecoratorsPhaseHandler extends EventHandler {
+
+ void onDecoratorsPhase(DecoratorsPhaseEvent event);
+
+}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.events;
+
+import java.util.List;
+
+import com.google.common.collect.Lists;
+import org.sonar.api.utils.Logs;
+
+/**
+ * Dispatches {@link SonarEvent}s. Eases decoupling by allowing objects to interact without having direct dependencies upon one another, and
+ * without requiring event sources to deal with maintaining handler lists.
+ *
+ * @since 2.7
+ */
+public class EventBus {
+
+ private EventHandler[] registeredHandlers;
+
+ public EventBus(EventHandler[] handlers) {
+ this.registeredHandlers = handlers;
+ }
+
+ /**
+ * Fires the given event.
+ */
+ public void fireEvent(SonarEvent event) {
+ doFireEvent(event);
+ }
+
+ private void doFireEvent(SonarEvent event) {
+ List<EventHandler> handlers = getDispatchList(event.getType());
+ Logs.INFO.debug("Dispatch event {} for {}", event, handlers);
+ for (EventHandler handler : handlers) {
+ event.dispatch(handler);
+ }
+ }
+
+ private List<EventHandler> getDispatchList(Class<? extends EventHandler> handlerType) {
+ List<EventHandler> result = Lists.newArrayList();
+ for (EventHandler handler : registeredHandlers) {
+ if (handlerType.isAssignableFrom(handler.getClass())) {
+ result.add(handler);
+ }
+ }
+ return result;
+ }
+
+}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.events;
+
+/**
+ * Marker interface for event handlers.
+ *
+ * @since 2.7
+ */
+public interface EventHandler {
+
+}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.events;
+
+import org.sonar.api.batch.Sensor;
+
+/**
+ * Fired on each execution of {@link Sensor} on start and on finish.
+ */
+public class SensorExecutionEvent extends SonarEvent<SensorExecutionHandler> {
+
+ private Sensor sensor;
+ private boolean start;
+
+ public SensorExecutionEvent(Sensor sensor, boolean start) {
+ this.sensor = sensor;
+ this.start = start;
+ }
+
+ public Sensor getSensor() {
+ return sensor;
+ }
+
+ public boolean isStartExecution() {
+ return start;
+ }
+
+ public boolean isDoneExecution() {
+ return !start;
+ }
+
+ @Override
+ public void dispatch(SensorExecutionHandler handler) {
+ handler.onSensorExecution(this);
+ }
+
+ @Override
+ public Class getType() {
+ return SensorExecutionHandler.class;
+ }
+
+}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.events;
+
+public interface SensorExecutionHandler extends EventHandler {
+
+ void onSensorExecution(SensorExecutionEvent event);
+
+}
--- /dev/null
+package org.sonar.batch.events;
+
+import org.sonar.api.batch.Sensor;
+
+import java.util.Collection;
+
+/**
+ * Fired before execution of {@link Sensor}s and after.
+ */
+public class SensorsPhaseEvent extends SonarEvent<SensorsPhaseHandler> {
+
+ private Collection<Sensor> sensors;
+ private boolean start;
+
+ public SensorsPhaseEvent(Collection<Sensor> sensors, boolean start) {
+ this.sensors = sensors;
+ this.start = start;
+ }
+
+ public Collection<Sensor> getSensors() {
+ return sensors;
+ }
+
+ public boolean isPhaseStart() {
+ return start;
+ }
+
+ @Override
+ protected void dispatch(SensorsPhaseHandler handler) {
+ handler.onSensorsPhase(this);
+ }
+
+ @Override
+ protected Class getType() {
+ return SensorsPhaseHandler.class;
+ }
+
+}
--- /dev/null
+package org.sonar.batch.events;
+
+public interface SensorsPhaseHandler extends EventHandler {
+
+ void onSensorsPhase(SensorsPhaseEvent event);
+
+}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.events;
+
+/**
+ * Root of all Sonar events.
+ *
+ * @param <H> handler type
+ * @since 2.7
+ */
+public abstract class SonarEvent<H extends EventHandler> {
+
+ protected SonarEvent() {
+ }
+
+ /**
+ * Do not call directly - should be called only by {@link EventBus}.
+ * Typically should be implemented as following: <code>handler.onEvent(this)</code>
+ */
+ protected abstract void dispatch(H handler);
+
+ /**
+ * Returns class of associated handler. Used by {@link EventBus} to dispatch events to the correct handlers.
+ */
+ protected abstract Class getType();
+
+}
*/
package org.sonar.batch.index;
+import java.util.List;
+import java.util.Map;
+
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.sonar.api.database.model.MeasureModel;
import org.sonar.api.measures.Measure;
import org.sonar.api.measures.PersistenceMode;
-
-import java.util.List;
-import java.util.Map;
+import org.sonar.batch.events.DecoratorExecutionEvent;
+import org.sonar.batch.events.DecoratorExecutionHandler;
+import org.sonar.batch.events.DecoratorsPhaseEvent;
+import org.sonar.batch.events.DecoratorsPhaseHandler;
+import org.sonar.batch.events.SensorExecutionEvent;
+import org.sonar.batch.events.SensorExecutionHandler;
/**
* @since 2.7
*/
-public class MemoryOptimizer {
+public class MemoryOptimizer implements SensorExecutionHandler, DecoratorExecutionHandler, DecoratorsPhaseHandler {
private static final Logger LOG = LoggerFactory.getLogger(MemoryOptimizer.class);
boolean isTracked(Long measureId) {
return dataIdByMeasureId.get(measureId) != null;
}
+
+ public void onSensorExecution(SensorExecutionEvent event) {
+ if (event.isDoneExecution()) {
+ flushMemory();
+ session.commit();
+ }
+ }
+
+ public void onDecoratorExecution(DecoratorExecutionEvent event) {
+ if (event.isDoneExecution()) {
+ flushMemory();
+ }
+ }
+
+ public void onDecoratorsPhase(DecoratorsPhaseEvent event) {
+ if (event.isPhaseDone()) {
+ session.commit();
+ }
+ }
+
}
*/
package org.sonar.batch.phases;
+import java.util.Collection;
+import java.util.List;
+
import com.google.common.collect.Lists;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.SystemUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.sonar.api.BatchComponent;
import org.sonar.api.batch.BatchExtensionDictionnary;
import org.sonar.api.batch.Decorator;
import org.sonar.api.resources.Resource;
import org.sonar.batch.DecoratorsSelector;
import org.sonar.batch.DefaultDecoratorContext;
+import org.sonar.batch.events.DecoratorExecutionEvent;
+import org.sonar.batch.events.DecoratorsPhaseEvent;
+import org.sonar.batch.events.EventBus;
import org.sonar.batch.index.DefaultIndex;
-import org.sonar.batch.index.MemoryOptimizer;
-
-import java.util.Collection;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
public class DecoratorsExecutor implements BatchComponent {
private DecoratorsSelector decoratorsSelector;
private DatabaseSession session;
- private static final Logger LOG = LoggerFactory.getLogger(DecoratorsExecutor.class);
private DefaultIndex index;
- private MemoryOptimizer memoryOptimizer;
+ private EventBus eventBus;
- public DecoratorsExecutor(BatchExtensionDictionnary extensionDictionnary, DefaultIndex index, DatabaseSession session,
- MemoryOptimizer memoryOptimizer) {
+ public DecoratorsExecutor(BatchExtensionDictionnary extensionDictionnary, DefaultIndex index, DatabaseSession session, EventBus eventBus) {
this.decoratorsSelector = new DecoratorsSelector(extensionDictionnary);
this.session = session;
this.index = index;
- this.memoryOptimizer = memoryOptimizer;
+ this.eventBus = eventBus;
}
-
public void execute(Project project) {
- LoggerFactory.getLogger(DecoratorsExecutor.class).info("Execute decorators...");
Collection<Decorator> decorators = decoratorsSelector.select(project);
-
- if (LOG.isDebugEnabled()) {
- LOG.debug("Decorators: {}", StringUtils.join(decorators, " -> "));
- }
-
- DecoratorsProfiler profiler = new DecoratorsProfiler(decorators);
- decorateResource(project, decorators, true, profiler);
- session.commit();
- profiler.log();
+ eventBus.fireEvent(new DecoratorsPhaseEvent(decorators, true));
+ decorateResource(project, decorators, true);
+ eventBus.fireEvent(new DecoratorsPhaseEvent(decorators, false));
}
- private DecoratorContext decorateResource(Resource resource, Collection<Decorator> decorators, boolean executeDecorators, DecoratorsProfiler profiler) {
+ private DecoratorContext decorateResource(Resource resource, Collection<Decorator> decorators, boolean executeDecorators) {
List<DecoratorContext> childrenContexts = Lists.newArrayList();
for (Resource child : index.getChildren(resource)) {
boolean isModule = (child instanceof Project);
- DefaultDecoratorContext childContext = (DefaultDecoratorContext) decorateResource(child, decorators, !isModule, profiler);
+ DefaultDecoratorContext childContext = (DefaultDecoratorContext) decorateResource(child, decorators, !isModule);
childrenContexts.add(childContext.setReadOnly(true));
}
DefaultDecoratorContext context = new DefaultDecoratorContext(resource, index, childrenContexts, session);
if (executeDecorators) {
for (Decorator decorator : decorators) {
- profiler.start(decorator);
+ eventBus.fireEvent(new DecoratorExecutionEvent(decorator, true));
decorator.decorate(resource, context);
- memoryOptimizer.flushMemory();
- profiler.stop();
+ eventBus.fireEvent(new DecoratorExecutionEvent(decorator, false));
}
}
return context;
}
-
- static class DecoratorsProfiler {
- Collection<Decorator> decorators;
- Map<Decorator, Long> durations = new IdentityHashMap<Decorator, Long>();
- long startTime;
- Decorator currentDecorator;
-
- DecoratorsProfiler(Collection<Decorator> decorators) {
- this.decorators = decorators;
- for (Decorator decorator : decorators) {
- durations.put(decorator, 0L);
- }
- }
-
- void start(Decorator decorator) {
- this.startTime = System.currentTimeMillis();
- this.currentDecorator = decorator;
- }
-
- void stop() {
- Long cumulatedDuration = durations.get(currentDecorator);
- durations.put(currentDecorator, cumulatedDuration + (System.currentTimeMillis() - startTime));
- }
-
- void log() {
- LOG.debug(getMessage());
- }
-
- String getMessage() {
- StringBuilder sb = new StringBuilder("Decorator time:").append(SystemUtils.LINE_SEPARATOR);
- for (Decorator decorator : decorators) {
- sb.append("\t").append(decorator.toString()).append(": ").append(durations.get(decorator)).append("ms").append(SystemUtils.LINE_SEPARATOR);
- }
- return sb.toString();
- }
- }
}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.phases;
+
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.collect.Lists;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.SystemUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.Decorator;
+import org.sonar.api.utils.TimeProfiler;
+import org.sonar.batch.events.DecoratorExecutionEvent;
+import org.sonar.batch.events.DecoratorExecutionHandler;
+import org.sonar.batch.events.DecoratorsPhaseEvent;
+import org.sonar.batch.events.DecoratorsPhaseHandler;
+import org.sonar.batch.events.SensorExecutionEvent;
+import org.sonar.batch.events.SensorExecutionHandler;
+import org.sonar.batch.events.SensorsPhaseEvent;
+import org.sonar.batch.events.SensorsPhaseHandler;
+
+public class PhasesTimeProfiler implements SensorExecutionHandler, DecoratorExecutionHandler, DecoratorsPhaseHandler, SensorsPhaseHandler {
+
+ private static final Logger LOG = LoggerFactory.getLogger(PhasesTimeProfiler.class);
+
+ private TimeProfiler profiler = new TimeProfiler(LOG);
+ private DecoratorsProfiler decoratorsProfiler = new DecoratorsProfiler();
+
+ public void onSensorsPhase(SensorsPhaseEvent event) {
+ if (event.isPhaseStart()) {
+ LOG.debug("Sensors : {}", StringUtils.join(event.getSensors(), " -> "));
+ }
+ }
+
+ public void onSensorExecution(SensorExecutionEvent event) {
+ if (event.isStartExecution()) {
+ profiler.start("Sensor " + event.getSensor());
+ } else {
+ profiler.stop();
+ }
+ }
+
+ public void onDecoratorExecution(DecoratorExecutionEvent event) {
+ if (event.isStartExecution()) {
+ decoratorsProfiler.start(event.getDecorator());
+ } else {
+ decoratorsProfiler.stop();
+ }
+ }
+
+ public void onDecoratorsPhase(DecoratorsPhaseEvent event) {
+ if (event.isPhaseStart()) {
+ LOG.info("Execute decorators...");
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Decorators: {}", StringUtils.join(event.getDecorators(), " -> "));
+ }
+ } else {
+ decoratorsProfiler.log();
+ }
+ }
+
+ static class DecoratorsProfiler {
+ List<Decorator> decorators = Lists.newArrayList();
+ Map<Decorator, Long> durations = new IdentityHashMap<Decorator, Long>();
+ long startTime;
+ Decorator currentDecorator;
+
+ DecoratorsProfiler() {
+ }
+
+ void start(Decorator decorator) {
+ this.startTime = System.currentTimeMillis();
+ this.currentDecorator = decorator;
+ }
+
+ void stop() {
+ final Long cumulatedDuration;
+ if (durations.containsKey(currentDecorator)) {
+ cumulatedDuration = durations.get(currentDecorator);
+ } else {
+ decorators.add(currentDecorator);
+ cumulatedDuration = 0L;
+ }
+ durations.put(currentDecorator, cumulatedDuration + (System.currentTimeMillis() - startTime));
+ }
+
+ void log() {
+ LOG.debug(getMessage());
+ }
+
+ String getMessage() {
+ StringBuilder sb = new StringBuilder("Decorator time:").append(SystemUtils.LINE_SEPARATOR);
+ for (Decorator decorator : decorators) {
+ sb.append("\t").append(decorator.toString()).append(": ").append(durations.get(decorator)).append("ms")
+ .append(SystemUtils.LINE_SEPARATOR);
+ }
+ return sb.toString();
+ }
+ }
+
+}
*/
package org.sonar.batch.phases;
-import org.apache.commons.lang.StringUtils;
+import java.util.Collection;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.BatchComponent;
import org.sonar.api.batch.SensorContext;
import org.sonar.api.batch.maven.DependsUponMavenPlugin;
import org.sonar.api.batch.maven.MavenPluginHandler;
-import org.sonar.api.database.DatabaseSession;
import org.sonar.api.resources.Project;
import org.sonar.api.utils.TimeProfiler;
import org.sonar.batch.MavenPluginExecutor;
-import org.sonar.batch.index.MemoryOptimizer;
-
-import java.util.Collection;
+import org.sonar.batch.events.EventBus;
+import org.sonar.batch.events.SensorExecutionEvent;
+import org.sonar.batch.events.SensorsPhaseEvent;
public class SensorsExecutor implements BatchComponent {
- private static final Logger logger = LoggerFactory.getLogger(SensorsExecutor.class);
+ private static final Logger LOG = LoggerFactory.getLogger(SensorsExecutor.class);
private Collection<Sensor> sensors;
- private DatabaseSession session;
private MavenPluginExecutor mavenExecutor;
- private MemoryOptimizer memoryOptimizer;
+ private EventBus eventBus;
- public SensorsExecutor(BatchExtensionDictionnary selector, Project project, DatabaseSession session, MavenPluginExecutor mavenExecutor,
- MemoryOptimizer memoryOptimizer) {
+ public SensorsExecutor(BatchExtensionDictionnary selector, Project project, MavenPluginExecutor mavenExecutor, EventBus eventBus) {
this.sensors = selector.select(Sensor.class, project, true);
- this.session = session;
this.mavenExecutor = mavenExecutor;
- this.memoryOptimizer = memoryOptimizer;
+ this.eventBus = eventBus;
}
public void execute(Project project, SensorContext context) {
- if (logger.isDebugEnabled()) {
- logger.debug("Sensors : {}", StringUtils.join(sensors, " -> "));
- }
+ eventBus.fireEvent(new SensorsPhaseEvent(sensors, true));
for (Sensor sensor : sensors) {
executeMavenPlugin(project, sensor);
- TimeProfiler profiler = new TimeProfiler(logger).start("Sensor " + sensor);
+ eventBus.fireEvent(new SensorExecutionEvent(sensor, true));
sensor.analyse(project, context);
- memoryOptimizer.flushMemory();
- session.commit();
- profiler.stop();
+ eventBus.fireEvent(new SensorExecutionEvent(sensor, false));
}
+
+ eventBus.fireEvent(new SensorsPhaseEvent(sensors, false));
}
private void executeMavenPlugin(Project project, Sensor sensor) {
if (sensor instanceof DependsUponMavenPlugin) {
MavenPluginHandler handler = ((DependsUponMavenPlugin) sensor).getMavenPluginHandler(project);
if (handler != null) {
- TimeProfiler profiler = new TimeProfiler(logger).start("Execute maven plugin " + handler.getArtifactId());
+ TimeProfiler profiler = new TimeProfiler(LOG).start("Execute maven plugin " + handler.getArtifactId());
mavenExecutor.execute(project, handler);
profiler.stop();
}
--- /dev/null
+/*
+ * Sonar, open source software quality management tool.
+ * Copyright (C) 2008-2011 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * Sonar 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.
+ *
+ * Sonar 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 Sonar; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
+ */
+package org.sonar.batch.events;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Test;
+
+public class EventBusTest {
+
+ @Test
+ public void shouldNotifyAboutEvent() {
+ FirstHandler firstHandler = mock(FirstHandler.class);
+ SecondHandler secondHandler = mock(SecondHandler.class);
+ EventBus eventBus = new EventBus(new EventHandler[] { firstHandler, secondHandler });
+
+ FirstEvent firstEvent = new FirstEvent();
+ eventBus.fireEvent(firstEvent);
+ SecondEvent secondEvent = new SecondEvent();
+ eventBus.fireEvent(secondEvent);
+
+ verify(firstHandler).onEvent(firstEvent);
+ verify(secondHandler).onEvent(secondEvent);
+ }
+
+ interface FirstHandler extends EventHandler {
+ void onEvent(FirstEvent event);
+ }
+
+ static class FirstEvent extends SonarEvent<FirstHandler> {
+ @Override
+ protected void dispatch(FirstHandler handler) {
+ handler.onEvent(this);
+ }
+
+ @Override
+ public Class getType() {
+ return FirstHandler.class;
+ }
+ }
+
+ interface SecondHandler extends EventHandler {
+ void onEvent(SecondEvent event);
+ }
+
+ static class SecondEvent extends SonarEvent<SecondHandler> {
+ @Override
+ protected void dispatch(SecondHandler handler) {
+ handler.onEvent(this);
+ }
+
+ @Override
+ public Class getType() {
+ return SecondHandler.class;
+ }
+ }
+
+}
*/
package org.sonar.batch.phases;
+import static org.hamcrest.number.OrderingComparisons.greaterThanOrEqualTo;
+import static org.hamcrest.number.OrderingComparisons.lessThan;
+import static org.junit.Assert.assertThat;
+
import org.junit.Test;
import org.sonar.api.batch.Decorator;
import org.sonar.api.batch.DecoratorContext;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
-import java.util.Arrays;
-import java.util.List;
-
-import static org.hamcrest.number.OrderingComparisons.greaterThanOrEqualTo;
-import static org.hamcrest.number.OrderingComparisons.lessThan;
-import static org.junit.Assert.assertThat;
-
public class DecoratorsExecutorTest {
@Test
public void shouldProfileExecutionTime() {
Decorator1 decorator1 = new Decorator1();
Decorator2 decorator2 = new Decorator2();
- List<Decorator> decorators = Arrays.asList(decorator1, decorator2);
- DecoratorsExecutor.DecoratorsProfiler profiler = new DecoratorsExecutor.DecoratorsProfiler(decorators);
+ PhasesTimeProfiler.DecoratorsProfiler profiler = new PhasesTimeProfiler.DecoratorsProfiler();
profiler.start(decorator1);
profiler.stop();