| // Copyright (C) 2020 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 com.google.auto.value.AutoValue; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.gerrit.common.UsedAt; |
| import com.google.gerrit.entities.Account; |
| import com.google.gerrit.entities.NotifyConfig; |
| import com.google.gerrit.entities.ProjectWatchKey; |
| import com.google.gerrit.entities.converter.AccountProtoConverter; |
| import com.google.gerrit.entities.converter.CachedProjectWatchProtoConverter; |
| import com.google.gerrit.proto.Protos; |
| import com.google.gerrit.server.cache.proto.Cache; |
| import com.google.gerrit.server.cache.serialize.CacheSerializer; |
| import com.google.gerrit.server.cache.serialize.ObjectIdConverter; |
| import com.google.gerrit.server.config.CachedPreferences; |
| import java.util.Map; |
| import java.util.Optional; |
| import org.eclipse.jgit.lib.ObjectId; |
| |
| /** Details of an account that are cached persistently in {@link AccountCache}. */ |
| @UsedAt(UsedAt.Project.GOOGLE) |
| @AutoValue |
| public abstract class CachedAccountDetails { |
| @AutoValue |
| public abstract static class Key { |
| public static Key create(Account.Id accountId, ObjectId id) { |
| return new AutoValue_CachedAccountDetails_Key(accountId, id.copy()); |
| } |
| |
| /** Identifier of the account. */ |
| public abstract Account.Id accountId(); |
| |
| /** |
| * Git revision at which the account was loaded. Corresponds to a revision on the account ref |
| * ({@code refs/users/<sharded-id>}). |
| */ |
| public abstract ObjectId id(); |
| |
| /** Serializer used to read this entity from and write it to a persistent storage. */ |
| public enum Serializer implements CacheSerializer<Key> { |
| INSTANCE; |
| |
| @Override |
| public byte[] serialize(Key object) { |
| return Protos.toByteArray( |
| Cache.AccountKeyProto.newBuilder() |
| .setAccountId(object.accountId().get()) |
| .setId(ObjectIdConverter.create().toByteString(object.id())) |
| .build()); |
| } |
| |
| @Override |
| public Key deserialize(byte[] in) { |
| Cache.AccountKeyProto proto = Protos.parseUnchecked(Cache.AccountKeyProto.parser(), in); |
| return Key.create( |
| Account.id(proto.getAccountId()), |
| ObjectIdConverter.create().fromByteString(proto.getId())); |
| } |
| } |
| } |
| |
| /** Essential attributes of the account, such as name or registration time. */ |
| public abstract Account account(); |
| |
| /** Projects that the user has configured to watch. */ |
| public abstract ImmutableMap<ProjectWatchKey, ImmutableSet<NotifyConfig.NotifyType>> |
| projectWatches(); |
| |
| /** Preferences that this user has. Serialized as Git-config style string. */ |
| public abstract CachedPreferences preferences(); |
| |
| public static CachedAccountDetails create( |
| Account account, |
| ImmutableMap<ProjectWatchKey, ImmutableSet<NotifyConfig.NotifyType>> projectWatches, |
| CachedPreferences preferences) { |
| return new AutoValue_CachedAccountDetails(account, projectWatches, preferences); |
| } |
| |
| /** Serializer used to read this entity from and write it to a persistent storage. */ |
| public enum Serializer implements CacheSerializer<CachedAccountDetails> { |
| INSTANCE; |
| |
| private static final AccountProtoConverter ACCOUNT_PROTO_CONVERTER = |
| AccountProtoConverter.INSTANCE; |
| private static final CachedProjectWatchProtoConverter PROJECT_WATCH_PROTO_CONVERTER = |
| CachedProjectWatchProtoConverter.INSTANCE; |
| |
| @Override |
| public byte[] serialize(CachedAccountDetails cachedAccountDetails) { |
| Cache.AccountDetailsProto.Builder serialized = Cache.AccountDetailsProto.newBuilder(); |
| // We don't care about the difference of empty strings and null in the Account entity. |
| Account account = cachedAccountDetails.account(); |
| serialized.setAccount(ACCOUNT_PROTO_CONVERTER.toProto(account)); |
| |
| for (Map.Entry<ProjectWatchKey, ImmutableSet<NotifyConfig.NotifyType>> watch : |
| cachedAccountDetails.projectWatches().entrySet()) { |
| serialized.addProjectWatchProto(PROJECT_WATCH_PROTO_CONVERTER.toProto(watch)); |
| } |
| |
| Optional<Cache.CachedPreferencesProto> cachedPreferencesProto = |
| cachedAccountDetails.preferences().nonEmptyConfig(); |
| if (cachedPreferencesProto.isPresent()) { |
| serialized.setUserPreferences(cachedPreferencesProto.get()); |
| } |
| return Protos.toByteArray(serialized.build()); |
| } |
| |
| @Override |
| public CachedAccountDetails deserialize(byte[] in) { |
| Cache.AccountDetailsProto proto = |
| Protos.parseUnchecked(Cache.AccountDetailsProto.parser(), in); |
| Account account = ACCOUNT_PROTO_CONVERTER.fromProto(proto.getAccount()); |
| |
| ImmutableMap.Builder<ProjectWatchKey, ImmutableSet<NotifyConfig.NotifyType>> projectWatches = |
| ImmutableMap.builder(); |
| proto.getProjectWatchProtoList().stream() |
| .forEach(p -> projectWatches.put(PROJECT_WATCH_PROTO_CONVERTER.fromProto(p))); |
| |
| return CachedAccountDetails.create( |
| account, |
| projectWatches.build(), |
| CachedPreferences.fromCachedPreferencesProto(proto.getUserPreferences())); |
| } |
| } |
| } |