Allow reloading secure.config

Align with Gerrit master ability to detect changes on secure.config
and reload it dynamically.

NOTE: The missing @Override annotations are explicitly left behind
to allow both stable-2.14 and master compilations succeed

Change-Id: Idc8ec91d2eba6ab7e3d93699403f2388bb04f0bf
diff --git a/src/main/java/com/googlesource/gerrit/plugins/secureconfig/SecureConfigStore.java b/src/main/java/com/googlesource/gerrit/plugins/secureconfig/SecureConfigStore.java
index 9d657d3..1d6c8b4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/secureconfig/SecureConfigStore.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/secureconfig/SecureConfigStore.java
@@ -42,6 +42,7 @@
   private final Map<String, FileBasedConfig> pluginSec;
   private final SitePaths site;
   private final Codec codec;
+  private long secFileLastmodified;
 
   @Inject
   SecureConfigStore(SitePaths site, PBECodec codec) {
@@ -50,6 +51,7 @@
     sec = new FileBasedConfig(site.secure_config.toFile(), FS.DETECTED);
     try {
       sec.load();
+      secFileLastmodified = sec.getFile().lastModified();
     } catch (IOException | ConfigInvalidException e) {
       throw new RuntimeException("Cannot load secure.config", e);
     }
@@ -123,6 +125,21 @@
     return result;
   }
 
+  /** @return <code>true</code> if currently loaded values are outdated */
+  public boolean isOutdated() {
+    long secFileCurrLastModified = sec.getFile().lastModified();
+    return secFileCurrLastModified > secFileLastmodified;
+  }
+
+  /** Reload the values */
+  public void reload() {
+    try {
+      sec.load();
+    } catch (IOException | ConfigInvalidException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
   private void save() {
     try {
       saveSecure(sec);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/secureconfig/SecureConfigStoreTest.java b/src/test/java/com/googlesource/gerrit/plugins/secureconfig/SecureConfigStoreTest.java
new file mode 100644
index 0000000..1095547
--- /dev/null
+++ b/src/test/java/com/googlesource/gerrit/plugins/secureconfig/SecureConfigStoreTest.java
@@ -0,0 +1,91 @@
+// Copyright (C) 2017 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.googlesource.gerrit.plugins.secureconfig;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import com.google.gerrit.server.config.SitePaths;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Writer;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.junit.Test;
+
+public class SecureConfigStoreTest {
+
+  @Test
+  public void shouldNotBeOutdatedWhenLoaded() throws Exception {
+    SecureConfigStore secureConfigStore = newSecureStore(createTempSecureConfigInSitePaths());
+
+    assertThat(secureConfigStore.isOutdated(), is(equalTo(false)));
+  }
+
+  @Test
+  public void shouldBeOutdatedWhenFileIsChangedAfterLoad() throws Exception {
+    SitePaths sitePaths = createTempSecureConfigInSitePaths();
+    SecureConfigStore secureConfigStore = newSecureStore(sitePaths);
+
+    Thread.sleep(1000L);
+
+    File secureConfigFile = sitePaths.secure_config.toFile();
+    try (Writer writer = new FileWriter(secureConfigFile, true)) {
+      writer.write("foo");
+    }
+
+    assertThat(secureConfigStore.isOutdated(), is(equalTo(true)));
+  }
+
+  @Test
+  public void shouldReloadNewContent() throws Exception {
+    SitePaths sitePaths = createTempSecureConfigInSitePaths();
+    PBECodec codec = newCodec(sitePaths);
+    SecureConfigStore secureConfigStore = new SecureConfigStore(sitePaths, codec);
+
+    File secureConfigFile = sitePaths.secure_config.toFile();
+    try (Writer writer = new FileWriter(secureConfigFile, true)) {
+      writer.write("[test]\n" + "foo=" + codec.encode("bar"));
+    }
+
+    secureConfigStore.reload();
+
+    assertThat(secureConfigStore.get("test", null, "foo"), is(equalTo("bar")));
+  }
+
+  private SitePaths createTempSecureConfigInSitePaths() {
+    try {
+      Path gerritSite = Files.createTempDirectory(SecureConfigStoreTest.class.getName());
+      gerritSite.resolve("etc").toFile().mkdirs();
+      File secureConfigFile = gerritSite.resolve("etc").resolve("secure.config").toFile();
+      secureConfigFile.createNewFile();
+      return new SitePaths(gerritSite);
+    } catch (IOException e) {
+      throw new IllegalStateException(e);
+    }
+  }
+
+  private SecureConfigStore newSecureStore(SitePaths sitePaths)
+      throws IOException, ConfigInvalidException {
+    return new SecureConfigStore(sitePaths, newCodec(sitePaths));
+  }
+
+  private PBECodec newCodec(SitePaths sitePaths) throws ConfigInvalidException, IOException {
+    return new PBECodec(new SecureConfigSettings(sitePaths));
+  }
+}