]> source.dussan.org Git - sonarqube.git/blob
f1b414359a5e9a66eb2c617eef16f0e0f3df7647
[sonarqube.git] /
1 /*
2  * SonarQube, open source software quality management tool.
3  * Copyright (C) 2008-2014 SonarSource
4  * mailto:contact AT sonarsource DOT com
5  *
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.
10  *
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.
15  *
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.
19  */
20
21 package org.sonar.server.db.migrations.v50;
22
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.util.ProgressLogger;
35
36 import java.util.List;
37 import java.util.Map;
38 import java.util.concurrent.atomic.AtomicLong;
39
40 import static com.google.common.collect.Lists.newArrayList;
41 import static com.google.common.collect.Maps.newHashMap;
42
43 /**
44  * Used in the Active Record Migration 705
45  *
46  * @since 5.0
47  */
48 public class PopulateProjectsUuidColumnsMigration implements DatabaseMigration {
49
50   private final DbClient db;
51   private final AtomicLong counter = new AtomicLong(0L);
52
53   public PopulateProjectsUuidColumnsMigration(DbClient db) {
54     this.db = db;
55   }
56
57   @Override
58   public void execute() {
59     ProgressLogger progress = ProgressLogger.create(getClass(), counter);
60     progress.start();
61
62     final DbSession readSession = db.openSession(false);
63     final DbSession writeSession = db.openSession(true);
64     try {
65       readSession.select("org.sonar.core.persistence.migration.v50.Migration50Mapper.selectRootProjects", new ResultHandler() {
66         @Override
67         public void handleResult(ResultContext context) {
68           Component project = (Component) context.getResultObject();
69           Map<Long, String> uuidByComponentId = newHashMap();
70           migrateEnabledComponents(readSession, writeSession, project, uuidByComponentId);
71           migrateDisabledComponents(readSession, writeSession, project, uuidByComponentId);
72         }
73       });
74       writeSession.commit(true);
75       readSession.commit(true);
76
77       migrateComponentsWithoutUuid(readSession, writeSession);
78       writeSession.commit(true);
79
80       // log the total number of process rows
81       progress.log();
82     } finally {
83       readSession.close();
84       writeSession.close();
85       progress.stop();
86     }
87   }
88
89   private void migrateEnabledComponents(DbSession readSession, DbSession writeSession, Component project, Map<Long, String> uuidByComponentId) {
90     Map<Long, Component> componentsBySnapshotId = newHashMap();
91
92     List<Component> components = readSession.getMapper(Migration50Mapper.class).selectComponentChildrenForProjects(project.getId());
93     components.add(project);
94     List<Component> componentsToMigrate = newArrayList();
95     for (Component component : components) {
96       componentsBySnapshotId.put(component.getSnapshotId(), component);
97
98       // Not migrate components already having an UUID
99       if (component.getUuid() == null) {
100         component.setUuid(getOrCreateUuid(component, uuidByComponentId));
101         component.setProjectUuid(getOrCreateUuid(project, uuidByComponentId));
102         componentsToMigrate.add(component);
103       }
104     }
105
106     for (Component component : componentsToMigrate) {
107       updateComponent(component, project, componentsBySnapshotId, uuidByComponentId);
108       writeSession.getMapper(Migration50Mapper.class).updateComponentUuids(component);
109       counter.getAndIncrement();
110     }
111   }
112
113   private void migrateDisabledComponents(DbSession readSession, DbSession writeSession, Component project, Map<Long, String> uuidByComponentId) {
114     String projectUuid = getOrCreateUuid(project, uuidByComponentId);
115     for (Component component : readSession.getMapper(Migration50Mapper.class).selectDisabledDirectComponentChildrenForProjects(project.getId())) {
116       component.setUuid(getOrCreateUuid(component, uuidByComponentId));
117       component.setProjectUuid(projectUuid);
118
119       writeSession.getMapper(Migration50Mapper.class).updateComponentUuids(component);
120       counter.getAndIncrement();
121     }
122     for (Component component : readSession.getMapper(Migration50Mapper.class).selectDisabledNoneDirectComponentChildrenForProjects(project.getId())) {
123       component.setUuid(getOrCreateUuid(component, uuidByComponentId));
124       component.setProjectUuid(projectUuid);
125
126       writeSession.getMapper(Migration50Mapper.class).updateComponentUuids(component);
127       counter.getAndIncrement();
128     }
129   }
130
131   private void updateComponent(Component component, Component project, Map<Long, Component> componentsBySnapshotId, Map<Long, String> uuidByComponentId) {
132     String snapshotPath = component.getSnapshotPath();
133     StringBuilder moduleUuidPath = new StringBuilder();
134     Component lastModule = null;
135     if (!Strings.isNullOrEmpty(snapshotPath)) {
136       for (String s : Splitter.on(".").omitEmptyStrings().split(snapshotPath)) {
137         Long snapshotId = Long.valueOf(s);
138         Component currentComponent = componentsBySnapshotId.get(snapshotId);
139         if (currentComponent.getScope().equals(Scopes.PROJECT)) {
140           lastModule = currentComponent;
141           moduleUuidPath.append(currentComponent.getUuid()).append(".");
142         }
143       }
144     }
145     if (moduleUuidPath.length() > 0) {
146       // Remove last '.'
147       moduleUuidPath.deleteCharAt(moduleUuidPath.length() - 1);
148       component.setModuleUuidPath(moduleUuidPath.toString());
149     }
150
151     // Module UUID contains direct module of a component
152     if (lastModule != null) {
153       component.setModuleUuid(getOrCreateUuid(lastModule, uuidByComponentId));
154     }
155   }
156
157   private void migrateComponentsWithoutUuid(DbSession readSession, DbSession writeSession) {
158     for (Component component : readSession.getMapper(Migration50Mapper.class).selectComponentsWithoutUuid()) {
159       String uuid = Uuids.create();
160       component.setUuid(uuid);
161       component.setProjectUuid(uuid);
162
163       writeSession.getMapper(Migration50Mapper.class).updateComponentUuids(component);
164       counter.getAndIncrement();
165     }
166   }
167
168   private static String getOrCreateUuid(Component component, Map<Long, String> uuidByComponentId) {
169     String existingUuid = component.getUuid();
170     String uuid = existingUuid == null ? uuidByComponentId.get(component.getId()) : existingUuid;
171     if (uuid == null) {
172       String newUuid = Uuids.create();
173       uuidByComponentId.put(component.getId(), newUuid);
174       return newUuid;
175     }
176     return uuid;
177   }
178
179 }