Merge "Migrate AccountGroup owner Id to UUID"

This commit is contained in:
Shawn Pearce
2012-05-18 12:22:14 -07:00
committed by gerrit code review
11 changed files with 147 additions and 52 deletions

View File

@@ -26,7 +26,7 @@ public class GroupDetail {
public AccountGroup group; public AccountGroup group;
public List<AccountGroupMember> members; public List<AccountGroupMember> members;
public List<AccountGroupInclude> includes; public List<AccountGroupInclude> includes;
public AccountGroup ownerGroup; public GroupReference ownerGroup;
public boolean canModify; public boolean canModify;
public GroupDetail() { public GroupDetail() {
@@ -52,7 +52,7 @@ public class GroupDetail {
includes = i; includes = i;
} }
public void setOwnerGroup(AccountGroup g) { public void setOwnerGroup(GroupReference g) {
ownerGroup = g; ownerGroup = g;
} }

View File

@@ -446,7 +446,7 @@ public class AccountGroupInfoScreen extends AccountGroupScreen {
if (groupDetail.ownerGroup != null) { if (groupDetail.ownerGroup != null) {
ownerTxt.setText(groupDetail.ownerGroup.getName()); ownerTxt.setText(groupDetail.ownerGroup.getName());
} else { } else {
ownerTxt.setText(Util.M.deletedGroup(group.getOwnerGroupId().get())); ownerTxt.setText(Util.M.deletedReference(group.getOwnerGroupUUID().get()));
} }
descTxt.setText(group.getDescription()); descTxt.setText(group.getDescription());

View File

@@ -145,13 +145,13 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
final AccountGroup group = db.accountGroups().get(groupId); final AccountGroup group = db.accountGroups().get(groupId);
assertAmGroupOwner(db, group); assertAmGroupOwner(db, group);
final AccountGroup owner = AccountGroup owner =
groupCache.get(new AccountGroup.NameKey(newOwnerName)); groupCache.get(new AccountGroup.NameKey(newOwnerName));
if (owner == null) { if (owner == null) {
throw new Failure(new NoSuchEntityException()); throw new Failure(new NoSuchEntityException());
} }
group.setOwnerGroupId(owner.getId()); group.setOwnerGroupUUID(owner.getGroupUUID());
db.accountGroups().update(Collections.singleton(group)); db.accountGroups().update(Collections.singleton(group));
groupCache.evict(group); groupCache.evict(group);
return VoidResult.INSTANCE; return VoidResult.INSTANCE;

View File

@@ -51,7 +51,7 @@ public final class AccountGroup {
StringKey<com.google.gwtorm.client.Key<?>> { StringKey<com.google.gwtorm.client.Key<?>> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Column(id = 1, length = 40) @Column(id = 1)
protected String uuid; protected String uuid;
protected UUID() { protected UUID() {
@@ -193,14 +193,6 @@ public final class AccountGroup {
@Column(id = 2) @Column(id = 2)
protected Id groupId; protected Id groupId;
/**
* Identity of the group whose members can manage this group.
* <p>
* This can be a self-reference to indicate the group's members manage itself.
*/
@Column(id = 3)
protected Id ownerGroupId;
/** A textual description of the group's purpose. */ /** A textual description of the group's purpose. */
@Column(id = 4, length = Integer.MAX_VALUE, notNull = false) @Column(id = 4, length = Integer.MAX_VALUE, notNull = false)
protected String description; protected String description;
@@ -220,6 +212,14 @@ public final class AccountGroup {
@Column(id = 9) @Column(id = 9)
protected UUID groupUUID; protected UUID groupUUID;
/**
* Identity of the group whose members can manage this group.
* <p>
* This can be a self-reference to indicate the group's members manage itself.
*/
@Column(id = 10)
protected UUID ownerGroupUUID;
protected AccountGroup() { protected AccountGroup() {
} }
@@ -227,9 +227,9 @@ public final class AccountGroup {
final AccountGroup.Id newId, final AccountGroup.UUID uuid) { final AccountGroup.Id newId, final AccountGroup.UUID uuid) {
name = newName; name = newName;
groupId = newId; groupId = newId;
ownerGroupId = groupId;
visibleToAll = false; visibleToAll = false;
groupUUID = uuid; groupUUID = uuid;
ownerGroupUUID = groupUUID;
setType(Type.INTERNAL); setType(Type.INTERNAL);
} }
@@ -257,12 +257,12 @@ public final class AccountGroup {
description = d; description = d;
} }
public AccountGroup.Id getOwnerGroupId() { public AccountGroup.UUID getOwnerGroupUUID() {
return ownerGroupId; return ownerGroupUUID;
} }
public void setOwnerGroupId(final AccountGroup.Id id) { public void setOwnerGroupUUID(final AccountGroup.UUID uuid) {
ownerGroupId = id; ownerGroupUUID = uuid;
} }
public Type getType() { public Type getType() {

View File

@@ -40,7 +40,7 @@ public class GroupControl {
if (group == null) { if (group == null) {
throw new NoSuchGroupException(groupId); throw new NoSuchGroupException(groupId);
} }
return new GroupControl(groupCache, user.get(), group); return new GroupControl(user.get(), group);
} }
public GroupControl controlFor(final AccountGroup.UUID groupId) public GroupControl controlFor(final AccountGroup.UUID groupId)
@@ -49,11 +49,11 @@ public class GroupControl {
if (group == null) { if (group == null) {
throw new NoSuchGroupException(groupId); throw new NoSuchGroupException(groupId);
} }
return new GroupControl(groupCache, user.get(), group); return new GroupControl(user.get(), group);
} }
public GroupControl controlFor(final AccountGroup group) { public GroupControl controlFor(final AccountGroup group) {
return new GroupControl(groupCache, user.get(), group); return new GroupControl(user.get(), group);
} }
public GroupControl validateFor(final AccountGroup.Id groupId) public GroupControl validateFor(final AccountGroup.Id groupId)
@@ -66,13 +66,11 @@ public class GroupControl {
} }
} }
private final GroupCache groupCache;
private final CurrentUser user; private final CurrentUser user;
private final AccountGroup group; private final AccountGroup group;
private Boolean isOwner; private Boolean isOwner;
GroupControl(GroupCache g, CurrentUser who, AccountGroup gc) { GroupControl(CurrentUser who, AccountGroup gc) {
groupCache = g;
user = who; user = who;
group = gc; group = gc;
} }
@@ -94,8 +92,7 @@ public class GroupControl {
public boolean isOwner() { public boolean isOwner() {
if (isOwner == null) { if (isOwner == null) {
AccountGroup g = groupCache.get(group.getOwnerGroupId()); AccountGroup.UUID ownerUUID = group.getOwnerGroupUUID();
AccountGroup.UUID ownerUUID = g != null ? g.getGroupUUID() : null;
isOwner = getCurrentUser().getEffectiveGroups().contains(ownerUUID) isOwner = getCurrentUser().getEffectiveGroups().contains(ownerUUID)
|| getCurrentUser().getCapabilities().canAdministrateServer(); || getCurrentUser().getCapabilities().canAdministrateServer();
} }

View File

@@ -15,6 +15,7 @@
package com.google.gerrit.server.account; package com.google.gerrit.server.account;
import com.google.gerrit.common.data.GroupDetail; import com.google.gerrit.common.data.GroupDetail;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.errors.NoSuchGroupException; import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup; import com.google.gerrit.reviewdb.client.AccountGroup;
@@ -66,7 +67,10 @@ public class GroupDetailFactory implements Callable<GroupDetail> {
final AccountGroup group = control.getAccountGroup(); final AccountGroup group = control.getAccountGroup();
final GroupDetail detail = new GroupDetail(); final GroupDetail detail = new GroupDetail();
detail.setGroup(group); detail.setGroup(group);
detail.setOwnerGroup(groupCache.get(group.getOwnerGroupId())); AccountGroup ownerGroup = groupCache.get(group.getGroupUUID());
if (ownerGroup != null) {
detail.setOwnerGroup(GroupReference.forGroup(ownerGroup));
}
switch (group.getType()) { switch (group.getType()) {
case INTERNAL: case INTERNAL:
detail.setMembers(loadMembers()); detail.setMembers(loadMembers());

View File

@@ -107,7 +107,10 @@ public class PerformCreateGroup {
final AccountGroup group = new AccountGroup(nameKey, groupId, uuid); final AccountGroup group = new AccountGroup(nameKey, groupId, uuid);
group.setVisibleToAll(visibleToAll); group.setVisibleToAll(visibleToAll);
if (ownerGroupId != null) { if (ownerGroupId != null) {
group.setOwnerGroupId(ownerGroupId); AccountGroup ownerGroup = groupCache.get(ownerGroupId);
if (ownerGroup != null) {
group.setOwnerGroupUUID(ownerGroup.getGroupUUID());
}
} }
if (groupDescription != null) { if (groupDescription != null) {
group.setDescription(groupDescription); group.setDescription(groupDescription);

View File

@@ -161,7 +161,7 @@ public class SchemaCreator {
anonymous = anonymous =
newGroup(c, "Anonymous Users", AccountGroup.ANONYMOUS_USERS); newGroup(c, "Anonymous Users", AccountGroup.ANONYMOUS_USERS);
anonymous.setDescription("Any user, signed-in or not"); anonymous.setDescription("Any user, signed-in or not");
anonymous.setOwnerGroupId(admin.getId()); anonymous.setOwnerGroupUUID(admin.getGroupUUID());
anonymous.setType(AccountGroup.Type.SYSTEM); anonymous.setType(AccountGroup.Type.SYSTEM);
c.accountGroups().insert(Collections.singleton(anonymous)); c.accountGroups().insert(Collections.singleton(anonymous));
c.accountGroupNames().insert( c.accountGroupNames().insert(
@@ -170,7 +170,7 @@ public class SchemaCreator {
registered = registered =
newGroup(c, "Registered Users", AccountGroup.REGISTERED_USERS); newGroup(c, "Registered Users", AccountGroup.REGISTERED_USERS);
registered.setDescription("Any signed-in user"); registered.setDescription("Any signed-in user");
registered.setOwnerGroupId(admin.getId()); registered.setOwnerGroupUUID(admin.getGroupUUID());
registered.setType(AccountGroup.Type.SYSTEM); registered.setType(AccountGroup.Type.SYSTEM);
c.accountGroups().insert(Collections.singleton(registered)); c.accountGroups().insert(Collections.singleton(registered));
c.accountGroupNames().insert( c.accountGroupNames().insert(
@@ -178,7 +178,7 @@ public class SchemaCreator {
final AccountGroup batchUsers = newGroup(c, "Non-Interactive Users", null); final AccountGroup batchUsers = newGroup(c, "Non-Interactive Users", null);
batchUsers.setDescription("Users who perform batch actions on Gerrit"); batchUsers.setDescription("Users who perform batch actions on Gerrit");
batchUsers.setOwnerGroupId(admin.getId()); batchUsers.setOwnerGroupUUID(admin.getGroupUUID());
batchUsers.setType(AccountGroup.Type.INTERNAL); batchUsers.setType(AccountGroup.Type.INTERNAL);
c.accountGroups().insert(Collections.singleton(batchUsers)); c.accountGroups().insert(Collections.singleton(batchUsers));
c.accountGroupNames().insert( c.accountGroupNames().insert(
@@ -186,7 +186,7 @@ public class SchemaCreator {
owners = newGroup(c, "Project Owners", AccountGroup.PROJECT_OWNERS); owners = newGroup(c, "Project Owners", AccountGroup.PROJECT_OWNERS);
owners.setDescription("Any owner of the project"); owners.setDescription("Any owner of the project");
owners.setOwnerGroupId(admin.getId()); owners.setOwnerGroupUUID(admin.getGroupUUID());
owners.setType(AccountGroup.Type.SYSTEM); owners.setType(AccountGroup.Type.SYSTEM);
c.accountGroups().insert(Collections.singleton(owners)); c.accountGroups().insert(Collections.singleton(owners));
c.accountGroupNames().insert( c.accountGroupNames().insert(

View File

@@ -32,7 +32,7 @@ import java.util.List;
/** A version of the database schema. */ /** A version of the database schema. */
public abstract class SchemaVersion { public abstract class SchemaVersion {
/** The current schema version. */ /** The current schema version. */
public static final Class<Schema_66> C = Schema_66.class; public static final Class<Schema_67> C = Schema_67.class;
public static class Module extends AbstractModule { public static class Module extends AbstractModule {
@Override @Override

View File

@@ -101,15 +101,15 @@ public class Schema_65 extends SchemaVersion {
ui.message("Moved contributor agreements to project.config"); ui.message("Moved contributor agreements to project.config");
// Create the auto verify groups. // Create the auto verify groups.
List<AccountGroup.Id> adminGroupIds = getAdministrateServerGroups(db, config); List<AccountGroup.UUID> adminGroupUUIDs = getAdministrateServerGroups(db, config);
for (ContributorAgreement agreement : agreements.values()) { for (ContributorAgreement agreement : agreements.values()) {
if (agreement.getAutoVerify() != null) { if (agreement.getAutoVerify() != null) {
getOrCreateGroupForIndividuals(db, config, adminGroupIds, agreement); getOrCreateGroupForIndividuals(db, config, adminGroupUUIDs, agreement);
} }
} }
// Scan AccountAgreement // Scan AccountAgreement
long minTime = addAccountAgreements(db, config, adminGroupIds, agreements); long minTime = addAccountAgreements(db, config, adminGroupUUIDs, agreements);
ProjectConfig base = ProjectConfig.read(md, null); ProjectConfig base = ProjectConfig.read(md, null);
for (ContributorAgreement agreement : agreements.values()) { for (ContributorAgreement agreement : agreements.values()) {
@@ -257,14 +257,14 @@ public class Schema_65 extends SchemaVersion {
} }
private AccountGroup createGroup(ReviewDb db, String groupName, private AccountGroup createGroup(ReviewDb db, String groupName,
AccountGroup.Id adminGroupId, String description) AccountGroup.UUID adminGroupUUID, String description)
throws OrmException { throws OrmException {
final AccountGroup.Id groupId = final AccountGroup.Id groupId =
new AccountGroup.Id(db.nextAccountGroupId()); new AccountGroup.Id(db.nextAccountGroupId());
final AccountGroup.NameKey nameKey = new AccountGroup.NameKey(groupName); final AccountGroup.NameKey nameKey = new AccountGroup.NameKey(groupName);
final AccountGroup.UUID uuid = GroupUUID.make(groupName, serverUser); final AccountGroup.UUID uuid = GroupUUID.make(groupName, serverUser);
final AccountGroup group = new AccountGroup(nameKey, groupId, uuid); final AccountGroup group = new AccountGroup(nameKey, groupId, uuid);
group.setOwnerGroupId(adminGroupId); group.setOwnerGroupUUID(adminGroupUUID);
group.setDescription(description); group.setDescription(description);
final AccountGroupName gn = new AccountGroupName(group); final AccountGroupName gn = new AccountGroupName(group);
// first insert the group name to validate that the group name hasn't // first insert the group name to validate that the group name hasn't
@@ -274,21 +274,17 @@ public class Schema_65 extends SchemaVersion {
return group; return group;
} }
private List<AccountGroup.Id> getAdministrateServerGroups( private List<AccountGroup.UUID> getAdministrateServerGroups(
ReviewDb db, ProjectConfig cfg) throws OrmException { ReviewDb db, ProjectConfig cfg) {
List<PermissionRule> rules = cfg.getAccessSection(AccessSection.GLOBAL_CAPABILITIES) List<PermissionRule> rules = cfg.getAccessSection(AccessSection.GLOBAL_CAPABILITIES)
.getPermission(GlobalCapability.ADMINISTRATE_SERVER) .getPermission(GlobalCapability.ADMINISTRATE_SERVER)
.getRules(); .getRules();
List<AccountGroup.Id> groups = List<AccountGroup.UUID> groups =
Lists.newArrayListWithExpectedSize(rules.size()); Lists.newArrayListWithExpectedSize(rules.size());
for (PermissionRule rule : rules) { for (PermissionRule rule : rules) {
if (rule.getAction() == Action.ALLOW) { if (rule.getAction() == Action.ALLOW) {
groups.add(db.accountGroups() groups.add(rule.getGroup().getUUID());
.byUUID(rule.getGroup().getUUID())
.toList()
.get(0)
.getId());
} }
} }
if (groups.isEmpty()) { if (groups.isEmpty()) {
@@ -299,7 +295,7 @@ public class Schema_65 extends SchemaVersion {
} }
private GroupReference getOrCreateGroupForIndividuals(ReviewDb db, private GroupReference getOrCreateGroupForIndividuals(ReviewDb db,
ProjectConfig config, List<AccountGroup.Id> adminGroupIds, ProjectConfig config, List<AccountGroup.UUID> adminGroupUUIDs,
ContributorAgreement agreement) ContributorAgreement agreement)
throws OrmException { throws OrmException {
if (!agreement.getAccepted().isEmpty()) { if (!agreement.getAccepted().isEmpty()) {
@@ -317,12 +313,12 @@ public class Schema_65 extends SchemaVersion {
"account group name exists but account group does not: " + name); "account group name exists but account group does not: " + name);
} }
if (!adminGroupIds.contains(ag.getOwnerGroupId())) { if (!adminGroupUUIDs.contains(ag.getOwnerGroupUUID())) {
throw new IllegalStateException( throw new IllegalStateException(
"individual group exists with non admin owner group: " + name); "individual group exists with non admin owner group: " + name);
} }
} else { } else {
ag = createGroup(db, name, adminGroupIds.get(0), ag = createGroup(db, name, adminGroupUUIDs.get(0),
String.format("Users who have accepted the %s CLA", agreement.getName())); String.format("Users who have accepted the %s CLA", agreement.getName()));
} }
GroupReference group = config.resolve(ag); GroupReference group = config.resolve(ag);
@@ -344,7 +340,7 @@ public class Schema_65 extends SchemaVersion {
} }
private long addAccountAgreements(ReviewDb db, ProjectConfig config, private long addAccountAgreements(ReviewDb db, ProjectConfig config,
List<AccountGroup.Id> adminGroupIds, List<AccountGroup.UUID> adminGroupUUIDs,
Map<Integer, ContributorAgreement> agreements) Map<Integer, ContributorAgreement> agreements)
throws SQLException, OrmException { throws SQLException, OrmException {
Statement stmt = ((JdbcSchema) db).getConnection().createStatement(); Statement stmt = ((JdbcSchema) db).getConnection().createStatement();
@@ -373,7 +369,7 @@ public class Schema_65 extends SchemaVersion {
// Enter Agreement // Enter Agreement
GroupReference individualGroup = GroupReference individualGroup =
getOrCreateGroupForIndividuals(db, config, adminGroupIds, agreement); getOrCreateGroupForIndividuals(db, config, adminGroupUUIDs, agreement);
AccountGroup.Id groupId = db.accountGroups() AccountGroup.Id groupId = db.accountGroups()
.byUUID(individualGroup.getUUID()) .byUUID(individualGroup.getUUID())
.toList() .toList()

View File

@@ -0,0 +1,95 @@
// Copyright (C) 2012 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.schema;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gerrit.common.data.ContributorAgreement;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gwtorm.jdbc.JdbcSchema;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class Schema_67 extends SchemaVersion {
@Inject
Schema_67(Provider<Schema_66> prior) {
super(prior);
}
@Override
protected void migrateData(ReviewDb db, UpdateUI ui)
throws OrmException, SQLException {
ui.message("Update ownerGroupId to ownerGroupUUID");
// Scan all AccountGroup, and find the ones that need the owner_group_id
// migrated to owner_group_uuid.
Map<AccountGroup.Id, AccountGroup.Id> idMap = Maps.newHashMap();
Statement stmt = ((JdbcSchema) db).getConnection().createStatement();
try {
ResultSet rs = stmt.executeQuery(
"SELECT group_id, owner_group_id FROM account_groups"
+ " WHERE owner_group_uuid is NULL or owner_group_uuid =''");
try {
Map<Integer, ContributorAgreement> agreements = Maps.newHashMap();
while (rs.next()) {
AccountGroup.Id groupId = new AccountGroup.Id(rs.getInt(1));
AccountGroup.Id ownerId = new AccountGroup.Id(rs.getInt(2));
idMap.put(groupId, ownerId);
}
} finally {
rs.close();
}
} finally {
stmt.close();
}
// Lookup up all groups by ID.
Set<AccountGroup.Id> all =
Sets.newHashSet(Iterables.concat(idMap.keySet(), idMap.values()));
Map<AccountGroup.Id, AccountGroup> groups = Maps.newHashMap();
com.google.gwtorm.server.ResultSet<AccountGroup> rs =
db.accountGroups().get(all);
try {
for (AccountGroup group : rs) {
groups.put(group.getId(), group);
}
} finally {
rs.close();
}
// Update the ownerGroupUUID.
List<AccountGroup> toUpdate = Lists.newArrayListWithCapacity(idMap.size());
for (Entry<AccountGroup.Id, AccountGroup.Id> entry : idMap.entrySet()) {
AccountGroup group = groups.get(entry.getKey());
AccountGroup owner = groups.get(entry.getValue());
group.setOwnerGroupUUID(owner.getGroupUUID());
toUpdate.add(group);
}
db.accountGroups().update(toUpdate);
}
}