org.sonar.server.db.migrations.v50.PopulateProjectsUuidColumnsMigrationStep.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.server.db.migrations.v50.PopulateProjectsUuidColumnsMigrationStep.java

Source

/*
 * SonarQube, open source software quality management tool.
 * Copyright (C) 2008-2014 SonarSource
 * mailto:contact AT sonarsource DOT com
 *
 * SonarQube is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * SonarQube is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

package org.sonar.server.db.migrations.v50;

import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.sonar.api.resources.Scopes;
import org.sonar.api.utils.internal.Uuids;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.migration.v50.Component;
import org.sonar.core.persistence.migration.v50.Migration50Mapper;
import org.sonar.server.db.DbClient;
import org.sonar.server.db.migrations.MigrationStep;
import org.sonar.server.util.ProgressLogger;

import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;

/**
 * Used in the Active Record Migration 705
 *
 * @since 5.0
 */
public class PopulateProjectsUuidColumnsMigrationStep implements MigrationStep {

    private static final Logger LOG = Loggers.get(PopulateProjectsUuidColumnsMigrationStep.class);

    private final DbClient db;
    private final AtomicLong counter = new AtomicLong(0L);

    public PopulateProjectsUuidColumnsMigrationStep(DbClient db) {
        this.db = db;
    }

    @Override
    public void execute() {
        ProgressLogger progress = ProgressLogger.create(getClass(), counter);
        progress.start();

        final DbSession readSession = db.openSession(false);
        final DbSession writeSession = db.openSession(true);
        try {
            readSession.select("org.sonar.core.persistence.migration.v50.Migration50Mapper.selectRootProjects",
                    new ResultHandler() {
                        @Override
                        public void handleResult(ResultContext context) {
                            Component project = (Component) context.getResultObject();
                            List<Component> components = readSession.getMapper(Migration50Mapper.class)
                                    .selectComponentChildrenForProjects(project.getId());
                            MigrationContext migrationContext = new MigrationContext(readSession, writeSession,
                                    project, components);
                            migrateEnabledComponents(migrationContext);
                            migrateDisabledComponents(migrationContext);
                        }
                    });
            writeSession.commit(true);
            readSession.commit(true);

            migrateComponentsWithoutUuid(readSession, writeSession);
            writeSession.commit(true);

            // log the total number of process rows
            progress.log();
        } finally {
            readSession.close();
            writeSession.close();
            progress.stop();
        }
    }

    private void migrateEnabledComponents(MigrationContext migrationContext) {
        saveComponent(migrationContext.writeSession, migrationContext.project);
        for (Component component : migrationContext.componentsToMigrate) {
            migrationContext.updateComponent(component);
            if (Strings.isNullOrEmpty(component.getModuleUuidPath())) {
                LOG.warn(String.format(
                        "Ignoring component id '%s' because the module uuid path could not be created",
                        component.getId()));
            } else {
                migrationContext.updateComponent(component);
                saveComponent(migrationContext.writeSession, component);
            }
        }
    }

    private void migrateDisabledComponents(MigrationContext migrationContext) {
        for (Component component : migrationContext.readSession.getMapper(Migration50Mapper.class)
                .selectDisabledDirectComponentChildrenForProjects(migrationContext.project.getId())) {
            migrationContext.updateComponent(component);
            saveComponent(migrationContext.writeSession, component);
        }
        for (Component component : migrationContext.readSession.getMapper(Migration50Mapper.class)
                .selectDisabledNoneDirectComponentChildrenForProjects(migrationContext.project.getId())) {
            migrationContext.updateComponent(component);
            saveComponent(migrationContext.writeSession, component);
        }
    }

    private void migrateComponentsWithoutUuid(DbSession readSession, DbSession writeSession) {
        for (Component component : readSession.getMapper(Migration50Mapper.class).selectComponentsWithoutUuid()) {
            String uuid = Uuids.create();
            component.setUuid(uuid);
            component.setProjectUuid(uuid);
            saveComponent(writeSession, component);
        }
    }

    private void saveComponent(DbSession writeSession, Component component) {
        writeSession.getMapper(Migration50Mapper.class).updateComponentUuids(component);
        counter.getAndIncrement();
    }

    private static class MigrationContext {
        private final DbSession readSession;
        private final DbSession writeSession;
        private final Component project;
        private final Map<Long, Component> componentsBySnapshotId = newHashMap();
        private final Map<Long, String> uuidByComponentId = newHashMap();
        private final List<Component> componentsToMigrate = newArrayList();

        private MigrationContext(DbSession readSession, DbSession writeSession, Component project,
                List<Component> components) {
            this.readSession = readSession;
            this.writeSession = writeSession;
            this.project = project;

            project.setUuid(getOrCreateUuid(project));
            project.setProjectUuid(project.getUuid());

            componentsBySnapshotId.put(project.getSnapshotId(), project);
            for (Component component : components) {
                componentsBySnapshotId.put(component.getSnapshotId(), component);
                if (component.getUuid() == null) {
                    componentsToMigrate.add(component);
                }
            }
        }

        public void updateComponent(Component component) {
            component.setUuid(getOrCreateUuid(component));
            component.setProjectUuid(getOrCreateUuid(project));

            String snapshotPath = component.getSnapshotPath();
            StringBuilder moduleUuidPath = new StringBuilder();
            String lastModuleUuid = null;
            if (!Strings.isNullOrEmpty(snapshotPath)) {
                for (String s : Splitter.on(".").omitEmptyStrings().split(snapshotPath)) {
                    Long snapshotId = Long.valueOf(s);
                    Component currentComponent = componentsBySnapshotId.get(snapshotId);
                    if (currentComponent != null && currentComponent.getScope().equals(Scopes.PROJECT)) {
                        lastModuleUuid = getOrCreateUuid(currentComponent);
                        moduleUuidPath.append(lastModuleUuid).append(".");
                    }
                }
            }

            if (moduleUuidPath.length() > 0 && lastModuleUuid != null) {
                // Remove last '.'
                moduleUuidPath.deleteCharAt(moduleUuidPath.length() - 1);

                component.setModuleUuidPath(moduleUuidPath.toString());
                component.setModuleUuid(lastModuleUuid);
            }
        }

        private String getOrCreateUuid(Component component) {
            String existingUuid = component.getUuid();
            String uuid = existingUuid == null ? uuidByComponentId.get(component.getId()) : existingUuid;
            if (uuid == null) {
                String newUuid = Uuids.create();
                uuidByComponentId.put(component.getId(), newUuid);
                return newUuid;
            }
            return uuid;
        }
    }

}