Add configuration to disable synchronization

Cache, event, index and websession synchronization can be disabled by
setting synchronize parameter to false, example:

[index]
  synchronize = false

Change-Id: I390ce723b665068b018953358d33a8798e74fb2a
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
index 3071a9c..0f5ad15 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Configuration.java
@@ -53,12 +53,18 @@
   // cache section
   static final String CACHE_SECTION = "cache";
 
+  // event section
+  static final String EVENT_SECTION = "event";
+
   // index section
   static final String INDEX_SECTION = "index";
 
-  // common parameters to cache and index section
+  // common parameters to cache and index sections
   static final String THREAD_POOL_SIZE_KEY = "threadPoolSize";
 
+  // common parameters to cache, event index and websession sections
+  static final String SYNCHRONIZE_KEY = "synchronize";
+
   // websession section
   static final String WEBSESSION_SECTION = "websession";
   static final String CLEANUP_INTERVAL_KEY = "cleanupInterval";
@@ -69,11 +75,13 @@
   static final int DEFAULT_THREAD_POOL_SIZE = 1;
   static final String DEFAULT_CLEANUP_INTERVAL = "24 hours";
   static final long DEFAULT_CLEANUP_INTERVAL_MS = HOURS.toMillis(24);
+  static final boolean DEFAULT_SYNCHRONIZE = true;
 
   private final Main main;
   private final PeerInfo peerInfo;
   private final Http http;
   private final Cache cache;
+  private final Event event;
   private final Index index;
   private final Websession websession;
 
@@ -84,6 +92,7 @@
     peerInfo = new PeerInfo(cfg);
     http = new Http(cfg);
     cache = new Cache(cfg);
+    event = new Event(cfg);
     index = new Index(cfg);
     websession = new Websession(cfg);
   }
@@ -104,6 +113,10 @@
     return cache;
   }
 
+  public Event event() {
+    return event;
+  }
+
   public Index index() {
     return index;
   }
@@ -122,6 +135,16 @@
     }
   }
 
+  private static boolean getBoolean(Config cfg, String section, String name, boolean defaultValue) {
+    try {
+      return cfg.getBoolean(section, name, defaultValue);
+    } catch (IllegalArgumentException e) {
+      log.error(String.format("invalid value for %s; using default value %s", name, defaultValue));
+      log.debug("Failed to retrieve boolean value: " + e.getMessage(), e);
+      return defaultValue;
+    }
+  }
+
   public static class Main {
     private final String sharedDirectory;
 
@@ -195,10 +218,24 @@
     }
   }
 
-  public static class Cache {
+  /** Common parameters to cache, event, index and websession */
+  public abstract static class Forwarding {
+    private final boolean synchronize;
+
+    private Forwarding(Config cfg, String section) {
+      synchronize = getBoolean(cfg, section, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE);
+    }
+
+    public boolean synchronize() {
+      return synchronize;
+    }
+  }
+
+  public static class Cache extends Forwarding {
     private final int threadPoolSize;
 
     private Cache(Config cfg) {
+      super(cfg, CACHE_SECTION);
       threadPoolSize = getInt(cfg, CACHE_SECTION, THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE);
     }
 
@@ -207,10 +244,17 @@
     }
   }
 
-  public static class Index {
+  public static class Event extends Forwarding {
+    private Event(Config cfg) {
+      super(cfg, EVENT_SECTION);
+    }
+  }
+
+  public static class Index extends Forwarding {
     private final int threadPoolSize;
 
     private Index(Config cfg) {
+      super(cfg, INDEX_SECTION);
       threadPoolSize = getInt(cfg, INDEX_SECTION, THREAD_POOL_SIZE_KEY, DEFAULT_THREAD_POOL_SIZE);
     }
 
@@ -219,10 +263,11 @@
     }
   }
 
-  public static class Websession {
+  public static class Websession extends Forwarding {
     private final long cleanupInterval;
 
     private Websession(Config cfg) {
+      super(cfg, WEBSESSION_SECTION);
       this.cleanupInterval =
           ConfigUtil.getTimeUnit(
               Strings.nullToEmpty(cfg.getString(WEBSESSION_SECTION, null, CLEANUP_INTERVAL_KEY)),
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/HttpModule.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/HttpModule.java
index 1ff0344..57d1d91 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/HttpModule.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/HttpModule.java
@@ -17,11 +17,21 @@
 import com.ericsson.gerrit.plugins.highavailability.forwarder.rest.RestForwarderServletModule;
 import com.ericsson.gerrit.plugins.highavailability.websession.file.FileBasedWebsessionModule;
 import com.google.gerrit.httpd.plugins.HttpPluginModule;
+import com.google.inject.Inject;
 
 class HttpModule extends HttpPluginModule {
+  private final Configuration config;
+
+  @Inject
+  HttpModule(Configuration config) {
+    this.config = config;
+  }
+
   @Override
   protected void configureServlets() {
     install(new RestForwarderServletModule());
-    install(new FileBasedWebsessionModule());
+    if (config.websession().synchronize()) {
+      install(new FileBasedWebsessionModule());
+    }
   }
 }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
index 56721af..11b0605 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/highavailability/Module.java
@@ -21,8 +21,8 @@
 import com.ericsson.gerrit.plugins.highavailability.index.IndexModule;
 import com.ericsson.gerrit.plugins.highavailability.peers.PeerInfoModule;
 import com.google.inject.AbstractModule;
+import com.google.inject.Inject;
 import com.google.inject.Provides;
-import com.google.inject.Scopes;
 import com.google.inject.Singleton;
 import java.io.IOException;
 import java.nio.file.Files;
@@ -30,23 +30,35 @@
 import java.nio.file.Paths;
 
 class Module extends AbstractModule {
+  private final Configuration config;
+
+  @Inject
+  Module(Configuration config) {
+    this.config = config;
+  }
 
   @Override
   protected void configure() {
-    bind(Configuration.class).in(Scopes.SINGLETON);
     install(new ForwarderModule());
     install(new RestForwarderModule());
-    install(new EventModule());
-    install(new IndexModule());
-    install(new CacheModule());
+
+    if (config.cache().synchronize()) {
+      install(new CacheModule());
+    }
+    if (config.event().synchronize()) {
+      install(new EventModule());
+    }
+    if (config.index().synchronize()) {
+      install(new IndexModule());
+    }
     install(new PeerInfoModule());
   }
 
   @Provides
   @Singleton
   @SharedDirectory
-  Path getSharedDirectory(Configuration cfg) throws IOException {
-    Path sharedDirectoryPath = Paths.get(cfg.main().sharedDirectory());
+  Path getSharedDirectory() throws IOException {
+    Path sharedDirectoryPath = Paths.get(config.main().sharedDirectory());
     Files.createDirectories(sharedDirectoryPath);
     return sharedDirectoryPath;
   }
diff --git a/src/main/resources/Documentation/config.md b/src/main/resources/Documentation/config.md
index 3290f1b..5faa11d 100644
--- a/src/main/resources/Documentation/config.md
+++ b/src/main/resources/Documentation/config.md
@@ -50,14 +50,30 @@
 :   The interval of time in milliseconds between the subsequent auto-retries.
     When not specified, the default value is set to 1000ms.
 
+cache.synchronize
+:   Whether to synchronize cache evictions.
+    Defaults to true.
+
 cache.threadPoolSize
 :   Maximum number of threads used to send cache evictions to the target instance.
     Defaults to 1.
 
+event.synchronize
+:   Whether to synchronize stream events.
+    Defaults to true.
+
+index.synchronize
+:   Whether to synchronize secondary indexes.
+    Defaults to true.
+
 index.threadPoolSize
 :   Maximum number of threads used to send index events to the target instance.
     Defaults to 1.
 
+websession.synchronize
+:   Whether to synchronize web sessions.
+    Defaults to true.
+
 websession.cleanupInterval
 :   Frequency for deleting expired web sessions. Values should use common time
     unit suffixes to express their setting:
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 31449e3..bb50a4d 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ConfigurationTest.java
@@ -20,8 +20,10 @@
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_CLEANUP_INTERVAL_MS;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_MAX_TRIES;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_RETRY_INTERVAL;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_SYNCHRONIZE;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_THREAD_POOL_SIZE;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.DEFAULT_TIMEOUT_MS;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.EVENT_SECTION;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.HTTP_SECTION;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.INDEX_SECTION;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.MAIN_SECTION;
@@ -31,6 +33,7 @@
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.RETRY_INTERVAL_KEY;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.SHARED_DIRECTORY_KEY;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.SOCKET_TIMEOUT_KEY;
+import static com.ericsson.gerrit.plugins.highavailability.Configuration.SYNCHRONIZE_KEY;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.THREAD_POOL_SIZE_KEY;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.URL_KEY;
 import static com.ericsson.gerrit.plugins.highavailability.Configuration.USER_KEY;
@@ -195,6 +198,24 @@
   }
 
   @Test
+  public void testGetIndexSynchronize() throws Exception {
+    when(configMock.getBoolean(INDEX_SECTION, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE))
+        .thenReturn(true);
+    initializeConfiguration();
+    assertThat(configuration.index().synchronize()).isTrue();
+
+    when(configMock.getBoolean(INDEX_SECTION, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE))
+        .thenReturn(false);
+    initializeConfiguration();
+    assertThat(configuration.index().synchronize()).isFalse();
+
+    when(configMock.getBoolean(INDEX_SECTION, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE))
+        .thenThrow(new IllegalArgumentException(ERROR_MESSAGE));
+    initializeConfiguration();
+    assertThat(configuration.index().synchronize()).isTrue();
+  }
+
+  @Test
   public void testGetCacheThreadPoolSize() throws Exception {
     initializeConfiguration();
     assertThat(configuration.cache().threadPoolSize()).isEqualTo(0);
@@ -211,6 +232,42 @@
   }
 
   @Test
+  public void testGetCacheSynchronize() throws Exception {
+    when(configMock.getBoolean(CACHE_SECTION, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE))
+        .thenReturn(true);
+    initializeConfiguration();
+    assertThat(configuration.cache().synchronize()).isTrue();
+
+    when(configMock.getBoolean(CACHE_SECTION, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE))
+        .thenReturn(false);
+    initializeConfiguration();
+    assertThat(configuration.cache().synchronize()).isFalse();
+
+    when(configMock.getBoolean(CACHE_SECTION, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE))
+        .thenThrow(new IllegalArgumentException(ERROR_MESSAGE));
+    initializeConfiguration();
+    assertThat(configuration.cache().synchronize()).isTrue();
+  }
+
+  @Test
+  public void testGetEventSynchronize() throws Exception {
+    when(configMock.getBoolean(EVENT_SECTION, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE))
+        .thenReturn(true);
+    initializeConfiguration();
+    assertThat(configuration.event().synchronize()).isTrue();
+
+    when(configMock.getBoolean(EVENT_SECTION, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE))
+        .thenReturn(false);
+    initializeConfiguration();
+    assertThat(configuration.event().synchronize()).isFalse();
+
+    when(configMock.getBoolean(EVENT_SECTION, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE))
+        .thenThrow(new IllegalArgumentException(ERROR_MESSAGE));
+    initializeConfiguration();
+    assertThat(configuration.event().synchronize()).isTrue();
+  }
+
+  @Test
   public void testGetSharedDirectory() throws Exception {
     initializeConfiguration();
     assertThat(configuration.main().sharedDirectory()).isEqualTo(SHARED_DIRECTORY);
@@ -232,4 +289,22 @@
     initializeConfiguration();
     assertThat(configuration.websession().cleanupInterval()).isEqualTo(SECONDS.toMillis(30));
   }
+
+  @Test
+  public void testGetWebsessionSynchronize() throws Exception {
+    when(configMock.getBoolean(WEBSESSION_SECTION, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE))
+        .thenReturn(true);
+    initializeConfiguration();
+    assertThat(configuration.websession().synchronize()).isTrue();
+
+    when(configMock.getBoolean(WEBSESSION_SECTION, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE))
+        .thenReturn(false);
+    initializeConfiguration();
+    assertThat(configuration.websession().synchronize()).isFalse();
+
+    when(configMock.getBoolean(WEBSESSION_SECTION, SYNCHRONIZE_KEY, DEFAULT_SYNCHRONIZE))
+        .thenThrow(new IllegalArgumentException(ERROR_MESSAGE));
+    initializeConfiguration();
+    assertThat(configuration.websession().synchronize()).isTrue();
+  }
 }
diff --git a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ModuleTest.java b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ModuleTest.java
index c577a01..746c694 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/highavailability/ModuleTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/highavailability/ModuleTest.java
@@ -41,7 +41,7 @@
 
   @Before
   public void setUp() {
-    module = new Module();
+    module = new Module(configMock);
   }
 
   @Test
@@ -50,7 +50,7 @@
     assertThat(configuredDirectory.delete()).isTrue();
     when(configMock.main().sharedDirectory()).thenReturn(configuredDirectory.getAbsolutePath());
 
-    Path sharedDirectory = module.getSharedDirectory(configMock);
+    Path sharedDirectory = module.getSharedDirectory();
     assertThat(sharedDirectory.toFile().exists()).isTrue();
   }
 
@@ -59,6 +59,6 @@
     File configuredDirectory = tempFolder.newFile();
     when(configMock.main().sharedDirectory()).thenReturn(configuredDirectory.getAbsolutePath());
 
-    module.getSharedDirectory(configMock);
+    module.getSharedDirectory();
   }
 }