]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-2272 Add EventBus
authorEvgeny Mandrikov <mandrikov@gmail.com>
Fri, 11 Mar 2011 12:14:08 +0000 (15:14 +0300)
committerEvgeny Mandrikov <mandrikov@gmail.com>
Fri, 11 Mar 2011 21:42:42 +0000 (00:42 +0300)
19 files changed:
sonar-batch/src/main/java/org/sonar/batch/Batch.java
sonar-batch/src/main/java/org/sonar/batch/ProjectBatch.java
sonar-batch/src/main/java/org/sonar/batch/events/DecoratorExecutionEvent.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/events/DecoratorExecutionHandler.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/events/DecoratorsPhaseEvent.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/events/DecoratorsPhaseHandler.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/events/EventBus.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/events/EventHandler.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/events/SensorExecutionEvent.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/events/SensorExecutionHandler.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/events/SensorsPhaseEvent.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/events/SensorsPhaseHandler.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/events/SonarEvent.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/index/MemoryOptimizer.java
sonar-batch/src/main/java/org/sonar/batch/phases/DecoratorsExecutor.java
sonar-batch/src/main/java/org/sonar/batch/phases/PhasesTimeProfiler.java [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/phases/SensorsExecutor.java
sonar-batch/src/test/java/org/sonar/batch/events/EventBusTest.java [new file with mode: 0644]
sonar-batch/src/test/java/org/sonar/batch/phases/DecoratorsExecutorTest.java

index c2b15adda09d6d3af6cb9181a5318e119f6dc242..d36128953eafd84c25b5b15f9d1325a35b539267 100644 (file)
@@ -19,6 +19,9 @@
  */
 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;
@@ -30,8 +33,23 @@ import org.sonar.batch.bootstrap.BatchPluginRepository;
 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;
@@ -40,9 +58,6 @@ import org.sonar.jpa.session.DatabaseSessionProvider;
 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);
@@ -89,6 +104,7 @@ public class Batch {
       addComponent(EventPersister.class);
       addComponent(LinkPersister.class);
       addComponent(MeasurePersister.class);
+      addComponent(EventBus.class);
       addComponent(MemoryOptimizer.class);
       addComponent(DefaultResourcePersister.class);
       addComponent(SourcePersister.class);
index 8614891b8b8889c44db216741a3992036bef7786..14406cf4ff97f6719950ac70d7d72558632d0fc3 100644 (file)
@@ -38,6 +38,7 @@ import org.sonar.batch.components.TimeMachineConfiguration;
 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;
@@ -147,6 +148,7 @@ public class ProjectBatch {
     @Override
     protected void configure() {
       addComponent(Phases.class);
+      addComponent(PhasesTimeProfiler.class);
       for (Class clazz : Phases.getPhaseClasses()) {
         addComponent(clazz);
       }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/events/DecoratorExecutionEvent.java b/sonar-batch/src/main/java/org/sonar/batch/events/DecoratorExecutionEvent.java
new file mode 100644 (file)
index 0000000..d55e3eb
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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;
+  }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/events/DecoratorExecutionHandler.java b/sonar-batch/src/main/java/org/sonar/batch/events/DecoratorExecutionHandler.java
new file mode 100644 (file)
index 0000000..3cf7af0
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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);
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/events/DecoratorsPhaseEvent.java b/sonar-batch/src/main/java/org/sonar/batch/events/DecoratorsPhaseEvent.java
new file mode 100644 (file)
index 0000000..34d9241
--- /dev/null
@@ -0,0 +1,42 @@
+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;
+  }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/events/DecoratorsPhaseHandler.java b/sonar-batch/src/main/java/org/sonar/batch/events/DecoratorsPhaseHandler.java
new file mode 100644 (file)
index 0000000..9c118e9
--- /dev/null
@@ -0,0 +1,7 @@
+package org.sonar.batch.events;
+
+public interface DecoratorsPhaseHandler extends EventHandler {
+
+  void onDecoratorsPhase(DecoratorsPhaseEvent event);
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/events/EventBus.java b/sonar-batch/src/main/java/org/sonar/batch/events/EventBus.java
new file mode 100644 (file)
index 0000000..b9aa8cf
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * 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;
+  }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/events/EventHandler.java b/sonar-batch/src/main/java/org/sonar/batch/events/EventHandler.java
new file mode 100644 (file)
index 0000000..55ed106
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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 {
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/events/SensorExecutionEvent.java b/sonar-batch/src/main/java/org/sonar/batch/events/SensorExecutionEvent.java
new file mode 100644 (file)
index 0000000..50ec165
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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;
+  }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/events/SensorExecutionHandler.java b/sonar-batch/src/main/java/org/sonar/batch/events/SensorExecutionHandler.java
new file mode 100644 (file)
index 0000000..8d33e28
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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);
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/events/SensorsPhaseEvent.java b/sonar-batch/src/main/java/org/sonar/batch/events/SensorsPhaseEvent.java
new file mode 100644 (file)
index 0000000..09ef80c
--- /dev/null
@@ -0,0 +1,38 @@
+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;
+  }
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/events/SensorsPhaseHandler.java b/sonar-batch/src/main/java/org/sonar/batch/events/SensorsPhaseHandler.java
new file mode 100644 (file)
index 0000000..256d24e
--- /dev/null
@@ -0,0 +1,7 @@
+package org.sonar.batch.events;
+
+public interface SensorsPhaseHandler extends EventHandler {
+
+  void onSensorsPhase(SensorsPhaseEvent event);
+
+}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/events/SonarEvent.java b/sonar-batch/src/main/java/org/sonar/batch/events/SonarEvent.java
new file mode 100644 (file)
index 0000000..9a544bd
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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();
+
+}
index aec3e77132420a91f4d30a903abd08c0cef93351..9c6bd0438340e5d69ac3648f163d8306d9b3c290 100644 (file)
@@ -19,6 +19,9 @@
  */
 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;
@@ -28,14 +31,17 @@ import org.sonar.api.database.model.MeasureData;
 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);
 
@@ -94,4 +100,24 @@ public class MemoryOptimizer {
   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();
+    }
+  }
+
 }
index a8f7e3ab862f1f387b2e4f5e50bd68e63ce7a1e4..9b294e8eb9023f8e3c367b86b3a5b443cdec42a4 100644 (file)
  */
 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;
@@ -33,99 +32,49 @@ import org.sonar.api.resources.Project;
 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();
-    }
-  }
 }
diff --git a/sonar-batch/src/main/java/org/sonar/batch/phases/PhasesTimeProfiler.java b/sonar-batch/src/main/java/org/sonar/batch/phases/PhasesTimeProfiler.java
new file mode 100644 (file)
index 0000000..07ceaba
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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();
+    }
+  }
+
+}
index e78a56f25c73c6702d19a17a1d8abf802e37393b..ba767cd0d401cae02aa29f014a606834d74b28c3 100644 (file)
@@ -19,7 +19,8 @@
  */
 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;
@@ -28,51 +29,45 @@ import org.sonar.api.batch.Sensor;
 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();
       }
diff --git a/sonar-batch/src/test/java/org/sonar/batch/events/EventBusTest.java b/sonar-batch/src/test/java/org/sonar/batch/events/EventBusTest.java
new file mode 100644 (file)
index 0000000..5817a80
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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;
+    }
+  }
+
+}
index 05cc65747039831b87c74f3d3e606ca052d9cac6..396ce2b4e36d5f655871f29a9c9c23d4a099e2d1 100644 (file)
  */
 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();