All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.db.version.v50.PopulateProjectsUuidColumnsMigrationStep Maven / Gradle / Ivy

There is a newer version: 6.3.1
Show newest version
/*
 * SonarQube
 * Copyright (C) 2009-2016 SonarSource SA
 * mailto:contact AT sonarsource DOT com
 *
 * This program 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.
 *
 * This program 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.db.version.v50;

import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.sonar.api.resources.Scopes;
import org.sonar.core.util.Uuids;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.core.util.ProgressLogger;
import org.sonar.db.DbClient;
import org.sonar.db.DbSession;
import org.sonar.db.version.MigrationStep;

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.db.version.v50.Migration50Mapper.selectRootProjects", new ResultHandler() {
        @Override
        public void handleResult(ResultContext context) {
          Component project = (Component) context.getResultObject();
          List 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 componentsBySnapshotId = newHashMap();
    private final Map uuidByComponentId = newHashMap();
    private final List componentsToMigrate = newArrayList();

    private MigrationContext(DbSession readSession, DbSession writeSession, Component project, List 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;
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy