org.sonar.server.db.migrations.v51.CopyScmAccountsFromAuthorsToUsers.java Source code

Java tutorial

Introduction

Here is the source code for org.sonar.server.db.migrations.v51.CopyScmAccountsFromAuthorsToUsers.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.v51;

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

import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

import javax.annotation.CheckForNull;

import org.sonar.api.utils.System2;
import org.sonar.core.persistence.Database;
import org.sonar.server.db.migrations.BaseDataChange;
import org.sonar.server.db.migrations.Select;
import org.sonar.server.db.migrations.Upsert;
import org.sonar.server.db.migrations.UpsertImpl;
import org.sonar.server.util.ProgressLogger;

import com.google.common.base.Joiner;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

public class CopyScmAccountsFromAuthorsToUsers extends BaseDataChange {

    private static final char SCM_ACCOUNTS_SEPARATOR = '\n';

    private final System2 system;
    private final AtomicLong counter = new AtomicLong(0L);

    public CopyScmAccountsFromAuthorsToUsers(Database db, System2 system) {
        super(db);
        this.system = system;
    }

    @Override
    public void execute(final Context context) throws SQLException {
        ProgressLogger progress = ProgressLogger.create(getClass(), counter);
        progress.start();
        final Long now = system.now();

        try {
            final Multimap<Long, String> authorsByPersonId = ArrayListMultimap.create();
            context.prepareSelect("SELECT a.person_id, a.login FROM authors a,"
                    + "  (SELECT person_id, COUNT(*) AS nb FROM authors GROUP BY person_id HAVING COUNT(*) > 1) group_by_person"
                    + "     WHERE a.person_id = group_by_person.person_id ").scroll(new Select.RowHandler() {
                        @Override
                        public void handle(Select.Row row) throws SQLException {
                            authorsByPersonId.put(row.getNullableLong(1), row.getNullableString(2));
                        }
                    });

            Upsert update = context.prepareUpsert("UPDATE users SET scm_accounts = ?, updated_at = ? WHERE id = ?");
            for (Long personId : authorsByPersonId.keySet()) {
                List<String> authors = newArrayList(authorsByPersonId.get(personId));
                List<User> users = selectUsersFromLoginOrEmail(context, authors);
                if (users.size() == 1) {
                    User user = users.get(0);
                    if (authors.contains(user.login)) {
                        authors.remove(user.login);
                    }
                    if (authors.contains(user.email)) {
                        authors.remove(user.email);
                    }
                    if (!authors.isEmpty()) {
                        update.setString(1, encodeScmAccounts(authors)).setLong(2, now).setLong(3, user.id)
                                .addBatch();
                        counter.getAndIncrement();
                    }
                }
            }
            if (((UpsertImpl) update).getBatchCount() > 0L) {
                update.execute().commit();
            }
            update.close();

            progress.log();
        } finally {
            progress.stop();
        }
    }

    private List<User> selectUsersFromLoginOrEmail(Context context, Collection<String> authors)
            throws SQLException {
        final List<User> users = newArrayList();
        StringBuilder sql = new StringBuilder(
                "SELECT u.id, u.login, u.email, u.scm_accounts FROM users u WHERE u.active=? AND (");
        for (int i = 0; i < authors.size(); i++) {
            if (i < authors.size() - 1) {
                sql.append("u.login=? OR u.email=? OR ");
            } else {
                sql.append("u.login=? OR u.email=?)");
            }
        }
        Select select = context.prepareSelect(sql.toString());
        select.setBoolean(1, true);
        int currentIndex = 1;
        for (String author : authors) {
            currentIndex++;
            select.setString(currentIndex, author);
            currentIndex++;
            select.setString(currentIndex, author);
        }

        select.scroll(new Select.RowHandler() {
            @Override
            public void handle(Select.Row row) throws SQLException {
                users.add(new User(row.getNullableLong(1), row.getNullableString(2), row.getNullableString(3),
                        row.getNullableString(4)));
            }
        });
        return users;
    }

    @CheckForNull
    private static String encodeScmAccounts(List<String> scmAccounts) {
        if (scmAccounts.isEmpty()) {
            return null;
        }
        return SCM_ACCOUNTS_SEPARATOR + Joiner.on(SCM_ACCOUNTS_SEPARATOR).join(scmAccounts)
                + SCM_ACCOUNTS_SEPARATOR;
    }

    private static class User {
        Long id;
        String login;
        String email;
        String scmAccounts;

        User(Long id, String login, String email, String scmAccounts) {
            this.id = id;
            this.login = login;
            this.email = email;
            this.scmAccounts = scmAccounts;
        }
    }
}