Allow group includes to be by UUID instead of group ID

Per discussion on-list, the behavior change in 2.5 to only
allow groups by ID is considered a regression for groups
that want to include external groups (like LDAP).

In order to permit smooth migration, we want to allow both
ID and UUIDs to co-exist for the time being.

Change-Id: I0dbdb15b9c62f2dbce64acbc34c515c7b8229c04
This commit is contained in:
Chad Horohoe
2012-12-13 15:00:04 -05:00
parent 57143be354
commit 2cf207f384
24 changed files with 329 additions and 192 deletions

View File

@@ -17,7 +17,7 @@ package com.google.gerrit.common.data;
import com.google.gerrit.common.audit.Audit;
import com.google.gerrit.common.auth.SignInRequired;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupInclude;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gwtjsonrpc.common.AsyncCallback;
import com.google.gwtjsonrpc.common.RemoteJsonService;
@@ -74,8 +74,8 @@ public interface GroupAdminService extends RemoteJsonService {
@Audit
@SignInRequired
void addGroupInclude(AccountGroup.Id groupId, String groupName,
AsyncCallback<GroupDetail> callback);
void addGroupInclude(AccountGroup.Id groupId, AccountGroup.UUID incGroupUUID,
String incGroupName, AsyncCallback<GroupDetail> callback);
@Audit
@SignInRequired
@@ -85,5 +85,5 @@ public interface GroupAdminService extends RemoteJsonService {
@Audit
@SignInRequired
void deleteGroupIncludes(AccountGroup.Id groupId,
Set<AccountGroupInclude.Key> keys, AsyncCallback<VoidResult> callback);
Set<AccountGroupIncludeByUuid.Key> keys, AsyncCallback<VoidResult> callback);
}

View File

@@ -15,7 +15,7 @@
package com.google.gerrit.common.data;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupInclude;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import java.util.List;
@@ -25,7 +25,7 @@ public class GroupDetail {
public GroupInfoCache groups;
public AccountGroup group;
public List<AccountGroupMember> members;
public List<AccountGroupInclude> includes;
public List<AccountGroupIncludeByUuid> includes;
public GroupReference ownerGroup;
public boolean canModify;
@@ -48,7 +48,7 @@ public class GroupDetail {
members = m;
}
public void setIncludes(List<AccountGroupInclude> i) {
public void setIncludes(List<AccountGroupIncludeByUuid> i) {
includes = i;
}

View File

@@ -18,7 +18,7 @@ import com.google.gerrit.reviewdb.client.AccountGroup;
/** Summary information about an {@link AccountGroup}, for simple tabular displays. */
public class GroupInfo {
protected AccountGroup.Id id;
protected AccountGroup.UUID uuid;
protected String name;
protected String description;
@@ -32,8 +32,8 @@ public class GroupInfo {
* lookup has failed and a stale group id has been discovered in the data
* store.
*/
public GroupInfo(final AccountGroup.Id id) {
this.id = id;
public GroupInfo(final AccountGroup.UUID uuid) {
this.uuid = uuid;
}
/**
@@ -42,14 +42,14 @@ public class GroupInfo {
* @param a the data store record holding the specific group details.
*/
public GroupInfo(final AccountGroup a) {
id = a.getId();
uuid = a.getGroupUUID();
name = a.getName();
description = a.getDescription();
}
/** @return the unique local id of the group */
public AccountGroup.Id getId() {
return id;
public AccountGroup.UUID getId() {
return uuid;
}
/** @return the name of the group; null if not supplied */

View File

@@ -33,13 +33,13 @@ public class GroupInfoCache {
return EMPTY;
}
protected Map<AccountGroup.Id, GroupInfo> groups;
protected Map<AccountGroup.UUID, GroupInfo> groups;
protected GroupInfoCache() {
}
public GroupInfoCache(final Iterable<GroupInfo> list) {
groups = new HashMap<AccountGroup.Id, GroupInfo>();
groups = new HashMap<AccountGroup.UUID, GroupInfo>();
for (final GroupInfo gi : list) {
groups.put(gi.getId(), gi);
}
@@ -58,15 +58,15 @@ public class GroupInfoCache {
* @param id the id desired.
* @return info block for the group.
*/
public GroupInfo get(final AccountGroup.Id id) {
if (id == null) {
public GroupInfo get(final AccountGroup.UUID uuid) {
if (uuid == null) {
return null;
}
GroupInfo r = groups.get(id);
GroupInfo r = groups.get(uuid);
if (r == null) {
r = new GroupInfo(id);
groups.put(id, r);
r = new GroupInfo(uuid);
groups.put(uuid, r);
}
return r;
}

View File

@@ -25,11 +25,10 @@ import com.google.gerrit.client.ui.Hyperlink;
import com.google.gerrit.client.ui.SmallHeading;
import com.google.gerrit.common.data.AccountInfoCache;
import com.google.gerrit.common.data.GroupDetail;
import com.google.gerrit.common.data.GroupInfo;
import com.google.gerrit.common.data.GroupInfoCache;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupInclude;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -110,14 +109,15 @@ public class AccountGroupMembersScreen extends AccountGroupScreen {
}
private void initIncludeList() {
final AccountGroupSuggestOracle oracle = new AccountGroupSuggestOracle();
addIncludeBox =
new AddMemberBox(Util.C.buttonAddIncludedGroup(),
Util.C.defaultAccountGroupName(), new AccountGroupSuggestOracle());
Util.C.defaultAccountGroupName(), oracle);
addIncludeBox.addClickHandler(new ClickHandler() {
@Override
public void onClick(final ClickEvent event) {
doAddNewInclude();
doAddNewInclude(oracle);
}
});
@@ -194,14 +194,14 @@ public class AccountGroupMembersScreen extends AccountGroupScreen {
});
}
void doAddNewInclude() {
void doAddNewInclude(final AccountGroupSuggestOracle oracle) {
final String groupName = addIncludeBox.getText();
if (groupName.length() == 0) {
return;
}
addIncludeBox.setEnabled(false);
Util.GROUP_SVC.addGroupInclude(getGroupId(), groupName,
Util.GROUP_SVC.addGroupInclude(getGroupId(), oracle.getUUID(groupName), groupName,
new GerritCallback<GroupDetail>() {
public void onSuccess(final GroupDetail result) {
addIncludeBox.setEnabled(true);
@@ -298,7 +298,7 @@ public class AccountGroupMembersScreen extends AccountGroupScreen {
}
}
private class IncludeTable extends FancyFlexTable<AccountGroupInclude> {
private class IncludeTable extends FancyFlexTable<AccountGroupIncludeByUuid> {
private boolean enabled = true;
IncludeTable() {
@@ -314,7 +314,7 @@ public class AccountGroupMembersScreen extends AccountGroupScreen {
void setEnabled(final boolean enabled) {
this.enabled = enabled;
for (int row = 1; row < table.getRowCount(); row++) {
final AccountGroupInclude k = getRowItem(row);
final AccountGroupIncludeByUuid k = getRowItem(row);
if (k != null) {
((CheckBox) table.getWidget(row, 1)).setEnabled(enabled);
}
@@ -322,10 +322,10 @@ public class AccountGroupMembersScreen extends AccountGroupScreen {
}
void deleteChecked() {
final HashSet<AccountGroupInclude.Key> keys =
new HashSet<AccountGroupInclude.Key>();
final HashSet<AccountGroupIncludeByUuid.Key> keys =
new HashSet<AccountGroupIncludeByUuid.Key>();
for (int row = 1; row < table.getRowCount(); row++) {
final AccountGroupInclude k = getRowItem(row);
final AccountGroupIncludeByUuid k = getRowItem(row);
if (k != null && ((CheckBox) table.getWidget(row, 1)).getValue()) {
keys.add(k.getKey());
}
@@ -335,7 +335,7 @@ public class AccountGroupMembersScreen extends AccountGroupScreen {
new GerritCallback<VoidResult>() {
public void onSuccess(final VoidResult result) {
for (int row = 1; row < table.getRowCount();) {
final AccountGroupInclude k = getRowItem(row);
final AccountGroupIncludeByUuid k = getRowItem(row);
if (k != null && keys.contains(k.getKey())) {
table.removeRow(row);
} else {
@@ -347,11 +347,11 @@ public class AccountGroupMembersScreen extends AccountGroupScreen {
}
}
void display(final List<AccountGroupInclude> result) {
void display(final List<AccountGroupIncludeByUuid> result) {
while (1 < table.getRowCount())
table.removeRow(table.getRowCount() - 1);
for (final AccountGroupInclude k : result) {
for (final AccountGroupIncludeByUuid k : result) {
final int row = table.getRowCount();
table.insertRow(row);
applyDataRowStyle(row);
@@ -359,15 +359,18 @@ public class AccountGroupMembersScreen extends AccountGroupScreen {
}
}
void populate(final int row, final AccountGroupInclude k) {
AccountGroup.Id id = k.getIncludeId();
GroupInfo group = groups.get(id);
void populate(final int row, final AccountGroupIncludeByUuid k) {
AccountGroup.UUID uuid = k.getIncludeUUID();
CheckBox checkBox = new CheckBox();
table.setWidget(row, 1, checkBox);
checkBox.setEnabled(enabled);
table.setWidget(row, 2,
new Hyperlink(group.getName(), Dispatcher.toGroup(id)));
table.setText(row, 3, groups.get(id).getDescription());
if (AccountGroup.isInternalGroup(uuid)) {
table.setWidget(row, 2,
new Hyperlink(groups.get(uuid).getName(), Dispatcher.toGroup(uuid)));
table.setText(row, 3, groups.get(uuid).getDescription());
} else {
table.setText(row, 2, uuid.get());
}
final FlexCellFormatter fmt = table.getFlexCellFormatter();
fmt.addStyleName(row, 1, Gerrit.RESOURCES.css().iconCell());

View File

@@ -27,8 +27,8 @@ import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.httpd.rpc.BaseServiceImplementation;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupInclude;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeAudit;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuidAudit;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.client.AuthType;
@@ -225,7 +225,8 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
}
public void addGroupInclude(final AccountGroup.Id groupId,
final String groupName, final AsyncCallback<GroupDetail> callback) {
final AccountGroup.UUID incGroupUUID, final String incGroupName,
final AsyncCallback<GroupDetail> callback) {
run(callback, new Action<GroupDetail>() {
public GroupDetail run(ReviewDb db) throws OrmException, Failure,
NoSuchGroupException {
@@ -234,21 +235,24 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
throw new Failure(new NameAlreadyUsedException());
}
final AccountGroup a = findGroup(groupName);
if (!control.canAddGroup(a.getId())) {
if (incGroupUUID == null) {
throw new Failure(new NoSuchGroupException(incGroupName));
}
if (!control.canAddGroup(incGroupUUID)) {
throw new Failure(new NoSuchEntityException());
}
final AccountGroupInclude.Key key =
new AccountGroupInclude.Key(groupId, a.getId());
AccountGroupInclude m = db.accountGroupIncludes().get(key);
final AccountGroupIncludeByUuid.Key key =
new AccountGroupIncludeByUuid.Key(groupId, incGroupUUID);
AccountGroupIncludeByUuid m = db.accountGroupIncludesByUuid().get(key);
if (m == null) {
m = new AccountGroupInclude(key);
db.accountGroupIncludesAudit().insert(
Collections.singleton(new AccountGroupIncludeAudit(m,
m = new AccountGroupIncludeByUuid(key);
db.accountGroupIncludesByUuidAudit().insert(
Collections.singleton(new AccountGroupIncludeByUuidAudit(m,
getAccountId())));
db.accountGroupIncludes().insert(Collections.singleton(m));
groupIncludeCache.evictInclude(a.getGroupUUID());
db.accountGroupIncludesByUuid().insert(Collections.singleton(m));
groupIncludeCache.evictInclude(incGroupUUID);
}
return groupDetailFactory.create(groupId).call();
@@ -311,7 +315,7 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
}
public void deleteGroupIncludes(final AccountGroup.Id groupId,
final Set<AccountGroupInclude.Key> keys,
final Set<AccountGroupIncludeByUuid.Key> keys,
final AsyncCallback<VoidResult> callback) {
run(callback, new Action<VoidResult>() {
public VoidResult run(final ReviewDb db) throws OrmException,
@@ -321,26 +325,26 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
throw new Failure(new NameAlreadyUsedException());
}
for (final AccountGroupInclude.Key k : keys) {
for (final AccountGroupIncludeByUuid.Key k : keys) {
if (!groupId.equals(k.getGroupId())) {
throw new Failure(new NoSuchEntityException());
}
}
final Account.Id me = getAccountId();
final Set<AccountGroup.Id> groupsToEvict = new HashSet<AccountGroup.Id>();
for (final AccountGroupInclude.Key k : keys) {
final AccountGroupInclude m =
db.accountGroupIncludes().get(k);
final Set<AccountGroup.UUID> groupsToEvict = new HashSet<AccountGroup.UUID>();
for (final AccountGroupIncludeByUuid.Key k : keys) {
final AccountGroupIncludeByUuid m =
db.accountGroupIncludesByUuid().get(k);
if (m != null) {
if (!control.canRemoveGroup(m.getIncludeId())) {
if (!control.canRemoveGroup(m.getIncludeUUID())) {
throw new Failure(new NoSuchEntityException());
}
AccountGroupIncludeAudit audit = null;
for (AccountGroupIncludeAudit a : db
.accountGroupIncludesAudit().byGroupInclude(
m.getGroupId(), m.getIncludeId())) {
AccountGroupIncludeByUuidAudit audit = null;
for (AccountGroupIncludeByUuidAudit a : db
.accountGroupIncludesByUuidAudit().byGroupInclude(
m.getGroupId(), m.getIncludeUUID())) {
if (a.isActive()) {
audit = a;
break;
@@ -349,15 +353,15 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
if (audit != null) {
audit.removed(me);
db.accountGroupIncludesAudit().update(
db.accountGroupIncludesByUuidAudit().update(
Collections.singleton(audit));
}
db.accountGroupIncludes().delete(Collections.singleton(m));
groupsToEvict.add(k.getIncludeId());
db.accountGroupIncludesByUuid().delete(Collections.singleton(m));
groupsToEvict.add(k.getIncludeUUID());
}
}
for (AccountGroup group : db.accountGroups().get(groupsToEvict)) {
groupIncludeCache.evictInclude(group.getGroupUUID());
for (AccountGroup.UUID uuid : groupsToEvict) {
groupIncludeCache.evictInclude(uuid);
}
return VoidResult.INSTANCE;
}
@@ -408,14 +412,4 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
return null;
}
}
private AccountGroup findGroup(final String name) throws OrmException,
Failure {
final AccountGroup g = groupCache.get(new AccountGroup.NameKey(name));
if (g == null) {
throw new Failure(new NoSuchGroupException(name));
}
return g;
}
}

View File

@@ -18,7 +18,7 @@ import com.google.gwtorm.client.Column;
import com.google.gwtorm.client.CompoundKey;
/** Membership of an {@link AccountGroup} in an {@link AccountGroup}. */
public final class AccountGroupInclude {
public final class AccountGroupIncludeByUuid {
public static class Key extends CompoundKey<AccountGroup.Id> {
private static final long serialVersionUID = 1L;
@@ -26,16 +26,16 @@ public final class AccountGroupInclude {
protected AccountGroup.Id groupId;
@Column(id = 2)
protected AccountGroup.Id includeId;
protected AccountGroup.UUID includeUUID;
protected Key() {
groupId = new AccountGroup.Id();
includeId = new AccountGroup.Id();
includeUUID = new AccountGroup.UUID();
}
public Key(final AccountGroup.Id g, final AccountGroup.Id i) {
public Key(final AccountGroup.Id g, final AccountGroup.UUID u) {
groupId = g;
includeId = i;
includeUUID = u;
}
@Override
@@ -47,27 +47,27 @@ public final class AccountGroupInclude {
return groupId;
}
public AccountGroup.Id getIncludeId() {
return includeId;
public AccountGroup.UUID getIncludeUUID() {
return includeUUID;
}
@Override
public com.google.gwtorm.client.Key<?>[] members() {
return new com.google.gwtorm.client.Key<?>[] {includeId};
return new com.google.gwtorm.client.Key<?>[] {includeUUID};
}
}
@Column(id = 1, name = Column.NONE)
protected Key key;
protected AccountGroupInclude() {
protected AccountGroupIncludeByUuid() {
}
public AccountGroupInclude(final AccountGroupInclude.Key k) {
public AccountGroupIncludeByUuid(final AccountGroupIncludeByUuid.Key k) {
key = k;
}
public AccountGroupInclude.Key getKey() {
public AccountGroupIncludeByUuid.Key getKey() {
return key;
}
@@ -75,7 +75,7 @@ public final class AccountGroupInclude {
return key.groupId;
}
public AccountGroup.Id getIncludeId() {
return key.includeId;
public AccountGroup.UUID getIncludeUUID() {
return key.includeUUID;
}
}

View File

@@ -20,7 +20,7 @@ import com.google.gwtorm.client.CompoundKey;
import java.sql.Timestamp;
/** Inclusion of an {@link AccountGroup} in another {@link AccountGroup}. */
public final class AccountGroupIncludeAudit {
public final class AccountGroupIncludeByUuidAudit {
public static class Key extends CompoundKey<AccountGroup.Id> {
private static final long serialVersionUID = 1L;
@@ -28,19 +28,19 @@ public final class AccountGroupIncludeAudit {
protected AccountGroup.Id groupId;
@Column(id = 2)
protected AccountGroup.Id includeId;
protected AccountGroup.UUID includeUUID;
@Column(id = 3)
protected Timestamp addedOn;
protected Key() {
groupId = new AccountGroup.Id();
includeId = new AccountGroup.Id();
includeUUID = new AccountGroup.UUID();
}
public Key(final AccountGroup.Id g, final AccountGroup.Id i, final Timestamp t) {
public Key(final AccountGroup.Id g, final AccountGroup.UUID u, final Timestamp t) {
groupId = g;
includeId = i;
includeUUID = u;
addedOn = t;
}
@@ -49,8 +49,8 @@ public final class AccountGroupIncludeAudit {
return groupId;
}
public AccountGroup.Id getIncludedId() {
return includeId;
public AccountGroup.UUID getIncludeUUID() {
return includeUUID;
}
public Timestamp getAddedOn() {
@@ -59,7 +59,7 @@ public final class AccountGroupIncludeAudit {
@Override
public com.google.gwtorm.client.Key<?>[] members() {
return new com.google.gwtorm.client.Key<?>[] {includeId};
return new com.google.gwtorm.client.Key<?>[] {includeUUID};
}
}
@@ -75,18 +75,23 @@ public final class AccountGroupIncludeAudit {
@Column(id = 4, notNull = false)
protected Timestamp removedOn;
protected AccountGroupIncludeAudit() {
protected AccountGroupIncludeByUuidAudit() {
}
public AccountGroupIncludeAudit(final AccountGroupInclude m,
final Account.Id adder) {
public AccountGroupIncludeByUuidAudit(final AccountGroupIncludeByUuid m,
final Account.Id adder, final Timestamp when) {
final AccountGroup.Id group = m.getGroupId();
final AccountGroup.Id include = m.getIncludeId();
key = new AccountGroupIncludeAudit.Key(group, include, now());
final AccountGroup.UUID include = m.getIncludeUUID();
key = new AccountGroupIncludeByUuidAudit.Key(group, include, when);
addedBy = adder;
}
public AccountGroupIncludeAudit.Key getKey() {
public AccountGroupIncludeByUuidAudit(final AccountGroupIncludeByUuid m,
final Account.Id adder) {
this(m, adder, now());
}
public AccountGroupIncludeByUuidAudit.Key getKey() {
return key;
}
@@ -99,6 +104,11 @@ public final class AccountGroupIncludeAudit {
removedOn = now();
}
public void removed(final Account.Id deleter, final Timestamp when) {
removedBy = deleter;
removedOn = when;
}
private static Timestamp now() {
return new Timestamp(System.currentTimeMillis());
}

View File

@@ -15,21 +15,21 @@
package com.google.gerrit.reviewdb.server;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupInclude;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid;
import com.google.gwtorm.server.Access;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.PrimaryKey;
import com.google.gwtorm.server.Query;
import com.google.gwtorm.server.ResultSet;
public interface AccountGroupIncludeAccess extends
Access<AccountGroupInclude, AccountGroupInclude.Key> {
public interface AccountGroupIncludeByUuidAccess extends
Access<AccountGroupIncludeByUuid, AccountGroupIncludeByUuid.Key> {
@PrimaryKey("key")
AccountGroupInclude get(AccountGroupInclude.Key key) throws OrmException;
AccountGroupIncludeByUuid get(AccountGroupIncludeByUuid.Key key) throws OrmException;
@Query("WHERE key.includeId = ?")
ResultSet<AccountGroupInclude> byInclude(AccountGroup.Id id) throws OrmException;
@Query("WHERE key.includeUUID = ?")
ResultSet<AccountGroupIncludeByUuid> byIncludeUUID(AccountGroup.UUID uuid) throws OrmException;
@Query("WHERE key.groupId = ?")
ResultSet<AccountGroupInclude> byGroup(AccountGroup.Id id) throws OrmException;
ResultSet<AccountGroupIncludeByUuid> byGroup(AccountGroup.Id id) throws OrmException;
}

View File

@@ -15,20 +15,20 @@
package com.google.gerrit.reviewdb.server;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeAudit;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuidAudit;
import com.google.gwtorm.server.Access;
import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.PrimaryKey;
import com.google.gwtorm.server.Query;
import com.google.gwtorm.server.ResultSet;
public interface AccountGroupIncludeAuditAccess extends
Access<AccountGroupIncludeAudit, AccountGroupIncludeAudit.Key> {
public interface AccountGroupIncludeByUuidAuditAccess extends
Access<AccountGroupIncludeByUuidAudit, AccountGroupIncludeByUuidAudit.Key> {
@PrimaryKey("key")
AccountGroupIncludeAudit get(AccountGroupIncludeAudit.Key key)
AccountGroupIncludeByUuidAudit get(AccountGroupIncludeByUuidAudit.Key key)
throws OrmException;
@Query("WHERE key.groupId = ? AND key.includeId = ?")
ResultSet<AccountGroupIncludeAudit> byGroupInclude(AccountGroup.Id groupId,
AccountGroup.Id incGroupId) throws OrmException;
@Query("WHERE key.groupId = ? AND key.includeUUID = ?")
ResultSet<AccountGroupIncludeByUuidAudit> byGroupInclude(AccountGroup.Id groupId,
AccountGroup.UUID incGroupUUID) throws OrmException;
}

View File

@@ -70,12 +70,6 @@ public interface ReviewDb extends Schema {
@Relation(id = 13)
AccountGroupMemberAuditAccess accountGroupMembersAudit();
@Relation(id = 14)
AccountGroupIncludeAccess accountGroupIncludes();
@Relation(id = 15)
AccountGroupIncludeAuditAccess accountGroupIncludesAudit();
@Relation(id = 17)
AccountDiffPreferenceAccess accountDiffPreferences();
@@ -112,6 +106,12 @@ public interface ReviewDb extends Schema {
@Relation(id = 28)
SubmoduleSubscriptionAccess submoduleSubscriptions();
@Relation(id = 29)
AccountGroupIncludeByUuidAccess accountGroupIncludesByUuid();
@Relation(id = 30)
AccountGroupIncludeByUuidAuditAccess accountGroupIncludesByUuidAudit();
/** Create the next unique id for an {@link Account}. */
@Sequence(startWith = 1000000)
int nextAccountId() throws OrmException;

View File

@@ -34,10 +34,10 @@ ON account_group_members (group_id);
-- *********************************************************************
-- AccountGroupIncludeAccess
-- AccountGroupIncludeByUuidAccess
-- @PrimaryKey covers: byGroup
CREATE INDEX account_group_includes_byInclude
ON account_group_includes (include_id);
CREATE INDEX account_group_includes_by_uuid_byInclude
ON account_group_includes_by_uuid (include_uuid);
-- *********************************************************************

View File

@@ -82,10 +82,10 @@ ON account_group_members (group_id);
-- *********************************************************************
-- AccountGroupIncludeAccess
-- AccountGroupIncludeByUuidAccess
-- @PrimaryKey covers: byGroup
CREATE INDEX account_group_includes_byInclude
ON account_group_includes (include_id);
CREATE INDEX account_group_includes_by_uuid_byInclude
ON account_group_includes_by_uuid (include_uuid);
-- *********************************************************************

View File

@@ -123,15 +123,15 @@ public class GroupControl {
return canSeeMembers();
}
public boolean canAddGroup(AccountGroup.Id id) {
public boolean canAddGroup(AccountGroup.UUID uuid) {
return isOwner();
}
public boolean canRemoveGroup(AccountGroup.Id id) {
public boolean canRemoveGroup(AccountGroup.UUID uuid) {
return isOwner();
}
public boolean canSeeGroup(AccountGroup.Id id) {
public boolean canSeeGroup(AccountGroup.UUID uuid) {
return canSeeMembers();
}

View File

@@ -20,7 +20,7 @@ import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupInclude;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gwtorm.server.OrmException;
@@ -123,21 +123,21 @@ public class GroupDetailFactory implements Callable<GroupDetail> {
return members;
}
private List<AccountGroupInclude> loadIncludes() throws OrmException {
List<AccountGroupInclude> groups = new ArrayList<AccountGroupInclude>();
private List<AccountGroupIncludeByUuid> loadIncludes() throws OrmException {
List<AccountGroupIncludeByUuid> groups = new ArrayList<AccountGroupIncludeByUuid>();
for (final AccountGroupInclude m : db.accountGroupIncludes().byGroup(groupId)) {
if (control.canSeeGroup(m.getIncludeId())) {
gic.want(m.getIncludeId());
for (final AccountGroupIncludeByUuid m : db.accountGroupIncludesByUuid().byGroup(groupId)) {
if (control.canSeeGroup(m.getIncludeUUID())) {
gic.want(m.getIncludeUUID());
groups.add(m);
}
}
Collections.sort(groups, new Comparator<AccountGroupInclude>() {
public int compare(final AccountGroupInclude o1,
final AccountGroupInclude o2) {
final AccountGroup a = gic.get(o1.getIncludeId());
final AccountGroup b = gic.get(o2.getIncludeId());
Collections.sort(groups, new Comparator<AccountGroupIncludeByUuid>() {
public int compare(final AccountGroupIncludeByUuid o1,
final AccountGroupIncludeByUuid o2) {
final AccountGroup a = gic.get(o1.getIncludeUUID());
final AccountGroup b = gic.get(o2.getIncludeUUID());
return n(a).compareTo(n(b));
}

View File

@@ -19,7 +19,7 @@ import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupInclude;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.cache.CacheModule;
import com.google.gwtorm.server.SchemaFactory;
@@ -102,8 +102,8 @@ public class GroupIncludeCacheImpl implements GroupIncludeCache {
}
Set<AccountGroup.Id> ids = Sets.newHashSet();
for (AccountGroupInclude agi : db.accountGroupIncludes()
.byInclude(group.get(0).getId())) {
for (AccountGroupIncludeByUuid agi : db.accountGroupIncludesByUuid()
.byIncludeUUID(group.get(0).getGroupUUID())) {
ids.add(agi.getGroupId());
}

View File

@@ -31,35 +31,35 @@ public class GroupInfoCacheFactory {
}
private final GroupCache groupCache;
private final Map<AccountGroup.Id, AccountGroup> out;
private final Map<AccountGroup.UUID, AccountGroup> out;
@Inject
GroupInfoCacheFactory(final GroupCache groupCache) {
this.groupCache = groupCache;
this.out = new HashMap<AccountGroup.Id, AccountGroup>();
this.out = new HashMap<AccountGroup.UUID, AccountGroup>();
}
/**
* Indicate a group will be needed later on.
*
* @param id identity that will be needed in the future; may be null.
* @param uuid identity that will be needed in the future; may be null.
*/
public void want(final AccountGroup.Id id) {
if (id != null && !out.containsKey(id)) {
out.put(id, groupCache.get(id));
public void want(final AccountGroup.UUID uuid) {
if (uuid != null && !out.containsKey(uuid)) {
out.put(uuid, groupCache.get(uuid));
}
}
/** Indicate one or more groups will be needed later on. */
public void want(final Iterable<AccountGroup.Id> ids) {
for (final AccountGroup.Id id : ids) {
want(id);
public void want(final Iterable<AccountGroup.UUID> uuids) {
for (final AccountGroup.UUID uuid : uuids) {
want(uuid);
}
}
public AccountGroup get(final AccountGroup.Id id) {
want(id);
return out.get(id);
public AccountGroup get(final AccountGroup.UUID uuid) {
want(uuid);
return out.get(uuid);
}
/**
@@ -68,6 +68,7 @@ public class GroupInfoCacheFactory {
public GroupInfoCache create() {
final List<GroupInfo> r = new ArrayList<GroupInfo>(out.size());
for (final AccountGroup a : out.values()) {
if (a == null) continue;
r.add(new GroupInfo(a));
}
return new GroupInfoCache(r);

View File

@@ -18,7 +18,7 @@ import com.google.gerrit.common.data.GroupDetail;
import com.google.gerrit.common.errors.NoSuchGroupException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupInclude;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.IdentifiedUser;
@@ -111,9 +111,9 @@ public class GroupMembers {
}
}
if (groupDetail.includes != null) {
for (final AccountGroupInclude groupInclude : groupDetail.includes) {
for (final AccountGroupIncludeByUuid groupInclude : groupDetail.includes) {
final AccountGroup includedGroup =
groupCache.get(groupInclude.getIncludeId());
groupCache.get(groupInclude.getIncludeUUID());
if (!seen.contains(includedGroup.getGroupUUID())) {
members.addAll(listAccounts(includedGroup.getGroupUUID(), project, seen));
}

View File

@@ -18,8 +18,8 @@ import com.google.gerrit.common.errors.NameAlreadyUsedException;
import com.google.gerrit.common.errors.PermissionDeniedException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupInclude;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeAudit;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuidAudit;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.client.AccountGroupName;
@@ -35,7 +35,6 @@ import org.eclipse.jgit.lib.PersonIdent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
public class PerformCreateGroup {
@@ -89,7 +88,7 @@ public class PerformCreateGroup {
final String groupDescription, final boolean visibleToAll,
final AccountGroup.Id ownerGroupId,
final Collection<? extends Account.Id> initialMembers,
final Collection<? extends AccountGroup.Id> initialGroups)
final Collection<? extends AccountGroup.UUID> initialGroups)
throws OrmException, NameAlreadyUsedException, PermissionDeniedException {
if (!currentUser.getCapabilities().canCreateGroup()) {
throw new PermissionDeniedException(String.format(
@@ -160,26 +159,25 @@ public class PerformCreateGroup {
}
private void addGroups(final AccountGroup.Id groupId,
final Collection<? extends AccountGroup.Id> groups) throws OrmException {
final List<AccountGroupInclude> includeList =
new ArrayList<AccountGroupInclude>();
final List<AccountGroupIncludeAudit> includesAudit =
new ArrayList<AccountGroupIncludeAudit>();
for (AccountGroup.Id includeId : groups) {
final AccountGroupInclude groupInclude =
new AccountGroupInclude(new AccountGroupInclude.Key(groupId, includeId));
final Collection<? extends AccountGroup.UUID> groups) throws OrmException {
final List<AccountGroupIncludeByUuid> includeList =
new ArrayList<AccountGroupIncludeByUuid>();
final List<AccountGroupIncludeByUuidAudit> includesAudit =
new ArrayList<AccountGroupIncludeByUuidAudit>();
for (AccountGroup.UUID includeUUID : groups) {
final AccountGroupIncludeByUuid groupInclude =
new AccountGroupIncludeByUuid(new AccountGroupIncludeByUuid.Key(groupId, includeUUID));
includeList.add(groupInclude);
final AccountGroupIncludeAudit audit =
new AccountGroupIncludeAudit(groupInclude, currentUser.getAccountId());
final AccountGroupIncludeByUuidAudit audit =
new AccountGroupIncludeByUuidAudit(groupInclude, currentUser.getAccountId());
includesAudit.add(audit);
}
db.accountGroupIncludes().insert(includeList);
db.accountGroupIncludesAudit().insert(includesAudit);
db.accountGroupIncludesByUuid().insert(includeList);
db.accountGroupIncludesByUuidAudit().insert(includesAudit);
for (AccountGroup group : db.accountGroups().get(
new HashSet<AccountGroup.Id>(groups))) {
groupIncludeCache.evictInclude(group.getGroupUUID());
for (AccountGroup.UUID uuid : groups) {
groupIncludeCache.evictInclude(uuid);
}
}
}

View File

@@ -20,7 +20,7 @@ import com.google.gerrit.common.data.GroupDescriptions;
import com.google.gerrit.common.data.GroupReference;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupInclude;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid;
import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountProjectWatch;
import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
@@ -59,6 +59,7 @@ import java.text.MessageFormat;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.TreeSet;
@@ -476,10 +477,15 @@ public abstract class ChangeEmail extends OutgoingEmail {
.byGroup(next)) {
matching.accounts.add(m.getAccountId());
}
for (AccountGroupInclude m : args.db.get().accountGroupIncludes()
for (AccountGroupIncludeByUuid m : args.db.get().accountGroupIncludesByUuid()
.byGroup(next)) {
if (seen.add(m.getIncludeId())) {
scan.add(m.getIncludeId());
List<AccountGroup> incGroup = args.db.get().accountGroups().
byUUID(m.getIncludeUUID()).toList();
if (incGroup.size() == 1) {
AccountGroup.Id includeId = incGroup.get(0).getId();
if (seen.add(includeId)) {
scan.add(includeId);
}
}
}
}

View File

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

View File

@@ -30,6 +30,7 @@ import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig;
import com.google.gwtorm.jdbc.JdbcSchema;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -41,6 +42,8 @@ import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collections;
public class Schema_57 extends SchemaVersion {
@@ -95,6 +98,11 @@ public class Schema_57 extends SchemaVersion {
// Move the repository.*.createGroup to Create Project.
String[] createGroupList = cfg.getStringList("repository", "*", "createGroup");
// Prepare the account_group_includes query
PreparedStatement stmt = ((JdbcSchema) db).getConnection().
prepareStatement("SELECT * FROM account_group_includes WHERE group_id = ?");
for (String name : createGroupList) {
AccountGroup.NameKey key = new AccountGroup.NameKey(name);
AccountGroupName groupName = db.accountGroupNames().get(key);
@@ -117,9 +125,10 @@ public class Schema_57 extends SchemaVersion {
}
AccountGroup batch = db.accountGroups().get(sc.batchUsersGroupId);
stmt.setInt(0, sc.batchUsersGroupId.get());
if (batch != null
&& db.accountGroupMembers().byGroup(sc.batchUsersGroupId).toList().isEmpty()
&& db.accountGroupIncludes().byGroup(sc.batchUsersGroupId).toList().isEmpty()) {
&& stmt.executeQuery().first() != false) {
// If the batch user group is not used, delete it.
//
db.accountGroups().delete(Collections.singleton(batch));
@@ -136,6 +145,8 @@ public class Schema_57 extends SchemaVersion {
md.setMessage("Upgrade to Gerrit Code Review schema 57\n");
config.commit(md);
} catch (SQLException err) {
throw new OrmException( "Cannot read account_group_includes", err);
} finally {
git.close();
}

View File

@@ -0,0 +1,114 @@
// 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.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuidAudit;
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.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
/* Handles copying all entries from AccountGroupIncludes(Audit) to the new tables */
public class Schema_74 extends SchemaVersion {
@Inject
Schema_74(Provider<Schema_73> prior) {
super(prior);
}
@Override
protected void migrateData(final ReviewDb db, final UpdateUI ui)
throws SQLException, OrmException {
// Grab all the groups since we don't have the cache available
HashMap<AccountGroup.Id, AccountGroup.UUID> allGroups =
new HashMap<AccountGroup.Id, AccountGroup.UUID>();
for( AccountGroup ag : db.accountGroups().all() ) {
allGroups.put(ag.getId(), ag.getGroupUUID());
}
// Initialize some variables
Connection conn = ((JdbcSchema) db).getConnection();
ArrayList<AccountGroupIncludeByUuid> newIncludes =
new ArrayList<AccountGroupIncludeByUuid>();
ArrayList<AccountGroupIncludeByUuidAudit> newIncludeAudits =
new ArrayList<AccountGroupIncludeByUuidAudit>();
// Iterate over all entries in account_group_includes
Statement oldGroupIncludesStmt = conn.createStatement();
ResultSet oldGroupIncludes = oldGroupIncludesStmt.
executeQuery("SELECT * FROM account_group_includes");
while (oldGroupIncludes.next()) {
AccountGroup.Id oldGroupId =
new AccountGroup.Id(oldGroupIncludes.getInt("group_id"));
AccountGroup.Id oldIncludeId =
new AccountGroup.Id(oldGroupIncludes.getInt("include_id"));
AccountGroup.UUID uuidFromIncludeId = allGroups.get(oldIncludeId);
// If we've got an include, but the group no longer exists, don't bother converting
if (uuidFromIncludeId == null) {
ui.message("Skipping group_id = \"" + oldIncludeId.get() +
"\", not a current group");
continue;
}
// Create the new include entry
AccountGroupIncludeByUuid destIncludeEntry = new AccountGroupIncludeByUuid(
new AccountGroupIncludeByUuid.Key(oldGroupId, uuidFromIncludeId));
// Iterate over all the audits (for this group)
PreparedStatement oldAuditsQuery = conn.prepareStatement(
"SELECT * FROM account_group_includes_audit WHERE group_id=? AND include_id=?");
oldAuditsQuery.setInt(1, oldGroupId.get());
oldAuditsQuery.setInt(2, oldIncludeId.get());
ResultSet oldGroupIncludeAudits = oldAuditsQuery.executeQuery();
while (oldGroupIncludeAudits.next()) {
Account.Id addedBy = new Account.Id(oldGroupIncludeAudits.getInt("added_by"));
int removedBy = oldGroupIncludeAudits.getInt("removed_by");
// Create the new audit entry
AccountGroupIncludeByUuidAudit destAuditEntry =
new AccountGroupIncludeByUuidAudit(destIncludeEntry, addedBy,
oldGroupIncludeAudits.getTimestamp("added_on"));
// If this was a "removed on" entry, note that
if (removedBy > 0) {
destAuditEntry.removed(new Account.Id(removedBy),
oldGroupIncludeAudits.getTimestamp("removed_on"));
}
newIncludeAudits.add(destAuditEntry);
}
newIncludes.add(destIncludeEntry);
oldAuditsQuery.close();
oldGroupIncludeAudits.close();
}
oldGroupIncludes.close();
oldGroupIncludesStmt.close();
// Now insert all of the new entries to the database
db.accountGroupIncludesByUuid().insert(newIncludes);
db.accountGroupIncludesByUuidAudit().insert(newIncludeAudits);
}
}

View File

@@ -57,10 +57,10 @@ final class CreateGroupCommand extends SshCommand {
@Option(name = "--visible-to-all", usage = "to make the group visible to all registered users")
private boolean visibleToAll;
private final Set<AccountGroup.Id> initialGroups = new HashSet<AccountGroup.Id>();
private final Set<AccountGroup.UUID> initialGroups = new HashSet<AccountGroup.UUID>();
@Option(name = "--group", aliases = "-g", metaVar = "GROUP", usage = "initial set of groups to be included in the group")
void addGroup(final AccountGroup.Id id) {
void addGroup(final AccountGroup.UUID id) {
initialGroups.add(id);
}