Cache the resolution of allowed listeners

Avoid checking if an event listener is allowed every time
by caching the result of the resolution.

Change-Id: I75cfaaf9e1182e292ab6884584aff993c0e4fea9
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/ConfigurableAllowedEventListeners.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/ConfigurableAllowedEventListeners.java
index f7d0755..ea5f69c 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/ConfigurableAllowedEventListeners.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/ConfigurableAllowedEventListeners.java
@@ -18,18 +18,25 @@
 import com.google.gerrit.server.events.EventListener;
 import com.google.inject.Inject;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 /** Configure the allowed listeners in high-availability.config */
 public class ConfigurableAllowedEventListeners implements AllowedForwardedEventListener {
   private final Set<String> allowedListenerClasses;
+  private final ConcurrentHashMap<EventListener, Boolean> cachedAllowedListeners;
 
   @Inject
   ConfigurableAllowedEventListeners(Configuration config) {
     allowedListenerClasses = config.event().allowedListeners();
+    cachedAllowedListeners = new ConcurrentHashMap<>();
   }
 
   @Override
   public boolean isAllowed(EventListener listener) {
+    return cachedAllowedListeners.computeIfAbsent(listener, this::computeIsAllowed);
+  }
+
+  protected Boolean computeIsAllowed(EventListener listener) {
     String listenerClassName = listener.getClass().getName();
     boolean allowed = false;
     while (!allowed && !listenerClassName.isEmpty()) {
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
index 1ad69c3..fb1b8d0 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
@@ -76,6 +76,7 @@
 import java.nio.file.Paths;
 import java.util.Arrays;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 import org.eclipse.jgit.lib.Config;
 import org.junit.Before;
 import org.junit.Test;
@@ -369,6 +370,36 @@
   }
 
   @Test
+  public void testConfiguredListenerAllowedShouldBeCached() throws Exception {
+    AtomicInteger allowedListenerResolutionCount = new AtomicInteger();
+    EventListener listener =
+        new EventListener() {
+
+          @Override
+          public void onEvent(Event event) {}
+        };
+    assertThat(new ConfigurableAllowedEventListeners(getConfiguration()).isAllowed(listener))
+        .isFalse();
+
+    globalPluginConfig.setString(
+        EVENT_SECTION, null, ALLOWED_LISTENERS, listener.getClass().getName());
+
+    ConfigurableAllowedEventListeners allowedEventListener =
+        new ConfigurableAllowedEventListeners(getConfiguration()) {
+          @Override
+          protected Boolean computeIsAllowed(EventListener listener) {
+            allowedListenerResolutionCount.incrementAndGet();
+            return super.computeIsAllowed(listener);
+          }
+        };
+
+    for (int i = 0; i < 2; i++) {
+      assertThat(allowedEventListener.isAllowed(listener)).isTrue();
+      assertThat(allowedListenerResolutionCount.get()).isEqualTo(1);
+    }
+  }
+
+  @Test
   public void testConfiguredPackageOfListenerShouldBeAllowed() throws Exception {
     EventListener listener =
         new EventListener() {