diff options
author | Jacek <jacek.poreda@sonarsource.com> | 2021-08-12 16:55:04 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2021-09-08 20:03:34 +0000 |
commit | cfe5faf0b14841bdad0cae24ac89832c98d1d32a (patch) | |
tree | b089d578bc9b598f46c79e0c22d254fafafcc1fe /server/sonar-db-dao/src/main/java/org/sonar/db | |
parent | 6ad72a24b224d7949ad790b70ef4ae8352ba1899 (diff) | |
download | sonarqube-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')
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; - } - -} |