aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-db-dao/src/main/java/org/sonar/db
diff options
context:
space:
mode:
authorJacek <jacek.poreda@sonarsource.com>2021-08-12 16:55:04 +0200
committersonartech <sonartech@sonarsource.com>2021-09-08 20:03:34 +0000
commitcfe5faf0b14841bdad0cae24ac89832c98d1d32a (patch)
treeb089d578bc9b598f46c79e0c22d254fafafcc1fe /server/sonar-db-dao/src/main/java/org/sonar/db
parent6ad72a24b224d7949ad790b70ef4ae8352ba1899 (diff)
downloadsonarqube-cfe5faf0b14841bdad0cae24ac89832c98d1d32a.tar.gz
sonarqube-cfe5faf0b14841bdad0cae24ac89832c98d1d32a.zip
SONAR-15259 Migrate portfolios from XML to DB
Diffstat (limited to 'server/sonar-db-dao/src/main/java/org/sonar/db')
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java2
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java7
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDao.java31
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDto.java5
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioMapper.java8
-rw-r--r--server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioService.java212
6 files changed, 45 insertions, 220 deletions
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java
index bf6bda78ddb..f288a33053d 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DaoModule.java
@@ -58,6 +58,7 @@ import org.sonar.db.permission.UserPermissionDao;
import org.sonar.db.permission.template.PermissionTemplateCharacteristicDao;
import org.sonar.db.permission.template.PermissionTemplateDao;
import org.sonar.db.plugin.PluginDao;
+import org.sonar.db.portfolio.PortfolioDao;
import org.sonar.db.project.ProjectDao;
import org.sonar.db.property.InternalComponentPropertiesDao;
import org.sonar.db.property.InternalPropertiesDao;
@@ -134,6 +135,7 @@ public class DaoModule extends Module {
PermissionTemplateDao.class,
PluginDao.class,
ProjectDao.class,
+ PortfolioDao.class,
ProjectLinkDao.class,
ProjectMappingsDao.class,
ProjectQgateAssociationDao.class,
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java
index ea6a0516646..3efb4aee142 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/DbClient.java
@@ -56,6 +56,7 @@ import org.sonar.db.permission.UserPermissionDao;
import org.sonar.db.permission.template.PermissionTemplateCharacteristicDao;
import org.sonar.db.permission.template.PermissionTemplateDao;
import org.sonar.db.plugin.PluginDao;
+import org.sonar.db.portfolio.PortfolioDao;
import org.sonar.db.project.ProjectDao;
import org.sonar.db.property.InternalComponentPropertiesDao;
import org.sonar.db.property.InternalPropertiesDao;
@@ -156,6 +157,7 @@ public class DbClient {
private final ProjectMappingsDao projectMappingsDao;
private final NewCodePeriodDao newCodePeriodDao;
private final ProjectDao projectDao;
+ private final PortfolioDao portfolioDao;
private final SessionTokensDao sessionTokensDao;
private final SamlMessageIdDao samlMessageIdDao;
private final UserDismissedMessagesDao userDismissedMessagesDao;
@@ -232,6 +234,7 @@ public class DbClient {
internalComponentPropertiesDao = getDao(map, InternalComponentPropertiesDao.class);
newCodePeriodDao = getDao(map, NewCodePeriodDao.class);
projectDao = getDao(map, ProjectDao.class);
+ portfolioDao = getDao(map, PortfolioDao.class);
sessionTokensDao = getDao(map, SessionTokensDao.class);
samlMessageIdDao = getDao(map, SamlMessageIdDao.class);
userDismissedMessagesDao = getDao(map, UserDismissedMessagesDao.class);
@@ -314,6 +317,10 @@ public class DbClient {
return projectDao;
}
+ public PortfolioDao portfolioDao() {
+ return portfolioDao;
+ }
+
public ComponentKeyUpdaterDao componentKeyUpdaterDao() {
return componentKeyUpdaterDao;
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDao.java b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDao.java
index 602ca4b6144..aaa87d1624d 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDao.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDao.java
@@ -19,15 +19,23 @@
*/
package org.sonar.db.portfolio;
-import static java.util.Collections.singleton;
-
+import java.util.Collection;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Collectors;
import org.sonar.api.utils.System2;
import org.sonar.core.util.UuidFactory;
import org.sonar.db.Dao;
import org.sonar.db.DbSession;
+import org.sonar.db.project.ProjectDto;
+
+import static java.util.Collections.singleton;
+import static java.util.stream.Collectors.groupingBy;
+import static java.util.stream.Collectors.mapping;
+import static java.util.stream.Collectors.toSet;
+import static org.sonar.db.DatabaseUtils.executeLargeInputs;
public class PortfolioDao implements Dao {
private final System2 system2;
@@ -54,6 +62,9 @@ public class PortfolioDao implements Dao {
}
public void insert(DbSession dbSession, PortfolioDto portfolio) {
+ if (portfolio.getUuid() == null) {
+ portfolio.setUuid(uuidFactory.create());
+ }
mapper(dbSession).insert(portfolio);
}
@@ -63,7 +74,6 @@ public class PortfolioDao implements Dao {
mapper(dbSession).deleteProjectsByPortfolioUuids(singleton(portfolioUuid));
}
-
public void deleteByUuids(DbSession dbSession, Set<String> portfolioUuids) {
if (portfolioUuids.isEmpty()) {
return;
@@ -95,12 +105,16 @@ public class PortfolioDao implements Dao {
return mapper(dbSession).selectReferencersByKey(referenceKey);
}
- public Set<String> getProjects(DbSession dbSession, String portfolioUuid) {
+ public List<ProjectDto> getProjects(DbSession dbSession, String portfolioUuid) {
return mapper(dbSession).selectProjects(portfolioUuid);
}
- Set<String> getAllProjectsInHierarchy(DbSession dbSession, String rootUuid) {
- return mapper(dbSession).selectAllProjectsInHierarchy(rootUuid);
+ public Map<String, Set<String>> getAllProjectsInHierarchy(DbSession dbSession, String rootUuid) {
+ return mapper(dbSession).selectAllProjectsInHierarchy(rootUuid)
+ .stream()
+ .collect(groupingBy(
+ PortfolioProjectDto::getProjectUuid,
+ mapping(PortfolioProjectDto::getPortfolioUuid, toSet())));
}
public void addProject(DbSession dbSession, String portfolioUuid, String projectUuid) {
@@ -123,4 +137,9 @@ public class PortfolioDao implements Dao {
public void deleteProjects(DbSession dbSession, String portfolioUuid) {
mapper(dbSession).deleteProjects(portfolioUuid);
}
+
+ public Map<String, String> selectKeysByUuids(DbSession dbSession, Collection<String> uuids) {
+ return executeLargeInputs(uuids, uuids1 -> mapper(dbSession).selectByUuids(uuids1)).stream()
+ .collect(Collectors.toMap(PortfolioDto::getUuid, PortfolioDto::getKey));
+ }
}
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDto.java b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDto.java
index 80ae264af5e..9a06cc38d65 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDto.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioDto.java
@@ -74,6 +74,11 @@ public class PortfolioDto {
return this;
}
+ public PortfolioDto setSelectionMode(SelectionMode selectionMode) {
+ this.selectionMode = selectionMode.name();
+ return this;
+ }
+
@CheckForNull
public String getSelectionExpression() {
return selectionExpression;
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioMapper.java b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioMapper.java
index 929ab51f82e..720ecd99e76 100644
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioMapper.java
+++ b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioMapper.java
@@ -19,10 +19,12 @@
*/
package org.sonar.db.portfolio;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
import javax.annotation.CheckForNull;
import org.apache.ibatis.annotations.Param;
+import org.sonar.db.project.ProjectDto;
public interface PortfolioMapper {
@CheckForNull
@@ -53,11 +55,13 @@ public interface PortfolioMapper {
List<PortfolioDto> selectReferencersByKey(String referenceKey);
- Set<String> selectProjects(String portfolioUuid);
+ List<ProjectDto> selectProjects(String portfolioUuid);
List<ReferenceDto> selectAllReferencesToPortfolios();
- Set<String> selectAllProjectsInHierarchy(String rootUuid);
+ Set<PortfolioProjectDto> selectAllProjectsInHierarchy(String rootUuid);
+
+ List<PortfolioDto> selectByUuids(@Param("uuids") Collection<String> uuids);
void update(PortfolioDto portfolio);
diff --git a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioService.java b/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioService.java
deleted file mode 100644
index 2c16358f579..00000000000
--- a/server/sonar-db-dao/src/main/java/org/sonar/db/portfolio/PortfolioService.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2016-2021 SonarSource SA
- * All rights reserved
- * mailto:info AT sonarsource DOT com
- */
-package org.sonar.db.portfolio;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-import javax.annotation.Nullable;
-import org.sonar.db.DbClient;
-import org.sonar.db.DbSession;
-import org.sonar.db.project.ProjectDao;
-import org.sonar.db.project.ProjectDto;
-
-import static java.lang.String.format;
-import static java.util.Collections.emptyList;
-
-public class PortfolioService {
- private final DbClient dbClient;
- private final PortfolioDao portfolioDao;
- private final ProjectDao projectDao;
-
- public PortfolioService(DbClient dbClient, PortfolioDao portfolioDao, ProjectDao projectDao) {
- this.dbClient = dbClient;
- this.portfolioDao = portfolioDao;
- this.projectDao = projectDao;
- }
-
- public void deleteReferencersTo(String referenceKey) {
- try (DbSession dbSession = dbClient.openSession(false)) {
- List<PortfolioDto> referencers = portfolioDao.selectReferencersByKey(dbSession, referenceKey);
- }
- }
-
- public List<PortfolioDto> getRoots() {
- try (DbSession dbSession = dbClient.openSession(false)) {
- return portfolioDao.selectAllRoots(dbSession);
- }
- }
-
- public List<PortfolioDto> getReferencersByKey(String referenceKey) {
- try (DbSession dbSession = dbClient.openSession(false)) {
- return portfolioDao.selectReferencersByKey(dbSession, referenceKey);
- }
- }
-
- public void addReferenceToPortfolio(String portfolioKey, PortfolioDto refPortfolio) {
- try (DbSession dbSession = dbClient.openSession(false)) {
- PortfolioDto portfolio = selectByKeyOrFail(dbSession, portfolioKey);
- Set<String> treeReferenceConnections = getTreeReferenceConnections(dbSession, portfolio.getRootUuid());
- if (treeReferenceConnections.contains(refPortfolio.getRootUuid())) {
- throw new IllegalArgumentException(format("Can't reference portfolio '%s' in portfolio '%s' - hierarchy would be inconsistent",
- refPortfolio.getKey(), portfolio.getKey()));
- }
- portfolioDao.addReference(dbSession, portfolio.getUuid(), refPortfolio.getUuid());
- }
- }
-
- public void addReferenceToApplication(String portfolioKey, ProjectDto app) {
- // TODO
- }
-
- public void refresh(List<PortfolioDto> portfolios) {
- Set<String> rootUuids = portfolios.stream().map(PortfolioDto::getRootUuid).collect(Collectors.toSet());
- // TODO eliminate duplicates based on references
-
-
- }
-
- public void appendProject(String portfolioKey, String projectKey) {
- try (DbSession dbSession = dbClient.openSession(false)) {
- PortfolioDto portfolio = selectByKeyOrFail(dbSession, portfolioKey);
- ProjectDto project = projectDao.selectProjectByKey(dbSession, projectKey).orElseThrow(() -> new IllegalArgumentException(format("Project '%s' not found", projectKey)));
-
- String rootUuid = portfolio.getRootUuid();
- Set<String> allProjectUuids = portfolioDao.getAllProjectsInHierarchy(dbSession, rootUuid);
- if (allProjectUuids.contains(project.getUuid())) {
- // TODO specify which portfolio?
- throw new IllegalArgumentException("The project with key %s is already selected in a portfolio in the hierarchy");
- }
- portfolioDao.addProject(dbSession, portfolio.getUuid(), project.getUuid());
- }
- }
-
- public void removeProject(String portfolioKey, String projectKey) {
-
- }
-
- public void updateSelectionMode(String portfolioKey, String selectionMode, @Nullable String selectionExpression) {
- PortfolioDto.SelectionMode mode = PortfolioDto.SelectionMode.valueOf(selectionMode);
- try (DbSession dbSession = dbClient.openSession(false)) {
- PortfolioDto portfolio = selectByKeyOrFail(dbSession, portfolioKey);
-
- if (mode.equals(PortfolioDto.SelectionMode.REST)) {
- for (PortfolioDto p : portfolioDao.selectTree(dbSession, portfolio.getUuid())) {
- if (!p.getUuid().equals(portfolio.getUuid()) && mode.name().equals(portfolio.getSelectionMode())) {
- p.setSelectionMode(PortfolioDto.SelectionMode.NONE.name());
- p.setSelectionExpression(null);
- portfolioDao.update(dbSession, p);
- }
- }
- }
-
- portfolio.setSelectionMode(selectionMode);
- portfolio.setSelectionExpression(selectionExpression);
-
- if (!mode.equals(PortfolioDto.SelectionMode.MANUAL)) {
- portfolioDao.deleteProjects(dbSession, portfolio.getUuid());
- }
-
- portfolioDao.update(dbSession, portfolio);
- }
- }
-
- /**
- * Deletes a portfolio and all of it's children.
- * Also deletes references from/to the deleted portfolios and the projects manually assigned to them.
- */
- public void delete(String portfolioKey) {
- try (DbSession dbSession = dbClient.openSession(false)) {
- PortfolioDto portfolio = selectByKeyOrFail(dbSession, portfolioKey);
- Set<String> subTree = getChildrenRecursively(dbSession, portfolio.getUuid()).stream().map(PortfolioDto::getUuid).collect(Collectors.toSet());
- portfolioDao.deleteByUuids(dbSession, subTree);
- // TODO trigger refresh
- }
- }
-
- private PortfolioDto selectByKeyOrFail(DbSession dbSession, String portfolioKey) {
- return portfolioDao.selectByKey(dbSession, portfolioKey).orElseThrow(() -> new IllegalArgumentException(format("Portfolio '%s' not found", portfolioKey)));
- }
-
- /**
- * Gets all portfolios belonging to a subtree, given its root
- */
- private List<PortfolioDto> getChildrenRecursively(DbSession dbSession, String portfolioUuid) {
- Map<String, PortfolioDto> tree = portfolioDao.selectTree(dbSession, portfolioUuid).stream().collect(Collectors.toMap(PortfolioDto::getUuid, x -> x));
- Map<String, Set<String>> childrenMap = new HashMap<>();
-
- for (PortfolioDto dto : tree.values()) {
- if (dto.getParentUuid() != null) {
- childrenMap.computeIfAbsent(dto.getParentUuid(), x -> new HashSet<>()).add(dto.getUuid());
- }
- }
-
- List<PortfolioDto> subTree = new ArrayList<>();
- LinkedList<String> stack = new LinkedList<>();
- stack.add(portfolioUuid);
-
- while (!stack.isEmpty()) {
- Set<String> children = childrenMap.get(stack.removeFirst());
- for (String child : children) {
- subTree.add(tree.get(child));
- stack.add(child);
- }
- }
-
- return subTree;
- }
-
- /**
- * Returns the root UUIDs of all trees with which the tree with the given root uuid is connected through a reference.
- * The connection can be incoming or outgoing, and it can be direct or indirect (through other trees).
- *
- * As an example, let's consider we have the following hierarchies of portfolios:
- *
- * A D - - -> F
- * |\ | |\
- * B C - - - > E G H
- *
- * Where C references E and D references F.
- * All 3 tree roots are connected to all the other roots.
- *
- * getTreeReferenceConnections(A) would return [D,F]
- * getTreeReferenceConnections(D) would return [A,F]
- * getTreeReferenceConnections(F) would return [A,D]
- */
- private Set<String> getTreeReferenceConnections(DbSession dbSession, String treeRootUuid) {
- List<ReferenceDto> references = portfolioDao.selectAllReferencesToPortfolios(dbSession);
-
- Map<String, List<String>> rootConnections = new HashMap<>();
-
- for (ReferenceDto ref : references) {
- rootConnections.computeIfAbsent(ref.getSourceRootUuid(), x -> new ArrayList<>()).add(ref.getTargetRootUuid());
- rootConnections.computeIfAbsent(ref.getTargetRootUuid(), x -> new ArrayList<>()).add(ref.getSourceRootUuid());
- }
-
- LinkedList<String> queue = new LinkedList<>();
- Set<String> transitiveReferences = new HashSet<>();
-
- // add all direct references
- queue.addAll(rootConnections.getOrDefault(treeRootUuid, emptyList()));
-
- // resolve all transitive references
- while (!queue.isEmpty()) {
- String uuid = queue.remove();
- if (!transitiveReferences.contains(uuid)) {
- queue.addAll(rootConnections.getOrDefault(treeRootUuid, emptyList()));
- transitiveReferences.add(uuid);
- }
- }
-
- return transitiveReferences;
- }
-
-}