]> source.dussan.org Git - sonarqube.git/commitdiff
Centralize algorithm of UUID generation
authorSimon Brandhof <simon.brandhof@sonarsource.com>
Fri, 21 Nov 2014 09:58:48 +0000 (10:58 +0100)
committerSimon Brandhof <simon.brandhof@sonarsource.com>
Fri, 21 Nov 2014 10:08:41 +0000 (11:08 +0100)
17 files changed:
server/sonar-server/src/main/java/org/sonar/server/component/DefaultRubyComponentService.java
server/sonar-server/src/main/java/org/sonar/server/db/migrations/v36/ViolationConverter.java
server/sonar-server/src/main/java/org/sonar/server/db/migrations/v50/PopulateProjectsUuidColumnsMigration.java
server/sonar-web/src/main/webapp/WEB-INF/db/migrate/394_add_key_to_action_plan.rb
sonar-batch/src/main/java/org/sonar/batch/index/DefaultResourcePersister.java
sonar-core/pom.xml
sonar-core/src/main/java/org/sonar/core/activity/db/ActivityDto.java
sonar-core/src/main/java/org/sonar/core/issue/ActionPlanStats.java
sonar-core/src/main/java/org/sonar/core/issue/DefaultActionPlan.java
sonar-core/src/main/java/org/sonar/core/issue/DefaultIssueBuilder.java
sonar-core/src/main/java/org/sonar/core/issue/db/IssueDto.java
sonar-core/src/main/java/org/sonar/core/resource/ResourceDao.java
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssue.java
sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/DefaultIssueComment.java
sonar-plugin-api/src/main/java/org/sonar/api/platform/ComponentKeys.java
sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/Uuids.java [new file with mode: 0644]
sonar-plugin-api/src/test/java/org/sonar/api/utils/internal/UuidsTest.java [new file with mode: 0644]

index 63d6e09cccf2849fb9005874c322dfd3b27f3c86..8184d2cae0c2fd4c48c4e53418de039f2dafbddc 100644 (file)
@@ -25,6 +25,7 @@ import org.sonar.api.component.RubyComponentService;
 import org.sonar.api.i18n.I18n;
 import org.sonar.api.resources.Qualifiers;
 import org.sonar.api.resources.Scopes;
+import org.sonar.api.utils.internal.Uuids;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.component.ComponentKeys;
 import org.sonar.core.resource.ResourceDao;
@@ -75,7 +76,7 @@ public class DefaultRubyComponentService implements RubyComponentService {
       }
       checkKeyFormat(qualifier, kee);
 
-      String uuid = UUID.randomUUID().toString();
+      String uuid = Uuids.create();
       resourceDao.insertOrUpdate(
         new ResourceDto()
           .setUuid(uuid)
index 1c9de9f6d121d9f1d902e036652e93e5770ed7f2..4403fe294c74191074ea35b4bc9c40b39896072c 100644 (file)
@@ -27,6 +27,7 @@ import org.apache.commons.dbutils.DbUtils;
 import org.apache.commons.dbutils.QueryRunner;
 import org.apache.commons.dbutils.handlers.AbstractListHandler;
 import org.sonar.api.rule.Severity;
+import org.sonar.api.utils.internal.Uuids;
 import org.sonar.core.persistence.Database;
 import org.sonar.server.db.migrations.SqlUtil;
 
@@ -177,7 +178,7 @@ class ViolationConverter implements Callable<Object> {
         if (componentId == null) {
           continue;
         }
-        String issueKey = UUID.randomUUID().toString();
+        String issueKey = Uuids.create();
         String status, severity, reporter = null;
         boolean manualSeverity;
         Object createdAt = Objects.firstNonNull(row.get(CREATED_AT), ONE_YEAR_AGO);
@@ -248,7 +249,7 @@ class ViolationConverter implements Callable<Object> {
       String login = referentials.userLogin((Long) comment.get(USER_ID));
       if (login != null) {
         Object[] params = new Object[6];
-        params[0] = UUID.randomUUID().toString();
+        params[0] = Uuids.create();
         params[1] = comment.get(ISSUE_KEY);
         params[2] = login;
         params[3] = comment.get(REVIEW_TEXT);
index 6bb0228c2c5ec9981910aa79c1a83beafb82fbc1..1e6cab9ba166bd755023eac1997bb34c8d7cc99b 100644 (file)
@@ -25,6 +25,7 @@ import com.google.common.base.Strings;
 import org.apache.ibatis.session.ResultContext;
 import org.apache.ibatis.session.ResultHandler;
 import org.sonar.api.resources.Scopes;
+import org.sonar.api.utils.internal.Uuids;
 import org.sonar.core.persistence.DbSession;
 import org.sonar.core.persistence.migration.v50.Component;
 import org.sonar.core.persistence.migration.v50.Migration50Mapper;
@@ -35,7 +36,6 @@ import org.sonar.server.db.migrations.MassUpdate;
 import java.util.List;
 import java.util.Map;
 import java.util.Timer;
-import java.util.UUID;
 import java.util.concurrent.atomic.AtomicLong;
 
 import static com.google.common.collect.Lists.newArrayList;
@@ -159,7 +159,7 @@ public class PopulateProjectsUuidColumnsMigration implements DatabaseMigration {
 
   private void migrateComponentsWithoutUuid(DbSession readSession, DbSession writeSession) {
     for (Component component : readSession.getMapper(Migration50Mapper.class).selectComponentsWithoutUuid()) {
-      String uuid = UUID.randomUUID().toString();
+      String uuid = Uuids.create();
       component.setUuid(uuid);
       component.setProjectUuid(uuid);
 
@@ -172,7 +172,7 @@ public class PopulateProjectsUuidColumnsMigration implements DatabaseMigration {
     String existingUuid = component.getUuid();
     String uuid = existingUuid == null ? uuidByComponentId.get(component.getId()) : existingUuid;
     if (uuid == null) {
-      String newUuid = UUID.randomUUID().toString();
+      String newUuid = Uuids.create();
       uuidByComponentId.put(component.getId(), newUuid);
       return newUuid;
     }
index 4143743906d4588ac406a31fe8369dd0aa3021a5..1da713a5c1264df1f5ff9d5cd5691e66465c764f 100644 (file)
@@ -30,7 +30,7 @@ class AddKeyToActionPlan < ActiveRecord::Migration
     add_column 'action_plans', 'kee', :string, :null => true, :limit => 100
     ActionPlan.reset_column_information
     ActionPlan.all.each do |a|
-      a.update_attributes!(:kee => Java::JavaUtil::UUID.randomUUID().toString())
+      a.update_attributes!(:kee => Java::OrgSonarApiUtilsInternal::Uuids.create())
     end
   end
 
index ea6a2d640d73c5887516d7b319da21b4810f2e2d..0f7faddb25fe7c248bce40dee53c86a4d5c615fe 100644 (file)
@@ -36,6 +36,7 @@ import org.sonar.api.resources.ResourceUtils;
 import org.sonar.api.resources.Scopes;
 import org.sonar.api.security.ResourcePermissions;
 import org.sonar.api.utils.SonarException;
+import org.sonar.api.utils.internal.Uuids;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
@@ -46,7 +47,6 @@ import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.UUID;
 
 public final class DefaultResourcePersister implements ResourcePersister {
 
@@ -306,7 +306,7 @@ public final class DefaultResourcePersister implements ResourcePersister {
     model.setEnabled(Boolean.TRUE);
     model.setDescription(resource.getDescription());
     model.setKey(resource.getEffectiveKey());
-    model.setUuid(UUID.randomUUID().toString());
+    model.setUuid(Uuids.create());
     model.setPath(resource.getPath());
     Language language = resource.getLanguage();
     if (language != null) {
index 0f16861286f5708f1710b1e129311e50c6bad110..956440c12685fc0883b3265e72e92a03ccadbe67 100644 (file)
 
     <!-- tests -->
     <dependency>
-      <groupId>junit</groupId>
-      <artifactId>junit</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-core</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.hamcrest</groupId>
-      <artifactId>hamcrest-all</artifactId>
+      <groupId>org.codehaus.sonar</groupId>
+      <artifactId>sonar-testing-harness</artifactId>
       <scope>test</scope>
     </dependency>
     <dependency>
       <artifactId>dbunit</artifactId>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.easytesting</groupId>
-      <artifactId>fest-assert</artifactId>
-      <scope>test</scope>
-    </dependency>
     <dependency>
       <groupId>com.google.code.bean-matchers</groupId>
       <artifactId>bean-matchers</artifactId>
index 2e4ae57f118a9d5841f021baced0f548bd12c1b6..517f0e998a75b18e8e5c09aac76fe31c6bd7db85 100644 (file)
@@ -22,12 +22,11 @@ package org.sonar.core.activity.db;
 import org.apache.commons.lang.builder.ReflectionToStringBuilder;
 import org.apache.commons.lang.builder.ToStringStyle;
 import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.api.utils.internal.Uuids;
 import org.sonar.core.activity.Activity;
 import org.sonar.core.activity.ActivityLog;
 import org.sonar.core.persistence.Dto;
 
-import java.util.UUID;
-
 /**
  * @since 4.4
  */
@@ -42,7 +41,7 @@ public final class ActivityDto extends Dto<String> {
   private String data;
 
   protected ActivityDto() {
-    this.key = UUID.randomUUID().toString();
+    this.key = Uuids.create();
   }
 
   @Override
index bafd57fbf6d4ec0e966585fe889c4c3e2e0f8ef6..cc4eba49a18e4aae9d8494c7ddd7c43e971a591d 100644 (file)
@@ -21,9 +21,9 @@
 package org.sonar.core.issue;
 
 import org.sonar.api.issue.ActionPlan;
+import org.sonar.api.utils.internal.Uuids;
 
 import java.util.Date;
-import java.util.UUID;
 
 public class ActionPlanStats extends DefaultActionPlan {
 
@@ -36,7 +36,7 @@ public class ActionPlanStats extends DefaultActionPlan {
 
   public static ActionPlanStats create(String name) {
     ActionPlanStats actionPlan = new ActionPlanStats();
-    actionPlan.setKey(UUID.randomUUID().toString());
+    actionPlan.setKey(Uuids.create());
     Date now = new Date();
     actionPlan.setName(name);
     actionPlan.setStatus(ActionPlan.STATUS_OPEN);
index 6106fd7a9ff3d67b185f2b00daa42404c5004bbb..0fe3fd96aeb1c5d404436a16f0643e9b0264d2f2 100644 (file)
 package org.sonar.core.issue;
 
 import org.sonar.api.issue.ActionPlan;
+import org.sonar.api.utils.internal.Uuids;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
-
 import java.util.Date;
-import java.util.UUID;
 
 public class DefaultActionPlan implements ActionPlan {
 
@@ -46,7 +45,7 @@ public class DefaultActionPlan implements ActionPlan {
 
   public static DefaultActionPlan create(String name) {
     DefaultActionPlan actionPlan = new DefaultActionPlan();
-    actionPlan.setKey(UUID.randomUUID().toString());
+    actionPlan.setKey(Uuids.create());
     Date now = new Date();
     actionPlan.setName(name);
     actionPlan.setStatus(ActionPlan.STATUS_OPEN);
index 3d1eaea338338c96ee93c1299c09a591b5b5f5da..e81ae5448b6938dfc905e85ad66ccbd13952d586 100644 (file)
 package org.sonar.core.issue;
 
 import com.google.common.base.Preconditions;
-import com.google.common.base.Strings;
 import com.google.common.collect.Maps;
 import org.sonar.api.issue.Issuable;
 import org.sonar.api.issue.Issue;
 import org.sonar.api.issue.internal.DefaultIssue;
 import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.internal.Uuids;
 
 import javax.annotation.Nullable;
-
 import java.util.Map;
-import java.util.UUID;
 
 public class DefaultIssueBuilder implements Issuable.IssueBuilder {
 
@@ -110,8 +108,7 @@ public class DefaultIssueBuilder implements Issuable.IssueBuilder {
     Preconditions.checkNotNull(ruleKey, "Rule key must be set");
 
     DefaultIssue issue = new DefaultIssue();
-    String key = UUID.randomUUID().toString();
-    Preconditions.checkState(!Strings.isNullOrEmpty(key), "Fail to generate issue key");
+    String key = Uuids.create();
     issue.setKey(key);
     issue.setComponentKey(componentKey);
     issue.setProjectKey(projectKey);
index 378c2fca6b200ab0e0b37bd9672e7de96e54b346..387d36efa6fc5be0261cc646667fa3588ce17cf3 100644 (file)
@@ -28,6 +28,7 @@ import org.sonar.api.resources.Project;
 import org.sonar.api.rule.RuleKey;
 import org.sonar.api.utils.Duration;
 import org.sonar.api.utils.KeyValueFormat;
+import org.sonar.api.utils.internal.Uuids;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.persistence.Dto;
 import org.sonar.core.rule.RuleDto;
@@ -633,6 +634,6 @@ public final class IssueDto extends Dto<String> implements Serializable {
     return new IssueDto()
       .setProjectId(Long.valueOf(project.getId()))
       .setRuleId(rule.getId())
-      .setKee(UUID.randomUUID().toString());
+      .setKee(Uuids.create());
   }
 }
index aa2a82606a55523cb22c17c4a5058f4adb89fb1d..538ff9cbb7fa2381d1dffbe8dcf85b7c0c24e839 100644 (file)
@@ -25,6 +25,7 @@ import org.apache.ibatis.session.SqlSession;
 import org.sonar.api.component.Component;
 import org.sonar.api.resources.Scopes;
 import org.sonar.api.utils.System2;
+import org.sonar.api.utils.internal.Uuids;
 import org.sonar.core.component.ComponentDto;
 import org.sonar.core.component.SnapshotDto;
 import org.sonar.core.persistence.DaoComponent;
@@ -151,7 +152,7 @@ public class ResourceDao implements DaoComponent {
         if (resource.getId() == null) {
           // Fix for Views
           if (resource.getUuid() == null && Scopes.PROJECT.equals(resource.getScope())) {
-            String uuid = UUID.randomUUID().toString();
+            String uuid = Uuids.create();
             resource.setUuid(uuid);
             resource.setProjectUuid(uuid);
           }
index ab7912cc8a839ccb9c8d693dd4626a62aac48f46..df4779a489481e8bf6c39121faf65c00f9980abe 100644 (file)
@@ -28,12 +28,11 @@ import org.sonar.api.batch.sensor.SensorStorage;
 import org.sonar.api.batch.sensor.internal.DefaultStorable;
 import org.sonar.api.batch.sensor.issue.Issue;
 import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.internal.Uuids;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
 
-import java.util.UUID;
-
 public class DefaultIssue extends DefaultStorable implements Issue {
 
   private static final String INPUT_DIR_SHOULD_BE_NON_NULL = "InputDir should be non null";
@@ -51,12 +50,12 @@ public class DefaultIssue extends DefaultStorable implements Issue {
 
   public DefaultIssue() {
     super(null);
-    this.key = UUID.randomUUID().toString();
+    this.key = Uuids.create();
   }
 
   public DefaultIssue(SensorStorage storage) {
     super(storage);
-    this.key = UUID.randomUUID().toString();
+    this.key = Uuids.create();
   }
 
   @Override
index dbff36ff05678ac1ef31d9b4bc099f3908491613..ad77a21f1c18731a0853234c5055b1011b00aaa8 100644 (file)
 package org.sonar.api.issue.internal;
 
 import org.sonar.api.issue.IssueComment;
+import org.sonar.api.utils.internal.Uuids;
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nullable;
-
 import java.io.Serializable;
 import java.util.Date;
-import java.util.UUID;
 
 /**
  * PLUGINS MUST NOT BE USED THIS CLASS, EXCEPT FOR UNIT TESTING.
@@ -118,7 +117,7 @@ public class DefaultIssueComment implements Serializable, IssueComment {
   public static DefaultIssueComment create(String issueKey, @Nullable String login, String markdownText) {
     DefaultIssueComment comment = new DefaultIssueComment();
     comment.setIssueKey(issueKey);
-    comment.setKey(UUID.randomUUID().toString());
+    comment.setKey(Uuids.create());
     Date now = new Date();
     comment.setUserLogin(login);
     comment.setMarkdownText(markdownText);
index 13da7d217762e69ff31f28916e7a9870af17b31d..3a603649e3b22a0275e81cf95a8325ad4165438f 100644 (file)
@@ -22,10 +22,10 @@ package org.sonar.api.platform;
 import com.google.common.annotations.VisibleForTesting;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.sonar.api.utils.internal.Uuids;
 
 import java.util.HashSet;
 import java.util.Set;
-import java.util.UUID;
 import java.util.regex.Pattern;
 
 /**
@@ -50,7 +50,7 @@ class ComponentKeys {
       if (!objectsWithoutToString.add(component.getClass())) {
         log.warn(String.format("Bad component key: %s. Please implement toString() method on class %s", key, component.getClass().getName()));
       }
-      key += UUID.randomUUID().toString();
+      key += Uuids.create();
     }
     return new StringBuilder().append(component.getClass().getCanonicalName()).append("-").append(key).toString();
   }
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/Uuids.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/internal/Uuids.java
new file mode 100644 (file)
index 0000000..e72c123
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.api.utils.internal;
+
+import java.util.UUID;
+
+/**
+ * @since 5.0
+ */
+public class Uuids {
+
+  private Uuids() {
+    // only static fields
+  }
+
+  /**
+   * Create a universally unique identifier. Underlying algorithm can change over SQ versions.
+   */
+  public static String create() {
+    return UUID.randomUUID().toString();
+  }
+}
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/utils/internal/UuidsTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/utils/internal/UuidsTest.java
new file mode 100644 (file)
index 0000000..70f1171
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * 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.api.utils.internal;
+
+import com.google.common.collect.Sets;
+import org.junit.Test;
+import org.sonar.test.TestUtils;
+
+import java.util.Set;
+
+import static org.fest.assertions.Assertions.assertThat;
+
+public class UuidsTest {
+
+  @Test
+  public void create_unique() throws Exception {
+    Set<String> all = Sets.newHashSet();
+    for (int i = 0; i < 50; i++) {
+      String uuid = Uuids.create();
+      assertThat(uuid).isNotEmpty();
+      all.add(uuid);
+    }
+    assertThat(all).hasSize(50);
+  }
+
+  @Test
+  public void constructor_is_private() throws Exception {
+    TestUtils.hasOnlyPrivateConstructors(Uuids.class);
+  }
+}