aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulien Lancelot <julien.lancelot@sonarsource.com>2015-01-28 12:24:33 +0100
committerJulien Lancelot <julien.lancelot@sonarsource.com>2015-01-29 15:08:49 +0100
commit18ff30bdf1a602b1eff8344af998ece8002af29e (patch)
tree90a78fdf40c002842cf0f4ef3bd79dadd3950865
parent410a553075d6047fa3ec8721f84ad753e2545c5f (diff)
downloadsonarqube-18ff30bdf1a602b1eff8344af998ece8002af29e.tar.gz
sonarqube-18ff30bdf1a602b1eff8344af998ece8002af29e.zip
SONAR-6087 Purge removed Views and Sub-Views Index on each Views analysis
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/db/ComponentDao.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/ComputationComponents.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java3
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PurgeRemovedViewsStep.java85
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/view/index/ViewDoc.java5
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndex.java84
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndexer.java8
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java5
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java9
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeRemovedViewsStepTest.java126
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexTest.java71
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerTest.java6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/view/index/ViewIndexTest/view1.json6
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/view/index/ViewIndexTest/view2.json8
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/UuidWithProjectUuidDto.java45
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/db/ComponentMapper.java4
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java2
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml2
18 files changed, 456 insertions, 23 deletions
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/db/ComponentDao.java b/server/sonar-server/src/main/java/org/sonar/server/component/db/ComponentDao.java
index 84091b1343e..858917deb05 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/component/db/ComponentDao.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/component/db/ComponentDao.java
@@ -27,6 +27,7 @@ import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.System2;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.component.FilePathWithHashDto;
+import org.sonar.core.component.UuidWithProjectUuidDto;
import org.sonar.core.component.db.ComponentMapper;
import org.sonar.core.persistence.DaoComponent;
import org.sonar.core.persistence.DbSession;
@@ -38,7 +39,6 @@ import javax.annotation.CheckForNull;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
import static com.google.common.collect.Lists.newArrayList;
@@ -143,7 +143,7 @@ public class ComponentDao extends BaseDao<ComponentMapper, ComponentDto, String>
return mapper(session).findProjectUuids();
}
- public List<Map<String, String>> selectAllViewsAndSubViews(DbSession session) {
+ public List<UuidWithProjectUuidDto> selectAllViewsAndSubViews(DbSession session) {
return mapper(session).selectAllViewsAndSubViews(Qualifiers.VIEW, Qualifiers.SUBVIEW);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationComponents.java b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationComponents.java
index 51f73608783..7a202030b18 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationComponents.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/ComputationComponents.java
@@ -22,6 +22,7 @@ package org.sonar.server.computation;
import org.sonar.core.issue.db.UpdateConflictResolver;
import org.sonar.server.computation.issue.*;
import org.sonar.server.computation.step.ComputationSteps;
+import org.sonar.server.view.index.ViewIndex;
import java.util.Arrays;
import java.util.List;
@@ -50,6 +51,9 @@ public class ComputationComponents {
RuleCache.class,
RuleCacheLoader.class,
IssueCache.class,
- UpdateConflictResolver.class);
+ UpdateConflictResolver.class,
+
+ // views
+ ViewIndex.class);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
index a2d1f605334..e19da64b18f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
@@ -46,6 +46,9 @@ public class ComputationSteps {
IndexSourceLinesStep.class,
IndexViewsStep.class,
+ // Purge of removed views has to be done after Views has been indexed
+ PurgeRemovedViewsStep.class,
+
// notifications are sent at the end, so that webapp displays up-to-date information
SendIssueNotificationsStep.class);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PurgeRemovedViewsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PurgeRemovedViewsStep.java
new file mode 100644
index 00000000000..de8c824018e
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PurgeRemovedViewsStep.java
@@ -0,0 +1,85 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation.step;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.core.component.UuidWithProjectUuidDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.server.computation.ComputationContext;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.view.index.ViewIndex;
+
+import javax.annotation.Nullable;
+
+import java.util.List;
+import java.util.Set;
+
+import static com.google.common.collect.Sets.newHashSet;
+
+/**
+ * This step will remove every Views and Sub Views from the index that do not exists in the db.
+ * As it's executed on each analysis, it means that when the Views task is executed on every views, this step will be executed on each views !
+ *
+ * A more optimized approach would be to execute this step only once at this end of the Views task.
+ */
+public class PurgeRemovedViewsStep implements ComputationStep {
+
+ private final DbClient dbClient;
+ private final ViewIndex index;
+
+ public PurgeRemovedViewsStep(ViewIndex index, DbClient dbClient) {
+ this.index = index;
+ this.dbClient = dbClient;
+ }
+
+ @Override
+ public void execute(ComputationContext context) {
+ if (context.getProject().qualifier().equals(Qualifiers.VIEW)) {
+ purgeRemovedViews();
+ }
+ }
+
+ private void purgeRemovedViews() {
+ DbSession session = dbClient.openSession(false);
+ try {
+ List<UuidWithProjectUuidDto> uuidWithProjectUuidDtos = dbClient.componentDao().selectAllViewsAndSubViews(session);
+ Set<String> viewUuidsInDb = newHashSet(Iterables.transform(uuidWithProjectUuidDtos, new Function<UuidWithProjectUuidDto, String>() {
+ @Override
+ public String apply(@Nullable UuidWithProjectUuidDto input) {
+ return input != null ? input.getUuid() : null;
+ }
+ }));
+ Set<String> viewUuidsInIndex = newHashSet(index.findAllViewUuids());
+ Set<String> viewsToRemove = Sets.difference(viewUuidsInIndex, viewUuidsInDb);
+ index.delete(viewsToRemove);
+ } finally {
+ session.close();
+ }
+ }
+
+ @Override
+ public String getDescription() {
+ return "Purge removed views";
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewDoc.java b/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewDoc.java
index 55ba66a1867..9b92dd8f72e 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewDoc.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewDoc.java
@@ -20,6 +20,7 @@
package org.sonar.server.view.index;
+import com.google.common.collect.Maps;
import org.sonar.server.search.BaseDoc;
import java.util.List;
@@ -31,6 +32,10 @@ public class ViewDoc extends BaseDoc {
super(fields);
}
+ public ViewDoc() {
+ super(Maps.<String, Object>newHashMap());
+ }
+
public String uuid() {
return getField(ViewIndexDefinition.FIELD_UUID);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndex.java b/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndex.java
new file mode 100644
index 00000000000..67341fb7e36
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndex.java
@@ -0,0 +1,84 @@
+/*
+ * 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.view.index;
+
+import org.elasticsearch.action.search.SearchRequestBuilder;
+import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.action.search.SearchType;
+import org.elasticsearch.common.unit.TimeValue;
+import org.elasticsearch.index.query.FilterBuilders;
+import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.search.SearchHit;
+import org.sonar.api.ServerComponent;
+import org.sonar.server.es.EsClient;
+
+import java.util.Collection;
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+
+public class ViewIndex implements ServerComponent {
+
+ private final int SCROLL_TIME_IN_MINUTES = 3;
+
+ private final EsClient esClient;
+
+ public ViewIndex(EsClient esClient) {
+ this.esClient = esClient;
+ }
+
+ public List<String> findAllViewUuids() {
+ SearchRequestBuilder esSearch = esClient.prepareSearch(ViewIndexDefinition.INDEX)
+ .setTypes(ViewIndexDefinition.TYPE_VIEW)
+ .setSearchType(SearchType.SCAN)
+ .setScroll(TimeValue.timeValueMinutes(SCROLL_TIME_IN_MINUTES))
+ .setFetchSource(ViewIndexDefinition.FIELD_UUID, null)
+ .setSize(100)
+ .setQuery(QueryBuilders.matchAllQuery());
+
+ SearchResponse response = esSearch.get();
+ List<String> result = newArrayList();
+ while (true) {
+ List<SearchHit> hits = newArrayList(response.getHits());
+ for (SearchHit hit : hits) {
+ result.add((String) hit.getSource().get(ViewIndexDefinition.FIELD_UUID));
+ }
+ response = esClient.prepareSearchScroll(response.getScrollId())
+ .setScroll(TimeValue.timeValueMinutes(SCROLL_TIME_IN_MINUTES))
+ .get();
+ // Break condition: No hits are returned
+ if (response.getHits().getHits().length == 0) {
+ break;
+ }
+ }
+ return result;
+ }
+
+ public void delete(Collection<String> viewUuids) {
+ esClient
+ .prepareDeleteByQuery(ViewIndexDefinition.INDEX)
+ .setTypes(ViewIndexDefinition.TYPE_VIEW)
+ .setQuery(QueryBuilders.filteredQuery(QueryBuilders.matchAllQuery(),
+ FilterBuilders.termsFilter(ViewIndexDefinition.FIELD_UUID, viewUuids)
+ ))
+ .get();
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndexer.java b/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndexer.java
index 78bc4f7d2c6..cb6ed32d19f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndexer.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndexer.java
@@ -20,9 +20,9 @@
package org.sonar.server.view.index;
-import com.google.common.collect.Maps;
import org.elasticsearch.action.update.UpdateRequest;
import org.sonar.core.component.ComponentDto;
+import org.sonar.core.component.UuidWithProjectUuidDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.server.db.DbClient;
import org.sonar.server.es.BaseIndexer;
@@ -53,8 +53,8 @@ public class ViewIndexer extends BaseIndexer {
DbSession dbSession = dbClient.openSession(false);
try {
Map<String, String> viewAndProjectViewUuidMap = newHashMap();
- for (Map<String, String> viewsMap : dbClient.componentDao().selectAllViewsAndSubViews(dbSession)) {
- viewAndProjectViewUuidMap.put(viewsMap.get("uuid"), viewsMap.get("projectUuid"));
+ for (UuidWithProjectUuidDto uuidWithProjectUuidDto : dbClient.componentDao().selectAllViewsAndSubViews(dbSession)) {
+ viewAndProjectViewUuidMap.put(uuidWithProjectUuidDto.getUuid(), uuidWithProjectUuidDto.getProjectUuid());
}
index(dbSession, viewAndProjectViewUuidMap);
} finally {
@@ -88,7 +88,7 @@ public class ViewIndexer extends BaseIndexer {
private void doIndex(DbSession dbSession, BulkIndexer bulk, String uuid, String projectUuid) {
List<String> projects = dbClient.componentDao().selectProjectsFromView(dbSession, uuid, projectUuid);
- bulk.add(newUpsertRequest(new ViewDoc(Maps.<String, Object>newHashMap())
+ bulk.add(newUpsertRequest(new ViewDoc()
.setUuid(uuid)
.setProjects(projects)));
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java
index ccbba1a36e4..a5f007bee05 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/component/ComponentTesting.java
@@ -56,7 +56,10 @@ public class ComponentTesting {
}
public static ComponentDto newModuleDto(ComponentDto subProjectOrProject) {
- String uuid = Uuids.create();
+ return newModuleDto(subProjectOrProject, Uuids.create());
+ }
+
+ public static ComponentDto newModuleDto(ComponentDto subProjectOrProject, String uuid) {
return newComponent(subProjectOrProject, uuid)
.setKey("KEY_" + uuid)
.setName("NAME_" + uuid)
diff --git a/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java b/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java
index 80ba999ed90..2cccb49f4c8 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/component/db/ComponentDaoTest.java
@@ -20,7 +20,6 @@
package org.sonar.server.component.db;
-import com.google.common.collect.ImmutableMap;
import org.apache.ibatis.exceptions.PersistenceException;
import org.junit.After;
import org.junit.Before;
@@ -440,12 +439,8 @@ public class ComponentDaoTest extends AbstractDaoTestCase {
public void select_views_and_sub_views() {
setupData("shared_views");
- assertThat(dao.selectAllViewsAndSubViews(session)).contains(
- ImmutableMap.of("uuid", "ABCD", "projectUuid", "ABCD"),
- ImmutableMap.of("uuid", "EFGH", "projectUuid", "EFGH"),
- ImmutableMap.of("uuid", "FGHI", "projectUuid", "EFGH"),
- ImmutableMap.of("uuid", "IJKL", "projectUuid", "IJKL")
- );
+ assertThat(dao.selectAllViewsAndSubViews(session)).extracting("uuid").containsOnly("ABCD", "EFGH", "FGHI", "IJKL");
+ assertThat(dao.selectAllViewsAndSubViews(session)).extracting("projectUuid").containsOnly("ABCD", "EFGH", "IJKL");
}
@Test
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeRemovedViewsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeRemovedViewsStepTest.java
new file mode 100644
index 00000000000..e14386b9705
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeRemovedViewsStepTest.java
@@ -0,0 +1,126 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation.step;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import org.elasticsearch.search.SearchHit;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.component.ComponentTesting;
+import org.sonar.server.component.db.ComponentDao;
+import org.sonar.server.computation.ComputationContext;
+import org.sonar.server.db.DbClient;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.issue.db.IssueDao;
+import org.sonar.server.view.index.ViewDoc;
+import org.sonar.server.view.index.ViewIndex;
+import org.sonar.server.view.index.ViewIndexDefinition;
+
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class PurgeRemovedViewsStepTest {
+
+ @Rule
+ public EsTester esTester = new EsTester().addDefinitions(new ViewIndexDefinition(new Settings()));
+
+ @Rule
+ public DbTester db = new DbTester();
+
+ ComputationContext context;
+
+ DbSession session;
+
+ DbClient dbClient;
+
+ PurgeRemovedViewsStep step;
+
+ @Before
+ public void setUp() {
+ context = mock(ComputationContext.class);
+ session = db.myBatis().openSession(false);
+ dbClient = new DbClient(db.database(), db.myBatis(), new IssueDao(db.myBatis()), new ComponentDao());
+ step = new PurgeRemovedViewsStep(new ViewIndex(esTester.client()), dbClient);
+ }
+
+ @After
+ public void after() {
+ this.session.close();
+ }
+
+ @Test
+ public void purge_removed_views() throws Exception {
+ when(context.getProject()).thenReturn(ComponentTesting.newProjectDto("DBCA").setQualifier(Qualifiers.VIEW));
+
+ esTester.putDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW,
+ new ViewDoc().setUuid("ABCD").getFields(),
+ new ViewDoc().setUuid("BCDE").getFields(),
+ // Should be removed as it no more exists in db
+ new ViewDoc().setUuid("CDEF").getFields());
+
+ ComponentDto view = ComponentTesting.newProjectDto("ABCD").setQualifier(Qualifiers.VIEW);
+ ComponentDto subView = ComponentTesting.newModuleDto(view, "BCDE").setQualifier(Qualifiers.SUBVIEW);
+ dbClient.componentDao().insert(session, view, subView);
+ session.commit();
+
+ step.execute(context);
+
+ List<SearchHit> results = esTester.getDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW);
+ List<String> viewUuids = newArrayList(Iterables.transform(results, new Function<SearchHit, String>() {
+ @Override
+ public String apply(SearchHit input) {
+ return new ViewDoc(input.getSource()).uuid();
+ }
+ }));
+ assertThat(viewUuids).containsOnly("ABCD", "BCDE");
+ }
+
+ @Test
+ public void nothing_to_do_when_not_analysing_view() throws Exception {
+ when(context.getProject()).thenReturn(ComponentTesting.newProjectDto("DBCA"));
+
+ esTester.putDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW,
+ new ViewDoc().setUuid("ABCD").getFields(),
+ // This vies does not exists in db...
+ new ViewDoc().setUuid("BCDE").getFields());
+
+ dbClient.componentDao().insert(session, ComponentTesting.newProjectDto("ABCD").setQualifier(Qualifiers.VIEW));
+ session.commit();
+
+ step.execute(context);
+
+ // ... But it should not be removed as the project of the context is not a view
+ assertThat(esTester.countDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW)).isEqualTo(2);
+ }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexTest.java b/server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexTest.java
new file mode 100644
index 00000000000..44f72a67151
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.view.index;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.config.Settings;
+import org.sonar.server.es.EsTester;
+
+import java.util.List;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ViewIndexTest {
+
+ @Rule
+ public EsTester esTester = new EsTester().addDefinitions(new ViewIndexDefinition(new Settings()));
+
+ private ViewIndex index;
+
+ @Before
+ public void setUp() {
+ index = new ViewIndex(esTester.client());
+ }
+
+ @Test
+ public void find_all_view_uuids() throws Exception {
+ esTester.putDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW, this.getClass(), "view1.json", "view2.json");
+
+ List<String> result = newArrayList(index.findAllViewUuids());
+
+ assertThat(result).containsOnly("fed0a543-9d9c-4af5-a4ec-450a8fe78ce7", "8d0bc2a5-bfba-464b-92de-bb170e9d978e");
+ }
+
+ @Test
+ public void not_find_all_view_uuids() throws Exception {
+ List<String> result = newArrayList(index.findAllViewUuids());
+
+ assertThat(result).isEmpty();
+ }
+
+ @Test
+ public void delete_views() throws Exception {
+ esTester.putDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW, this.getClass(), "view1.json", "view2.json");
+
+ index.delete(newArrayList("fed0a543-9d9c-4af5-a4ec-450a8fe78ce7", "8d0bc2a5-bfba-464b-92de-bb170e9d978e"));
+
+ assertThat(esTester.countDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW)).isEqualTo(0L);
+ }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerTest.java b/server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerTest.java
index 966b66d9401..4e8485a5027 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/view/index/ViewIndexerTest.java
@@ -21,7 +21,6 @@
package org.sonar.server.view.index;
import com.google.common.base.Function;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import org.junit.Before;
import org.junit.Rule;
@@ -89,10 +88,7 @@ public class ViewIndexerTest {
// Some views are not in the db
dbTester.prepareDbUnit(getClass(), "index.xml");
esTester.putDocuments(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW,
- ImmutableMap.<String, Object>of(
- ViewIndexDefinition.FIELD_UUID, "ABCD",
- ViewIndexDefinition.FIELD_PROJECTS, newArrayList("BCDE")
- ));
+ new ViewDoc().setUuid("ABCD").setProjects(newArrayList("BCDE")).getFields());
indexer.index();
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/view/index/ViewIndexTest/view1.json b/server/sonar-server/src/test/resources/org/sonar/server/view/index/ViewIndexTest/view1.json
new file mode 100644
index 00000000000..246e7ad41a6
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/view/index/ViewIndexTest/view1.json
@@ -0,0 +1,6 @@
+{
+ "uuid": "fed0a543-9d9c-4af5-a4ec-450a8fe78ce7",
+ "projects": [
+ "548415bc-6626-45b1-a99a-ca77aedec45f"
+ ]
+}
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/view/index/ViewIndexTest/view2.json b/server/sonar-server/src/test/resources/org/sonar/server/view/index/ViewIndexTest/view2.json
new file mode 100644
index 00000000000..b88462641d2
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/view/index/ViewIndexTest/view2.json
@@ -0,0 +1,8 @@
+{
+ "uuid": "8d0bc2a5-bfba-464b-92de-bb170e9d978e",
+ "projects": [
+ "e5dccc4f-431a-46ba-ab55-47318c332af7",
+ "6432a311-4d1f-41fd-b90a-826130f6f890",
+ "bf93ca9b-18f6-4f5d-848b-722ca7bd67d1"
+ ]
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/component/UuidWithProjectUuidDto.java b/sonar-core/src/main/java/org/sonar/core/component/UuidWithProjectUuidDto.java
new file mode 100644
index 00000000000..82fe44a82dd
--- /dev/null
+++ b/sonar-core/src/main/java/org/sonar/core/component/UuidWithProjectUuidDto.java
@@ -0,0 +1,45 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.core.component;
+
+public class UuidWithProjectUuidDto {
+
+ private String uuid;
+ private String projectUuid;
+
+ public String getProjectUuid() {
+ return projectUuid;
+ }
+
+ public UuidWithProjectUuidDto setProjectUuid(String projectUuid) {
+ this.projectUuid = projectUuid;
+ return this;
+ }
+
+ public String getUuid() {
+ return uuid;
+ }
+
+ public UuidWithProjectUuidDto setUuid(String uuid) {
+ this.uuid = uuid;
+ return this;
+ }
+}
diff --git a/sonar-core/src/main/java/org/sonar/core/component/db/ComponentMapper.java b/sonar-core/src/main/java/org/sonar/core/component/db/ComponentMapper.java
index 81215f8d557..344bedd75fa 100644
--- a/sonar-core/src/main/java/org/sonar/core/component/db/ComponentMapper.java
+++ b/sonar-core/src/main/java/org/sonar/core/component/db/ComponentMapper.java
@@ -23,12 +23,12 @@ package org.sonar.core.component.db;
import org.apache.ibatis.annotations.Param;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.component.FilePathWithHashDto;
+import org.sonar.core.component.UuidWithProjectUuidDto;
import javax.annotation.CheckForNull;
import java.util.Collection;
import java.util.List;
-import java.util.Map;
/**
* @since 4.3
@@ -88,7 +88,7 @@ public interface ComponentMapper {
/**
* Return all views and sub views
*/
- List<Map<String, String>> selectAllViewsAndSubViews(@Param("viewQualifier") String viewQualifier, @Param("subViewQualifier") String subViewQualifier);
+ List<UuidWithProjectUuidDto> selectAllViewsAndSubViews(@Param("viewQualifier") String viewQualifier, @Param("subViewQualifier") String subViewQualifier);
/**
* Return technical projects from a view or a sub-view
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
index 75f75cf9089..a3c29f4e0c0 100644
--- a/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/MyBatis.java
@@ -38,6 +38,7 @@ import org.sonar.core.cluster.WorkQueue;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.component.FilePathWithHashDto;
import org.sonar.core.component.SnapshotDto;
+import org.sonar.core.component.UuidWithProjectUuidDto;
import org.sonar.core.component.db.ComponentMapper;
import org.sonar.core.component.db.SnapshotMapper;
import org.sonar.core.computation.db.AnalysisReportDto;
@@ -181,6 +182,7 @@ public class MyBatis implements BatchComponent, ServerComponent {
loadAlias(conf, "AnalysisReport", AnalysisReportDto.class);
loadAlias(conf, "IdUuidPair", IdUuidPair.class);
loadAlias(conf, "FilePathWithHash", FilePathWithHashDto.class);
+ loadAlias(conf, "UuidWithProjectUuid", UuidWithProjectUuidDto.class);
// AuthorizationMapper has to be loaded before IssueMapper because this last one used it
loadMapper(conf, "org.sonar.core.user.AuthorizationMapper");
diff --git a/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml b/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml
index c9a2d7ca514..3b496246050 100644
--- a/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml
+++ b/sonar-core/src/main/resources/org/sonar/core/component/db/ComponentMapper.xml
@@ -156,7 +156,7 @@
</where>
</select>
- <select id="selectAllViewsAndSubViews" resultType="hashmap">
+ <select id="selectAllViewsAndSubViews" resultType="UuidWithProjectUuid">
SELECT v.uuid as "uuid", v.project_uuid as "projectUuid" FROM projects v
<where>
v.enabled=${_true} AND v.qualifier=#{viewQualifier} OR v.qualifier=#{subViewQualifier}