<commit_before>// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.server.account;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Runnables;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.account.externalids.ExternalIdNotes.ExternalIdNotesLoader;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.LockFailureException;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.index.change.ReindexAfterRefUpdate;
import com.google.gerrit.server.update.RefUpdateUtil;
import com.google.gerrit.server.update.RetryHelper;
import com.google.gerrit.server.update.RetryHelper.Action;
import com.google.gerrit.server.update.RetryHelper.ActionType;
import com.google.gwtorm.server.OrmDuplicateKeyException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;

/**
 * Creates and updates accounts.
 *
 * <p>This class should be used for all account updates. It supports updating account properties,
 * external IDs, preferences (general, diff and edit preferences) and project watches.
 *
 * <p>Updates to one account are always atomic. Batch updating several accounts within one
 * transaction is not supported.
 *
 * <p>For any account update the caller must provide a commit message, the account ID and an {@link
 * AccountUpdater}. The account updater allows to read the current {@link AccountState} and to
 * prepare updates to the account by calling setters on the provided {@link
 * InternalAccountUpdate.Builder}. If the current account state is of no interest the caller may
 * also provide a {@link Consumer} for {@link InternalAccountUpdate.Builder} instead of the account
 * updater.
 *
 * <p>The provided commit message is used for the update of the user branch. Using a precise and
 * unique commit message allows to identify the code from which an update was made when looking at a
 * commit in the user branch, and thus help debugging.
 *
 * <p>For creating a new account a new account ID can be retrieved from {@link
 * com.google.gerrit.server.Sequences#nextAccountId()}.
 *
 * <p>The account updates are written to NoteDb. In NoteDb accounts are represented as user branches
 * in the {@code All-Users} repository. Optionally a user branch can contain a 'account.config' file
 * that stores account properties, such as full name, preferred email, status and the active flag.
 * The timestamp of the first commit on a user branch denotes the registration date. The initial
 * commit on the user branch may be empty (since having an 'account.config' is optional). See {@link
 * AccountConfig} for details of the 'account.config' file format. In addition the user branch can
 * contain a 'preferences.config' config file to store preferences (see {@link Preferences}) and a
 * 'watch.config' config file to store project watches (see {@link ProjectWatches}). External IDs
 * are stored separately in the {@code refs/meta/external-ids} notes branch (see {@link
 * ExternalIdNotes}).
 *
 * <p>On updating an account the account is evicted from the account cache and thus reindexed. The
 * eviction from the account cache is done by the {@link ReindexAfterRefUpdate} class which receives
 * the event about updating the user branch that is triggered by this class. By passing an {@link
 * ExternalIdNotes.FactoryNoReindex} factory as parameter of {@link
 * AccountsUpdate.Factory#create(IdentifiedUser, ExternalIdNotesLoader)}, reindexing and flushing
 * the account from the account cache can be disabled. If external IDs are updated, the
 * ExternalIdCache is automatically updated.
 *
 * <p>If there are concurrent account updates updating the user branch in NoteDb may fail with
 * {@link LockFailureException}. In this case the account update is automatically retried and the
 * account updater is invoked once more with the updated account state. This means the whole
 * read-modify-write sequence is atomic. Retrying is limited by a timeout. If the timeout is
 * exceeded the account update can still fail with {@link LockFailureException}.
 */
public class AccountsUpdate {
  public interface Factory {
    /**
     * Creates an {@code AccountsUpdate} which uses the identity of the specified user as author for
     * all commits related to accounts. The Gerrit server identity will be used as committer.
     *
     * <p><strong>Note</strong>: Please use this method with care and rather consider to use the
     * correct annotation on the provider of an {@code AccountsUpdate} instead.
     *<commit_msg>Fix "Javadoc: Invalid member type qualification" warning<commit_after>// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.server.account;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.Runnables;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.GerritPersonIdent;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.account.externalids.ExternalIdNotes;
import com.google.gerrit.server.account.externalids.ExternalIdNotes.ExternalIdNotesLoader;
import com.google.gerrit.server.account.externalids.ExternalIds;
import com.google.gerrit.server.config.AllUsersName;
import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.git.LockFailureException;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.index.change.ReindexAfterRefUpdate;
import com.google.gerrit.server.update.RefUpdateUtil;
import com.google.gerrit.server.update.RetryHelper;
import com.google.gerrit.server.update.RetryHelper.Action;
import com.google.gerrit.server.update.RetryHelper.ActionType;
import com.google.gwtorm.server.OrmDuplicateKeyException;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import org.eclipse.jgit.errors.ConfigInvalidException;
import org.eclipse.jgit.lib.BatchRefUpdate;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;

/**
 * Creates and updates accounts.
 *
 * <p>This class should be used for all account updates. It supports updating account properties,
 * external IDs, preferences (general, diff and edit preferences) and project watches.
 *
 * <p>Updates to one account are always atomic. Batch updating several accounts within one
 * transaction is not supported.
 *
 * <p>For any account update the caller must provide a commit message, the account ID and an {@link
 * AccountUpdater}. The account updater allows to read the current {@link AccountState} and to
 * prepare updates to the account by calling setters on the provided {@link
 * InternalAccountUpdate.Builder}. If the current account state is of no interest the caller may
 * also provide a {@link Consumer} for {@link InternalAccountUpdate.Builder} instead of the account
 * updater.
 *
 * <p>The provided commit message is used for the update of the user branch. Using a precise and
 * unique commit message allows to identify the code from which an update was made when looking at a
 * commit in the user branch, and thus help debugging.
 *
 * <p>For creating a new account a new account ID can be retrieved from {@link
 * com.google.gerrit.server.Sequences#nextAccountId()}.
 *
 * <p>The account updates are written to NoteDb. In NoteDb accounts are represented as user branches
 * in the {@code All-Users} repository. Optionally a user branch can contain a 'account.config' file
 * that stores account properties, such as full name, preferred email, status and the active flag.
 * The timestamp of the first commit on a user branch denotes the registration date. The initial
 * commit on the user branch may be empty (since having an 'account.config' is optional). See {@link
 * AccountConfig} for details of the 'account.config' file format. In addition the user branch can
 * contain a 'preferences.config' config file to store preferences (see {@link Preferences}) and a
 * 'watch.config' config file to store project watches (see {@link ProjectWatches}). External IDs
 * are stored separately in the {@code refs/meta/external-ids} notes branch (see {@link
 * ExternalIdNotes}).
 *
 * <p>On updating an account the account is evicted from the account cache and thus reindexed. The
 * eviction from the account cache is done by the {@link ReindexAfterRefUpdate} class which receives
 * the event about updating the user branch that is triggered by this class. By passing an {@link
 * com.google.gerrit.server.account.externalids.ExternalIdNotes.FactoryNoReindex} factory as
 * parameter of {@link AccountsUpdate.Factory#create(IdentifiedUser, ExternalIdNotesLoader)},
 * reindexing and flushing the account from the account cache can be disabled. If external IDs are
 * updated, the ExternalIdCache is automatically updated.
 *
 * <p>If there are concurrent account updates updating the user branch in NoteDb may fail with
 * {@link LockFailureException}. In this case the account update is automatically retried and the
 * account updater is invoked once more with the updated account state. This means the whole
 * read-modify-write sequence is atomic. Retrying is limited by a timeout. If the timeout is
 * exceeded the account update can still fail with {@link LockFailureException}.
 */
public class AccountsUpdate {
  public interface Factory {
    /**
     * Creates an {@code AccountsUpdate} which uses the identity of the specified user as author for
     * all commits related to accounts. The Gerrit server identity will be used as committer.
     *
     * <p><strong>Note</strong>: Please use this method with care and rather consider to use the
     * correct annotation on the provider of an {@code AccountsUpdate} instead.
     *
{'fraction_non_alphanumeric': 0.0798649285377729, 'fraction_numerical': 0.0012564787183917073, 'mean_word_length': 4.765052059755545, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '977647', 'n_tokens_mistral': 3374, 'n_tokens_neox': 3281, 'n_words': 1352}