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.audit.Audit;
import com.google.gerrit.common.auth.SignInRequired; import com.google.gerrit.common.auth.SignInRequired;
import com.google.gerrit.reviewdb.client.AccountGroup; 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.AccountGroupMember;
import com.google.gwtjsonrpc.common.AsyncCallback; import com.google.gwtjsonrpc.common.AsyncCallback;
import com.google.gwtjsonrpc.common.RemoteJsonService; import com.google.gwtjsonrpc.common.RemoteJsonService;
@@ -74,8 +74,8 @@ public interface GroupAdminService extends RemoteJsonService {
@Audit @Audit
@SignInRequired @SignInRequired
void addGroupInclude(AccountGroup.Id groupId, String groupName, void addGroupInclude(AccountGroup.Id groupId, AccountGroup.UUID incGroupUUID,
AsyncCallback<GroupDetail> callback); String incGroupName, AsyncCallback<GroupDetail> callback);
@Audit @Audit
@SignInRequired @SignInRequired
@@ -85,5 +85,5 @@ public interface GroupAdminService extends RemoteJsonService {
@Audit @Audit
@SignInRequired @SignInRequired
void deleteGroupIncludes(AccountGroup.Id groupId, 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; package com.google.gerrit.common.data;
import com.google.gerrit.reviewdb.client.AccountGroup; 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.AccountGroupMember;
import java.util.List; import java.util.List;
@@ -25,7 +25,7 @@ public class GroupDetail {
public GroupInfoCache groups; public GroupInfoCache groups;
public AccountGroup group; public AccountGroup group;
public List<AccountGroupMember> members; public List<AccountGroupMember> members;
public List<AccountGroupInclude> includes; public List<AccountGroupIncludeByUuid> includes;
public GroupReference ownerGroup; public GroupReference ownerGroup;
public boolean canModify; public boolean canModify;
@@ -48,7 +48,7 @@ public class GroupDetail {
members = m; members = m;
} }
public void setIncludes(List<AccountGroupInclude> i) { public void setIncludes(List<AccountGroupIncludeByUuid> i) {
includes = 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. */ /** Summary information about an {@link AccountGroup}, for simple tabular displays. */
public class GroupInfo { public class GroupInfo {
protected AccountGroup.Id id; protected AccountGroup.UUID uuid;
protected String name; protected String name;
protected String description; protected String description;
@@ -32,8 +32,8 @@ public class GroupInfo {
* lookup has failed and a stale group id has been discovered in the data * lookup has failed and a stale group id has been discovered in the data
* store. * store.
*/ */
public GroupInfo(final AccountGroup.Id id) { public GroupInfo(final AccountGroup.UUID uuid) {
this.id = id; this.uuid = uuid;
} }
/** /**
@@ -42,14 +42,14 @@ public class GroupInfo {
* @param a the data store record holding the specific group details. * @param a the data store record holding the specific group details.
*/ */
public GroupInfo(final AccountGroup a) { public GroupInfo(final AccountGroup a) {
id = a.getId(); uuid = a.getGroupUUID();
name = a.getName(); name = a.getName();
description = a.getDescription(); description = a.getDescription();
} }
/** @return the unique local id of the group */ /** @return the unique local id of the group */
public AccountGroup.Id getId() { public AccountGroup.UUID getId() {
return id; return uuid;
} }
/** @return the name of the group; null if not supplied */ /** @return the name of the group; null if not supplied */

View File

@@ -33,13 +33,13 @@ public class GroupInfoCache {
return EMPTY; return EMPTY;
} }
protected Map<AccountGroup.Id, GroupInfo> groups; protected Map<AccountGroup.UUID, GroupInfo> groups;
protected GroupInfoCache() { protected GroupInfoCache() {
} }
public GroupInfoCache(final Iterable<GroupInfo> list) { public GroupInfoCache(final Iterable<GroupInfo> list) {
groups = new HashMap<AccountGroup.Id, GroupInfo>(); groups = new HashMap<AccountGroup.UUID, GroupInfo>();
for (final GroupInfo gi : list) { for (final GroupInfo gi : list) {
groups.put(gi.getId(), gi); groups.put(gi.getId(), gi);
} }
@@ -58,15 +58,15 @@ public class GroupInfoCache {
* @param id the id desired. * @param id the id desired.
* @return info block for the group. * @return info block for the group.
*/ */
public GroupInfo get(final AccountGroup.Id id) { public GroupInfo get(final AccountGroup.UUID uuid) {
if (id == null) { if (uuid == null) {
return null; return null;
} }
GroupInfo r = groups.get(id); GroupInfo r = groups.get(uuid);
if (r == null) { if (r == null) {
r = new GroupInfo(id); r = new GroupInfo(uuid);
groups.put(id, r); groups.put(uuid, r);
} }
return 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.client.ui.SmallHeading;
import com.google.gerrit.common.data.AccountInfoCache; import com.google.gerrit.common.data.AccountInfoCache;
import com.google.gerrit.common.data.GroupDetail; 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.common.data.GroupInfoCache;
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;
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.AccountGroupMember;
import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.ClickHandler;
@@ -110,14 +109,15 @@ public class AccountGroupMembersScreen extends AccountGroupScreen {
} }
private void initIncludeList() { private void initIncludeList() {
final AccountGroupSuggestOracle oracle = new AccountGroupSuggestOracle();
addIncludeBox = addIncludeBox =
new AddMemberBox(Util.C.buttonAddIncludedGroup(), new AddMemberBox(Util.C.buttonAddIncludedGroup(),
Util.C.defaultAccountGroupName(), new AccountGroupSuggestOracle()); Util.C.defaultAccountGroupName(), oracle);
addIncludeBox.addClickHandler(new ClickHandler() { addIncludeBox.addClickHandler(new ClickHandler() {
@Override @Override
public void onClick(final ClickEvent event) { 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(); final String groupName = addIncludeBox.getText();
if (groupName.length() == 0) { if (groupName.length() == 0) {
return; return;
} }
addIncludeBox.setEnabled(false); addIncludeBox.setEnabled(false);
Util.GROUP_SVC.addGroupInclude(getGroupId(), groupName, Util.GROUP_SVC.addGroupInclude(getGroupId(), oracle.getUUID(groupName), groupName,
new GerritCallback<GroupDetail>() { new GerritCallback<GroupDetail>() {
public void onSuccess(final GroupDetail result) { public void onSuccess(final GroupDetail result) {
addIncludeBox.setEnabled(true); 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; private boolean enabled = true;
IncludeTable() { IncludeTable() {
@@ -314,7 +314,7 @@ public class AccountGroupMembersScreen extends AccountGroupScreen {
void setEnabled(final boolean enabled) { void setEnabled(final boolean enabled) {
this.enabled = enabled; this.enabled = enabled;
for (int row = 1; row < table.getRowCount(); row++) { for (int row = 1; row < table.getRowCount(); row++) {
final AccountGroupInclude k = getRowItem(row); final AccountGroupIncludeByUuid k = getRowItem(row);
if (k != null) { if (k != null) {
((CheckBox) table.getWidget(row, 1)).setEnabled(enabled); ((CheckBox) table.getWidget(row, 1)).setEnabled(enabled);
} }
@@ -322,10 +322,10 @@ public class AccountGroupMembersScreen extends AccountGroupScreen {
} }
void deleteChecked() { void deleteChecked() {
final HashSet<AccountGroupInclude.Key> keys = final HashSet<AccountGroupIncludeByUuid.Key> keys =
new HashSet<AccountGroupInclude.Key>(); new HashSet<AccountGroupIncludeByUuid.Key>();
for (int row = 1; row < table.getRowCount(); row++) { 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()) { if (k != null && ((CheckBox) table.getWidget(row, 1)).getValue()) {
keys.add(k.getKey()); keys.add(k.getKey());
} }
@@ -335,7 +335,7 @@ public class AccountGroupMembersScreen extends AccountGroupScreen {
new GerritCallback<VoidResult>() { new GerritCallback<VoidResult>() {
public void onSuccess(final VoidResult result) { public void onSuccess(final VoidResult result) {
for (int row = 1; row < table.getRowCount();) { for (int row = 1; row < table.getRowCount();) {
final AccountGroupInclude k = getRowItem(row); final AccountGroupIncludeByUuid k = getRowItem(row);
if (k != null && keys.contains(k.getKey())) { if (k != null && keys.contains(k.getKey())) {
table.removeRow(row); table.removeRow(row);
} else { } 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()) while (1 < table.getRowCount())
table.removeRow(table.getRowCount() - 1); table.removeRow(table.getRowCount() - 1);
for (final AccountGroupInclude k : result) { for (final AccountGroupIncludeByUuid k : result) {
final int row = table.getRowCount(); final int row = table.getRowCount();
table.insertRow(row); table.insertRow(row);
applyDataRowStyle(row); applyDataRowStyle(row);
@@ -359,15 +359,18 @@ public class AccountGroupMembersScreen extends AccountGroupScreen {
} }
} }
void populate(final int row, final AccountGroupInclude k) { void populate(final int row, final AccountGroupIncludeByUuid k) {
AccountGroup.Id id = k.getIncludeId(); AccountGroup.UUID uuid = k.getIncludeUUID();
GroupInfo group = groups.get(id);
CheckBox checkBox = new CheckBox(); CheckBox checkBox = new CheckBox();
table.setWidget(row, 1, checkBox); table.setWidget(row, 1, checkBox);
checkBox.setEnabled(enabled); checkBox.setEnabled(enabled);
if (AccountGroup.isInternalGroup(uuid)) {
table.setWidget(row, 2, table.setWidget(row, 2,
new Hyperlink(group.getName(), Dispatcher.toGroup(id))); new Hyperlink(groups.get(uuid).getName(), Dispatcher.toGroup(uuid)));
table.setText(row, 3, groups.get(id).getDescription()); table.setText(row, 3, groups.get(uuid).getDescription());
} else {
table.setText(row, 2, uuid.get());
}
final FlexCellFormatter fmt = table.getFlexCellFormatter(); final FlexCellFormatter fmt = table.getFlexCellFormatter();
fmt.addStyleName(row, 1, Gerrit.RESOURCES.css().iconCell()); 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.httpd.rpc.BaseServiceImplementation;
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;
import com.google.gerrit.reviewdb.client.AccountGroupInclude; import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeAudit; import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuidAudit;
import com.google.gerrit.reviewdb.client.AccountGroupMember; import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit; import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.client.AuthType; import com.google.gerrit.reviewdb.client.AuthType;
@@ -225,7 +225,8 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
} }
public void addGroupInclude(final AccountGroup.Id groupId, 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>() { run(callback, new Action<GroupDetail>() {
public GroupDetail run(ReviewDb db) throws OrmException, Failure, public GroupDetail run(ReviewDb db) throws OrmException, Failure,
NoSuchGroupException { NoSuchGroupException {
@@ -234,21 +235,24 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
throw new Failure(new NameAlreadyUsedException()); throw new Failure(new NameAlreadyUsedException());
} }
final AccountGroup a = findGroup(groupName); if (incGroupUUID == null) {
if (!control.canAddGroup(a.getId())) { throw new Failure(new NoSuchGroupException(incGroupName));
}
if (!control.canAddGroup(incGroupUUID)) {
throw new Failure(new NoSuchEntityException()); throw new Failure(new NoSuchEntityException());
} }
final AccountGroupInclude.Key key = final AccountGroupIncludeByUuid.Key key =
new AccountGroupInclude.Key(groupId, a.getId()); new AccountGroupIncludeByUuid.Key(groupId, incGroupUUID);
AccountGroupInclude m = db.accountGroupIncludes().get(key); AccountGroupIncludeByUuid m = db.accountGroupIncludesByUuid().get(key);
if (m == null) { if (m == null) {
m = new AccountGroupInclude(key); m = new AccountGroupIncludeByUuid(key);
db.accountGroupIncludesAudit().insert( db.accountGroupIncludesByUuidAudit().insert(
Collections.singleton(new AccountGroupIncludeAudit(m, Collections.singleton(new AccountGroupIncludeByUuidAudit(m,
getAccountId()))); getAccountId())));
db.accountGroupIncludes().insert(Collections.singleton(m)); db.accountGroupIncludesByUuid().insert(Collections.singleton(m));
groupIncludeCache.evictInclude(a.getGroupUUID()); groupIncludeCache.evictInclude(incGroupUUID);
} }
return groupDetailFactory.create(groupId).call(); return groupDetailFactory.create(groupId).call();
@@ -311,7 +315,7 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
} }
public void deleteGroupIncludes(final AccountGroup.Id groupId, public void deleteGroupIncludes(final AccountGroup.Id groupId,
final Set<AccountGroupInclude.Key> keys, final Set<AccountGroupIncludeByUuid.Key> keys,
final AsyncCallback<VoidResult> callback) { final AsyncCallback<VoidResult> callback) {
run(callback, new Action<VoidResult>() { run(callback, new Action<VoidResult>() {
public VoidResult run(final ReviewDb db) throws OrmException, public VoidResult run(final ReviewDb db) throws OrmException,
@@ -321,26 +325,26 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
throw new Failure(new NameAlreadyUsedException()); throw new Failure(new NameAlreadyUsedException());
} }
for (final AccountGroupInclude.Key k : keys) { for (final AccountGroupIncludeByUuid.Key k : keys) {
if (!groupId.equals(k.getGroupId())) { if (!groupId.equals(k.getGroupId())) {
throw new Failure(new NoSuchEntityException()); throw new Failure(new NoSuchEntityException());
} }
} }
final Account.Id me = getAccountId(); final Account.Id me = getAccountId();
final Set<AccountGroup.Id> groupsToEvict = new HashSet<AccountGroup.Id>(); final Set<AccountGroup.UUID> groupsToEvict = new HashSet<AccountGroup.UUID>();
for (final AccountGroupInclude.Key k : keys) { for (final AccountGroupIncludeByUuid.Key k : keys) {
final AccountGroupInclude m = final AccountGroupIncludeByUuid m =
db.accountGroupIncludes().get(k); db.accountGroupIncludesByUuid().get(k);
if (m != null) { if (m != null) {
if (!control.canRemoveGroup(m.getIncludeId())) { if (!control.canRemoveGroup(m.getIncludeUUID())) {
throw new Failure(new NoSuchEntityException()); throw new Failure(new NoSuchEntityException());
} }
AccountGroupIncludeAudit audit = null; AccountGroupIncludeByUuidAudit audit = null;
for (AccountGroupIncludeAudit a : db for (AccountGroupIncludeByUuidAudit a : db
.accountGroupIncludesAudit().byGroupInclude( .accountGroupIncludesByUuidAudit().byGroupInclude(
m.getGroupId(), m.getIncludeId())) { m.getGroupId(), m.getIncludeUUID())) {
if (a.isActive()) { if (a.isActive()) {
audit = a; audit = a;
break; break;
@@ -349,15 +353,15 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
if (audit != null) { if (audit != null) {
audit.removed(me); audit.removed(me);
db.accountGroupIncludesAudit().update( db.accountGroupIncludesByUuidAudit().update(
Collections.singleton(audit)); Collections.singleton(audit));
} }
db.accountGroupIncludes().delete(Collections.singleton(m)); db.accountGroupIncludesByUuid().delete(Collections.singleton(m));
groupsToEvict.add(k.getIncludeId()); groupsToEvict.add(k.getIncludeUUID());
} }
} }
for (AccountGroup group : db.accountGroups().get(groupsToEvict)) { for (AccountGroup.UUID uuid : groupsToEvict) {
groupIncludeCache.evictInclude(group.getGroupUUID()); groupIncludeCache.evictInclude(uuid);
} }
return VoidResult.INSTANCE; return VoidResult.INSTANCE;
} }
@@ -408,14 +412,4 @@ class GroupAdminServiceImpl extends BaseServiceImplementation implements
return null; 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; import com.google.gwtorm.client.CompoundKey;
/** Membership of an {@link AccountGroup} in an {@link AccountGroup}. */ /** 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> { public static class Key extends CompoundKey<AccountGroup.Id> {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@@ -26,16 +26,16 @@ public final class AccountGroupInclude {
protected AccountGroup.Id groupId; protected AccountGroup.Id groupId;
@Column(id = 2) @Column(id = 2)
protected AccountGroup.Id includeId; protected AccountGroup.UUID includeUUID;
protected Key() { protected Key() {
groupId = new AccountGroup.Id(); 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; groupId = g;
includeId = i; includeUUID = u;
} }
@Override @Override
@@ -47,27 +47,27 @@ public final class AccountGroupInclude {
return groupId; return groupId;
} }
public AccountGroup.Id getIncludeId() { public AccountGroup.UUID getIncludeUUID() {
return includeId; return includeUUID;
} }
@Override @Override
public com.google.gwtorm.client.Key<?>[] members() { 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) @Column(id = 1, name = Column.NONE)
protected Key key; protected Key key;
protected AccountGroupInclude() { protected AccountGroupIncludeByUuid() {
} }
public AccountGroupInclude(final AccountGroupInclude.Key k) { public AccountGroupIncludeByUuid(final AccountGroupIncludeByUuid.Key k) {
key = k; key = k;
} }
public AccountGroupInclude.Key getKey() { public AccountGroupIncludeByUuid.Key getKey() {
return key; return key;
} }
@@ -75,7 +75,7 @@ public final class AccountGroupInclude {
return key.groupId; return key.groupId;
} }
public AccountGroup.Id getIncludeId() { public AccountGroup.UUID getIncludeUUID() {
return key.includeId; return key.includeUUID;
} }
} }

View File

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

View File

@@ -15,21 +15,21 @@
package com.google.gerrit.reviewdb.server; package com.google.gerrit.reviewdb.server;
import com.google.gerrit.reviewdb.client.AccountGroup; 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.Access;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.PrimaryKey; import com.google.gwtorm.server.PrimaryKey;
import com.google.gwtorm.server.Query; import com.google.gwtorm.server.Query;
import com.google.gwtorm.server.ResultSet; import com.google.gwtorm.server.ResultSet;
public interface AccountGroupIncludeAccess extends public interface AccountGroupIncludeByUuidAccess extends
Access<AccountGroupInclude, AccountGroupInclude.Key> { Access<AccountGroupIncludeByUuid, AccountGroupIncludeByUuid.Key> {
@PrimaryKey("key") @PrimaryKey("key")
AccountGroupInclude get(AccountGroupInclude.Key key) throws OrmException; AccountGroupIncludeByUuid get(AccountGroupIncludeByUuid.Key key) throws OrmException;
@Query("WHERE key.includeId = ?") @Query("WHERE key.includeUUID = ?")
ResultSet<AccountGroupInclude> byInclude(AccountGroup.Id id) throws OrmException; ResultSet<AccountGroupIncludeByUuid> byIncludeUUID(AccountGroup.UUID uuid) throws OrmException;
@Query("WHERE key.groupId = ?") @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; package com.google.gerrit.reviewdb.server;
import com.google.gerrit.reviewdb.client.AccountGroup; 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.Access;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.PrimaryKey; import com.google.gwtorm.server.PrimaryKey;
import com.google.gwtorm.server.Query; import com.google.gwtorm.server.Query;
import com.google.gwtorm.server.ResultSet; import com.google.gwtorm.server.ResultSet;
public interface AccountGroupIncludeAuditAccess extends public interface AccountGroupIncludeByUuidAuditAccess extends
Access<AccountGroupIncludeAudit, AccountGroupIncludeAudit.Key> { Access<AccountGroupIncludeByUuidAudit, AccountGroupIncludeByUuidAudit.Key> {
@PrimaryKey("key") @PrimaryKey("key")
AccountGroupIncludeAudit get(AccountGroupIncludeAudit.Key key) AccountGroupIncludeByUuidAudit get(AccountGroupIncludeByUuidAudit.Key key)
throws OrmException; throws OrmException;
@Query("WHERE key.groupId = ? AND key.includeId = ?") @Query("WHERE key.groupId = ? AND key.includeUUID = ?")
ResultSet<AccountGroupIncludeAudit> byGroupInclude(AccountGroup.Id groupId, ResultSet<AccountGroupIncludeByUuidAudit> byGroupInclude(AccountGroup.Id groupId,
AccountGroup.Id incGroupId) throws OrmException; AccountGroup.UUID incGroupUUID) throws OrmException;
} }

View File

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

View File

@@ -34,10 +34,10 @@ ON account_group_members (group_id);
-- ********************************************************************* -- *********************************************************************
-- AccountGroupIncludeAccess -- AccountGroupIncludeByUuidAccess
-- @PrimaryKey covers: byGroup -- @PrimaryKey covers: byGroup
CREATE INDEX account_group_includes_byInclude CREATE INDEX account_group_includes_by_uuid_byInclude
ON account_group_includes (include_id); 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 -- @PrimaryKey covers: byGroup
CREATE INDEX account_group_includes_byInclude CREATE INDEX account_group_includes_by_uuid_byInclude
ON account_group_includes (include_id); ON account_group_includes_by_uuid (include_uuid);
-- ********************************************************************* -- *********************************************************************

View File

@@ -123,15 +123,15 @@ public class GroupControl {
return canSeeMembers(); return canSeeMembers();
} }
public boolean canAddGroup(AccountGroup.Id id) { public boolean canAddGroup(AccountGroup.UUID uuid) {
return isOwner(); return isOwner();
} }
public boolean canRemoveGroup(AccountGroup.Id id) { public boolean canRemoveGroup(AccountGroup.UUID uuid) {
return isOwner(); return isOwner();
} }
public boolean canSeeGroup(AccountGroup.Id id) { public boolean canSeeGroup(AccountGroup.UUID uuid) {
return canSeeMembers(); 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.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;
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.AccountGroupMember;
import com.google.gerrit.reviewdb.server.ReviewDb; import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
@@ -123,21 +123,21 @@ public class GroupDetailFactory implements Callable<GroupDetail> {
return members; return members;
} }
private List<AccountGroupInclude> loadIncludes() throws OrmException { private List<AccountGroupIncludeByUuid> loadIncludes() throws OrmException {
List<AccountGroupInclude> groups = new ArrayList<AccountGroupInclude>(); List<AccountGroupIncludeByUuid> groups = new ArrayList<AccountGroupIncludeByUuid>();
for (final AccountGroupInclude m : db.accountGroupIncludes().byGroup(groupId)) { for (final AccountGroupIncludeByUuid m : db.accountGroupIncludesByUuid().byGroup(groupId)) {
if (control.canSeeGroup(m.getIncludeId())) { if (control.canSeeGroup(m.getIncludeUUID())) {
gic.want(m.getIncludeId()); gic.want(m.getIncludeUUID());
groups.add(m); groups.add(m);
} }
} }
Collections.sort(groups, new Comparator<AccountGroupInclude>() { Collections.sort(groups, new Comparator<AccountGroupIncludeByUuid>() {
public int compare(final AccountGroupInclude o1, public int compare(final AccountGroupIncludeByUuid o1,
final AccountGroupInclude o2) { final AccountGroupIncludeByUuid o2) {
final AccountGroup a = gic.get(o1.getIncludeId()); final AccountGroup a = gic.get(o1.getIncludeUUID());
final AccountGroup b = gic.get(o2.getIncludeId()); final AccountGroup b = gic.get(o2.getIncludeUUID());
return n(a).compareTo(n(b)); 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.ImmutableSet;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.gerrit.reviewdb.client.AccountGroup; 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.reviewdb.server.ReviewDb;
import com.google.gerrit.server.cache.CacheModule; import com.google.gerrit.server.cache.CacheModule;
import com.google.gwtorm.server.SchemaFactory; import com.google.gwtorm.server.SchemaFactory;
@@ -102,8 +102,8 @@ public class GroupIncludeCacheImpl implements GroupIncludeCache {
} }
Set<AccountGroup.Id> ids = Sets.newHashSet(); Set<AccountGroup.Id> ids = Sets.newHashSet();
for (AccountGroupInclude agi : db.accountGroupIncludes() for (AccountGroupIncludeByUuid agi : db.accountGroupIncludesByUuid()
.byInclude(group.get(0).getId())) { .byIncludeUUID(group.get(0).getGroupUUID())) {
ids.add(agi.getGroupId()); ids.add(agi.getGroupId());
} }

View File

@@ -31,35 +31,35 @@ public class GroupInfoCacheFactory {
} }
private final GroupCache groupCache; private final GroupCache groupCache;
private final Map<AccountGroup.Id, AccountGroup> out; private final Map<AccountGroup.UUID, AccountGroup> out;
@Inject @Inject
GroupInfoCacheFactory(final GroupCache groupCache) { GroupInfoCacheFactory(final GroupCache groupCache) {
this.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. * 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) { public void want(final AccountGroup.UUID uuid) {
if (id != null && !out.containsKey(id)) { if (uuid != null && !out.containsKey(uuid)) {
out.put(id, groupCache.get(id)); out.put(uuid, groupCache.get(uuid));
} }
} }
/** Indicate one or more groups will be needed later on. */ /** Indicate one or more groups will be needed later on. */
public void want(final Iterable<AccountGroup.Id> ids) { public void want(final Iterable<AccountGroup.UUID> uuids) {
for (final AccountGroup.Id id : ids) { for (final AccountGroup.UUID uuid : uuids) {
want(id); want(uuid);
} }
} }
public AccountGroup get(final AccountGroup.Id id) { public AccountGroup get(final AccountGroup.UUID uuid) {
want(id); want(uuid);
return out.get(id); return out.get(uuid);
} }
/** /**
@@ -68,6 +68,7 @@ public class GroupInfoCacheFactory {
public GroupInfoCache create() { public GroupInfoCache create() {
final List<GroupInfo> r = new ArrayList<GroupInfo>(out.size()); final List<GroupInfo> r = new ArrayList<GroupInfo>(out.size());
for (final AccountGroup a : out.values()) { for (final AccountGroup a : out.values()) {
if (a == null) continue;
r.add(new GroupInfo(a)); r.add(new GroupInfo(a));
} }
return new GroupInfoCache(r); 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.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;
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.AccountGroupMember;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.IdentifiedUser;
@@ -111,9 +111,9 @@ public class GroupMembers {
} }
} }
if (groupDetail.includes != null) { if (groupDetail.includes != null) {
for (final AccountGroupInclude groupInclude : groupDetail.includes) { for (final AccountGroupIncludeByUuid groupInclude : groupDetail.includes) {
final AccountGroup includedGroup = final AccountGroup includedGroup =
groupCache.get(groupInclude.getIncludeId()); groupCache.get(groupInclude.getIncludeUUID());
if (!seen.contains(includedGroup.getGroupUUID())) { if (!seen.contains(includedGroup.getGroupUUID())) {
members.addAll(listAccounts(includedGroup.getGroupUUID(), project, seen)); 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.common.errors.PermissionDeniedException;
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;
import com.google.gerrit.reviewdb.client.AccountGroupInclude; import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuid;
import com.google.gerrit.reviewdb.client.AccountGroupIncludeAudit; import com.google.gerrit.reviewdb.client.AccountGroupIncludeByUuidAudit;
import com.google.gerrit.reviewdb.client.AccountGroupMember; import com.google.gerrit.reviewdb.client.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit; import com.google.gerrit.reviewdb.client.AccountGroupMemberAudit;
import com.google.gerrit.reviewdb.client.AccountGroupName; import com.google.gerrit.reviewdb.client.AccountGroupName;
@@ -35,7 +35,6 @@ import org.eclipse.jgit.lib.PersonIdent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
public class PerformCreateGroup { public class PerformCreateGroup {
@@ -89,7 +88,7 @@ public class PerformCreateGroup {
final String groupDescription, final boolean visibleToAll, final String groupDescription, final boolean visibleToAll,
final AccountGroup.Id ownerGroupId, final AccountGroup.Id ownerGroupId,
final Collection<? extends Account.Id> initialMembers, final Collection<? extends Account.Id> initialMembers,
final Collection<? extends AccountGroup.Id> initialGroups) final Collection<? extends AccountGroup.UUID> initialGroups)
throws OrmException, NameAlreadyUsedException, PermissionDeniedException { throws OrmException, NameAlreadyUsedException, PermissionDeniedException {
if (!currentUser.getCapabilities().canCreateGroup()) { if (!currentUser.getCapabilities().canCreateGroup()) {
throw new PermissionDeniedException(String.format( throw new PermissionDeniedException(String.format(
@@ -160,26 +159,25 @@ public class PerformCreateGroup {
} }
private void addGroups(final AccountGroup.Id groupId, private void addGroups(final AccountGroup.Id groupId,
final Collection<? extends AccountGroup.Id> groups) throws OrmException { final Collection<? extends AccountGroup.UUID> groups) throws OrmException {
final List<AccountGroupInclude> includeList = final List<AccountGroupIncludeByUuid> includeList =
new ArrayList<AccountGroupInclude>(); new ArrayList<AccountGroupIncludeByUuid>();
final List<AccountGroupIncludeAudit> includesAudit = final List<AccountGroupIncludeByUuidAudit> includesAudit =
new ArrayList<AccountGroupIncludeAudit>(); new ArrayList<AccountGroupIncludeByUuidAudit>();
for (AccountGroup.Id includeId : groups) { for (AccountGroup.UUID includeUUID : groups) {
final AccountGroupInclude groupInclude = final AccountGroupIncludeByUuid groupInclude =
new AccountGroupInclude(new AccountGroupInclude.Key(groupId, includeId)); new AccountGroupIncludeByUuid(new AccountGroupIncludeByUuid.Key(groupId, includeUUID));
includeList.add(groupInclude); includeList.add(groupInclude);
final AccountGroupIncludeAudit audit = final AccountGroupIncludeByUuidAudit audit =
new AccountGroupIncludeAudit(groupInclude, currentUser.getAccountId()); new AccountGroupIncludeByUuidAudit(groupInclude, currentUser.getAccountId());
includesAudit.add(audit); includesAudit.add(audit);
} }
db.accountGroupIncludes().insert(includeList); db.accountGroupIncludesByUuid().insert(includeList);
db.accountGroupIncludesAudit().insert(includesAudit); db.accountGroupIncludesByUuidAudit().insert(includesAudit);
for (AccountGroup group : db.accountGroups().get( for (AccountGroup.UUID uuid : groups) {
new HashSet<AccountGroup.Id>(groups))) { groupIncludeCache.evictInclude(uuid);
groupIncludeCache.evictInclude(group.getGroupUUID());
} }
} }
} }

View File

@@ -20,7 +20,7 @@ import com.google.gerrit.common.data.GroupDescriptions;
import com.google.gerrit.common.data.GroupReference; import com.google.gerrit.common.data.GroupReference;
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;
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.AccountGroupMember;
import com.google.gerrit.reviewdb.client.AccountProjectWatch; import com.google.gerrit.reviewdb.client.AccountProjectWatch;
import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType; import com.google.gerrit.reviewdb.client.AccountProjectWatch.NotifyType;
@@ -59,6 +59,7 @@ import java.text.MessageFormat;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Queue; import java.util.Queue;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
@@ -476,10 +477,15 @@ public abstract class ChangeEmail extends OutgoingEmail {
.byGroup(next)) { .byGroup(next)) {
matching.accounts.add(m.getAccountId()); matching.accounts.add(m.getAccountId());
} }
for (AccountGroupInclude m : args.db.get().accountGroupIncludes() for (AccountGroupIncludeByUuid m : args.db.get().accountGroupIncludesByUuid()
.byGroup(next)) { .byGroup(next)) {
if (seen.add(m.getIncludeId())) { List<AccountGroup> incGroup = args.db.get().accountGroups().
scan.add(m.getIncludeId()); 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. */ /** 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_73> C = Schema_73.class; public static final Class<Schema_74> C = Schema_74.class;
public static class Module extends AbstractModule { public static class Module extends AbstractModule {
@Override @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.LocalDiskRepositoryManager;
import com.google.gerrit.server.git.MetaDataUpdate; import com.google.gerrit.server.git.MetaDataUpdate;
import com.google.gerrit.server.git.ProjectConfig; import com.google.gerrit.server.git.ProjectConfig;
import com.google.gwtorm.jdbc.JdbcSchema;
import com.google.gwtorm.server.OrmException; 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;
@@ -41,6 +42,8 @@ import org.eclipse.jgit.storage.file.FileBasedConfig;
import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS;
import java.io.IOException; import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collections; import java.util.Collections;
public class Schema_57 extends SchemaVersion { public class Schema_57 extends SchemaVersion {
@@ -95,6 +98,11 @@ public class Schema_57 extends SchemaVersion {
// Move the repository.*.createGroup to Create Project. // Move the repository.*.createGroup to Create Project.
String[] createGroupList = cfg.getStringList("repository", "*", "createGroup"); 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) { for (String name : createGroupList) {
AccountGroup.NameKey key = new AccountGroup.NameKey(name); AccountGroup.NameKey key = new AccountGroup.NameKey(name);
AccountGroupName groupName = db.accountGroupNames().get(key); AccountGroupName groupName = db.accountGroupNames().get(key);
@@ -117,9 +125,10 @@ public class Schema_57 extends SchemaVersion {
} }
AccountGroup batch = db.accountGroups().get(sc.batchUsersGroupId); AccountGroup batch = db.accountGroups().get(sc.batchUsersGroupId);
stmt.setInt(0, sc.batchUsersGroupId.get());
if (batch != null if (batch != null
&& db.accountGroupMembers().byGroup(sc.batchUsersGroupId).toList().isEmpty() && 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. // If the batch user group is not used, delete it.
// //
db.accountGroups().delete(Collections.singleton(batch)); 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"); md.setMessage("Upgrade to Gerrit Code Review schema 57\n");
config.commit(md); config.commit(md);
} catch (SQLException err) {
throw new OrmException( "Cannot read account_group_includes", err);
} finally { } finally {
git.close(); 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") @Option(name = "--visible-to-all", usage = "to make the group visible to all registered users")
private boolean visibleToAll; 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") @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); initialGroups.add(id);
} }