Merge "User memoized supplier pattern to reduce resource consumption"

This commit is contained in:
Shawn Pearce 2016-01-01 17:04:35 +00:00 committed by Gerrit Code Review
commit fbb95cb6d2
17 changed files with 418 additions and 181 deletions

View File

@ -106,7 +106,7 @@ public abstract class AbstractSubmit extends AbstractDaemonTest {
public void onEvent(Event event) { public void onEvent(Event event) {
if (event instanceof ChangeMergedEvent) { if (event instanceof ChangeMergedEvent) {
ChangeMergedEvent changeMergedEvent = (ChangeMergedEvent) event; ChangeMergedEvent changeMergedEvent = (ChangeMergedEvent) event;
mergeResults.put(changeMergedEvent.change.number, mergeResults.put(changeMergedEvent.change.get().number,
changeMergedEvent.newRev); changeMergedEvent.newRev);
} }
} }

View File

@ -14,6 +14,10 @@
package com.google.gerrit.common; package com.google.gerrit.common;
import com.google.common.base.Optional;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.base.Throwables;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ThreadFactoryBuilder; import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.gerrit.common.data.LabelType; import com.google.gerrit.common.data.LabelType;
@ -34,8 +38,11 @@ import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.config.AnonymousCowardName; import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.GerritServerConfig; import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.data.AccountAttribute;
import com.google.gerrit.server.data.ApprovalAttribute; import com.google.gerrit.server.data.ApprovalAttribute;
import com.google.gerrit.server.data.ChangeAttribute;
import com.google.gerrit.server.data.PatchSetAttribute; import com.google.gerrit.server.data.PatchSetAttribute;
import com.google.gerrit.server.data.RefUpdateAttribute;
import com.google.gerrit.server.events.ChangeAbandonedEvent; import com.google.gerrit.server.events.ChangeAbandonedEvent;
import com.google.gerrit.server.events.ChangeMergedEvent; import com.google.gerrit.server.events.ChangeMergedEvent;
import com.google.gerrit.server.events.ChangeRestoredEvent; import com.google.gerrit.server.events.ChangeRestoredEvent;
@ -174,46 +181,46 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
private final DynamicSet<EventListener> unrestrictedListeners; private final DynamicSet<EventListener> unrestrictedListeners;
/** Path of the new patchset hook. */ /** Path of the new patchset hook. */
private final Path patchsetCreatedHook; private final Optional<Path> patchsetCreatedHook;
/** Path of the draft published hook. */ /** Path of the draft published hook. */
private final Path draftPublishedHook; private final Optional<Path> draftPublishedHook;
/** Path of the new comments hook. */ /** Path of the new comments hook. */
private final Path commentAddedHook; private final Optional<Path> commentAddedHook;
/** Path of the change merged hook. */ /** Path of the change merged hook. */
private final Path changeMergedHook; private final Optional<Path> changeMergedHook;
/** Path of the merge failed hook. */ /** Path of the merge failed hook. */
private final Path mergeFailedHook; private final Optional<Path> mergeFailedHook;
/** Path of the change abandoned hook. */ /** Path of the change abandoned hook. */
private final Path changeAbandonedHook; private final Optional<Path> changeAbandonedHook;
/** Path of the change restored hook. */ /** Path of the change restored hook. */
private final Path changeRestoredHook; private final Optional<Path> changeRestoredHook;
/** Path of the ref updated hook. */ /** Path of the ref updated hook. */
private final Path refUpdatedHook; private final Optional<Path> refUpdatedHook;
/** Path of the reviewer added hook. */ /** Path of the reviewer added hook. */
private final Path reviewerAddedHook; private final Optional<Path> reviewerAddedHook;
/** Path of the topic changed hook. */ /** Path of the topic changed hook. */
private final Path topicChangedHook; private final Optional<Path> topicChangedHook;
/** Path of the cla signed hook. */ /** Path of the cla signed hook. */
private final Path claSignedHook; private final Optional<Path> claSignedHook;
/** Path of the update hook. */ /** Path of the update hook. */
private final Path refUpdateHook; private final Optional<Path> refUpdateHook;
/** Path of the hashtags changed hook */ /** Path of the hashtags changed hook */
private final Path hashtagsChangedHook; private final Optional<Path> hashtagsChangedHook;
/** Path of the project created hook. */ /** Path of the project created hook. */
private final Path projectCreatedHook; private final Optional<Path> projectCreatedHook;
private final String anonymousCowardName; private final String anonymousCowardName;
@ -297,10 +304,11 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
.build()); .build());
} }
private static Path hook(Config config, Path path, String name) { private static Optional<Path> hook(Config config, Path path, String name) {
String setting = name.replace("-", "") + "hook"; String setting = name.replace("-", "") + "hook";
String value = config.getString("hooks", null, setting); String value = config.getString("hooks", null, setting);
return path.resolve(value != null ? value : name); Path p = path.resolve(value != null ? value : name);
return Files.exists(p) ? Optional.of(p) : Optional.<Path>absent();
} }
@Override @Override
@ -335,16 +343,6 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
} }
} }
private PatchSetAttribute asPatchSetAttribute(Change change,
PatchSet patchSet, ReviewDb db) throws OrmException {
try (Repository repo = repoManager.openRepository(change.getProject());
RevWalk revWalk = new RevWalk(repo)) {
return eventFactory.asPatchSetAttribute(db, revWalk, patchSet);
} catch (IOException e) {
throw new OrmException(e);
}
}
/** /**
* Fire the update hook * Fire the update hook
* *
@ -352,6 +350,9 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
@Override @Override
public HookResult doRefUpdateHook(Project project, String refname, public HookResult doRefUpdateHook(Project project, String refname,
Account uploader, ObjectId oldId, ObjectId newId) { Account uploader, ObjectId oldId, ObjectId newId) {
if (!refUpdateHook.isPresent()) {
return null;
}
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--project", project.getName()); addArg(args, "--project", project.getName());
@ -368,8 +369,13 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
ProjectCreatedEvent event = new ProjectCreatedEvent(); ProjectCreatedEvent event = new ProjectCreatedEvent();
event.projectName = project.get(); event.projectName = project.get();
event.headName = headName; event.headName = headName;
fireEvent(project, event); fireEvent(project, event);
if (!projectCreatedHook.isPresent()) {
return;
}
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--project", project.get()); addArg(args, "--project", project.get());
addArg(args, "--head", headName); addArg(args, "--head", headName);
@ -382,32 +388,42 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
* *
* @param change The change itself. * @param change The change itself.
* @param patchSet The Patchset that was created. * @param patchSet The Patchset that was created.
* @param db Review database.
* @throws OrmException * @throws OrmException
*/ */
@Override @Override
public void doPatchsetCreatedHook(Change change, PatchSet patchSet, public void doPatchsetCreatedHook(Change change,
ReviewDb db) throws OrmException { PatchSet patchSet, ReviewDb db) throws OrmException {
PatchSetCreatedEvent event = new PatchSetCreatedEvent(); PatchSetCreatedEvent event = new PatchSetCreatedEvent();
AccountState uploader = accountCache.get(patchSet.getUploader()); Supplier<AccountState> uploader =
AccountState owner = accountCache.get(change.getOwner()); getAccountSupplier(patchSet.getUploader());
Supplier<AccountState> owner = getAccountSupplier(change.getOwner());
event.change = changeAttributeSupplier(change);
event.patchSet = patchSetAttributeSupplier(change, patchSet);
event.uploader = accountAttributeSupplier(uploader);
event.change = eventFactory.asChangeAttribute(db, change);
event.patchSet = asPatchSetAttribute(change, patchSet, db);
event.uploader = eventFactory.asAccountAttribute(uploader.getAccount());
fireEvent(change, event, db); fireEvent(change, event, db);
if (!patchsetCreatedHook.isPresent()) {
return;
}
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--change", event.change.id);
ChangeAttribute c = event.change.get();
PatchSetAttribute ps = event.patchSet.get();
addArg(args, "--change", c.id);
addArg(args, "--is-draft", String.valueOf(patchSet.isDraft())); addArg(args, "--is-draft", String.valueOf(patchSet.isDraft()));
addArg(args, "--kind", String.valueOf(event.patchSet.kind)); addArg(args, "--kind", String.valueOf(ps.kind));
addArg(args, "--change-url", event.change.url); addArg(args, "--change-url", c.url);
addArg(args, "--change-owner", getDisplayName(owner.getAccount())); addArg(args, "--change-owner", getDisplayName(owner.get().getAccount()));
addArg(args, "--project", event.change.project); addArg(args, "--project", c.project);
addArg(args, "--branch", event.change.branch); addArg(args, "--branch", c.branch);
addArg(args, "--topic", event.change.topic); addArg(args, "--topic", c.topic);
addArg(args, "--uploader", getDisplayName(uploader.getAccount())); addArg(args, "--uploader", getDisplayName(uploader.get().getAccount()));
addArg(args, "--commit", event.patchSet.revision); addArg(args, "--commit", ps.revision);
addArg(args, "--patchset", event.patchSet.number); addArg(args, "--patchset", ps.number);
runHook(change.getProject(), patchsetCreatedHook, args); runHook(change.getProject(), patchsetCreatedHook, args);
} }
@ -416,62 +432,88 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
public void doDraftPublishedHook(Change change, PatchSet patchSet, public void doDraftPublishedHook(Change change, PatchSet patchSet,
ReviewDb db) throws OrmException { ReviewDb db) throws OrmException {
DraftPublishedEvent event = new DraftPublishedEvent(); DraftPublishedEvent event = new DraftPublishedEvent();
AccountState uploader = accountCache.get(patchSet.getUploader()); Supplier<AccountState> uploader =
AccountState owner = accountCache.get(change.getOwner()); getAccountSupplier(patchSet.getUploader());
Supplier<AccountState> owner = getAccountSupplier(change.getOwner());
event.change = changeAttributeSupplier(change);
event.patchSet = patchSetAttributeSupplier(change, patchSet);
event.uploader = accountAttributeSupplier(uploader);
event.change = eventFactory.asChangeAttribute(db, change);
event.patchSet = asPatchSetAttribute(change, patchSet, db);
event.uploader = eventFactory.asAccountAttribute(uploader.getAccount());
fireEvent(change, event, db); fireEvent(change, event, db);
if (!draftPublishedHook.isPresent()) {
return;
}
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--change", event.change.id); ChangeAttribute c = event.change.get();
addArg(args, "--change-url", event.change.url); PatchSetAttribute ps = event.patchSet.get();
addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
addArg(args, "--project", event.change.project); addArg(args, "--change", c.id);
addArg(args, "--branch", event.change.branch); addArg(args, "--change-url", c.url);
addArg(args, "--topic", event.change.topic); addArg(args, "--change-owner", getDisplayName(owner.get().getAccount()));
addArg(args, "--uploader", getDisplayName(uploader.getAccount())); addArg(args, "--project", c.project);
addArg(args, "--commit", event.patchSet.revision); addArg(args, "--branch", c.branch);
addArg(args, "--patchset", event.patchSet.number); addArg(args, "--topic", c.topic);
addArg(args, "--uploader", getDisplayName(uploader.get().getAccount()));
addArg(args, "--commit", ps.revision);
addArg(args, "--patchset", ps.number);
runHook(change.getProject(), draftPublishedHook, args); runHook(change.getProject(), draftPublishedHook, args);
} }
@Override @Override
public void doCommentAddedHook(Change change, Account account, public void doCommentAddedHook(final Change change, Account account,
PatchSet patchSet, String comment, Map<String, Short> approvals, PatchSet patchSet, String comment, final Map<String, Short> approvals,
ReviewDb db) throws OrmException { ReviewDb db) throws OrmException {
CommentAddedEvent event = new CommentAddedEvent(); CommentAddedEvent event = new CommentAddedEvent();
AccountState owner = accountCache.get(change.getOwner()); Supplier<AccountState> owner = getAccountSupplier(change.getOwner());
event.change = eventFactory.asChangeAttribute(db, change); event.change = changeAttributeSupplier(change);
event.author = eventFactory.asAccountAttribute(account); event.author = accountAttributeSupplier(account);
event.patchSet = asPatchSetAttribute(change, patchSet, db); event.patchSet = patchSetAttributeSupplier(change, patchSet);
event.comment = comment; event.comment = comment;
event.approvals = Suppliers.memoize(
LabelTypes labelTypes = projectCache.get(change.getProject()).getLabelTypes(); new Supplier<ApprovalAttribute[]>() {
if (approvals.size() > 0) { @Override
event.approvals = new ApprovalAttribute[approvals.size()]; public ApprovalAttribute[] get() {
int i = 0; LabelTypes labelTypes = projectCache.get(
for (Map.Entry<String, Short> approval : approvals.entrySet()) { change.getProject()).getLabelTypes();
event.approvals[i++] = getApprovalAttribute(labelTypes, approval); if (approvals.size() > 0) {
} ApprovalAttribute[] r = new ApprovalAttribute[approvals.size()];
} int i = 0;
for (Map.Entry<String, Short> approval : approvals.entrySet()) {
r[i++] = getApprovalAttribute(labelTypes, approval);
}
return r;
}
return null;
}
});
fireEvent(change, event, db); fireEvent(change, event, db);
if (!commentAddedHook.isPresent()) {
return;
}
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--change", event.change.id); ChangeAttribute c = event.change.get();
PatchSetAttribute ps = event.patchSet.get();
addArg(args, "--change", c.id);
addArg(args, "--is-draft", patchSet.isDraft() ? "true" : "false"); addArg(args, "--is-draft", patchSet.isDraft() ? "true" : "false");
addArg(args, "--change-url", event.change.url); addArg(args, "--change-url", c.url);
addArg(args, "--change-owner", getDisplayName(owner.getAccount())); addArg(args, "--change-owner", getDisplayName(owner.get().getAccount()));
addArg(args, "--project", event.change.project); addArg(args, "--project", c.project);
addArg(args, "--branch", event.change.branch); addArg(args, "--branch", c.branch);
addArg(args, "--topic", event.change.topic); addArg(args, "--topic", c.topic);
addArg(args, "--author", getDisplayName(account)); addArg(args, "--author", getDisplayName(account));
addArg(args, "--commit", event.patchSet.revision); addArg(args, "--commit", ps.revision);
addArg(args, "--comment", comment == null ? "" : comment); addArg(args, "--comment", comment == null ? "" : comment);
LabelTypes labelTypes = projectCache.get(
change.getProject()).getLabelTypes();
for (Map.Entry<String, Short> approval : approvals.entrySet()) { for (Map.Entry<String, Short> approval : approvals.entrySet()) {
LabelType lt = labelTypes.byLabel(approval.getKey()); LabelType lt = labelTypes.byLabel(approval.getKey());
if (lt != null) { if (lt != null) {
@ -487,23 +529,31 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
PatchSet patchSet, ReviewDb db, String mergeResultRev) PatchSet patchSet, ReviewDb db, String mergeResultRev)
throws OrmException { throws OrmException {
ChangeMergedEvent event = new ChangeMergedEvent(); ChangeMergedEvent event = new ChangeMergedEvent();
AccountState owner = accountCache.get(change.getOwner()); Supplier<AccountState> owner = getAccountSupplier(change.getOwner());
event.change = eventFactory.asChangeAttribute(db, change); event.change = changeAttributeSupplier(change);
event.submitter = eventFactory.asAccountAttribute(account); event.submitter = accountAttributeSupplier(account);
event.patchSet = asPatchSetAttribute(change, patchSet, db); event.patchSet = patchSetAttributeSupplier(change, patchSet);
event.newRev = mergeResultRev; event.newRev = mergeResultRev;
fireEvent(change, event, db); fireEvent(change, event, db);
if (!changeMergedHook.isPresent()) {
return;
}
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--change", event.change.id); ChangeAttribute c = event.change.get();
addArg(args, "--change-url", event.change.url); PatchSetAttribute ps = event.patchSet.get();
addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
addArg(args, "--project", event.change.project); addArg(args, "--change", c.id);
addArg(args, "--branch", event.change.branch); addArg(args, "--change-url", c.url);
addArg(args, "--topic", event.change.topic); addArg(args, "--change-owner", getDisplayName(owner.get().getAccount()));
addArg(args, "--project", c.project);
addArg(args, "--branch", c.branch);
addArg(args, "--topic", c.topic);
addArg(args, "--submitter", getDisplayName(account)); addArg(args, "--submitter", getDisplayName(account));
addArg(args, "--commit", event.patchSet.revision); addArg(args, "--commit", ps.revision);
addArg(args, "--newrev", mergeResultRev); addArg(args, "--newrev", mergeResultRev);
runHook(change.getProject(), changeMergedHook, args); runHook(change.getProject(), changeMergedHook, args);
@ -514,23 +564,31 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
PatchSet patchSet, String reason, PatchSet patchSet, String reason,
ReviewDb db) throws OrmException { ReviewDb db) throws OrmException {
MergeFailedEvent event = new MergeFailedEvent(); MergeFailedEvent event = new MergeFailedEvent();
AccountState owner = accountCache.get(change.getOwner()); Supplier<AccountState> owner = getAccountSupplier(change.getOwner());
event.change = eventFactory.asChangeAttribute(db, change); event.change = changeAttributeSupplier(change);
event.submitter = eventFactory.asAccountAttribute(account); event.submitter = accountAttributeSupplier(account);
event.patchSet = asPatchSetAttribute(change, patchSet, db); event.patchSet = patchSetAttributeSupplier(change, patchSet);
event.reason = reason; event.reason = reason;
fireEvent(change, event, db); fireEvent(change, event, db);
if (!mergeFailedHook.isPresent()) {
return;
}
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--change", event.change.id); ChangeAttribute c = event.change.get();
addArg(args, "--change-url", event.change.url); PatchSetAttribute ps = event.patchSet.get();
addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
addArg(args, "--project", event.change.project); addArg(args, "--change", c.id);
addArg(args, "--branch", event.change.branch); addArg(args, "--change-url", c.url);
addArg(args, "--topic", event.change.topic); addArg(args, "--change-owner", getDisplayName(owner.get().getAccount()));
addArg(args, "--project", c.project);
addArg(args, "--branch", c.branch);
addArg(args, "--topic", c.topic);
addArg(args, "--submitter", getDisplayName(account)); addArg(args, "--submitter", getDisplayName(account));
addArg(args, "--commit", event.patchSet.revision); addArg(args, "--commit", ps.revision);
addArg(args, "--reason", reason == null ? "" : reason); addArg(args, "--reason", reason == null ? "" : reason);
runHook(change.getProject(), mergeFailedHook, args); runHook(change.getProject(), mergeFailedHook, args);
@ -543,21 +601,29 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
ChangeAbandonedEvent event = new ChangeAbandonedEvent(); ChangeAbandonedEvent event = new ChangeAbandonedEvent();
AccountState owner = accountCache.get(change.getOwner()); AccountState owner = accountCache.get(change.getOwner());
event.change = eventFactory.asChangeAttribute(db, change); event.change = changeAttributeSupplier(change);
event.abandoner = eventFactory.asAccountAttribute(account); event.abandoner = accountAttributeSupplier(account);
event.patchSet = asPatchSetAttribute(change, patchSet, db); event.patchSet = patchSetAttributeSupplier(change, patchSet);
event.reason = reason; event.reason = reason;
fireEvent(change, event, db); fireEvent(change, event, db);
if (!changeAbandonedHook.isPresent()) {
return;
}
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--change", event.change.id); ChangeAttribute c = event.change.get();
addArg(args, "--change-url", event.change.url); PatchSetAttribute ps = event.patchSet.get();
addArg(args, "--change", c.id);
addArg(args, "--change-url", c.url);
addArg(args, "--change-owner", getDisplayName(owner.getAccount())); addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
addArg(args, "--project", event.change.project); addArg(args, "--project", c.project);
addArg(args, "--branch", event.change.branch); addArg(args, "--branch", c.branch);
addArg(args, "--topic", event.change.topic); addArg(args, "--topic", c.topic);
addArg(args, "--abandoner", getDisplayName(account)); addArg(args, "--abandoner", getDisplayName(account));
addArg(args, "--commit", event.patchSet.revision); addArg(args, "--commit", ps.revision);
addArg(args, "--reason", reason == null ? "" : reason); addArg(args, "--reason", reason == null ? "" : reason);
runHook(change.getProject(), changeAbandonedHook, args); runHook(change.getProject(), changeAbandonedHook, args);
@ -570,21 +636,29 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
ChangeRestoredEvent event = new ChangeRestoredEvent(); ChangeRestoredEvent event = new ChangeRestoredEvent();
AccountState owner = accountCache.get(change.getOwner()); AccountState owner = accountCache.get(change.getOwner());
event.change = eventFactory.asChangeAttribute(db, change); event.change = changeAttributeSupplier(change);
event.restorer = eventFactory.asAccountAttribute(account); event.restorer = accountAttributeSupplier(account);
event.patchSet = asPatchSetAttribute(change, patchSet, db); event.patchSet = patchSetAttributeSupplier(change, patchSet);
event.reason = reason; event.reason = reason;
fireEvent(change, event, db); fireEvent(change, event, db);
if (!changeRestoredHook.isPresent()) {
return;
}
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--change", event.change.id); ChangeAttribute c = event.change.get();
addArg(args, "--change-url", event.change.url); PatchSetAttribute ps = event.patchSet.get();
addArg(args, "--change", c.id);
addArg(args, "--change-url", c.url);
addArg(args, "--change-owner", getDisplayName(owner.getAccount())); addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
addArg(args, "--project", event.change.project); addArg(args, "--project", c.project);
addArg(args, "--branch", event.change.branch); addArg(args, "--branch", c.branch);
addArg(args, "--topic", event.change.topic); addArg(args, "--topic", c.topic);
addArg(args, "--restorer", getDisplayName(account)); addArg(args, "--restorer", getDisplayName(account));
addArg(args, "--commit", event.patchSet.revision); addArg(args, "--commit", ps.revision);
addArg(args, "--reason", reason == null ? "" : reason); addArg(args, "--reason", reason == null ? "" : reason);
runHook(change.getProject(), changeRestoredHook, args); runHook(change.getProject(), changeRestoredHook, args);
@ -598,21 +672,33 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
} }
@Override @Override
public void doRefUpdatedHook(Branch.NameKey refName, ObjectId oldId, public void doRefUpdatedHook(final Branch.NameKey refName,
ObjectId newId, Account account) { final ObjectId oldId, final ObjectId newId, Account account) {
RefUpdatedEvent event = new RefUpdatedEvent(); RefUpdatedEvent event = new RefUpdatedEvent();
if (account != null) { if (account != null) {
event.submitter = eventFactory.asAccountAttribute(account); event.submitter = accountAttributeSupplier(account);
} }
event.refUpdate = eventFactory.asRefUpdateAttribute(oldId, newId, refName); event.refUpdate = Suppliers.memoize(
new Supplier<RefUpdateAttribute>() {
@Override
public RefUpdateAttribute get() {
return eventFactory.asRefUpdateAttribute(oldId, newId, refName);
}
});
fireEvent(refName, event); fireEvent(refName, event);
if (!refUpdatedHook.isPresent()) {
return;
}
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--oldrev", event.refUpdate.oldRev); RefUpdateAttribute r = event.refUpdate.get();
addArg(args, "--newrev", event.refUpdate.newRev); addArg(args, "--oldrev", r.oldRev);
addArg(args, "--refname", event.refUpdate.refName); addArg(args, "--newrev", r.newRev);
addArg(args, "--project", event.refUpdate.project); addArg(args, "--refname", r.refName);
addArg(args, "--project", r.project);
if (account != null) { if (account != null) {
addArg(args, "--submitter", getDisplayName(account)); addArg(args, "--submitter", getDisplayName(account));
} }
@ -624,19 +710,26 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
public void doReviewerAddedHook(Change change, Account account, public void doReviewerAddedHook(Change change, Account account,
PatchSet patchSet, ReviewDb db) throws OrmException { PatchSet patchSet, ReviewDb db) throws OrmException {
ReviewerAddedEvent event = new ReviewerAddedEvent(); ReviewerAddedEvent event = new ReviewerAddedEvent();
AccountState owner = accountCache.get(change.getOwner()); Supplier<AccountState> owner = getAccountSupplier(change.getOwner());
event.change = changeAttributeSupplier(change);
event.patchSet = null;//patchSetAttributeSupplier(change, patchSet, db);
event.reviewer = null;//accountAttributeSupplier(account);
event.change = eventFactory.asChangeAttribute(db, change);
event.patchSet = asPatchSetAttribute(change, patchSet, db);
event.reviewer = eventFactory.asAccountAttribute(account);
fireEvent(change, event, db); fireEvent(change, event, db);
if (!reviewerAddedHook.isPresent()) {
return;
}
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--change", event.change.id); ChangeAttribute c = event.change.get();
addArg(args, "--change-url", event.change.url);
addArg(args, "--change-owner", getDisplayName(owner.getAccount())); addArg(args, "--change", c.id);
addArg(args, "--project", event.change.project); addArg(args, "--change-url", c.url);
addArg(args, "--branch", event.change.branch); addArg(args, "--change-owner", getDisplayName(owner.get().getAccount()));
addArg(args, "--project", c.project);
addArg(args, "--branch", c.branch);
addArg(args, "--reviewer", getDisplayName(account)); addArg(args, "--reviewer", getDisplayName(account));
runHook(change.getProject(), reviewerAddedHook, args); runHook(change.getProject(), reviewerAddedHook, args);
@ -649,19 +742,26 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
TopicChangedEvent event = new TopicChangedEvent(); TopicChangedEvent event = new TopicChangedEvent();
AccountState owner = accountCache.get(change.getOwner()); AccountState owner = accountCache.get(change.getOwner());
event.change = eventFactory.asChangeAttribute(db, change); event.change = changeAttributeSupplier(change);
event.changer = eventFactory.asAccountAttribute(account); event.changer = accountAttributeSupplier(account);
event.oldTopic = oldTopic; event.oldTopic = oldTopic;
fireEvent(change, event, db); fireEvent(change, event, db);
if (!topicChangedHook.isPresent()) {
return;
}
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--change", event.change.id); ChangeAttribute c = event.change.get();
addArg(args, "--change", c.id);
addArg(args, "--change-owner", getDisplayName(owner.getAccount())); addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
addArg(args, "--project", event.change.project); addArg(args, "--project", c.project);
addArg(args, "--branch", event.change.branch); addArg(args, "--branch", c.branch);
addArg(args, "--changer", getDisplayName(account)); addArg(args, "--changer", getDisplayName(account));
addArg(args, "--old-topic", oldTopic); addArg(args, "--old-topic", oldTopic);
addArg(args, "--new-topic", event.change.topic); addArg(args, "--new-topic", c.topic);
runHook(change.getProject(), topicChangedHook, args); runHook(change.getProject(), topicChangedHook, args);
} }
@ -681,19 +781,25 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
HashtagsChangedEvent event = new HashtagsChangedEvent(); HashtagsChangedEvent event = new HashtagsChangedEvent();
AccountState owner = accountCache.get(change.getOwner()); AccountState owner = accountCache.get(change.getOwner());
event.change = eventFactory.asChangeAttribute(db, change); event.change = changeAttributeSupplier(change);
event.editor = eventFactory.asAccountAttribute(account); event.editor = accountAttributeSupplier(account);
event.hashtags = hashtagArray(hashtags); event.hashtags = hashtagArray(hashtags);
event.added = hashtagArray(added); event.added = hashtagArray(added);
event.removed = hashtagArray(removed); event.removed = hashtagArray(removed);
fireEvent(change, event, db); fireEvent(change, event, db);
if (!hashtagsChangedHook.isPresent()) {
return;
}
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--change", event.change.id); ChangeAttribute c = event.change.get();
addArg(args, "--change", c.id);
addArg(args, "--change-owner", getDisplayName(owner.getAccount())); addArg(args, "--change-owner", getDisplayName(owner.getAccount()));
addArg(args, "--project", event.change.project); addArg(args, "--project", c.project);
addArg(args, "--branch", event.change.branch); addArg(args, "--branch", c.branch);
addArg(args, "--editor", getDisplayName(account)); addArg(args, "--editor", getDisplayName(account));
if (hashtags != null) { if (hashtags != null) {
for (String hashtag : hashtags) { for (String hashtag : hashtags) {
@ -715,6 +821,10 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
@Override @Override
public void doClaSignupHook(Account account, String claName) { public void doClaSignupHook(Account account, String claName) {
if (!claSignedHook.isPresent()) {
return;
}
if (account != null) { if (account != null) {
List<String> args = new ArrayList<>(); List<String> args = new ArrayList<>();
addArg(args, "--submitter", getDisplayName(account)); addArg(args, "--submitter", getDisplayName(account));
@ -736,6 +846,67 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
fireEvent(branchName, event); fireEvent(branchName, event);
} }
private Supplier<AccountState> getAccountSupplier(
final Account.Id account) {
return Suppliers.memoize(
new Supplier<AccountState>() {
@Override
public AccountState get() {
return accountCache.get(account);
}
});
}
private Supplier<AccountAttribute> accountAttributeSupplier(
final Supplier<AccountState> s) {
return Suppliers.memoize(
new Supplier<AccountAttribute>() {
@Override
public AccountAttribute get() {
return eventFactory.asAccountAttribute(s.get().getAccount());
}
});
}
private Supplier<AccountAttribute> accountAttributeSupplier(
final Account account) {
return Suppliers.memoize(
new Supplier<AccountAttribute>() {
@Override
public AccountAttribute get() {
return eventFactory.asAccountAttribute(account);
}
});
}
private Supplier<PatchSetAttribute> patchSetAttributeSupplier(
final Change change, final PatchSet patchSet) {
return Suppliers.memoize(
new Supplier<PatchSetAttribute>() {
@Override
public PatchSetAttribute get() {
try (Repository repo
= repoManager.openRepository(change.getProject());
RevWalk revWalk = new RevWalk(repo)) {
return eventFactory.asPatchSetAttribute(revWalk, patchSet);
} catch (IOException e) {
throw Throwables.propagate(e);
}
}
});
}
private Supplier<ChangeAttribute> changeAttributeSupplier(
final Change change) {
return Suppliers.memoize(
new Supplier<ChangeAttribute>() {
@Override
public ChangeAttribute get() {
return eventFactory.asChangeAttribute(change);
}
});
}
private void fireEventForUnrestrictedListeners(com.google.gerrit.server.events.Event event) { private void fireEventForUnrestrictedListeners(com.google.gerrit.server.events.Event event) {
for (EventListener listener : unrestrictedListeners) { for (EventListener listener : unrestrictedListeners) {
listener.onEvent(event); listener.onEvent(event);
@ -851,27 +1022,27 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
* @param hook the hook to execute. * @param hook the hook to execute.
* @param args Arguments to use to run the hook. * @param args Arguments to use to run the hook.
*/ */
private synchronized void runHook(Project.NameKey project, Path hook, private synchronized void runHook(Project.NameKey project, Optional<Path> hook,
List<String> args) { List<String> args) {
if (project != null && Files.exists(hook)) { if (project != null && hook.isPresent()) {
hookQueue.execute(new AsyncHookTask(project, hook, args)); hookQueue.execute(new AsyncHookTask(project, hook.get(), args));
} }
} }
private synchronized void runHook(Path hook, List<String> args) { private synchronized void runHook(Optional<Path> hook, List<String> args) {
if (Files.exists(hook)) { if (hook.isPresent()) {
hookQueue.execute(new AsyncHookTask(null, hook, args)); hookQueue.execute(new AsyncHookTask(null, hook.get(), args));
} }
} }
private HookResult runSyncHook(Project.NameKey project, private HookResult runSyncHook(Project.NameKey project,
Path hook, List<String> args) { Optional<Path> hook, List<String> args) {
if (!Files.exists(hook)) { if (!hook.isPresent()) {
return null; return null;
} }
SyncHookTask syncHook = new SyncHookTask(project, hook, args); SyncHookTask syncHook = new SyncHookTask(project, hook.get(), args);
FutureTask<HookResult> task = new FutureTask<>(syncHook); FutureTask<HookResult> task = new FutureTask<>(syncHook);
syncHookThreadPool.execute(task); syncHookThreadPool.execute(task);
@ -881,10 +1052,10 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
try { try {
return task.get(syncHookTimeout, TimeUnit.SECONDS); return task.get(syncHookTimeout, TimeUnit.SECONDS);
} catch (TimeoutException e) { } catch (TimeoutException e) {
message = "Synchronous hook timed out " + hook.toAbsolutePath(); message = "Synchronous hook timed out " + hook.get().toAbsolutePath();
log.error(message); log.error(message);
} catch (Exception e) { } catch (Exception e) {
message = "Error running hook " + hook.toAbsolutePath(); message = "Error running hook " + hook.get().toAbsolutePath();
log.error(message, e); log.error(message, e);
} }

View File

@ -14,10 +14,11 @@
package com.google.gerrit.server.events; package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.server.data.AccountAttribute; import com.google.gerrit.server.data.AccountAttribute;
public class ChangeAbandonedEvent extends PatchSetEvent { public class ChangeAbandonedEvent extends PatchSetEvent {
public AccountAttribute abandoner; public Supplier<AccountAttribute> abandoner;
public String reason; public String reason;
public ChangeAbandonedEvent() { public ChangeAbandonedEvent() {

View File

@ -14,13 +14,14 @@
package com.google.gerrit.server.events; package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.client.RefNames; import com.google.gerrit.reviewdb.client.RefNames;
import com.google.gerrit.server.data.ChangeAttribute; import com.google.gerrit.server.data.ChangeAttribute;
public abstract class ChangeEvent extends RefEvent { public abstract class ChangeEvent extends RefEvent {
public ChangeAttribute change; public Supplier<ChangeAttribute> change;
protected ChangeEvent(String type) { protected ChangeEvent(String type) {
super(type); super(type);
@ -28,15 +29,15 @@ public abstract class ChangeEvent extends RefEvent {
@Override @Override
public Project.NameKey getProjectNameKey() { public Project.NameKey getProjectNameKey() {
return new Project.NameKey(change.project); return new Project.NameKey(change.get().project);
} }
@Override @Override
public String getRefName() { public String getRefName() {
return RefNames.fullName(change.branch); return RefNames.fullName(change.get().branch);
} }
public Change.Key getChangeKey() { public Change.Key getChangeKey() {
return new Change.Key(change.id); return new Change.Key(change.get().id);
} }
} }

View File

@ -14,10 +14,11 @@
package com.google.gerrit.server.events; package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.server.data.AccountAttribute; import com.google.gerrit.server.data.AccountAttribute;
public class ChangeMergedEvent extends PatchSetEvent { public class ChangeMergedEvent extends PatchSetEvent {
public AccountAttribute submitter; public Supplier<AccountAttribute> submitter;
public String newRev; public String newRev;
public ChangeMergedEvent() { public ChangeMergedEvent() {

View File

@ -14,10 +14,11 @@
package com.google.gerrit.server.events; package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.server.data.AccountAttribute; import com.google.gerrit.server.data.AccountAttribute;
public class ChangeRestoredEvent extends PatchSetEvent { public class ChangeRestoredEvent extends PatchSetEvent {
public AccountAttribute restorer; public Supplier<AccountAttribute> restorer;
public String reason; public String reason;
public ChangeRestoredEvent () { public ChangeRestoredEvent () {

View File

@ -14,12 +14,13 @@
package com.google.gerrit.server.events; package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.server.data.AccountAttribute; import com.google.gerrit.server.data.AccountAttribute;
import com.google.gerrit.server.data.ApprovalAttribute; import com.google.gerrit.server.data.ApprovalAttribute;
public class CommentAddedEvent extends PatchSetEvent { public class CommentAddedEvent extends PatchSetEvent {
public AccountAttribute author; public Supplier<AccountAttribute> author;
public ApprovalAttribute[] approvals; public Supplier<ApprovalAttribute[]> approvals;
public String comment; public String comment;
public CommentAddedEvent() { public CommentAddedEvent() {

View File

@ -14,10 +14,11 @@
package com.google.gerrit.server.events; package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.server.data.AccountAttribute; import com.google.gerrit.server.data.AccountAttribute;
public class DraftPublishedEvent extends PatchSetEvent { public class DraftPublishedEvent extends PatchSetEvent {
public AccountAttribute uploader; public Supplier<AccountAttribute> uploader;
public DraftPublishedEvent() { public DraftPublishedEvent() {
super("draft-published"); super("draft-published");

View File

@ -61,6 +61,7 @@ import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
import com.google.gerrit.server.query.change.ChangeData; import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.InternalChangeQuery; import com.google.gerrit.server.query.change.InternalChangeQuery;
import com.google.gwtorm.server.OrmException; import com.google.gwtorm.server.OrmException;
import com.google.gwtorm.server.SchemaFactory;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
import com.google.inject.Singleton; import com.google.inject.Singleton;
@ -92,6 +93,7 @@ public class EventFactory {
private final ApprovalsUtil approvalsUtil; private final ApprovalsUtil approvalsUtil;
private final ChangeKindCache changeKindCache; private final ChangeKindCache changeKindCache;
private final Provider<InternalChangeQuery> queryProvider; private final Provider<InternalChangeQuery> queryProvider;
private final SchemaFactory<ReviewDb> schema;
@Inject @Inject
EventFactory(AccountCache accountCache, EventFactory(AccountCache accountCache,
@ -102,7 +104,8 @@ public class EventFactory {
ChangeData.Factory changeDataFactory, ChangeData.Factory changeDataFactory,
ApprovalsUtil approvalsUtil, ApprovalsUtil approvalsUtil,
ChangeKindCache changeKindCache, ChangeKindCache changeKindCache,
Provider<InternalChangeQuery> queryProvider) { Provider<InternalChangeQuery> queryProvider,
SchemaFactory<ReviewDb> schema) {
this.accountCache = accountCache; this.accountCache = accountCache;
this.urlProvider = urlProvider; this.urlProvider = urlProvider;
this.patchListCache = patchListCache; this.patchListCache = patchListCache;
@ -112,6 +115,7 @@ public class EventFactory {
this.approvalsUtil = approvalsUtil; this.approvalsUtil = approvalsUtil;
this.changeKindCache = changeKindCache; this.changeKindCache = changeKindCache;
this.queryProvider = queryProvider; this.queryProvider = queryProvider;
this.schema = schema;
} }
/** /**
@ -121,6 +125,23 @@ public class EventFactory {
* @param change * @param change
* @return object suitable for serialization to JSON * @return object suitable for serialization to JSON
*/ */
public ChangeAttribute asChangeAttribute(Change change) {
try (ReviewDb db = schema.open()) {
return asChangeAttribute(db, change);
} catch (OrmException e) {
log.error("Cannot open database connection", e);
return new ChangeAttribute();
}
}
/**
* Create a ChangeAttribute for the given change suitable for serialization to
* JSON.
*
* @param db Review database
* @param change
* @return object suitable for serialization to JSON
*/
public ChangeAttribute asChangeAttribute(ReviewDb db, Change change) { public ChangeAttribute asChangeAttribute(ReviewDb db, Change change) {
ChangeAttribute a = new ChangeAttribute(); ChangeAttribute a = new ChangeAttribute();
a.project = change.getProject().get(); a.project = change.getProject().get();
@ -429,6 +450,19 @@ public class EventFactory {
* @param patchSet * @param patchSet
* @return object suitable for serialization to JSON * @return object suitable for serialization to JSON
*/ */
public PatchSetAttribute asPatchSetAttribute(RevWalk revWalk,
PatchSet patchSet) {
return asPatchSetAttribute(revWalk, patchSet);
}
/**
* Create a PatchSetAttribute for the given patchset suitable for
* serialization to JSON.
*
* @param db Review database
* @param patchSet
* @return object suitable for serialization to JSON
*/
public PatchSetAttribute asPatchSetAttribute(ReviewDb db, RevWalk revWalk, public PatchSetAttribute asPatchSetAttribute(ReviewDb db, RevWalk revWalk,
PatchSet patchSet) { PatchSet patchSet) {
PatchSetAttribute p = new PatchSetAttribute(); PatchSetAttribute p = new PatchSetAttribute();

View File

@ -14,10 +14,11 @@
package com.google.gerrit.server.events; package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.server.data.AccountAttribute; import com.google.gerrit.server.data.AccountAttribute;
public class HashtagsChangedEvent extends ChangeEvent { public class HashtagsChangedEvent extends ChangeEvent {
public AccountAttribute editor; public Supplier<AccountAttribute> editor;
public String[] added; public String[] added;
public String[] removed; public String[] removed;
public String[] hashtags; public String[] hashtags;

View File

@ -14,10 +14,11 @@
package com.google.gerrit.server.events; package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.server.data.AccountAttribute; import com.google.gerrit.server.data.AccountAttribute;
public class MergeFailedEvent extends PatchSetEvent { public class MergeFailedEvent extends PatchSetEvent {
public AccountAttribute submitter; public Supplier<AccountAttribute> submitter;
public String reason; public String reason;
public MergeFailedEvent() { public MergeFailedEvent() {

View File

@ -14,10 +14,11 @@
package com.google.gerrit.server.events; package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.server.data.AccountAttribute; import com.google.gerrit.server.data.AccountAttribute;
public class PatchSetCreatedEvent extends PatchSetEvent { public class PatchSetCreatedEvent extends PatchSetEvent {
public AccountAttribute uploader; public Supplier<AccountAttribute> uploader;
public PatchSetCreatedEvent() { public PatchSetCreatedEvent() {
super("patchset-created"); super("patchset-created");

View File

@ -14,10 +14,11 @@
package com.google.gerrit.server.events; package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.server.data.PatchSetAttribute; import com.google.gerrit.server.data.PatchSetAttribute;
public class PatchSetEvent extends ChangeEvent { public class PatchSetEvent extends ChangeEvent {
public PatchSetAttribute patchSet; public Supplier<PatchSetAttribute> patchSet;
protected PatchSetEvent(String type) { protected PatchSetEvent(String type) {
super(type); super(type);

View File

@ -14,13 +14,14 @@
package com.google.gerrit.server.events; package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.reviewdb.client.Project; import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.data.AccountAttribute; import com.google.gerrit.server.data.AccountAttribute;
import com.google.gerrit.server.data.RefUpdateAttribute; import com.google.gerrit.server.data.RefUpdateAttribute;
public class RefUpdatedEvent extends RefEvent { public class RefUpdatedEvent extends RefEvent {
public AccountAttribute submitter; public Supplier<AccountAttribute> submitter;
public RefUpdateAttribute refUpdate; public Supplier<RefUpdateAttribute> refUpdate;
public RefUpdatedEvent() { public RefUpdatedEvent() {
super("ref-updated"); super("ref-updated");
@ -28,11 +29,11 @@ public class RefUpdatedEvent extends RefEvent {
@Override @Override
public Project.NameKey getProjectNameKey() { public Project.NameKey getProjectNameKey() {
return new Project.NameKey(refUpdate.project); return new Project.NameKey(refUpdate.get().project);
} }
@Override @Override
public String getRefName() { public String getRefName() {
return refUpdate.refName; return refUpdate.get().refName;
} }
} }

View File

@ -14,10 +14,11 @@
package com.google.gerrit.server.events; package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.server.data.AccountAttribute; import com.google.gerrit.server.data.AccountAttribute;
public class ReviewerAddedEvent extends PatchSetEvent { public class ReviewerAddedEvent extends PatchSetEvent {
public AccountAttribute reviewer; public Supplier<AccountAttribute> reviewer;
public ReviewerAddedEvent() { public ReviewerAddedEvent() {
super("reviewer-added"); super("reviewer-added");

View File

@ -14,10 +14,11 @@
package com.google.gerrit.server.events; package com.google.gerrit.server.events;
import com.google.common.base.Supplier;
import com.google.gerrit.server.data.AccountAttribute; import com.google.gerrit.server.data.AccountAttribute;
public class TopicChangedEvent extends ChangeEvent { public class TopicChangedEvent extends ChangeEvent {
public AccountAttribute changer; public Supplier<AccountAttribute> changer;
public String oldTopic; public String oldTopic;
public TopicChangedEvent() { public TopicChangedEvent() {

View File

@ -17,6 +17,7 @@ package com.google.gerrit.sshd.commands;
import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER; import static com.google.gerrit.sshd.CommandMetaData.Mode.MASTER;
import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.base.Supplier;
import com.google.gerrit.common.EventListener; import com.google.gerrit.common.EventListener;
import com.google.gerrit.common.EventSource; import com.google.gerrit.common.EventSource;
import com.google.gerrit.common.data.GlobalCapability; import com.google.gerrit.common.data.GlobalCapability;
@ -30,12 +31,17 @@ import com.google.gerrit.sshd.BaseCommand;
import com.google.gerrit.sshd.CommandMetaData; import com.google.gerrit.sshd.CommandMetaData;
import com.google.gerrit.sshd.StreamCommandExecutor; import com.google.gerrit.sshd.StreamCommandExecutor;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.inject.Inject; import com.google.inject.Inject;
import org.apache.sshd.server.Environment; import org.apache.sshd.server.Environment;
import java.io.IOException; import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.reflect.Type;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
@ -63,7 +69,7 @@ final class StreamEvents extends BaseCommand {
private final LinkedBlockingQueue<Event> queue = private final LinkedBlockingQueue<Event> queue =
new LinkedBlockingQueue<>(MAX_EVENTS); new LinkedBlockingQueue<>(MAX_EVENTS);
private final Gson gson = new Gson(); private Gson gson;
/** Special event to notify clients they missed other events. */ /** Special event to notify clients they missed other events. */
private static final class DroppedOutputEvent extends Event { private static final class DroppedOutputEvent extends Event {
@ -139,6 +145,10 @@ final class StreamEvents extends BaseCommand {
stdout = toPrintWriter(out); stdout = toPrintWriter(out);
source.addEventListener(listener, currentUser); source.addEventListener(listener, currentUser);
gson = new GsonBuilder()
.registerTypeAdapter(Supplier.class, new SupplierSerializer())
.create();
} }
@Override @Override
@ -247,4 +257,13 @@ final class StreamEvents extends BaseCommand {
stdout.flush(); stdout.flush();
} }
} }
private static class SupplierSerializer
implements JsonSerializer<Supplier<?>> {
@Override
public JsonElement serialize(Supplier<?> src, Type typeOfSrc,
JsonSerializationContext context) {
return context.serialize(src.get());
}
}
} }