]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-5559 Implemente IssueAuthorization mapping
authorJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 4 Sep 2014 08:38:18 +0000 (10:38 +0200)
committerJulien Lancelot <julien.lancelot@sonarsource.com>
Thu, 4 Sep 2014 08:38:18 +0000 (10:38 +0200)
16 files changed:
server/sonar-server/src/main/java/org/sonar/server/db/DbClient.java
server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueAuthorizationDao.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/issue/db/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationDoc.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationIndex.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationNormalizer.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueIndex.java
server/sonar-server/src/main/java/org/sonar/server/issue/index/package-info.java [new file with mode: 0644]
server/sonar-server/src/main/java/org/sonar/server/platform/ServerComponents.java
server/sonar-server/src/main/java/org/sonar/server/search/IndexDefinition.java
server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest.java
server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest2.java [deleted file]
sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationDto.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationMapper.java [new file with mode: 0644]
sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
sonar-core/src/main/resources/org/sonar/core/issue/db/IssueAuthorizationMapper.xml [new file with mode: 0644]

index 846357d0bc4f45a76c540d8b21abe90ab2ae9031..d9fc72df394240077f99f840650295fb9256e8f9 100644 (file)
@@ -34,6 +34,7 @@ import org.sonar.core.user.AuthorizationDao;
 import org.sonar.core.user.UserDao;
 import org.sonar.server.activity.db.ActivityDao;
 import org.sonar.server.component.persistence.ComponentDao;
+import org.sonar.server.issue.db.IssueAuthorizationDao;
 import org.sonar.server.issue.db.IssueDao;
 import org.sonar.server.measure.persistence.MeasureDao;
 import org.sonar.server.measure.persistence.MetricDao;
@@ -63,6 +64,7 @@ public class DbClient implements ServerComponent {
   private final AuthorizationDao authorizationDao;
   private final UserDao userDao;
   private final IssueDao issueDao;
+  private final IssueAuthorizationDao issueAuthorizationDao;
 
   public DbClient(Database db, MyBatis myBatis, DaoComponent... daoComponents) {
     this.db = db;
@@ -86,6 +88,7 @@ public class DbClient implements ServerComponent {
     authorizationDao = getDao(map, AuthorizationDao.class);
     userDao = getDao(map, UserDao.class);
     issueDao = getDao(map, IssueDao.class);
+    issueAuthorizationDao = getDao(map, IssueAuthorizationDao.class);
   }
 
   public Database database() {
@@ -108,6 +111,10 @@ public class DbClient implements ServerComponent {
     return issueDao;
   }
 
+  public IssueAuthorizationDao issueAuthorizationDao() {
+    return issueAuthorizationDao;
+  }
+
   public QualityProfileDao qualityProfileDao() {
     return qualityProfileDao;
   }
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueAuthorizationDao.java b/server/sonar-server/src/main/java/org/sonar/server/issue/db/IssueAuthorizationDao.java
new file mode 100644 (file)
index 0000000..24ae9bf
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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.issue.db;
+
+import com.google.common.annotations.VisibleForTesting;
+import org.sonar.api.utils.System2;
+import org.sonar.core.issue.db.IssueAuthorizationDto;
+import org.sonar.core.issue.db.IssueAuthorizationMapper;
+import org.sonar.core.persistence.DaoComponent;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.server.db.BaseDao;
+import org.sonar.server.search.IndexDefinition;
+
+import java.util.Date;
+
+public class IssueAuthorizationDao extends BaseDao<IssueAuthorizationMapper, IssueAuthorizationDto, String> implements DaoComponent {
+
+  public IssueAuthorizationDao() {
+    this(System2.INSTANCE);
+  }
+
+  @VisibleForTesting
+  public IssueAuthorizationDao(System2 system) {
+    super(IndexDefinition.ISSUES_AUTHORIZATION, IssueAuthorizationMapper.class, system);
+  }
+
+  @Override
+  protected IssueAuthorizationDto doGetNullableByKey(DbSession session, String key) {
+    return mapper(session).selectByKey(key);
+  }
+
+  @Override
+  protected IssueAuthorizationDto doUpdate(DbSession session, IssueAuthorizationDto issueAuthorization) {
+    // TODO ?
+    // mapper(session).update(issueAuthorization);
+    return issueAuthorization;
+  }
+
+  @Override
+  protected IssueAuthorizationDto doInsert(DbSession session, IssueAuthorizationDto issueAuthorization) {
+    // TODO ?
+    // Preconditions.checkNotNull(issueAuthorization.getKey(), "Cannot insert IssueAuthorization with empty key!");
+    // Preconditions.checkNotNull(issueAuthorization.getPermission(), "Cannot insert IssueAuthorization with no permission!");
+    // mapper(session).insert(issueAuthorization);
+    return issueAuthorization;
+  }
+
+  @Override
+  protected Iterable<IssueAuthorizationDto> findAfterDate(DbSession session, Date date) {
+    // TODO ?
+    // return mapper(session).selectAfterDate(new Timestamp(date.getTime()));
+    return null;
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/db/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/issue/db/package-info.java
new file mode 100644 (file)
index 0000000..9d25d51
--- /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.issue.db;
+
+import javax.annotation.ParametersAreNonnullByDefault;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationDoc.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationDoc.java
new file mode 100644 (file)
index 0000000..f0f9fd7
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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.issue.index;
+
+import org.sonar.server.search.BaseDoc;
+
+import java.util.List;
+import java.util.Map;
+
+public class IssueAuthorizationDoc extends BaseDoc {
+
+  public IssueAuthorizationDoc(Map<String, Object> fields) {
+    super(fields);
+  }
+
+  public String project() {
+    return getField(IssueAuthorizationNormalizer.IssueAuthorizationField.PROJECT.field());
+  }
+
+  public String permission() {
+    return getField(IssueAuthorizationNormalizer.IssueAuthorizationField.PERMISSION.field());
+  }
+
+  public List<String> groups() {
+    return (List<String>) getField(IssueAuthorizationNormalizer.IssueAuthorizationField.GROUPS.field());
+  }
+
+  public List<String> users() {
+    return (List<String>) getField(IssueAuthorizationNormalizer.IssueAuthorizationField.USERS.field());
+  }
+
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationIndex.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationIndex.java
new file mode 100644 (file)
index 0000000..c746fb2
--- /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.issue.index;
+
+import com.google.common.base.Preconditions;
+import org.elasticsearch.common.settings.ImmutableSettings;
+import org.elasticsearch.common.settings.Settings;
+import org.sonar.core.issue.db.IssueAuthorizationDto;
+import org.sonar.server.search.BaseIndex;
+import org.sonar.server.search.IndexDefinition;
+import org.sonar.server.search.IndexField;
+import org.sonar.server.search.SearchClient;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class IssueAuthorizationIndex extends BaseIndex<IssueAuthorizationDoc, IssueAuthorizationDto, String> {
+
+  public IssueAuthorizationIndex(IssueAuthorizationNormalizer normalizer, SearchClient client) {
+    super(IndexDefinition.ISSUES_AUTHORIZATION, normalizer, client);
+  }
+
+  @Override
+  protected String getKeyValue(String s) {
+    return s;
+  }
+
+  @Override
+  protected Settings getIndexSettings() throws IOException {
+    return ImmutableSettings.builder()
+      .put("index.number_of_replicas", 0)
+      .put("index.number_of_shards", 1)
+      .build();
+  }
+
+  @Override
+  protected Map mapProperties() {
+    Map<String, Object> mapping = new HashMap<String, Object>();
+    for (IndexField field : IssueAuthorizationNormalizer.IssueAuthorizationField.ALL_FIELDS) {
+      mapping.put(field.field(), mapField(field));
+    }
+    return mapping;
+  }
+
+  @Override
+  protected Map mapKey() {
+    Map<String, Object> mapping = new HashMap<String, Object>();
+    mapping.put("path", IssueAuthorizationNormalizer.IssueAuthorizationField.PROJECT.field());
+    return mapping;
+  }
+
+  @Override
+  public IssueAuthorizationDoc toDoc(Map fields) {
+    Preconditions.checkNotNull(fields, "Cannot construct IssueAuthorization with null response");
+    return new IssueAuthorizationDoc(fields);
+  }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationNormalizer.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/IssueAuthorizationNormalizer.java
new file mode 100644 (file)
index 0000000..001ad5f
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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.issue.index;
+
+import com.google.common.collect.ImmutableList;
+import org.elasticsearch.action.update.UpdateRequest;
+import org.sonar.core.issue.db.IssueAuthorizationDto;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.search.BaseNormalizer;
+import org.sonar.server.search.IndexDefinition;
+import org.sonar.server.search.IndexField;
+import org.sonar.server.search.Indexable;
+
+import java.lang.reflect.Field;
+import java.util.*;
+
+public class IssueAuthorizationNormalizer extends BaseNormalizer<IssueAuthorizationDto, String> {
+
+  public IssueAuthorizationNormalizer(DbClient db) {
+    super(IndexDefinition.ISSUES, db);
+  }
+
+  public static final class IssueAuthorizationField extends Indexable {
+
+    public static final IndexField PROJECT = add(IndexField.Type.STRING, "project");
+    public static final IndexField PERMISSION = add(IndexField.Type.STRING, "permission");
+    public static final IndexField GROUPS = add(IndexField.Type.STRING, "groups");
+    public static final IndexField USERS = add(IndexField.Type.STRING, "users");
+
+    public static final Set<IndexField> ALL_FIELDS = getAllFields();
+
+    private static final Set<IndexField> getAllFields() {
+      Set<IndexField> fields = new HashSet<IndexField>();
+      for (Field classField : IssueAuthorizationField.class.getDeclaredFields()) {
+        if (classField.getType().isAssignableFrom(IndexField.class)) {
+          try {
+            fields.add(IndexField.class.cast(classField.get(null)));
+          } catch (IllegalAccessException e) {
+            throw new IllegalStateException("Could not access Field '" + classField.getName() + "'", e);
+          }
+        }
+      }
+      return fields;
+    }
+
+    public static final IndexField of(String fieldName) {
+      for (IndexField field : ALL_FIELDS) {
+        if (field.field().equals(fieldName)) {
+          return field;
+        }
+      }
+      throw new IllegalStateException("Could not find an IndexField for '" + fieldName + "'");
+    }
+  }
+
+  @Override
+  public List<UpdateRequest> normalize(IssueAuthorizationDto dto) {
+    Map<String, Object> update = new HashMap<String, Object>();
+
+    update.put(IssueAuthorizationField.PROJECT.field(), dto.getProject());
+    update.put(IssueAuthorizationField.PERMISSION.field(), dto.getPermission());
+    update.put(IssueAuthorizationField.USERS.field(), dto.getUsers());
+    update.put(IssueAuthorizationField.GROUPS.field(), dto.getGroups());
+
+    /** Upsert elements */
+    Map<String, Object> upsert = getUpsertFor(IssueAuthorizationField.ALL_FIELDS, update);
+    upsert.put(IssueAuthorizationField.PROJECT.field(), dto.getKey());
+
+    return ImmutableList.of(
+      new UpdateRequest()
+        .id(dto.getKey())
+        .doc(update)
+        .upsert(upsert));
+  }
+}
index ff2f9be83fa2643f079a9758f021909288d4735d..465013a2b9121576e64f3d56030e734611421c51 100644 (file)
@@ -78,7 +78,7 @@ public class IssueIndex extends BaseIndex<IssueDoc, IssueDto, String> {
   }
 
   private String getParentType() {
-    return IndexDefinition.ISSUES_PROJECT.getIndexType();
+    return IndexDefinition.ISSUES_AUTHORIZATION.getIndexType();
   }
 
   private Map mapRouting() {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/index/package-info.java b/server/sonar-server/src/main/java/org/sonar/server/issue/index/package-info.java
new file mode 100644 (file)
index 0000000..da175d8
--- /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.issue.index;
+
+import javax.annotation.ParametersAreNonnullByDefault;
index 70d00ae006943b16586959237d7b36b8cadac3a0..c92fa04d4285c312fa695b87ed25f747220ffa11 100644 (file)
@@ -52,13 +52,7 @@ import org.sonar.core.measure.db.MeasureFilterDao;
 import org.sonar.core.metric.DefaultMetricFinder;
 import org.sonar.core.notification.DefaultNotificationManager;
 import org.sonar.core.permission.PermissionFacade;
-import org.sonar.core.persistence.DaoUtils;
-import org.sonar.core.persistence.DatabaseVersion;
-import org.sonar.core.persistence.DefaultDatabase;
-import org.sonar.core.persistence.MyBatis;
-import org.sonar.core.persistence.PreviewDatabaseFactory;
-import org.sonar.core.persistence.SemaphoreUpdater;
-import org.sonar.core.persistence.SemaphoresImpl;
+import org.sonar.core.persistence.*;
 import org.sonar.core.preview.PreviewCache;
 import org.sonar.core.profiling.Profiling;
 import org.sonar.core.purge.PurgeProfiler;
@@ -92,50 +86,26 @@ import org.sonar.server.charts.ChartFactory;
 import org.sonar.server.component.DefaultComponentFinder;
 import org.sonar.server.component.DefaultRubyComponentService;
 import org.sonar.server.component.persistence.ComponentDao;
-import org.sonar.server.component.ws.ComponentAppAction;
-import org.sonar.server.component.ws.ComponentsWs;
-import org.sonar.server.component.ws.EventsWs;
-import org.sonar.server.component.ws.ProjectsWs;
-import org.sonar.server.component.ws.ResourcesWs;
+import org.sonar.server.component.ws.*;
 import org.sonar.server.config.ws.PropertiesWs;
 import org.sonar.server.db.DatabaseChecker;
 import org.sonar.server.db.DbClient;
 import org.sonar.server.db.EmbeddedDatabaseFactory;
 import org.sonar.server.db.migrations.DatabaseMigrations;
 import org.sonar.server.db.migrations.DatabaseMigrator;
-import org.sonar.server.debt.DebtCharacteristicsXMLImporter;
-import org.sonar.server.debt.DebtModelBackup;
-import org.sonar.server.debt.DebtModelLookup;
-import org.sonar.server.debt.DebtModelOperations;
-import org.sonar.server.debt.DebtModelPluginRepository;
-import org.sonar.server.debt.DebtModelService;
-import org.sonar.server.debt.DebtModelXMLExporter;
-import org.sonar.server.debt.DebtRulesXMLImporter;
+import org.sonar.server.debt.*;
 import org.sonar.server.duplication.ws.DuplicationsJsonWriter;
 import org.sonar.server.duplication.ws.DuplicationsParser;
 import org.sonar.server.duplication.ws.DuplicationsWs;
-import org.sonar.server.issue.ActionService;
-import org.sonar.server.issue.AssignAction;
-import org.sonar.server.issue.CommentAction;
-import org.sonar.server.issue.DefaultIssueFinder;
-import org.sonar.server.issue.InternalRubyIssueService;
-import org.sonar.server.issue.IssueBulkChangeService;
-import org.sonar.server.issue.IssueChangelogFormatter;
-import org.sonar.server.issue.IssueChangelogService;
-import org.sonar.server.issue.IssueCommentService;
-import org.sonar.server.issue.IssueService;
-import org.sonar.server.issue.IssueStatsFinder;
-import org.sonar.server.issue.PlanAction;
-import org.sonar.server.issue.PublicRubyIssueService;
-import org.sonar.server.issue.ServerIssueStorage;
-import org.sonar.server.issue.SetSeverityAction;
-import org.sonar.server.issue.TransitionAction;
+import org.sonar.server.issue.*;
 import org.sonar.server.issue.actionplan.ActionPlanService;
 import org.sonar.server.issue.actionplan.ActionPlanWs;
 import org.sonar.server.issue.db.IssueDao;
 import org.sonar.server.issue.filter.IssueFilterService;
 import org.sonar.server.issue.filter.IssueFilterWriter;
 import org.sonar.server.issue.filter.IssueFilterWs;
+import org.sonar.server.issue.index.IssueAuthorizationIndex;
+import org.sonar.server.issue.index.IssueAuthorizationNormalizer;
 import org.sonar.server.issue.index.IssueIndex;
 import org.sonar.server.issue.index.IssueNormalizer;
 import org.sonar.server.issue.ws.IssueActionsWriter;
@@ -160,84 +130,22 @@ import org.sonar.server.platform.ws.L10nWs;
 import org.sonar.server.platform.ws.RestartHandler;
 import org.sonar.server.platform.ws.ServerWs;
 import org.sonar.server.platform.ws.SystemWs;
-import org.sonar.server.plugins.InstalledPluginReferentialFactory;
-import org.sonar.server.plugins.PluginDownloader;
-import org.sonar.server.plugins.ServerExtensionInstaller;
-import org.sonar.server.plugins.ServerPluginJarInstaller;
-import org.sonar.server.plugins.ServerPluginJarsInstaller;
-import org.sonar.server.plugins.ServerPluginRepository;
-import org.sonar.server.plugins.UpdateCenterClient;
-import org.sonar.server.plugins.UpdateCenterMatrixFactory;
+import org.sonar.server.plugins.*;
 import org.sonar.server.qualitygate.QgateProjectFinder;
 import org.sonar.server.qualitygate.QualityGates;
 import org.sonar.server.qualitygate.RegisterQualityGates;
-import org.sonar.server.qualitygate.ws.QGatesAppAction;
-import org.sonar.server.qualitygate.ws.QGatesCopyAction;
-import org.sonar.server.qualitygate.ws.QGatesCreateAction;
-import org.sonar.server.qualitygate.ws.QGatesCreateConditionAction;
-import org.sonar.server.qualitygate.ws.QGatesDeleteConditionAction;
-import org.sonar.server.qualitygate.ws.QGatesDeselectAction;
-import org.sonar.server.qualitygate.ws.QGatesDestroyAction;
-import org.sonar.server.qualitygate.ws.QGatesListAction;
-import org.sonar.server.qualitygate.ws.QGatesRenameAction;
-import org.sonar.server.qualitygate.ws.QGatesSearchAction;
-import org.sonar.server.qualitygate.ws.QGatesSelectAction;
-import org.sonar.server.qualitygate.ws.QGatesSetAsDefaultAction;
-import org.sonar.server.qualitygate.ws.QGatesShowAction;
-import org.sonar.server.qualitygate.ws.QGatesUnsetDefaultAction;
-import org.sonar.server.qualitygate.ws.QGatesUpdateConditionAction;
-import org.sonar.server.qualitygate.ws.QGatesWs;
-import org.sonar.server.qualityprofile.BuiltInProfiles;
-import org.sonar.server.qualityprofile.QProfileBackuper;
-import org.sonar.server.qualityprofile.QProfileCopier;
-import org.sonar.server.qualityprofile.QProfileExporters;
-import org.sonar.server.qualityprofile.QProfileFactory;
-import org.sonar.server.qualityprofile.QProfileLoader;
-import org.sonar.server.qualityprofile.QProfileLookup;
-import org.sonar.server.qualityprofile.QProfileProjectLookup;
-import org.sonar.server.qualityprofile.QProfileProjectOperations;
-import org.sonar.server.qualityprofile.QProfileRepositoryExporter;
-import org.sonar.server.qualityprofile.QProfileReset;
-import org.sonar.server.qualityprofile.QProfileService;
-import org.sonar.server.qualityprofile.QProfiles;
-import org.sonar.server.qualityprofile.RegisterQualityProfiles;
-import org.sonar.server.qualityprofile.RuleActivator;
-import org.sonar.server.qualityprofile.RuleActivatorContextFactory;
+import org.sonar.server.qualitygate.ws.*;
+import org.sonar.server.qualityprofile.*;
 import org.sonar.server.qualityprofile.db.ActiveRuleDao;
 import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
 import org.sonar.server.qualityprofile.index.ActiveRuleNormalizer;
-import org.sonar.server.qualityprofile.ws.BulkRuleActivationActions;
-import org.sonar.server.qualityprofile.ws.ProfilesWs;
-import org.sonar.server.qualityprofile.ws.QProfileRestoreBuiltInAction;
-import org.sonar.server.qualityprofile.ws.QProfilesWs;
-import org.sonar.server.qualityprofile.ws.RuleActivationActions;
-import org.sonar.server.rule.DefaultRuleFinder;
-import org.sonar.server.rule.DeprecatedRulesDefinition;
-import org.sonar.server.rule.RegisterRules;
-import org.sonar.server.rule.RubyRuleService;
-import org.sonar.server.rule.RuleCreator;
-import org.sonar.server.rule.RuleDefinitionsLoader;
-import org.sonar.server.rule.RuleDeleter;
-import org.sonar.server.rule.RuleOperations;
-import org.sonar.server.rule.RuleRepositories;
-import org.sonar.server.rule.RuleService;
-import org.sonar.server.rule.RuleUpdater;
+import org.sonar.server.qualityprofile.ws.*;
+import org.sonar.server.rule.*;
 import org.sonar.server.rule.db.RuleDao;
 import org.sonar.server.rule.index.RuleIndex;
 import org.sonar.server.rule.index.RuleNormalizer;
-import org.sonar.server.rule.ws.ActiveRuleCompleter;
-import org.sonar.server.rule.ws.AppAction;
-import org.sonar.server.rule.ws.DeleteAction;
-import org.sonar.server.rule.ws.RuleMapping;
-import org.sonar.server.rule.ws.RulesWebService;
-import org.sonar.server.rule.ws.SearchAction;
-import org.sonar.server.rule.ws.TagsAction;
-import org.sonar.server.rule.ws.UpdateAction;
-import org.sonar.server.search.IndexClient;
-import org.sonar.server.search.IndexQueue;
-import org.sonar.server.search.IndexSynchronizer;
-import org.sonar.server.search.SearchClient;
-import org.sonar.server.search.SearchHealth;
+import org.sonar.server.rule.ws.*;
+import org.sonar.server.search.*;
 import org.sonar.server.source.CodeColorizers;
 import org.sonar.server.source.DeprecatedSourceDecorator;
 import org.sonar.server.source.HtmlSourceDecorator;
@@ -246,27 +154,9 @@ import org.sonar.server.source.ws.ScmAction;
 import org.sonar.server.source.ws.ScmWriter;
 import org.sonar.server.source.ws.ShowAction;
 import org.sonar.server.source.ws.SourcesWs;
-import org.sonar.server.startup.CleanPreviewAnalysisCache;
-import org.sonar.server.startup.CopyRequirementsFromCharacteristicsToRules;
-import org.sonar.server.startup.GeneratePluginIndex;
-import org.sonar.server.startup.GwtPublisher;
-import org.sonar.server.startup.JdbcDriverDeployer;
-import org.sonar.server.startup.LogServerId;
-import org.sonar.server.startup.RegisterDashboards;
-import org.sonar.server.startup.RegisterDebtModel;
-import org.sonar.server.startup.RegisterMetrics;
-import org.sonar.server.startup.RegisterNewMeasureFilters;
-import org.sonar.server.startup.RegisterPermissionTemplates;
-import org.sonar.server.startup.RegisterServletFilters;
-import org.sonar.server.startup.RenameDeprecatedPropertyKeys;
-import org.sonar.server.startup.ServerMetadataPersister;
+import org.sonar.server.startup.*;
 import org.sonar.server.test.CoverageService;
-import org.sonar.server.test.ws.CoverageShowAction;
-import org.sonar.server.test.ws.CoverageWs;
-import org.sonar.server.test.ws.TestsCoveredFilesAction;
-import org.sonar.server.test.ws.TestsShowAction;
-import org.sonar.server.test.ws.TestsTestCasesAction;
-import org.sonar.server.test.ws.TestsWs;
+import org.sonar.server.test.ws.*;
 import org.sonar.server.text.MacroInterpreter;
 import org.sonar.server.text.RubyTextService;
 import org.sonar.server.ui.JRubyI18n;
@@ -274,22 +164,11 @@ import org.sonar.server.ui.JRubyProfiling;
 import org.sonar.server.ui.PageDecorations;
 import org.sonar.server.ui.Views;
 import org.sonar.server.updatecenter.ws.UpdateCenterWs;
-import org.sonar.server.user.DefaultUserService;
-import org.sonar.server.user.DoPrivileged;
-import org.sonar.server.user.GroupMembershipFinder;
-import org.sonar.server.user.GroupMembershipService;
-import org.sonar.server.user.NewUserNotifier;
-import org.sonar.server.user.SecurityRealmFactory;
+import org.sonar.server.user.*;
 import org.sonar.server.user.ws.FavoritesWs;
 import org.sonar.server.user.ws.UserPropertiesWs;
 import org.sonar.server.user.ws.UsersWs;
-import org.sonar.server.util.BooleanTypeValidation;
-import org.sonar.server.util.FloatTypeValidation;
-import org.sonar.server.util.IntegerTypeValidation;
-import org.sonar.server.util.StringListTypeValidation;
-import org.sonar.server.util.StringTypeValidation;
-import org.sonar.server.util.TextTypeValidation;
-import org.sonar.server.util.TypeValidations;
+import org.sonar.server.util.*;
 import org.sonar.server.ws.ListingWs;
 import org.sonar.server.ws.WebServiceEngine;
 
@@ -347,11 +226,13 @@ class ServerComponents {
       SearchClient.class,
       ActivityNormalizer.class,
       IssueNormalizer.class,
+      IssueAuthorizationNormalizer.class,
       RuleNormalizer.class,
       ActiveRuleNormalizer.class,
       RuleIndex.class,
       ActiveRuleIndex.class,
       IssueIndex.class,
+      IssueAuthorizationIndex.class,
       ActivityIndex.class,
       IndexClient.class,
       SearchHealth.class,
index 39ce5c7ba7f65118ab54623f07dc9619e4bd7dc4..0b7a06a6ce680f4b6b346eb5e7b0d7244119ec35 100644 (file)
@@ -52,8 +52,7 @@ public class IndexDefinition {
 
   public static final IndexDefinition RULE = new IndexDefinition("rules", "rule");
   public static final IndexDefinition ACTIVE_RULE = new IndexDefinition("rules", "activeRule");
-  public static final IndexDefinition ISSUES_PROJECT = new IndexDefinition("issues", "issueProject");
-  public static final IndexDefinition ISSUES_PERMISSION = new IndexDefinition("issues", "issuePermission");
+  public static final IndexDefinition ISSUES_AUTHORIZATION = new IndexDefinition("issues", "issueAuthorization");
   public static final IndexDefinition ISSUES = new IndexDefinition("issues", "issue");
   public static final IndexDefinition LOG = new IndexDefinition("logs", "sonarLog");
 
index fe15c037a39c263da01b4b39feaf38c245200ccb..b83fc24095deb0d94dc3e95abcb80aa11d65cb49 100644 (file)
  * 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.issue.db;
 
 import org.elasticsearch.action.bulk.BulkRequestBuilder;
 import org.elasticsearch.action.index.IndexRequestBuilder;
 import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.common.settings.ImmutableSettings;
 import org.elasticsearch.index.query.BoolFilterBuilder;
 import org.elasticsearch.index.query.FilterBuilders;
 import org.elasticsearch.index.query.OrFilterBuilder;
@@ -44,16 +44,17 @@ import org.sonar.server.issue.index.IssueIndex;
 import org.sonar.server.platform.Platform;
 import org.sonar.server.rule.RuleTesting;
 import org.sonar.server.rule.db.RuleDao;
-import org.sonar.server.search.BaseIndex;
 import org.sonar.server.search.IndexClient;
 import org.sonar.server.search.IndexDefinition;
 import org.sonar.server.search.SearchClient;
 import org.sonar.server.tester.ServerTester;
 
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.*;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
 
+import static com.google.common.collect.Lists.newArrayList;
 import static com.google.common.collect.Maps.newHashMap;
 import static org.fest.assertions.Assertions.assertThat;
 
@@ -192,8 +193,6 @@ public class IssueBackendMediumTest {
   @Test
   public void issue_authorization_on_group() throws Exception {
     SearchClient searchClient = tester.get(SearchClient.class);
-    createIssuePermissionIndex(searchClient);
-    createIssueProjectIndex(searchClient);
 
     RuleDto rule = RuleTesting.newXooX1();
     tester.get(RuleDao.class).insert(dbSession, rule);
@@ -201,18 +200,17 @@ public class IssueBackendMediumTest {
     ComponentDto project1 = addComponent(1L, 1L, "SonarQube :: Server");
     ComponentDto file1 = addComponent(2L, 1L, "IssueAction.java");
     addIssue(rule, project1, file1);
-    addIssueAuthorization(searchClient, project1, null, "user");
+    addIssueAuthorization(searchClient, project1, null, newArrayList("user")).get();
 
     ComponentDto project2 = addComponent(10L, 10L, "SonarQube :: Core");
     ComponentDto file2 = addComponent(11L, 10L, "IssueDao.java");
     addIssue(rule, project2, file2);
-    addIssueAuthorization(searchClient, project2, null, "reviewer");
+    addIssueAuthorization(searchClient, project2, null, newArrayList("reviewer")).get();
 
     ComponentDto project3 = addComponent(20L, 20L, "SonarQube :: WS");
     ComponentDto file3 = addComponent(21L, 20L, "IssueWS.java");
     addIssue(rule, project3, file3);
-    addIssueAuthorization(searchClient, project3, null, "user");
-    addIssueAuthorization(searchClient, project3, null, "reviewer");
+    addIssueAuthorization(searchClient, project3, null, newArrayList("user", "reviewer")).get();
 
     dbSession.commit();
 
@@ -225,8 +223,6 @@ public class IssueBackendMediumTest {
   @Test
   public void issue_authorization_on_user() throws Exception {
     SearchClient searchClient = tester.get(SearchClient.class);
-    createIssuePermissionIndex(searchClient);
-    createIssueProjectIndex(searchClient);
 
     RuleDto rule = RuleTesting.newXooX1();
     tester.get(RuleDao.class).insert(dbSession, rule);
@@ -234,7 +230,7 @@ public class IssueBackendMediumTest {
     ComponentDto project = addComponent(1L, 1L, "SonarQube");
     ComponentDto file = addComponent(2L, 1L, "IssueAction.java");
     addIssue(rule, project, file);
-    addIssueAuthorization(searchClient, project, "julien", null);
+    addIssueAuthorization(searchClient, project, newArrayList("julien"), null).get();
 
     dbSession.commit();
 
@@ -242,15 +238,11 @@ public class IssueBackendMediumTest {
     assertThat(searchIssueWithAuthorization(searchClient, "julien", "user").getHits().getTotalHits()).isEqualTo(1);
     // The issue is not visible for user simon
     assertThat(searchIssueWithAuthorization(searchClient, "simon", "user").getHits().getTotalHits()).isEqualTo(0);
-
-//    Thread.sleep(Integer.MAX_VALUE);
   }
 
   @Test
   public void issue_authorization_with_a_lot_of_issues() throws Exception {
     SearchClient searchClient = tester.get(SearchClient.class);
-    createIssuePermissionIndex(searchClient);
-    createIssueProjectIndex(searchClient);
 
     RuleDto rule = RuleTesting.newXooX1();
     tester.get(RuleDao.class).insert(dbSession, rule);
@@ -261,17 +253,23 @@ public class IssueBackendMediumTest {
 
     Long projectId = 1L;
     Long componentId = 1L;
-    BulkRequestBuilder bulkRequestBuilder = new BulkRequestBuilder(searchClient);
+
+    List<String> users = newArrayList();
+    for (int u = 0; u < nbUser; u++) {
+      users.add("user-" + u);
+    }
+
+    BulkRequestBuilder bulkRequestBuilder = new BulkRequestBuilder(searchClient).setRefresh(true);
     for (int p = 0; p < nbProject; p++) {
       ComponentDto project = addComponent(projectId, projectId, "Project-" + projectId.toString());
 
-      addIssueAuthorization(searchClient, bulkRequestBuilder, project, null, "anyone");
+      List<String> groups = newArrayList();
+      groups.add("anyone");
       if (p % 2 == 0) {
-        addIssueAuthorization(searchClient, bulkRequestBuilder, project, null, "user");
-      }
-      for (int u = 0; u < nbUser; u++) {
-        addIssueAuthorization(searchClient, bulkRequestBuilder, project, "user-" + u, null);
+        groups.add("user");
       }
+
+      bulkRequestBuilder.add(addIssueAuthorization(searchClient, project, users, groups, false));
       for (int c = 0; c < componentPerProject; c++) {
         ComponentDto file = addComponent(componentId, projectId, "Component-" + componentId.toString());
         addIssue(rule, project, file);
@@ -294,15 +292,15 @@ public class IssueBackendMediumTest {
     // user-1 should see all issues
     assertThat(searchIssueWithAuthorization(searchClient, "user-1", "").getHits().getTotalHits()).isEqualTo(nbProject * componentPerProject);
 
-//    Thread.sleep(Integer.MAX_VALUE);
+    // Thread.sleep(Integer.MAX_VALUE);
   }
 
   private SearchResponse searchIssueWithAuthorization(SearchClient searchClient, String user, String... groups) {
     BoolFilterBuilder fb = FilterBuilders.boolFilter();
 
-    OrFilterBuilder or = FilterBuilders.orFilter(FilterBuilders.termFilter("user", user));
+    OrFilterBuilder or = FilterBuilders.orFilter(FilterBuilders.termFilter("users", user));
     for (String group : groups) {
-      or.add(FilterBuilders.termFilter("group", group));
+      or.add(FilterBuilders.termFilter("groups", group));
     }
     fb.must(FilterBuilders.termFilter("permission", "read"), or).cache(true);
     // fb.must(FilterBuilders.termFilter("permission", "read"), or);
@@ -311,11 +309,9 @@ public class IssueBackendMediumTest {
       .setQuery(
         QueryBuilders.filteredQuery(
           QueryBuilders.matchAllQuery(),
-          FilterBuilders.hasParentFilter(IndexDefinition.ISSUES_PROJECT.getIndexType(),
-            QueryBuilders.hasChildQuery(IndexDefinition.ISSUES_PERMISSION.getIndexType(),
-              QueryBuilders.filteredQuery(
-                QueryBuilders.matchAllQuery(), fb)
-            )
+          FilterBuilders.hasParentFilter(IndexDefinition.ISSUES_AUTHORIZATION.getIndexType(),
+            QueryBuilders.filteredQuery(
+              QueryBuilders.matchAllQuery(), fb)
             )
           )
       )
@@ -346,159 +342,26 @@ public class IssueBackendMediumTest {
     return issue;
   }
 
-  private void addIssueAuthorization(SearchClient searchClient, ComponentDto project, String user, String group) {
-    addIssueAuthorization(searchClient, null, project, user, group);
+  private IndexRequestBuilder addIssueAuthorization(final SearchClient searchClient, ComponentDto project, List<String> users, List<String> groups) {
+    return addIssueAuthorization(searchClient, project, users, groups, true);
   }
 
-  private void addIssueAuthorization(SearchClient searchClient, BulkRequestBuilder bulkRequestBuilder, ComponentDto project, String user, String group) {
+  private IndexRequestBuilder addIssueAuthorization(final SearchClient searchClient, ComponentDto project, List<String> users, List<String> groups, boolean refresh) {
     Map<String, Object> permissionSource = newHashMap();
     permissionSource.put("_parent", project.key());
     permissionSource.put("permission", "read");
     permissionSource.put("project", project.key());
-    if (user != null) {
-      permissionSource.put("user", user);
-    }
-    if (group != null) {
-      permissionSource.put("group", group);
+    if (users != null) {
+      permissionSource.put("users", users);
     }
-
-    IndexRequestBuilder permissionRequestBuilder = searchClient.prepareIndex(IndexDefinition.ISSUES_PERMISSION.getIndexName(), IndexDefinition.ISSUES_PERMISSION.getIndexType())
-      .setSource(permissionSource);
-    if (bulkRequestBuilder != null) {
-      bulkRequestBuilder.add(permissionRequestBuilder);
-    } else {
-      permissionRequestBuilder.setRefresh(true).get();
+    if (groups != null) {
+      permissionSource.put("groups", groups);
     }
 
-    Map<String, Object> projectSource = newHashMap();
-    projectSource.put("key", project.key());
-
-    IndexRequestBuilder projectRequestBuilder = searchClient.prepareIndex(IndexDefinition.ISSUES_PROJECT.getIndexName(), IndexDefinition.ISSUES_PROJECT.getIndexType())
+    return searchClient.prepareIndex(IndexDefinition.ISSUES_AUTHORIZATION.getIndexName(), IndexDefinition.ISSUES_AUTHORIZATION.getIndexType())
       .setId(project.key())
-      .setSource(projectSource);
-    if (bulkRequestBuilder != null) {
-      bulkRequestBuilder.add(projectRequestBuilder);
-    } else {
-      projectRequestBuilder.setRefresh(true).get();
-    }
+      .setSource(permissionSource)
+      .setRefresh(refresh);
   }
 
-  private BaseIndex createIssueProjectIndex(final SearchClient searchClient) {
-    BaseIndex baseIndex = new BaseIndex(
-      IndexDefinition.createFor(IndexDefinition.ISSUES_PROJECT.getIndexName(), IndexDefinition.ISSUES_PROJECT.getIndexType()),
-      null, searchClient) {
-      @Override
-      protected String getKeyValue(Serializable key) {
-        return null;
-      }
-
-      @Override
-      protected org.elasticsearch.common.settings.Settings getIndexSettings() throws IOException {
-        return ImmutableSettings.builder().build();
-      }
-
-      @Override
-      protected Map mapProperties() {
-        Map<String, Object> mapping = new HashMap<String, Object>();
-        mapping.put("project", mapStringField());
-        return mapping;
-      }
-
-      protected Map mapStringField() {
-        Map<String, Object> mapping = new HashMap<String, Object>();
-        mapping.put("type", "string");
-        mapping.put("index", "analyzed");
-        mapping.put("index_analyzer", "keyword");
-        mapping.put("search_analyzer", "whitespace");
-        return mapping;
-      }
-
-      @Override
-      protected Map mapKey() {
-        return Collections.emptyMap();
-      }
-
-      @Override
-      public Object toDoc(Map fields) {
-        return null;
-      }
-    };
-    baseIndex.start();
-    return baseIndex;
-  }
-
-  private BaseIndex createIssuePermissionIndex(final SearchClient searchClient) {
-    BaseIndex baseIndex = new BaseIndex(
-      IndexDefinition.createFor(IndexDefinition.ISSUES_PERMISSION.getIndexName(), IndexDefinition.ISSUES_PERMISSION.getIndexType()),
-      null, searchClient) {
-      @Override
-      protected String getKeyValue(Serializable key) {
-        return null;
-      }
-
-      @Override
-      protected org.elasticsearch.common.settings.Settings getIndexSettings() throws IOException {
-        return ImmutableSettings.builder().build();
-      }
-
-      @Override
-      protected Map mapDomain() {
-        Map<String, Object> mapping = new HashMap<String, Object>();
-        mapping.put("dynamic", false);
-        mapping.put("_parent", mapParent());
-        mapping.put("_routing", mapRouting());
-        mapping.put("properties", mapProperties());
-        return mapping;
-      }
-
-      private Object mapParent() {
-        Map<String, Object> mapping = new HashMap<String, Object>();
-        mapping.put("type", getParentType());
-        return mapping;
-      }
-
-      private String getParentType() {
-        return IndexDefinition.ISSUES_PROJECT.getIndexType();
-      }
-
-      private Map mapRouting() {
-        Map<String, Object> mapping = new HashMap<String, Object>();
-        mapping.put("required", true);
-        mapping.put("path", "project");
-        return mapping;
-      }
-
-      @Override
-      protected Map mapProperties() {
-        Map<String, Object> mapping = new HashMap<String, Object>();
-        mapping.put("permission", mapStringField());
-        mapping.put("project", mapStringField());
-        mapping.put("group", mapStringField());
-        mapping.put("user", mapStringField());
-        return mapping;
-      }
-
-      protected Map mapStringField() {
-        Map<String, Object> mapping = new HashMap<String, Object>();
-        mapping.put("type", "string");
-        mapping.put("index", "analyzed");
-        mapping.put("index_analyzer", "keyword");
-        mapping.put("search_analyzer", "whitespace");
-        return mapping;
-      }
-
-      @Override
-      protected Map mapKey() {
-        Map<String, Object> mapping = new HashMap<String, Object>();
-        return mapping;
-      }
-
-      @Override
-      public Object toDoc(Map fields) {
-        return null;
-      }
-    };
-    baseIndex.start();
-    return baseIndex;
-  }
 }
diff --git a/server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest2.java b/server/sonar-server/src/test/java/org/sonar/server/issue/db/IssueBackendMediumTest2.java
deleted file mode 100644 (file)
index b0415a6..0000000
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * 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.issue.db;
-
-import org.elasticsearch.action.bulk.BulkRequestBuilder;
-import org.elasticsearch.action.index.IndexRequestBuilder;
-import org.elasticsearch.action.search.SearchRequestBuilder;
-import org.elasticsearch.action.search.SearchResponse;
-import org.elasticsearch.common.settings.ImmutableSettings;
-import org.elasticsearch.index.query.BoolFilterBuilder;
-import org.elasticsearch.index.query.FilterBuilders;
-import org.elasticsearch.index.query.OrFilterBuilder;
-import org.elasticsearch.index.query.QueryBuilders;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Test;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.issue.db.IssueDto;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.rule.RuleDto;
-import org.sonar.server.component.persistence.ComponentDao;
-import org.sonar.server.db.DbClient;
-import org.sonar.server.issue.index.IssueDoc;
-import org.sonar.server.issue.index.IssueIndex;
-import org.sonar.server.platform.Platform;
-import org.sonar.server.rule.RuleTesting;
-import org.sonar.server.rule.db.RuleDao;
-import org.sonar.server.search.BaseIndex;
-import org.sonar.server.search.IndexClient;
-import org.sonar.server.search.IndexDefinition;
-import org.sonar.server.search.SearchClient;
-import org.sonar.server.tester.ServerTester;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.*;
-
-import static com.google.common.collect.Lists.newArrayList;
-import static com.google.common.collect.Maps.newHashMap;
-import static org.fest.assertions.Assertions.assertThat;
-
-public class IssueBackendMediumTest2 {
-
-  @ClassRule
-  public static ServerTester tester = new ServerTester();
-
-  DbClient dbClient;
-  IndexClient indexClient;
-  Platform platform;
-  DbSession dbSession;
-
-  @Before
-  public void setUp() throws Exception {
-    dbClient = tester.get(DbClient.class);
-    indexClient = tester.get(IndexClient.class);
-    platform = tester.get(Platform.class);
-    dbSession = dbClient.openSession(false);
-    tester.clearDbAndIndexes();
-  }
-
-  @After
-  public void tearDown() throws Exception {
-    if (dbSession != null) {
-      dbSession.close();
-    }
-  }
-
-  @Test
-  public void insert_and_find_by_key() throws Exception {
-    RuleDto rule = RuleTesting.newXooX1();
-    tester.get(RuleDao.class).insert(dbSession, rule);
-
-    ComponentDto project = new ComponentDto()
-      .setId(1L)
-      .setKey("MyProject")
-      .setProjectId(1L);
-    tester.get(ComponentDao.class).insert(dbSession, project);
-
-    ComponentDto resource = new ComponentDto()
-      .setProjectId(1L)
-      .setKey("MyComponent")
-      .setId(2L);
-    tester.get(ComponentDao.class).insert(dbSession, resource);
-
-    IssueDto issue = new IssueDto()
-      .setIssueCreationDate(new Date())
-      .setIssueUpdateDate(new Date())
-      .setRule(rule)
-      .setRootComponent(project)
-      .setComponent(resource)
-      .setStatus("OPEN").setResolution("OPEN")
-      .setKee(UUID.randomUUID().toString())
-      .setSeverity("MAJOR");
-    dbClient.issueDao().insert(dbSession, issue);
-
-    dbSession.commit();
-
-    // Check that Issue is in Index
-    assertThat(indexClient.get(IssueIndex.class).countAll()).isEqualTo(1);
-
-    // should find by key
-    IssueDoc issueDoc = indexClient.get(IssueIndex.class).getByKey(issue.getKey());
-    assertThat(issueDoc).isNotNull();
-
-    // Check all normalized fields
-    assertThat(issueDoc.actionPlanKey()).isEqualTo(issue.getActionPlanKey());
-    assertThat(issueDoc.assignee()).isEqualTo(issue.getAssignee());
-    assertThat(issueDoc.authorLogin()).isEqualTo(issue.getAuthorLogin());
-    assertThat(issueDoc.closeDate()).isEqualTo(issue.getIssueCloseDate());
-    assertThat(issueDoc.componentKey()).isEqualTo(issue.getComponentKey());
-    assertThat(issueDoc.creationDate()).isEqualTo(issue.getCreatedAt());
-    assertThat(issueDoc.effortToFix()).isEqualTo(issue.getEffortToFix());
-    assertThat(issueDoc.resolution()).isEqualTo(issue.getResolution());
-    assertThat(issueDoc.ruleKey()).isEqualTo(RuleKey.of(issue.getRuleRepo(), issue.getRule()));
-    assertThat(issueDoc.line()).isEqualTo(issue.getLine());
-    assertThat(issueDoc.message()).isEqualTo(issue.getMessage());
-    assertThat(issueDoc.reporter()).isEqualTo(issue.getReporter());
-    assertThat(issueDoc.key()).isEqualTo(issue.getKey());
-    assertThat(issueDoc.updateDate()).isEqualTo(issue.getIssueUpdateDate());
-    assertThat(issueDoc.status()).isEqualTo(issue.getStatus());
-    assertThat(issueDoc.severity()).isEqualTo(issue.getSeverity());
-
-    // assertThat(issueDoc.attributes()).isEqualTo(issue.getIssueAttributes());
-    // assertThat(issueDoc.isNew()).isEqualTo(issue.isN());
-    // assertThat(issueDoc.comments()).isEqualTo(issue.());
-  }
-
-  @Test
-  public void insert_and_find_after_date() throws Exception {
-
-    RuleDto rule = RuleTesting.newXooX1();
-    tester.get(RuleDao.class).insert(dbSession, rule);
-
-    ComponentDto project = new ComponentDto()
-      .setId(1L)
-      .setKey("MyProject")
-      .setProjectId(1L);
-    tester.get(ComponentDao.class).insert(dbSession, project);
-
-    ComponentDto resource = new ComponentDto()
-      .setId(2L)
-      .setKey("MyComponent")
-      .setProjectId(1L);
-    tester.get(ComponentDao.class).insert(dbSession, resource);
-
-    IssueDto issue = new IssueDto().setId(1L)
-      .setRuleId(rule.getId())
-      .setRootComponentId(project.getId())
-      .setRootComponentKey_unit_test_only(project.key())
-      .setComponentId(resource.getId())
-      .setComponentKey_unit_test_only(resource.key())
-      .setStatus("OPEN").setResolution("OPEN")
-      .setKee(UUID.randomUUID().toString());
-    dbClient.issueDao().insert(dbSession, issue);
-
-    dbSession.commit();
-    assertThat(issue.getId()).isNotNull();
-
-    // Find Issues since forever
-    Date t0 = new Date(0);
-    assertThat(dbClient.issueDao().findAfterDate(dbSession, t0)).hasSize(1);
-
-    // Should not find any new issues
-    Date t1 = new Date();
-    assertThat(dbClient.issueDao().findAfterDate(dbSession, t1)).hasSize(0);
-
-    // Should synchronise
-    tester.clearIndexes();
-    assertThat(indexClient.get(IssueIndex.class).countAll()).isEqualTo(0);
-    tester.get(Platform.class).executeStartupTasks();
-    assertThat(indexClient.get(IssueIndex.class).countAll()).isEqualTo(1);
-  }
-
-  @Test
-  public void issue_authorization_on_group() throws Exception {
-    SearchClient searchClient = tester.get(SearchClient.class);
-    // createIssuePermissionIndex(searchClient);
-    createIssueAuthorizationIndex(searchClient);
-
-    RuleDto rule = RuleTesting.newXooX1();
-    tester.get(RuleDao.class).insert(dbSession, rule);
-
-    ComponentDto project1 = addComponent(1L, 1L, "SonarQube :: Server");
-    ComponentDto file1 = addComponent(2L, 1L, "IssueAction.java");
-    addIssue(rule, project1, file1);
-    addIssueAuthorization(searchClient, project1, null, newArrayList("user")).get();
-
-    ComponentDto project2 = addComponent(10L, 10L, "SonarQube :: Core");
-    ComponentDto file2 = addComponent(11L, 10L, "IssueDao.java");
-    addIssue(rule, project2, file2);
-    addIssueAuthorization(searchClient, project2, null, newArrayList("reviewer")).get();
-
-    ComponentDto project3 = addComponent(20L, 20L, "SonarQube :: WS");
-    ComponentDto file3 = addComponent(21L, 20L, "IssueWS.java");
-    addIssue(rule, project3, file3);
-    addIssueAuthorization(searchClient, project3, null, newArrayList("user", "reviewer")).get();
-
-    dbSession.commit();
-
-    assertThat(searchIssueWithAuthorization(searchClient, "julien", "user", "reviewer").getHits().getTotalHits()).isEqualTo(3); // ok
-    assertThat(searchIssueWithAuthorization(searchClient, "julien", "user").getHits().getTotalHits()).isEqualTo(2); // ko -> 1
-    assertThat(searchIssueWithAuthorization(searchClient, "julien", "reviewer").getHits().getTotalHits()).isEqualTo(2); // ko -> 1
-    assertThat(searchIssueWithAuthorization(searchClient, "julien", "unknown").getHits().getTotalHits()).isEqualTo(0);
-  }
-
-  @Test
-  public void issue_authorization_on_user() throws Exception {
-    SearchClient searchClient = tester.get(SearchClient.class);
-    // createIssuePermissionIndex(searchClient);
-    createIssueAuthorizationIndex(searchClient);
-
-    RuleDto rule = RuleTesting.newXooX1();
-    tester.get(RuleDao.class).insert(dbSession, rule);
-
-    ComponentDto project = addComponent(1L, 1L, "SonarQube");
-    ComponentDto file = addComponent(2L, 1L, "IssueAction.java");
-    addIssue(rule, project, file);
-    addIssueAuthorization(searchClient, project, newArrayList("julien"), null).get();
-
-    dbSession.commit();
-
-    // The issue is visible for user julien
-    assertThat(searchIssueWithAuthorization(searchClient, "julien", "user").getHits().getTotalHits()).isEqualTo(1);
-    // The issue is not visible for user simon
-    assertThat(searchIssueWithAuthorization(searchClient, "simon", "user").getHits().getTotalHits()).isEqualTo(0);
-  }
-
-  @Test
-  public void issue_authorization_with_a_lot_of_issues() throws Exception {
-    SearchClient searchClient = tester.get(SearchClient.class);
-    // createIssuePermissionIndex(searchClient);
-    createIssueAuthorizationIndex(searchClient);
-
-    RuleDto rule = RuleTesting.newXooX1();
-    tester.get(RuleDao.class).insert(dbSession, rule);
-
-    int nbProject = 10;
-    int nbUser = 5;
-    int componentPerProject = 5;
-
-    Long projectId = 1L;
-    Long componentId = 1L;
-
-    List<String> users = newArrayList();
-    for (int u = 0; u < nbUser; u++) {
-      users.add("user-" + u);
-    }
-
-    BulkRequestBuilder bulkRequestBuilder = new BulkRequestBuilder(searchClient).setRefresh(true);
-    for (int p = 0; p < nbProject; p++) {
-      ComponentDto project = addComponent(projectId, projectId, "Project-" + projectId.toString());
-
-      List<String> groups = newArrayList();
-      groups.add("anyone");
-      if (p % 2 == 0) {
-        groups.add("user");
-      }
-
-      bulkRequestBuilder.add(addIssueAuthorization(searchClient, project, users, groups, false));
-      for (int c = 0; c < componentPerProject; c++) {
-        ComponentDto file = addComponent(componentId, projectId, "Component-" + componentId.toString());
-        addIssue(rule, project, file);
-        componentId++;
-      }
-      projectId++;
-
-      if (bulkRequestBuilder.numberOfActions() == nbProject) {
-        bulkRequestBuilder.get();
-        dbSession.commit();
-      }
-    }
-    bulkRequestBuilder.setRefresh(true).get();
-    dbSession.commit();
-
-    // All issues are visible by group anyone
-    assertThat(searchIssueWithAuthorization(searchClient, "", "anyone").getHits().getTotalHits()).isEqualTo(nbProject * componentPerProject);
-    // Half of issues are visible by group user
-    assertThat(searchIssueWithAuthorization(searchClient, "", "user").getHits().getTotalHits()).isEqualTo(nbProject * componentPerProject / 2);
-    // user-1 should see all issues
-    assertThat(searchIssueWithAuthorization(searchClient, "user-1", "").getHits().getTotalHits()).isEqualTo(nbProject * componentPerProject);
-
-//    Thread.sleep(Integer.MAX_VALUE);
-  }
-
-  private SearchResponse searchIssueWithAuthorization(SearchClient searchClient, String user, String... groups) {
-    BoolFilterBuilder fb = FilterBuilders.boolFilter();
-
-    OrFilterBuilder or = FilterBuilders.orFilter(FilterBuilders.termFilter("users", user));
-    for (String group : groups) {
-      or.add(FilterBuilders.termFilter("groups", group));
-    }
-    fb.must(FilterBuilders.termFilter("permission", "read"), or).cache(true);
-    // fb.must(FilterBuilders.termFilter("permission", "read"), or);
-
-    SearchRequestBuilder request = searchClient.prepareSearch(IndexDefinition.ISSUES.getIndexName()).setTypes(IndexDefinition.ISSUES.getIndexType())
-      .setQuery(
-        QueryBuilders.filteredQuery(
-          QueryBuilders.matchAllQuery(),
-          FilterBuilders.hasParentFilter(IndexDefinition.ISSUES_PROJECT.getIndexType(),
-            QueryBuilders.filteredQuery(
-              QueryBuilders.matchAllQuery(), fb)
-            )
-          )
-      )
-      .setSize(Integer.MAX_VALUE);
-
-    return searchClient.execute(request);
-  }
-
-  private ComponentDto addComponent(Long id, Long projectId, String key) {
-    ComponentDto project = new ComponentDto()
-      .setId(id)
-      .setProjectId(projectId)
-      .setKey(key);
-    tester.get(ComponentDao.class).insert(dbSession, project);
-    return project;
-  }
-
-  private IssueDto addIssue(RuleDto rule, ComponentDto project, ComponentDto file) {
-    IssueDto issue = new IssueDto()
-      .setRuleId(rule.getId())
-      .setRootComponentKey_unit_test_only(project.key())
-      .setRootComponentId(project.getId())
-      .setComponentKey_unit_test_only(file.key())
-      .setComponentId(file.getId())
-      .setStatus("OPEN").setResolution("OPEN")
-      .setKee(UUID.randomUUID().toString());
-    dbClient.issueDao().insert(dbSession, issue);
-    return issue;
-  }
-
-  private IndexRequestBuilder addIssueAuthorization(final SearchClient searchClient, ComponentDto project, List<String> users, List<String> groups) {
-    return addIssueAuthorization(searchClient, project, users, groups, true);
-  }
-
-  private IndexRequestBuilder addIssueAuthorization(final SearchClient searchClient, ComponentDto project, List<String> users, List<String> groups, boolean refresh) {
-    Map<String, Object> permissionSource = newHashMap();
-    permissionSource.put("_parent", project.key());
-    permissionSource.put("permission", "read");
-    permissionSource.put("project", project.key());
-    if (users != null) {
-      permissionSource.put("users", users);
-    }
-    if (groups != null) {
-      permissionSource.put("groups", groups);
-    }
-
-    return searchClient.prepareIndex(IndexDefinition.ISSUES_PROJECT.getIndexName(), IndexDefinition.ISSUES_PROJECT.getIndexType())
-      .setId(project.key())
-      .setSource(permissionSource)
-      .setRefresh(refresh);
-  }
-
-  private BaseIndex createIssueAuthorizationIndex(final SearchClient searchClient) {
-    BaseIndex baseIndex = new BaseIndex(
-      IndexDefinition.createFor(IndexDefinition.ISSUES_PROJECT.getIndexName(), IndexDefinition.ISSUES_PROJECT.getIndexType()),
-      null, searchClient) {
-      @Override
-      protected String getKeyValue(Serializable key) {
-        return null;
-      }
-
-      @Override
-      protected org.elasticsearch.common.settings.Settings getIndexSettings() throws IOException {
-        return ImmutableSettings.builder().build();
-      }
-
-      @Override
-      protected Map mapProperties() {
-        Map<String, Object> mapping = new HashMap<String, Object>();
-        mapping.put("project", mapStringField());
-        mapping.put("permission", mapStringField());
-        mapping.put("groups", mapStringField());
-        mapping.put("users", mapStringField());
-        return mapping;
-      }
-
-      protected Map mapStringField() {
-        Map<String, Object> mapping = new HashMap<String, Object>();
-        mapping.put("type", "string");
-        mapping.put("index", "analyzed");
-        mapping.put("index_analyzer", "keyword");
-        mapping.put("search_analyzer", "whitespace");
-        return mapping;
-      }
-
-      @Override
-      protected Map mapKey() {
-        return Collections.emptyMap();
-      }
-
-      @Override
-      public Object toDoc(Map fields) {
-        return null;
-      }
-    };
-    baseIndex.start();
-    return baseIndex;
-  }
-
-}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationDto.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationDto.java
new file mode 100644 (file)
index 0000000..d66f0c9
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.issue.db;
+
+import org.sonar.core.persistence.Dto;
+
+import java.io.Serializable;
+import java.util.List;
+
+public final class IssueAuthorizationDto extends Dto<String> implements Serializable {
+
+  private String project;
+  private String permission;
+  private List<String> groups;
+  private List<String> users;
+
+  @Override
+  public String getKey() {
+    return null;
+  }
+
+  public String getProject() {
+    return project;
+  }
+
+  public IssueAuthorizationDto setProject(String project) {
+    this.project = project;
+    return this;
+  }
+
+  public String getPermission() {
+    return permission;
+  }
+
+  public IssueAuthorizationDto setPermission(String permission) {
+    this.permission = permission;
+    return this;
+  }
+
+  public List<String> getGroups() {
+    return groups;
+  }
+
+  public IssueAuthorizationDto setGroups(List<String> groups) {
+    this.groups = groups;
+    return this;
+  }
+
+  public List<String> getUsers() {
+    return users;
+  }
+
+  public IssueAuthorizationDto setUsers(List<String> users) {
+    this.users = users;
+    return this;
+  }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationMapper.java b/sonar-core/src/main/java/org/sonar/core/issue/db/IssueAuthorizationMapper.java
new file mode 100644 (file)
index 0000000..d327f7f
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * 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.issue.db;
+
+public interface IssueAuthorizationMapper {
+
+  IssueAuthorizationDto selectByKey(String key);
+
+}
index 3e9c9d2f5f4a4c43e7958431d5ede9bded6d5e99..58d40c935026afb2fcb71f11ffed128db92390a6 100644 (file)
@@ -137,6 +137,7 @@ public class MyBatis implements BatchComponent, ServerComponent {
     loadAlias(conf, "Measure", MeasureDto.class);
     loadAlias(conf, "Metric", MetricDto.class);
     loadAlias(conf, "Issue", IssueDto.class);
+    loadAlias(conf, "IssueAuthorization", IssueAuthorizationDto.class);
     loadAlias(conf, "IssueChange", IssueChangeDto.class);
     loadAlias(conf, "IssueFilter", IssueFilterDto.class);
     loadAlias(conf, "IssueFilterFavourite", IssueFilterFavouriteDto.class);
@@ -163,7 +164,7 @@ public class MyBatis implements BatchComponent, ServerComponent {
     loadMapper(conf, "org.sonar.core.permission.PermissionMapper");
     Class<?>[] mappers = {ActivityMapper.class, ActiveDashboardMapper.class, AuthorMapper.class, DashboardMapper.class,
       DependencyMapper.class, DuplicationMapper.class, GraphDtoMapper.class,
-      IssueMapper.class, IssueStatsMapper.class, IssueChangeMapper.class, IssueFilterMapper.class, IssueFilterFavouriteMapper.class,
+      IssueMapper.class, IssueAuthorizationMapper.class, IssueStatsMapper.class, IssueChangeMapper.class, IssueFilterMapper.class, IssueFilterFavouriteMapper.class,
       LoadedTemplateMapper.class, MeasureFilterMapper.class, Migration44Mapper.class, PermissionTemplateMapper.class, PropertiesMapper.class, PurgeMapper.class,
       ResourceKeyUpdaterMapper.class, ResourceIndexerMapper.class, ResourceSnapshotMapper.class, RoleMapper.class, RuleMapper.class,
       SchemaMigrationMapper.class, SemaphoreMapper.class, UserMapper.class, WidgetMapper.class, WidgetPropertyMapper.class,
diff --git a/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueAuthorizationMapper.xml b/sonar-core/src/main/resources/org/sonar/core/issue/db/IssueAuthorizationMapper.xml
new file mode 100644 (file)
index 0000000..59dd149
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mappei.dtd">
+
+<mapper namespace="org.sonar.core.issue.db.IssueAuthorizationMapper">
+
+  <select id="selectByKey" parameterType="String" resultType="IssueAuthorization">
+    select *
+    from issues i
+    inner join rules r on r.id=i.rule_id
+    inner join projects p on p.id=i.component_id
+    inner join projects root on root.id=i.root_component_id
+    where i.kee=#{kee}
+  </select>
+
+</mapper>
+