]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-6163 - timezones - events migration 86/head
authorTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Wed, 11 Feb 2015 14:05:15 +0000 (15:05 +0100)
committerTeryk Bellahsene <teryk.bellahsene@sonarsource.com>
Tue, 17 Feb 2015 16:34:37 +0000 (17:34 +0100)
33 files changed:
plugins/sonar-core-plugin/src/main/resources/org/sonar/plugins/core/widgets/timeline.html.erb
server/sonar-server/src/main/java/org/sonar/server/db/migrations/DatabaseMigrations.java
server/sonar-server/src/main/java/org/sonar/server/db/migrations/v51/FeedEventsLongDates.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/db/migrations/v51/FeedManualMeasuresLongDates.java
server/sonar-server/src/main/java/org/sonar/server/db/migrations/v51/FeedProjectMeasuresLongDates.java
server/sonar-server/src/test/java/org/sonar/server/db/migrations/v51/FeedEventsLongDatesTest.java [new file with mode: 0644]
server/sonar-server/src/test/java/org/sonar/server/db/migrations/v51/FeedManualMeasuresLongDatesTest.java
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v51/FeedEventsLongDatesTest/before.xml [new file with mode: 0644]
server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v51/FeedEventsLongDatesTest/schema.sql [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/models/event.rb
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/791_add_events_long_dates.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/792_feed_events_long_dates.rb [new file with mode: 0644]
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/793_rename_events_long_dates.rb [new file with mode: 0644]
sonar-batch/src/main/java/org/sonar/batch/deprecated/DeprecatedSensorContext.java
sonar-batch/src/main/java/org/sonar/batch/index/DefaultIndex.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/persistence/DatabaseVersion.java
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/test/java/org/sonar/core/purge/PurgeCommandsTest.java
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/batch/SensorContext.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/SonarIndex.java

index 18c5d7785a2edff1a39b4a818dded2a9ba729afa..55ce78fe4d6c9daf8fa37d4677961a62c69df854 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], :order => 'event_date').each() do |event|
+       Event.find(:all, :conditions => ["resource_id=? AND event_date>=?", @resource.id, from_date.to_i*1000], :order => 'event_date').each() do |event|
          if events[event.event_date]
            events[event.event_date] << event
          else
index dd8a452b74cc732c6d5dac00b73289ce3de53acf..661fff4fcfb7b46b4f2b2bd43d04fa3330b574c9 100644 (file)
@@ -90,6 +90,7 @@ public interface DatabaseMigrations {
     FeedFileSourcesBinaryData.class,
     FeedSemaphoresLongDates.class,
     FeedProjectMeasuresLongDates.class,
-    FeedManualMeasuresLongDates.class
+    FeedManualMeasuresLongDates.class,
+    FeedEventsLongDates.class
     );
 }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v51/FeedEventsLongDates.java b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v51/FeedEventsLongDates.java
new file mode 100644 (file)
index 0000000..239b16f
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * 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.v51;
+
+import org.sonar.api.utils.System2;
+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;
+import java.util.Date;
+
+public class FeedEventsLongDates extends BaseDataChange {
+
+  private final System2 system2;
+
+  public FeedEventsLongDates(Database db, System2 system2) {
+    super(db);
+    this.system2 = system2;
+  }
+
+  @Override
+  public void execute(Context context) throws SQLException {
+    MassUpdate massUpdate = context.prepareMassUpdate();
+    massUpdate
+      .select("SELECT e.event_date, e.created_at, e.id FROM events e WHERE event_date_ms IS NULL");
+    massUpdate
+      .update("UPDATE events SET event_date_ms=?, created_at_ms=? WHERE id=?");
+    massUpdate.rowPluralName("events");
+    massUpdate.execute(new EventDateHandler(system2.now()));
+  }
+
+  private static class EventDateHandler implements MassUpdate.Handler {
+
+    private final long now;
+
+    public EventDateHandler(long now) {
+      this.now = now;
+    }
+
+    @Override
+    public boolean handle(Select.Row row, SqlStatement update) throws SQLException {
+      Date eventDate = row.getDate(1);
+      long eventTime = eventDate == null ? now : Math.min(now, eventDate.getTime());
+      update.setLong(1, eventTime);
+      Date createdAt = row.getDate(2);
+      update.setLong(2, createdAt == null ? eventTime : Math.min(now, createdAt.getTime()));
+
+      Long id = row.getLong(3);
+      update.setLong(3, id);
+
+      return true;
+    }
+  }
+
+}
index 78529fcfa6c4bf0dda3315081681cd9696f8afd3..2244c603065cf9d7b88c9d4f8bbdedf11203405a 100644 (file)
@@ -47,7 +47,7 @@ public class FeedManualMeasuresLongDates extends BaseDataChange {
       .select("SELECT m.created_at, m.updated_at, m.id FROM manual_measures m WHERE created_at_ms IS NULL");
     massUpdate
       .update("UPDATE manual_measures SET created_at_ms=?, updated_at_ms=? WHERE id=?");
-    massUpdate.rowPluralName("manualMeasures");
+    massUpdate.rowPluralName("manual measures");
     massUpdate.execute(new MassUpdate.Handler() {
       @Override
       public boolean handle(Select.Row row, SqlStatement update) throws SQLException {
index 6cea58309dc9a61cca5797504ebdcf4040e56494..00e00feccbfeddb930f10302bbaf1a580d01d8b5 100644 (file)
@@ -47,7 +47,7 @@ public class FeedProjectMeasuresLongDates extends BaseDataChange {
       .select("SELECT m.measure_date, m.id FROM project_measures m WHERE measure_date_ms IS NULL");
     massUpdate
       .update("UPDATE project_measures SET measure_date_ms=? WHERE id=?");
-    massUpdate.rowPluralName("projectMeasures");
+    massUpdate.rowPluralName("project measures");
     massUpdate.execute(new MassUpdate.Handler() {
       @Override
       public boolean handle(Select.Row row, SqlStatement update) throws SQLException {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v51/FeedEventsLongDatesTest.java b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v51/FeedEventsLongDatesTest.java
new file mode 100644 (file)
index 0000000..4076ba2
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * 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.v51;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.api.utils.System2;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.db.migrations.DatabaseMigration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.utils.DateUtils.parseDate;
+
+public class FeedEventsLongDatesTest {
+  @ClassRule
+  public static DbTester db = new DbTester().schema(FeedEventsLongDatesTest.class, "schema.sql");
+
+  @Before
+  public void before() throws Exception {
+    db.prepareDbUnit(getClass(), "before.xml");
+  }
+
+  @Test
+  public void execute() throws Exception {
+    DatabaseMigration migration = newMigration(System2.INSTANCE);
+
+    migration.execute();
+
+    int count = db
+      .countSql("select count(*) from events where " +
+        "created_at_ms is not null " +
+        "and event_date_ms is not null");
+    assertThat(count).isEqualTo(3);
+  }
+
+  @Test
+  public void take_now_if_date_in_the_future() throws Exception {
+    System2 system = mock(System2.class);
+    when(system.now()).thenReturn(1234L);
+
+    DatabaseMigration migration = newMigration(system);
+
+    migration.execute();
+
+    int count = db
+      .countSql("select count(*) from events where " +
+        "created_at_ms = 1234");
+    assertThat(count).isEqualTo(2);
+  }
+
+  @Test
+  public void take_date_if_in_the_past() throws Exception {
+    DatabaseMigration migration = newMigration(System2.INSTANCE);
+
+    migration.execute();
+
+    long time = parseDate("2014-09-25").getTime();
+    int count = db
+      .countSql("select count(*) from events where " +
+        "created_at_ms=" + time);
+    assertThat(count).isEqualTo(1);
+  }
+
+  private DatabaseMigration newMigration(System2 system) {
+    return new FeedEventsLongDates(db.database(), system);
+  }
+}
index c3b2a47c45d7844cd46f7cdfec7a34672575fea1..d91efe790242415f6a4f70eb771739d02c46f5d2 100644 (file)
@@ -70,7 +70,7 @@ public class FeedManualMeasuresLongDatesTest {
   }
 
   @Test
-  public void take_snapshot_date_if_in_the_past() throws Exception {
+  public void take_manual_measure_date_if_in_the_past() throws Exception {
     DatabaseMigration migration = newMigration(System2.INSTANCE);
 
     migration.execute();
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v51/FeedEventsLongDatesTest/before.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v51/FeedEventsLongDatesTest/before.xml
new file mode 100644 (file)
index 0000000..52ad14d
--- /dev/null
@@ -0,0 +1,28 @@
+<dataset>
+  <!-- new migration -->
+  <events
+      id="1"
+      created_at="2014-09-25"
+      created_at_ms="[null]"
+      event_date="2014-09-25"
+      event_date_ms="[null]"
+      />
+
+  <!-- re-entrant migration - ignore the ones that are already fed with new dates -->
+  <events
+      id="2"
+      created_at="2014-09-25"
+      created_at_ms="1500000000"
+      event_date="2014-09-25"
+      event_date_ms="1500000000"
+      />
+
+  <!-- NULL dates -->
+  <events
+      id="3"
+      created_at="[null]"
+      created_at_ms="[null]"
+      event_date="[null]"
+      event_date_ms="[null]"
+      />
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v51/FeedEventsLongDatesTest/schema.sql b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v51/FeedEventsLongDatesTest/schema.sql
new file mode 100644 (file)
index 0000000..71ac42d
--- /dev/null
@@ -0,0 +1,7 @@
+CREATE TABLE "EVENTS" (
+  "ID" BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+  "CREATED_AT" TIMESTAMP,
+  "CREATED_AT_MS" BIGINT,
+  "EVENT_DATE" TIMESTAMP,
+  "EVENT_DATE_MS" BIGINT
+);
index ebf29970d0959c4869d1f4e19be07d772310e0a6..e6d4696c397d8a7ca2ee8c41ec6e296a8ead64dc 100644 (file)
@@ -51,7 +51,7 @@ class Api::EventsController < Api::ApiController
       end
       if from
         conditions<<'event_date>=:from'
-        values[:from]=from
+        values[:from]=from.to_i*1000
       end
 
       to=nil
@@ -62,7 +62,7 @@ class Api::EventsController < Api::ApiController
       end
       if to
         conditions<<'event_date<=:to'
-        values[:to]=to
+        values[:to]=to.to_i*1000
       end
 
       events=Event.find(:all, :conditions => [conditions.join(' AND '), values], :order => 'event_date DESC')
index 97d5c277e7ac052ed2ed48abcd425fa4a8269208..d5349ebaad34346b9f2437ad8243f25cb348a1da 100644 (file)
@@ -27,6 +27,27 @@ class Event < ActiveRecord::Base
   belongs_to :snapshot
 
   before_save :populate_snapshot
+  
+  def created_at
+    long_to_date(:created_at)
+  end
+  
+  def created_at=(date)
+    write_attribute(:created_at, date.to_i*1000)
+  end
+  
+  def event_date
+    long_to_date(:event_date)
+  end
+  
+  def event_date=(date)
+    write_attribute(:event_date, date.to_i*1000)
+  end
+  
+  def long_to_date(attribute)
+    date_in_long = read_attribute(attribute)
+    Time.at(date_in_long/1000) if date_in_long
+  end
 
   def fullname
     if category
@@ -59,10 +80,8 @@ class Event < ActiveRecord::Base
     return false
   end
   
-  #
-  # TODO: Remove this code when everything has been checked on the Event handling, both on the UI and the WS API
-  #
   def populate_snapshot
+    self.created_at=DateTime.now unless self.created_at
     self.snapshot=Snapshot.snapshot_by_date(resource_id, event_date) unless self.snapshot
   end
 end
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/791_add_events_long_dates.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/791_add_events_long_dates.rb
new file mode 100644 (file)
index 0000000..ae4f097
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# 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.1
+#
+class AddEventsLongDates < ActiveRecord::Migration
+  def self.up
+    add_column 'events', :event_date_ms, :big_integer, :null => true
+    add_column 'events', :created_at_ms, :big_integer, :null => true
+  end
+end
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/792_feed_events_long_dates.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/792_feed_events_long_dates.rb
new file mode 100644 (file)
index 0000000..b058d46
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# 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.1
+#
+class FeedEventsLongDates < ActiveRecord::Migration
+  def self.up
+    execute_java_migration('org.sonar.server.db.migrations.v51.FeedEventsLongDates')
+  end
+end
+
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/793_rename_events_long_dates.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/793_rename_events_long_dates.rb
new file mode 100644 (file)
index 0000000..a46e2a5
--- /dev/null
@@ -0,0 +1,34 @@
+#
+# 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.1
+#
+class RenameEventsLongDates < ActiveRecord::Migration
+  def self.up
+    remove_column 'events', 'created_at'
+    remove_column 'events', 'event_date'
+    rename_column 'events', 'created_at_ms', 'created_at'
+    rename_column 'events', 'event_date_ms', 'event_date'
+    change_column 'events', 'created_at', :big_integer, :null => false
+    change_column 'events', 'event_date', :big_integer, :null => false
+  end
+end
+
index 2b309da11000b399d7a5a6344e349e2ed9fbc690..6c7146c6e61eb16e95279bae63305cfc27b27ad6 100644 (file)
@@ -37,12 +37,7 @@ import org.sonar.api.design.Dependency;
 import org.sonar.api.measures.Measure;
 import org.sonar.api.measures.MeasuresFilter;
 import org.sonar.api.measures.Metric;
-import org.sonar.api.resources.Directory;
-import org.sonar.api.resources.File;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.ProjectLink;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.resources.Resource;
+import org.sonar.api.resources.*;
 import org.sonar.api.rules.Violation;
 import org.sonar.api.utils.SonarException;
 import org.sonar.batch.duplication.DuplicationCache;
@@ -50,6 +45,8 @@ import org.sonar.batch.index.ComponentDataCache;
 import org.sonar.batch.sensor.DefaultSensorContext;
 import org.sonar.batch.sensor.coverage.CoverageExclusions;
 
+import javax.annotation.Nullable;
+
 import java.io.Serializable;
 import java.util.Collection;
 import java.util.Date;
@@ -255,7 +252,7 @@ public class DeprecatedSensorContext extends DefaultSensorContext implements Sen
   }
 
   @Override
-  public Event createEvent(Resource resource, String name, String description, String category, Date date) {
+  public Event createEvent(Resource resource, String name, String description, String category, @Nullable Date date) {
     return index.addEvent(resource, name, description, category, date);
   }
 
index 4cc275dc4aa1537c7d7bf1e7a5d1e8a0dc6354f5..e551d46250796f005accd18c9d19b3ee918883cc 100644 (file)
@@ -38,14 +38,7 @@ import org.sonar.api.measures.CoreMetrics;
 import org.sonar.api.measures.Measure;
 import org.sonar.api.measures.MeasuresFilter;
 import org.sonar.api.measures.MeasuresFilters;
-import org.sonar.api.resources.Directory;
-import org.sonar.api.resources.File;
-import org.sonar.api.resources.Project;
-import org.sonar.api.resources.ProjectLink;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.resources.Resource;
-import org.sonar.api.resources.ResourceUtils;
-import org.sonar.api.resources.Scopes;
+import org.sonar.api.resources.*;
 import org.sonar.api.rules.Rule;
 import org.sonar.api.rules.Violation;
 import org.sonar.api.scan.filesystem.PathResolver;
@@ -59,16 +52,7 @@ import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 
 public class DefaultIndex extends SonarIndex {
 
@@ -103,7 +87,11 @@ public class DefaultIndex extends SonarIndex {
 
   private final ResourceCache resourceCache;
   private final MetricFinder metricFinder;
-
+  private final MeasureCache measureCache;
+  private final ResourceKeyMigration migration;
+  private final DependencyPersister dependencyPersister;
+  private final LinkPersister linkPersister;
+  private final EventPersister eventPersister;
   // caches
   private Project currentProject;
   private Map<Resource, Bucket> buckets = Maps.newLinkedHashMap();
@@ -112,11 +100,6 @@ public class DefaultIndex extends SonarIndex {
   private Map<Resource, Map<Resource, Dependency>> incomingDependenciesByResource = Maps.newLinkedHashMap();
   private ProjectTree projectTree;
   private ModuleIssues moduleIssues;
-  private final MeasureCache measureCache;
-  private final ResourceKeyMigration migration;
-  private final DependencyPersister dependencyPersister;
-  private final LinkPersister linkPersister;
-  private final EventPersister eventPersister;
 
   public DefaultIndex(ResourceCache resourceCache, DependencyPersister dependencyPersister,
     LinkPersister linkPersister, EventPersister eventPersister, ProjectTree projectTree, MetricFinder metricFinder,
@@ -476,10 +459,11 @@ public class DefaultIndex extends SonarIndex {
   }
 
   @Override
-  public Event addEvent(Resource resource, String name, String description, String category, Date date) {
+  public Event addEvent(Resource resource, String name, String description, String category, @Nullable Date date) {
     Event event = new Event(name, description, category);
-    event.setDate(date);
-    event.setCreatedAt(new Date());
+    if (date != null) {
+      event.setDate(date);
+    }
 
     if (eventPersister != null) {
       eventPersister.saveEvent(resource, event);
index b01efa10063668887aa730845c9debb56d2bf99c..8ee521c247e911af7b9f0e9759abcf5c817547aa 100644 (file)
@@ -22,16 +22,22 @@ package org.sonar.batch.index;
 import org.sonar.api.batch.Event;
 import org.sonar.api.database.DatabaseSession;
 import org.sonar.api.resources.Resource;
+import org.sonar.api.utils.System2;
 
+import java.util.Date;
 import java.util.List;
 
+import static com.google.common.base.Preconditions.checkState;
+
 public class EventPersister {
+  private final System2 system2;
   private DatabaseSession session;
   private ResourceCache resourceCache;
 
-  public EventPersister(DatabaseSession session, ResourceCache resourceCache) {
+  public EventPersister(DatabaseSession session, ResourceCache resourceCache, System2 system2) {
     this.session = session;
     this.resourceCache = resourceCache;
+    this.system2 = system2;
   }
 
   public List<Event> getEvents(Resource resource) {
@@ -45,16 +51,16 @@ public class EventPersister {
 
   public void saveEvent(Resource resource, Event event) {
     BatchResource batchResource = resourceCache.get(resource.getEffectiveKey());
-    if (batchResource == null) {
-      throw new IllegalStateException("Unknow component: " + resource);
-    }
+    checkState(batchResource != null, "Unknown component: " + resource);
+
+    event.setCreatedAt(new Date(system2.now()));
     if (event.getDate() == null) {
       event.setSnapshot(batchResource.snapshot());
     } else {
       event.setResourceId(batchResource.resource().getId());
     }
+
     session.save(event);
     session.commit();
-
   }
 }
index 2f01f86b9898660019c4c5db6c61886ebceaa1a8..480b91f147e715cc1fd4093525a62935411465aa 100644 (file)
              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="2008-11-03 13:58:00.00" created_at="2008-11-03 13:58:00.00" description=""
+  <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="4" name="Bar" resource_id="1" snapshot_id="1001" category="Other" event_date="2008-11-05 13:58:00.00" created_at="2008-11-05 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=""
           event_data="[null]"/>
-  <events id="5" name="Uhh" resource_id="1" snapshot_id="1002" category="Other" event_date="2008-11-07 13:58:00.00" created_at="2008-11-07 13:58:00.00" description=""
+  <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="2008-11-09 13:58:00.00" created_at="2008-11-09 13:58:00.00" description=""
+  <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]"/>
 
 </dataset>
index d990e648414c0623247731aa1b2bd6e1c52b573e..bc3a3c9c0551d8643d23e3a91748016604d830b6 100644 (file)
              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="2008-11-02 13:58:00.00" created_at="2008-11-02 13:58:00.00" description=""
+  <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="2008-11-03 13:58:00.00" created_at="2008-11-03 13:58:00.00" description=""
+  <events id="2" name="Foo" resource_id="1" 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="2008-11-05 13:58:00.00" created_at="2008-11-05 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=""
           event_data="[null]"/>
-  <events id="5" name="Uhh" resource_id="1" snapshot_id="1002" category="Other" event_date="2008-11-07 13:58:00.00" created_at="2008-11-07 13:58:00.00" description=""
+  <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="2008-11-09 13:58:00.00" created_at="2008-11-09 13:58:00.00" description=""
+  <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]"/>
 
 </dataset>
index 5ecbc2fa9598d370dcf881915e6ffbe832656315..6efee1a0f516008d17d2ab70029392f25de11649 100644 (file)
              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="2008-11-02 13:58:00.00" created_at="2008-11-02 13:58:00.00" description="" event_data="[null]"/>
-  <events id="2" name="Foo" resource_id="1" snapshot_id="1000" category="Other" event_date="2008-11-03 13:58:00.00" created_at="2008-11-03 13:58:00.00" description="" event_data="[null]"/>
-  <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="" event_data="[null]"/>
-  <events id="4" name="Bar" resource_id="1" snapshot_id="1001" category="Other" event_date="2008-11-05 13:58:00.00" created_at="2008-11-05 13:58:00.00" description="" event_data="[null]"/>
-  <events id="5" name="Uhh" resource_id="1" snapshot_id="1002" category="Other" event_date="2008-11-07 13:58:00.00" created_at="2008-11-07 13:58:00.00" description="" event_data="[null]"/>
-  <events id="6" name="1.2-SNAPSHOT" resource_id="1" snapshot_id="1003" category="Version" event_date="2008-11-09 13:58:00.00" created_at="2008-11-09 13:58:00.00" description="" event_data="[null]"/>
+  <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]"/>
 
 </dataset>
index 048e602afe97f641f58c1412527c88c98172579d..790209ba8b069c38cedff532ca2262b734b4d4ab 100644 (file)
@@ -33,7 +33,7 @@ import java.util.List;
  */
 public class DatabaseVersion implements BatchComponent, ServerComponent {
 
-  public static final int LAST_VERSION = 790;
+  public static final int LAST_VERSION = 793;
 
   /**
    * List of all the tables.n
index af6b0b2df0078a60f79126c21c4d97f993bf4831..c44b9b31dd49d6f12b55dbd24dacae7424d9a660 100644 (file)
@@ -317,6 +317,9 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('787');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('788');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('789');
 INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('790');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('791');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('792');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('793');
 
 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 484d9265b83d7a9e4df7331eb6276c335b18e60d..86d2134ef546ddf2a25e64178fa3e0f0c58f2105 100644 (file)
@@ -167,8 +167,8 @@ CREATE TABLE "EVENTS" (
   "RESOURCE_ID" INTEGER,
   "SNAPSHOT_ID" INTEGER,
   "CATEGORY" VARCHAR(50),
-  "EVENT_DATE" TIMESTAMP,
-  "CREATED_AT" TIMESTAMP,
+  "EVENT_DATE" BIGINT NOT NULL,
+  "CREATED_AT" BIGINT NOT NULL,
   "DESCRIPTION" VARCHAR(4000),
   "EVENT_DATA"  VARCHAR(4000)
 );
index d7d285e42faa8dd44d1155489886aa06875f1299..693ea65a44721c257aa204c6b78f93b9d94e717a 100644 (file)
@@ -115,12 +115,10 @@ public class PurgeCommandsTest extends AbstractDaoTestCase {
   @Test
   public void shouldDeleteResource() {
     setupData("shouldDeleteResource");
-    SqlSession session = getMyBatis().openSession();
-    try {
+    try (SqlSession session = getMyBatis().openSession()) {
       new PurgeCommands(session, profiler).deleteResources(newArrayList(new IdUuidPair(1L, "1")));
-    } finally {
-      MyBatis.closeQuietly(session);
     }
+
     assertEmptyTables("projects", "snapshots", "events", "issues", "issue_changes", "authors");
   }
 
index e7d8f49a2b4da0791855dac8630191f1cdfd276c..2f30df757d09d9682419894bff09470db0d18037 100644 (file)
@@ -16,7 +16,7 @@
              version="[null]" path="[null]"/>
 
   <events id="1" name="Version 1.0" resource_id="1" snapshot_id="1" category="VERSION" description="[null]"
-          event_date="2008-12-02 13:58:00.00" created_at="[null]" event_data="[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"
           severity="BLOCKER"
index 3bac29d413a18a5542e6f9417115df71fbfb33a4..f7a0a3a81b35a2d78d63c0426fbb67cb2d3519ce 100644 (file)
@@ -26,7 +26,7 @@
                 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]"
-          event_date="2008-12-02 13:58:00.00" created_at="[null]" event_data="[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"/>
 </dataset>
index 8fd273d1c0813efe525f64c1e7e4e11eb119e93c..45eaee581634cb81eec24d6e6ba4e6235c981b56 100644 (file)
@@ -25,7 +25,7 @@
                 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]"
-          event_date="2008-12-02 13:58:00.00" created_at="[null]" event_data="[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"/>
 
@@ -58,7 +58,7 @@
                 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]"
-          event_date="2008-12-02 13:58:00.00" created_at="[null]" event_data="[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 bcd5544b9f6a9b4afddf952a47c7f24ab5599e85..4a45a7fc40593b43add3f575d8c67971992879c8 100644 (file)
@@ -42,8 +42,8 @@ Note that measures, events and reviews are not deleted.
   <!--dep_usage="USES" dep_weight="1" from_scope="LIB" to_scope="PRJ"/>-->
 
   <events id="1" resource_id="1" snapshot_id="1"
-          category="VERSION" description="[null]" name="Version 1.0" event_date="2008-12-02 13:58:00.00"
-          created_at="[null]"
+          category="VERSION" description="[null]" name="Version 1.0" event_date="1228222680000"
+          created_at="1228222680000"
           event_data="[null]"/>
 
   <!--<duplications_index id="1" project_snapshot_id="1" snapshot_id="1"-->
@@ -81,8 +81,8 @@ Note that measures, events and reviews are not deleted.
                 dep_usage="USES" dep_weight="1" from_scope="LIB" to_scope="PRJ"/>
 
   <events id="2" resource_id="2" snapshot_id="2"
-          category="VERSION" description="[null]" name="Version 1.0" event_date="2008-12-02 13:58:00.00"
-          created_at="[null]"
+          category="VERSION" description="[null]" name="Version 1.0" event_date="1228222680000"
+          created_at="1228222680000"
           event_data="[null]"/>
 
   <duplications_index id="2" project_snapshot_id="2" snapshot_id="2"
index 5a576b3edf8e75d0bb9030935a11a73952529ba7..6c6e5bd44c254521780afdd7ec7dbc5840cc6f25 100644 (file)
@@ -27,8 +27,8 @@
                 dep_usage="USES" dep_weight="1" from_scope="LIB" to_scope="PRJ"/>
 
   <events id="1" resource_id="1" snapshot_id="1"
-          category="VERSION" description="[null]" name="Version 1.0" event_date="2008-12-02 13:58:00.00"
-          created_at="[null]"
+          category="VERSION" description="[null]" name="Version 1.0" event_date="1228222680000"
+          created_at="1228222680000"
           event_data="[null]"/>
 
   <duplications_index id="1" project_snapshot_id="1" snapshot_id="1"
@@ -65,8 +65,8 @@
                 dep_usage="USES" dep_weight="1" from_scope="LIB" to_scope="PRJ"/>
 
   <events id="2" resource_id="2" snapshot_id="2"
-          category="VERSION" description="[null]" name="Version 1.0" event_date="2008-12-02 13:58:00.00"
-          created_at="[null]"
+          category="VERSION" description="[null]" name="Version 1.0" event_date="1228222680000"
+          created_at="1228222680000"
           event_data="[null]"/>
 
   <duplications_index id="2" project_snapshot_id="2" snapshot_id="2"
index f3a3b9bd0b33e47d3714f63ccab5975f09059133..78e14ead2a70df5b0a3ad5ec6b02ca16ff6901e8 100644 (file)
@@ -56,7 +56,7 @@
              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"
-          category="Version" description="[null]" name="Version 1.0" event_date="2008-12-02 13:58:00.00" created_at="[null]"
+          category="Version" description="[null]" name="Version 1.0" event_date="1228222680000" created_at="1228222680000"
           event_data="[null]"/>
 
 </dataset>
index 8c802c2ca9813aa0d8040f0180b2b00c284ce85d..eb4db71fe41748022ca33504dee7a4e0692f8536 100644 (file)
@@ -26,6 +26,9 @@ import org.sonar.api.database.model.Snapshot;
 import javax.persistence.*;
 import java.util.Date;
 
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.sonar.api.utils.DateUtils.longToDate;
+
 /**
  * @since 1.10
  */
@@ -46,10 +49,10 @@ public class Event extends BaseIdentifiable {
   private String category;
 
   @Column(name = "event_date", updatable = true, nullable = false)
-  private Date date;
+  private Long date;
 
-  @Column(name = "created_at", updatable = true, nullable = true)
-  private Date createdAt;
+  @Column(name = "created_at", updatable = true, nullable = false)
+  private Long createdAt;
 
   @Column(name = "event_data", updatable = true, nullable = true)
   private String data;
@@ -103,11 +106,11 @@ public class Event extends BaseIdentifiable {
   }
 
   public Date getDate() {
-    return date;
+    return longToDate(date);
   }
 
   public void setDate(Date date) {
-    this.date = date;
+    this.date = date.getTime();
   }
 
   public Snapshot getSnapshot() {
@@ -115,19 +118,17 @@ public class Event extends BaseIdentifiable {
   }
 
   public Date getCreatedAt() {
-    return createdAt;
+    return new Date(createdAt);
   }
 
   public void setCreatedAt(Date createdAt) {
-    this.createdAt = createdAt;
+    this.createdAt = createdAt.getTime();
   }
 
   public final void setSnapshot(Snapshot snapshot) {
-    this.snapshot = snapshot;
-    if (snapshot != null) {
-      this.date = (snapshot.getCreatedAtMs() == null ? null : new Date(snapshot.getCreatedAtMs()));
-      this.resourceId = snapshot.getResourceId();
-    }
+    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();
   }
 
   public Integer getResourceId() {
index b75209e1538845150add6173f54ae7547ee58b91..00fd00d8314730f38f8b29da9bf4362f4a8ecca8 100644 (file)
@@ -30,6 +30,7 @@ import org.sonar.api.resources.Resource;
 import org.sonar.api.rules.Violation;
 
 import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
 
 import java.io.Serializable;
 import java.util.Collection;
@@ -242,7 +243,7 @@ public interface SensorContext extends org.sonar.api.batch.sensor.SensorContext
    * @param date        the event date
    * @return the created event
    */
-  Event createEvent(Resource resource, String name, String description, String category, Date date);
+  Event createEvent(Resource resource, String name, @Nullable String description, String category, @Nullable Date date);
 
   /**
    * Deletes an event
index f21b83bab5fb1788777037829beb5d9c87e49012..6714ed9c1bb0cd2979f8dea1ef4a3b18e1887d09 100644 (file)
@@ -30,6 +30,7 @@ import org.sonar.api.rules.Violation;
 import org.sonar.graph.DirectedGraphAccessor;
 
 import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
 
 import java.util.Collection;
 import java.util.Date;
@@ -155,7 +156,7 @@ public abstract class SonarIndex implements DirectedGraphAccessor<Resource, Depe
 
   public abstract void deleteEvent(Event event);
 
-  public abstract Event addEvent(Resource resource, String name, String description, String category, Date date);
+  public abstract Event addEvent(Resource resource, String name, String description, String category, @Nullable Date date);
 
   public final Collection<Dependency> getOutgoingDependencies(Resource from) {
     return getOutgoingEdges(from);