2 * SonarQube, open source software quality management tool.
3 * Copyright (C) 2008-2014 SonarSource
4 * mailto:contact AT sonarsource DOT com
6 * SonarQube is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 3 of the License, or (at your option) any later version.
11 * SonarQube is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 package org.sonar.server.db.migrations.v50;
23 import com.google.common.base.Splitter;
24 import com.google.common.base.Strings;
25 import org.apache.ibatis.session.ResultContext;
26 import org.apache.ibatis.session.ResultHandler;
27 import org.sonar.api.resources.Scopes;
28 import org.sonar.api.utils.internal.Uuids;
29 import org.sonar.core.persistence.DbSession;
30 import org.sonar.core.persistence.migration.v50.Component;
31 import org.sonar.core.persistence.migration.v50.Migration50Mapper;
32 import org.sonar.server.db.DbClient;
33 import org.sonar.server.db.migrations.DatabaseMigration;
34 import org.sonar.server.db.migrations.MassUpdate;
36 import java.util.List;
38 import java.util.Timer;
39 import java.util.concurrent.atomic.AtomicLong;
41 import static com.google.common.collect.Lists.newArrayList;
42 import static com.google.common.collect.Maps.newHashMap;
45 * Used in the Active Record Migration 705
49 public class PopulateProjectsUuidColumnsMigration implements DatabaseMigration {
51 private final DbClient db;
52 private final AtomicLong counter = new AtomicLong(0L);
53 private final MassUpdate.ProgressTask progressTask = new MassUpdate.ProgressTask(counter);
55 public PopulateProjectsUuidColumnsMigration(DbClient db) {
60 public void execute() {
61 Timer timer = new Timer("Db Migration Progress");
62 timer.schedule(progressTask, MassUpdate.ProgressTask.PERIOD_MS, MassUpdate.ProgressTask.PERIOD_MS);
64 final DbSession readSession = db.openSession(false);
65 final DbSession writeSession = db.openSession(true);
67 readSession.select("org.sonar.core.persistence.migration.v50.Migration50Mapper.selectRootProjects", new ResultHandler() {
69 public void handleResult(ResultContext context) {
70 Component project = (Component) context.getResultObject();
71 Map<Long, String> uuidByComponentId = newHashMap();
72 migrateEnabledComponents(readSession, writeSession, project, uuidByComponentId);
73 migrateDisabledComponents(readSession, writeSession, project, uuidByComponentId);
76 writeSession.commit();
79 migrateComponentsWithoutUuid(readSession, writeSession);
80 writeSession.commit();
82 // log the total number of process rows
92 private void migrateEnabledComponents(DbSession readSession, DbSession writeSession, Component project, Map<Long, String> uuidByComponentId) {
93 Map<Long, Component> componentsBySnapshotId = newHashMap();
95 List<Component> components = readSession.getMapper(Migration50Mapper.class).selectComponentChildrenForProjects(project.getId());
96 components.add(project);
97 List<Component> componentsToMigrate = newArrayList();
98 for (Component component : components) {
99 componentsBySnapshotId.put(component.getSnapshotId(), component);
101 // Not migrate components already having an UUID
102 if (component.getUuid() == null) {
103 component.setUuid(getOrCreateUuid(component, uuidByComponentId));
104 component.setProjectUuid(getOrCreateUuid(project, uuidByComponentId));
105 componentsToMigrate.add(component);
109 for (Component component : componentsToMigrate) {
110 updateComponent(component, project, componentsBySnapshotId, uuidByComponentId);
111 writeSession.getMapper(Migration50Mapper.class).updateComponentUuids(component);
112 counter.getAndIncrement();
116 private void migrateDisabledComponents(DbSession readSession, DbSession writeSession, Component project, Map<Long, String> uuidByComponentId) {
117 String projectUuid = getOrCreateUuid(project, uuidByComponentId);
118 for (Component component : readSession.getMapper(Migration50Mapper.class).selectDisabledDirectComponentChildrenForProjects(project.getId())) {
119 component.setUuid(getOrCreateUuid(component, uuidByComponentId));
120 component.setProjectUuid(projectUuid);
122 writeSession.getMapper(Migration50Mapper.class).updateComponentUuids(component);
123 counter.getAndIncrement();
125 for (Component component : readSession.getMapper(Migration50Mapper.class).selectDisabledNoneDirectComponentChildrenForProjects(project.getId())) {
126 component.setUuid(getOrCreateUuid(component, uuidByComponentId));
127 component.setProjectUuid(projectUuid);
129 writeSession.getMapper(Migration50Mapper.class).updateComponentUuids(component);
130 counter.getAndIncrement();
134 private void updateComponent(Component component, Component project, Map<Long, Component> componentsBySnapshotId, Map<Long, String> uuidByComponentId) {
135 String snapshotPath = component.getSnapshotPath();
136 StringBuilder moduleUuidPath = new StringBuilder();
137 Component lastModule = null;
138 if (!Strings.isNullOrEmpty(snapshotPath)) {
139 for (String s : Splitter.on(".").omitEmptyStrings().split(snapshotPath)) {
140 Long snapshotId = Long.valueOf(s);
141 Component currentComponent = componentsBySnapshotId.get(snapshotId);
142 if (currentComponent.getScope().equals(Scopes.PROJECT)) {
143 lastModule = currentComponent;
144 moduleUuidPath.append(currentComponent.getUuid()).append(".");
148 if (moduleUuidPath.length() > 0) {
150 moduleUuidPath.deleteCharAt(moduleUuidPath.length() - 1);
151 component.setModuleUuidPath(moduleUuidPath.toString());
154 // Module UUID contains direct module of a component
155 if (lastModule != null) {
156 component.setModuleUuid(getOrCreateUuid(lastModule, uuidByComponentId));
160 private void migrateComponentsWithoutUuid(DbSession readSession, DbSession writeSession) {
161 for (Component component : readSession.getMapper(Migration50Mapper.class).selectComponentsWithoutUuid()) {
162 String uuid = Uuids.create();
163 component.setUuid(uuid);
164 component.setProjectUuid(uuid);
166 writeSession.getMapper(Migration50Mapper.class).updateComponentUuids(component);
167 counter.getAndIncrement();
171 private static String getOrCreateUuid(Component component, Map<Long, String> uuidByComponentId) {
172 String existingUuid = component.getUuid();
173 String uuid = existingUuid == null ? uuidByComponentId.get(component.getId()) : existingUuid;
175 String newUuid = Uuids.create();
176 uuidByComponentId.put(component.getId(), newUuid);