Set logging tag with plugin name on invocation of extension point
With this logging tag one can easily see in the log file which logs have
been triggered by the plugin. For traces this is interesting because
then for actions such as loading files, doing index queries etc. one can
see if they have been triggered by a plugin. E.g. if there is an
extensive number of index queries that are triggered by a plugin we want
to see this in the trace.
Such logging tags are mostly useful for extension points that are likely
to have complex or expensive implementations. We may not want to set
such a logging tag for extension points which only have trivial
implementations.
Setting the logging tag with the plugin name when an extension point is
invoked is done by opening a trace context. To invoke extension points
with such a trace context they should be invoked through a plugin
context. The plugin context can be directly injected. Instead of
injecting DynamicItem/DynamicSet/DynamicMap you can now inject
PluginItemContext/PluginSetContext/PluginMapContext.
The plugin context classes offer methods to invoke the extension
points that automatically set the trace context. In addition they
provide functionality for catching and logging exceptions from plugins.
This makes the logging and exception handling for plugin invocations
more consistent across the code base and removes the need to have code
for this in multiple places.
Since exception handling with plugin contexts is easy now more plugin
invocations handle exceptions now which makes Gerrit more resilient
against plugin failures.
This change adapts calls to most important extensions points, such as
validators and listeners.
Change-Id: Iab41d0059049f06ca41b697e93aa6a1f9668de5b
Signed-off-by: Edwin Kempin <ekempin@google.com>
diff --git a/java/com/google/gerrit/server/StartupChecks.java b/java/com/google/gerrit/server/StartupChecks.java
index 9df2604..5ece91d 100644
--- a/java/com/google/gerrit/server/StartupChecks.java
+++ b/java/com/google/gerrit/server/StartupChecks.java
@@ -19,6 +19,7 @@
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.server.account.UniversalGroupBackend;
import com.google.gerrit.server.group.SystemGroupBackend;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -34,18 +35,16 @@
}
}
- private final DynamicSet<StartupCheck> startupChecks;
+ private final PluginSetContext<StartupCheck> startupChecks;
@Inject
- StartupChecks(DynamicSet<StartupCheck> startupChecks) {
+ StartupChecks(PluginSetContext<StartupCheck> startupChecks) {
this.startupChecks = startupChecks;
}
@Override
public void start() throws StartupException {
- for (StartupCheck startupCheck : startupChecks) {
- startupCheck.check();
- }
+ startupChecks.runEach(c -> c.check(), StartupException.class);
}
@Override
diff --git a/java/com/google/gerrit/server/account/SetInactiveFlag.java b/java/com/google/gerrit/server/account/SetInactiveFlag.java
index af68d05..a683849 100644
--- a/java/com/google/gerrit/server/account/SetInactiveFlag.java
+++ b/java/com/google/gerrit/server/account/SetInactiveFlag.java
@@ -14,13 +14,13 @@
package com.google.gerrit.server.account;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.ServerInitiated;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.validators.AccountActivationValidationListener;
import com.google.gerrit.server.validators.ValidationException;
import com.google.gwtorm.server.OrmException;
@@ -35,13 +35,13 @@
@Singleton
public class SetInactiveFlag {
- private final DynamicSet<AccountActivationValidationListener>
+ private final PluginSetContext<AccountActivationValidationListener>
accountActivationValidationListeners;
private final Provider<AccountsUpdate> accountsUpdateProvider;
@Inject
SetInactiveFlag(
- DynamicSet<AccountActivationValidationListener> accountActivationValidationListeners,
+ PluginSetContext<AccountActivationValidationListener> accountActivationValidationListeners,
@ServerInitiated Provider<AccountsUpdate> accountsUpdateProvider) {
this.accountActivationValidationListeners = accountActivationValidationListeners;
this.accountsUpdateProvider = accountsUpdateProvider;
@@ -60,13 +60,12 @@
if (!a.getAccount().isActive()) {
alreadyInactive.set(true);
} else {
- for (AccountActivationValidationListener l : accountActivationValidationListeners) {
- try {
- l.validateDeactivation(a);
- } catch (ValidationException e) {
- exception.set(Optional.of(new ResourceConflictException(e.getMessage(), e)));
- return;
- }
+ try {
+ accountActivationValidationListeners.runEach(
+ l -> l.validateDeactivation(a), ValidationException.class);
+ } catch (ValidationException e) {
+ exception.set(Optional.of(new ResourceConflictException(e.getMessage(), e)));
+ return;
}
u.setActive(false);
}
@@ -94,13 +93,12 @@
if (a.getAccount().isActive()) {
alreadyActive.set(true);
} else {
- for (AccountActivationValidationListener l : accountActivationValidationListeners) {
- try {
- l.validateActivation(a);
- } catch (ValidationException e) {
- exception.set(Optional.of(new ResourceConflictException(e.getMessage(), e)));
- return;
- }
+ try {
+ accountActivationValidationListeners.runEach(
+ l -> l.validateActivation(a), ValidationException.class);
+ } catch (ValidationException e) {
+ exception.set(Optional.of(new ResourceConflictException(e.getMessage(), e)));
+ return;
}
u.setActive(true);
}
diff --git a/java/com/google/gerrit/server/account/UniversalGroupBackend.java b/java/com/google/gerrit/server/account/UniversalGroupBackend.java
index 22e9dbd..e7b3c91 100644
--- a/java/com/google/gerrit/server/account/UniversalGroupBackend.java
+++ b/java/com/google/gerrit/server/account/UniversalGroupBackend.java
@@ -26,12 +26,13 @@
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.GroupDescription;
import com.google.gerrit.common.data.GroupReference;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.StartupCheck;
import com.google.gerrit.server.StartupException;
import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.plugincontext.PluginSetEntryContext;
import com.google.gerrit.server.project.ProjectState;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -48,19 +49,19 @@
public class UniversalGroupBackend implements GroupBackend {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<GroupBackend> backends;
+ private final PluginSetContext<GroupBackend> backends;
@Inject
- UniversalGroupBackend(DynamicSet<GroupBackend> backends) {
+ UniversalGroupBackend(PluginSetContext<GroupBackend> backends) {
this.backends = backends;
}
@Nullable
private GroupBackend backend(AccountGroup.UUID uuid) {
if (uuid != null) {
- for (GroupBackend g : backends) {
- if (g.handles(uuid)) {
- return g;
+ for (PluginSetEntryContext<GroupBackend> c : backends) {
+ if (c.call(b -> b.handles(uuid))) {
+ return c.get();
}
}
}
@@ -88,9 +89,7 @@
@Override
public Collection<GroupReference> suggest(String name, ProjectState project) {
Set<GroupReference> groups = Sets.newTreeSet(GROUP_REF_NAME_COMPARATOR);
- for (GroupBackend g : backends) {
- groups.addAll(g.suggest(name, project));
- }
+ backends.runEach(g -> groups.addAll(g.suggest(name, project)));
return groups;
}
@@ -104,9 +103,7 @@
private UniversalGroupMembership(IdentifiedUser user) {
ImmutableMap.Builder<GroupBackend, GroupMembership> builder = ImmutableMap.builder();
- for (GroupBackend g : backends) {
- builder.put(g, g.membershipsOf(user));
- }
+ backends.runEach(g -> builder.put(g, g.membershipsOf(user)));
this.memberships = builder.build();
}
@@ -200,9 +197,9 @@
@Override
public boolean isVisibleToAll(AccountGroup.UUID uuid) {
- for (GroupBackend g : backends) {
- if (g.handles(uuid)) {
- return g.isVisibleToAll(uuid);
+ for (PluginSetEntryContext<GroupBackend> c : backends) {
+ if (c.call(b -> b.handles(uuid))) {
+ return c.call(b -> b.isVisibleToAll(uuid));
}
}
return false;
diff --git a/java/com/google/gerrit/server/audit/AuditService.java b/java/com/google/gerrit/server/audit/AuditService.java
index 2055e33..cbca65b 100644
--- a/java/com/google/gerrit/server/audit/AuditService.java
+++ b/java/com/google/gerrit/server/audit/AuditService.java
@@ -15,37 +15,32 @@
package com.google.gerrit.server.audit;
import com.google.common.collect.ImmutableSet;
-import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.audit.group.GroupAuditListener;
import com.google.gerrit.server.audit.group.GroupMemberAuditEvent;
import com.google.gerrit.server.audit.group.GroupSubgroupAuditEvent;
import com.google.gerrit.server.group.GroupAuditService;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.sql.Timestamp;
@Singleton
public class AuditService implements GroupAuditService {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
- private final DynamicSet<AuditListener> auditListeners;
- private final DynamicSet<GroupAuditListener> groupAuditListeners;
+ private final PluginSetContext<AuditListener> auditListeners;
+ private final PluginSetContext<GroupAuditListener> groupAuditListeners;
@Inject
public AuditService(
- DynamicSet<AuditListener> auditListeners,
- DynamicSet<GroupAuditListener> groupAuditListeners) {
+ PluginSetContext<AuditListener> auditListeners,
+ PluginSetContext<GroupAuditListener> groupAuditListeners) {
this.auditListeners = auditListeners;
this.groupAuditListeners = groupAuditListeners;
}
public void dispatch(AuditEvent action) {
- for (AuditListener auditListener : auditListeners) {
- auditListener.onAuditableAction(action);
- }
+ auditListeners.runEach(l -> l.onAuditableAction(action));
}
@Override
@@ -54,15 +49,9 @@
AccountGroup.UUID updatedGroup,
ImmutableSet<Account.Id> addedMembers,
Timestamp addedOn) {
- for (GroupAuditListener auditListener : groupAuditListeners) {
- try {
- GroupMemberAuditEvent event =
- GroupMemberAuditEvent.create(actor, updatedGroup, addedMembers, addedOn);
- auditListener.onAddMembers(event);
- } catch (RuntimeException e) {
- logger.atSevere().withCause(e).log("failed to log add accounts to group event");
- }
- }
+ GroupMemberAuditEvent event =
+ GroupMemberAuditEvent.create(actor, updatedGroup, addedMembers, addedOn);
+ groupAuditListeners.runEach(l -> l.onAddMembers(event));
}
@Override
@@ -71,15 +60,9 @@
AccountGroup.UUID updatedGroup,
ImmutableSet<Account.Id> deletedMembers,
Timestamp deletedOn) {
- for (GroupAuditListener auditListener : groupAuditListeners) {
- try {
- GroupMemberAuditEvent event =
- GroupMemberAuditEvent.create(actor, updatedGroup, deletedMembers, deletedOn);
- auditListener.onDeleteMembers(event);
- } catch (RuntimeException e) {
- logger.atSevere().withCause(e).log("failed to log delete accounts from group event");
- }
- }
+ GroupMemberAuditEvent event =
+ GroupMemberAuditEvent.create(actor, updatedGroup, deletedMembers, deletedOn);
+ groupAuditListeners.runEach(l -> l.onDeleteMembers(event));
}
@Override
@@ -88,15 +71,9 @@
AccountGroup.UUID updatedGroup,
ImmutableSet<AccountGroup.UUID> addedSubgroups,
Timestamp addedOn) {
- for (GroupAuditListener auditListener : groupAuditListeners) {
- try {
- GroupSubgroupAuditEvent event =
- GroupSubgroupAuditEvent.create(actor, updatedGroup, addedSubgroups, addedOn);
- auditListener.onAddSubgroups(event);
- } catch (RuntimeException e) {
- logger.atSevere().withCause(e).log("failed to log add groups to group event");
- }
- }
+ GroupSubgroupAuditEvent event =
+ GroupSubgroupAuditEvent.create(actor, updatedGroup, addedSubgroups, addedOn);
+ groupAuditListeners.runEach(l -> l.onAddSubgroups(event));
}
@Override
@@ -105,14 +82,8 @@
AccountGroup.UUID updatedGroup,
ImmutableSet<AccountGroup.UUID> deletedSubgroups,
Timestamp deletedOn) {
- for (GroupAuditListener auditListener : groupAuditListeners) {
- try {
- GroupSubgroupAuditEvent event =
- GroupSubgroupAuditEvent.create(actor, updatedGroup, deletedSubgroups, deletedOn);
- auditListener.onDeleteSubgroups(event);
- } catch (RuntimeException e) {
- logger.atSevere().withCause(e).log("failed to log delete groups from group event");
- }
- }
+ GroupSubgroupAuditEvent event =
+ GroupSubgroupAuditEvent.create(actor, updatedGroup, deletedSubgroups, deletedOn);
+ groupAuditListeners.runEach(l -> l.onDeleteSubgroups(event));
}
}
diff --git a/java/com/google/gerrit/server/audit/BUILD b/java/com/google/gerrit/server/audit/BUILD
index 6982766..1756713 100644
--- a/java/com/google/gerrit/server/audit/BUILD
+++ b/java/com/google/gerrit/server/audit/BUILD
@@ -17,6 +17,7 @@
"//java/com/google/gerrit/reviewdb:server",
"//java/com/google/gerrit/server",
"//java/com/google/gerrit/server/ioutil",
+ "//java/com/google/gerrit/server/logging",
"//java/com/google/gerrit/server/util/time",
"//java/com/google/gerrit/util/cli",
"//java/com/google/gerrit/util/ssl",
diff --git a/java/com/google/gerrit/server/change/ConsistencyChecker.java b/java/com/google/gerrit/server/change/ConsistencyChecker.java
index 0bda066..238598c 100644
--- a/java/com/google/gerrit/server/change/ConsistencyChecker.java
+++ b/java/com/google/gerrit/server/change/ConsistencyChecker.java
@@ -33,7 +33,6 @@
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.common.ProblemInfo;
import com.google.gerrit.extensions.common.ProblemInfo.Status;
-import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
@@ -50,6 +49,7 @@
import com.google.gerrit.server.notedb.PatchSetState;
import com.google.gerrit.server.patch.PatchSetInfoFactory;
import com.google.gerrit.server.patch.PatchSetInfoNotAvailableException;
+import com.google.gerrit.server.plugincontext.PluginItemContext;
import com.google.gerrit.server.update.BatchUpdate;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.BatchUpdateReviewDb;
@@ -107,7 +107,7 @@
private final ChangeNotes.Factory notesFactory;
private final Accounts accounts;
- private final DynamicItem<AccountPatchReviewStore> accountPatchReviewStore;
+ private final PluginItemContext<AccountPatchReviewStore> accountPatchReviewStore;
private final GitRepositoryManager repoManager;
private final PatchSetInfoFactory patchSetInfoFactory;
private final PatchSetInserter.Factory patchSetInserterFactory;
@@ -136,7 +136,7 @@
@GerritPersonIdent Provider<PersonIdent> serverIdent,
ChangeNotes.Factory notesFactory,
Accounts accounts,
- DynamicItem<AccountPatchReviewStore> accountPatchReviewStore,
+ PluginItemContext<AccountPatchReviewStore> accountPatchReviewStore,
GitRepositoryManager repoManager,
PatchSetInfoFactory patchSetInfoFactory,
PatchSetInserter.Factory patchSetInserterFactory,
@@ -668,7 +668,7 @@
throws OrmException, PatchSetInfoNotAvailableException {
// Delete dangling key references.
ReviewDb db = BatchUpdateReviewDb.unwrap(ctx.getDb());
- accountPatchReviewStore.get().clearReviewed(psId);
+ accountPatchReviewStore.run(s -> s.clearReviewed(psId), OrmException.class);
db.changeMessages().delete(db.changeMessages().byChange(psId.getParentKey()));
db.patchSetApprovals().delete(db.patchSetApprovals().byPatchSet(psId));
db.patchComments().delete(db.patchComments().byPatchSet(psId));
diff --git a/java/com/google/gerrit/server/change/IncludedIn.java b/java/com/google/gerrit/server/change/IncludedIn.java
index d5d54ec..3ac6959 100644
--- a/java/com/google/gerrit/server/change/IncludedIn.java
+++ b/java/com/google/gerrit/server/change/IncludedIn.java
@@ -18,12 +18,12 @@
import com.google.common.collect.MultimapBuilder;
import com.google.gerrit.extensions.api.changes.IncludedInInfo;
import com.google.gerrit.extensions.config.ExternalIncludedIn;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.git.GitRepositoryManager;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.IOException;
@@ -37,10 +37,11 @@
@Singleton
public class IncludedIn {
private final GitRepositoryManager repoManager;
- private final DynamicSet<ExternalIncludedIn> externalIncludedIn;
+ private final PluginSetContext<ExternalIncludedIn> externalIncludedIn;
@Inject
- IncludedIn(GitRepositoryManager repoManager, DynamicSet<ExternalIncludedIn> externalIncludedIn) {
+ IncludedIn(
+ GitRepositoryManager repoManager, PluginSetContext<ExternalIncludedIn> externalIncludedIn) {
this.repoManager = repoManager;
this.externalIncludedIn = externalIncludedIn;
}
@@ -61,13 +62,15 @@
IncludedInResolver.Result d = IncludedInResolver.resolve(r, rw, rev);
ListMultimap<String, String> external = MultimapBuilder.hashKeys().arrayListValues().build();
- for (ExternalIncludedIn ext : externalIncludedIn) {
- ListMultimap<String, String> extIncludedIns =
- ext.getIncludedIn(project.get(), rev.name(), d.tags(), d.branches());
- if (extIncludedIns != null) {
- external.putAll(extIncludedIns);
- }
- }
+ externalIncludedIn.runEach(
+ ext -> {
+ ListMultimap<String, String> extIncludedIns =
+ ext.getIncludedIn(project.get(), rev.name(), d.tags(), d.branches());
+ if (extIncludedIns != null) {
+ external.putAll(extIncludedIns);
+ }
+ });
+
return new IncludedInInfo(
d.branches(), d.tags(), (!external.isEmpty() ? external.asMap() : null));
}
diff --git a/java/com/google/gerrit/server/change/SetAssigneeOp.java b/java/com/google/gerrit/server/change/SetAssigneeOp.java
index e2258c0..2242ef3 100644
--- a/java/com/google/gerrit/server/change/SetAssigneeOp.java
+++ b/java/com/google/gerrit/server/change/SetAssigneeOp.java
@@ -17,7 +17,6 @@
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestApiException;
import com.google.gerrit.reviewdb.client.Change;
@@ -27,6 +26,7 @@
import com.google.gerrit.server.extensions.events.AssigneeChanged;
import com.google.gerrit.server.mail.send.SetAssigneeSender;
import com.google.gerrit.server.notedb.ChangeUpdate;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
import com.google.gerrit.server.update.Context;
@@ -45,7 +45,7 @@
}
private final ChangeMessagesUtil cmUtil;
- private final DynamicSet<AssigneeValidationListener> validationListeners;
+ private final PluginSetContext<AssigneeValidationListener> validationListeners;
private final IdentifiedUser newAssignee;
private final AssigneeChanged assigneeChanged;
private final SetAssigneeSender.Factory setAssigneeSenderFactory;
@@ -58,7 +58,7 @@
@Inject
SetAssigneeOp(
ChangeMessagesUtil cmUtil,
- DynamicSet<AssigneeValidationListener> validationListeners,
+ PluginSetContext<AssigneeValidationListener> validationListeners,
AssigneeChanged assigneeChanged,
SetAssigneeSender.Factory setAssigneeSenderFactory,
Provider<IdentifiedUser> user,
@@ -80,11 +80,10 @@
return false;
}
try {
- for (AssigneeValidationListener validator : validationListeners) {
- validator.validateAssignee(change, newAssignee.getAccount());
- }
+ validationListeners.runEach(
+ l -> l.validateAssignee(change, newAssignee.getAccount()), ValidationException.class);
} catch (ValidationException e) {
- throw new ResourceConflictException(e.getMessage());
+ throw new ResourceConflictException(e.getMessage(), e);
}
if (change.getAssignee() != null) {
diff --git a/java/com/google/gerrit/server/change/SetHashtagsOp.java b/java/com/google/gerrit/server/change/SetHashtagsOp.java
index 1f17dd3..d11b2df 100644
--- a/java/com/google/gerrit/server/change/SetHashtagsOp.java
+++ b/java/com/google/gerrit/server/change/SetHashtagsOp.java
@@ -22,7 +22,6 @@
import com.google.common.collect.Ordering;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.api.changes.HashtagsInput;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
@@ -34,6 +33,7 @@
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.ChangeUpdate;
import com.google.gerrit.server.notedb.NotesMigration;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.ChangeContext;
import com.google.gerrit.server.update.Context;
@@ -54,7 +54,7 @@
private final NotesMigration notesMigration;
private final ChangeMessagesUtil cmUtil;
- private final DynamicSet<HashtagValidationListener> validationListeners;
+ private final PluginSetContext<HashtagValidationListener> validationListeners;
private final HashtagsEdited hashtagsEdited;
private final HashtagsInput input;
@@ -69,7 +69,7 @@
SetHashtagsOp(
NotesMigration notesMigration,
ChangeMessagesUtil cmUtil,
- DynamicSet<HashtagValidationListener> validationListeners,
+ PluginSetContext<HashtagValidationListener> validationListeners,
HashtagsEdited hashtagsEdited,
@Assisted @Nullable HashtagsInput input) {
this.notesMigration = notesMigration;
@@ -106,10 +106,8 @@
toAdd = new HashSet<>(extractTags(input.add));
toRemove = new HashSet<>(extractTags(input.remove));
- for (HashtagValidationListener validator : validationListeners) {
- validator.validateHashtags(update.getChange(), toAdd, toRemove);
- }
-
+ validationListeners.runEach(
+ l -> l.validateHashtags(update.getChange(), toAdd, toRemove), ValidationException.class);
updated.addAll(existingHashtags);
toAdd.removeAll(existingHashtags);
toRemove.retainAll(existingHashtags);
@@ -123,7 +121,7 @@
updatedHashtags = ImmutableSortedSet.copyOf(updated);
return true;
} catch (ValidationException | InvalidHashtagException e) {
- throw new BadRequestException(e.getMessage());
+ throw new BadRequestException(e.getMessage(), e);
}
}
diff --git a/java/com/google/gerrit/server/events/EventBroker.java b/java/com/google/gerrit/server/events/EventBroker.java
index 1aff0fa..94e9bb1 100644
--- a/java/com/google/gerrit/server/events/EventBroker.java
+++ b/java/com/google/gerrit/server/events/EventBroker.java
@@ -16,7 +16,6 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.registration.DynamicItem;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.lifecycle.LifecycleModule;
import com.google.gerrit.reviewdb.client.Branch;
@@ -31,6 +30,8 @@
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.permissions.ProjectPermission;
import com.google.gerrit.server.permissions.RefPermission;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
+import com.google.gerrit.server.plugincontext.PluginSetEntryContext;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
@@ -53,10 +54,10 @@
}
/** Listeners to receive changes as they happen (limited by visibility of user). */
- protected final DynamicSet<UserScopedEventListener> listeners;
+ protected final PluginSetContext<UserScopedEventListener> listeners;
/** Listeners to receive all changes as they happen. */
- protected final DynamicSet<EventListener> unrestrictedListeners;
+ protected final PluginSetContext<EventListener> unrestrictedListeners;
private final PermissionBackend permissionBackend;
protected final ProjectCache projectCache;
@@ -67,8 +68,8 @@
@Inject
public EventBroker(
- DynamicSet<UserScopedEventListener> listeners,
- DynamicSet<EventListener> unrestrictedListeners,
+ PluginSetContext<UserScopedEventListener> listeners,
+ PluginSetContext<EventListener> unrestrictedListeners,
PermissionBackend permissionBackend,
ProjectCache projectCache,
ChangeNotes.Factory notesFactory,
@@ -104,25 +105,25 @@
}
protected void fireEventForUnrestrictedListeners(Event event) {
- for (EventListener listener : unrestrictedListeners) {
- listener.onEvent(event);
- }
+ unrestrictedListeners.runEach(l -> l.onEvent(event));
}
protected void fireEvent(Change change, ChangeEvent event)
throws OrmException, PermissionBackendException {
- for (UserScopedEventListener listener : listeners) {
- if (isVisibleTo(change, listener.getUser())) {
- listener.onEvent(event);
+ for (PluginSetEntryContext<UserScopedEventListener> c : listeners) {
+ CurrentUser user = c.call(l -> l.getUser());
+ if (isVisibleTo(change, user)) {
+ c.run(l -> l.onEvent(event));
}
}
fireEventForUnrestrictedListeners(event);
}
protected void fireEvent(Project.NameKey project, ProjectEvent event) {
- for (UserScopedEventListener listener : listeners) {
- if (isVisibleTo(project, listener.getUser())) {
- listener.onEvent(event);
+ for (PluginSetEntryContext<UserScopedEventListener> c : listeners) {
+ CurrentUser user = c.call(l -> l.getUser());
+ if (isVisibleTo(project, user)) {
+ c.run(l -> l.onEvent(event));
}
}
fireEventForUnrestrictedListeners(event);
@@ -130,18 +131,20 @@
protected void fireEvent(Branch.NameKey branchName, RefEvent event)
throws PermissionBackendException {
- for (UserScopedEventListener listener : listeners) {
- if (isVisibleTo(branchName, listener.getUser())) {
- listener.onEvent(event);
+ for (PluginSetEntryContext<UserScopedEventListener> c : listeners) {
+ CurrentUser user = c.call(l -> l.getUser());
+ if (isVisibleTo(branchName, user)) {
+ c.run(l -> l.onEvent(event));
}
}
fireEventForUnrestrictedListeners(event);
}
protected void fireEvent(Event event) throws OrmException, PermissionBackendException {
- for (UserScopedEventListener listener : listeners) {
- if (isVisibleTo(event, listener.getUser())) {
- listener.onEvent(event);
+ for (PluginSetEntryContext<UserScopedEventListener> c : listeners) {
+ CurrentUser user = c.call(l -> l.getUser());
+ if (isVisibleTo(event, user)) {
+ c.run(l -> l.onEvent(event));
}
}
fireEventForUnrestrictedListeners(event);
diff --git a/java/com/google/gerrit/server/events/StreamEventsApiListener.java b/java/com/google/gerrit/server/events/StreamEventsApiListener.java
index 97a3f39..972266a 100644
--- a/java/com/google/gerrit/server/events/StreamEventsApiListener.java
+++ b/java/com/google/gerrit/server/events/StreamEventsApiListener.java
@@ -40,7 +40,6 @@
import com.google.gerrit.extensions.events.TopicEditedListener;
import com.google.gerrit.extensions.events.VoteDeletedListener;
import com.google.gerrit.extensions.events.WorkInProgressStateChangedListener;
-import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Branch;
@@ -55,7 +54,7 @@
import com.google.gerrit.server.data.RefUpdateAttribute;
import com.google.gerrit.server.git.GitRepositoryManager;
import com.google.gerrit.server.notedb.ChangeNotes;
-import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginItemContext;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gwtorm.server.OrmException;
@@ -117,7 +116,7 @@
}
}
- private final DynamicItem<EventDispatcher> dispatcher;
+ private final PluginItemContext<EventDispatcher> dispatcher;
private final Provider<ReviewDb> db;
private final EventFactory eventFactory;
private final ProjectCache projectCache;
@@ -127,7 +126,7 @@
@Inject
StreamEventsApiListener(
- DynamicItem<EventDispatcher> dispatcher,
+ PluginItemContext<EventDispatcher> dispatcher,
Provider<ReviewDb> db,
EventFactory eventFactory,
ProjectCache projectCache,
@@ -264,8 +263,8 @@
event.changer = accountAttributeSupplier(ev.getWho());
event.oldAssignee = accountAttributeSupplier(ev.getOldAssignee());
- dispatcher.get().postEvent(change, event);
- } catch (OrmException | PermissionBackendException e) {
+ dispatcher.run(d -> d.postEvent(change, event));
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
@@ -281,8 +280,8 @@
event.changer = accountAttributeSupplier(ev.getWho());
event.oldTopic = ev.getOldTopic();
- dispatcher.get().postEvent(change, event);
- } catch (OrmException | PermissionBackendException e) {
+ dispatcher.run(d -> d.postEvent(change, event));
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
@@ -299,8 +298,8 @@
event.patchSet = patchSetAttributeSupplier(change, patchSet);
event.uploader = accountAttributeSupplier(ev.getWho());
- dispatcher.get().postEvent(change, event);
- } catch (OrmException | PermissionBackendException e) {
+ dispatcher.run(d -> d.postEvent(change, event));
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
@@ -319,8 +318,8 @@
event.approvals =
approvalsAttributeSupplier(change, ev.getNewApprovals(), ev.getOldApprovals());
- dispatcher.get().postEvent(change, event);
- } catch (OrmException | PermissionBackendException e) {
+ dispatcher.run(d -> d.postEvent(change, event));
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
@@ -336,9 +335,9 @@
event.patchSet = patchSetAttributeSupplier(change, psUtil.current(db.get(), notes));
for (AccountInfo reviewer : ev.getReviewers()) {
event.reviewer = accountAttributeSupplier(reviewer);
- dispatcher.get().postEvent(change, event);
+ dispatcher.run(d -> d.postEvent(event));
}
- } catch (OrmException | PermissionBackendException e) {
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
@@ -349,7 +348,7 @@
event.projectName = ev.getProjectName();
event.headName = ev.getHeadName();
- dispatcher.get().postEvent(event.getProjectNameKey(), event);
+ dispatcher.run(d -> d.postEvent(event.getProjectNameKey(), event));
}
@Override
@@ -365,8 +364,8 @@
event.added = hashtagArray(ev.getAddedHashtags());
event.removed = hashtagArray(ev.getRemovedHashtags());
- dispatcher.get().postEvent(change, event);
- } catch (OrmException | PermissionBackendException e) {
+ dispatcher.run(d -> d.postEvent(change, event));
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
@@ -389,11 +388,7 @@
refName);
}
});
- try {
- dispatcher.get().postEvent(refName, event);
- } catch (PermissionBackendException e) {
- logger.atSevere().withCause(e).log("Failed to dispatch event");
- }
+ dispatcher.run(d -> d.postEvent(refName, event));
}
@Override
@@ -410,8 +405,8 @@
event.comment = ev.getComment();
event.approvals = approvalsAttributeSupplier(change, ev.getApprovals(), ev.getOldApprovals());
- dispatcher.get().postEvent(change, event);
- } catch (OrmException | PermissionBackendException e) {
+ dispatcher.run(d -> d.postEvent(change, event));
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
@@ -428,8 +423,8 @@
event.patchSet = patchSetAttributeSupplier(change, psUtil.current(db.get(), notes));
event.reason = ev.getReason();
- dispatcher.get().postEvent(change, event);
- } catch (OrmException | PermissionBackendException e) {
+ dispatcher.run(d -> d.postEvent(change, event));
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
@@ -446,8 +441,8 @@
event.patchSet = patchSetAttributeSupplier(change, psUtil.current(db.get(), notes));
event.newRev = ev.getNewRevisionId();
- dispatcher.get().postEvent(change, event);
- } catch (OrmException | PermissionBackendException e) {
+ dispatcher.run(d -> d.postEvent(change, event));
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
@@ -464,8 +459,8 @@
event.patchSet = patchSetAttributeSupplier(change, psUtil.current(db.get(), notes));
event.reason = ev.getReason();
- dispatcher.get().postEvent(change, event);
- } catch (OrmException | PermissionBackendException e) {
+ dispatcher.run(d -> d.postEvent(change, event));
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
@@ -482,8 +477,8 @@
event.changer = accountAttributeSupplier(ev.getWho());
event.patchSet = patchSetAttributeSupplier(change, patchSet);
- dispatcher.get().postEvent(change, event);
- } catch (OrmException | PermissionBackendException e) {
+ dispatcher.run(d -> d.postEvent(change, event));
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
@@ -500,8 +495,8 @@
event.changer = accountAttributeSupplier(ev.getWho());
event.patchSet = patchSetAttributeSupplier(change, patchSet);
- dispatcher.get().postEvent(change, event);
- } catch (OrmException | PermissionBackendException e) {
+ dispatcher.run(d -> d.postEvent(change, event));
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
@@ -520,8 +515,8 @@
event.remover = accountAttributeSupplier(ev.getWho());
event.approvals = approvalsAttributeSupplier(change, ev.getApprovals(), ev.getOldApprovals());
- dispatcher.get().postEvent(change, event);
- } catch (OrmException | PermissionBackendException e) {
+ dispatcher.run(d -> d.postEvent(change, event));
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
@@ -536,8 +531,8 @@
event.change = changeAttributeSupplier(change, notes);
event.deleter = accountAttributeSupplier(ev.getWho());
- dispatcher.get().postEvent(change, event);
- } catch (OrmException | PermissionBackendException e) {
+ dispatcher.run(d -> d.postEvent(change, event));
+ } catch (OrmException e) {
logger.atSevere().withCause(e).log("Failed to dispatch event");
}
}
diff --git a/java/com/google/gerrit/server/extensions/events/AgreementSignup.java b/java/com/google/gerrit/server/extensions/events/AgreementSignup.java
index 1548c38..b692cf5 100644
--- a/java/com/google/gerrit/server/extensions/events/AgreementSignup.java
+++ b/java/com/google/gerrit/server/extensions/events/AgreementSignup.java
@@ -16,34 +16,28 @@
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.events.AgreementSignupListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@Singleton
public class AgreementSignup {
- private final DynamicSet<AgreementSignupListener> listeners;
+ private final PluginSetContext<AgreementSignupListener> listeners;
private final EventUtil util;
@Inject
- AgreementSignup(DynamicSet<AgreementSignupListener> listeners, EventUtil util) {
+ AgreementSignup(PluginSetContext<AgreementSignupListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
public void fire(AccountState accountState, String agreementName) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
Event event = new Event(util.accountInfo(accountState), agreementName);
- for (AgreementSignupListener l : listeners) {
- try {
- l.onAgreementSignup(event);
- } catch (Exception e) {
- util.logEventListenerError(this, l, e);
- }
- }
+ listeners.runEach(l -> l.onAgreementSignup(event));
}
private static class Event extends AbstractNoNotifyEvent
diff --git a/java/com/google/gerrit/server/extensions/events/AssigneeChanged.java b/java/com/google/gerrit/server/extensions/events/AssigneeChanged.java
index 7320fd3..513a5de 100644
--- a/java/com/google/gerrit/server/extensions/events/AssigneeChanged.java
+++ b/java/com/google/gerrit/server/extensions/events/AssigneeChanged.java
@@ -19,9 +19,9 @@
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.events.AssigneeChangedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -31,18 +31,18 @@
public class AssigneeChanged {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<AssigneeChangedListener> listeners;
+ private final PluginSetContext<AssigneeChangedListener> listeners;
private final EventUtil util;
@Inject
- AssigneeChanged(DynamicSet<AssigneeChangedListener> listeners, EventUtil util) {
+ AssigneeChanged(PluginSetContext<AssigneeChangedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
public void fire(
Change change, AccountState accountState, AccountState oldAssignee, Timestamp when) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
@@ -52,13 +52,7 @@
util.accountInfo(accountState),
util.accountInfo(oldAssignee),
when);
- for (AssigneeChangedListener l : listeners) {
- try {
- l.onAssigneeChanged(event);
- } catch (Exception e) {
- util.logEventListenerError(event, l, e);
- }
- }
+ listeners.runEach(l -> l.onAssigneeChanged(event));
} catch (OrmException e) {
logger.atSevere().withCause(e).log("Couldn't fire event");
}
diff --git a/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java b/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java
index 3a19e97..3d6700e 100644
--- a/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java
+++ b/java/com/google/gerrit/server/extensions/events/ChangeAbandoned.java
@@ -20,7 +20,6 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.events.ChangeAbandonedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.GpgException;
@@ -28,6 +27,7 @@
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -38,11 +38,11 @@
public class ChangeAbandoned {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<ChangeAbandonedListener> listeners;
+ private final PluginSetContext<ChangeAbandonedListener> listeners;
private final EventUtil util;
@Inject
- ChangeAbandoned(DynamicSet<ChangeAbandonedListener> listeners, EventUtil util) {
+ ChangeAbandoned(PluginSetContext<ChangeAbandonedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
@@ -54,7 +54,7 @@
String reason,
Timestamp when,
NotifyHandling notifyHandling) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
@@ -66,13 +66,7 @@
reason,
when,
notifyHandling);
- for (ChangeAbandonedListener l : listeners) {
- try {
- l.onChangeAbandoned(event);
- } catch (Exception e) {
- util.logEventListenerError(this, l, e);
- }
- }
+ listeners.runEach(l -> l.onChangeAbandoned(event));
} catch (PatchListObjectTooLargeException e) {
logger.atWarning().log("Couldn't fire event: %s", e.getMessage());
} catch (PatchListNotAvailableException
diff --git a/java/com/google/gerrit/server/extensions/events/ChangeDeleted.java b/java/com/google/gerrit/server/extensions/events/ChangeDeleted.java
index dd1dc07..d9eb9f9 100644
--- a/java/com/google/gerrit/server/extensions/events/ChangeDeleted.java
+++ b/java/com/google/gerrit/server/extensions/events/ChangeDeleted.java
@@ -19,9 +19,9 @@
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.events.ChangeDeletedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -31,28 +31,22 @@
public class ChangeDeleted {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<ChangeDeletedListener> listeners;
+ private final PluginSetContext<ChangeDeletedListener> listeners;
private final EventUtil util;
@Inject
- ChangeDeleted(DynamicSet<ChangeDeletedListener> listeners, EventUtil util) {
+ ChangeDeleted(PluginSetContext<ChangeDeletedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
public void fire(Change change, AccountState deleter, Timestamp when) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
Event event = new Event(util.changeInfo(change), util.accountInfo(deleter), when);
- for (ChangeDeletedListener l : listeners) {
- try {
- l.onChangeDeleted(event);
- } catch (Exception e) {
- util.logEventListenerError(this, l, e);
- }
- }
+ listeners.runEach(l -> l.onChangeDeleted(event));
} catch (OrmException e) {
logger.atSevere().withCause(e).log("Couldn't fire event");
}
diff --git a/java/com/google/gerrit/server/extensions/events/ChangeMerged.java b/java/com/google/gerrit/server/extensions/events/ChangeMerged.java
index 5b882b8..7b814ae 100644
--- a/java/com/google/gerrit/server/extensions/events/ChangeMerged.java
+++ b/java/com/google/gerrit/server/extensions/events/ChangeMerged.java
@@ -20,7 +20,6 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.events.ChangeMergedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.GpgException;
@@ -28,6 +27,7 @@
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -38,18 +38,18 @@
public class ChangeMerged {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<ChangeMergedListener> listeners;
+ private final PluginSetContext<ChangeMergedListener> listeners;
private final EventUtil util;
@Inject
- ChangeMerged(DynamicSet<ChangeMergedListener> listeners, EventUtil util) {
+ ChangeMerged(PluginSetContext<ChangeMergedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
public void fire(
Change change, PatchSet ps, AccountState merger, String newRevisionId, Timestamp when) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
@@ -60,13 +60,7 @@
util.accountInfo(merger),
newRevisionId,
when);
- for (ChangeMergedListener l : listeners) {
- try {
- l.onChangeMerged(event);
- } catch (Exception e) {
- util.logEventListenerError(this, l, e);
- }
- }
+ listeners.runEach(l -> l.onChangeMerged(event));
} catch (PatchListObjectTooLargeException e) {
logger.atWarning().log("Couldn't fire event: %s", e.getMessage());
} catch (PatchListNotAvailableException
diff --git a/java/com/google/gerrit/server/extensions/events/ChangeRestored.java b/java/com/google/gerrit/server/extensions/events/ChangeRestored.java
index d62b6c1..81b04cd 100644
--- a/java/com/google/gerrit/server/extensions/events/ChangeRestored.java
+++ b/java/com/google/gerrit/server/extensions/events/ChangeRestored.java
@@ -20,7 +20,6 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.events.ChangeRestoredListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.GpgException;
@@ -28,6 +27,7 @@
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -38,18 +38,18 @@
public class ChangeRestored {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<ChangeRestoredListener> listeners;
+ private final PluginSetContext<ChangeRestoredListener> listeners;
private final EventUtil util;
@Inject
- ChangeRestored(DynamicSet<ChangeRestoredListener> listeners, EventUtil util) {
+ ChangeRestored(PluginSetContext<ChangeRestoredListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
public void fire(
Change change, PatchSet ps, AccountState restorer, String reason, Timestamp when) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
@@ -60,13 +60,7 @@
util.accountInfo(restorer),
reason,
when);
- for (ChangeRestoredListener l : listeners) {
- try {
- l.onChangeRestored(event);
- } catch (Exception e) {
- util.logEventListenerError(this, l, e);
- }
- }
+ listeners.runEach(l -> l.onChangeRestored(event));
} catch (PatchListObjectTooLargeException e) {
logger.atWarning().log("Couldn't fire event: %s", e.getMessage());
} catch (PatchListNotAvailableException
diff --git a/java/com/google/gerrit/server/extensions/events/ChangeReverted.java b/java/com/google/gerrit/server/extensions/events/ChangeReverted.java
index 5f8f8c3..ac7aac0 100644
--- a/java/com/google/gerrit/server/extensions/events/ChangeReverted.java
+++ b/java/com/google/gerrit/server/extensions/events/ChangeReverted.java
@@ -18,8 +18,8 @@
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.events.ChangeRevertedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -29,28 +29,22 @@
public class ChangeReverted {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<ChangeRevertedListener> listeners;
+ private final PluginSetContext<ChangeRevertedListener> listeners;
private final EventUtil util;
@Inject
- ChangeReverted(DynamicSet<ChangeRevertedListener> listeners, EventUtil util) {
+ ChangeReverted(PluginSetContext<ChangeRevertedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
public void fire(Change change, Change revertChange, Timestamp when) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
Event event = new Event(util.changeInfo(change), util.changeInfo(revertChange), when);
- for (ChangeRevertedListener l : listeners) {
- try {
- l.onChangeReverted(event);
- } catch (Exception e) {
- util.logEventListenerError(this, l, e);
- }
- }
+ listeners.runEach(l -> l.onChangeReverted(event));
} catch (OrmException e) {
logger.atSevere().withCause(e).log("Couldn't fire event");
}
diff --git a/java/com/google/gerrit/server/extensions/events/CommentAdded.java b/java/com/google/gerrit/server/extensions/events/CommentAdded.java
index 8ba9f82..e224540 100644
--- a/java/com/google/gerrit/server/extensions/events/CommentAdded.java
+++ b/java/com/google/gerrit/server/extensions/events/CommentAdded.java
@@ -21,7 +21,6 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.events.CommentAddedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.GpgException;
@@ -29,6 +28,7 @@
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -40,11 +40,11 @@
public class CommentAdded {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<CommentAddedListener> listeners;
+ private final PluginSetContext<CommentAddedListener> listeners;
private final EventUtil util;
@Inject
- CommentAdded(DynamicSet<CommentAddedListener> listeners, EventUtil util) {
+ CommentAdded(PluginSetContext<CommentAddedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
@@ -57,7 +57,7 @@
Map<String, Short> approvals,
Map<String, Short> oldApprovals,
Timestamp when) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
@@ -70,13 +70,7 @@
util.approvals(author, approvals, when),
util.approvals(author, oldApprovals, when),
when);
- for (CommentAddedListener l : listeners) {
- try {
- l.onCommentAdded(event);
- } catch (Exception e) {
- util.logEventListenerError(this, l, e);
- }
- }
+ listeners.runEach(l -> l.onCommentAdded(event));
} catch (PatchListObjectTooLargeException e) {
logger.atWarning().log("Couldn't fire event: %s", e.getMessage());
} catch (PatchListNotAvailableException
diff --git a/java/com/google/gerrit/server/extensions/events/EventUtil.java b/java/com/google/gerrit/server/extensions/events/EventUtil.java
index 5116708..3a10fc5 100644
--- a/java/com/google/gerrit/server/extensions/events/EventUtil.java
+++ b/java/com/google/gerrit/server/extensions/events/EventUtil.java
@@ -16,7 +16,6 @@
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
-import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ApprovalInfo;
@@ -45,8 +44,6 @@
@Singleton
public class EventUtil {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
private static final ImmutableSet<ListChangesOption> CHANGE_OPTIONS;
static {
@@ -118,22 +115,4 @@
}
return result;
}
-
- public void logEventListenerError(Object event, Object listener, Exception error) {
- logger.atWarning().log(
- "Error in event listener %s for event %s: %s - %s",
- listener.getClass().getName(),
- event.getClass().getName(),
- error.getClass().getName(),
- error.getMessage());
- logger.atFine().withCause(error).log(
- "Cause of error in event listener %s:", listener.getClass().getName());
- }
-
- public static void logEventListenerError(Object listener, Exception error) {
- logger.atWarning().log(
- "Error in event listener %s: %s", listener.getClass().getName(), error.getMessage());
- logger.atFine().withCause(error).log(
- "Cause of error in event listener %s", listener.getClass().getName());
- }
}
diff --git a/java/com/google/gerrit/server/extensions/events/GitReferenceUpdated.java b/java/com/google/gerrit/server/extensions/events/GitReferenceUpdated.java
index 61533da..bae17e7 100644
--- a/java/com/google/gerrit/server/extensions/events/GitReferenceUpdated.java
+++ b/java/com/google/gerrit/server/extensions/events/GitReferenceUpdated.java
@@ -17,9 +17,9 @@
import com.google.gerrit.extensions.api.changes.NotifyHandling;
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.events.GitReferenceUpdatedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.jgit.lib.BatchRefUpdate;
@@ -57,11 +57,11 @@
Project.NameKey project, BatchRefUpdate batchRefUpdate, AccountState updater) {}
};
- private final DynamicSet<GitReferenceUpdatedListener> listeners;
+ private final PluginSetContext<GitReferenceUpdatedListener> listeners;
private final EventUtil util;
@Inject
- GitReferenceUpdated(DynamicSet<GitReferenceUpdatedListener> listeners, EventUtil util) {
+ GitReferenceUpdated(PluginSetContext<GitReferenceUpdatedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
@@ -121,7 +121,7 @@
}
public void fire(Project.NameKey project, BatchRefUpdate batchRefUpdate, AccountState updater) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
for (ReceiveCommand cmd : batchRefUpdate.getCommands()) {
@@ -144,19 +144,13 @@
ObjectId newObjectId,
ReceiveCommand.Type type,
AccountInfo updater) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
ObjectId o = oldObjectId != null ? oldObjectId : ObjectId.zeroId();
ObjectId n = newObjectId != null ? newObjectId : ObjectId.zeroId();
Event event = new Event(project, ref, o.name(), n.name(), type, updater);
- for (GitReferenceUpdatedListener l : listeners) {
- try {
- l.onGitReferenceUpdated(event);
- } catch (Exception e) {
- util.logEventListenerError(this, l, e);
- }
- }
+ listeners.runEach(l -> l.onGitReferenceUpdated(event));
}
public static class Event implements GitReferenceUpdatedListener.Event {
diff --git a/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java b/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java
index 9a0247a..ca0edab 100644
--- a/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java
+++ b/java/com/google/gerrit/server/extensions/events/HashtagsEdited.java
@@ -20,9 +20,9 @@
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.events.HashtagsEditedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -34,11 +34,11 @@
public class HashtagsEdited {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<HashtagsEditedListener> listeners;
+ private final PluginSetContext<HashtagsEditedListener> listeners;
private final EventUtil util;
@Inject
- public HashtagsEdited(DynamicSet<HashtagsEditedListener> listeners, EventUtil util) {
+ public HashtagsEdited(PluginSetContext<HashtagsEditedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
@@ -50,20 +50,14 @@
Set<String> added,
Set<String> removed,
Timestamp when) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
Event event =
new Event(
util.changeInfo(change), util.accountInfo(editor), hashtags, added, removed, when);
- for (HashtagsEditedListener l : listeners) {
- try {
- l.onHashtagsEdited(event);
- } catch (Exception e) {
- util.logEventListenerError(this, l, e);
- }
- }
+ listeners.runEach(l -> l.onHashtagsEdited(event));
} catch (OrmException e) {
logger.atSevere().withCause(e).log("Couldn't fire event");
}
diff --git a/java/com/google/gerrit/server/extensions/events/PrivateStateChanged.java b/java/com/google/gerrit/server/extensions/events/PrivateStateChanged.java
index 2df56aa..358667f 100644
--- a/java/com/google/gerrit/server/extensions/events/PrivateStateChanged.java
+++ b/java/com/google/gerrit/server/extensions/events/PrivateStateChanged.java
@@ -20,13 +20,13 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.events.PrivateStateChangedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.GpgException;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -37,17 +37,17 @@
public class PrivateStateChanged {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<PrivateStateChangedListener> listeners;
+ private final PluginSetContext<PrivateStateChangedListener> listeners;
private final EventUtil util;
@Inject
- PrivateStateChanged(DynamicSet<PrivateStateChangedListener> listeners, EventUtil util) {
+ PrivateStateChanged(PluginSetContext<PrivateStateChangedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
public void fire(Change change, PatchSet patchSet, AccountState account, Timestamp when) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
@@ -57,13 +57,7 @@
util.revisionInfo(change.getProject(), patchSet),
util.accountInfo(account),
when);
- for (PrivateStateChangedListener l : listeners) {
- try {
- l.onPrivateStateChanged(event);
- } catch (Exception e) {
- util.logEventListenerError(event, l, e);
- }
- }
+ listeners.runEach(l -> l.onPrivateStateChanged(event));
} catch (OrmException
| PatchListNotAvailableException
| GpgException
diff --git a/java/com/google/gerrit/server/extensions/events/ReviewerAdded.java b/java/com/google/gerrit/server/extensions/events/ReviewerAdded.java
index e33715b..8e5259c 100644
--- a/java/com/google/gerrit/server/extensions/events/ReviewerAdded.java
+++ b/java/com/google/gerrit/server/extensions/events/ReviewerAdded.java
@@ -21,7 +21,6 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.events.ReviewerAddedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.GpgException;
@@ -29,6 +28,7 @@
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -40,11 +40,11 @@
public class ReviewerAdded {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<ReviewerAddedListener> listeners;
+ private final PluginSetContext<ReviewerAddedListener> listeners;
private final EventUtil util;
@Inject
- ReviewerAdded(DynamicSet<ReviewerAddedListener> listeners, EventUtil util) {
+ ReviewerAdded(PluginSetContext<ReviewerAddedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
@@ -55,7 +55,7 @@
List<AccountState> reviewers,
AccountState adder,
Timestamp when) {
- if (!listeners.iterator().hasNext() || reviewers.isEmpty()) {
+ if (listeners.isEmpty() || reviewers.isEmpty()) {
return;
}
@@ -67,13 +67,7 @@
Lists.transform(reviewers, util::accountInfo),
util.accountInfo(adder),
when);
- for (ReviewerAddedListener l : listeners) {
- try {
- l.onReviewersAdded(event);
- } catch (Exception e) {
- util.logEventListenerError(this, l, e);
- }
- }
+ listeners.runEach(l -> l.onReviewersAdded(event));
} catch (PatchListObjectTooLargeException e) {
logger.atWarning().log("Couldn't fire event: %s", e.getMessage());
} catch (PatchListNotAvailableException
diff --git a/java/com/google/gerrit/server/extensions/events/ReviewerDeleted.java b/java/com/google/gerrit/server/extensions/events/ReviewerDeleted.java
index 011a3e8..89c8f18 100644
--- a/java/com/google/gerrit/server/extensions/events/ReviewerDeleted.java
+++ b/java/com/google/gerrit/server/extensions/events/ReviewerDeleted.java
@@ -21,7 +21,6 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.events.ReviewerDeletedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.GpgException;
@@ -29,6 +28,7 @@
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -40,11 +40,11 @@
public class ReviewerDeleted {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<ReviewerDeletedListener> listeners;
+ private final PluginSetContext<ReviewerDeletedListener> listeners;
private final EventUtil util;
@Inject
- ReviewerDeleted(DynamicSet<ReviewerDeletedListener> listeners, EventUtil util) {
+ ReviewerDeleted(PluginSetContext<ReviewerDeletedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
@@ -59,7 +59,7 @@
Map<String, Short> oldApprovals,
NotifyHandling notify,
Timestamp when) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
@@ -74,13 +74,7 @@
util.approvals(reviewer, oldApprovals, when),
notify,
when);
- for (ReviewerDeletedListener listener : listeners) {
- try {
- listener.onReviewerDeleted(event);
- } catch (Exception e) {
- util.logEventListenerError(this, listener, e);
- }
- }
+ listeners.runEach(l -> l.onReviewerDeleted(event));
} catch (PatchListObjectTooLargeException e) {
logger.atWarning().log("Couldn't fire event: %s", e.getMessage());
} catch (PatchListNotAvailableException
diff --git a/java/com/google/gerrit/server/extensions/events/RevisionCreated.java b/java/com/google/gerrit/server/extensions/events/RevisionCreated.java
index f203f5d..e043e9f 100644
--- a/java/com/google/gerrit/server/extensions/events/RevisionCreated.java
+++ b/java/com/google/gerrit/server/extensions/events/RevisionCreated.java
@@ -20,7 +20,6 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.events.RevisionCreatedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.GpgException;
@@ -28,6 +27,7 @@
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -49,11 +49,11 @@
NotifyHandling notify) {}
};
- private final DynamicSet<RevisionCreatedListener> listeners;
+ private final PluginSetContext<RevisionCreatedListener> listeners;
private final EventUtil util;
@Inject
- RevisionCreated(DynamicSet<RevisionCreatedListener> listeners, EventUtil util) {
+ RevisionCreated(PluginSetContext<RevisionCreatedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
@@ -69,7 +69,7 @@
AccountState uploader,
Timestamp when,
NotifyHandling notify) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
@@ -80,13 +80,7 @@
util.accountInfo(uploader),
when,
notify);
- for (RevisionCreatedListener l : listeners) {
- try {
- l.onRevisionCreated(event);
- } catch (Exception e) {
- util.logEventListenerError(this, l, e);
- }
- }
+ listeners.runEach(l -> l.onRevisionCreated(event));
} catch (PatchListObjectTooLargeException e) {
logger.atWarning().log("Couldn't fire event: %s", e.getMessage());
} catch (PatchListNotAvailableException
diff --git a/java/com/google/gerrit/server/extensions/events/TopicEdited.java b/java/com/google/gerrit/server/extensions/events/TopicEdited.java
index 45962f9..8568c0f 100644
--- a/java/com/google/gerrit/server/extensions/events/TopicEdited.java
+++ b/java/com/google/gerrit/server/extensions/events/TopicEdited.java
@@ -19,9 +19,9 @@
import com.google.gerrit.extensions.common.AccountInfo;
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.events.TopicEditedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.server.account.AccountState;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -31,29 +31,23 @@
public class TopicEdited {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<TopicEditedListener> listeners;
+ private final PluginSetContext<TopicEditedListener> listeners;
private final EventUtil util;
@Inject
- TopicEdited(DynamicSet<TopicEditedListener> listeners, EventUtil util) {
+ TopicEdited(PluginSetContext<TopicEditedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
public void fire(Change change, AccountState account, String oldTopicName, Timestamp when) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
Event event =
new Event(util.changeInfo(change), util.accountInfo(account), oldTopicName, when);
- for (TopicEditedListener l : listeners) {
- try {
- l.onTopicEdited(event);
- } catch (Exception e) {
- util.logEventListenerError(this, l, e);
- }
- }
+ listeners.runEach(l -> l.onTopicEdited(event));
} catch (OrmException e) {
logger.atSevere().withCause(e).log("Couldn't fire event");
}
diff --git a/java/com/google/gerrit/server/extensions/events/VoteDeleted.java b/java/com/google/gerrit/server/extensions/events/VoteDeleted.java
index 5480dd8..b750851 100644
--- a/java/com/google/gerrit/server/extensions/events/VoteDeleted.java
+++ b/java/com/google/gerrit/server/extensions/events/VoteDeleted.java
@@ -21,7 +21,6 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.events.VoteDeletedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.GpgException;
@@ -29,6 +28,7 @@
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -40,11 +40,11 @@
public class VoteDeleted {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<VoteDeletedListener> listeners;
+ private final PluginSetContext<VoteDeletedListener> listeners;
private final EventUtil util;
@Inject
- VoteDeleted(DynamicSet<VoteDeletedListener> listeners, EventUtil util) {
+ VoteDeleted(PluginSetContext<VoteDeletedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
@@ -59,7 +59,7 @@
String message,
AccountState remover,
Timestamp when) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
@@ -74,13 +74,7 @@
message,
util.accountInfo(remover),
when);
- for (VoteDeletedListener l : listeners) {
- try {
- l.onVoteDeleted(event);
- } catch (Exception e) {
- util.logEventListenerError(this, l, e);
- }
- }
+ listeners.runEach(l -> l.onVoteDeleted(event));
} catch (PatchListObjectTooLargeException e) {
logger.atWarning().log("Couldn't fire event: %s", e.getMessage());
} catch (PatchListNotAvailableException
diff --git a/java/com/google/gerrit/server/extensions/events/WorkInProgressStateChanged.java b/java/com/google/gerrit/server/extensions/events/WorkInProgressStateChanged.java
index 1c22561..6273ad6 100644
--- a/java/com/google/gerrit/server/extensions/events/WorkInProgressStateChanged.java
+++ b/java/com/google/gerrit/server/extensions/events/WorkInProgressStateChanged.java
@@ -20,13 +20,13 @@
import com.google.gerrit.extensions.common.ChangeInfo;
import com.google.gerrit.extensions.common.RevisionInfo;
import com.google.gerrit.extensions.events.WorkInProgressStateChangedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.server.GpgException;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -37,18 +37,18 @@
public class WorkInProgressStateChanged {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<WorkInProgressStateChangedListener> listeners;
+ private final PluginSetContext<WorkInProgressStateChangedListener> listeners;
private final EventUtil util;
@Inject
WorkInProgressStateChanged(
- DynamicSet<WorkInProgressStateChangedListener> listeners, EventUtil util) {
+ PluginSetContext<WorkInProgressStateChangedListener> listeners, EventUtil util) {
this.listeners = listeners;
this.util = util;
}
public void fire(Change change, PatchSet patchSet, AccountState account, Timestamp when) {
- if (!listeners.iterator().hasNext()) {
+ if (listeners.isEmpty()) {
return;
}
try {
@@ -58,13 +58,7 @@
util.revisionInfo(change.getProject(), patchSet),
util.accountInfo(account),
when);
- for (WorkInProgressStateChangedListener l : listeners) {
- try {
- l.onWorkInProgressStateChanged(event);
- } catch (Exception e) {
- util.logEventListenerError(event, l, e);
- }
- }
+ listeners.runEach(l -> l.onWorkInProgressStateChanged(event));
} catch (OrmException
| PatchListNotAvailableException
| GpgException
diff --git a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
index ef699b3..b6d4b12 100644
--- a/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
+++ b/java/com/google/gerrit/server/git/receive/ReceiveCommits.java
@@ -70,7 +70,6 @@
import com.google.gerrit.extensions.client.GeneralPreferencesInfo;
import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
@@ -129,6 +128,7 @@
import com.google.gerrit.server.permissions.PermissionDeniedException;
import com.google.gerrit.server.permissions.ProjectPermission;
import com.google.gerrit.server.permissions.RefPermission;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.project.CreateRefControl;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.project.NoSuchProjectException;
@@ -301,7 +301,7 @@
private final CreateGroupPermissionSyncer createGroupPermissionSyncer;
private final CreateRefControl createRefControl;
private final DynamicMap<ProjectConfigEntry> pluginConfigEntries;
- private final DynamicSet<ReceivePackInitializer> initializers;
+ private final PluginSetContext<ReceivePackInitializer> initializers;
private final MergedByPushOp.Factory mergedByPushOpFactory;
private final NotesMigration notesMigration;
private final PatchSetInfoFactory patchSetInfoFactory;
@@ -376,7 +376,7 @@
CreateGroupPermissionSyncer createGroupPermissionSyncer,
CreateRefControl createRefControl,
DynamicMap<ProjectConfigEntry> pluginConfigEntries,
- DynamicSet<ReceivePackInitializer> initializers,
+ PluginSetContext<ReceivePackInitializer> initializers,
MergedByPushOp.Factory mergedByPushOpFactory,
NotesMigration notesMigration,
PatchSetInfoFactory patchSetInfoFactory,
@@ -472,9 +472,7 @@
}
void init() {
- for (ReceivePackInitializer i : initializers) {
- i.init(projectState.getNameKey(), receivePack);
- }
+ initializers.runEach(i -> i.init(projectState.getNameKey(), receivePack));
}
MessageSender getMessageSender() {
diff --git a/java/com/google/gerrit/server/git/validators/CommitValidators.java b/java/com/google/gerrit/server/git/validators/CommitValidators.java
index 8af04e0..a66e07f 100644
--- a/java/com/google/gerrit/server/git/validators/CommitValidators.java
+++ b/java/com/google/gerrit/server/git/validators/CommitValidators.java
@@ -28,7 +28,6 @@
import com.google.gerrit.common.FooterConstants;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.api.config.ConsistencyCheckInfo.ConsistencyProblemInfo;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.BooleanProjectConfig;
@@ -49,6 +48,7 @@
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.permissions.RefPermission;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.gerrit.server.project.ProjectState;
@@ -89,7 +89,7 @@
public static class Factory {
private final PersonIdent gerritIdent;
private final UrlFormatter urlFormatter;
- private final DynamicSet<CommitValidationListener> pluginValidators;
+ private final PluginSetContext<CommitValidationListener> pluginValidators;
private final GitRepositoryManager repoManager;
private final AllUsersName allUsers;
private final AllProjectsName allProjects;
@@ -103,7 +103,7 @@
@GerritPersonIdent PersonIdent gerritIdent,
UrlFormatter urlFormatter,
@GerritServerConfig Config cfg,
- DynamicSet<CommitValidationListener> pluginValidators,
+ PluginSetContext<CommitValidationListener> pluginValidators,
GitRepositoryManager repoManager,
AllUsersName allUsers,
AllProjectsName allProjects,
@@ -462,10 +462,10 @@
/** Execute commit validation plug-ins */
public static class PluginCommitValidationListener implements CommitValidationListener {
- private final DynamicSet<CommitValidationListener> commitValidationListeners;
+ private final PluginSetContext<CommitValidationListener> commitValidationListeners;
public PluginCommitValidationListener(
- final DynamicSet<CommitValidationListener> commitValidationListeners) {
+ final PluginSetContext<CommitValidationListener> commitValidationListeners) {
this.commitValidationListeners = commitValidationListeners;
}
@@ -473,14 +473,12 @@
public List<CommitValidationMessage> onCommitReceived(CommitReceivedEvent receiveEvent)
throws CommitValidationException {
List<CommitValidationMessage> messages = new ArrayList<>();
-
- for (CommitValidationListener validator : commitValidationListeners) {
- try {
- messages.addAll(validator.onCommitReceived(receiveEvent));
- } catch (CommitValidationException e) {
- messages.addAll(e.getMessages());
- throw new CommitValidationException(e.getMessage(), messages);
- }
+ try {
+ commitValidationListeners.runEach(
+ l -> l.onCommitReceived(receiveEvent), CommitValidationException.class);
+ } catch (CommitValidationException e) {
+ messages.addAll(e.getMessages());
+ throw new CommitValidationException(e.getMessage(), messages);
}
return messages;
}
diff --git a/java/com/google/gerrit/server/git/validators/MergeValidators.java b/java/com/google/gerrit/server/git/validators/MergeValidators.java
index f755aab..0422c51 100644
--- a/java/com/google/gerrit/server/git/validators/MergeValidators.java
+++ b/java/com/google/gerrit/server/git/validators/MergeValidators.java
@@ -19,7 +19,6 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.api.projects.ProjectConfigEntryType;
import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.reviewdb.client.Account;
@@ -40,6 +39,7 @@
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.permissions.ProjectPermission;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.gerrit.server.project.ProjectState;
@@ -57,7 +57,7 @@
public class MergeValidators {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
- private final DynamicSet<MergeValidationListener> mergeValidationListeners;
+ private final PluginSetContext<MergeValidationListener> mergeValidationListeners;
private final ProjectConfigValidator.Factory projectConfigValidatorFactory;
private final AccountMergeValidator.Factory accountValidatorFactory;
private final GroupMergeValidator.Factory groupValidatorFactory;
@@ -68,7 +68,7 @@
@Inject
MergeValidators(
- DynamicSet<MergeValidationListener> mergeValidationListeners,
+ PluginSetContext<MergeValidationListener> mergeValidationListeners,
ProjectConfigValidator.Factory projectConfigValidatorFactory,
AccountMergeValidator.Factory accountValidatorFactory,
GroupMergeValidator.Factory groupValidatorFactory) {
@@ -238,10 +238,10 @@
/** Execute merge validation plug-ins */
public static class PluginMergeValidationListener implements MergeValidationListener {
- private final DynamicSet<MergeValidationListener> mergeValidationListeners;
+ private final PluginSetContext<MergeValidationListener> mergeValidationListeners;
public PluginMergeValidationListener(
- DynamicSet<MergeValidationListener> mergeValidationListeners) {
+ PluginSetContext<MergeValidationListener> mergeValidationListeners) {
this.mergeValidationListeners = mergeValidationListeners;
}
@@ -254,9 +254,9 @@
PatchSet.Id patchSetId,
IdentifiedUser caller)
throws MergeValidationException {
- for (MergeValidationListener validator : mergeValidationListeners) {
- validator.onPreMerge(repo, commit, destProject, destBranch, patchSetId, caller);
- }
+ mergeValidationListeners.runEach(
+ l -> l.onPreMerge(repo, commit, destProject, destBranch, patchSetId, caller),
+ MergeValidationException.class);
}
}
diff --git a/java/com/google/gerrit/server/git/validators/OnSubmitValidators.java b/java/com/google/gerrit/server/git/validators/OnSubmitValidators.java
index 3a50a15..409240e 100644
--- a/java/com/google/gerrit/server/git/validators/OnSubmitValidators.java
+++ b/java/com/google/gerrit/server/git/validators/OnSubmitValidators.java
@@ -14,9 +14,9 @@
package com.google.gerrit.server.git.validators;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.git.validators.OnSubmitValidationListener.Arguments;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.submit.IntegrationException;
import com.google.gerrit.server.update.ChainedReceiveCommands;
import com.google.gerrit.server.validators.ValidationException;
@@ -29,10 +29,10 @@
OnSubmitValidators create();
}
- private final DynamicSet<OnSubmitValidationListener> listeners;
+ private final PluginSetContext<OnSubmitValidationListener> listeners;
@Inject
- OnSubmitValidators(DynamicSet<OnSubmitValidationListener> listeners) {
+ OnSubmitValidators(PluginSetContext<OnSubmitValidationListener> listeners) {
this.listeners = listeners;
}
@@ -41,11 +41,9 @@
throws IntegrationException {
try (RevWalk rw = new RevWalk(objectReader)) {
Arguments args = new Arguments(project, rw, commands);
- for (OnSubmitValidationListener listener : listeners) {
- listener.preBranchUpdate(args);
- }
+ listeners.runEach(l -> l.preBranchUpdate(args), ValidationException.class);
} catch (ValidationException e) {
- throw new IntegrationException(e.getMessage());
+ throw new IntegrationException(e.getMessage(), e);
}
}
}
diff --git a/java/com/google/gerrit/server/git/validators/RefOperationValidators.java b/java/com/google/gerrit/server/git/validators/RefOperationValidators.java
index 1df8da4..acae533 100644
--- a/java/com/google/gerrit/server/git/validators/RefOperationValidators.java
+++ b/java/com/google/gerrit/server/git/validators/RefOperationValidators.java
@@ -17,7 +17,6 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.flogger.FluentLogger;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Project;
@@ -28,6 +27,7 @@
import com.google.gerrit.server.permissions.GlobalPermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.validators.ValidationException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -52,14 +52,14 @@
private final PermissionBackend.WithUser perm;
private final AllUsersName allUsersName;
- private final DynamicSet<RefOperationValidationListener> refOperationValidationListeners;
+ private final PluginSetContext<RefOperationValidationListener> refOperationValidationListeners;
private final RefReceivedEvent event;
@Inject
RefOperationValidators(
PermissionBackend permissionBackend,
AllUsersName allUsersName,
- DynamicSet<RefOperationValidationListener> refOperationValidationListeners,
+ PluginSetContext<RefOperationValidationListener> refOperationValidationListeners,
@Assisted Project project,
@Assisted IdentifiedUser user,
@Assisted ReceiveCommand cmd) {
@@ -75,13 +75,11 @@
public List<ValidationMessage> validateForRefOperation() throws RefOperationValidationException {
List<ValidationMessage> messages = new ArrayList<>();
boolean withException = false;
- List<RefOperationValidationListener> listeners = new ArrayList<>();
- listeners.add(new DisallowCreationAndDeletionOfUserBranches(perm, allUsersName));
- refOperationValidationListeners.forEach(listeners::add);
try {
- for (RefOperationValidationListener listener : listeners) {
- messages.addAll(listener.onRefOperation(event));
- }
+ messages.addAll(
+ new DisallowCreationAndDeletionOfUserBranches(perm, allUsersName).onRefOperation(event));
+ refOperationValidationListeners.runEach(
+ l -> l.onRefOperation(event), ValidationException.class);
} catch (ValidationException e) {
messages.add(new ValidationMessage(e.getMessage(), true));
withException = true;
diff --git a/java/com/google/gerrit/server/git/validators/UploadValidators.java b/java/com/google/gerrit/server/git/validators/UploadValidators.java
index 84d4586..2595283 100644
--- a/java/com/google/gerrit/server/git/validators/UploadValidators.java
+++ b/java/com/google/gerrit/server/git/validators/UploadValidators.java
@@ -14,8 +14,8 @@
package com.google.gerrit.server.git.validators;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Project;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.validators.ValidationException;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -28,7 +28,7 @@
public class UploadValidators implements PreUploadHook {
- private final DynamicSet<UploadValidationListener> uploadValidationListeners;
+ private final PluginSetContext<UploadValidationListener> uploadValidationListeners;
private final Project project;
private final Repository repository;
private final String remoteHost;
@@ -39,7 +39,7 @@
@Inject
UploadValidators(
- DynamicSet<UploadValidationListener> uploadValidationListeners,
+ PluginSetContext<UploadValidationListener> uploadValidationListeners,
@Assisted Project project,
@Assisted Repository repository,
@Assisted String remoteHost) {
@@ -53,12 +53,12 @@
public void onSendPack(
UploadPack up, Collection<? extends ObjectId> wants, Collection<? extends ObjectId> haves)
throws ServiceMayNotContinueException {
- for (UploadValidationListener validator : uploadValidationListeners) {
- try {
- validator.onPreUpload(repository, project, remoteHost, up, wants, haves);
- } catch (ValidationException e) {
- throw new UploadValidationException(e.getMessage());
- }
+ try {
+ uploadValidationListeners.runEach(
+ l -> l.onPreUpload(repository, project, remoteHost, up, wants, haves),
+ ValidationException.class);
+ } catch (ValidationException e) {
+ throw new UploadValidationException(e.getMessage());
}
}
@@ -66,12 +66,12 @@
public void onBeginNegotiateRound(
UploadPack up, Collection<? extends ObjectId> wants, int cntOffered)
throws ServiceMayNotContinueException {
- for (UploadValidationListener validator : uploadValidationListeners) {
- try {
- validator.onBeginNegotiate(repository, project, remoteHost, up, wants, cntOffered);
- } catch (ValidationException e) {
- throw new UploadValidationException(e.getMessage());
- }
+ try {
+ uploadValidationListeners.runEach(
+ l -> l.onBeginNegotiate(repository, project, remoteHost, up, wants, cntOffered),
+ ValidationException.class);
+ } catch (ValidationException e) {
+ throw new UploadValidationException(e.getMessage());
}
}
diff --git a/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java b/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java
index f8c17d1..e1b0edd 100644
--- a/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java
+++ b/java/com/google/gerrit/server/index/account/AccountIndexerImpl.java
@@ -18,13 +18,13 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.events.AccountIndexedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.index.Index;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.AccountState;
import com.google.gerrit.server.logging.TraceContext;
import com.google.gerrit.server.logging.TraceContext.TraceTimer;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import java.io.IOException;
@@ -42,7 +42,7 @@
}
private final AccountCache byIdCache;
- private final DynamicSet<AccountIndexedListener> indexedListener;
+ private final PluginSetContext<AccountIndexedListener> indexedListener;
private final StalenessChecker stalenessChecker;
@Nullable private final AccountIndexCollection indexes;
@Nullable private final AccountIndex index;
@@ -50,7 +50,7 @@
@AssistedInject
AccountIndexerImpl(
AccountCache byIdCache,
- DynamicSet<AccountIndexedListener> indexedListener,
+ PluginSetContext<AccountIndexedListener> indexedListener,
StalenessChecker stalenessChecker,
@Assisted AccountIndexCollection indexes) {
this.byIdCache = byIdCache;
@@ -63,7 +63,7 @@
@AssistedInject
AccountIndexerImpl(
AccountCache byIdCache,
- DynamicSet<AccountIndexedListener> indexedListener,
+ PluginSetContext<AccountIndexedListener> indexedListener,
StalenessChecker stalenessChecker,
@Assisted @Nullable AccountIndex index) {
this.byIdCache = byIdCache;
@@ -113,9 +113,7 @@
}
private void fireAccountIndexedEvent(int id) {
- for (AccountIndexedListener listener : indexedListener) {
- listener.onAccountIndexed(id);
- }
+ indexedListener.runEach(l -> l.onAccountIndexed(id));
}
private Collection<AccountIndex> getWriteIndexes() {
diff --git a/java/com/google/gerrit/server/index/change/ChangeIndexer.java b/java/com/google/gerrit/server/index/change/ChangeIndexer.java
index d0a9749..8f9dc06 100644
--- a/java/com/google/gerrit/server/index/change/ChangeIndexer.java
+++ b/java/com/google/gerrit/server/index/change/ChangeIndexer.java
@@ -14,7 +14,6 @@
package com.google.gerrit.server.index.change;
-import static com.google.gerrit.server.extensions.events.EventUtil.logEventListenerError;
import static com.google.gerrit.server.git.QueueProvider.QueueType.BATCH;
import com.google.common.flogger.FluentLogger;
@@ -24,7 +23,6 @@
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.events.ChangeIndexedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.index.Index;
import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.Project;
@@ -37,6 +35,7 @@
import com.google.gerrit.server.logging.TraceContext.TraceTimer;
import com.google.gerrit.server.notedb.ChangeNotes;
import com.google.gerrit.server.notedb.NotesMigration;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.util.RequestContext;
@@ -94,7 +93,7 @@
private final ThreadLocalRequestContext context;
private final ListeningExecutorService batchExecutor;
private final ListeningExecutorService executor;
- private final DynamicSet<ChangeIndexedListener> indexedListeners;
+ private final PluginSetContext<ChangeIndexedListener> indexedListeners;
private final StalenessChecker stalenessChecker;
private final boolean autoReindexIfStale;
@@ -106,7 +105,7 @@
ChangeNotes.Factory changeNotesFactory,
ChangeData.Factory changeDataFactory,
ThreadLocalRequestContext context,
- DynamicSet<ChangeIndexedListener> indexedListeners,
+ PluginSetContext<ChangeIndexedListener> indexedListeners,
StalenessChecker stalenessChecker,
@IndexExecutor(BATCH) ListeningExecutorService batchExecutor,
@Assisted ListeningExecutorService executor,
@@ -133,7 +132,7 @@
ChangeNotes.Factory changeNotesFactory,
ChangeData.Factory changeDataFactory,
ThreadLocalRequestContext context,
- DynamicSet<ChangeIndexedListener> indexedListeners,
+ PluginSetContext<ChangeIndexedListener> indexedListeners,
StalenessChecker stalenessChecker,
@IndexExecutor(BATCH) ListeningExecutorService batchExecutor,
@Assisted ListeningExecutorService executor,
@@ -227,23 +226,11 @@
}
private void fireChangeIndexedEvent(String projectName, int id) {
- for (ChangeIndexedListener listener : indexedListeners) {
- try {
- listener.onChangeIndexed(projectName, id);
- } catch (Exception e) {
- logEventListenerError(listener, e);
- }
- }
+ indexedListeners.runEach(l -> l.onChangeIndexed(projectName, id));
}
private void fireChangeDeletedFromIndexEvent(int id) {
- for (ChangeIndexedListener listener : indexedListeners) {
- try {
- listener.onChangeDeleted(id);
- } catch (Exception e) {
- logEventListenerError(listener, e);
- }
- }
+ indexedListeners.runEach(l -> l.onChangeDeleted(id));
}
/**
diff --git a/java/com/google/gerrit/server/index/group/GroupIndexerImpl.java b/java/com/google/gerrit/server/index/group/GroupIndexerImpl.java
index d6ba253..a9124e1 100644
--- a/java/com/google/gerrit/server/index/group/GroupIndexerImpl.java
+++ b/java/com/google/gerrit/server/index/group/GroupIndexerImpl.java
@@ -18,13 +18,13 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.events.GroupIndexedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.index.Index;
import com.google.gerrit.reviewdb.client.AccountGroup;
import com.google.gerrit.server.account.GroupCache;
import com.google.gerrit.server.group.InternalGroup;
import com.google.gerrit.server.logging.TraceContext;
import com.google.gerrit.server.logging.TraceContext.TraceTimer;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import java.io.IOException;
@@ -42,7 +42,7 @@
}
private final GroupCache groupCache;
- private final DynamicSet<GroupIndexedListener> indexedListener;
+ private final PluginSetContext<GroupIndexedListener> indexedListener;
private final StalenessChecker stalenessChecker;
@Nullable private final GroupIndexCollection indexes;
@Nullable private final GroupIndex index;
@@ -50,7 +50,7 @@
@AssistedInject
GroupIndexerImpl(
GroupCache groupCache,
- DynamicSet<GroupIndexedListener> indexedListener,
+ PluginSetContext<GroupIndexedListener> indexedListener,
StalenessChecker stalenessChecker,
@Assisted GroupIndexCollection indexes) {
this.groupCache = groupCache;
@@ -63,7 +63,7 @@
@AssistedInject
GroupIndexerImpl(
GroupCache groupCache,
- DynamicSet<GroupIndexedListener> indexedListener,
+ PluginSetContext<GroupIndexedListener> indexedListener,
StalenessChecker stalenessChecker,
@Assisted @Nullable GroupIndex index) {
this.groupCache = groupCache;
@@ -113,9 +113,7 @@
}
private void fireGroupIndexedEvent(String uuid) {
- for (GroupIndexedListener listener : indexedListener) {
- listener.onGroupIndexed(uuid);
- }
+ indexedListener.runEach(l -> l.onGroupIndexed(uuid));
}
private Collection<GroupIndex> getWriteIndexes() {
diff --git a/java/com/google/gerrit/server/index/project/ProjectIndexerImpl.java b/java/com/google/gerrit/server/index/project/ProjectIndexerImpl.java
index c2a28af..1a74eca 100644
--- a/java/com/google/gerrit/server/index/project/ProjectIndexerImpl.java
+++ b/java/com/google/gerrit/server/index/project/ProjectIndexerImpl.java
@@ -18,7 +18,6 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.extensions.events.ProjectIndexedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.index.project.ProjectData;
import com.google.gerrit.index.project.ProjectIndex;
import com.google.gerrit.index.project.ProjectIndexCollection;
@@ -26,6 +25,7 @@
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.logging.TraceContext;
import com.google.gerrit.server.logging.TraceContext.TraceTimer;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
import com.google.inject.assistedinject.Assisted;
@@ -44,14 +44,14 @@
}
private final ProjectCache projectCache;
- private final DynamicSet<ProjectIndexedListener> indexedListener;
+ private final PluginSetContext<ProjectIndexedListener> indexedListener;
@Nullable private final ProjectIndexCollection indexes;
@Nullable private final ProjectIndex index;
@AssistedInject
ProjectIndexerImpl(
ProjectCache projectCache,
- DynamicSet<ProjectIndexedListener> indexedListener,
+ PluginSetContext<ProjectIndexedListener> indexedListener,
@Assisted ProjectIndexCollection indexes) {
this.projectCache = projectCache;
this.indexedListener = indexedListener;
@@ -62,7 +62,7 @@
@AssistedInject
ProjectIndexerImpl(
ProjectCache projectCache,
- DynamicSet<ProjectIndexedListener> indexedListener,
+ PluginSetContext<ProjectIndexedListener> indexedListener,
@Assisted @Nullable ProjectIndex index) {
this.projectCache = projectCache;
this.indexedListener = indexedListener;
@@ -99,9 +99,7 @@
}
private void fireProjectIndexedEvent(String name) {
- for (ProjectIndexedListener listener : indexedListener) {
- listener.onProjectIndexed(name);
- }
+ indexedListener.runEach(l -> l.onProjectIndexed(name));
}
private Collection<ProjectIndex> getWriteIndexes() {
diff --git a/java/com/google/gerrit/server/logging/TraceContext.java b/java/com/google/gerrit/server/logging/TraceContext.java
index d688740..614bf9a 100644
--- a/java/com/google/gerrit/server/logging/TraceContext.java
+++ b/java/com/google/gerrit/server/logging/TraceContext.java
@@ -94,6 +94,8 @@
* </pre>
*/
public class TraceContext implements AutoCloseable {
+ private static final String PLUGIN_TAG = "PLUGIN";
+
public static TraceContext open() {
return new TraceContext();
}
@@ -260,6 +262,10 @@
return this;
}
+ public TraceContext addPluginTag(String pluginName) {
+ return addTag(PLUGIN_TAG, pluginName);
+ }
+
public TraceContext forceLogging() {
if (stopForceLoggingOnClose) {
return this;
diff --git a/java/com/google/gerrit/server/plugincontext/PluginContext.java b/java/com/google/gerrit/server/plugincontext/PluginContext.java
new file mode 100644
index 0000000..f1e2358
--- /dev/null
+++ b/java/com/google/gerrit/server/plugincontext/PluginContext.java
@@ -0,0 +1,330 @@
+// Copyright (C) 2018 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.plugincontext;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.common.base.Throwables;
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.extensions.registration.DynamicItem;
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.registration.Extension;
+import com.google.gerrit.server.logging.TraceContext;
+
+/**
+ * Context for invoking plugin extensions.
+ *
+ * <p>Invoking a plugin extension through a PluginContext sets a logging tag with the plugin name is
+ * set. This way any errors that are triggered by the plugin extension (even if they happen in
+ * Gerrit code which is called by the plugin extension) can be easily attributed to the plugin.
+ *
+ * <p>If possible plugin extensions should be invoked through:
+ *
+ * <ul>
+ * <li>{@link PluginItemContext} for extensions from {@link DynamicItem}
+ * <li>{@link PluginSetContext} for extensions from {@link DynamicSet}
+ * <li>{@link PluginMapContext} for extensions from {@link DynamicMap}
+ * </ul>
+ *
+ * <p>A plugin context can be manually opened by invoking the newTrace methods. This should only be
+ * needed if an extension throws multiple exceptions that need to be handled:
+ *
+ * <pre>
+ * public interface Foo {
+ * void doFoo() throws Exception1, Exception2, Exception3;
+ * }
+ *
+ * ...
+ *
+ * for (Extension<Foo> fooExtension : fooDynamicMap) {
+ * try (TraceContext traceContext = PluginContext.newTrace(fooExtension)) {
+ * fooExtension.get().doFoo();
+ * }
+ * }
+ * </pre>
+ *
+ * <p>This class hosts static methods with generic functionality to invoke plugin extensions with a
+ * trace context that are commonly used by {@link PluginItemContext}, {@link PluginSetContext} and
+ * {@link PluginMapContext}.
+ *
+ * <p>The run* methods execute an extension but don't deliver a result back to the caller.
+ * Exceptions can be caught and logged.
+ *
+ * <p>The call* methods execute an extension and deliver a result back to the caller.
+ */
+public class PluginContext<T> {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ @FunctionalInterface
+ public interface ExtensionImplConsumer<T> {
+ void run(T t) throws Exception;
+ }
+
+ @FunctionalInterface
+ public interface ExtensionImplFunction<T, R> {
+ R call(T input);
+ }
+
+ @FunctionalInterface
+ public interface CheckedExtensionImplFunction<T, R, X extends Exception> {
+ R call(T input) throws X;
+ }
+
+ @FunctionalInterface
+ public interface ExtensionConsumer<T extends Extension<?>> {
+ void run(T extension) throws Exception;
+ }
+
+ @FunctionalInterface
+ public interface ExtensionFunction<T extends Extension<?>, R> {
+ R call(T extension);
+ }
+
+ @FunctionalInterface
+ public interface CheckedExtensionFunction<T extends Extension<?>, R, X extends Exception> {
+ R call(T extension) throws X;
+ }
+
+ /**
+ * Opens a new trace context for invoking a plugin extension.
+ *
+ * @param dynamicItem dynamic item that holds the extension implementation that is being invoked
+ * from within the trace context
+ * @return the created trace context
+ */
+ public static <T> TraceContext newTrace(DynamicItem<T> dynamicItem) {
+ Extension<T> extension = dynamicItem.getEntry();
+ if (extension == null) {
+ return TraceContext.open();
+ }
+ return newTrace(extension);
+ }
+
+ /**
+ * Opens a new trace context for invoking a plugin extension.
+ *
+ * @param extension extension that is being invoked from within the trace context
+ * @return the created trace context
+ */
+ public static <T> TraceContext newTrace(Extension<T> extension) {
+ return TraceContext.open().addPluginTag(checkNotNull(extension).getPluginName());
+ }
+
+ /**
+ * Runs a plugin extension. All exceptions from the plugin extension are caught and logged.
+ *
+ * <p>The consumer gets the extension implementation provided that should be invoked.
+ *
+ * @param extension extension that is being invoked
+ * @param extensionImplConsumer the consumer that invokes the extension
+ */
+ static <T> void runLogExceptions(
+ Extension<T> extension, ExtensionImplConsumer<T> extensionImplConsumer) {
+ T extensionImpl = extension.get();
+ if (extensionImpl == null) {
+ return;
+ }
+
+ try (TraceContext traceContext = newTrace(extension)) {
+ extensionImplConsumer.run(extensionImpl);
+ } catch (Throwable e) {
+ logger.atWarning().withCause(e).log(
+ "Failure in %s of plugin %s", extensionImpl.getClass(), extension.getPluginName());
+ }
+ }
+
+ /**
+ * Runs a plugin extension. All exceptions from the plugin extension are caught and logged.
+ *
+ * <p>The consumer get the {@link Extension} provided that should be invoked. The extension
+ * provides access to the plugin name and the export name.
+ *
+ * @param extension extension that is being invoked
+ * @param extensionConsumer the consumer that invokes the extension
+ */
+ static <T> void runLogExceptions(
+ Extension<T> extension, ExtensionConsumer<Extension<T>> extensionConsumer) {
+ T extensionImpl = extension.get();
+ if (extensionImpl == null) {
+ return;
+ }
+
+ try (TraceContext traceContext = newTrace(extension)) {
+ extensionConsumer.run(extension);
+ } catch (Throwable e) {
+ logger.atWarning().withCause(e).log(
+ "Failure in %s of plugin %s", extensionImpl.getClass(), extension.getPluginName());
+ }
+ }
+
+ /**
+ * Runs a plugin extension. All exceptions from the plugin extension except exceptions of the
+ * specified type are caught and logged. Exceptions of the specified type are thrown and must be
+ * handled by the caller.
+ *
+ * <p>The consumer gets the extension implementation provided that should be invoked.
+ *
+ * @param extension extension that is being invoked
+ * @param extensionImplConsumer the consumer that invokes the extension
+ * @param exceptionClass type of the exceptions that should be thrown
+ * @throws X expected exception from the plugin extension
+ */
+ static <T, X extends Exception> void runLogExceptions(
+ Extension<T> extension,
+ ExtensionImplConsumer<T> extensionImplConsumer,
+ Class<X> exceptionClass)
+ throws X {
+ T extensionImpl = extension.get();
+ if (extensionImpl == null) {
+ return;
+ }
+
+ try (TraceContext traceContext = newTrace(extension)) {
+ extensionImplConsumer.run(extensionImpl);
+ } catch (Throwable e) {
+ Throwables.throwIfInstanceOf(e, exceptionClass);
+ Throwables.throwIfUnchecked(e);
+ logger.atWarning().withCause(e).log(
+ "Failure in %s of plugin invoke%s", extensionImpl.getClass(), extension.getPluginName());
+ }
+ }
+
+ /**
+ * Runs a plugin extension. All exceptions from the plugin extension except exceptions of the
+ * specified type are caught and logged. Exceptions of the specified type are thrown and must be
+ * handled by the caller.
+ *
+ * <p>The consumer get the {@link Extension} provided that should be invoked. The extension
+ * provides access to the plugin name and the export name.
+ *
+ * @param extension extension that is being invoked
+ * @param extensionConsumer the consumer that invokes the extension
+ * @param exceptionClass type of the exceptions that should be thrown
+ * @throws X expected exception from the plugin extension
+ */
+ static <T, X extends Exception> void runLogExceptions(
+ Extension<T> extension,
+ ExtensionConsumer<Extension<T>> extensionConsumer,
+ Class<X> exceptionClass)
+ throws X {
+ T extensionImpl = extension.get();
+ if (extensionImpl == null) {
+ return;
+ }
+
+ try (TraceContext traceContext = newTrace(extension)) {
+ extensionConsumer.run(extension);
+ } catch (Throwable e) {
+ Throwables.throwIfInstanceOf(e, exceptionClass);
+ Throwables.throwIfUnchecked(e);
+ logger.atWarning().withCause(e).log(
+ "Failure in %s of plugin %s", extensionImpl.getClass(), extension.getPluginName());
+ }
+ }
+
+ /**
+ * Calls a plugin extension and returns the result from the plugin extension call.
+ *
+ * <p>The function gets the extension implementation provided that should be invoked.
+ *
+ * @param extension extension that is being invoked
+ * @param extensionImplFunction function that invokes the extension
+ * @return the result from the plugin extension
+ */
+ static <T, R> R call(Extension<T> extension, ExtensionImplFunction<T, R> extensionImplFunction) {
+ try (TraceContext traceContext = newTrace(extension)) {
+ return extensionImplFunction.call(extension.get());
+ }
+ }
+
+ /**
+ * Calls a plugin extension and returns the result from the plugin extension call. Exceptions of
+ * the specified type are thrown and must be handled by the caller.
+ *
+ * <p>The function gets the extension implementation provided that should be invoked.
+ *
+ * @param extension extension that is being invoked
+ * @param checkedExtensionImplFunction function that invokes the extension
+ * @param exceptionClass type of the exceptions that should be thrown
+ * @return the result from the plugin extension
+ * @throws X expected exception from the plugin extension
+ */
+ static <T, R, X extends Exception> R call(
+ Extension<T> extension,
+ CheckedExtensionImplFunction<T, R, X> checkedExtensionImplFunction,
+ Class<X> exceptionClass)
+ throws X {
+ try (TraceContext traceContext = newTrace(extension)) {
+ try {
+ return checkedExtensionImplFunction.call(extension.get());
+ } catch (Exception e) {
+ // The only exception that can be thrown is X, but we cannot catch X since it is a generic
+ // type.
+ Throwables.throwIfInstanceOf(e, exceptionClass);
+ Throwables.throwIfUnchecked(e);
+ throw new IllegalStateException("unexpected exception: " + e.getMessage(), e);
+ }
+ }
+ }
+
+ /**
+ * Calls a plugin extension and returns the result from the plugin extension call.
+ *
+ * <p>The function get the {@link Extension} provided that should be invoked. The extension
+ * provides access to the plugin name and the export name.
+ *
+ * @param extension extension that is being invoked
+ * @param extensionFunction function that invokes the extension
+ * @return the result from the plugin extension
+ */
+ static <T, R> R call(
+ Extension<T> extension, ExtensionFunction<Extension<T>, R> extensionFunction) {
+ try (TraceContext traceContext = newTrace(extension)) {
+ return extensionFunction.call(extension);
+ }
+ }
+
+ /**
+ * Calls a plugin extension and returns the result from the plugin extension call. Exceptions of
+ * the specified type are thrown and must be handled by the caller.
+ *
+ * <p>The function get the {@link Extension} provided that should be invoked. The extension
+ * provides access to the plugin name and the export name.
+ *
+ * @param extension extension that is being invoked
+ * @param checkedExtensionFunction function that invokes the extension
+ * @param exceptionClass type of the exceptions that should be thrown
+ * @return the result from the plugin extension
+ * @throws X expected exception from the plugin extension
+ */
+ static <T, R, X extends Exception> R call(
+ Extension<T> extension,
+ CheckedExtensionFunction<Extension<T>, R, X> checkedExtensionFunction,
+ Class<X> exceptionClass)
+ throws X {
+ try (TraceContext traceContext = newTrace(extension)) {
+ try {
+ return checkedExtensionFunction.call(extension);
+ } catch (Exception e) {
+ // The only exception that can be thrown is X, but we cannot catch X since it is a generic
+ // type.
+ Throwables.throwIfInstanceOf(e, exceptionClass);
+ Throwables.throwIfUnchecked(e);
+ throw new IllegalStateException("unexpected exception: " + e.getMessage(), e);
+ }
+ }
+ }
+}
diff --git a/java/com/google/gerrit/server/plugincontext/PluginItemContext.java b/java/com/google/gerrit/server/plugincontext/PluginItemContext.java
new file mode 100644
index 0000000..1bb1f2a
--- /dev/null
+++ b/java/com/google/gerrit/server/plugincontext/PluginItemContext.java
@@ -0,0 +1,180 @@
+// Copyright (C) 2018 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.plugincontext;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.gerrit.common.Nullable;
+import com.google.gerrit.extensions.registration.DynamicItem;
+import com.google.gerrit.extensions.registration.Extension;
+import com.google.gerrit.server.plugincontext.PluginContext.CheckedExtensionImplFunction;
+import com.google.gerrit.server.plugincontext.PluginContext.ExtensionImplConsumer;
+import com.google.gerrit.server.plugincontext.PluginContext.ExtensionImplFunction;
+import com.google.inject.Inject;
+
+/**
+ * Context to invoke an extension from a {@link DynamicItem}.
+ *
+ * <p>When the plugin extension is invoked a logging tag with the plugin name is set. This way any
+ * errors that are triggered by the plugin extension (even if they happen in Gerrit code which is
+ * called by the plugin extension) can be easily attributed to the plugin.
+ *
+ * <p>The run* methods execute an extension but don't deliver a result back to the caller.
+ * Exceptions can be caught and logged.
+ *
+ * <p>The call* methods execute an extension and deliver a result back to the caller.
+ *
+ * <p>Example if all exceptions should be caught and logged:
+ *
+ * <pre>
+ * fooPluginItemContext.run(foo -> foo.doFoo());
+ * </pre>
+ *
+ * <p>Example if all exceptions, but one, should be caught and logged:
+ *
+ * <pre>
+ * try {
+ * fooPluginItemContext.run(foo -> foo.doFoo(), MyException.class);
+ * } catch (MyException e) {
+ * // handle the exception
+ * }
+ * </pre>
+ *
+ * <p>Example if return values should be handled:
+ *
+ * <pre>
+ * Object result = fooPluginItemContext.call(foo -> foo.getFoo());
+ * </pre>
+ *
+ * <p>Example if return values and a single exception should be handled:
+ *
+ * <pre>
+ * Object result;
+ * try {
+ * result = fooPluginItemContext.call(foo -> foo.getFoo(), MyException.class);
+ * } catch (MyException e) {
+ * // handle the exception
+ * }
+ * </pre>
+ *
+ * <p>Example if several exceptions should be handled:
+ *
+ * <pre>
+ * try (TraceContext traceContext = PluginContext.newTrace(fooDynamicItem.getEntry())) {
+ * fooDynamicItem.get().doFoo();
+ * } catch (MyException1 | MyException2 | MyException3 e) {
+ * // handle the exception
+ * }
+ * </pre>
+ */
+public class PluginItemContext<T> {
+ @Nullable private final DynamicItem<T> dynamicItem;
+
+ @VisibleForTesting
+ @Inject
+ public PluginItemContext(DynamicItem<T> dynamicItem) {
+ this.dynamicItem = dynamicItem;
+ }
+
+ /**
+ * Returns the name of the plugin that registered the extension.
+ *
+ * @return the plugin name, {@code null} if no implementation is registered for this extension
+ * point
+ */
+ @Nullable
+ public String getPluginName() {
+ return dynamicItem.getPluginName();
+ }
+
+ /**
+ * Invokes the plugin extension of the item. All exceptions from the plugin extension are caught
+ * and logged.
+ *
+ * <p>The consumer gets the extension implementation provided that should be invoked.
+ *
+ * <p>No-op if no implementation is registered for this extension point.
+ *
+ * @param extensionImplConsumer consumer that invokes the extension
+ */
+ public void run(ExtensionImplConsumer<T> extensionImplConsumer) {
+ Extension<T> extension = dynamicItem.getEntry();
+ if (extension == null) {
+ return;
+ }
+ PluginContext.runLogExceptions(extension, extensionImplConsumer);
+ }
+
+ /**
+ * Invokes the plugin extension of the item. All exceptions from the plugin extension are caught
+ * and logged.
+ *
+ * <p>The consumer gets the extension implementation provided that should be invoked.
+ *
+ * <p>No-op if no implementation is registered for this extension point.
+ *
+ * @param extensionImplConsumer consumer that invokes the extension
+ * @param exceptionClass type of the exceptions that should be thrown
+ * @throws X expected exception from the plugin extension
+ */
+ public <X extends Exception> void run(
+ ExtensionImplConsumer<T> extensionImplConsumer, Class<X> exceptionClass) throws X {
+ Extension<T> extension = dynamicItem.getEntry();
+ if (extension == null) {
+ return;
+ }
+ PluginContext.runLogExceptions(extension, extensionImplConsumer, exceptionClass);
+ }
+
+ /**
+ * Calls the plugin extension of the item and returns the result from the plugin extension call.
+ *
+ * <p>The function gets the extension implementation provided that should be invoked.
+ *
+ * <p>Fails with {@link IllegalStateException} if no implementation is registered for the item.
+ *
+ * @param extensionImplFunction function that invokes the extension
+ * @return the result from the plugin extension
+ * @throws IllegalStateException if no implementation is registered for the item
+ */
+ public <R> R call(ExtensionImplFunction<T, R> extensionImplFunction) {
+ Extension<T> extension = dynamicItem.getEntry();
+ checkState(extension != null);
+ return PluginContext.call(extension, extensionImplFunction);
+ }
+
+ /**
+ * Calls the plugin extension of the item and returns the result from the plugin extension call.
+ * Exceptions of the specified type are thrown and must be handled by the caller.
+ *
+ * <p>The function gets the extension implementation provided that should be invoked.
+ *
+ * <p>Fails with {@link IllegalStateException} if no implementation is registered for the item.
+ *
+ * @param checkedExtensionImplFunction function that invokes the extension
+ * @param exceptionClass type of the exceptions that should be thrown
+ * @return the result from the plugin extension
+ * @throws X expected exception from the plugin extension
+ * @throws IllegalStateException if no implementation is registered for the item
+ */
+ public <R, X extends Exception> R call(
+ CheckedExtensionImplFunction<T, R, X> checkedExtensionImplFunction, Class<X> exceptionClass)
+ throws X {
+ Extension<T> extension = dynamicItem.getEntry();
+ checkState(extension != null);
+ return PluginContext.call(extension, checkedExtensionImplFunction, exceptionClass);
+ }
+}
diff --git a/java/com/google/gerrit/server/plugincontext/PluginMapContext.java b/java/com/google/gerrit/server/plugincontext/PluginMapContext.java
new file mode 100644
index 0000000..4c99f7e
--- /dev/null
+++ b/java/com/google/gerrit/server/plugincontext/PluginMapContext.java
@@ -0,0 +1,172 @@
+// Copyright (C) 2018 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.plugincontext;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Iterators;
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.Extension;
+import com.google.gerrit.server.plugincontext.PluginContext.ExtensionConsumer;
+import com.google.inject.Inject;
+import java.util.Iterator;
+import java.util.SortedSet;
+
+/**
+ * Context to invoke extensions from a {@link DynamicMap}.
+ *
+ * <p>When a plugin extension is invoked a logging tag with the plugin name is set. This way any
+ * errors that are triggered by the plugin extension (even if they happen in Gerrit code which is
+ * called by the plugin extension) can be easily attributed to the plugin.
+ *
+ * <p>Example if all exceptions should be caught and logged:
+ *
+ * <pre>
+ * Map<String, Object> results = new HashMap<>();
+ * fooPluginMapContext.runEach(
+ * extension -> results.put(extension.getExportName(), extension.get().getFoo());
+ * </pre>
+ *
+ * <p>Example if all exceptions, but one, should be caught and logged:
+ *
+ * <pre>
+ * Map<String, Object> results = new HashMap<>();
+ * try {
+ * fooPluginMapContext.runEach(
+ * extension -> results.put(extension.getExportName(), extension.get().getFoo(),
+ * MyException.class);
+ * } catch (MyException e) {
+ * // handle the exception
+ * }
+ * </pre>
+ *
+ * <p>Example if return values should be handled:
+ *
+ * <pre>
+ * Map<String, Object> results = new HashMap<>();
+ * for (PluginMapEntryContext<Foo> c : fooPluginMapContext) {
+ * if (c.call(extension -> extension.get().handles(x))) {
+ * c.run(extension -> results.put(extension.getExportName(), extension.get().getFoo());
+ * }
+ * }
+ * </pre>
+ *
+ * <p>Example if return values and a single exception should be handled:
+ *
+ * <pre>
+ * Map<String, Object> results = new HashMap<>();
+ * try {
+ * for (PluginMapEntryContext<Foo> c : fooPluginMapContext) {
+ * if (c.call(extension -> extension.handles(x), MyException.class)) {
+ * c.run(extension -> results.put(extension.getExportName(), extension.get().getFoo(),
+ * MyException.class);
+ * }
+ * }
+ * } catch (MyException e) {
+ * // handle the exception
+ * }
+ * </pre>
+ *
+ * <p>Example if several exceptions should be handled:
+ *
+ * <pre>
+ * for (Extension<Foo> fooExtension : fooDynamicMap) {
+ * try (TraceContext traceContext = PluginContext.newTrace(fooExtension)) {
+ * fooExtension.get().doFoo();
+ * } catch (MyException1 | MyException2 | MyException3 e) {
+ * // handle the exception
+ * }
+ * }
+ * </pre>
+ */
+public class PluginMapContext<T> implements Iterable<PluginMapEntryContext<T>> {
+ private final DynamicMap<T> dynamicMap;
+
+ @VisibleForTesting
+ @Inject
+ public PluginMapContext(DynamicMap<T> dynamicMap) {
+ this.dynamicMap = dynamicMap;
+ }
+
+ /**
+ * Iterator that provides contexts for invoking the extensions in this map.
+ *
+ * <p>This is useful if:
+ *
+ * <ul>
+ * <li>invoking of each extension returns a result that should be handled
+ * <li>a sequence of invocations should be done on each extension
+ * </ul>
+ */
+ @Override
+ public Iterator<PluginMapEntryContext<T>> iterator() {
+ return Iterators.transform(dynamicMap.iterator(), PluginMapEntryContext<T>::new);
+ }
+
+ /**
+ * Checks if no implementations for this extension point have been registered.
+ *
+ * @return {@code true} if no implementations for this extension point have been registered,
+ * otherwise {@code false}
+ */
+ public boolean isEmpty() {
+ return !dynamicMap.iterator().hasNext();
+ }
+
+ /**
+ * Returns a sorted list of the plugins that have registered implementations for this extension
+ * point.
+ *
+ * @return sorted list of the plugins that have registered implementations for this extension
+ * point
+ */
+ public SortedSet<String> plugins() {
+ return dynamicMap.plugins();
+ }
+
+ /**
+ * Invokes each extension in the map. All exceptions from the plugin extensions are caught and
+ * logged.
+ *
+ * <p>The consumer get the {@link Extension} provided that should be invoked. The extension
+ * provides access to the plugin name and the export name.
+ *
+ * <p>All extension in the map are invoked, even if invoking some of the extensions failed.
+ *
+ * @param extensionConsumer consumer that invokes the extension
+ */
+ public void runEach(ExtensionConsumer<Extension<T>> extensionConsumer) {
+ dynamicMap.forEach(p -> PluginContext.runLogExceptions(p, extensionConsumer));
+ }
+
+ /**
+ * Invokes each extension in the map. All exceptions from the plugin extensions except exceptions
+ * of the specified type are caught and logged.
+ *
+ * <p>The consumer get the {@link Extension} provided that should be invoked. The extension
+ * provides access to the plugin name and the export name.
+ *
+ * <p>All extension in the map are invoked, even if invoking some of the extensions failed.
+ *
+ * @param extensionConsumer consumer that invokes the extension
+ * @param exceptionClass type of the exceptions that should be thrown
+ * @throws X expected exception from the plugin extension
+ */
+ public <X extends Exception> void runEach(
+ ExtensionConsumer<Extension<T>> extensionConsumer, Class<X> exceptionClass) throws X {
+ for (Extension<T> extension : dynamicMap) {
+ PluginContext.runLogExceptions(extension, extensionConsumer, exceptionClass);
+ }
+ }
+}
diff --git a/java/com/google/gerrit/server/plugincontext/PluginMapEntryContext.java b/java/com/google/gerrit/server/plugincontext/PluginMapEntryContext.java
new file mode 100644
index 0000000..d772a51
--- /dev/null
+++ b/java/com/google/gerrit/server/plugincontext/PluginMapEntryContext.java
@@ -0,0 +1,170 @@
+// Copyright (C) 2018 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.plugincontext;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.gerrit.extensions.registration.DynamicMap;
+import com.google.gerrit.extensions.registration.Extension;
+import com.google.gerrit.server.plugincontext.PluginContext.CheckedExtensionFunction;
+import com.google.gerrit.server.plugincontext.PluginContext.ExtensionConsumer;
+import com.google.gerrit.server.plugincontext.PluginContext.ExtensionFunction;
+
+/**
+ * Context to invoke an extension from {@link DynamicMap}.
+ *
+ * <p>When the plugin extension is invoked a logging tag with the plugin name is set. This way any
+ * errors that are triggered by the plugin extension (even if they happen in Gerrit code which is
+ * called by the plugin extension) can be easily attributed to the plugin.
+ *
+ * <p>The run* methods execute the extension but don't deliver a result back to the caller.
+ * Exceptions can be caught and logged.
+ *
+ * <p>The call* methods execute the extension and deliver a result back to the caller.
+ *
+ * <pre>
+ * Map<String, Object> results = new HashMap<>();
+ * fooPluginMapEntryContext.run(
+ * extension -> results.put(extension.getExportName(), extension.get().getFoo());
+ * </pre>
+ *
+ * <p>Example if all exceptions, but one, should be caught and logged:
+ *
+ * <pre>
+ * Map<String, Object> results = new HashMap<>();
+ * try {
+ * fooPluginMapEntryContext.run(
+ * extension -> results.put(extension.getExportName(), extension.get().getFoo(),
+ * MyException.class);
+ * } catch (MyException e) {
+ * // handle the exception
+ * }
+ * </pre>
+ *
+ * <p>Example if return values should be handled:
+ *
+ * <pre>
+ * Object result = fooPluginMapEntryContext.call(extension -> extension.get().getFoo());
+ * </pre>
+ *
+ * <p>Example if return values and a single exception should be handled:
+ *
+ * <pre>
+ * Object result;
+ * try {
+ * result = fooPluginMapEntryContext.call(extension -> extension.get().getFoo(), MyException.class);
+ * } catch (MyException e) {
+ * // handle the exception
+ * }
+ * </pre>
+ *
+ * <p>Example if several exceptions should be handled:
+ *
+ * <pre>
+ * for (Extension<Foo> fooExtension : fooDynamicMap) {
+ * try (TraceContext traceContext = PluginContext.newTrace(fooExtension)) {
+ * fooExtension.get().doFoo();
+ * } catch (MyException1 | MyException2 | MyException3 e) {
+ * // handle the exception
+ * }
+ * }
+ * </pre>
+ */
+public class PluginMapEntryContext<T> {
+ private final Extension<T> extension;
+
+ PluginMapEntryContext(Extension<T> extension) {
+ checkNotNull(extension);
+ checkNotNull(extension.getExportName(), "export name must be set for plugin map entries");
+ this.extension = extension;
+ }
+
+ /**
+ * Returns the name of the plugin that registered this map entry.
+ *
+ * @return the plugin name
+ */
+ public String getPluginName() {
+ return extension.getPluginName();
+ }
+
+ /**
+ * Returns the export name for which this map entry was registered.
+ *
+ * @return the export name
+ */
+ public String getExportName() {
+ return extension.getExportName();
+ }
+
+ /**
+ * Invokes the plugin extension. All exceptions from the plugin extension are caught and logged.
+ *
+ * <p>The consumer get the {@link Extension} provided that should be invoked. The extension
+ * provides access to the plugin name and the export name.
+ *
+ * @param extensionConsumer consumer that invokes the extension
+ */
+ public void run(ExtensionConsumer<Extension<T>> extensionConsumer) {
+ PluginContext.runLogExceptions(extension, extensionConsumer);
+ }
+
+ /**
+ * Invokes the plugin extension. All exceptions from the plugin extension are caught and logged.
+ *
+ * <p>The consumer get the {@link Extension} provided that should be invoked. The extension
+ * provides access to the plugin name and the export name.
+ *
+ * @param extensionConsumer consumer that invokes the extension
+ * @param exceptionClass type of the exceptions that should be thrown
+ * @throws X expected exception from the plugin extension
+ */
+ public <X extends Exception> void run(
+ ExtensionConsumer<Extension<T>> extensionConsumer, Class<X> exceptionClass) throws X {
+ PluginContext.runLogExceptions(extension, extensionConsumer, exceptionClass);
+ }
+
+ /**
+ * Calls the plugin extension and returns the result from the plugin extension call.
+ *
+ * <p>The consumer get the {@link Extension} provided that should be invoked. The extension
+ * provides access to the plugin name and the export name.
+ *
+ * @param extensionFunction function that invokes the extension
+ * @return the result from the plugin extension
+ */
+ public <R> R call(ExtensionFunction<Extension<T>, R> extensionFunction) {
+ return PluginContext.call(extension, extensionFunction);
+ }
+
+ /**
+ * Calls the plugin extension and returns the result from the plugin extension call. Exceptions of
+ * the specified type are thrown and must be handled by the caller.
+ *
+ * <p>The consumer get the {@link Extension} provided that should be invoked. The extension
+ * provides access to the plugin name and the export name.
+ *
+ * @param checkedExtensionFunction function that invokes the extension
+ * @param exceptionClass type of the exceptions that should be thrown
+ * @return the result from the plugin extension
+ * @throws X expected exception from the plugin extension
+ */
+ public <R, X extends Exception> R call(
+ CheckedExtensionFunction<Extension<T>, R, X> checkedExtensionFunction,
+ Class<X> exceptionClass)
+ throws X {
+ return PluginContext.call(extension, checkedExtensionFunction, exceptionClass);
+ }
+}
diff --git a/java/com/google/gerrit/server/plugincontext/PluginSetContext.java b/java/com/google/gerrit/server/plugincontext/PluginSetContext.java
new file mode 100644
index 0000000..bfcfac7
--- /dev/null
+++ b/java/com/google/gerrit/server/plugincontext/PluginSetContext.java
@@ -0,0 +1,162 @@
+// Copyright (C) 2018 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.plugincontext;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.Iterators;
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.registration.Extension;
+import com.google.gerrit.server.plugincontext.PluginContext.ExtensionImplConsumer;
+import com.google.inject.Inject;
+import java.util.Iterator;
+import java.util.SortedSet;
+
+/**
+ * Context to invoke extensions from a {@link DynamicSet}.
+ *
+ * <p>When a plugin extension is invoked a logging tag with the plugin name is set. This way any
+ * errors that are triggered by the plugin extension (even if they happen in Gerrit code which is
+ * called by the plugin extension) can be easily attributed to the plugin.
+ *
+ * <p>Example if all exceptions should be caught and logged:
+ *
+ * <pre>
+ * fooPluginSetContext.runEach(foo -> foo.doFoo());
+ * </pre>
+ *
+ * <p>Example if all exceptions, but one, should be caught and logged:
+ *
+ * <pre>
+ * try {
+ * fooPluginSetContext.runEach(foo -> foo.doFoo(), MyException.class);
+ * } catch (MyException e) {
+ * // handle the exception
+ * }
+ * </pre>
+ *
+ * <p>Example if return values should be handled:
+ *
+ * <pre>
+ * for (PluginSetEntryContext<Foo> c : fooPluginSetContext) {
+ * if (c.call(foo -> foo.handles(x))) {
+ * c.run(foo -> foo.doFoo());
+ * }
+ * }
+ * </pre>
+ *
+ * <p>Example if return values and a single exception should be handled:
+ *
+ * <pre>
+ * try {
+ * for (PluginSetEntryContext<Foo> c : fooPluginSetContext) {
+ * if (c.call(foo -> foo.handles(x), MyException.class)) {
+ * c.run(foo -> foo.doFoo(), MyException.class);
+ * }
+ * }
+ * } catch (MyException e) {
+ * // handle the exception
+ * }
+ * </pre>
+ *
+ * <p>Example if several exceptions should be handled:
+ *
+ * <pre>
+ * for (Extension<Foo> fooExtension : fooDynamicSet.entries()) {
+ * try (TraceContext traceContext = PluginContext.newTrace(fooExtension)) {
+ * fooExtension.get().doFoo();
+ * } catch (MyException1 | MyException2 | MyException3 e) {
+ * // handle the exception
+ * }
+ * }
+ * </pre>
+ */
+public class PluginSetContext<T> implements Iterable<PluginSetEntryContext<T>> {
+ private final DynamicSet<T> dynamicSet;
+
+ @VisibleForTesting
+ @Inject
+ public PluginSetContext(DynamicSet<T> dynamicSet) {
+ this.dynamicSet = dynamicSet;
+ }
+
+ /**
+ * Iterator that provides contexts for invoking the extensions in this set.
+ *
+ * <p>This is useful if:
+ *
+ * <ul>
+ * <li>invoking of each extension returns a result that should be handled
+ * <li>a sequence of invocations should be done on each extension
+ * </ul>
+ */
+ @Override
+ public Iterator<PluginSetEntryContext<T>> iterator() {
+ return Iterators.transform(dynamicSet.entries().iterator(), PluginSetEntryContext<T>::new);
+ }
+
+ /**
+ * Checks if no implementations for this extension point have been registered.
+ *
+ * @return {@code true} if no implementations for this extension point have been registered,
+ * otherwise {@code false}
+ */
+ public boolean isEmpty() {
+ return !dynamicSet.iterator().hasNext();
+ }
+
+ /**
+ * Returns a sorted list of the plugins that have registered implementations for this extension
+ * point.
+ *
+ * @return sorted list of the plugins that have registered implementations for this extension
+ * point
+ */
+ public SortedSet<String> plugins() {
+ return dynamicSet.plugins();
+ }
+
+ /**
+ * Invokes each extension in the set. All exceptions from the plugin extensions are caught and
+ * logged.
+ *
+ * <p>The consumer gets the extension implementation provided that should be invoked.
+ *
+ * <p>All extension in the set are invoked, even if invoking some of the extensions failed.
+ *
+ * @param extensionImplConsumer consumer that invokes the extension
+ */
+ public void runEach(ExtensionImplConsumer<T> extensionImplConsumer) {
+ dynamicSet.entries().forEach(p -> PluginContext.runLogExceptions(p, extensionImplConsumer));
+ }
+
+ /**
+ * Invokes each extension in the set. All exceptions from the plugin extensions except exceptions
+ * of the specified type are caught and logged.
+ *
+ * <p>The consumer gets the extension implementation provided that should be invoked.
+ *
+ * <p>All extension in the set are invoked, even if invoking some of the extensions failed.
+ *
+ * @param extensionImplConsumer consumer that invokes the extension
+ * @param exceptionClass type of the exceptions that should be thrown
+ * @throws X expected exception from the plugin extension
+ */
+ public <X extends Exception> void runEach(
+ ExtensionImplConsumer<T> extensionImplConsumer, Class<X> exceptionClass) throws X {
+ for (Extension<T> extension : dynamicSet.entries()) {
+ PluginContext.runLogExceptions(extension, extensionImplConsumer, exceptionClass);
+ }
+ }
+}
diff --git a/java/com/google/gerrit/server/plugincontext/PluginSetEntryContext.java b/java/com/google/gerrit/server/plugincontext/PluginSetEntryContext.java
new file mode 100644
index 0000000..43cab11
--- /dev/null
+++ b/java/com/google/gerrit/server/plugincontext/PluginSetEntryContext.java
@@ -0,0 +1,165 @@
+// Copyright (C) 2018 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.plugincontext;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.gerrit.extensions.registration.DynamicSet;
+import com.google.gerrit.extensions.registration.Extension;
+import com.google.gerrit.server.plugincontext.PluginContext.CheckedExtensionImplFunction;
+import com.google.gerrit.server.plugincontext.PluginContext.ExtensionImplConsumer;
+import com.google.gerrit.server.plugincontext.PluginContext.ExtensionImplFunction;
+
+/**
+ * Context to invoke an extension from {@link DynamicSet}.
+ *
+ * <p>When the plugin extension is invoked a logging tag with the plugin name is set. This way any
+ * errors that are triggered by the plugin extension (even if they happen in Gerrit code which is
+ * called by the plugin extension) can be easily attributed to the plugin.
+ *
+ * <p>The run* methods execute the extension but don't deliver a result back to the caller.
+ * Exceptions can be caught and logged.
+ *
+ * <p>The call* methods execute the extension and deliver a result back to the caller.
+ *
+ * <p>Example if all exceptions should be caught and logged:
+ *
+ * <pre>
+ * fooPluginSetEntryContext.run(foo -> foo.doFoo());
+ * </pre>
+ *
+ * <p>Example if all exceptions, but one, should be caught and logged:
+ *
+ * <pre>
+ * try {
+ * fooPluginSetEntryContext.run(foo -> foo.doFoo(), MyException.class);
+ * } catch (MyException e) {
+ * // handle the exception
+ * }
+ * </pre>
+ *
+ * <p>Example if return values should be handled:
+ *
+ * <pre>
+ * Object result = fooPluginSetEntryContext.call(foo -> foo.getFoo());
+ * </pre>
+ *
+ * <p>Example if return values and a single exception should be handled:
+ *
+ * <pre>
+ * Object result;
+ * try {
+ * result = fooPluginSetEntryContext.call(foo -> foo.getFoo(), MyException.class);
+ * } catch (MyException e) {
+ * // handle the exception
+ * }
+ * </pre>
+ *
+ * <p>Example if several exceptions should be handled:
+ *
+ * <pre>
+ * for (Extension<Foo> fooExtension : fooDynamicSet.entries()) {
+ * try (TraceContext traceContext = PluginContext.newTrace(fooExtension)) {
+ * fooExtension.get().doFoo();
+ * } catch (MyException1 | MyException2 | MyException3 e) {
+ * // handle the exception
+ * }
+ * }
+ * </pre>
+ */
+public class PluginSetEntryContext<T> {
+ private final Extension<T> extension;
+
+ PluginSetEntryContext(Extension<T> extension) {
+ this.extension = checkNotNull(extension);
+ }
+
+ /**
+ * Returns the name of the plugin that registered this extension.
+ *
+ * @return the plugin name
+ */
+ public String getPluginName() {
+ return extension.getPluginName();
+ }
+
+ /**
+ * Returns the implementation of this extension.
+ *
+ * <p>Should only be used in exceptional cases to get direct access to the extension
+ * implementation. If possible the extension should be invoked through {@link
+ * #run(ExtensionImplConsumer)}, {@link #run(ExtensionImplConsumer, Class)}, {@link
+ * #call(ExtensionImplFunction)} and {@link #call(CheckedExtensionImplFunction, Class)}.
+ *
+ * @return the implementation of this extension
+ */
+ public T get() {
+ return extension.get();
+ }
+
+ /**
+ * Invokes the plugin extension. All exceptions from the plugin extension are caught and logged.
+ *
+ * <p>The consumer gets the extension implementation provided that should be invoked.
+ *
+ * @param extensionImplConsumer consumer that invokes the extension
+ */
+ public void run(ExtensionImplConsumer<T> extensionImplConsumer) {
+ PluginContext.runLogExceptions(extension, extensionImplConsumer);
+ }
+
+ /**
+ * Invokes the plugin extension. All exceptions from the plugin extension are caught and logged.
+ *
+ * <p>The consumer gets the extension implementation provided that should be invoked.
+ *
+ * @param extensionImplConsumer consumer that invokes the extension
+ * @param exceptionClass type of the exceptions that should be thrown
+ * @throws X expected exception from the plugin extension
+ */
+ public <X extends Exception> void run(
+ ExtensionImplConsumer<T> extensionImplConsumer, Class<X> exceptionClass) throws X {
+ PluginContext.runLogExceptions(extension, extensionImplConsumer, exceptionClass);
+ }
+
+ /**
+ * Calls the plugin extension and returns the result from the plugin extension call.
+ *
+ * <p>The function gets the extension point provided that should be invoked.
+ *
+ * @param extensionImplFunction function that invokes the extension
+ * @return the result from the plugin extension
+ */
+ public <R> R call(ExtensionImplFunction<T, R> extensionImplFunction) {
+ return PluginContext.call(extension, extensionImplFunction);
+ }
+
+ /**
+ * Calls the plugin extension and returns the result from the plugin extension call. Exceptions of
+ * the specified type are thrown and must be handled by the caller.
+ *
+ * <p>The function gets the extension implementation provided that should be invoked.
+ *
+ * @param checkedExtensionImplFunction function that invokes the extension
+ * @param exceptionClass type of the exceptions that should be thrown
+ * @return the result from the plugin extension
+ * @throws X expected exception from the plugin extension
+ */
+ public <R, X extends Exception> R call(
+ CheckedExtensionImplFunction<T, R, X> checkedExtensionImplFunction, Class<X> exceptionClass)
+ throws X {
+ return PluginContext.call(extension, checkedExtensionImplFunction, exceptionClass);
+ }
+}
diff --git a/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java b/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
index 3fcb3a9..7150fae 100644
--- a/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
+++ b/java/com/google/gerrit/server/project/SubmitRuleEvaluator.java
@@ -14,11 +14,12 @@
package com.google.gerrit.server.project;
+import com.google.common.collect.Streams;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.common.data.SubmitTypeRecord;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.rules.PrologRule;
import com.google.gerrit.server.rules.SubmitRule;
@@ -29,7 +30,6 @@
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
-import java.util.stream.StreamSupport;
/**
* Evaluates a submit-like Prolog rule found in the rules.pl file of the current project and filters
@@ -42,7 +42,7 @@
private final ProjectCache projectCache;
private final PrologRule prologRule;
- private final DynamicSet<SubmitRule> submitRules;
+ private final PluginSetContext<SubmitRule> submitRules;
private final SubmitRuleOptions opts;
public interface Factory {
@@ -54,7 +54,7 @@
private SubmitRuleEvaluator(
ProjectCache projectCache,
PrologRule prologRule,
- DynamicSet<SubmitRule> submitRules,
+ PluginSetContext<SubmitRule> submitRules,
@Assisted SubmitRuleOptions options) {
this.projectCache = projectCache;
this.prologRule = prologRule;
@@ -110,8 +110,8 @@
// We evaluate all the plugin-defined evaluators,
// and then we collect the results in one list.
- return StreamSupport.stream(submitRules.spliterator(), false)
- .map(s -> s.evaluate(cd, opts))
+ return Streams.stream(submitRules)
+ .map(c -> c.call(s -> s.evaluate(cd, opts)))
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
diff --git a/java/com/google/gerrit/server/restapi/BUILD b/java/com/google/gerrit/server/restapi/BUILD
index 5e6dddf..1df431e 100644
--- a/java/com/google/gerrit/server/restapi/BUILD
+++ b/java/com/google/gerrit/server/restapi/BUILD
@@ -18,6 +18,7 @@
"//java/com/google/gerrit/reviewdb:server",
"//java/com/google/gerrit/server",
"//java/com/google/gerrit/server/ioutil",
+ "//java/com/google/gerrit/server/logging",
"//java/com/google/gerrit/server/util/time",
"//java/com/google/gerrit/util/cli",
"//java/org/eclipse/jgit:server",
diff --git a/java/com/google/gerrit/server/restapi/change/DeleteChangeOp.java b/java/com/google/gerrit/server/restapi/change/DeleteChangeOp.java
index d41e504..ae2d2eb 100644
--- a/java/com/google/gerrit/server/restapi/change/DeleteChangeOp.java
+++ b/java/com/google/gerrit/server/restapi/change/DeleteChangeOp.java
@@ -16,7 +16,6 @@
import static com.google.common.base.Preconditions.checkState;
-import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.restapi.MethodNotAllowedException;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
import com.google.gerrit.extensions.restapi.RestApiException;
@@ -27,6 +26,7 @@
import com.google.gerrit.server.StarredChangesUtil;
import com.google.gerrit.server.change.AccountPatchReviewStore;
import com.google.gerrit.server.extensions.events.ChangeDeleted;
+import com.google.gerrit.server.plugincontext.PluginItemContext;
import com.google.gerrit.server.project.NoSuchChangeException;
import com.google.gerrit.server.update.BatchUpdateOp;
import com.google.gerrit.server.update.BatchUpdateReviewDb;
@@ -45,7 +45,7 @@
class DeleteChangeOp implements BatchUpdateOp {
private final PatchSetUtil psUtil;
private final StarredChangesUtil starredChangesUtil;
- private final DynamicItem<AccountPatchReviewStore> accountPatchReviewStore;
+ private final PluginItemContext<AccountPatchReviewStore> accountPatchReviewStore;
private final ChangeDeleted changeDeleted;
private Change.Id id;
@@ -54,7 +54,7 @@
DeleteChangeOp(
PatchSetUtil psUtil,
StarredChangesUtil starredChangesUtil,
- DynamicItem<AccountPatchReviewStore> accountPatchReviewStore,
+ PluginItemContext<AccountPatchReviewStore> accountPatchReviewStore,
ChangeDeleted changeDeleted) {
this.psUtil = psUtil;
this.starredChangesUtil = starredChangesUtil;
@@ -127,7 +127,7 @@
private void cleanUpReferences(ChangeContext ctx, Change.Id id, Collection<PatchSet> patchSets)
throws OrmException, NoSuchChangeException {
for (PatchSet ps : patchSets) {
- accountPatchReviewStore.get().clearReviewed(ps.getId());
+ accountPatchReviewStore.run(s -> s.clearReviewed(ps.getId()), OrmException.class);
}
// Non-atomic operation on Accounts table; not much we can do to make it
diff --git a/java/com/google/gerrit/server/restapi/change/Files.java b/java/com/google/gerrit/server/restapi/change/Files.java
index bb2f668..1bb6bf2 100644
--- a/java/com/google/gerrit/server/restapi/change/Files.java
+++ b/java/com/google/gerrit/server/restapi/change/Files.java
@@ -19,7 +19,6 @@
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import com.google.gerrit.extensions.common.FileInfo;
-import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
@@ -49,6 +48,7 @@
import com.google.gerrit.server.patch.PatchListNotAvailableException;
import com.google.gerrit.server.patch.PatchListObjectTooLargeException;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginItemContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -120,7 +120,7 @@
private final GitRepositoryManager gitManager;
private final PatchListCache patchListCache;
private final PatchSetUtil psUtil;
- private final DynamicItem<AccountPatchReviewStore> accountPatchReviewStore;
+ private final PluginItemContext<AccountPatchReviewStore> accountPatchReviewStore;
@Inject
ListFiles(
@@ -131,7 +131,7 @@
GitRepositoryManager gitManager,
PatchListCache patchListCache,
PatchSetUtil psUtil,
- DynamicItem<AccountPatchReviewStore> accountPatchReviewStore) {
+ PluginItemContext<AccountPatchReviewStore> accountPatchReviewStore) {
this.db = db;
this.self = self;
this.fileInfoJson = fileInfoJson;
@@ -235,8 +235,10 @@
Account.Id userId = user.getAccountId();
PatchSet patchSetId = resource.getPatchSet();
- Optional<PatchSetWithReviewedFiles> o =
- accountPatchReviewStore.get().findReviewed(patchSetId.getId(), userId);
+ Optional<PatchSetWithReviewedFiles> o;
+ o =
+ accountPatchReviewStore.call(
+ s -> s.findReviewed(patchSetId.getId(), userId), OrmException.class);
if (o.isPresent()) {
PatchSetWithReviewedFiles res = o.get();
@@ -317,9 +319,10 @@
pathList.add(path);
}
}
- accountPatchReviewStore
- .get()
- .markReviewed(resource.getPatchSet().getId(), userId, pathList);
+
+ accountPatchReviewStore.run(
+ s -> s.markReviewed(resource.getPatchSet().getId(), userId, pathList),
+ OrmException.class);
return pathList;
}
}
diff --git a/java/com/google/gerrit/server/restapi/change/Reviewed.java b/java/com/google/gerrit/server/restapi/change/Reviewed.java
index d1a2168..accc355 100644
--- a/java/com/google/gerrit/server/restapi/change/Reviewed.java
+++ b/java/com/google/gerrit/server/restapi/change/Reviewed.java
@@ -15,11 +15,11 @@
package com.google.gerrit.server.restapi.change;
import com.google.gerrit.extensions.common.Input;
-import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.restapi.Response;
import com.google.gerrit.extensions.restapi.RestModifyView;
import com.google.gerrit.server.change.AccountPatchReviewStore;
import com.google.gerrit.server.change.FileResource;
+import com.google.gerrit.server.plugincontext.PluginItemContext;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@@ -28,44 +28,45 @@
@Singleton
public static class PutReviewed implements RestModifyView<FileResource, Input> {
- private final DynamicItem<AccountPatchReviewStore> accountPatchReviewStore;
+ private final PluginItemContext<AccountPatchReviewStore> accountPatchReviewStore;
@Inject
- PutReviewed(DynamicItem<AccountPatchReviewStore> accountPatchReviewStore) {
+ PutReviewed(PluginItemContext<AccountPatchReviewStore> accountPatchReviewStore) {
this.accountPatchReviewStore = accountPatchReviewStore;
}
@Override
public Response<String> apply(FileResource resource, Input input) throws OrmException {
- if (accountPatchReviewStore
- .get()
- .markReviewed(
- resource.getPatchKey().getParentKey(),
- resource.getAccountId(),
- resource.getPatchKey().getFileName())) {
- return Response.created("");
- }
- return Response.ok("");
+ boolean reviewFlagUpdated =
+ accountPatchReviewStore.call(
+ s ->
+ s.markReviewed(
+ resource.getPatchKey().getParentKey(),
+ resource.getAccountId(),
+ resource.getPatchKey().getFileName()),
+ OrmException.class);
+ return reviewFlagUpdated ? Response.created("") : Response.ok("");
}
}
@Singleton
public static class DeleteReviewed implements RestModifyView<FileResource, Input> {
- private final DynamicItem<AccountPatchReviewStore> accountPatchReviewStore;
+ private final PluginItemContext<AccountPatchReviewStore> accountPatchReviewStore;
@Inject
- DeleteReviewed(DynamicItem<AccountPatchReviewStore> accountPatchReviewStore) {
+ DeleteReviewed(PluginItemContext<AccountPatchReviewStore> accountPatchReviewStore) {
this.accountPatchReviewStore = accountPatchReviewStore;
}
@Override
public Response<?> apply(FileResource resource, Input input) throws OrmException {
- accountPatchReviewStore
- .get()
- .clearReviewed(
- resource.getPatchKey().getParentKey(),
- resource.getAccountId(),
- resource.getPatchKey().getFileName());
+ accountPatchReviewStore.run(
+ s ->
+ s.clearReviewed(
+ resource.getPatchKey().getParentKey(),
+ resource.getAccountId(),
+ resource.getPatchKey().getFileName()),
+ OrmException.class);
return Response.none();
}
}
diff --git a/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java b/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java
index ae6e5d1..d88489e 100644
--- a/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java
+++ b/java/com/google/gerrit/server/restapi/change/ReviewerRecommender.java
@@ -23,8 +23,6 @@
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.data.LabelType;
-import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.registration.Extension;
import com.google.gerrit.index.query.Predicate;
import com.google.gerrit.index.query.QueryParseException;
import com.google.gerrit.reviewdb.client.Account;
@@ -37,6 +35,7 @@
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.index.change.ChangeField;
import com.google.gerrit.server.notedb.ChangeNotes;
+import com.google.gerrit.server.plugincontext.PluginMapContext;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
@@ -78,7 +77,7 @@
private final ChangeQueryBuilder changeQueryBuilder;
private final Config config;
- private final DynamicMap<ReviewerSuggestion> reviewerSuggestionPluginMap;
+ private final PluginMapContext<ReviewerSuggestion> reviewerSuggestionPluginMap;
private final Provider<InternalChangeQuery> queryProvider;
private final ExecutorService executor;
private final Provider<ReviewDb> dbProvider;
@@ -87,7 +86,7 @@
@Inject
ReviewerRecommender(
ChangeQueryBuilder changeQueryBuilder,
- DynamicMap<ReviewerSuggestion> reviewerSuggestionPluginMap,
+ PluginMapContext<ReviewerSuggestion> reviewerSuggestionPluginMap,
Provider<InternalChangeQuery> queryProvider,
@FanOutExecutor ExecutorService executor,
Provider<ReviewDb> dbProvider,
@@ -131,30 +130,30 @@
new ArrayList<>(reviewerSuggestionPluginMap.plugins().size());
List<Double> weights = new ArrayList<>(reviewerSuggestionPluginMap.plugins().size());
- for (Extension<ReviewerSuggestion> plugin : reviewerSuggestionPluginMap) {
- tasks.add(
- () ->
- plugin
- .getProvider()
- .get()
- .suggestReviewers(
- projectState.getNameKey(),
- changeNotes != null ? changeNotes.getChangeId() : null,
- query,
- reviewerScores.keySet()));
- String key = plugin.getPluginName() + "-" + plugin.getExportName();
- String pluginWeight = config.getString("addReviewer", key, "weight");
- if (Strings.isNullOrEmpty(pluginWeight)) {
- pluginWeight = "1";
- }
- logger.atFine().log("weight for %s: %s", key, pluginWeight);
- try {
- weights.add(Double.parseDouble(pluginWeight));
- } catch (NumberFormatException e) {
- logger.atSevere().withCause(e).log("Exception while parsing weight for %s", key);
- weights.add(1d);
- }
- }
+ reviewerSuggestionPluginMap.runEach(
+ extension -> {
+ tasks.add(
+ () ->
+ extension
+ .get()
+ .suggestReviewers(
+ projectState.getNameKey(),
+ changeNotes != null ? changeNotes.getChangeId() : null,
+ query,
+ reviewerScores.keySet()));
+ String key = extension.getPluginName() + "-" + extension.getExportName();
+ String pluginWeight = config.getString("addReviewer", key, "weight");
+ if (Strings.isNullOrEmpty(pluginWeight)) {
+ pluginWeight = "1";
+ }
+ logger.atFine().log("weight for %s: %s", key, pluginWeight);
+ try {
+ weights.add(Double.parseDouble(pluginWeight));
+ } catch (NumberFormatException e) {
+ logger.atSevere().withCause(e).log("Exception while parsing weight for %s", key);
+ weights.add(1d);
+ }
+ });
try {
List<Future<Set<SuggestedReviewer>>> futures =
diff --git a/java/com/google/gerrit/server/restapi/group/CreateGroup.java b/java/com/google/gerrit/server/restapi/group/CreateGroup.java
index 64d515c..6b01cda 100644
--- a/java/com/google/gerrit/server/restapi/group/CreateGroup.java
+++ b/java/com/google/gerrit/server/restapi/group/CreateGroup.java
@@ -23,7 +23,6 @@
import com.google.gerrit.extensions.api.groups.GroupInput;
import com.google.gerrit.extensions.client.ListGroupsOption;
import com.google.gerrit.extensions.common.GroupInfo;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.IdString;
@@ -51,6 +50,7 @@
import com.google.gerrit.server.group.db.InternalGroupCreation;
import com.google.gerrit.server.group.db.InternalGroupUpdate;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.validators.GroupCreationValidationListener;
import com.google.gerrit.server.validators.ValidationException;
import com.google.gwtorm.server.OrmDuplicateKeyException;
@@ -79,7 +79,7 @@
private final GroupCache groupCache;
private final GroupsCollection groups;
private final GroupJson json;
- private final DynamicSet<GroupCreationValidationListener> groupCreationValidationListeners;
+ private final PluginSetContext<GroupCreationValidationListener> groupCreationValidationListeners;
private final AddMembers addMembers;
private final SystemGroupBackend systemGroupBackend;
private final boolean defaultVisibleToAll;
@@ -93,7 +93,7 @@
GroupCache groupCache,
GroupsCollection groups,
GroupJson json,
- DynamicSet<GroupCreationValidationListener> groupCreationValidationListeners,
+ PluginSetContext<GroupCreationValidationListener> groupCreationValidationListeners,
AddMembers addMembers,
SystemGroupBackend systemGroupBackend,
@GerritServerConfig Config cfg,
@@ -158,12 +158,11 @@
: Collections.<Account.Id>emptySet();
}
- for (GroupCreationValidationListener l : groupCreationValidationListeners) {
- try {
- l.validateNewGroup(args);
- } catch (ValidationException e) {
- throw new ResourceConflictException(e.getMessage(), e);
- }
+ try {
+ groupCreationValidationListeners.runEach(
+ l -> l.validateNewGroup(args), ValidationException.class);
+ } catch (ValidationException e) {
+ throw new ResourceConflictException(e.getMessage(), e);
}
return json.format(new InternalGroupDescription(createGroup(args)));
diff --git a/java/com/google/gerrit/server/restapi/project/CreateProject.java b/java/com/google/gerrit/server/restapi/project/CreateProject.java
index 030402e..79ff3c9 100644
--- a/java/com/google/gerrit/server/restapi/project/CreateProject.java
+++ b/java/com/google/gerrit/server/restapi/project/CreateProject.java
@@ -34,8 +34,6 @@
import com.google.gerrit.extensions.client.SubmitType;
import com.google.gerrit.extensions.common.ProjectInfo;
import com.google.gerrit.extensions.events.NewProjectCreatedListener;
-import com.google.gerrit.extensions.registration.DynamicItem;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.IdString;
import com.google.gerrit.extensions.restapi.ResourceConflictException;
@@ -60,6 +58,8 @@
import com.google.gerrit.server.git.RepositoryCaseMismatchException;
import com.google.gerrit.server.git.meta.MetaDataUpdate;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginItemContext;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.project.CreateProjectArgs;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectConfig;
@@ -98,10 +98,11 @@
private final Provider<ProjectsCollection> projectsCollection;
private final Provider<GroupsCollection> groupsCollection;
- private final DynamicSet<ProjectCreationValidationListener> projectCreationValidationListeners;
+ private final PluginSetContext<ProjectCreationValidationListener>
+ projectCreationValidationListeners;
private final ProjectJson json;
private final GitRepositoryManager repoManager;
- private final DynamicSet<NewProjectCreatedListener> createdListeners;
+ private final PluginSetContext<NewProjectCreatedListener> createdListeners;
private final ProjectCache projectCache;
private final GroupBackend groupBackend;
private final ProjectOwnerGroupsProvider.Factory projectOwnerGroups;
@@ -113,16 +114,16 @@
private final Provider<PutConfig> putConfig;
private final AllProjectsName allProjects;
private final AllUsersName allUsers;
- private final DynamicItem<ProjectNameLockManager> lockManager;
+ private final PluginItemContext<ProjectNameLockManager> lockManager;
@Inject
CreateProject(
Provider<ProjectsCollection> projectsCollection,
Provider<GroupsCollection> groupsCollection,
ProjectJson json,
- DynamicSet<ProjectCreationValidationListener> projectCreationValidationListeners,
+ PluginSetContext<ProjectCreationValidationListener> projectCreationValidationListeners,
GitRepositoryManager repoManager,
- DynamicSet<NewProjectCreatedListener> createdListeners,
+ PluginSetContext<NewProjectCreatedListener> createdListeners,
ProjectCache projectCache,
GroupBackend groupBackend,
ProjectOwnerGroupsProvider.Factory projectOwnerGroups,
@@ -134,7 +135,7 @@
Provider<PutConfig> putConfig,
AllProjectsName allProjects,
AllUsersName allUsers,
- DynamicItem<ProjectNameLockManager> lockManager) {
+ PluginItemContext<ProjectNameLockManager> lockManager) {
this.projectsCollection = projectsCollection;
this.groupsCollection = groupsCollection;
this.projectCreationValidationListeners = projectCreationValidationListeners;
@@ -213,15 +214,14 @@
throw new BadRequestException(e.getMessage());
}
- Lock nameLock = lockManager.get().getLock(args.getProject());
+ Lock nameLock = lockManager.call(lockManager -> lockManager.getLock(args.getProject()));
nameLock.lock();
try {
- for (ProjectCreationValidationListener l : projectCreationValidationListeners) {
- try {
- l.validateNewProject(args);
- } catch (ValidationException e) {
- throw new ResourceConflictException(e.getMessage(), e);
- }
+ try {
+ projectCreationValidationListeners.runEach(
+ l -> l.validateNewProject(args), ValidationException.class);
+ } catch (ValidationException e) {
+ throw new ResourceConflictException(e.getMessage(), e);
}
ProjectState projectState = createProject(args);
@@ -392,18 +392,12 @@
}
private void fire(Project.NameKey name, String head) {
- if (!createdListeners.iterator().hasNext()) {
+ if (createdListeners.isEmpty()) {
return;
}
Event event = new Event(name, head);
- for (NewProjectCreatedListener l : createdListeners) {
- try {
- l.onNewProjectCreated(event);
- } catch (RuntimeException e) {
- logger.atWarning().withCause(e).log("Failure in NewProjectCreatedListener");
- }
- }
+ createdListeners.runEach(l -> l.onNewProjectCreated(event));
}
static class Event extends AbstractNoNotifyEvent implements NewProjectCreatedListener.Event {
diff --git a/java/com/google/gerrit/server/restapi/project/SetHead.java b/java/com/google/gerrit/server/restapi/project/SetHead.java
index feff98e..b310f16 100644
--- a/java/com/google/gerrit/server/restapi/project/SetHead.java
+++ b/java/com/google/gerrit/server/restapi/project/SetHead.java
@@ -15,10 +15,8 @@
package com.google.gerrit.server.restapi.project;
import com.google.common.base.Strings;
-import com.google.common.flogger.FluentLogger;
import com.google.gerrit.extensions.api.projects.HeadInput;
import com.google.gerrit.extensions.events.HeadUpdatedListener;
-import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.extensions.restapi.AuthException;
import com.google.gerrit.extensions.restapi.BadRequestException;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
@@ -32,6 +30,7 @@
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
import com.google.gerrit.server.permissions.RefPermission;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.server.project.ProjectResource;
import com.google.inject.Inject;
import com.google.inject.Provider;
@@ -46,18 +45,16 @@
@Singleton
public class SetHead implements RestModifyView<ProjectResource, HeadInput> {
- private static final FluentLogger logger = FluentLogger.forEnclosingClass();
-
private final GitRepositoryManager repoManager;
private final Provider<IdentifiedUser> identifiedUser;
- private final DynamicSet<HeadUpdatedListener> headUpdatedListeners;
+ private final PluginSetContext<HeadUpdatedListener> headUpdatedListeners;
private final PermissionBackend permissionBackend;
@Inject
SetHead(
GitRepositoryManager repoManager,
Provider<IdentifiedUser> identifiedUser,
- DynamicSet<HeadUpdatedListener> headUpdatedListeners,
+ PluginSetContext<HeadUpdatedListener> headUpdatedListeners,
PermissionBackend permissionBackend) {
this.repoManager = repoManager;
this.identifiedUser = identifiedUser;
@@ -119,17 +116,12 @@
}
private void fire(Project.NameKey nameKey, String oldHead, String newHead) {
- if (!headUpdatedListeners.iterator().hasNext()) {
+ if (headUpdatedListeners.isEmpty()) {
return;
}
+
Event event = new Event(nameKey, oldHead, newHead);
- for (HeadUpdatedListener l : headUpdatedListeners) {
- try {
- l.onHeadUpdated(event);
- } catch (RuntimeException e) {
- logger.atWarning().withCause(e).log("Failure in HeadUpdatedListener");
- }
- }
+ headUpdatedListeners.runEach(l -> l.onHeadUpdated(event));
}
static class Event extends AbstractNoNotifyEvent implements HeadUpdatedListener.Event {
diff --git a/java/com/google/gerrit/server/submit/MergeSuperSet.java b/java/com/google/gerrit/server/submit/MergeSuperSet.java
index 2bd7d26..dc8b51a 100644
--- a/java/com/google/gerrit/server/submit/MergeSuperSet.java
+++ b/java/com/google/gerrit/server/submit/MergeSuperSet.java
@@ -25,9 +25,11 @@
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.logging.TraceContext;
import com.google.gerrit.server.permissions.ChangePermission;
import com.google.gerrit.server.permissions.PermissionBackend;
import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.plugincontext.PluginContext;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.query.change.ChangeData;
@@ -120,7 +122,9 @@
if (wholeTopicEnabled(cfg)) {
return completeChangeSetIncludingTopics(db, changeSet, user);
}
- return mergeSuperSetComputation.get().completeWithoutTopic(db, orm, changeSet, user);
+ try (TraceContext traceContext = PluginContext.newTrace(mergeSuperSetComputation)) {
+ return mergeSuperSetComputation.get().completeWithoutTopic(db, orm, changeSet, user);
+ }
} finally {
if (closeOrm && orm != null) {
orm.close();
@@ -195,7 +199,9 @@
do {
oldSeen = seen;
- changeSet = mergeSuperSetComputation.get().completeWithoutTopic(db, orm, changeSet, user);
+ try (TraceContext traceContext = PluginContext.newTrace(mergeSuperSetComputation)) {
+ changeSet = mergeSuperSetComputation.get().completeWithoutTopic(db, orm, changeSet, user);
+ }
changeSet = topicClosure(db, changeSet, user, topicsSeen, visibleTopicsSeen);
seen = topicsSeen.size() + visibleTopicsSeen.size();
} while (seen != oldSeen);
diff --git a/javatests/com/google/gerrit/server/account/UniversalGroupBackendTest.java b/javatests/com/google/gerrit/server/account/UniversalGroupBackendTest.java
index 6dd0f3e..0cdf1a8 100644
--- a/javatests/com/google/gerrit/server/account/UniversalGroupBackendTest.java
+++ b/javatests/com/google/gerrit/server/account/UniversalGroupBackendTest.java
@@ -35,6 +35,7 @@
import com.google.gerrit.reviewdb.client.AccountGroup.UUID;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.group.SystemGroupBackend;
+import com.google.gerrit.server.plugincontext.PluginSetContext;
import com.google.gerrit.testing.GerritBaseTests;
import java.util.Set;
import org.easymock.IAnswer;
@@ -56,7 +57,7 @@
replay(user);
backends = new DynamicSet<>();
backends.add("gerrit", new SystemGroupBackend(new Config()));
- backend = new UniversalGroupBackend(backends);
+ backend = new UniversalGroupBackend(new PluginSetContext<>(backends));
}
@Test
@@ -124,7 +125,7 @@
backends = new DynamicSet<>();
backends.add("gerrit", backend);
- backend = new UniversalGroupBackend(backends);
+ backend = new UniversalGroupBackend(new PluginSetContext<>(backends));
GroupMembership checker = backend.membershipsOf(member);
assertFalse(checker.contains(REGISTERED_USERS));