Move PatchSetPublishDetail.load() to server side and introduce PatchSetInfoFactory.

This is analogous to 8d79fd29a5.

PatchSetInfoFactory is a class containing a few static methods used for
obtaining PatchSetInfo from Git repository. This class is going to replace
any use of PatchSetInfoAccess interface which will make it possible to
remove redundant information from database.

Added small FIXME reminding to move code not related to patchSetInfo to
separate method once refactoring is finished.

Signed-off-by: Grzegorz Kossakowski <grek@google.com>
This commit is contained in:
Grzegorz Kossakowski
2009-07-29 13:50:15 -07:00
parent 5775075e37
commit 203a775142
7 changed files with 328 additions and 77 deletions

View File

@@ -22,6 +22,8 @@ import com.google.gerrit.client.reviewdb.Change;
import com.google.gerrit.client.reviewdb.PatchSet;
import com.google.gerrit.client.reviewdb.ReviewDb;
import com.google.gerrit.client.rpc.NoSuchEntityException;
import com.google.gerrit.server.changes.PatchSetPublishDetailFactory;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.SchemaFactory;
@@ -29,9 +31,14 @@ import com.google.inject.Inject;
class ChangeDetailServiceImpl extends BaseServiceImplementation implements
ChangeDetailService {
private final PatchSetInfoFactory infoFactory;
@Inject
ChangeDetailServiceImpl(final SchemaFactory<ReviewDb> sf) {
ChangeDetailServiceImpl(final SchemaFactory<ReviewDb> sf,
PatchSetInfoFactory infoFactory) {
super(sf);
this.infoFactory = infoFactory;
}
public void changeDetail(final Change.Id id,
@@ -58,20 +65,6 @@ class ChangeDetailServiceImpl extends BaseServiceImplementation implements
public void patchSetPublishDetail(final PatchSet.Id id,
final AsyncCallback<PatchSetPublishDetail> callback) {
run(callback, new Action<PatchSetPublishDetail>() {
public PatchSetPublishDetail run(final ReviewDb db) throws OrmException,
Failure {
final PatchSet ps = db.patchSets().get(id);
final Change change = db.changes().get(ps.getId().getParentKey());
if (ps == null || change == null) {
throw new Failure(new NoSuchEntityException());
}
assertCanRead(change);
final PatchSetPublishDetail d = new PatchSetPublishDetail();
d.load(db, change, id);
return d;
}
});
run(callback, new PatchSetPublishDetailFactory(id, infoFactory));
}
}

View File

@@ -23,6 +23,7 @@ import com.google.gerrit.git.ChangeMergeQueue;
import com.google.gerrit.git.MergeQueue;
import com.google.gerrit.git.PushReplication;
import com.google.gerrit.git.ReplicationQueue;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.GerritServerConfigProvider;
import com.google.gerrit.server.config.SitePath;
@@ -70,5 +71,6 @@ public class GerritServerModule extends AbstractModule {
bind(EmailSender.class).to(SmtpEmailSender.class).in(SINGLETON);
bind(GerritConfig.class).toProvider(GerritConfigProvider.class).in(
SINGLETON);
bind(PatchSetInfoFactory.class);
}
}

View File

@@ -0,0 +1,139 @@
// Copyright (C) 2009 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.changes;
import com.google.gerrit.client.changes.PatchSetPublishDetail;
import com.google.gerrit.client.data.AccountInfoCache;
import com.google.gerrit.client.data.AccountInfoCacheFactory;
import com.google.gerrit.client.data.ApprovalType;
import com.google.gerrit.client.data.GerritConfig;
import com.google.gerrit.client.data.ProjectCache;
import com.google.gerrit.client.reviewdb.Account;
import com.google.gerrit.client.reviewdb.AccountGroup;
import com.google.gerrit.client.reviewdb.ApprovalCategory;
import com.google.gerrit.client.reviewdb.ApprovalCategoryValue;
import com.google.gerrit.client.reviewdb.Change;
import com.google.gerrit.client.reviewdb.ChangeApproval;
import com.google.gerrit.client.reviewdb.PatchLineComment;
import com.google.gerrit.client.reviewdb.PatchSet;
import com.google.gerrit.client.reviewdb.PatchSetInfo;
import com.google.gerrit.client.reviewdb.ProjectRight;
import com.google.gerrit.client.reviewdb.ReviewDb;
import com.google.gerrit.client.rpc.Common;
import com.google.gerrit.server.BaseServiceImplementation.Action;
import com.google.gerrit.server.BaseServiceImplementation.Failure;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gwtorm.client.OrmException;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public final class PatchSetPublishDetailFactory
implements Action<PatchSetPublishDetail> {
final PatchSet.Id patchSetId;
final PatchSetInfoFactory infoFactory;
protected AccountInfoCache accounts;
protected PatchSetInfo patchSetInfo;
protected Change change;
protected List<PatchLineComment> drafts;
protected Map<ApprovalCategory.Id, Set<ApprovalCategoryValue.Id>> allowed;
protected Map<ApprovalCategory.Id, ChangeApproval> given;
public PatchSetPublishDetailFactory(PatchSet.Id patchSetId,
PatchSetInfoFactory infoFactory) {
this.patchSetId = patchSetId;
this.infoFactory = infoFactory;
}
@Override
public PatchSetPublishDetail run(ReviewDb db) throws OrmException, Failure {
final AccountInfoCacheFactory acc = new AccountInfoCacheFactory(db);
final Account.Id me = Common.getAccountId();
final Change.Id changeId = patchSetId.getParentKey();
change = db.changes().get(changeId);
try {
patchSetInfo = infoFactory.get(patchSetId);
} catch (PatchSetInfoNotAvailableException e) {
throw new Failure(e);
}
drafts = db.patchComments().draft(patchSetId, me).toList();
allowed = new HashMap<ApprovalCategory.Id, Set<ApprovalCategoryValue.Id>>();
given = new HashMap<ApprovalCategory.Id, ChangeApproval>();
if (change.getStatus().isOpen() &&
patchSetId.equals(change.currentPatchSetId())) {
computeAllowed();
for (final ChangeApproval a : db.changeApprovals().byChangeUser(
changeId, me)) {
given.put(a.getCategoryId(), a);
}
}
acc.want(change.getOwner());
accounts = acc.create();
PatchSetPublishDetail detail = new PatchSetPublishDetail();
detail.setAccounts(accounts);
detail.setPatchSetInfo(patchSetInfo);
detail.setChange(change);
detail.setDrafts(drafts);
detail.setAllowed(allowed);
detail.setGiven(given);
return detail;
}
private void computeAllowed() {
final Account.Id me = Common.getAccountId();
final Set<AccountGroup.Id> am = Common.getGroupCache().getEffectiveGroups(me);
final ProjectCache.Entry pe =
Common.getProjectCache().get(change.getDest().getParentKey());
computeAllowed(am, pe.getRights());
computeAllowed(am, Common.getProjectCache().getWildcardRights());
}
private void computeAllowed(final Set<AccountGroup.Id> am,
final Collection<ProjectRight> list) {
final GerritConfig cfg = Common.getGerritConfig();
for (final ProjectRight r : list) {
if (!am.contains(r.getAccountGroupId())) {
continue;
}
Set<ApprovalCategoryValue.Id> s = allowed.get(r.getApprovalCategoryId());
if (s == null) {
s = new HashSet<ApprovalCategoryValue.Id>();
allowed.put(r.getApprovalCategoryId(), s);
}
final ApprovalType at = cfg.getApprovalType(r.getApprovalCategoryId());
for (short m = r.getMinValue(); m <= r.getMaxValue(); m++) {
final ApprovalCategoryValue v = at.getValue(m);
if (v != null) {
s.add(v.getId());
}
}
}
}
}

View File

@@ -0,0 +1,128 @@
// Copyright (C) 2009 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.patch;
import com.google.gerrit.client.reviewdb.Account;
import com.google.gerrit.client.reviewdb.AccountExternalId;
import com.google.gerrit.client.reviewdb.Change;
import com.google.gerrit.client.reviewdb.PatchSet;
import com.google.gerrit.client.reviewdb.PatchSetInfo;
import com.google.gerrit.client.reviewdb.Project;
import com.google.gerrit.client.reviewdb.ReviewDb;
import com.google.gerrit.client.reviewdb.UserIdentity;
import com.google.gerrit.server.GerritServer;
import com.google.gwtorm.client.OrmException;
import com.google.gwtorm.client.SchemaFactory;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.spearce.jgit.lib.ObjectId;
import org.spearce.jgit.lib.PersonIdent;
import org.spearce.jgit.lib.Repository;
import org.spearce.jgit.revwalk.RevCommit;
import org.spearce.jgit.revwalk.RevWalk;
import java.io.IOException;
import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set;
/**
* Factory class creating PatchSetInfo from meta-data found in Git repository.
*/
@Singleton
public class PatchSetInfoFactory {
private final GerritServer gs;
private final SchemaFactory<ReviewDb> schemaFactory;
@Inject
public PatchSetInfoFactory(GerritServer gs,
SchemaFactory<ReviewDb> schemaFactory) {
this.gs = gs;
this.schemaFactory = schemaFactory;
}
public PatchSetInfo get(RevCommit src, PatchSet.Id psi)
throws OrmException {
PatchSetInfo info = new PatchSetInfo(psi);
info.setSubject(src.getShortMessage());
info.setMessage(src.getFullMessage());
info.setAuthor(toUserIdentity(src.getAuthorIdent()));
info.setCommitter(toUserIdentity(src.getCommitterIdent()));
return info;
}
public PatchSetInfo get(PatchSet.Id patchSetId)
throws PatchSetInfoNotAvailableException {
ReviewDb db = null;
Repository repo = null;
try {
db = schemaFactory.open();
final PatchSet patchSet = db.patchSets().get(patchSetId);
final Change change = db.changes().get(patchSet.getId().getParentKey());
final Project.NameKey projectKey = change.getDest().getParentKey();
final String projectName = projectKey.get();
repo = gs.openRepository(projectName);
final RevWalk rw = new RevWalk(repo);
final RevCommit src =
rw.parseCommit(ObjectId.fromString(patchSet.getRevision().get()));
return get(src, patchSetId);
} catch (OrmException e) {
throw new PatchSetInfoNotAvailableException(e);
} catch (IOException e) {
throw new PatchSetInfoNotAvailableException(e);
} finally {
if (db != null)
db.close();
if (repo != null)
repo.close();
}
}
private UserIdentity toUserIdentity(final PersonIdent who)
throws OrmException {
final UserIdentity u = new UserIdentity();
u.setName(who.getName());
u.setEmail(who.getEmailAddress());
u.setDate(new Timestamp(who.getWhen().getTime()));
u.setTimeZone(who.getTimeZoneOffset());
if (u.getEmail() != null) {
// If only one account has access to this email address, select it
// as the identity of the user.
//
final Set<Account.Id> a = new HashSet<Account.Id>();
final ReviewDb db = schemaFactory.open();
try {
for (final AccountExternalId e : db.accountExternalIds().byEmailAddress(
u.getEmail())) {
a.add(e.getAccountId());
}
} finally {
db.close();
}
if (a.size() == 1) {
u.setAccount(a.iterator().next());
}
}
return u;
}
}

View File

@@ -0,0 +1,23 @@
// Copyright (C) 2009 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.patch;
public final class PatchSetInfoNotAvailableException extends Exception {
public PatchSetInfoNotAvailableException(Exception cause) {
super(cause);
}
}