]> source.dussan.org Git - sonarqube.git/blob
1e6cab9ba166bd755023eac1997bb34c8d7cc99b
[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.db.migrations.MassUpdate;
35
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Timer;
39 import java.util.concurrent.atomic.AtomicLong;
40
41 import static com.google.common.collect.Lists.newArrayList;
42 import static com.google.common.collect.Maps.newHashMap;
43
44 /**
45  * Used in the Active Record Migration 705
46  *
47  * @since 5.0
48  */
49 public class PopulateProjectsUuidColumnsMigration implements DatabaseMigration {
50
51   private final DbClient db;
52   private final AtomicLong counter = new AtomicLong(0L);
53   private final MassUpdate.ProgressTask progressTask = new MassUpdate.ProgressTask(counter);
54
55   public PopulateProjectsUuidColumnsMigration(DbClient db) {
56     this.db = db;
57   }
58
59   @Override
60   public void execute() {
61     Timer timer = new Timer("Db Migration Progress");
62     timer.schedule(progressTask, MassUpdate.ProgressTask.PERIOD_MS, MassUpdate.ProgressTask.PERIOD_MS);
63
64     final DbSession readSession = db.openSession(false);
65     final DbSession writeSession = db.openSession(true);
66     try {
67       readSession.select("org.sonar.core.persistence.migration.v50.Migration50Mapper.selectRootProjects", new ResultHandler() {
68         @Override
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);
74         }
75       });
76       writeSession.commit();
77       readSession.commit();
78
79       migrateComponentsWithoutUuid(readSession, writeSession);
80       writeSession.commit();
81
82       // log the total number of process rows
83       progressTask.log();
84     } finally {
85       readSession.close();
86       writeSession.close();
87       timer.cancel();
88       timer.purge();
89     }
90   }
91
92   private void migrateEnabledComponents(DbSession readSession, DbSession writeSession, Component project, Map<Long, String> uuidByComponentId) {
93     Map<Long, Component> componentsBySnapshotId = newHashMap();
94
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);
100
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);
106       }
107     }
108
109     for (Component component : componentsToMigrate) {
110       updateComponent(component, project, componentsBySnapshotId, uuidByComponentId);
111       writeSession.getMapper(Migration50Mapper.class).updateComponentUuids(component);
112       counter.getAndIncrement();
113     }
114   }
115
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);
121
122       writeSession.getMapper(Migration50Mapper.class).updateComponentUuids(component);
123       counter.getAndIncrement();
124     }
125     for (Component component : readSession.getMapper(Migration50Mapper.class).selectDisabledNoneDirectComponentChildrenForProjects(project.getId())) {
126       component.setUuid(getOrCreateUuid(component, uuidByComponentId));
127       component.setProjectUuid(projectUuid);
128
129       writeSession.getMapper(Migration50Mapper.class).updateComponentUuids(component);
130       counter.getAndIncrement();
131     }
132   }
133
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(".");
145         }
146       }
147     }
148     if (moduleUuidPath.length() > 0) {
149       // Remove last '.'
150       moduleUuidPath.deleteCharAt(moduleUuidPath.length() - 1);
151       component.setModuleUuidPath(moduleUuidPath.toString());
152     }
153
154     // Module UUID contains direct module of a component
155     if (lastModule != null) {
156       component.setModuleUuid(getOrCreateUuid(lastModule, uuidByComponentId));
157     }
158   }
159
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);
165
166       writeSession.getMapper(Migration50Mapper.class).updateComponentUuids(component);
167       counter.getAndIncrement();
168     }
169   }
170
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;
174     if (uuid == null) {
175       String newUuid = Uuids.create();
176       uuidByComponentId.put(component.getId(), newUuid);
177       return newUuid;
178     }
179     return uuid;
180   }
181
182 }