Merge "Define an extension for user scoped event listeners"

This commit is contained in:
Saša Živkov
2016-03-09 12:18:34 +00:00
committed by Gerrit Code Review
8 changed files with 91 additions and 95 deletions

View File

@@ -92,7 +92,6 @@ import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
@@ -102,7 +101,7 @@ import java.util.concurrent.TimeoutException;
/** Spawns local executables when a hook action occurs. */
@Singleton
public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
EventSource, LifecycleListener, NewProjectCreatedListener {
LifecycleListener, NewProjectCreatedListener {
/** A logger for this class. */
private static final Logger log = LoggerFactory.getLogger(ChangeHookRunner.class);
@@ -112,22 +111,11 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
bind(ChangeHookRunner.class);
bind(ChangeHooks.class).to(ChangeHookRunner.class);
bind(EventDispatcher.class).to(ChangeHookRunner.class);
bind(EventSource.class).to(ChangeHookRunner.class);
DynamicSet.bind(binder(), NewProjectCreatedListener.class).to(ChangeHookRunner.class);
listener().to(ChangeHookRunner.class);
}
}
private static class EventListenerHolder {
final EventListener listener;
final CurrentUser user;
EventListenerHolder(EventListener l, CurrentUser u) {
listener = l;
user = u;
}
}
/** Container class used to hold the return code and output of script hook execution */
public static class HookResult {
private int exitValue = -1;
@@ -177,9 +165,8 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
}
/** Listeners to receive changes as they happen (limited by visibility
* of holder's user). */
private final Map<EventListener, EventListenerHolder> listeners =
new ConcurrentHashMap<>();
* of user). */
private final DynamicSet<UserScopedEventListener> listeners;
/** Listeners to receive all changes as they happen. */
private final DynamicSet<EventListener> unrestrictedListeners;
@@ -268,6 +255,7 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
ProjectCache projectCache,
AccountCache accountCache,
EventFactory eventFactory,
DynamicSet<UserScopedEventListener> listeners,
DynamicSet<EventListener> unrestrictedListeners,
ChangeNotes.Factory notesFactory) {
this.anonymousCowardName = anonymousCowardName;
@@ -277,6 +265,7 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
this.accountCache = accountCache;
this.eventFactory = eventFactory;
this.sitePaths = sitePath;
this.listeners = listeners;
this.unrestrictedListeners = unrestrictedListeners;
this.notesFactory = notesFactory;
@@ -319,16 +308,6 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
return Files.exists(p) ? Optional.of(p) : Optional.<Path>absent();
}
@Override
public void addEventListener(EventListener listener, CurrentUser user) {
listeners.put(listener, new EventListenerHolder(listener, user));
}
@Override
public void removeEventListener(EventListener listener) {
listeners.remove(listener);
}
/**
* Get the Repository for the given project name, or null on error.
*
@@ -923,9 +902,9 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
private void fireEvent(Change change, ChangeEvent event, ReviewDb db)
throws OrmException {
for (EventListenerHolder holder : listeners.values()) {
if (isVisibleTo(change, holder.user, db)) {
holder.listener.onEvent(event);
for (UserScopedEventListener listener : listeners) {
if (isVisibleTo(change, listener.getUser(), db)) {
listener.onEvent(event);
}
}
@@ -933,9 +912,9 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
}
private void fireEvent(Project.NameKey project, ProjectEvent event) {
for (EventListenerHolder holder : listeners.values()) {
if (isVisibleTo(project, holder.user)) {
holder.listener.onEvent(event);
for (UserScopedEventListener listener : listeners) {
if (isVisibleTo(project, listener.getUser())) {
listener.onEvent(event);
}
}
@@ -943,9 +922,9 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
}
private void fireEvent(Branch.NameKey branchName, RefEvent event) {
for (EventListenerHolder holder : listeners.values()) {
if (isVisibleTo(branchName, holder.user)) {
holder.listener.onEvent(event);
for (UserScopedEventListener listener : listeners) {
if (isVisibleTo(branchName, listener.getUser())) {
listener.onEvent(event);
}
}
@@ -954,9 +933,9 @@ public class ChangeHookRunner implements ChangeHooks, EventDispatcher,
private void fireEvent(com.google.gerrit.server.events.Event event,
ReviewDb db) throws OrmException {
for (EventListenerHolder holder : listeners.values()) {
if (isVisibleTo(event, holder.user, db)) {
holder.listener.onEvent(event);
for (UserScopedEventListener listener : listeners) {
if (isVisibleTo(event, listener.getUser(), db)) {
listener.onEvent(event);
}
}

View File

@@ -21,7 +21,6 @@ import com.google.gerrit.reviewdb.client.Change;
import com.google.gerrit.reviewdb.client.PatchSet;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.reviewdb.server.ReviewDb;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.events.ChangeEvent;
import com.google.gerrit.server.events.Event;
import com.google.gerrit.server.events.ProjectEvent;
@@ -34,12 +33,7 @@ import java.util.Map;
import java.util.Set;
/** Does not invoke hooks. */
public final class DisabledChangeHooks implements ChangeHooks, EventDispatcher,
EventSource {
@Override
public void addEventListener(EventListener listener, CurrentUser user) {
}
public final class DisabledChangeHooks implements ChangeHooks, EventDispatcher {
@Override
public void doChangeAbandonedHook(Change change, Account account,
PatchSet patchSet, String reason, ReviewDb db) {
@@ -105,10 +99,6 @@ public final class DisabledChangeHooks implements ChangeHooks, EventDispatcher,
Set<String> removed, Set<String> hashtags, ReviewDb db) {
}
@Override
public void removeEventListener(EventListener listener) {
}
@Override
public HookResult doRefUpdateHook(Project project, String refName,
Account uploader, ObjectId oldId, ObjectId newId) {

View File

@@ -17,6 +17,10 @@ package com.google.gerrit.common;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
import com.google.gerrit.server.events.Event;
/**
* Allows to listen to events without user visibility restrictions. To listen to
* events visible to a specific user, use {@link UserScopedEventListener}.
*/
@ExtensionPoint
public interface EventListener {
void onEvent(Event event);

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2014 The Android Open Source Project
// Copyright (C) 2016 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.
@@ -11,14 +11,16 @@
// 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.common;
import com.google.gerrit.extensions.annotations.ExtensionPoint;
import com.google.gerrit.server.CurrentUser;
/** Distributes Events to ChangeListeners. Register listeners here. */
public interface EventSource {
void addEventListener(EventListener listener, CurrentUser user);
void removeEventListener(EventListener listener);
/**
* Allows to listen to events visible to the specified user. To listen to events
* without user visibility restrictions, use {@link EventListener}.
*/
@ExtensionPoint
public interface UserScopedEventListener extends EventListener {
CurrentUser getUser();
}

View File

@@ -19,6 +19,7 @@ import static com.google.inject.Scopes.SINGLETON;
import com.google.common.cache.Cache;
import com.google.gerrit.audit.AuditModule;
import com.google.gerrit.common.EventListener;
import com.google.gerrit.common.UserScopedEventListener;
import com.google.gerrit.extensions.auth.oauth.OAuthLoginProvider;
import com.google.gerrit.extensions.config.CapabilityDefinition;
import com.google.gerrit.extensions.config.CloneCommand;
@@ -281,6 +282,7 @@ public class GerritGlobalModule extends FactoryModule {
.to(ProjectConfigEntry.UpdateChecker.class);
DynamicSet.setOf(binder(), EventListener.class);
DynamicSet.bind(binder(), EventListener.class).to(EventsMetrics.class);
DynamicSet.setOf(binder(), UserScopedEventListener.class);
DynamicSet.setOf(binder(), CommitValidationListener.class);
DynamicSet.setOf(binder(), RefOperationValidationListener.class);
DynamicSet.setOf(binder(), MergeValidationListener.class);