]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6261 Persist events in compute stack
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Fri, 13 Mar 2015 13:25:42 +0000 (14:25 +0100)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Tue, 17 Mar 2015 11:16:33 +0000 (12:16 +0100)
62 files changed:
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/events.html.erb
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/timeline.html.erb
server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistEventsStep.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java
server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrations.java
server/sonar-server/src/main/java/org/sonar/server/db/migrations/v52/FeedEventsComponentUuid.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/event/db/EventDao.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/event/db/package-info.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistEventsStepTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/event/db/EventDaoTest.java [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/add_events-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/add_version_event-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/empty.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/keep_one_event_by_version-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/keep_one_event_by_version.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/nothing_to_do_when_no_events_in_report.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/migrate-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/migrate.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/not_migrate_already_migrated_data.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/schema.sql [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/delete.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/empty.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/insert-result.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/shared.xml [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/api/events_controller.rb
server/sonar-web/src/main/webapp/WEB-INF/app/controllers/project_controller.rb
server/sonar-web/src/main/webapp/WEB-INF/app/models/event.rb
server/sonar-web/src/main/webapp/WEB-INF/app/models/project.rb
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/903_add_events_component_uuid.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/904_feed_events_component_uuid.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/905_remove_events_resource_id.rb [new file with mode: 0644]
sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/Constants.java
sonar-batch-protocol/src/main/gen-java/org/sonar/batch/protocol/output/BatchReport.java
sonar-batch-protocol/src/main/protobuf/batch_report.proto
sonar-batch-protocol/src/main/protobuf/constants.proto
sonar-batch/src/main/java/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersion.java
sonar-batch/src/main/java/org/sonar/batch/index/EventPersister.java
sonar-batch/src/test/resources/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersionTest/no-previous-version.xml
sonar-batch/src/test/resources/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersionTest/with-previous-version-deleted.xml
sonar-batch/src/test/resources/org/sonar/batch/deprecated/components/PastSnapshotFinderByPreviousVersionTest/with-previous-version.xml
sonar-core/src/main/java/org/sonar/core/event/EventDto.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/event/db/EventMapper.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/event/db/package-info.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/event/package-info.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
sonar-core/src/main/java/org/sonar/core/purge/PurgeCommands.java
sonar-core/src/main/java/org/sonar/core/purge/PurgeMapper.java
sonar-core/src/main/resources/org/sonar/core/event/db/EventMapper.xml [new file with mode: 0644]
sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
sonar-core/src/main/resources/org/sonar/core/persistence/schema-h2.ddl
sonar-core/src/main/resources/org/sonar/core/purge/PurgeMapper.xml
sonar-core/src/test/resources/org/sonar/core/persistence/PreviewDatabaseFactoryTest/should_create_database.xml
sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldDeleteResource.xml
sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldDeleteSnapshot-result.xml
sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldDeleteSnapshot.xml
sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldPurgeSnapshot-result.xml
sonar-core/src/test/resources/org/sonar/core/purge/PurgeCommandsTest/shouldPurgeSnapshot.xml
sonar-core/src/test/resources/org/sonar/core/purge/PurgeDaoTest/shouldSelectPurgeableSnapshots.xml
sonar-plugin-api/src/main/java/org/sonar/api/batch/Event.java
sonar-plugin-api/src/main/java/org/sonar/api/database/model/ResourceModel.java

index 9f0381f48cbf00ecb3242ef613dd6a98c300387b..d6be1d2e6671168ce153eff16dc4e61c50c4f7af 100644 (file)
@@ -1,8 +1,8 @@
 <% 
   if @resource.scope=='PRJ'
 
-    conditions = "resource_id=:resource_id"
-    values = {:resource_id => @resource.id}
+    conditions = "component_uuid=:component_uuid"
+    values = {:component_uuid => @resource.uuid}
     # in order to not display events linked to deleted snapshot, we build the SQL request with 'NOT IN' as most of the time, there won't be unprocessed snapshots
     snapshots_to_be_deleted = Snapshot.find(:all, :conditions => ["status='U' AND project_id=?", @resource.id])
     unless snapshots_to_be_deleted.empty?
index 55ce78fe4d6c9daf8fa37d4677961a62c69df854..7e7ad6ec44f266a7fe87d9ba53611b93bced8788 100644 (file)
            from_date = first_date if !from_date || from_date > first_date
          end
        end
-       Event.find(:all, :conditions => ["resource_id=? AND event_date>=?", @resource.id, from_date.to_i*1000], :order => 'event_date').each() do |event|
+       Event.find(:all, :conditions => ["component_uuid=? AND event_date>=?", @resource.uuid, from_date.to_i*1000], :order => 'event_date').each() do |event|
          if events[event.event_date]
            events[event.event_date] << event
          else
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistEventsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistEventsStep.java
new file mode 100644 (file)
index 0000000..97c678b
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.server.computation.step;
+
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.utils.System2;
+import org.sonar.batch.protocol.Constants;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.batch.protocol.output.BatchReportReader;
+import org.sonar.core.event.EventDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
+import org.sonar.server.computation.ComputationContext;
+import org.sonar.server.db.DbClient;
+
+import java.util.List;
+
+public class PersistEventsStep implements ComputationStep {
+
+  private final DbClient dbClient;
+  private final System2 system2;
+
+  public PersistEventsStep(DbClient dbClient, System2 system2) {
+    this.dbClient = dbClient;
+    this.system2 = system2;
+  }
+
+  @Override
+  public String[] supportedProjectQualifiers() {
+    return new String[] {Qualifiers.PROJECT};
+  }
+
+  @Override
+  public void execute(ComputationContext context) {
+    DbSession session = dbClient.openSession(false);
+    try {
+      int rootComponentRef = context.getReportMetadata().getRootComponentRef();
+      recursivelyProcessComponent(session, context, rootComponentRef);
+      session.commit();
+    } finally {
+      MyBatis.closeQuietly(session);
+    }
+  }
+
+  private void recursivelyProcessComponent(DbSession session, ComputationContext context, int componentRef) {
+    BatchReportReader reportReader = context.getReportReader();
+    BatchReport.Component component = reportReader.readComponent(componentRef);
+    processEvents(session, component, context.getReportMetadata().getAnalysisDate());
+    createVersionEvent(session, component, context.getReportMetadata().getAnalysisDate());
+
+    for (Integer childRef : component.getChildRefsList()) {
+      recursivelyProcessComponent(session, context, childRef);
+    }
+  }
+
+  private void processEvents(DbSession session, BatchReport.Component component, Long analysisDate) {
+    List<BatchReport.Event> events = component.getEventsList();
+    if (!events.isEmpty()) {
+      for (BatchReport.Event event : component.getEventsList()) {
+        dbClient.eventDao().insert(session, createBaseEvent(component, analysisDate)
+            .setName(event.getName())
+            .setCategory(convertCategory(event.getCategory()))
+            .setDescription(event.hasDescription() ? event.getDescription() : null)
+            .setData(event.hasEventData() ? event.getEventData() : null)
+          );
+      }
+    }
+  }
+
+  private void createVersionEvent(DbSession session, BatchReport.Component component, Long analysisDate) {
+    if (component.hasVersion()) {
+      deletePreviousEventsHavingSameVersion(session, component);
+      dbClient.eventDao().insert(session, createBaseEvent(component, analysisDate)
+          .setName(component.getVersion())
+          .setCategory(EventDto.CATEGORY_VERSION)
+        );
+    }
+  }
+
+  private void deletePreviousEventsHavingSameVersion(DbSession session, BatchReport.Component component){
+    for (EventDto dto : dbClient.eventDao().selectByComponentUuid(session, component.getUuid())) {
+      if (dto.getCategory().equals(EventDto.CATEGORY_VERSION) && dto.getName().equals(component.getVersion())) {
+        dbClient.eventDao().delete(session, dto.getId());
+      }
+    }
+  }
+
+  private EventDto createBaseEvent(BatchReport.Component component, Long analysisDate) {
+    return new EventDto()
+      .setComponentUuid(component.getUuid())
+      .setSnapshotId(component.getSnapshotId())
+      .setCreatedAt(system2.now())
+      .setDate(analysisDate);
+  }
+
+  private static String convertCategory(Constants.EventCategory category) {
+    switch (category) {
+      case ALERT:
+        return EventDto.CATEGORY_ALERT;
+      case PROFILE:
+        return EventDto.CATEGORY_PROFILE;
+      default:
+        throw new IllegalArgumentException(String.format("Unsupported category %s", category.name()));
+    }
+  }
+
+  @Override
+  public String getDescription() {
+    return "Persist component links";
+  }
+}
index 77cc92e3c27a079fd81f527248dbac380922f8b7..a0056e420647eb5fd4e9df94a9e276a072c25517 100644 (file)
@@ -43,6 +43,7 @@ import org.sonar.server.computation.db.AnalysisReportDao;
 import org.sonar.server.dashboard.db.DashboardDao;
 import org.sonar.server.dashboard.db.WidgetDao;
 import org.sonar.server.dashboard.db.WidgetPropertyDao;
+import org.sonar.server.event.db.EventDao;
 import org.sonar.server.issue.db.IssueDao;
 import org.sonar.server.measure.persistence.MeasureDao;
 import org.sonar.server.measure.persistence.MetricDao;
@@ -91,6 +92,7 @@ public class DbClient implements ServerComponent {
   private final AuthorDao authorDao;
   private final ComponentIndexDao componentIndexDao;
   private final ComponentLinkDao componentLinkDao;
+  private final EventDao eventDao;
 
   public DbClient(Database db, MyBatis myBatis, DaoComponent... daoComponents) {
     this.db = db;
@@ -126,6 +128,7 @@ public class DbClient implements ServerComponent {
     authorDao = getDao(map, AuthorDao.class);
     componentIndexDao = getDao(map, ComponentIndexDao.class);
     componentLinkDao = getDao(map, ComponentLinkDao.class);
+    eventDao = getDao(map, EventDao.class);
   }
 
   public Database database() {
@@ -240,6 +243,10 @@ public class DbClient implements ServerComponent {
     return componentLinkDao;
   }
 
+  public EventDao eventDao() {
+    return eventDao;
+  }
+
   private <K> K getDao(Map<Class, DaoComponent> map, Class<K> clazz) {
     return (K) map.get(clazz);
   }
index 86cffa68afd802472a96334bdac33fffcc878aee..dba501d891c55212bc334bd36d901cfa2209b49a 100644 (file)
@@ -31,6 +31,7 @@ import org.sonar.server.db.migrations.v451.AddMissingCustomRuleParametersMigrati
 import org.sonar.server.db.migrations.v451.DeleteUnescapedActivities;
 import org.sonar.server.db.migrations.v50.*;
 import org.sonar.server.db.migrations.v51.*;
+import org.sonar.server.db.migrations.v52.FeedEventsComponentUuid;
 import org.sonar.server.db.migrations.v52.FeedProjectLinksComponentUuid;
 
 import java.util.List;
@@ -97,6 +98,7 @@ public interface DatabaseMigrations {
     RemovePermissionsOnModulesMigration.class,
 
     // 5.2
-    FeedProjectLinksComponentUuid.class
+    FeedProjectLinksComponentUuid.class,
+    FeedEventsComponentUuid.class
     );
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v52/FeedEventsComponentUuid.java b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v52/FeedEventsComponentUuid.java
new file mode 100644 (file)
index 0000000..5e2c83d
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.server.db.migrations.v52;
+
+import org.sonar.core.persistence.Database;
+import org.sonar.server.db.migrations.BaseDataChange;
+import org.sonar.server.db.migrations.MassUpdate;
+import org.sonar.server.db.migrations.Select;
+import org.sonar.server.db.migrations.SqlStatement;
+
+import java.sql.SQLException;
+
+public class FeedEventsComponentUuid extends BaseDataChange {
+
+  public FeedEventsComponentUuid(Database db) {
+    super(db);
+  }
+
+  @Override
+  public void execute(Context context) throws SQLException {
+    MassUpdate update = context.prepareMassUpdate().rowPluralName("events");
+    update.select(
+      "SELECT p.uuid, event.id " +
+        "FROM events event " +
+        "INNER JOIN projects p ON p.id=event.resource_id " +
+        "WHERE event.component_uuid is null");
+    update.update("UPDATE events SET component_uuid=? WHERE id=?");
+    update.execute(new MassUpdate.Handler() {
+      @Override
+      public boolean handle(Select.Row row, SqlStatement update) throws SQLException {
+        update.setString(1, row.getString(1));
+        update.setLong(2, row.getLong(2));
+        return true;
+      }
+    });
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/event/db/EventDao.java b/server/sonar-server/src/main/java/org/sonar/server/event/db/EventDao.java
new file mode 100644 (file)
index 0000000..ef03a50
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.server.event.db;
+
+import org.sonar.api.ServerComponent;
+import org.sonar.core.event.EventDto;
+import org.sonar.core.event.db.EventMapper;
+import org.sonar.core.persistence.DaoComponent;
+import org.sonar.core.persistence.DbSession;
+
+import java.util.List;
+
+public class EventDao implements ServerComponent, DaoComponent {
+
+  public List<EventDto> selectByComponentUuid(DbSession session, String componentUuid) {
+    return session.getMapper(EventMapper.class).selectByComponentUuid(componentUuid);
+  }
+
+  public void insert(DbSession session, EventDto dto) {
+    session.getMapper(EventMapper.class).insert(dto);
+  }
+
+  public void delete(DbSession session, Long id) {
+    session.getMapper(EventMapper.class).delete(id);
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/event/db/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/event/db/package-info.java
new file mode 100644 (file)
index 0000000..b0e2602
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.server.event.db;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistEventsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistEventsStepTest.java
new file mode 100644 (file)
index 0000000..4224112
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.server.computation.step;
+
+import org.junit.*;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+import org.sonar.api.utils.System2;
+import org.sonar.batch.protocol.Constants;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.batch.protocol.output.BatchReportReader;
+import org.sonar.batch.protocol.output.BatchReportWriter;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.computation.ComputationContext;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.event.db.EventDao;
+import org.sonar.test.DbTests;
+
+import java.io.File;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@Category(DbTests.class)
+public class PersistEventsStepTest {
+
+  @Rule
+  public TemporaryFolder temp = new TemporaryFolder();
+
+  @ClassRule
+  public static DbTester dbTester = new DbTester();
+
+  DbSession session;
+
+  EventDao dao;
+
+  System2 system2;
+
+  PersistEventsStep step;
+
+  @Before
+  public void setup() throws Exception {
+    session = dbTester.myBatis().openSession(false);
+    dao = new EventDao();
+    DbClient dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), dao);
+
+    system2 = mock(System2.class);
+    when(system2.now()).thenReturn(1225630680000L);
+
+    step = new PersistEventsStep(dbClient, system2);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    session.close();
+  }
+
+  @Test
+  public void execute_only_on_projects() throws Exception {
+    assertThat(step.supportedProjectQualifiers()).containsOnly("TRK");
+  }
+
+  @Test
+  public void nothing_to_do_when_no_events_in_report() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "nothing_to_do_when_no_events_in_report.xml");
+
+    File reportDir = temp.newFolder();
+    BatchReportWriter writer = new BatchReportWriter(reportDir);
+    writer.writeMetadata(BatchReport.Metadata.newBuilder()
+      .setRootComponentRef(1)
+      .setProjectKey("PROJECT_KEY")
+      .setAnalysisDate(150000000L)
+      .build());
+
+    writer.writeComponent(BatchReport.Component.newBuilder()
+      .setRef(1)
+      .setType(Constants.ComponentType.PROJECT)
+      .setUuid("ABCD")
+      .build());
+
+    step.execute(new ComputationContext(new BatchReportReader(reportDir), mock(ComponentDto.class)));
+
+    dbTester.assertDbUnit(getClass(), "nothing_to_do_when_no_events_in_report.xml", "events");
+  }
+
+  @Test
+  public void persist_report_events() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "empty.xml");
+
+    File reportDir = temp.newFolder();
+    BatchReportWriter writer = new BatchReportWriter(reportDir);
+    writer.writeMetadata(BatchReport.Metadata.newBuilder()
+      .setRootComponentRef(1)
+      .setProjectKey("PROJECT_KEY")
+      .setAnalysisDate(150000000L)
+      .build());
+
+    writer.writeComponent(BatchReport.Component.newBuilder()
+      .setRef(1)
+      .setType(Constants.ComponentType.PROJECT)
+      .setUuid("ABCD")
+      .setSnapshotId(1000L)
+      .addEvents(BatchReport.Event.newBuilder()
+          .setName("Red (was Orange)")
+          .setCategory(Constants.EventCategory.ALERT)
+          .setDescription("Open issues > 0")
+          .build()
+      )
+      .addEvents(BatchReport.Event.newBuilder()
+          .setName("Changes in 'Default' (Java)")
+          .setCategory(Constants.EventCategory.PROFILE)
+          .setEventData("from=2014-10-12T08:36:25+0000;key=java-default;to=2014-10-12T10:36:25+0000")
+          .build()
+      )
+      .build());
+
+    step.execute(new ComputationContext(new BatchReportReader(reportDir), mock(ComponentDto.class)));
+
+    dbTester.assertDbUnit(getClass(), "add_events-result.xml", "events");
+  }
+
+  @Test
+  public void create_version_event() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "empty.xml");
+
+    File reportDir = temp.newFolder();
+    BatchReportWriter writer = new BatchReportWriter(reportDir);
+    writer.writeMetadata(BatchReport.Metadata.newBuilder()
+      .setRootComponentRef(1)
+      .setProjectKey("PROJECT_KEY")
+      .setAnalysisDate(150000000L)
+      .build());
+
+    writer.writeComponent(BatchReport.Component.newBuilder()
+      .setRef(1)
+      .setType(Constants.ComponentType.PROJECT)
+      .setUuid("ABCD")
+      .setSnapshotId(1000L)
+      .setVersion("1.0")
+      .build());
+
+    step.execute(new ComputationContext(new BatchReportReader(reportDir), mock(ComponentDto.class)));
+
+    dbTester.assertDbUnit(getClass(), "add_version_event-result.xml", "events");
+  }
+
+  @Test
+  public void keep_one_event_by_version() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "keep_one_event_by_version.xml");
+
+    File reportDir = temp.newFolder();
+    BatchReportWriter writer = new BatchReportWriter(reportDir);
+    writer.writeMetadata(BatchReport.Metadata.newBuilder()
+      .setRootComponentRef(1)
+      .setProjectKey("PROJECT_KEY")
+      .setAnalysisDate(150000000L)
+      .build());
+
+    writer.writeComponent(BatchReport.Component.newBuilder()
+      .setRef(1)
+      .setType(Constants.ComponentType.PROJECT)
+      .setUuid("ABCD")
+      .setSnapshotId(1001L)
+      .setVersion("1.5-SNAPSHOT")
+      .build());
+
+    step.execute(new ComputationContext(new BatchReportReader(reportDir), mock(ComponentDto.class)));
+
+    dbTester.assertDbUnit(getClass(), "keep_one_event_by_version-result.xml", "events");
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest.java b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest.java
new file mode 100644 (file)
index 0000000..2e13dbb
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.server.db.migrations.v52;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.db.migrations.DatabaseMigration;
+
+public class FeedEventsComponentUuidTest {
+
+  @ClassRule
+  public static DbTester db = new DbTester().schema(FeedEventsComponentUuidTest.class, "schema.sql");
+
+  DatabaseMigration migration;
+
+  @Before
+  public void setUp() throws Exception {
+    db.executeUpdateSql("truncate table events");
+    db.executeUpdateSql("truncate table projects");
+
+    migration = new FeedEventsComponentUuid(db.database());
+  }
+
+  @Test
+  public void migrate_empty_db() throws Exception {
+    migration.execute();
+  }
+
+  @Test
+  public void migrate() throws Exception {
+    db.prepareDbUnit(this.getClass(), "migrate.xml");
+    migration.execute();
+    db.assertDbUnit(this.getClass(), "migrate-result.xml", "events");
+  }
+
+  @Test
+  public void not_migrate_already_migrated_data() throws Exception {
+    db.prepareDbUnit(this.getClass(), "not_migrate_already_migrated_data.xml");
+    migration.execute();
+    db.assertDbUnit(this.getClass(), "not_migrate_already_migrated_data.xml", "events");
+  }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/event/db/EventDaoTest.java b/server/sonar-server/src/test/java/org/sonar/server/event/db/EventDaoTest.java
new file mode 100644 (file)
index 0000000..9dba34a
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.server.event.db;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.sonar.core.event.EventDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.test.DbTests;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+@Category(DbTests.class)
+public class EventDaoTest {
+
+  @ClassRule
+  public static DbTester dbTester = new DbTester();
+
+  DbSession session;
+
+  EventDao dao;
+
+  @Before
+  public void setup() throws Exception {
+    session = dbTester.myBatis().openSession(false);
+    dao = new EventDao();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    session.close();
+  }
+
+  @Test
+  public void select_by_component_uuid() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+
+    List<EventDto> dtos = dao.selectByComponentUuid(session, "ABCD");
+    assertThat(dtos).hasSize(3);
+
+    dtos = dao.selectByComponentUuid(session, "BCDE");
+    assertThat(dtos).hasSize(1);
+
+    EventDto dto = dtos.get(0);
+    assertThat(dto.getId()).isEqualTo(4L);
+    assertThat(dto.getComponentUuid()).isEqualTo("BCDE");
+    assertThat(dto.getSnapshotId()).isEqualTo(1000L);
+    assertThat(dto.getName()).isEqualTo("1.0");
+    assertThat(dto.getCategory()).isEqualTo("Version");
+    assertThat(dto.getDescription()).isEqualTo("Version 1.0");
+    assertThat(dto.getData()).isEqualTo("some data");
+    assertThat(dto.getDate()).isEqualTo(1413407091086L);
+    assertThat(dto.getCreatedAt()).isEqualTo(1225630680000L);
+  }
+
+  @Test
+  public void return_different_categories() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "shared.xml");
+
+    List<EventDto> dtos = dao.selectByComponentUuid(session, "ABCD");
+    assertThat(dtos).extracting("category").containsOnly(EventDto.CATEGORY_ALERT, EventDto.CATEGORY_PROFILE, EventDto.CATEGORY_VERSION);
+  }
+
+  @Test
+  public void insert() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "empty.xml");
+
+    dao.insert(session, new EventDto()
+      .setName("1.0")
+      .setCategory(EventDto.CATEGORY_VERSION)
+      .setDescription("Version 1.0")
+      .setData("some data")
+      .setDate(1413407091086L)
+      .setComponentUuid("ABCD")
+      .setSnapshotId(1000L)
+      .setCreatedAt(1225630680000L)
+      );
+    session.commit();
+
+    dbTester.assertDbUnit(getClass(), "insert-result.xml", "events");
+  }
+
+  @Test
+  public void delete() throws Exception {
+    dbTester.prepareDbUnit(getClass(), "delete.xml");
+
+    dao.delete(session, 1L);
+    session.commit();
+
+    assertThat(dbTester.countRowsOfTable("events")).isEqualTo(0);
+  }
+
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/add_events-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/add_events-result.xml
new file mode 100644 (file)
index 0000000..a1ba2c0
--- /dev/null
@@ -0,0 +1,10 @@
+<dataset>
+
+  <events id="1" name="Red (was Orange)" category="Alert" description="Open issues > 0"
+          event_data="[null]"
+          event_date="150000000" component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
+  <events id="2" name="Changes in 'Default' (Java)" category="Profile" description="[null]"
+          event_data="from=2014-10-12T08:36:25+0000;key=java-default;to=2014-10-12T10:36:25+0000"
+          event_date="150000000" component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/add_version_event-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/add_version_event-result.xml
new file mode 100644 (file)
index 0000000..458a042
--- /dev/null
@@ -0,0 +1,6 @@
+<dataset>
+
+  <events id="1" name="1.0" category="Version" description="[null]" event_data="[null]" event_date="150000000"
+          component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/empty.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/empty.xml
new file mode 100644 (file)
index 0000000..871dedc
--- /dev/null
@@ -0,0 +1,3 @@
+<dataset>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/keep_one_event_by_version-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/keep_one_event_by_version-result.xml
new file mode 100644 (file)
index 0000000..2a56e0c
--- /dev/null
@@ -0,0 +1,14 @@
+<dataset>
+
+  <events id="1" name="1.3-SNAPSHOT" category="Version" description="[null]" event_data="[null]" event_date="120000000"
+          component_uuid="ABCD" snapshot_id="1000" created_at="120000000" />
+  <events id="2" name="1.4" category="Version" description="[null]" event_data="[null]" event_date="130000000"
+          component_uuid="ABCD" snapshot_id="1000" created_at="130000000" />
+  <!-- Has been removed -->
+  <!--<events id="3" name="1.5-SNAPSHOT" category="Version" description="[null]" event_data="[null]" event_date="140000000"-->
+          <!--component_uuid="ABCD" snapshot_id="1000" created_at="140000000" />-->
+
+  <events id="4" name="1.5-SNAPSHOT" category="Version" description="[null]" event_data="[null]" event_date="150000000"
+          component_uuid="ABCD" snapshot_id="1001" created_at="1225630680000" />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/keep_one_event_by_version.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/keep_one_event_by_version.xml
new file mode 100644 (file)
index 0000000..44c19d1
--- /dev/null
@@ -0,0 +1,10 @@
+<dataset>
+
+  <events id="1" name="1.3-SNAPSHOT" category="Version" description="[null]" event_data="[null]" event_date="120000000"
+          component_uuid="ABCD" snapshot_id="1000" created_at="120000000" />
+  <events id="2" name="1.4" category="Version" description="[null]" event_data="[null]" event_date="130000000"
+          component_uuid="ABCD" snapshot_id="1000" created_at="130000000" />
+  <events id="3" name="1.5-SNAPSHOT" category="Version" description="[null]" event_data="[null]" event_date="140000000"
+          component_uuid="ABCD" snapshot_id="1000" created_at="140000000" />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/nothing_to_do_when_no_events_in_report.xml b/server/sonar-server/src/test/resources/org/sonar/server/computation/step/PersistEventsStepTest/nothing_to_do_when_no_events_in_report.xml
new file mode 100644 (file)
index 0000000..0002dee
--- /dev/null
@@ -0,0 +1,13 @@
+<dataset>
+
+  <events id="1" name="1.0" category="Version" description="Version 1.0" event_data="some data" event_date="1413407091086"
+          component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
+  <events id="2" name="Red (was Orange)" category="Alert" description="Critical issues variation > 0 since previous version (1.0 - 2015 Feb 09), Open issues > 0"
+          event_data="[null]" event_date="1413407091086" component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
+  <events id="3" name="Changes in 'Default' (Java)" category="Profile" description="Version 1.0" event_data="from=2014-10-12T08:36:25+0000;key=java-default;to=2014-10-12T10:36:25+0000"
+          event_date="1413407091086" component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
+
+  <events id="4" name="1.0" category="Version" description="Version 1.0" event_data="some data" event_date="1413407091086"
+          component_uuid="BCDE" snapshot_id="1000" created_at="1225630680000" />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/migrate-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/migrate-result.xml
new file mode 100644 (file)
index 0000000..ada195e
--- /dev/null
@@ -0,0 +1,5 @@
+<dataset>
+
+  <events id="1" name="1.0" resource_id="1" component_uuid="ABCD" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description="" event_data="[null]"/>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/migrate.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/migrate.xml
new file mode 100644 (file)
index 0000000..476fad9
--- /dev/null
@@ -0,0 +1,11 @@
+<dataset>
+
+  <projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts" deprecated_kee="org.struts:struts"
+            uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=""
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]"
+            created_at="2008-12-02 13:58:00.00" authorization_updated_at="[null]"/>
+
+  <events id="1" name="1.0" resource_id="1" component_uuid="[null]" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description="" event_data="[null]"/>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/not_migrate_already_migrated_data.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/not_migrate_already_migrated_data.xml
new file mode 100644 (file)
index 0000000..7c0d6df
--- /dev/null
@@ -0,0 +1,11 @@
+<dataset>
+
+  <projects id="1" root_id="[null]" scope="PRJ" qualifier="TRK" kee="org.struts:struts" name="Struts" deprecated_kee="org.struts:struts"
+            uuid="ABCD" project_uuid="ABCD" module_uuid="[null]" module_uuid_path=""
+            description="the description" long_name="Apache Struts"
+            enabled="[true]" language="[null]" copy_resource_id="[null]" person_id="[null]" path="[null]"
+            created_at="2008-12-02 13:58:00.00" authorization_updated_at="[null]"/>
+
+  <events id="1" name="1.0" resource_id="1" component_uuid="ABCD" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description="" event_data="[null]"/>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/schema.sql b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedEventsComponentUuidTest/schema.sql
new file mode 100644 (file)
index 0000000..e4ca540
--- /dev/null
@@ -0,0 +1,35 @@
+CREATE TABLE "PROJECTS" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "KEE" VARCHAR(400),
+  "ROOT_ID" INTEGER,
+  "UUID" VARCHAR(50),
+  "PROJECT_UUID" VARCHAR(50),
+  "MODULE_UUID" VARCHAR(50),
+  "MODULE_UUID_PATH" VARCHAR(4000),
+  "NAME" VARCHAR(256),
+  "DESCRIPTION" VARCHAR(2000),
+  "ENABLED" BOOLEAN NOT NULL DEFAULT TRUE,
+  "SCOPE" VARCHAR(3),
+  "QUALIFIER" VARCHAR(10),
+  "DEPRECATED_KEE" VARCHAR(400),
+  "PATH" VARCHAR(2000),
+  "LANGUAGE" VARCHAR(20),
+  "COPY_RESOURCE_ID" INTEGER,
+  "LONG_NAME" VARCHAR(256),
+  "PERSON_ID" INTEGER,
+  "CREATED_AT" TIMESTAMP,
+  "AUTHORIZATION_UPDATED_AT" BIGINT
+);
+
+CREATE TABLE "EVENTS" (
+  "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "NAME" VARCHAR(400),
+  "RESOURCE_ID" INTEGER,
+  "COMPONENT_UUID" VARCHAR(50),
+  "SNAPSHOT_ID" INTEGER,
+  "CATEGORY" VARCHAR(50),
+  "EVENT_DATE" BIGINT NOT NULL,
+  "CREATED_AT" BIGINT NOT NULL,
+  "DESCRIPTION" VARCHAR(4000),
+  "EVENT_DATA"  VARCHAR(4000)
+);
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/delete.xml b/server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/delete.xml
new file mode 100644 (file)
index 0000000..c22a68e
--- /dev/null
@@ -0,0 +1,6 @@
+<dataset>
+
+  <events id="1" name="1.0" category="Version" description="Version 1.0" event_data="some data" event_date="1225630680000"
+          component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/empty.xml b/server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/empty.xml
new file mode 100644 (file)
index 0000000..871dedc
--- /dev/null
@@ -0,0 +1,3 @@
+<dataset>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/insert-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/insert-result.xml
new file mode 100644 (file)
index 0000000..27a2a24
--- /dev/null
@@ -0,0 +1,6 @@
+<dataset>
+
+  <events id="1" name="1.0" category="Version" description="Version 1.0" event_data="some data" event_date="1413407091086"
+          component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/shared.xml b/server/sonar-server/src/test/resources/org/sonar/server/event/db/EventDaoTest/shared.xml
new file mode 100644 (file)
index 0000000..0002dee
--- /dev/null
@@ -0,0 +1,13 @@
+<dataset>
+
+  <events id="1" name="1.0" category="Version" description="Version 1.0" event_data="some data" event_date="1413407091086"
+          component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
+  <events id="2" name="Red (was Orange)" category="Alert" description="Critical issues variation > 0 since previous version (1.0 - 2015 Feb 09), Open issues > 0"
+          event_data="[null]" event_date="1413407091086" component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
+  <events id="3" name="Changes in 'Default' (Java)" category="Profile" description="Version 1.0" event_data="from=2014-10-12T08:36:25+0000;key=java-default;to=2014-10-12T10:36:25+0000"
+          event_date="1413407091086" component_uuid="ABCD" snapshot_id="1000" created_at="1225630680000" />
+
+  <events id="4" name="1.0" category="Version" description="Version 1.0" event_data="some data" event_date="1413407091086"
+          component_uuid="BCDE" snapshot_id="1000" created_at="1225630680000" />
+
+</dataset>
index e6d4696c397d8a7ca2ee8c41ec6e296a8ead64dc..44277d0885b79344d8641b004d3b821523f73aa0 100644 (file)
@@ -37,10 +37,10 @@ class Api::EventsController < Api::ApiController
       end
       
       if @resource
-        conditions<<'resource_id=:rid'
-        values[:rid]=@resource.id
+        conditions<<'component_uuid=:component_uuid'
+        values[:component_uuid]=@resource.uuid
       else
-        conditions<<'resource_id IS NULL'
+        conditions<<'component_uuid IS NULL'
       end
 
       from=nil
@@ -87,7 +87,7 @@ class Api::EventsController < Api::ApiController
   def show
     begin
       event=Event.find(params[:id])
-      load_resource(:user, event.resource_id)
+      load_resource_by_uuid(:user, event.component_uuid)
 
       respond_to do |format|
         format.json { render :json => jsonp(events_to_json([event])) }
@@ -144,7 +144,7 @@ class Api::EventsController < Api::ApiController
       name = params[:name]
       desc = params[:description]
       category = params[:category]
-      snapshots = Snapshot.find(:all, :include => 'events', :conditions => ["(root_snapshot_id = ? OR id = ?) AND scope = 'PRJ'", root_snapshot.id, root_snapshot.id])
+      snapshots = Snapshot.find(:all, :include => ['events', 'project'], :conditions => ["(root_snapshot_id = ? OR id = ?) AND scope = 'PRJ'", root_snapshot.id, root_snapshot.id])
       snapshots.each do |snapshot|
         # if this is a 'Version' event, must propagate the version number to the snapshot
         if category==EventCategory::KEY_VERSION
@@ -157,7 +157,7 @@ class Api::EventsController < Api::ApiController
           :description => desc,
           :category => category,
           :snapshot => snapshot,
-          :resource_id => snapshot.project_id,
+          :component_uuid => snapshot.project.uuid,
           :event_date => snapshot.created_at
         )
         event.save!
@@ -185,7 +185,7 @@ class Api::EventsController < Api::ApiController
   def destroy
     begin
       event=Event.find(params[:id])
-      load_resource(:admin, event.resource_id)
+      load_resource_by_uuid(:admin, event.component_uuid)
       
       events = []
       name = event.name
@@ -238,6 +238,24 @@ class Api::EventsController < Api::ApiController
     end
   end
 
+  def load_resource_by_uuid(required_resource_role, component_uuid=nil)
+    if component_uuid
+      @resource=Project.first(:conditions => {:uuid => component_uuid})
+      if @resource.nil?
+        raise ApiException.new 404, "Component uuid not found: #{component_uuid}"
+      end
+
+      unless has_role?(required_resource_role, @resource)
+        raise ApiException.new 401, "Unauthorized"
+      end
+    else
+      # global events
+      unless is_admin?
+        raise ApiException.new 401, "Unauthorized"
+      end
+    end
+  end
+
   def events_to_json(events=[])
     json=[]
     events.each do |event|
index 5bcc25b9c4e0f4f525f0c84c71c25cfc235880a5..8e3d9358012f8a20a0cf13972f054ce3db6559c0 100644 (file)
@@ -283,7 +283,7 @@ class ProjectController < ApplicationController
   end
 
   def update_version
-    snapshot=Snapshot.find(params[:sid])
+    snapshot=Snapshot.find(params[:sid], :include => 'project')
     not_found("Snapshot not found") unless snapshot
     access_denied unless is_admin?(snapshot)
 
@@ -307,7 +307,7 @@ class ProjectController < ApplicationController
           # We create an event for every concerned snapshot
           snapshots.each do |snapshot|
             event = Event.create!(:name => params[:version_name], :snapshot => snapshot,
-                                  :resource_id => snapshot.project_id, :category => EventCategory::KEY_VERSION,
+                                  :component_uuid => snapshot.project.uuid, :category => EventCategory::KEY_VERSION,
                                   :event_date => snapshot.created_at)
           end
           flash[:notice] = message('project_history.version_created', :params => params[:version_name])
@@ -359,7 +359,7 @@ class ProjectController < ApplicationController
         e = Event.new({:name => params[:event_name],
                        :category => EventCategory::KEY_OTHER,
                        :snapshot => s,
-                       :resource_id => s.project_id,
+                       :component_uuid => s.project.uuid,
                        :event_date => s.created_at})
         e.save!
       end
@@ -385,7 +385,7 @@ class ProjectController < ApplicationController
       flash[:notice] = message('project_history.event_updated')
     end
 
-    redirect_to :action => 'history', :id => event.resource_id
+    redirect_to :action => 'history', :id => event.resource.id
   end
 
   def delete_event
@@ -394,7 +394,7 @@ class ProjectController < ApplicationController
     access_denied unless is_admin?(event.resource)
 
     name = event.name
-    resource_id = event.resource_id
+    resource_id = event.resource.id
     events = find_events(event)
     Event.transaction do
       events.map { |e| e.id }.each_slice(999) do |safe_for_oracle_ids|
@@ -416,7 +416,7 @@ class ProjectController < ApplicationController
   end
 
   def find_project_snapshots(root_snapshot_id)
-    snapshots = Snapshot.find(:all, :include => 'events', :conditions => ["(root_snapshot_id = ? OR id = ?) AND scope = 'PRJ'", root_snapshot_id, root_snapshot_id])
+    Snapshot.find(:all, :include => ['events', 'project'], :conditions => ["(root_snapshot_id = ? OR id = ?) AND scope = 'PRJ'", root_snapshot_id, root_snapshot_id])
   end
 
   # Returns all an array that contains the given event + all the events that are the same, but which are attached on the submodules
index d5349ebaad34346b9f2437ad8243f25cb348a1da..01e4c8ef7f13739a6eb318bac163eaf50c9be775 100644 (file)
@@ -23,7 +23,7 @@ class Event < ActiveRecord::Base
   validates_length_of      :name, :within => 1..400
   validates_length_of      :category, :within => 1..50
 
-  belongs_to :resource, :class_name => 'Project', :foreign_key => 'resource_id'
+  belongs_to :resource, :class_name => 'Project', :foreign_key => 'component_uuid', :primary_key => 'uuid'
   belongs_to :snapshot
 
   before_save :populate_snapshot
index f8d83a5640b149d189d1f00ab41169c1203112fb..2c6c8b9cbf79a8c46183cf879ef3820a6f3dab20 100644 (file)
@@ -23,7 +23,7 @@ class Project < ActiveRecord::Base
 
   has_many :snapshots
   has_many :processed_snapshots, :class_name => 'Snapshot', :conditions => "status='#{Snapshot::STATUS_PROCESSED}' AND qualifier<>'LIB'", :order => 'created_at asc'
-  has_many :events, :foreign_key => 'resource_id', :order => 'event_date DESC'
+  has_many :events, :foreign_key => 'component_uuid', :primary_key => 'uuid', :order => 'event_date DESC'
   has_many :project_links, :foreign_key => 'component_uuid', :primary_key => 'uuid', :dependent => :delete_all, :order => 'link_type'
   has_many :user_roles, :foreign_key => 'resource_id'
   has_many :group_roles, :foreign_key => 'resource_id'
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/903_add_events_component_uuid.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/903_add_events_component_uuid.rb
new file mode 100644 (file)
index 0000000..e721acc
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 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.
+#
+
+#
+# SonarQube 5.2
+# SONAR-6261
+#
+class AddEventsComponentUuid < ActiveRecord::Migration
+
+  def self.up
+    add_column 'events', 'component_uuid', :string, :limit => 50
+    add_index 'events', 'component_uuid', :name => 'events_component_uuid'
+  end
+
+end
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/904_feed_events_component_uuid.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/904_feed_events_component_uuid.rb
new file mode 100644 (file)
index 0000000..fb840df
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 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.
+#
+
+#
+# SonarQube 5.2
+# SONAR-6261
+#
+class FeedEventsComponentUuid < ActiveRecord::Migration
+
+  def self.up
+    execute_java_migration('org.sonar.server.db.migrations.v52.FeedEventsComponentUuid')
+  end
+
+end
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/905_remove_events_resource_id.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/905_remove_events_resource_id.rb
new file mode 100644 (file)
index 0000000..ba3ff7f
--- /dev/null
@@ -0,0 +1,32 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 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.
+#
+
+#
+# SonarQube 5.2
+# SONAR-6261
+#
+class RemoveEventsResourceId < ActiveRecord::Migration
+
+  def self.up
+    remove_index 'events', :name => 'events_resource_id'
+    remove_column 'events', 'resource_id'
+  end
+
+end
index bb13257ef3e0ffd3cf325dc613499d111281d963..0c5b8965216146d39fcb1894755afba4001b8568 100644 (file)
@@ -235,6 +235,92 @@ public final class Constants {
     // @@protoc_insertion_point(enum_scope:ComponentType)
   }
 
+  /**
+   * Protobuf enum {@code EventCategory}
+   *
+   * <pre>
+   * temporary enum during development of computation stack
+   * </pre>
+   */
+  public enum EventCategory
+      implements com.google.protobuf.ProtocolMessageEnum {
+    /**
+     * <code>ALERT = 0;</code>
+     */
+    ALERT(0, 0),
+    /**
+     * <code>PROFILE = 1;</code>
+     */
+    PROFILE(1, 1),
+    ;
+
+    /**
+     * <code>ALERT = 0;</code>
+     */
+    public static final int ALERT_VALUE = 0;
+    /**
+     * <code>PROFILE = 1;</code>
+     */
+    public static final int PROFILE_VALUE = 1;
+
+
+    public final int getNumber() { return value; }
+
+    public static EventCategory valueOf(int value) {
+      switch (value) {
+        case 0: return ALERT;
+        case 1: return PROFILE;
+        default: return null;
+      }
+    }
+
+    public static com.google.protobuf.Internal.EnumLiteMap<EventCategory>
+        internalGetValueMap() {
+      return internalValueMap;
+    }
+    private static com.google.protobuf.Internal.EnumLiteMap<EventCategory>
+        internalValueMap =
+          new com.google.protobuf.Internal.EnumLiteMap<EventCategory>() {
+            public EventCategory findValueByNumber(int number) {
+              return EventCategory.valueOf(number);
+            }
+          };
+
+    public final com.google.protobuf.Descriptors.EnumValueDescriptor
+        getValueDescriptor() {
+      return getDescriptor().getValues().get(index);
+    }
+    public final com.google.protobuf.Descriptors.EnumDescriptor
+        getDescriptorForType() {
+      return getDescriptor();
+    }
+    public static final com.google.protobuf.Descriptors.EnumDescriptor
+        getDescriptor() {
+      return org.sonar.batch.protocol.Constants.getDescriptor().getEnumTypes().get(2);
+    }
+
+    private static final EventCategory[] VALUES = values();
+
+    public static EventCategory valueOf(
+        com.google.protobuf.Descriptors.EnumValueDescriptor desc) {
+      if (desc.getType() != getDescriptor()) {
+        throw new java.lang.IllegalArgumentException(
+          "EnumValueDescriptor is not for this type.");
+      }
+      return VALUES[desc.getIndex()];
+    }
+
+    private final int index;
+    private final int value;
+
+    private EventCategory(int index, int value) {
+      this.index = index;
+      this.value = value;
+    }
+
+    // @@protoc_insertion_point(enum_scope:EventCategory)
+  }
+
   /**
    * Protobuf enum {@code ComponentLinkType}
    */
@@ -319,7 +405,7 @@ public final class Constants {
     }
     public static final com.google.protobuf.Descriptors.EnumDescriptor
         getDescriptor() {
-      return org.sonar.batch.protocol.Constants.getDescriptor().getEnumTypes().get(2);
+      return org.sonar.batch.protocol.Constants.getDescriptor().getEnumTypes().get(3);
     }
 
     private static final ComponentLinkType[] VALUES = values();
@@ -357,9 +443,11 @@ public final class Constants {
       "\t\n\005MINOR\020\001\022\t\n\005MAJOR\020\002\022\014\n\010CRITICAL\020\003\022\013\n\007B" +
       "LOCKER\020\004*X\n\rComponentType\022\013\n\007PROJECT\020\000\022\n" +
       "\n\006MODULE\020\001\022\r\n\tDIRECTORY\020\002\022\010\n\004FILE\020\003\022\010\n\004V" +
-      "IEW\020\004\022\013\n\007SUBVIEW\020\005*F\n\021ComponentLinkType\022" +
-      "\010\n\004HOME\020\000\022\007\n\003SCM\020\001\022\013\n\007SCM_DEV\020\002\022\t\n\005ISSUE" +
-      "\020\003\022\006\n\002CI\020\004B\034\n\030org.sonar.batch.protocolH\001"
+      "IEW\020\004\022\013\n\007SUBVIEW\020\005*\'\n\rEventCategory\022\t\n\005A" +
+      "LERT\020\000\022\013\n\007PROFILE\020\001*F\n\021ComponentLinkType" +
+      "\022\010\n\004HOME\020\000\022\007\n\003SCM\020\001\022\013\n\007SCM_DEV\020\002\022\t\n\005ISSU" +
+      "E\020\003\022\006\n\002CI\020\004B\034\n\030org.sonar.batch.protocolH" +
+      "\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
       new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
index c544e6f356b8ead2bac78704023f1f1e6f883b49..19f233b6ebb73f80417ac8186b376aa0ac55021b 100644 (file)
@@ -1396,6 +1396,968 @@ public final class BatchReport {
     // @@protoc_insertion_point(class_scope:ComponentLink)
   }
 
+  public interface EventOrBuilder
+      extends com.google.protobuf.MessageOrBuilder {
+
+    // optional int32 component_ref = 1;
+    /**
+     * <code>optional int32 component_ref = 1;</code>
+     */
+    boolean hasComponentRef();
+    /**
+     * <code>optional int32 component_ref = 1;</code>
+     */
+    int getComponentRef();
+
+    // optional string name = 2;
+    /**
+     * <code>optional string name = 2;</code>
+     */
+    boolean hasName();
+    /**
+     * <code>optional string name = 2;</code>
+     */
+    java.lang.String getName();
+    /**
+     * <code>optional string name = 2;</code>
+     */
+    com.google.protobuf.ByteString
+        getNameBytes();
+
+    // optional string description = 3;
+    /**
+     * <code>optional string description = 3;</code>
+     */
+    boolean hasDescription();
+    /**
+     * <code>optional string description = 3;</code>
+     */
+    java.lang.String getDescription();
+    /**
+     * <code>optional string description = 3;</code>
+     */
+    com.google.protobuf.ByteString
+        getDescriptionBytes();
+
+    // optional .EventCategory category = 4;
+    /**
+     * <code>optional .EventCategory category = 4;</code>
+     */
+    boolean hasCategory();
+    /**
+     * <code>optional .EventCategory category = 4;</code>
+     */
+    org.sonar.batch.protocol.Constants.EventCategory getCategory();
+
+    // optional string event_data = 5;
+    /**
+     * <code>optional string event_data = 5;</code>
+     */
+    boolean hasEventData();
+    /**
+     * <code>optional string event_data = 5;</code>
+     */
+    java.lang.String getEventData();
+    /**
+     * <code>optional string event_data = 5;</code>
+     */
+    com.google.protobuf.ByteString
+        getEventDataBytes();
+  }
+  /**
+   * Protobuf type {@code Event}
+   *
+   * <pre>
+   * temporary message during development of computation stack
+   * </pre>
+   */
+  public static final class Event extends
+      com.google.protobuf.GeneratedMessage
+      implements EventOrBuilder {
+    // Use Event.newBuilder() to construct.
+    private Event(com.google.protobuf.GeneratedMessage.Builder<?> builder) {
+      super(builder);
+      this.unknownFields = builder.getUnknownFields();
+    }
+    private Event(boolean noInit) { this.unknownFields = com.google.protobuf.UnknownFieldSet.getDefaultInstance(); }
+
+    private static final Event defaultInstance;
+    public static Event getDefaultInstance() {
+      return defaultInstance;
+    }
+
+    public Event getDefaultInstanceForType() {
+      return defaultInstance;
+    }
+
+    private final com.google.protobuf.UnknownFieldSet unknownFields;
+    @java.lang.Override
+    public final com.google.protobuf.UnknownFieldSet
+        getUnknownFields() {
+      return this.unknownFields;
+    }
+    private Event(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      initFields();
+      int mutable_bitField0_ = 0;
+      com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+          com.google.protobuf.UnknownFieldSet.newBuilder();
+      try {
+        boolean done = false;
+        while (!done) {
+          int tag = input.readTag();
+          switch (tag) {
+            case 0:
+              done = true;
+              break;
+            default: {
+              if (!parseUnknownField(input, unknownFields,
+                                     extensionRegistry, tag)) {
+                done = true;
+              }
+              break;
+            }
+            case 8: {
+              bitField0_ |= 0x00000001;
+              componentRef_ = input.readInt32();
+              break;
+            }
+            case 18: {
+              bitField0_ |= 0x00000002;
+              name_ = input.readBytes();
+              break;
+            }
+            case 26: {
+              bitField0_ |= 0x00000004;
+              description_ = input.readBytes();
+              break;
+            }
+            case 32: {
+              int rawValue = input.readEnum();
+              org.sonar.batch.protocol.Constants.EventCategory value = org.sonar.batch.protocol.Constants.EventCategory.valueOf(rawValue);
+              if (value == null) {
+                unknownFields.mergeVarintField(4, rawValue);
+              } else {
+                bitField0_ |= 0x00000008;
+                category_ = value;
+              }
+              break;
+            }
+            case 42: {
+              bitField0_ |= 0x00000010;
+              eventData_ = input.readBytes();
+              break;
+            }
+          }
+        }
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        throw e.setUnfinishedMessage(this);
+      } catch (java.io.IOException e) {
+        throw new com.google.protobuf.InvalidProtocolBufferException(
+            e.getMessage()).setUnfinishedMessage(this);
+      } finally {
+        this.unknownFields = unknownFields.build();
+        makeExtensionsImmutable();
+      }
+    }
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return org.sonar.batch.protocol.output.BatchReport.internal_static_Event_descriptor;
+    }
+
+    protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return org.sonar.batch.protocol.output.BatchReport.internal_static_Event_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              org.sonar.batch.protocol.output.BatchReport.Event.class, org.sonar.batch.protocol.output.BatchReport.Event.Builder.class);
+    }
+
+    public static com.google.protobuf.Parser<Event> PARSER =
+        new com.google.protobuf.AbstractParser<Event>() {
+      public Event parsePartialFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws com.google.protobuf.InvalidProtocolBufferException {
+        return new Event(input, extensionRegistry);
+      }
+    };
+
+    @java.lang.Override
+    public com.google.protobuf.Parser<Event> getParserForType() {
+      return PARSER;
+    }
+
+    private int bitField0_;
+    // optional int32 component_ref = 1;
+    public static final int COMPONENT_REF_FIELD_NUMBER = 1;
+    private int componentRef_;
+    /**
+     * <code>optional int32 component_ref = 1;</code>
+     */
+    public boolean hasComponentRef() {
+      return ((bitField0_ & 0x00000001) == 0x00000001);
+    }
+    /**
+     * <code>optional int32 component_ref = 1;</code>
+     */
+    public int getComponentRef() {
+      return componentRef_;
+    }
+
+    // optional string name = 2;
+    public static final int NAME_FIELD_NUMBER = 2;
+    private java.lang.Object name_;
+    /**
+     * <code>optional string name = 2;</code>
+     */
+    public boolean hasName() {
+      return ((bitField0_ & 0x00000002) == 0x00000002);
+    }
+    /**
+     * <code>optional string name = 2;</code>
+     */
+    public java.lang.String getName() {
+      java.lang.Object ref = name_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          name_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string name = 2;</code>
+     */
+    public com.google.protobuf.ByteString
+        getNameBytes() {
+      java.lang.Object ref = name_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        name_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    // optional string description = 3;
+    public static final int DESCRIPTION_FIELD_NUMBER = 3;
+    private java.lang.Object description_;
+    /**
+     * <code>optional string description = 3;</code>
+     */
+    public boolean hasDescription() {
+      return ((bitField0_ & 0x00000004) == 0x00000004);
+    }
+    /**
+     * <code>optional string description = 3;</code>
+     */
+    public java.lang.String getDescription() {
+      java.lang.Object ref = description_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          description_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string description = 3;</code>
+     */
+    public com.google.protobuf.ByteString
+        getDescriptionBytes() {
+      java.lang.Object ref = description_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        description_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    // optional .EventCategory category = 4;
+    public static final int CATEGORY_FIELD_NUMBER = 4;
+    private org.sonar.batch.protocol.Constants.EventCategory category_;
+    /**
+     * <code>optional .EventCategory category = 4;</code>
+     */
+    public boolean hasCategory() {
+      return ((bitField0_ & 0x00000008) == 0x00000008);
+    }
+    /**
+     * <code>optional .EventCategory category = 4;</code>
+     */
+    public org.sonar.batch.protocol.Constants.EventCategory getCategory() {
+      return category_;
+    }
+
+    // optional string event_data = 5;
+    public static final int EVENT_DATA_FIELD_NUMBER = 5;
+    private java.lang.Object eventData_;
+    /**
+     * <code>optional string event_data = 5;</code>
+     */
+    public boolean hasEventData() {
+      return ((bitField0_ & 0x00000010) == 0x00000010);
+    }
+    /**
+     * <code>optional string event_data = 5;</code>
+     */
+    public java.lang.String getEventData() {
+      java.lang.Object ref = eventData_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          eventData_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string event_data = 5;</code>
+     */
+    public com.google.protobuf.ByteString
+        getEventDataBytes() {
+      java.lang.Object ref = eventData_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        eventData_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    private void initFields() {
+      componentRef_ = 0;
+      name_ = "";
+      description_ = "";
+      category_ = org.sonar.batch.protocol.Constants.EventCategory.ALERT;
+      eventData_ = "";
+    }
+    private byte memoizedIsInitialized = -1;
+    public final boolean isInitialized() {
+      byte isInitialized = memoizedIsInitialized;
+      if (isInitialized != -1) return isInitialized == 1;
+
+      memoizedIsInitialized = 1;
+      return true;
+    }
+
+    public void writeTo(com.google.protobuf.CodedOutputStream output)
+                        throws java.io.IOException {
+      getSerializedSize();
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        output.writeInt32(1, componentRef_);
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        output.writeBytes(2, getNameBytes());
+      }
+      if (((bitField0_ & 0x00000004) == 0x00000004)) {
+        output.writeBytes(3, getDescriptionBytes());
+      }
+      if (((bitField0_ & 0x00000008) == 0x00000008)) {
+        output.writeEnum(4, category_.getNumber());
+      }
+      if (((bitField0_ & 0x00000010) == 0x00000010)) {
+        output.writeBytes(5, getEventDataBytes());
+      }
+      getUnknownFields().writeTo(output);
+    }
+
+    private int memoizedSerializedSize = -1;
+    public int getSerializedSize() {
+      int size = memoizedSerializedSize;
+      if (size != -1) return size;
+
+      size = 0;
+      if (((bitField0_ & 0x00000001) == 0x00000001)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt32Size(1, componentRef_);
+      }
+      if (((bitField0_ & 0x00000002) == 0x00000002)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(2, getNameBytes());
+      }
+      if (((bitField0_ & 0x00000004) == 0x00000004)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(3, getDescriptionBytes());
+      }
+      if (((bitField0_ & 0x00000008) == 0x00000008)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeEnumSize(4, category_.getNumber());
+      }
+      if (((bitField0_ & 0x00000010) == 0x00000010)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(5, getEventDataBytes());
+      }
+      size += getUnknownFields().getSerializedSize();
+      memoizedSerializedSize = size;
+      return size;
+    }
+
+    private static final long serialVersionUID = 0L;
+    @java.lang.Override
+    protected java.lang.Object writeReplace()
+        throws java.io.ObjectStreamException {
+      return super.writeReplace();
+    }
+
+    public static org.sonar.batch.protocol.output.BatchReport.Event parseFrom(
+        com.google.protobuf.ByteString data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.Event parseFrom(
+        com.google.protobuf.ByteString data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.Event parseFrom(byte[] data)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.Event parseFrom(
+        byte[] data,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return PARSER.parseFrom(data, extensionRegistry);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.Event parseFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.Event parseFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.Event parseDelimitedFrom(java.io.InputStream input)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.Event parseDelimitedFrom(
+        java.io.InputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseDelimitedFrom(input, extensionRegistry);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.Event parseFrom(
+        com.google.protobuf.CodedInputStream input)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input);
+    }
+    public static org.sonar.batch.protocol.output.BatchReport.Event parseFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      return PARSER.parseFrom(input, extensionRegistry);
+    }
+
+    public static Builder newBuilder() { return Builder.create(); }
+    public Builder newBuilderForType() { return newBuilder(); }
+    public static Builder newBuilder(org.sonar.batch.protocol.output.BatchReport.Event prototype) {
+      return newBuilder().mergeFrom(prototype);
+    }
+    public Builder toBuilder() { return newBuilder(this); }
+
+    @java.lang.Override
+    protected Builder newBuilderForType(
+        com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+      Builder builder = new Builder(parent);
+      return builder;
+    }
+    /**
+     * Protobuf type {@code Event}
+     *
+     * <pre>
+     * temporary message during development of computation stack
+     * </pre>
+     */
+    public static final class Builder extends
+        com.google.protobuf.GeneratedMessage.Builder<Builder>
+       implements org.sonar.batch.protocol.output.BatchReport.EventOrBuilder {
+      public static final com.google.protobuf.Descriptors.Descriptor
+          getDescriptor() {
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_Event_descriptor;
+      }
+
+      protected com.google.protobuf.GeneratedMessage.FieldAccessorTable
+          internalGetFieldAccessorTable() {
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_Event_fieldAccessorTable
+            .ensureFieldAccessorsInitialized(
+                org.sonar.batch.protocol.output.BatchReport.Event.class, org.sonar.batch.protocol.output.BatchReport.Event.Builder.class);
+      }
+
+      // Construct using org.sonar.batch.protocol.output.BatchReport.Event.newBuilder()
+      private Builder() {
+        maybeForceBuilderInitialization();
+      }
+
+      private Builder(
+          com.google.protobuf.GeneratedMessage.BuilderParent parent) {
+        super(parent);
+        maybeForceBuilderInitialization();
+      }
+      private void maybeForceBuilderInitialization() {
+        if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
+        }
+      }
+      private static Builder create() {
+        return new Builder();
+      }
+
+      public Builder clear() {
+        super.clear();
+        componentRef_ = 0;
+        bitField0_ = (bitField0_ & ~0x00000001);
+        name_ = "";
+        bitField0_ = (bitField0_ & ~0x00000002);
+        description_ = "";
+        bitField0_ = (bitField0_ & ~0x00000004);
+        category_ = org.sonar.batch.protocol.Constants.EventCategory.ALERT;
+        bitField0_ = (bitField0_ & ~0x00000008);
+        eventData_ = "";
+        bitField0_ = (bitField0_ & ~0x00000010);
+        return this;
+      }
+
+      public Builder clone() {
+        return create().mergeFrom(buildPartial());
+      }
+
+      public com.google.protobuf.Descriptors.Descriptor
+          getDescriptorForType() {
+        return org.sonar.batch.protocol.output.BatchReport.internal_static_Event_descriptor;
+      }
+
+      public org.sonar.batch.protocol.output.BatchReport.Event getDefaultInstanceForType() {
+        return org.sonar.batch.protocol.output.BatchReport.Event.getDefaultInstance();
+      }
+
+      public org.sonar.batch.protocol.output.BatchReport.Event build() {
+        org.sonar.batch.protocol.output.BatchReport.Event result = buildPartial();
+        if (!result.isInitialized()) {
+          throw newUninitializedMessageException(result);
+        }
+        return result;
+      }
+
+      public org.sonar.batch.protocol.output.BatchReport.Event buildPartial() {
+        org.sonar.batch.protocol.output.BatchReport.Event result = new org.sonar.batch.protocol.output.BatchReport.Event(this);
+        int from_bitField0_ = bitField0_;
+        int to_bitField0_ = 0;
+        if (((from_bitField0_ & 0x00000001) == 0x00000001)) {
+          to_bitField0_ |= 0x00000001;
+        }
+        result.componentRef_ = componentRef_;
+        if (((from_bitField0_ & 0x00000002) == 0x00000002)) {
+          to_bitField0_ |= 0x00000002;
+        }
+        result.name_ = name_;
+        if (((from_bitField0_ & 0x00000004) == 0x00000004)) {
+          to_bitField0_ |= 0x00000004;
+        }
+        result.description_ = description_;
+        if (((from_bitField0_ & 0x00000008) == 0x00000008)) {
+          to_bitField0_ |= 0x00000008;
+        }
+        result.category_ = category_;
+        if (((from_bitField0_ & 0x00000010) == 0x00000010)) {
+          to_bitField0_ |= 0x00000010;
+        }
+        result.eventData_ = eventData_;
+        result.bitField0_ = to_bitField0_;
+        onBuilt();
+        return result;
+      }
+
+      public Builder mergeFrom(com.google.protobuf.Message other) {
+        if (other instanceof org.sonar.batch.protocol.output.BatchReport.Event) {
+          return mergeFrom((org.sonar.batch.protocol.output.BatchReport.Event)other);
+        } else {
+          super.mergeFrom(other);
+          return this;
+        }
+      }
+
+      public Builder mergeFrom(org.sonar.batch.protocol.output.BatchReport.Event other) {
+        if (other == org.sonar.batch.protocol.output.BatchReport.Event.getDefaultInstance()) return this;
+        if (other.hasComponentRef()) {
+          setComponentRef(other.getComponentRef());
+        }
+        if (other.hasName()) {
+          bitField0_ |= 0x00000002;
+          name_ = other.name_;
+          onChanged();
+        }
+        if (other.hasDescription()) {
+          bitField0_ |= 0x00000004;
+          description_ = other.description_;
+          onChanged();
+        }
+        if (other.hasCategory()) {
+          setCategory(other.getCategory());
+        }
+        if (other.hasEventData()) {
+          bitField0_ |= 0x00000010;
+          eventData_ = other.eventData_;
+          onChanged();
+        }
+        this.mergeUnknownFields(other.getUnknownFields());
+        return this;
+      }
+
+      public final boolean isInitialized() {
+        return true;
+      }
+
+      public Builder mergeFrom(
+          com.google.protobuf.CodedInputStream input,
+          com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+          throws java.io.IOException {
+        org.sonar.batch.protocol.output.BatchReport.Event parsedMessage = null;
+        try {
+          parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+        } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+          parsedMessage = (org.sonar.batch.protocol.output.BatchReport.Event) e.getUnfinishedMessage();
+          throw e;
+        } finally {
+          if (parsedMessage != null) {
+            mergeFrom(parsedMessage);
+          }
+        }
+        return this;
+      }
+      private int bitField0_;
+
+      // optional int32 component_ref = 1;
+      private int componentRef_ ;
+      /**
+       * <code>optional int32 component_ref = 1;</code>
+       */
+      public boolean hasComponentRef() {
+        return ((bitField0_ & 0x00000001) == 0x00000001);
+      }
+      /**
+       * <code>optional int32 component_ref = 1;</code>
+       */
+      public int getComponentRef() {
+        return componentRef_;
+      }
+      /**
+       * <code>optional int32 component_ref = 1;</code>
+       */
+      public Builder setComponentRef(int value) {
+        bitField0_ |= 0x00000001;
+        componentRef_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional int32 component_ref = 1;</code>
+       */
+      public Builder clearComponentRef() {
+        bitField0_ = (bitField0_ & ~0x00000001);
+        componentRef_ = 0;
+        onChanged();
+        return this;
+      }
+
+      // optional string name = 2;
+      private java.lang.Object name_ = "";
+      /**
+       * <code>optional string name = 2;</code>
+       */
+      public boolean hasName() {
+        return ((bitField0_ & 0x00000002) == 0x00000002);
+      }
+      /**
+       * <code>optional string name = 2;</code>
+       */
+      public java.lang.String getName() {
+        java.lang.Object ref = name_;
+        if (!(ref instanceof java.lang.String)) {
+          java.lang.String s = ((com.google.protobuf.ByteString) ref)
+              .toStringUtf8();
+          name_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string name = 2;</code>
+       */
+      public com.google.protobuf.ByteString
+          getNameBytes() {
+        java.lang.Object ref = name_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          name_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string name = 2;</code>
+       */
+      public Builder setName(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000002;
+        name_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string name = 2;</code>
+       */
+      public Builder clearName() {
+        bitField0_ = (bitField0_ & ~0x00000002);
+        name_ = getDefaultInstance().getName();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string name = 2;</code>
+       */
+      public Builder setNameBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000002;
+        name_ = value;
+        onChanged();
+        return this;
+      }
+
+      // optional string description = 3;
+      private java.lang.Object description_ = "";
+      /**
+       * <code>optional string description = 3;</code>
+       */
+      public boolean hasDescription() {
+        return ((bitField0_ & 0x00000004) == 0x00000004);
+      }
+      /**
+       * <code>optional string description = 3;</code>
+       */
+      public java.lang.String getDescription() {
+        java.lang.Object ref = description_;
+        if (!(ref instanceof java.lang.String)) {
+          java.lang.String s = ((com.google.protobuf.ByteString) ref)
+              .toStringUtf8();
+          description_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string description = 3;</code>
+       */
+      public com.google.protobuf.ByteString
+          getDescriptionBytes() {
+        java.lang.Object ref = description_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          description_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string description = 3;</code>
+       */
+      public Builder setDescription(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000004;
+        description_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string description = 3;</code>
+       */
+      public Builder clearDescription() {
+        bitField0_ = (bitField0_ & ~0x00000004);
+        description_ = getDefaultInstance().getDescription();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string description = 3;</code>
+       */
+      public Builder setDescriptionBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000004;
+        description_ = value;
+        onChanged();
+        return this;
+      }
+
+      // optional .EventCategory category = 4;
+      private org.sonar.batch.protocol.Constants.EventCategory category_ = org.sonar.batch.protocol.Constants.EventCategory.ALERT;
+      /**
+       * <code>optional .EventCategory category = 4;</code>
+       */
+      public boolean hasCategory() {
+        return ((bitField0_ & 0x00000008) == 0x00000008);
+      }
+      /**
+       * <code>optional .EventCategory category = 4;</code>
+       */
+      public org.sonar.batch.protocol.Constants.EventCategory getCategory() {
+        return category_;
+      }
+      /**
+       * <code>optional .EventCategory category = 4;</code>
+       */
+      public Builder setCategory(org.sonar.batch.protocol.Constants.EventCategory value) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        bitField0_ |= 0x00000008;
+        category_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional .EventCategory category = 4;</code>
+       */
+      public Builder clearCategory() {
+        bitField0_ = (bitField0_ & ~0x00000008);
+        category_ = org.sonar.batch.protocol.Constants.EventCategory.ALERT;
+        onChanged();
+        return this;
+      }
+
+      // optional string event_data = 5;
+      private java.lang.Object eventData_ = "";
+      /**
+       * <code>optional string event_data = 5;</code>
+       */
+      public boolean hasEventData() {
+        return ((bitField0_ & 0x00000010) == 0x00000010);
+      }
+      /**
+       * <code>optional string event_data = 5;</code>
+       */
+      public java.lang.String getEventData() {
+        java.lang.Object ref = eventData_;
+        if (!(ref instanceof java.lang.String)) {
+          java.lang.String s = ((com.google.protobuf.ByteString) ref)
+              .toStringUtf8();
+          eventData_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string event_data = 5;</code>
+       */
+      public com.google.protobuf.ByteString
+          getEventDataBytes() {
+        java.lang.Object ref = eventData_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          eventData_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string event_data = 5;</code>
+       */
+      public Builder setEventData(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000010;
+        eventData_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string event_data = 5;</code>
+       */
+      public Builder clearEventData() {
+        bitField0_ = (bitField0_ & ~0x00000010);
+        eventData_ = getDefaultInstance().getEventData();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string event_data = 5;</code>
+       */
+      public Builder setEventDataBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000010;
+        eventData_ = value;
+        onChanged();
+        return this;
+      }
+
+      // @@protoc_insertion_point(builder_scope:Event)
+    }
+
+    static {
+      defaultInstance = new Event(true);
+      defaultInstance.initFields();
+    }
+
+    // @@protoc_insertion_point(class_scope:Event)
+  }
+
   public interface ComponentOrBuilder
       extends com.google.protobuf.MessageOrBuilder {
 
@@ -1513,9 +2475,36 @@ public final class BatchReport {
     org.sonar.batch.protocol.output.BatchReport.ComponentLinkOrBuilder getLinkOrBuilder(
         int index);
 
-    // optional int32 snapshot_id = 8;
+    // optional string version = 12;
+    /**
+     * <code>optional string version = 12;</code>
+     *
+     * <pre>
+     * Only available on PROJECT and MODULE type
+     * </pre>
+     */
+    boolean hasVersion();
+    /**
+     * <code>optional string version = 12;</code>
+     *
+     * <pre>
+     * Only available on PROJECT and MODULE type
+     * </pre>
+     */
+    java.lang.String getVersion();
+    /**
+     * <code>optional string version = 12;</code>
+     *
+     * <pre>
+     * Only available on PROJECT and MODULE type
+     * </pre>
+     */
+    com.google.protobuf.ByteString
+        getVersionBytes();
+
+    // optional int64 snapshot_id = 8;
     /**
-     * <code>optional int32 snapshot_id = 8;</code>
+     * <code>optional int64 snapshot_id = 8;</code>
      *
      * <pre>
      * temporary fields during development of computation stack
@@ -1523,13 +2512,13 @@ public final class BatchReport {
      */
     boolean hasSnapshotId();
     /**
-     * <code>optional int32 snapshot_id = 8;</code>
+     * <code>optional int64 snapshot_id = 8;</code>
      *
      * <pre>
      * temporary fields during development of computation stack
      * </pre>
      */
-    int getSnapshotId();
+    long getSnapshotId();
 
     // optional string uuid = 9;
     /**
@@ -1545,6 +2534,31 @@ public final class BatchReport {
      */
     com.google.protobuf.ByteString
         getUuidBytes();
+
+    // repeated .Event events = 11;
+    /**
+     * <code>repeated .Event events = 11;</code>
+     */
+    java.util.List<org.sonar.batch.protocol.output.BatchReport.Event> 
+        getEventsList();
+    /**
+     * <code>repeated .Event events = 11;</code>
+     */
+    org.sonar.batch.protocol.output.BatchReport.Event getEvents(int index);
+    /**
+     * <code>repeated .Event events = 11;</code>
+     */
+    int getEventsCount();
+    /**
+     * <code>repeated .Event events = 11;</code>
+     */
+    java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.EventOrBuilder> 
+        getEventsOrBuilderList();
+    /**
+     * <code>repeated .Event events = 11;</code>
+     */
+    org.sonar.batch.protocol.output.BatchReport.EventOrBuilder getEventsOrBuilder(
+        int index);
   }
   /**
    * Protobuf type {@code Component}
@@ -1655,12 +2669,12 @@ public final class BatchReport {
               break;
             }
             case 64: {
-              bitField0_ |= 0x00000040;
-              snapshotId_ = input.readInt32();
+              bitField0_ |= 0x00000080;
+              snapshotId_ = input.readInt64();
               break;
             }
             case 74: {
-              bitField0_ |= 0x00000080;
+              bitField0_ |= 0x00000100;
               uuid_ = input.readBytes();
               break;
             }
@@ -1672,6 +2686,19 @@ public final class BatchReport {
               link_.add(input.readMessage(org.sonar.batch.protocol.output.BatchReport.ComponentLink.PARSER, extensionRegistry));
               break;
             }
+            case 90: {
+              if (!((mutable_bitField0_ & 0x00000800) == 0x00000800)) {
+                events_ = new java.util.ArrayList<org.sonar.batch.protocol.output.BatchReport.Event>();
+                mutable_bitField0_ |= 0x00000800;
+              }
+              events_.add(input.readMessage(org.sonar.batch.protocol.output.BatchReport.Event.PARSER, extensionRegistry));
+              break;
+            }
+            case 98: {
+              bitField0_ |= 0x00000040;
+              version_ = input.readBytes();
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -1686,6 +2713,9 @@ public final class BatchReport {
         if (((mutable_bitField0_ & 0x00000080) == 0x00000080)) {
           link_ = java.util.Collections.unmodifiableList(link_);
         }
+        if (((mutable_bitField0_ & 0x00000800) == 0x00000800)) {
+          events_ = java.util.Collections.unmodifiableList(events_);
+        }
         this.unknownFields = unknownFields.build();
         makeExtensionsImmutable();
       }
@@ -1955,27 +2985,82 @@ public final class BatchReport {
       return link_.get(index);
     }
 
-    // optional int32 snapshot_id = 8;
+    // optional string version = 12;
+    public static final int VERSION_FIELD_NUMBER = 12;
+    private java.lang.Object version_;
+    /**
+     * <code>optional string version = 12;</code>
+     *
+     * <pre>
+     * Only available on PROJECT and MODULE type
+     * </pre>
+     */
+    public boolean hasVersion() {
+      return ((bitField0_ & 0x00000040) == 0x00000040);
+    }
+    /**
+     * <code>optional string version = 12;</code>
+     *
+     * <pre>
+     * Only available on PROJECT and MODULE type
+     * </pre>
+     */
+    public java.lang.String getVersion() {
+      java.lang.Object ref = version_;
+      if (ref instanceof java.lang.String) {
+        return (java.lang.String) ref;
+      } else {
+        com.google.protobuf.ByteString bs = 
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        if (bs.isValidUtf8()) {
+          version_ = s;
+        }
+        return s;
+      }
+    }
+    /**
+     * <code>optional string version = 12;</code>
+     *
+     * <pre>
+     * Only available on PROJECT and MODULE type
+     * </pre>
+     */
+    public com.google.protobuf.ByteString
+        getVersionBytes() {
+      java.lang.Object ref = version_;
+      if (ref instanceof java.lang.String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        version_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+
+    // optional int64 snapshot_id = 8;
     public static final int SNAPSHOT_ID_FIELD_NUMBER = 8;
-    private int snapshotId_;
+    private long snapshotId_;
     /**
-     * <code>optional int32 snapshot_id = 8;</code>
+     * <code>optional int64 snapshot_id = 8;</code>
      *
      * <pre>
      * temporary fields during development of computation stack
      * </pre>
      */
     public boolean hasSnapshotId() {
-      return ((bitField0_ & 0x00000040) == 0x00000040);
+      return ((bitField0_ & 0x00000080) == 0x00000080);
     }
     /**
-     * <code>optional int32 snapshot_id = 8;</code>
+     * <code>optional int64 snapshot_id = 8;</code>
      *
      * <pre>
      * temporary fields during development of computation stack
      * </pre>
      */
-    public int getSnapshotId() {
+    public long getSnapshotId() {
       return snapshotId_;
     }
 
@@ -1986,7 +3071,7 @@ public final class BatchReport {
      * <code>optional string uuid = 9;</code>
      */
     public boolean hasUuid() {
-      return ((bitField0_ & 0x00000080) == 0x00000080);
+      return ((bitField0_ & 0x00000100) == 0x00000100);
     }
     /**
      * <code>optional string uuid = 9;</code>
@@ -2022,6 +3107,42 @@ public final class BatchReport {
       }
     }
 
+    // repeated .Event events = 11;
+    public static final int EVENTS_FIELD_NUMBER = 11;
+    private java.util.List<org.sonar.batch.protocol.output.BatchReport.Event> events_;
+    /**
+     * <code>repeated .Event events = 11;</code>
+     */
+    public java.util.List<org.sonar.batch.protocol.output.BatchReport.Event> getEventsList() {
+      return events_;
+    }
+    /**
+     * <code>repeated .Event events = 11;</code>
+     */
+    public java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.EventOrBuilder> 
+        getEventsOrBuilderList() {
+      return events_;
+    }
+    /**
+     * <code>repeated .Event events = 11;</code>
+     */
+    public int getEventsCount() {
+      return events_.size();
+    }
+    /**
+     * <code>repeated .Event events = 11;</code>
+     */
+    public org.sonar.batch.protocol.output.BatchReport.Event getEvents(int index) {
+      return events_.get(index);
+    }
+    /**
+     * <code>repeated .Event events = 11;</code>
+     */
+    public org.sonar.batch.protocol.output.BatchReport.EventOrBuilder getEventsOrBuilder(
+        int index) {
+      return events_.get(index);
+    }
+
     private void initFields() {
       ref_ = 0;
       path_ = "";
@@ -2031,8 +3152,10 @@ public final class BatchReport {
       language_ = "";
       childRef_ = java.util.Collections.emptyList();
       link_ = java.util.Collections.emptyList();
-      snapshotId_ = 0;
+      version_ = "";
+      snapshotId_ = 0L;
       uuid_ = "";
+      events_ = java.util.Collections.emptyList();
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -2071,15 +3194,21 @@ public final class BatchReport {
       for (int i = 0; i < childRef_.size(); i++) {
         output.writeInt32NoTag(childRef_.get(i));
       }
-      if (((bitField0_ & 0x00000040) == 0x00000040)) {
-        output.writeInt32(8, snapshotId_);
-      }
       if (((bitField0_ & 0x00000080) == 0x00000080)) {
+        output.writeInt64(8, snapshotId_);
+      }
+      if (((bitField0_ & 0x00000100) == 0x00000100)) {
         output.writeBytes(9, getUuidBytes());
       }
       for (int i = 0; i < link_.size(); i++) {
         output.writeMessage(10, link_.get(i));
       }
+      for (int i = 0; i < events_.size(); i++) {
+        output.writeMessage(11, events_.get(i));
+      }
+      if (((bitField0_ & 0x00000040) == 0x00000040)) {
+        output.writeBytes(12, getVersionBytes());
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -2127,11 +3256,11 @@ public final class BatchReport {
         }
         childRefMemoizedSerializedSize = dataSize;
       }
-      if (((bitField0_ & 0x00000040) == 0x00000040)) {
-        size += com.google.protobuf.CodedOutputStream
-          .computeInt32Size(8, snapshotId_);
-      }
       if (((bitField0_ & 0x00000080) == 0x00000080)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt64Size(8, snapshotId_);
+      }
+      if (((bitField0_ & 0x00000100) == 0x00000100)) {
         size += com.google.protobuf.CodedOutputStream
           .computeBytesSize(9, getUuidBytes());
       }
@@ -2139,6 +3268,14 @@ public final class BatchReport {
         size += com.google.protobuf.CodedOutputStream
           .computeMessageSize(10, link_.get(i));
       }
+      for (int i = 0; i < events_.size(); i++) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeMessageSize(11, events_.get(i));
+      }
+      if (((bitField0_ & 0x00000040) == 0x00000040)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBytesSize(12, getVersionBytes());
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -2248,6 +3385,7 @@ public final class BatchReport {
       private void maybeForceBuilderInitialization() {
         if (com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders) {
           getLinkFieldBuilder();
+          getEventsFieldBuilder();
         }
       }
       private static Builder create() {
@@ -2276,10 +3414,18 @@ public final class BatchReport {
         } else {
           linkBuilder_.clear();
         }
-        snapshotId_ = 0;
+        version_ = "";
         bitField0_ = (bitField0_ & ~0x00000100);
-        uuid_ = "";
+        snapshotId_ = 0L;
         bitField0_ = (bitField0_ & ~0x00000200);
+        uuid_ = "";
+        bitField0_ = (bitField0_ & ~0x00000400);
+        if (eventsBuilder_ == null) {
+          events_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000800);
+        } else {
+          eventsBuilder_.clear();
+        }
         return this;
       }
 
@@ -2349,11 +3495,24 @@ public final class BatchReport {
         if (((from_bitField0_ & 0x00000100) == 0x00000100)) {
           to_bitField0_ |= 0x00000040;
         }
-        result.snapshotId_ = snapshotId_;
+        result.version_ = version_;
         if (((from_bitField0_ & 0x00000200) == 0x00000200)) {
           to_bitField0_ |= 0x00000080;
         }
+        result.snapshotId_ = snapshotId_;
+        if (((from_bitField0_ & 0x00000400) == 0x00000400)) {
+          to_bitField0_ |= 0x00000100;
+        }
         result.uuid_ = uuid_;
+        if (eventsBuilder_ == null) {
+          if (((bitField0_ & 0x00000800) == 0x00000800)) {
+            events_ = java.util.Collections.unmodifiableList(events_);
+            bitField0_ = (bitField0_ & ~0x00000800);
+          }
+          result.events_ = events_;
+        } else {
+          result.events_ = eventsBuilder_.build();
+        }
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -2430,14 +3589,45 @@ public final class BatchReport {
             }
           }
         }
+        if (other.hasVersion()) {
+          bitField0_ |= 0x00000100;
+          version_ = other.version_;
+          onChanged();
+        }
         if (other.hasSnapshotId()) {
           setSnapshotId(other.getSnapshotId());
         }
         if (other.hasUuid()) {
-          bitField0_ |= 0x00000200;
+          bitField0_ |= 0x00000400;
           uuid_ = other.uuid_;
           onChanged();
         }
+        if (eventsBuilder_ == null) {
+          if (!other.events_.isEmpty()) {
+            if (events_.isEmpty()) {
+              events_ = other.events_;
+              bitField0_ = (bitField0_ & ~0x00000800);
+            } else {
+              ensureEventsIsMutable();
+              events_.addAll(other.events_);
+            }
+            onChanged();
+          }
+        } else {
+          if (!other.events_.isEmpty()) {
+            if (eventsBuilder_.isEmpty()) {
+              eventsBuilder_.dispose();
+              eventsBuilder_ = null;
+              events_ = other.events_;
+              bitField0_ = (bitField0_ & ~0x00000800);
+              eventsBuilder_ = 
+                com.google.protobuf.GeneratedMessage.alwaysUseFieldBuilders ?
+                   getEventsFieldBuilder() : null;
+            } else {
+              eventsBuilder_.addAllMessages(other.events_);
+            }
+          }
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -3095,51 +4285,149 @@ public final class BatchReport {
         return linkBuilder_;
       }
 
-      // optional int32 snapshot_id = 8;
-      private int snapshotId_ ;
+      // optional string version = 12;
+      private java.lang.Object version_ = "";
+      /**
+       * <code>optional string version = 12;</code>
+       *
+       * <pre>
+       * Only available on PROJECT and MODULE type
+       * </pre>
+       */
+      public boolean hasVersion() {
+        return ((bitField0_ & 0x00000100) == 0x00000100);
+      }
+      /**
+       * <code>optional string version = 12;</code>
+       *
+       * <pre>
+       * Only available on PROJECT and MODULE type
+       * </pre>
+       */
+      public java.lang.String getVersion() {
+        java.lang.Object ref = version_;
+        if (!(ref instanceof java.lang.String)) {
+          java.lang.String s = ((com.google.protobuf.ByteString) ref)
+              .toStringUtf8();
+          version_ = s;
+          return s;
+        } else {
+          return (java.lang.String) ref;
+        }
+      }
+      /**
+       * <code>optional string version = 12;</code>
+       *
+       * <pre>
+       * Only available on PROJECT and MODULE type
+       * </pre>
+       */
+      public com.google.protobuf.ByteString
+          getVersionBytes() {
+        java.lang.Object ref = version_;
+        if (ref instanceof String) {
+          com.google.protobuf.ByteString b = 
+              com.google.protobuf.ByteString.copyFromUtf8(
+                  (java.lang.String) ref);
+          version_ = b;
+          return b;
+        } else {
+          return (com.google.protobuf.ByteString) ref;
+        }
+      }
+      /**
+       * <code>optional string version = 12;</code>
+       *
+       * <pre>
+       * Only available on PROJECT and MODULE type
+       * </pre>
+       */
+      public Builder setVersion(
+          java.lang.String value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000100;
+        version_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string version = 12;</code>
+       *
+       * <pre>
+       * Only available on PROJECT and MODULE type
+       * </pre>
+       */
+      public Builder clearVersion() {
+        bitField0_ = (bitField0_ & ~0x00000100);
+        version_ = getDefaultInstance().getVersion();
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional string version = 12;</code>
+       *
+       * <pre>
+       * Only available on PROJECT and MODULE type
+       * </pre>
+       */
+      public Builder setVersionBytes(
+          com.google.protobuf.ByteString value) {
+        if (value == null) {
+    throw new NullPointerException();
+  }
+  bitField0_ |= 0x00000100;
+        version_ = value;
+        onChanged();
+        return this;
+      }
+
+      // optional int64 snapshot_id = 8;
+      private long snapshotId_ ;
       /**
-       * <code>optional int32 snapshot_id = 8;</code>
+       * <code>optional int64 snapshot_id = 8;</code>
        *
        * <pre>
        * temporary fields during development of computation stack
        * </pre>
        */
       public boolean hasSnapshotId() {
-        return ((bitField0_ & 0x00000100) == 0x00000100);
+        return ((bitField0_ & 0x00000200) == 0x00000200);
       }
       /**
-       * <code>optional int32 snapshot_id = 8;</code>
+       * <code>optional int64 snapshot_id = 8;</code>
        *
        * <pre>
        * temporary fields during development of computation stack
        * </pre>
        */
-      public int getSnapshotId() {
+      public long getSnapshotId() {
         return snapshotId_;
       }
       /**
-       * <code>optional int32 snapshot_id = 8;</code>
+       * <code>optional int64 snapshot_id = 8;</code>
        *
        * <pre>
        * temporary fields during development of computation stack
        * </pre>
        */
-      public Builder setSnapshotId(int value) {
-        bitField0_ |= 0x00000100;
+      public Builder setSnapshotId(long value) {
+        bitField0_ |= 0x00000200;
         snapshotId_ = value;
         onChanged();
         return this;
       }
       /**
-       * <code>optional int32 snapshot_id = 8;</code>
+       * <code>optional int64 snapshot_id = 8;</code>
        *
        * <pre>
        * temporary fields during development of computation stack
        * </pre>
        */
       public Builder clearSnapshotId() {
-        bitField0_ = (bitField0_ & ~0x00000100);
-        snapshotId_ = 0;
+        bitField0_ = (bitField0_ & ~0x00000200);
+        snapshotId_ = 0L;
         onChanged();
         return this;
       }
@@ -3150,7 +4438,7 @@ public final class BatchReport {
        * <code>optional string uuid = 9;</code>
        */
       public boolean hasUuid() {
-        return ((bitField0_ & 0x00000200) == 0x00000200);
+        return ((bitField0_ & 0x00000400) == 0x00000400);
       }
       /**
        * <code>optional string uuid = 9;</code>
@@ -3190,7 +4478,7 @@ public final class BatchReport {
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00000200;
+  bitField0_ |= 0x00000400;
         uuid_ = value;
         onChanged();
         return this;
@@ -3199,7 +4487,7 @@ public final class BatchReport {
        * <code>optional string uuid = 9;</code>
        */
       public Builder clearUuid() {
-        bitField0_ = (bitField0_ & ~0x00000200);
+        bitField0_ = (bitField0_ & ~0x00000400);
         uuid_ = getDefaultInstance().getUuid();
         onChanged();
         return this;
@@ -3212,12 +4500,252 @@ public final class BatchReport {
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00000200;
+  bitField0_ |= 0x00000400;
         uuid_ = value;
         onChanged();
         return this;
       }
 
+      // repeated .Event events = 11;
+      private java.util.List<org.sonar.batch.protocol.output.BatchReport.Event> events_ =
+        java.util.Collections.emptyList();
+      private void ensureEventsIsMutable() {
+        if (!((bitField0_ & 0x00000800) == 0x00000800)) {
+          events_ = new java.util.ArrayList<org.sonar.batch.protocol.output.BatchReport.Event>(events_);
+          bitField0_ |= 0x00000800;
+         }
+      }
+
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonar.batch.protocol.output.BatchReport.Event, org.sonar.batch.protocol.output.BatchReport.Event.Builder, org.sonar.batch.protocol.output.BatchReport.EventOrBuilder> eventsBuilder_;
+
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public java.util.List<org.sonar.batch.protocol.output.BatchReport.Event> getEventsList() {
+        if (eventsBuilder_ == null) {
+          return java.util.Collections.unmodifiableList(events_);
+        } else {
+          return eventsBuilder_.getMessageList();
+        }
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public int getEventsCount() {
+        if (eventsBuilder_ == null) {
+          return events_.size();
+        } else {
+          return eventsBuilder_.getCount();
+        }
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.Event getEvents(int index) {
+        if (eventsBuilder_ == null) {
+          return events_.get(index);
+        } else {
+          return eventsBuilder_.getMessage(index);
+        }
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public Builder setEvents(
+          int index, org.sonar.batch.protocol.output.BatchReport.Event value) {
+        if (eventsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureEventsIsMutable();
+          events_.set(index, value);
+          onChanged();
+        } else {
+          eventsBuilder_.setMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public Builder setEvents(
+          int index, org.sonar.batch.protocol.output.BatchReport.Event.Builder builderForValue) {
+        if (eventsBuilder_ == null) {
+          ensureEventsIsMutable();
+          events_.set(index, builderForValue.build());
+          onChanged();
+        } else {
+          eventsBuilder_.setMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public Builder addEvents(org.sonar.batch.protocol.output.BatchReport.Event value) {
+        if (eventsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureEventsIsMutable();
+          events_.add(value);
+          onChanged();
+        } else {
+          eventsBuilder_.addMessage(value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public Builder addEvents(
+          int index, org.sonar.batch.protocol.output.BatchReport.Event value) {
+        if (eventsBuilder_ == null) {
+          if (value == null) {
+            throw new NullPointerException();
+          }
+          ensureEventsIsMutable();
+          events_.add(index, value);
+          onChanged();
+        } else {
+          eventsBuilder_.addMessage(index, value);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public Builder addEvents(
+          org.sonar.batch.protocol.output.BatchReport.Event.Builder builderForValue) {
+        if (eventsBuilder_ == null) {
+          ensureEventsIsMutable();
+          events_.add(builderForValue.build());
+          onChanged();
+        } else {
+          eventsBuilder_.addMessage(builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public Builder addEvents(
+          int index, org.sonar.batch.protocol.output.BatchReport.Event.Builder builderForValue) {
+        if (eventsBuilder_ == null) {
+          ensureEventsIsMutable();
+          events_.add(index, builderForValue.build());
+          onChanged();
+        } else {
+          eventsBuilder_.addMessage(index, builderForValue.build());
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public Builder addAllEvents(
+          java.lang.Iterable<? extends org.sonar.batch.protocol.output.BatchReport.Event> values) {
+        if (eventsBuilder_ == null) {
+          ensureEventsIsMutable();
+          super.addAll(values, events_);
+          onChanged();
+        } else {
+          eventsBuilder_.addAllMessages(values);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public Builder clearEvents() {
+        if (eventsBuilder_ == null) {
+          events_ = java.util.Collections.emptyList();
+          bitField0_ = (bitField0_ & ~0x00000800);
+          onChanged();
+        } else {
+          eventsBuilder_.clear();
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public Builder removeEvents(int index) {
+        if (eventsBuilder_ == null) {
+          ensureEventsIsMutable();
+          events_.remove(index);
+          onChanged();
+        } else {
+          eventsBuilder_.remove(index);
+        }
+        return this;
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.Event.Builder getEventsBuilder(
+          int index) {
+        return getEventsFieldBuilder().getBuilder(index);
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.EventOrBuilder getEventsOrBuilder(
+          int index) {
+        if (eventsBuilder_ == null) {
+          return events_.get(index);  } else {
+          return eventsBuilder_.getMessageOrBuilder(index);
+        }
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public java.util.List<? extends org.sonar.batch.protocol.output.BatchReport.EventOrBuilder> 
+           getEventsOrBuilderList() {
+        if (eventsBuilder_ != null) {
+          return eventsBuilder_.getMessageOrBuilderList();
+        } else {
+          return java.util.Collections.unmodifiableList(events_);
+        }
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.Event.Builder addEventsBuilder() {
+        return getEventsFieldBuilder().addBuilder(
+            org.sonar.batch.protocol.output.BatchReport.Event.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public org.sonar.batch.protocol.output.BatchReport.Event.Builder addEventsBuilder(
+          int index) {
+        return getEventsFieldBuilder().addBuilder(
+            index, org.sonar.batch.protocol.output.BatchReport.Event.getDefaultInstance());
+      }
+      /**
+       * <code>repeated .Event events = 11;</code>
+       */
+      public java.util.List<org.sonar.batch.protocol.output.BatchReport.Event.Builder> 
+           getEventsBuilderList() {
+        return getEventsFieldBuilder().getBuilderList();
+      }
+      private com.google.protobuf.RepeatedFieldBuilder<
+          org.sonar.batch.protocol.output.BatchReport.Event, org.sonar.batch.protocol.output.BatchReport.Event.Builder, org.sonar.batch.protocol.output.BatchReport.EventOrBuilder> 
+          getEventsFieldBuilder() {
+        if (eventsBuilder_ == null) {
+          eventsBuilder_ = new com.google.protobuf.RepeatedFieldBuilder<
+              org.sonar.batch.protocol.output.BatchReport.Event, org.sonar.batch.protocol.output.BatchReport.Event.Builder, org.sonar.batch.protocol.output.BatchReport.EventOrBuilder>(
+                  events_,
+                  ((bitField0_ & 0x00000800) == 0x00000800),
+                  getParentForChildren(),
+                  isClean());
+          events_ = null;
+        }
+        return eventsBuilder_;
+      }
+
       // @@protoc_insertion_point(builder_scope:Component)
     }
 
@@ -7742,6 +9270,11 @@ public final class BatchReport {
   private static
     com.google.protobuf.GeneratedMessage.FieldAccessorTable
       internal_static_ComponentLink_fieldAccessorTable;
+  private static com.google.protobuf.Descriptors.Descriptor
+    internal_static_Event_descriptor;
+  private static
+    com.google.protobuf.GeneratedMessage.FieldAccessorTable
+      internal_static_Event_fieldAccessorTable;
   private static com.google.protobuf.Descriptors.Descriptor
     internal_static_Component_descriptor;
   private static
@@ -7772,28 +9305,32 @@ public final class BatchReport {
       "(\005\022\023\n\013snapshot_id\030\004 \001(\003\022 \n\030deleted_compo" +
       "nents_count\030\005 \001(\005\"?\n\rComponentLink\022 \n\004ty" +
       "pe\030\001 \001(\0162\022.ComponentLinkType\022\014\n\004href\030\002 \001" +
-      "(\t\"\315\001\n\tComponent\022\013\n\003ref\030\001 \001(\005\022\014\n\004path\030\002 " +
-      "\001(\t\022\014\n\004name\030\003 \001(\t\022\034\n\004type\030\004 \001(\0162\016.Compon" +
-      "entType\022\017\n\007is_test\030\005 \001(\010\022\020\n\010language\030\006 \001" +
-      "(\t\022\025\n\tchild_ref\030\007 \003(\005B\002\020\001\022\034\n\004link\030\n \003(\0132",
-      "\016.ComponentLink\022\023\n\013snapshot_id\030\010 \001(\005\022\014\n\004" +
-      "uuid\030\t \001(\t\"\231\004\n\005Issue\022\027\n\017rule_repository\030" +
-      "\001 \001(\t\022\020\n\010rule_key\030\002 \001(\t\022\014\n\004line\030\003 \001(\005\022\013\n" +
-      "\003msg\030\004 \001(\t\022\033\n\010severity\030\005 \001(\0162\t.Severity\022" +
-      "\013\n\003tag\030\006 \003(\t\022\025\n\reffort_to_fix\030\007 \001(\001\022\016\n\006i" +
-      "s_new\030\010 \001(\010\022\014\n\004uuid\030\t \001(\t\022\027\n\017debt_in_min" +
-      "utes\030\n \001(\003\022\022\n\nresolution\030\013 \001(\t\022\016\n\006status" +
-      "\030\014 \001(\t\022\020\n\010checksum\030\r \001(\t\022\027\n\017manual_sever" +
-      "ity\030\016 \001(\010\022\020\n\010reporter\030\017 \001(\t\022\020\n\010assignee\030" +
-      "\020 \001(\t\022\027\n\017action_plan_key\030\021 \001(\t\022\022\n\nattrib",
-      "utes\030\022 \001(\t\022\024\n\014author_login\030\023 \001(\t\022\025\n\rcrea" +
-      "tion_date\030\024 \001(\003\022\022\n\nclose_date\030\025 \001(\003\022\023\n\013u" +
-      "pdate_date\030\026 \001(\003\022\023\n\013selected_at\030\027 \001(\003\022\023\n" +
-      "\013diff_fields\030\030 \001(\t\022\022\n\nis_changed\030\031 \001(\010\022\036" +
-      "\n\026must_send_notification\030\032 \001(\010\"N\n\006Issues" +
-      "\022\025\n\rcomponent_ref\030\001 \001(\005\022\025\n\005issue\030\002 \003(\0132\006" +
-      ".Issue\022\026\n\016component_uuid\030\003 \001(\tB#\n\037org.so" +
-      "nar.batch.protocol.outputH\001"
+      "(\t\"w\n\005Event\022\025\n\rcomponent_ref\030\001 \001(\005\022\014\n\004na" +
+      "me\030\002 \001(\t\022\023\n\013description\030\003 \001(\t\022 \n\010categor" +
+      "y\030\004 \001(\0162\016.EventCategory\022\022\n\nevent_data\030\005 " +
+      "\001(\t\"\366\001\n\tComponent\022\013\n\003ref\030\001 \001(\005\022\014\n\004path\030\002",
+      " \001(\t\022\014\n\004name\030\003 \001(\t\022\034\n\004type\030\004 \001(\0162\016.Compo" +
+      "nentType\022\017\n\007is_test\030\005 \001(\010\022\020\n\010language\030\006 " +
+      "\001(\t\022\025\n\tchild_ref\030\007 \003(\005B\002\020\001\022\034\n\004link\030\n \003(\013" +
+      "2\016.ComponentLink\022\017\n\007version\030\014 \001(\t\022\023\n\013sna" +
+      "pshot_id\030\010 \001(\003\022\014\n\004uuid\030\t \001(\t\022\026\n\006events\030\013" +
+      " \003(\0132\006.Event\"\231\004\n\005Issue\022\027\n\017rule_repositor" +
+      "y\030\001 \001(\t\022\020\n\010rule_key\030\002 \001(\t\022\014\n\004line\030\003 \001(\005\022" +
+      "\013\n\003msg\030\004 \001(\t\022\033\n\010severity\030\005 \001(\0162\t.Severit" +
+      "y\022\013\n\003tag\030\006 \003(\t\022\025\n\reffort_to_fix\030\007 \001(\001\022\016\n" +
+      "\006is_new\030\010 \001(\010\022\014\n\004uuid\030\t \001(\t\022\027\n\017debt_in_m",
+      "inutes\030\n \001(\003\022\022\n\nresolution\030\013 \001(\t\022\016\n\006stat" +
+      "us\030\014 \001(\t\022\020\n\010checksum\030\r \001(\t\022\027\n\017manual_sev" +
+      "erity\030\016 \001(\010\022\020\n\010reporter\030\017 \001(\t\022\020\n\010assigne" +
+      "e\030\020 \001(\t\022\027\n\017action_plan_key\030\021 \001(\t\022\022\n\nattr" +
+      "ibutes\030\022 \001(\t\022\024\n\014author_login\030\023 \001(\t\022\025\n\rcr" +
+      "eation_date\030\024 \001(\003\022\022\n\nclose_date\030\025 \001(\003\022\023\n" +
+      "\013update_date\030\026 \001(\003\022\023\n\013selected_at\030\027 \001(\003\022" +
+      "\023\n\013diff_fields\030\030 \001(\t\022\022\n\nis_changed\030\031 \001(\010" +
+      "\022\036\n\026must_send_notification\030\032 \001(\010\"N\n\006Issu" +
+      "es\022\025\n\rcomponent_ref\030\001 \001(\005\022\025\n\005issue\030\002 \003(\013",
+      "2\006.Issue\022\026\n\016component_uuid\030\003 \001(\tB#\n\037org." +
+      "sonar.batch.protocol.outputH\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
       new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -7812,20 +9349,26 @@ public final class BatchReport {
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_ComponentLink_descriptor,
               new java.lang.String[] { "Type", "Href", });
-          internal_static_Component_descriptor =
+          internal_static_Event_descriptor =
             getDescriptor().getMessageTypes().get(2);
+          internal_static_Event_fieldAccessorTable = new
+            com.google.protobuf.GeneratedMessage.FieldAccessorTable(
+              internal_static_Event_descriptor,
+              new java.lang.String[] { "ComponentRef", "Name", "Description", "Category", "EventData", });
+          internal_static_Component_descriptor =
+            getDescriptor().getMessageTypes().get(3);
           internal_static_Component_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_Component_descriptor,
-              new java.lang.String[] { "Ref", "Path", "Name", "Type", "IsTest", "Language", "ChildRef", "Link", "SnapshotId", "Uuid", });
+              new java.lang.String[] { "Ref", "Path", "Name", "Type", "IsTest", "Language", "ChildRef", "Link", "Version", "SnapshotId", "Uuid", "Events", });
           internal_static_Issue_descriptor =
-            getDescriptor().getMessageTypes().get(3);
+            getDescriptor().getMessageTypes().get(4);
           internal_static_Issue_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_Issue_descriptor,
               new java.lang.String[] { "RuleRepository", "RuleKey", "Line", "Msg", "Severity", "Tag", "EffortToFix", "IsNew", "Uuid", "DebtInMinutes", "Resolution", "Status", "Checksum", "ManualSeverity", "Reporter", "Assignee", "ActionPlanKey", "Attributes", "AuthorLogin", "CreationDate", "CloseDate", "UpdateDate", "SelectedAt", "DiffFields", "IsChanged", "MustSendNotification", });
           internal_static_Issues_descriptor =
-            getDescriptor().getMessageTypes().get(4);
+            getDescriptor().getMessageTypes().get(5);
           internal_static_Issues_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_Issues_descriptor,
index e159bedf516fd7409bb6b2dad4575923027181cb..4f5145cb87b87507c98daf22a79b2ad7333efddc 100644 (file)
@@ -53,6 +53,15 @@ message ComponentLink {
   optional string href = 2;
 }
 
+// temporary message during development of computation stack
+message Event {
+  optional int32 component_ref = 1;
+  optional string name = 2;
+  optional string description = 3;
+  optional EventCategory category = 4;
+  optional string event_data = 5;
+}
+
 message Component {
   optional int32 ref = 1;
   optional string path = 2;
@@ -62,10 +71,13 @@ message Component {
   optional string language = 6;
   repeated int32 child_ref = 7 [packed=true];
   repeated ComponentLink link = 10;
+  // Only available on PROJECT and MODULE type
+  optional string version = 12;
 
   // temporary fields during development of computation stack
-  optional int32 snapshot_id = 8;
+  optional int64 snapshot_id = 8;
   optional string uuid = 9;
+  repeated Event events = 11;
 }
 
 message Issue {
index e4e06eb0570b1edcae19a13871c1d778d841da7b..07c8aaf35408e71c7a7623c41204ff917c8f5ebc 100644 (file)
@@ -38,6 +38,12 @@ enum ComponentType {
   SUBVIEW = 5;
 }
 
+// temporary enum during development of computation stack
+enum EventCategory {
+  ALERT = 0;
+  PROFILE = 1;
+}
+
 enum ComponentLinkType {
   HOME = 0;
   SCM = 1;
index 0125fa7d4d7b5479c5180a776ff3e22ddf7796c3..fcb0fce8ffb1ad0fc5283ecfb5c05c0bb71a9a3c 100644 (file)
  */
 package org.sonar.batch.deprecated.components;
 
-import org.sonar.batch.components.PastSnapshot;
-
 import org.sonar.api.BatchExtension;
 import org.sonar.api.CoreProperties;
 import org.sonar.api.batch.Event;
 import org.sonar.api.database.DatabaseSession;
 import org.sonar.api.database.model.Snapshot;
+import org.sonar.batch.components.PastSnapshot;
 
 import java.util.List;
 
@@ -43,8 +42,8 @@ public class PastSnapshotFinderByPreviousVersion implements BatchExtension {
     String currentVersion = projectSnapshot.getVersion();
     Integer resourceId = projectSnapshot.getResourceId();
 
-    String hql = "from " + Event.class.getSimpleName() +
-      " where name<>:version AND category='Version' AND resourceId=:resourceId ORDER BY date DESC";
+    String hql = "select e from " + Event.class.getSimpleName() + " e " +
+      " join e.resource component where e.name<>:version AND e.category='Version' AND component.id=:resourceId ORDER BY e.date DESC";
 
     List<Event> events = session.createQuery(hql)
       .setParameter("version", currentVersion)
index 8ee521c247e911af7b9f0e9759abcf5c817547aa..3b68e8cda4811195f977446c5602581ebbbedacf 100644 (file)
@@ -41,7 +41,7 @@ public class EventPersister {
   }
 
   public List<Event> getEvents(Resource resource) {
-    return session.getResults(Event.class, "resourceId", resource.getId());
+    return session.getResults(Event.class, "componentUuid", resource.getUuid());
   }
 
   public void deleteEvent(Event event) {
@@ -56,8 +56,9 @@ public class EventPersister {
     event.setCreatedAt(new Date(system2.now()));
     if (event.getDate() == null) {
       event.setSnapshot(batchResource.snapshot());
+      event.setComponentUuid(batchResource.resource().getUuid());
     } else {
-      event.setResourceId(batchResource.resource().getId());
+      event.setComponentUuid(batchResource.resource().getUuid());
     }
 
     session.save(event);
index 480b91f147e715cc1fd4093525a62935411465aa..eb6b6ba8ee3fc58427b4896fc1b605d9bf859484 100644 (file)
@@ -1,7 +1,7 @@
 <dataset>
 
   <projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="project" name="project"
-            root_id="[null]"
+            root_id="[null]" uuid="ABCD"
             description="[null]"
             enabled="true" language="java" copy_resource_id="[null]" person_id="[null]"/>
 
              scope="PRJ" qualifier="TRK" created_at="1226235480000" build_date="1226235480000" version="1.2-SNAPSHOT" path=""
              status="U" islast="true" depth="0" />
   
-  <events id="2" name="Foo" resource_id="1" snapshot_id="1000" category="Other" event_date="1225717080000" created_at="1225717080000" description=""
+  <events id="2" name="Foo" component_uuid="ABCD" snapshot_id="1000" category="Other" event_date="1225717080000" created_at="1225717080000" description=""
           event_data="[null]"/>
-  <events id="4" name="Bar" resource_id="1" snapshot_id="1001" category="Other" event_date="1225889880000" created_at="1225889880000" description=""
+  <events id="4" name="Bar" component_uuid="ABCD" snapshot_id="1001" category="Other" event_date="1225889880000" created_at="1225889880000" description=""
           event_data="[null]"/>
-  <events id="5" name="Uhh" resource_id="1" snapshot_id="1002" category="Other" event_date="1226062680000" created_at="1226062680000" description=""
+  <events id="5" name="Uhh" component_uuid="ABCD" snapshot_id="1002" category="Other" event_date="1226062680000" created_at="1226062680000" description=""
           event_data="[null]"/>
-  <events id="6" name="1.2-SNAPSHOT" resource_id="1" snapshot_id="1003" category="Version" event_date="1226235480000" created_at="1226235480000" description=""
+  <events id="6" name="1.2-SNAPSHOT" component_uuid="ABCD" snapshot_id="1003" category="Version" event_date="1226235480000" created_at="1226235480000" description=""
           event_data="[null]"/>
 
 </dataset>
index bc3a3c9c0551d8643d23e3a91748016604d830b6..5c328032d44a39e6d37d1ef7604052d1070d90d8 100644 (file)
@@ -1,7 +1,7 @@
 <dataset>
 
   <projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="project" name="project"
-            root_id="[null]"
+            root_id="[null]" uuid="ABCD"
             description="[null]"
             enabled="true" language="java" copy_resource_id="[null]" person_id="[null]"/>
 
              scope="PRJ" qualifier="TRK" created_at="1226235480000" build_date="1226235480000" version="1.2-SNAPSHOT" path=""
              status="U" islast="true" depth="0" />
   
-  <events id="1" name="1.0" resource_id="1" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description=""
+  <events id="1" name="1.0" component_uuid="ABCD" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description=""
           event_data="[null]"/>
-  <events id="2" name="Foo" resource_id="1" snapshot_id="1000" category="Other" event_date="1225717080000" created_at="1225717080000" description=""
+  <events id="2" name="Foo" component_uuid="ABCD" snapshot_id="1000" category="Other" event_date="1225717080000" created_at="1225717080000" description=""
           event_data="[null]"/>
   <!-- The "1.1" version was deleted from the history :  -->
-  <!-- events id="3" name="1.1" resource_id="1" snapshot_id="1001" category="Version" event_date="2008-11-04 13:58:00.00" created_at="2008-11-04 13:58:00.00" description=""/-->
-  <events id="4" name="Bar" resource_id="1" snapshot_id="1001" category="Other" event_date="1225889880000" created_at="1225889880000" description=""
+  <!-- events id="3" name="1.1" component_uuid="ABCD" snapshot_id="1001" category="Version" event_date="2008-11-04 13:58:00.00" created_at="2008-11-04 13:58:00.00" description=""/-->
+  <events id="4" name="Bar" component_uuid="ABCD" snapshot_id="1001" category="Other" event_date="1225889880000" created_at="1225889880000" description=""
           event_data="[null]"/>
-  <events id="5" name="Uhh" resource_id="1" snapshot_id="1002" category="Other" event_date="1226062680000" created_at="1226062680000" description=""
+  <events id="5" name="Uhh" component_uuid="ABCD" snapshot_id="1002" category="Other" event_date="1226062680000" created_at="1226062680000" description=""
           event_data="[null]"/>
-  <events id="6" name="1.2-SNAPSHOT" resource_id="1" snapshot_id="1003" category="Version" event_date="1226235480000" created_at="1226235480000" description=""
+  <events id="6" name="1.2-SNAPSHOT" component_uuid="ABCD" snapshot_id="1003" category="Version" event_date="1226235480000" created_at="1226235480000" description=""
           event_data="[null]"/>
 
 </dataset>
index 6efee1a0f516008d17d2ab70029392f25de11649..64ebe4d642eeab86960d023e683d7a21893212ba 100644 (file)
@@ -1,7 +1,7 @@
 <dataset>
 
   <projects long_name="[null]" id="1" scope="PRJ" qualifier="TRK" kee="project" name="project"
-            root_id="[null]"
+            root_id="[null]" uuid="ABCD"
             description="[null]"
             enabled="true" language="java" copy_resource_id="[null]" person_id="[null]"/>
 
              scope="PRJ" qualifier="TRK" created_at="1226235480000" build_date="1226235480000" version="1.2-SNAPSHOT" path=""
              status="U" islast="true" depth="0" />
   
-  <events id="1" name="1.0" resource_id="1" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description="" event_data="[null]"/>
-  <events id="2" name="Foo" resource_id="1" snapshot_id="1000" category="Other" event_date="1225717080000" created_at="1225717080000" description="" event_data="[null]"/>
-  <events id="3" name="1.1" resource_id="1" snapshot_id="1001" category="Version" event_date="1225803480000" created_at="1225803480000" description="" event_data="[null]"/>
-  <events id="4" name="Bar" resource_id="1" snapshot_id="1001" category="Other" event_date="1225889880000" created_at="1225889880000" description="" event_data="[null]"/>
-  <events id="5" name="Uhh" resource_id="1" snapshot_id="1002" category="Other" event_date="1226062680000" created_at="1226062680000" description="" event_data="[null]"/>
-  <events id="6" name="1.2-SNAPSHOT" resource_id="1" snapshot_id="1003" category="Version" event_date="1226235480000" created_at="1226235480000" description="" event_data="[null]"/>
+  <events id="1" name="1.0" component_uuid="ABCD" snapshot_id="1000" category="Version" event_date="1225630680000" created_at="1225630680000" description="" event_data="[null]"/>
+  <events id="2" name="Foo" component_uuid="ABCD" snapshot_id="1000" category="Other" event_date="1225717080000" created_at="1225717080000" description="" event_data="[null]"/>
+  <events id="3" name="1.1" component_uuid="ABCD" snapshot_id="1001" category="Version" event_date="1225803480000" created_at="1225803480000" description="" event_data="[null]"/>
+  <events id="4" name="Bar" component_uuid="ABCD" snapshot_id="1001" category="Other" event_date="1225889880000" created_at="1225889880000" description="" event_data="[null]"/>
+  <events id="5" name="Uhh" component_uuid="ABCD" snapshot_id="1002" category="Other" event_date="1226062680000" created_at="1226062680000" description="" event_data="[null]"/>
+  <events id="6" name="1.2-SNAPSHOT" component_uuid="ABCD" snapshot_id="1003" category="Version" event_date="1226235480000" created_at="1226235480000" description="" event_data="[null]"/>
 
 </dataset>
diff --git a/sonar-core/src/main/java/org/sonar/core/event/EventDto.java b/sonar-core/src/main/java/org/sonar/core/event/EventDto.java
new file mode 100644 (file)
index 0000000..f505c3a
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.core.event;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
+public class EventDto {
+
+  public static final String CATEGORY_VERSION = "Version";
+  public static final String CATEGORY_ALERT = "Alert";
+  public static final String CATEGORY_PROFILE = "Profile";
+
+  private Long id;
+
+  private String name;
+
+  private String description;
+
+  private String category;
+
+  private Long date;
+
+  private Long createdAt;
+
+  private String data;
+
+  private Long snapshotId;
+
+  private String componentUuid;
+
+  public Long getId() {
+    return id;
+  }
+
+  public EventDto setId(Long id) {
+    this.id = id;
+    return this;
+  }
+
+  public String getCategory() {
+    return category;
+  }
+
+  public EventDto setCategory(String category) {
+    this.category = category;
+    return this;
+  }
+
+  public String getComponentUuid() {
+    return componentUuid;
+  }
+
+  public EventDto setComponentUuid(String componentUuid) {
+    this.componentUuid = componentUuid;
+    return this;
+  }
+
+  public Long getCreatedAt() {
+    return createdAt;
+  }
+
+  public EventDto setCreatedAt(Long createdAt) {
+    this.createdAt = createdAt;
+    return this;
+  }
+
+  @CheckForNull
+  public String getData() {
+    return data;
+  }
+
+  public EventDto setData(@Nullable String data) {
+    this.data = data;
+    return this;
+  }
+
+  public Long getDate() {
+    return date;
+  }
+
+  public EventDto setDate(Long date) {
+    this.date = date;
+    return this;
+  }
+
+  @CheckForNull
+  public String getDescription() {
+    return description;
+  }
+
+  public EventDto setDescription(@Nullable String description) {
+    this.description = description;
+    return this;
+  }
+
+  public String getName() {
+    return name;
+  }
+
+  public EventDto setName(String name) {
+    this.name = name;
+    return this;
+  }
+
+  public Long getSnapshotId() {
+    return snapshotId;
+  }
+
+  public EventDto setSnapshotId(Long snapshotId) {
+    this.snapshotId = snapshotId;
+    return this;
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/event/db/EventMapper.java b/sonar-core/src/main/java/org/sonar/core/event/db/EventMapper.java
new file mode 100644 (file)
index 0000000..7fa3734
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.core.event.db;
+
+import org.sonar.core.event.EventDto;
+
+import java.util.List;
+
+public interface EventMapper {
+
+  List<EventDto> selectByComponentUuid(String uuid);
+
+  void insert(EventDto dto);
+
+  void delete(long id);
+
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/event/db/package-info.java b/sonar-core/src/main/java/org/sonar/core/event/db/package-info.java
new file mode 100644 (file)
index 0000000..7651f0b
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.core.event.db;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/sonar-core/src/main/java/org/sonar/core/event/package-info.java b/sonar-core/src/main/java/org/sonar/core/event/package-info.java
new file mode 100644 (file)
index 0000000..a11358f
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 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.
+ */
+
+@ParametersAreNonnullByDefault
+package org.sonar.core.event;
+
+import javax.annotation.ParametersAreNonnullByDefault;
index 1ebd681a27c298a95aaacf8f88eab90b2027507f..72d79512ceb528a9903c7925e6afa2cbc99e3d37 100644 (file)
@@ -33,7 +33,7 @@ import java.util.List;
  */
 public class DatabaseVersion implements BatchComponent, ServerComponent {
 
-  public static final int LAST_VERSION = 902;
+  public static final int LAST_VERSION = 905;
 
   /**
    * List of all the tables.n
index 721288c807e0212cf6bfbfe0f10442daf4d561e6..85873f4fc45be17bb47bf777dcab8fdddbfe22e4 100644 (file)
@@ -50,6 +50,8 @@ import org.sonar.core.dependency.ResourceSnapshotDto;
 import org.sonar.core.dependency.ResourceSnapshotMapper;
 import org.sonar.core.duplication.DuplicationMapper;
 import org.sonar.core.duplication.DuplicationUnitDto;
+import org.sonar.core.event.EventDto;
+import org.sonar.core.event.db.EventMapper;
 import org.sonar.core.graph.jdbc.GraphDto;
 import org.sonar.core.graph.jdbc.GraphDtoMapper;
 import org.sonar.core.issue.db.*;
@@ -184,6 +186,7 @@ public class MyBatis implements BatchComponent, ServerComponent {
     loadAlias(conf, "IdUuidPair", IdUuidPair.class);
     loadAlias(conf, "FilePathWithHash", FilePathWithHashDto.class);
     loadAlias(conf, "UuidWithProjectUuid", UuidWithProjectUuidDto.class);
+    loadAlias(conf, "Event", EventDto.class);
 
     // AuthorizationMapper has to be loaded before IssueMapper because this last one used it
     loadMapper(conf, "org.sonar.core.user.AuthorizationMapper");
@@ -202,7 +205,7 @@ public class MyBatis implements BatchComponent, ServerComponent {
       NotificationQueueMapper.class, CharacteristicMapper.class,
       GroupMembershipMapper.class, QualityProfileMapper.class, ActiveRuleMapper.class,
       MeasureMapper.class, MetricMapper.class, QualityGateMapper.class, QualityGateConditionMapper.class, ComponentMapper.class, SnapshotMapper.class,
-      ProjectQgateAssociationMapper.class,
+      ProjectQgateAssociationMapper.class, EventMapper.class,
       AnalysisReportMapper.class, ComponentIndexMapper.class, ComponentLinkMapper.class,
       Migration45Mapper.class, Migration50Mapper.class
     };
index 6abf150e396dc12ee82d3b90a016511be5e79e1b..438f416177c38d326218658c1fd72ee8016d4e86 100644 (file)
@@ -125,9 +125,9 @@ class PurgeCommands {
     session.commit();
     profiler.stop();
 
-    profiler.start("deleteResourceEvents (events)");
-    for (List<Long> partResourceIds : componentIdPartitions) {
-      purgeMapper.deleteResourceEvents(partResourceIds);
+    profiler.start("deleteComponentEvents (events)");
+    for (List<String> componentUuidPartition : componentUuidsPartitions) {
+      purgeMapper.deleteComponentEvents(componentUuidPartition);
     }
     session.commit();
     profiler.stop();
index 730b6845f4350ae51d93fcd4a6653dc26c86ea11..2dda5e5283778f77832f91147c74db96fb568b4e 100644 (file)
@@ -79,7 +79,7 @@ public interface PurgeMapper {
 
   void deleteResourceManualMeasures(@Param("resourceIds") List<Long> resourceIds);
 
-  void deleteResourceEvents(@Param("resourceIds") List<Long> resourceIds);
+  void deleteComponentEvents(@Param("componentUuids") List<String> componentUuids);
 
   void deleteResourceActionPlans(@Param("resourceIds") List<Long> resourceIds);
 
diff --git a/sonar-core/src/main/resources/org/sonar/core/event/db/EventMapper.xml b/sonar-core/src/main/resources/org/sonar/core/event/db/EventMapper.xml
new file mode 100644 (file)
index 0000000..11cd9bb
--- /dev/null
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.sonar.core.event.db.EventMapper">
+
+  <sql id="eventColumns">
+    e.id,
+    e.name,
+    e.category,
+    e.description,
+    e.event_data as "data",
+    e.event_date as "date",
+    e.component_uuid as "componentUuid",
+    e.snapshot_id as "snapshotId",
+    e.created_at as "createdAt"
+  </sql>
+
+  <select id="selectByComponentUuid" parameterType="String" resultType="Event">
+    SELECT <include refid="eventColumns"/>
+    FROM events e
+    <where>
+      AND e.component_uuid=#{uuid}
+    </where>
+  </select>
+
+  <insert id="insert" parameterType="Event" keyColumn="id" useGeneratedKeys="true" keyProperty="id">
+    INSERT INTO events (name, category, description, event_data, event_date, component_uuid, snapshot_id, created_at)
+    VALUES (#{name}, #{category}, #{description}, #{data}, #{date}, #{componentUuid}, #{snapshotId}, #{createdAt})
+  </insert>
+
+  <delete id="delete">
+    DELETE FROM events WHERE id=#{id}
+  </delete>
+
+</mapper>
+
index f09dceaddea8596b49fbd74863c4f93006bf0a61..33e1daf7412615a6a191ece34e2d07a0c43acb48 100644 (file)
@@ -326,6 +326,9 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('796');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('900');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('901');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('902');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('903');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('904');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('905');
 
 INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482', null, null);
 ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
index 91af4c3176901679c7126f451ffaf73824255d5c..720e4fd0ee69e27167c0a034d0d9e27933cecbc3 100644 (file)
@@ -164,7 +164,7 @@ CREATE TABLE "WIDGET_PROPERTIES" (
 CREATE TABLE "EVENTS" (
   "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
   "NAME" VARCHAR(400),
-  "RESOURCE_ID" INTEGER,
+  "COMPONENT_UUID" VARCHAR(50),
   "SNAPSHOT_ID" INTEGER,
   "CATEGORY" VARCHAR(50),
   "EVENT_DATE" BIGINT NOT NULL,
@@ -599,7 +599,7 @@ CREATE UNIQUE INDEX "METRICS_UNIQUE_NAME" ON "METRICS" ("NAME");
 
 CREATE INDEX "EVENTS_SNAPSHOT_ID" ON "EVENTS" ("SNAPSHOT_ID");
 
-CREATE INDEX "EVENTS_RESOURCE_ID" ON "EVENTS" ("RESOURCE_ID");
+CREATE INDEX "EVENTS_COMPONENT_UUID" ON "EVENTS" ("COMPONENT_UUID");
 
 CREATE INDEX "WIDGETS_WIDGETKEY" ON "WIDGETS" ("WIDGET_KEY");
 
index 04c718a1ecad6db938b2fca355b0cf44dc72fd73..6ba17308f50ff48963b6be8163659779ed0ef678 100644 (file)
     </foreach>
   </delete>
 
-  <delete id="deleteResourceEvents" parameterType="map">
-    delete from events where resource_id in
-    <foreach collection="resourceIds" open="(" close=")" item="resourceId" separator=",">
-      #{resourceId}
+  <delete id="deleteComponentEvents" parameterType="map">
+    delete from events where component_uuid in
+    <foreach collection="componentUuids" open="(" close=")" item="componentUuid" separator=",">
+      #{componentUuid}
     </foreach>
   </delete>
 
index 060dbfb065b83eab316d571b6aaab95fe3a518ba..374c0652a833ed625e6648c529526b77b0a805ac 100644 (file)
@@ -22,9 +22,9 @@
 
   <project_measures id="1" value="10" metric_id="1" snapshot_id="1000" />
 
-  <events id="1" name="1.0-SNAPSHOT" resource_id="123" event_data="[null]"/>
-  <events id="2" name="2.0-SNAPSHOT" resource_id="123" event_data="[null]" />
-  <events id="3" name="1.0-SNAPSHOT" resource_id="456" event_data="[null]" />
+  <events id="1" name="1.0-SNAPSHOT" component_uuid="123" event_data="[null]"/>
+  <events id="2" name="2.0-SNAPSHOT" component_uuid="123" event_data="[null]" />
+  <events id="3" name="1.0-SNAPSHOT" component_uuid="456" event_data="[null]" />
 
   <users id="1" login="julien" name="Julien" crypted_password="foo" active="1" />
   <users id="2" login="simon" name="Simon" active="1" />
index 2f30df757d09d9682419894bff09470db0d18037..00363eb0100efc5e8fc632d6af8be9472b24cfc2 100644 (file)
@@ -15,7 +15,7 @@
              build_date="1228222680000"
              version="[null]" path="[null]"/>
 
-  <events id="1" name="Version 1.0" resource_id="1" snapshot_id="1" category="VERSION" description="[null]"
+  <events id="1" name="Version 1.0" component_uuid="1" snapshot_id="1" category="VERSION" description="[null]"
           event_date="1228222680000" created_at="1228222680000" event_data="[null]"/>
 
   <issues id="1" kee="ABCDE" component_uuid="1" project_uuid="1" status="CLOSED" resolution="[null]" line="200"
index f7a0a3a81b35a2d78d63c0426fbb67cb2d3519ce..e6e06a96fa99bf36a4de8236bcc3561282ca7297 100644 (file)
@@ -25,7 +25,7 @@
   <dependencies id="1" from_resource_id="1" from_snapshot_id="1" to_resource_id="30" to_snapshot_id="30"
                 parent_dependency_id="[null]" project_snapshot_id="1"
                 dep_usage="USES" dep_weight="1" from_scope="PRJ" to_scope="LIB"/>
-  <events id="1" name="Version 1.0" resource_id="1" snapshot_id="1" category="VERSION" description="[null]"
+  <events id="1" name="Version 1.0" component_uuid="1" snapshot_id="1" category="VERSION" description="[null]"
           event_date="1228222680000" created_at="1228222680000" event_data="[null]"/>
   <duplications_index id="1" project_snapshot_id="1" snapshot_id="1" hash="bb" index_in_file="0" start_line="0"
                       end_line="0"/>
index 45eaee581634cb81eec24d6e6ba4e6235c981b56..a4cabcfff0dade6daeee73f95ec437939b6c9a59 100644 (file)
@@ -24,7 +24,7 @@
   <dependencies id="1" from_resource_id="1" from_snapshot_id="1" to_resource_id="30" to_snapshot_id="30"
                 parent_dependency_id="[null]" project_snapshot_id="1"
                 dep_usage="USES" dep_weight="1" from_scope="PRJ" to_scope="LIB"/>
-  <events id="1" name="Version 1.0" resource_id="1" snapshot_id="1" category="VERSION" description="[null]"
+  <events id="1" name="Version 1.0" component_uuid="1" snapshot_id="1" category="VERSION" description="[null]"
           event_date="1228222680000" created_at="1228222680000" event_data="[null]"/>
   <duplications_index id="1" project_snapshot_id="1" snapshot_id="1" hash="bb" index_in_file="0" start_line="0"
                       end_line="0"/>
@@ -57,7 +57,7 @@
   <dependencies id="3" from_resource_id="5" from_snapshot_id="5" to_resource_id="300" to_snapshot_id="300"
                 parent_dependency_id="[null]" project_snapshot_id="5"
                 dep_usage="USES" dep_weight="1" from_scope="PRJ" to_scope="LIB"/>
-  <events id="2" name="Version 1.0" resource_id="5" snapshot_id="5" category="VERSION" description="[null]"
+  <events id="2" name="Version 1.0" component_uuid="5" snapshot_id="5" category="VERSION" description="[null]"
           event_date="1228222680000" created_at="1228222680000" event_data="[null]"/>
   <duplications_index id="2" project_snapshot_id="5" snapshot_id="5" hash="bb" index_in_file="0" start_line="0"
                       end_line="0"/>
index 4a45a7fc40593b43add3f575d8c67971992879c8..8ca10cdab74dba5c805b15fa8d53411bf9a819c3 100644 (file)
@@ -41,7 +41,7 @@ Note that measures, events and reviews are not deleted.
   <!--parent_dependency_id="[null]" project_snapshot_id="2"-->
   <!--dep_usage="USES" dep_weight="1" from_scope="LIB" to_scope="PRJ"/>-->
 
-  <events id="1" resource_id="1" snapshot_id="1"
+  <events id="1" component_uuid="1" snapshot_id="1"
           category="VERSION" description="[null]" name="Version 1.0" event_date="1228222680000"
           created_at="1228222680000"
           event_data="[null]"/>
@@ -80,7 +80,7 @@ Note that measures, events and reviews are not deleted.
                 parent_dependency_id="[null]" project_snapshot_id="2"
                 dep_usage="USES" dep_weight="1" from_scope="LIB" to_scope="PRJ"/>
 
-  <events id="2" resource_id="2" snapshot_id="2"
+  <events id="2" component_uuid="2" snapshot_id="2"
           category="VERSION" description="[null]" name="Version 1.0" event_date="1228222680000"
           created_at="1228222680000"
           event_data="[null]"/>
index 6c6e5bd44c254521780afdd7ec7dbc5840cc6f25..00253585b495d7b40cced5145ee946bf17b1f643 100644 (file)
@@ -26,7 +26,7 @@
                 parent_dependency_id="[null]" project_snapshot_id="2"
                 dep_usage="USES" dep_weight="1" from_scope="LIB" to_scope="PRJ"/>
 
-  <events id="1" resource_id="1" snapshot_id="1"
+  <events id="1" component_uuid="1" snapshot_id="1"
           category="VERSION" description="[null]" name="Version 1.0" event_date="1228222680000"
           created_at="1228222680000"
           event_data="[null]"/>
@@ -64,7 +64,7 @@
                 parent_dependency_id="[null]" project_snapshot_id="2"
                 dep_usage="USES" dep_weight="1" from_scope="LIB" to_scope="PRJ"/>
 
-  <events id="2" resource_id="2" snapshot_id="2"
+  <events id="2" component_uuid="2" snapshot_id="2"
           category="VERSION" description="[null]" name="Version 1.0" event_date="1228222680000"
           created_at="1228222680000"
           event_data="[null]"/>
index 78e14ead2a70df5b0a3ad5ec6b02ca16ff6901e8..6a924f7f98a082283d7751508cc06f03900aeea8 100644 (file)
@@ -55,7 +55,7 @@
              period5_mode="[null]" period5_param="[null]" period5_date="[null]"
              depth="[null]" scope="PRJ" qualifier="TRK" created_at="1228222680000" build_date="1228222680000" version="[null]" path="[null]"/>
 
-  <events id="2" resource_id="1" snapshot_id="5"
+  <events id="2" component_uuid="1" snapshot_id="5"
           category="Version" description="[null]" name="Version 1.0" event_date="1228222680000" created_at="1228222680000"
           event_data="[null]"/>
 
index eb4db71fe41748022ca33504dee7a4e0692f8536..1e756c3f6bdb5b5d527cc1464b77348e50a7eb5e 100644 (file)
@@ -21,9 +21,11 @@ package org.sonar.api.batch;
 
 import org.apache.commons.lang.builder.ToStringBuilder;
 import org.sonar.api.database.BaseIdentifiable;
+import org.sonar.api.database.model.ResourceModel;
 import org.sonar.api.database.model.Snapshot;
 
 import javax.persistence.*;
+
 import java.util.Date;
 
 import static com.google.common.base.Preconditions.checkNotNull;
@@ -61,8 +63,12 @@ public class Event extends BaseIdentifiable {
   @JoinColumn(name = "snapshot_id", updatable = true, nullable = true)
   private Snapshot snapshot;
 
-  @Column(name = "resource_id", updatable = true, nullable = true)
-  private Integer resourceId;
+  @ManyToOne(fetch = FetchType.LAZY)
+  @JoinColumn(name = "component_uuid", referencedColumnName = "uuid", insertable = false, updatable = false, nullable = false)
+  private ResourceModel resource;
+
+  @Column(name = "component_uuid", updatable = true, nullable = true)
+  private String componentUuid;
 
   public Event() {
   }
@@ -128,16 +134,23 @@ public class Event extends BaseIdentifiable {
   public final void setSnapshot(Snapshot snapshot) {
     this.snapshot = checkNotNull(snapshot, "it is not possible to set a null snapshot linked to an event");
     this.date = snapshot.getCreatedAtMs();
-    this.resourceId = snapshot.getResourceId();
+//    this.resourceId = snapshot.getResourceId();
+  }
+
+  public ResourceModel getResource() {
+    return resource;
+  }
+
+  public void setResource(ResourceModel resource) {
+    this.resource = resource;
   }
 
-  public Integer getResourceId() {
-    return resourceId;
+  public String getComponentUuid() {
+    return componentUuid;
   }
 
-  public Event setResourceId(Integer resourceId) {
-    this.resourceId = resourceId;
-    return this;
+  public void setComponentUuid(String componentUuid) {
+    this.componentUuid = componentUuid;
   }
 
   public String getData() {
@@ -155,7 +168,7 @@ public class Event extends BaseIdentifiable {
       .append("categ", category)
       .append("date", date)
       .append("snapshot", snapshot)
-      .append("resource", resourceId)
+      .append("resource", resource)
       .toString();
   }
 }
index d8b080cdab4775cdc4f1e8cf2b3a8a3f5ec5ea0d..832885dfc8a321d6d6cbe0e421f2f690780fe6f8 100644 (file)
@@ -30,6 +30,7 @@ import org.sonar.api.resources.Resource;
 import javax.annotation.Nullable;
 import javax.persistence.*;
 
+import java.io.Serializable;
 import java.util.Date;
 
 /**
@@ -37,7 +38,7 @@ import java.util.Date;
  */
 @Entity
 @Table(name = "projects")
-public class ResourceModel extends BaseIdentifiable implements Cloneable {
+public class ResourceModel extends BaseIdentifiable implements Cloneable, Serializable {
 
   public static final String SCOPE_PROJECT = "PRJ";
   public static final String QUALIFIER_PROJECT_TRUNK = "TRK";