Reindex account whenever account is evicted from cache

Change-Id: I025cabc9be98628777066cda7aa97186f5a0da15
Signed-off-by: Edwin Kempin <ekempin@google.com>
This commit is contained in:
Edwin Kempin
2016-06-20 16:06:54 +02:00
parent ebbf81470a
commit 94732bfa19
29 changed files with 115 additions and 55 deletions

View File

@@ -66,6 +66,7 @@ import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@@ -154,7 +155,7 @@ public class GerritPublicKeyCheckerTest {
return userFactory.create(id); return userFactory.create(id);
} }
private IdentifiedUser reloadUser() { private IdentifiedUser reloadUser() throws IOException {
accountCache.evict(userId); accountCache.evict(userId);
user = userFactory.create(userId); user = userFactory.create(userId);
return user; return user;

View File

@@ -219,7 +219,7 @@ class BecomeAnyAccountLoginServlet extends HttpServlet {
} }
} }
private AuthResult create() { private AuthResult create() throws IOException {
String fakeId = AccountExternalId.SCHEME_UUID + UUID.randomUUID(); String fakeId = AccountExternalId.SCHEME_UUID + UUID.randomUUID();
try { try {
return accountManager.authenticate(new AuthRequest(fakeId)); return accountManager.authenticate(new AuthRequest(fakeId));

View File

@@ -153,7 +153,7 @@ class HttpLoginServlet extends HttpServlet {
} }
private void updateRemoteExternalId(AuthResult arsp, String remoteAuthToken) private void updateRemoteExternalId(AuthResult arsp, String remoteAuthToken)
throws AccountException, OrmException { throws AccountException, OrmException, IOException {
AccountExternalId remoteAuthExtId = AccountExternalId remoteAuthExtId =
new AccountExternalId(arsp.getAccountId(), new AccountExternalId.Key( new AccountExternalId(arsp.getAccountId(), new AccountExternalId.Key(
SCHEME_EXTERNAL, remoteAuthToken)); SCHEME_EXTERNAL, remoteAuthToken));

View File

@@ -27,6 +27,8 @@ import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.OrmRuntimeException; import com.google.gwtorm.server.OrmRuntimeException;
import com.google.inject.Provider; import com.google.inject.Provider;
import java.io.IOException;
/** Support for services which require a {@link ReviewDb} instance. */ /** Support for services which require a {@link ReviewDb} instance. */
public class BaseServiceImplementation { public class BaseServiceImplementation {
private final Provider<ReviewDb> schema; private final Provider<ReviewDb> schema;
@@ -86,6 +88,8 @@ public class BaseServiceImplementation {
handleOrmException(callback, ex); handleOrmException(callback, ex);
} catch (OrmException e) { } catch (OrmException e) {
handleOrmException(callback, e); handleOrmException(callback, e);
} catch (IOException e) {
callback.onFailure(e);
} catch (Failure e) { } catch (Failure e) {
if (e.getCause() instanceof NoSuchProjectException if (e.getCause() instanceof NoSuchProjectException
|| e.getCause() instanceof NoSuchChangeException) { || e.getCause() instanceof NoSuchChangeException) {
@@ -132,6 +136,6 @@ public class BaseServiceImplementation {
* @throws InvalidQueryException * @throws InvalidQueryException
*/ */
T run(ReviewDb db) throws OrmException, Failure, NoSuchProjectException, T run(ReviewDb db) throws OrmException, Failure, NoSuchProjectException,
NoSuchGroupException, InvalidQueryException; NoSuchGroupException, InvalidQueryException, IOException;
} }
} }

View File

@@ -40,6 +40,7 @@ import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -98,7 +99,8 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
final AsyncCallback<Account> callback) { final AsyncCallback<Account> callback) {
run(callback, new Action<Account>() { run(callback, new Action<Account>() {
@Override @Override
public Account run(ReviewDb db) throws OrmException, Failure { public Account run(ReviewDb db)
throws OrmException, Failure, IOException {
IdentifiedUser self = user.get(); IdentifiedUser self = user.get();
final Account me = db.accounts().get(self.getAccountId()); final Account me = db.accounts().get(self.getAccountId());
final String oldEmail = me.getPreferredEmail(); final String oldEmail = me.getPreferredEmail();
@@ -133,7 +135,8 @@ class AccountSecurityImpl extends BaseServiceImplementation implements
final AsyncCallback<VoidResult> callback) { final AsyncCallback<VoidResult> callback) {
run(callback, new Action<VoidResult>() { run(callback, new Action<VoidResult>() {
@Override @Override
public VoidResult run(final ReviewDb db) throws OrmException, Failure { public VoidResult run(final ReviewDb db)
throws OrmException, Failure, IOException {
ContributorAgreement ca = projectCache.getAllProjects().getConfig() ContributorAgreement ca = projectCache.getAllProjects().getConfig()
.getContributorAgreement(agreementName); .getContributorAgreement(agreementName);
if (ca == null) { if (ca == null) {

View File

@@ -24,6 +24,7 @@ import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@@ -60,7 +61,7 @@ class DeleteExternalIds extends Handler<Set<AccountExternalId.Key>> {
} }
@Override @Override
public Set<AccountExternalId.Key> call() throws OrmException { public Set<AccountExternalId.Key> call() throws OrmException, IOException {
final Map<AccountExternalId.Key, AccountExternalId> have = have(); final Map<AccountExternalId.Key, AccountExternalId> have = have();
List<AccountExternalId> toDelete = new ArrayList<>(); List<AccountExternalId> toDelete = new ArrayList<>();

View File

@@ -16,6 +16,8 @@ package com.google.gerrit.server.account;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import java.io.IOException;
/** Caches important (but small) account state to avoid database hits. */ /** Caches important (but small) account state to avoid database hits. */
public interface AccountCache { public interface AccountCache {
AccountState get(Account.Id accountId); AccountState get(Account.Id accountId);
@@ -24,7 +26,7 @@ public interface AccountCache {
AccountState getByUsername(String username); AccountState getByUsername(String username);
void evict(Account.Id accountId); void evict(Account.Id accountId) throws IOException;
void evictByUsername(String username); void evictByUsername(String username);
} }

View File

@@ -26,6 +26,8 @@ import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupMember; import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.cache.CacheModule; import com.google.gerrit.server.cache.CacheModule;
import com.google.gerrit.server.index.Index;
import com.google.gerrit.server.index.account.AccountIndexCollection;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory; import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject; import com.google.inject.Inject;
@@ -74,12 +76,15 @@ public class AccountCacheImpl implements AccountCache {
private final LoadingCache<Account.Id, AccountState> byId; private final LoadingCache<Account.Id, AccountState> byId;
private final LoadingCache<String, Optional<Account.Id>> byName; private final LoadingCache<String, Optional<Account.Id>> byName;
private final AccountIndexCollection indexes;
@Inject @Inject
AccountCacheImpl(@Named(BYID_NAME) LoadingCache<Account.Id, AccountState> byId, AccountCacheImpl(@Named(BYID_NAME) LoadingCache<Account.Id, AccountState> byId,
@Named(BYUSER_NAME) LoadingCache<String, Optional<Account.Id>> byUsername) { @Named(BYUSER_NAME) LoadingCache<String, Optional<Account.Id>> byUsername,
AccountIndexCollection indexes) {
this.byId = byId; this.byId = byId;
this.byName = byUsername; this.byName = byUsername;
this.indexes = indexes;
} }
@Override @Override
@@ -109,9 +114,16 @@ public class AccountCacheImpl implements AccountCache {
} }
@Override @Override
public void evict(Account.Id accountId) { public void evict(Account.Id accountId) throws IOException {
if (accountId != null) { if (accountId != null) {
byId.invalidate(accountId); byId.invalidate(accountId);
index(accountId);
}
}
private void index(Account.Id id) throws IOException {
for (Index<?, AccountState> i : indexes.getWriteIndexes()) {
i.replace(get(id));
} }
} }

View File

@@ -37,6 +37,7 @@ import com.google.inject.Singleton;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -101,7 +102,8 @@ public class AccountManager {
* @throws AccountException the account does not exist, and cannot be created, * @throws AccountException the account does not exist, and cannot be created,
* or exists, but cannot be located, or is inactive. * or exists, but cannot be located, or is inactive.
*/ */
public AuthResult authenticate(AuthRequest who) throws AccountException { public AuthResult authenticate(AuthRequest who)
throws AccountException, IOException {
who = realm.authenticate(who); who = realm.authenticate(who);
try { try {
try (ReviewDb db = schema.open()) { try (ReviewDb db = schema.open()) {
@@ -152,7 +154,8 @@ public class AccountManager {
} }
private void update(ReviewDb db, AuthRequest who, AccountExternalId extId) private void update(ReviewDb db, AuthRequest who, AccountExternalId extId)
throws OrmException, NameAlreadyUsedException, InvalidUserNameException { throws OrmException, NameAlreadyUsedException, InvalidUserNameException,
IOException {
IdentifiedUser user = userFactory.create(extId.getAccountId()); IdentifiedUser user = userFactory.create(extId.getAccountId());
Account toUpdate = null; Account toUpdate = null;
@@ -214,7 +217,7 @@ public class AccountManager {
} }
private AuthResult create(ReviewDb db, AuthRequest who) private AuthResult create(ReviewDb db, AuthRequest who)
throws OrmException, AccountException { throws OrmException, AccountException, IOException {
Account.Id newId = new Account.Id(db.nextAccountId()); Account.Id newId = new Account.Id(db.nextAccountId());
Account account = new Account(newId, TimeUtil.nowTs()); Account account = new Account(newId, TimeUtil.nowTs());
AccountExternalId extId = createId(newId, who); AccountExternalId extId = createId(newId, who);
@@ -340,7 +343,7 @@ public class AccountManager {
* cannot be linked at this time. * cannot be linked at this time.
*/ */
public AuthResult link(Account.Id to, AuthRequest who) public AuthResult link(Account.Id to, AuthRequest who)
throws AccountException, OrmException { throws AccountException, OrmException, IOException {
try (ReviewDb db = schema.open()) { try (ReviewDb db = schema.open()) {
AccountExternalId.Key key = id(who); AccountExternalId.Key key = id(who);
AccountExternalId extId = getAccountExternalId(db, key); AccountExternalId extId = getAccountExternalId(db, key);
@@ -392,7 +395,7 @@ public class AccountManager {
* cannot be linked at this time. * cannot be linked at this time.
*/ */
public AuthResult updateLink(Account.Id to, AuthRequest who) throws OrmException, public AuthResult updateLink(Account.Id to, AuthRequest who) throws OrmException,
AccountException { AccountException, IOException {
try (ReviewDb db = schema.open()) { try (ReviewDb db = schema.open()) {
AccountExternalId.Key key = id(who); AccountExternalId.Key key = id(who);
List<AccountExternalId.Key> filteredKeysByScheme = List<AccountExternalId.Key> filteredKeysByScheme =
@@ -429,7 +432,7 @@ public class AccountManager {
* cannot be unlinked at this time. * cannot be unlinked at this time.
*/ */
public AuthResult unlink(Account.Id from, AuthRequest who) public AuthResult unlink(Account.Id from, AuthRequest who)
throws AccountException, OrmException { throws AccountException, OrmException, IOException {
try (ReviewDb db = schema.open()) { try (ReviewDb db = schema.open()) {
AccountExternalId.Key key = id(who); AccountExternalId.Key key = id(who);
AccountExternalId extId = getAccountExternalId(db, key); AccountExternalId extId = getAccountExternalId(db, key);

View File

@@ -29,6 +29,7 @@ import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@@ -71,7 +72,7 @@ public class ChangeUserName implements Callable<VoidResult> {
@Override @Override
public VoidResult call() throws OrmException, NameAlreadyUsedException, public VoidResult call() throws OrmException, NameAlreadyUsedException,
InvalidUserNameException { InvalidUserNameException, IOException {
final Collection<AccountExternalId> old = old(); final Collection<AccountExternalId> old = old();
if (!old.isEmpty()) { if (!old.isEmpty()) {
throw new IllegalStateException(USERNAME_CANNOT_BE_CHANGED); throw new IllegalStateException(USERNAME_CANNOT_BE_CHANGED);

View File

@@ -39,6 +39,8 @@ import org.apache.commons.validator.routines.EmailValidator;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException;
public class CreateEmail implements RestModifyView<AccountResource, EmailInput> { public class CreateEmail implements RestModifyView<AccountResource, EmailInput> {
private static final Logger log = LoggerFactory.getLogger(CreateEmail.class); private static final Logger log = LoggerFactory.getLogger(CreateEmail.class);
@@ -75,7 +77,7 @@ public class CreateEmail implements RestModifyView<AccountResource, EmailInput>
public Response<EmailInfo> apply(AccountResource rsrc, EmailInput input) public Response<EmailInfo> apply(AccountResource rsrc, EmailInput input)
throws AuthException, BadRequestException, ResourceConflictException, throws AuthException, BadRequestException, ResourceConflictException,
ResourceNotFoundException, OrmException, EmailException, ResourceNotFoundException, OrmException, EmailException,
MethodNotAllowedException { MethodNotAllowedException, IOException {
if (self.get() != rsrc.getUser() if (self.get() != rsrc.getUser()
&& !self.get().getCapabilities().canModifyAccount()) { && !self.get().getCapabilities().canModifyAccount()) {
throw new AuthException("not allowed to add email address"); throw new AuthException("not allowed to add email address");
@@ -104,7 +106,7 @@ public class CreateEmail implements RestModifyView<AccountResource, EmailInput>
public Response<EmailInfo> apply(IdentifiedUser user, EmailInput input) public Response<EmailInfo> apply(IdentifiedUser user, EmailInput input)
throws AuthException, BadRequestException, ResourceConflictException, throws AuthException, BadRequestException, ResourceConflictException,
ResourceNotFoundException, OrmException, EmailException, ResourceNotFoundException, OrmException, EmailException,
MethodNotAllowedException { MethodNotAllowedException, IOException {
if (input.email != null && !email.equals(input.email)) { if (input.email != null && !email.equals(input.email)) {
throw new BadRequestException("email address must match URL"); throw new BadRequestException("email address must match URL");
} }

View File

@@ -27,6 +27,7 @@ import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.io.IOException;
import java.util.Collections; import java.util.Collections;
@RequiresCapability(GlobalCapability.MODIFY_ACCOUNT) @RequiresCapability(GlobalCapability.MODIFY_ACCOUNT)
@@ -46,7 +47,7 @@ public class DeleteActive implements RestModifyView<AccountResource, Input> {
@Override @Override
public Response<?> apply(AccountResource rsrc, Input input) public Response<?> apply(AccountResource rsrc, Input input)
throws ResourceNotFoundException, OrmException { throws ResourceNotFoundException, OrmException, IOException {
Account a = dbProvider.get().accounts().get(rsrc.getUser().getAccountId()); Account a = dbProvider.get().accounts().get(rsrc.getUser().getAccountId());
if (a == null) { if (a == null) {
throw new ResourceNotFoundException("account not found"); throw new ResourceNotFoundException("account not found");

View File

@@ -31,6 +31,8 @@ import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.io.IOException;
@Singleton @Singleton
public class DeleteEmail implements RestModifyView<AccountResource.Email, Input> { public class DeleteEmail implements RestModifyView<AccountResource.Email, Input> {
public static class Input { public static class Input {
@@ -53,7 +55,8 @@ public class DeleteEmail implements RestModifyView<AccountResource.Email, Input>
@Override @Override
public Response<?> apply(AccountResource.Email rsrc, Input input) public Response<?> apply(AccountResource.Email rsrc, Input input)
throws AuthException, ResourceNotFoundException, throws AuthException, ResourceNotFoundException,
ResourceConflictException, MethodNotAllowedException, OrmException { ResourceConflictException, MethodNotAllowedException, OrmException,
IOException {
if (self.get() != rsrc.getUser() if (self.get() != rsrc.getUser()
&& !self.get().getCapabilities().canModifyAccount()) { && !self.get().getCapabilities().canModifyAccount()) {
throw new AuthException("not allowed to delete email address"); throw new AuthException("not allowed to delete email address");
@@ -63,7 +66,7 @@ public class DeleteEmail implements RestModifyView<AccountResource.Email, Input>
public Response<?> apply(IdentifiedUser user, String email) public Response<?> apply(IdentifiedUser user, String email)
throws ResourceNotFoundException, ResourceConflictException, throws ResourceNotFoundException, ResourceConflictException,
MethodNotAllowedException, OrmException { MethodNotAllowedException, OrmException, IOException {
if (!realm.allowsEdit(FieldName.REGISTER_NEW_EMAIL)) { if (!realm.allowsEdit(FieldName.REGISTER_NEW_EMAIL)) {
throw new MethodNotAllowedException("realm does not allow deleting emails"); throw new MethodNotAllowedException("realm does not allow deleting emails");
} }

View File

@@ -27,6 +27,7 @@ import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.io.IOException;
import java.util.Collections; import java.util.Collections;
@RequiresCapability(GlobalCapability.MODIFY_ACCOUNT) @RequiresCapability(GlobalCapability.MODIFY_ACCOUNT)
@@ -46,7 +47,7 @@ public class PutActive implements RestModifyView<AccountResource, Input> {
@Override @Override
public Response<String> apply(AccountResource rsrc, Input input) public Response<String> apply(AccountResource rsrc, Input input)
throws ResourceNotFoundException, OrmException { throws ResourceNotFoundException, OrmException, IOException {
Account a = dbProvider.get().accounts().get(rsrc.getUser().getAccountId()); Account a = dbProvider.get().accounts().get(rsrc.getUser().getAccountId());
if (a == null) { if (a == null) {
throw new ResourceNotFoundException("account not found"); throw new ResourceNotFoundException("account not found");

View File

@@ -34,6 +34,7 @@ import com.google.inject.Singleton;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import java.io.IOException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.Collections; import java.util.Collections;
@@ -69,8 +70,9 @@ public class PutHttpPassword implements RestModifyView<AccountResource, Input> {
} }
@Override @Override
public Response<String> apply(AccountResource rsrc, Input input) throws AuthException, public Response<String> apply(AccountResource rsrc, Input input)
ResourceNotFoundException, ResourceConflictException, OrmException { throws AuthException, ResourceNotFoundException,
ResourceConflictException, OrmException, IOException {
if (input == null) { if (input == null) {
input = new Input(); input = new Input();
} }
@@ -101,7 +103,8 @@ public class PutHttpPassword implements RestModifyView<AccountResource, Input> {
} }
public Response<String> apply(IdentifiedUser user, String newPassword) public Response<String> apply(IdentifiedUser user, String newPassword)
throws ResourceNotFoundException, ResourceConflictException, OrmException { throws ResourceNotFoundException, ResourceConflictException, OrmException,
IOException {
if (user.getUserName() == null) { if (user.getUserName() == null) {
throw new ResourceConflictException("username must be set"); throw new ResourceConflictException("username must be set");
} }

View File

@@ -36,6 +36,7 @@ import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.io.IOException;
import java.util.Collections; import java.util.Collections;
@Singleton @Singleton
@@ -62,7 +63,7 @@ public class PutName implements RestModifyView<AccountResource, Input> {
@Override @Override
public Response<String> apply(AccountResource rsrc, Input input) public Response<String> apply(AccountResource rsrc, Input input)
throws AuthException, MethodNotAllowedException, throws AuthException, MethodNotAllowedException,
ResourceNotFoundException, OrmException { ResourceNotFoundException, OrmException, IOException {
if (self.get() != rsrc.getUser() if (self.get() != rsrc.getUser()
&& !self.get().getCapabilities().canModifyAccount()) { && !self.get().getCapabilities().canModifyAccount()) {
throw new AuthException("not allowed to change name"); throw new AuthException("not allowed to change name");
@@ -71,7 +72,8 @@ public class PutName implements RestModifyView<AccountResource, Input> {
} }
public Response<String> apply(IdentifiedUser user, Input input) public Response<String> apply(IdentifiedUser user, Input input)
throws MethodNotAllowedException, ResourceNotFoundException, OrmException { throws MethodNotAllowedException, ResourceNotFoundException, OrmException,
IOException {
if (input == null) { if (input == null) {
input = new Input(); input = new Input();
} }

View File

@@ -28,6 +28,7 @@ import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.io.IOException;
import java.util.Collections; import java.util.Collections;
@Singleton @Singleton
@@ -50,7 +51,8 @@ public class PutPreferred implements
@Override @Override
public Response<String> apply(AccountResource.Email rsrc, Input input) public Response<String> apply(AccountResource.Email rsrc, Input input)
throws AuthException, ResourceNotFoundException, OrmException { throws AuthException, ResourceNotFoundException, OrmException,
IOException {
if (self.get() != rsrc.getUser() if (self.get() != rsrc.getUser()
&& !self.get().getCapabilities().canModifyAccount()) { && !self.get().getCapabilities().canModifyAccount()) {
throw new AuthException("not allowed to set preferred email address"); throw new AuthException("not allowed to set preferred email address");
@@ -59,7 +61,7 @@ public class PutPreferred implements
} }
public Response<String> apply(IdentifiedUser user, String email) public Response<String> apply(IdentifiedUser user, String email)
throws ResourceNotFoundException, OrmException { throws ResourceNotFoundException, OrmException, IOException {
Account a = dbProvider.get().accounts().get(user.getAccountId()); Account a = dbProvider.get().accounts().get(user.getAccountId());
if (a == null) { if (a == null) {
throw new ResourceNotFoundException("account not found"); throw new ResourceNotFoundException("account not found");

View File

@@ -30,6 +30,8 @@ import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.io.IOException;
@Singleton @Singleton
public class PutUsername implements RestModifyView<AccountResource, Input> { public class PutUsername implements RestModifyView<AccountResource, Input> {
public static class Input { public static class Input {
@@ -56,7 +58,7 @@ public class PutUsername implements RestModifyView<AccountResource, Input> {
@Override @Override
public String apply(AccountResource rsrc, Input input) throws AuthException, public String apply(AccountResource rsrc, Input input) throws AuthException,
MethodNotAllowedException, UnprocessableEntityException, MethodNotAllowedException, UnprocessableEntityException,
ResourceConflictException, OrmException { ResourceConflictException, OrmException, IOException {
if (self.get() != rsrc.getUser() if (self.get() != rsrc.getUser()
&& !self.get().getCapabilities().canAdministrateServer()) { && !self.get().getCapabilities().canAdministrateServer()) {
throw new AuthException("not allowed to set username"); throw new AuthException("not allowed to set username");

View File

@@ -311,7 +311,7 @@ public class AccountApiImpl implements AccountApi {
new AccountResource.Email(account.getUser(), input.email); new AccountResource.Email(account.getUser(), input.email);
try { try {
createEmailFactory.create(input.email).apply(rsrc, input); createEmailFactory.create(input.email).apply(rsrc, input);
} catch (EmailException | OrmException e) { } catch (EmailException | OrmException | IOException e) {
throw new RestApiException("Cannot add email", e); throw new RestApiException("Cannot add email", e);
} }
} }

View File

@@ -44,6 +44,7 @@ import com.google.gwtorm.server.OrmException;
import com.google.inject.assistedinject.Assisted; import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject; import com.google.inject.assistedinject.AssistedInject;
import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -217,7 +218,7 @@ class GroupApiImpl implements GroupApi {
try { try {
addMembers.apply( addMembers.apply(
rsrc, AddMembers.Input.fromMembers(Arrays.asList(members))); rsrc, AddMembers.Input.fromMembers(Arrays.asList(members)));
} catch (OrmException e) { } catch (OrmException | IOException e) {
throw new RestApiException("Cannot add group members", e); throw new RestApiException("Cannot add group members", e);
} }
} }
@@ -227,7 +228,7 @@ class GroupApiImpl implements GroupApi {
try { try {
deleteMembers.apply( deleteMembers.apply(
rsrc, AddMembers.Input.fromMembers(Arrays.asList(members))); rsrc, AddMembers.Input.fromMembers(Arrays.asList(members)));
} catch (OrmException e) { } catch (OrmException | IOException e) {
throw new RestApiException("Cannot remove group members", e); throw new RestApiException("Cannot remove group members", e);
} }
} }

View File

@@ -90,7 +90,7 @@ class GroupsImpl implements Groups {
GroupInfo info = createGroup.create(in.name) GroupInfo info = createGroup.create(in.name)
.apply(TopLevelResource.INSTANCE, in); .apply(TopLevelResource.INSTANCE, in);
return id(info.id); return id(info.id);
} catch (OrmException e) { } catch (OrmException | IOException e) {
throw new RestApiException("Cannot create group " + in.name, e); throw new RestApiException("Cannot create group " + in.name, e);
} }
} }

View File

@@ -32,6 +32,8 @@ import org.kohsuke.args4j.spi.OptionHandler;
import org.kohsuke.args4j.spi.Parameters; import org.kohsuke.args4j.spi.Parameters;
import org.kohsuke.args4j.spi.Setter; import org.kohsuke.args4j.spi.Setter;
import java.io.IOException;
public class AccountIdHandler extends OptionHandler<Account.Id> { public class AccountIdHandler extends OptionHandler<Account.Id> {
private final AccountResolver accountResolver; private final AccountResolver accountResolver;
private final AccountManager accountManager; private final AccountManager accountManager;
@@ -76,7 +78,7 @@ public class AccountIdHandler extends OptionHandler<Account.Id> {
throw new CmdLineException(owner, "user \"" + token + "\" not found"); throw new CmdLineException(owner, "user \"" + token + "\" not found");
} }
} }
} catch (OrmException e) { } catch (OrmException | IOException e) {
throw new CmdLineException(owner, "database is down"); throw new CmdLineException(owner, "database is down");
} }
setter.addValue(accountId); setter.addValue(accountId);
@@ -84,7 +86,7 @@ public class AccountIdHandler extends OptionHandler<Account.Id> {
} }
private Account.Id createAccountByLdap(String user) private Account.Id createAccountByLdap(String user)
throws CmdLineException { throws CmdLineException, IOException {
if (!user.matches(Account.USER_NAME_PATTERN)) { if (!user.matches(Account.USER_NAME_PATTERN)) {
throw new CmdLineException(owner, "user \"" + user + "\" not found"); throw new CmdLineException(owner, "user \"" + user + "\" not found");
} }

View File

@@ -30,6 +30,8 @@ import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.io.IOException;
@Singleton @Singleton
public class ConfirmEmail implements RestModifyView<ConfigResource, Input> { public class ConfirmEmail implements RestModifyView<ConfigResource, Input> {
public static class Input { public static class Input {
@@ -53,7 +55,7 @@ public class ConfirmEmail implements RestModifyView<ConfigResource, Input> {
@Override @Override
public Response<?> apply(ConfigResource rsrc, Input input) public Response<?> apply(ConfigResource rsrc, Input input)
throws AuthException, UnprocessableEntityException, AccountException, throws AuthException, UnprocessableEntityException, AccountException,
OrmException { OrmException, IOException {
CurrentUser user = self.get(); CurrentUser user = self.get();
if (!user.isIdentifiedUser()) { if (!user.isIdentifiedUser()) {
throw new AuthException("Authentication required"); throw new AuthException("Authentication required");

View File

@@ -45,6 +45,7 @@ import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@@ -114,7 +115,7 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
@Override @Override
public List<AccountInfo> apply(GroupResource resource, Input input) public List<AccountInfo> apply(GroupResource resource, Input input)
throws AuthException, MethodNotAllowedException, throws AuthException, MethodNotAllowedException,
UnprocessableEntityException, OrmException { UnprocessableEntityException, OrmException, IOException {
AccountGroup internalGroup = resource.toAccountGroup(); AccountGroup internalGroup = resource.toAccountGroup();
if (internalGroup == null) { if (internalGroup == null) {
throw new MethodNotAllowedException(); throw new MethodNotAllowedException();
@@ -142,7 +143,7 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
} }
private Account findAccount(String nameOrEmail) throws AuthException, private Account findAccount(String nameOrEmail) throws AuthException,
UnprocessableEntityException, OrmException { UnprocessableEntityException, OrmException, IOException {
try { try {
return accounts.parse(nameOrEmail).getAccount(); return accounts.parse(nameOrEmail).getAccount();
} catch (UnprocessableEntityException e) { } catch (UnprocessableEntityException e) {
@@ -174,7 +175,8 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
} }
public void addMembers(AccountGroup.Id groupId, public void addMembers(AccountGroup.Id groupId,
Collection<? extends Account.Id> newMemberIds) throws OrmException { Collection<? extends Account.Id> newMemberIds)
throws OrmException, IOException {
Map<Account.Id, AccountGroupMember> newAccountGroupMembers = new HashMap<>(); Map<Account.Id, AccountGroupMember> newAccountGroupMembers = new HashMap<>();
for (Account.Id accId : newMemberIds) { for (Account.Id accId : newMemberIds) {
if (!newAccountGroupMembers.containsKey(accId)) { if (!newAccountGroupMembers.containsKey(accId)) {
@@ -197,7 +199,7 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
} }
} }
private Account createAccountByLdap(String user) { private Account createAccountByLdap(String user) throws IOException {
if (!user.matches(Account.USER_NAME_PATTERN)) { if (!user.matches(Account.USER_NAME_PATTERN)) {
return null; return null;
} }
@@ -238,7 +240,7 @@ public class AddMembers implements RestModifyView<GroupResource, Input> {
@Override @Override
public AccountInfo apply(GroupResource resource, PutMember.Input input) public AccountInfo apply(GroupResource resource, PutMember.Input input)
throws AuthException, MethodNotAllowedException, throws AuthException, MethodNotAllowedException,
ResourceNotFoundException, OrmException { ResourceNotFoundException, OrmException, IOException {
AddMembers.Input in = new AddMembers.Input(); AddMembers.Input in = new AddMembers.Input();
in._oneMember = id; in._oneMember = id;
try { try {

View File

@@ -50,6 +50,7 @@ import com.google.inject.assistedinject.Assisted;
import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.PersonIdent;
import java.io.IOException;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@@ -98,7 +99,7 @@ public class CreateGroup implements RestModifyView<TopLevelResource, GroupInput>
@Override @Override
public GroupInfo apply(TopLevelResource resource, GroupInput input) public GroupInfo apply(TopLevelResource resource, GroupInput input)
throws BadRequestException, UnprocessableEntityException, throws BadRequestException, UnprocessableEntityException,
ResourceConflictException, OrmException { ResourceConflictException, OrmException, IOException {
if (input == null) { if (input == null) {
input = new GroupInput(); input = new GroupInput();
} }
@@ -138,7 +139,7 @@ public class CreateGroup implements RestModifyView<TopLevelResource, GroupInput>
} }
private AccountGroup createGroup(CreateGroupArgs createGroupArgs) private AccountGroup createGroup(CreateGroupArgs createGroupArgs)
throws OrmException, ResourceConflictException { throws OrmException, ResourceConflictException, IOException {
// Do not allow creating groups with the same name as system groups // Do not allow creating groups with the same name as system groups
List<String> sysGroupNames = SystemGroupBackend.getNames(); List<String> sysGroupNames = SystemGroupBackend.getNames();

View File

@@ -34,6 +34,7 @@ import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
import java.io.IOException;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@@ -62,7 +63,7 @@ public class DeleteMembers implements RestModifyView<GroupResource, Input> {
@Override @Override
public Response<?> apply(GroupResource resource, Input input) public Response<?> apply(GroupResource resource, Input input)
throws AuthException, MethodNotAllowedException, throws AuthException, MethodNotAllowedException,
UnprocessableEntityException, OrmException { UnprocessableEntityException, OrmException, IOException {
AccountGroup internalGroup = resource.toAccountGroup(); AccountGroup internalGroup = resource.toAccountGroup();
if (internalGroup == null) { if (internalGroup == null) {
throw new MethodNotAllowedException(); throw new MethodNotAllowedException();
@@ -125,7 +126,7 @@ public class DeleteMembers implements RestModifyView<GroupResource, Input> {
@Override @Override
public Response<?> apply(MemberResource resource, Input input) public Response<?> apply(MemberResource resource, Input input)
throws AuthException, MethodNotAllowedException, throws AuthException, MethodNotAllowedException,
UnprocessableEntityException, OrmException { UnprocessableEntityException, OrmException, IOException {
AddMembers.Input in = new AddMembers.Input(); AddMembers.Input in = new AddMembers.Input();
in._oneMember = resource.getMember().getAccountId().toString(); in._oneMember = resource.getMember().getAccountId().toString();
return delete.get().apply(resource, in); return delete.get().apply(resource, in);

View File

@@ -26,6 +26,7 @@ import com.google.common.util.concurrent.MoreExecutors;
import com.google.gerrit.lifecycle.LifecycleModule; import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.git.WorkQueue; import com.google.gerrit.server.git.WorkQueue;
import com.google.gerrit.server.index.account.AccountIndexCollection;
import com.google.gerrit.server.index.account.AccountIndexDefinition; import com.google.gerrit.server.index.account.AccountIndexDefinition;
import com.google.gerrit.server.index.account.AccountSchemaDefinitions; import com.google.gerrit.server.index.account.AccountSchemaDefinitions;
import com.google.gerrit.server.index.change.ChangeIndexCollection; import com.google.gerrit.server.index.change.ChangeIndexCollection;
@@ -87,6 +88,10 @@ public class IndexModule extends LifecycleModule {
@Override @Override
protected void configure() { protected void configure() {
bind(IndexRewriter.class); bind(IndexRewriter.class);
bind(AccountIndexCollection.class);
listener().to(AccountIndexCollection.class);
bind(ChangeIndexCollection.class); bind(ChangeIndexCollection.class);
listener().to(ChangeIndexCollection.class); listener().to(ChangeIndexCollection.class);
factory(ChangeIndexer.Factory.class); factory(ChangeIndexer.Factory.class);

View File

@@ -38,6 +38,7 @@ import com.google.inject.Inject;
import org.kohsuke.args4j.Argument; import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option; import org.kohsuke.args4j.Option;
import java.io.IOException;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@@ -88,7 +89,7 @@ final class CreateGroupCommand extends SshCommand {
private AddIncludedGroups addIncludedGroups; private AddIncludedGroups addIncludedGroups;
@Override @Override
protected void run() throws Failure, OrmException { protected void run() throws Failure, OrmException, IOException {
try { try {
GroupResource rsrc = createGroup(); GroupResource rsrc = createGroup();
@@ -104,7 +105,8 @@ final class CreateGroupCommand extends SshCommand {
} }
} }
private GroupResource createGroup() throws RestApiException, OrmException { private GroupResource createGroup()
throws RestApiException, OrmException, IOException {
GroupInput input = new GroupInput(); GroupInput input = new GroupInput();
input.description = groupDescription; input.description = groupDescription;
input.visibleToAll = visibleToAll; input.visibleToAll = visibleToAll;
@@ -120,7 +122,7 @@ final class CreateGroupCommand extends SshCommand {
} }
private void addMembers(GroupResource rsrc) throws RestApiException, private void addMembers(GroupResource rsrc) throws RestApiException,
OrmException { OrmException, IOException {
AddMembers.Input input = AddMembers.Input input =
AddMembers.Input.fromMembers(FluentIterable AddMembers.Input.fromMembers(FluentIterable
.from(initialMembers) .from(initialMembers)

View File

@@ -256,8 +256,8 @@ final class SetAccountCommand extends SshCommand {
new AccountResource.SshKey(user, sshKey), null); new AccountResource.SshKey(user, sshKey), null);
} }
private void addEmail(String email) throws UnloggedFailure, RestApiException, private void addEmail(String email)
OrmException { throws UnloggedFailure, RestApiException, OrmException, IOException {
EmailInput in = new EmailInput(); EmailInput in = new EmailInput();
in.email = email; in.email = email;
in.noConfirmation = true; in.noConfirmation = true;
@@ -268,7 +268,8 @@ final class SetAccountCommand extends SshCommand {
} }
} }
private void deleteEmail(String email) throws RestApiException, OrmException { private void deleteEmail(String email)
throws RestApiException, OrmException, IOException {
if (email.equals("ALL")) { if (email.equals("ALL")) {
List<EmailInfo> emails = getEmails.apply(rsrc); List<EmailInfo> emails = getEmails.apply(rsrc);
for (EmailInfo e : emails) { for (EmailInfo e : emails) {
@@ -281,8 +282,8 @@ final class SetAccountCommand extends SshCommand {
} }
} }
private void putPreferred(String email) throws RestApiException, private void putPreferred(String email)
OrmException { throws RestApiException, OrmException, IOException {
for (EmailInfo e : getEmails.apply(rsrc)) { for (EmailInfo e : getEmails.apply(rsrc)) {
if (e.email.equals(email)) { if (e.email.equals(email)) {
putPreferred.apply(new AccountResource.Email(user, email), null); putPreferred.apply(new AccountResource.Email(user, email), null);