Merge branch 'stable-2.14'

* stable-2.14:
  Remove redundant type definition
  Fix documentation
  Fix broken default configuration
  Remove buck build
  Stand-alone bazel build for events-log plugin
  Attach sources of byte-buddy and objenesis in eclipse
  Fix in-tree Eclipse project generation
  Remove dependency already packaged in gerrit-plugin-api
  Use double quotes in external_plugin_deps.bzl
  Format build file with buildifier

Test plan:

- bazel clean --expunge
- bazel build events-log
- bazel test --nocache_test_results //...
- Deploy plugin to gerrit master site
- Verify plugin loads without errors
- Do some change operations: create change, review, rebase, etc...
- Query REST endpoint
- Verify events for above operations are present

Just checking that a plugin builds is not enough to vote Verified

Change-Id: Ib735d186965fc645fddf242ed4c15a574e5d4444
diff --git a/WORKSPACE b/WORKSPACE
index cd861c2..91147b7 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,27 +3,27 @@
 load("//:bazlets.bzl", "load_bazlets")
 
 load_bazlets(
-    commit = "e8160a65a591e602a2fb48953b269dd8d42a7c37",
+    commit = "b7514d03a7798905ff1513295b46620e57b8f386",
     #    local_path = "/home/<user>/projects/bazlets",
 )
 
 #Snapshot Plugin API
-#load(
-#    "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
-#    "gerrit_api_maven_local",
-#)
-
-# Load snapshot Plugin API
-#gerrit_api_maven_local()
-
-# Release Plugin API
 load(
-    "@com_googlesource_gerrit_bazlets//:gerrit_api.bzl",
-    "gerrit_api",
+    "@com_googlesource_gerrit_bazlets//:gerrit_api_maven_local.bzl",
+    "gerrit_api_maven_local",
 )
 
+# Load snapshot Plugin API
+gerrit_api_maven_local()
+
+# Release Plugin API
+#load(
+#    "@com_googlesource_gerrit_bazlets//:gerrit_api.bzl",
+#    "gerrit_api",
+#)
+
 # Load release Plugin API
-gerrit_api()
+#gerrit_api()
 
 load("//:external_plugin_deps.bzl", "external_plugin_deps")
 
diff --git a/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventHandler.java b/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventHandler.java
index 4c92dd2..7e2a4c1 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventHandler.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventHandler.java
@@ -19,18 +19,18 @@
 import com.google.gerrit.server.events.ProjectEvent;
 import com.google.inject.Inject;
 
-import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ScheduledExecutorService;
 
 /**
  * Listen to Events and store them into the EventStore
  */
 class EventHandler implements EventListener {
   private final EventStore store;
-  private final ScheduledThreadPoolExecutor pool;
+  private final ScheduledExecutorService pool;
 
   @Inject
   EventHandler(EventStore store,
-      @EventPool ScheduledThreadPoolExecutor pool) {
+      @EventPool ScheduledExecutorService pool) {
     this.store = store;
     this.pool = pool;
   }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventModule.java b/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventModule.java
index 04b4abd..1098759 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventModule.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventModule.java
@@ -22,7 +22,7 @@
 import com.google.inject.Scopes;
 import com.google.inject.internal.UniqueAnnotations;
 
-import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ScheduledExecutorService;
 
 /** Configures handling for an event queue while providing its pool. */
 public class EventModule extends AbstractModule {
@@ -39,7 +39,7 @@
 
   @Provides
   @EventPool
-  ScheduledThreadPoolExecutor provideEventPool(EventQueue queue) {
+  ScheduledExecutorService provideEventPool(EventQueue queue) {
     return queue.getPool();
   }
 }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventPool.java b/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventPool.java
index 25aeef4..1c3f536 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventPool.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventPool.java
@@ -21,7 +21,7 @@
 import java.lang.annotation.Retention;
 
 /**
- * Annotation applied to a ScheduledThreadPoolExecutor.
+ * Annotation applied to a ScheduledExecutorService.
  */
 @Retention(RUNTIME)
 @BindingAnnotation
diff --git a/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventQueue.java b/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventQueue.java
index cdb3fb9..5ec6bfd 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventQueue.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/eventslog/EventQueue.java
@@ -18,12 +18,12 @@
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.inject.Inject;
 
-import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ScheduledExecutorService;
 
 /** A queue for events to store. */
 public class EventQueue implements LifecycleListener {
   private final WorkQueue workQueue;
-  private WorkQueue.Executor pool;
+  private ScheduledExecutorService pool;
 
   @Inject
   EventQueue(WorkQueue workQueue) {
@@ -42,12 +42,11 @@
   @Override
   public void stop() {
     if (pool != null) {
-      pool.unregisterWorkQueue();
       pool = null;
     }
   }
 
-  ScheduledThreadPoolExecutor getPool() {
+  ScheduledExecutorService getPool() {
     return this.pool;
   }
 }
diff --git a/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLStore.java b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLStore.java
index 4947f78..7224b38 100644
--- a/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLStore.java
+++ b/src/main/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLStore.java
@@ -19,11 +19,13 @@
 import com.google.common.io.Files;
 import com.google.gerrit.common.TimeUtil;
 import com.google.gerrit.extensions.events.LifecycleListener;
+import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.events.ProjectEvent;
-import com.google.gerrit.server.project.NoSuchProjectException;
-import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.permissions.ProjectPermission;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import com.google.inject.Singleton;
@@ -48,7 +50,7 @@
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 @Singleton
@@ -56,7 +58,6 @@
   private static final Logger log = LoggerFactory.getLogger(SQLStore.class);
   private static final String H2_DB_SUFFIX = ".h2.db";
 
-  private final ProjectControl.GenericFactory projectControlFactory;
   private final Provider<CurrentUser> userProvider;
   private SQLClient eventsDb;
   private SQLClient localEventsDb;
@@ -66,27 +67,28 @@
   private final int connectTime;
   private boolean online = true;
   private boolean copyLocal;
-  private final ScheduledThreadPoolExecutor pool;
+  private final ScheduledExecutorService pool;
+  private final PermissionBackend permissionBackend;
   private ScheduledFuture<?> checkConnTask;
   private Path localPath;
 
   @Inject
-  SQLStore(ProjectControl.GenericFactory projectControlFactory,
-      Provider<CurrentUser> userProvider,
+  SQLStore(Provider<CurrentUser> userProvider,
       EventsLogConfig cfg,
       @EventsDb SQLClient eventsDb,
       @LocalEventsDb SQLClient localEventsDb,
-      @EventPool ScheduledThreadPoolExecutor pool) {
+      @EventPool ScheduledExecutorService pool,
+      PermissionBackend permissionBackend) {
     this.maxAge = cfg.getMaxAge();
     this.maxTries = cfg.getMaxTries();
     this.waitTime = cfg.getWaitTime();
     this.connectTime = cfg.getConnectTime();
     this.copyLocal = cfg.getCopyLocal();
-    this.projectControlFactory = projectControlFactory;
     this.userProvider = userProvider;
     this.eventsDb = eventsDb;
     this.localEventsDb = localEventsDb;
     this.pool = pool;
+    this.permissionBackend = permissionBackend;
     this.localPath = cfg.getLocalStorePath();
   }
 
@@ -119,17 +121,15 @@
         : eventsDb.getEvents(query).asMap().entrySet()) {
       String projectName = entry.getKey();
       try {
-        if (projectControlFactory.controlFor(new Project.NameKey(projectName),
-            userProvider.get()).isVisible()) {
-          entries.addAll(entry.getValue());
-        }
-      } catch (NoSuchProjectException e) {
-        log.warn("Database contains a non-existing project, " + projectName
-            + ", removing project from database");
-        eventsDb.removeProjectEvents(projectName);
-      } catch (IOException e) {
-        log.warn("Cannot get project visibility info for " + projectName
-            + " from cache", e);
+        permissionBackend
+            .user(userProvider)
+            .project(new Project.NameKey(projectName))
+            .check(ProjectPermission.ACCESS);
+        entries.addAll(entry.getValue());
+      } catch (AuthException e) {
+        // Ignore
+      } catch (PermissionBackendException e) {
+        log.warn("Cannot check project access permission", e);
       }
     }
     return sortedEventsFromEntries(entries);
diff --git a/src/test/java/com/ericsson/gerrit/plugins/eventslog/EventHandlerTest.java b/src/test/java/com/ericsson/gerrit/plugins/eventslog/EventHandlerTest.java
index 68f1ea4..af1cfa8 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/eventslog/EventHandlerTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/eventslog/EventHandlerTest.java
@@ -28,6 +28,7 @@
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
+import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 
 @RunWith(MockitoJUnitRunner.class)
@@ -38,7 +39,7 @@
 
   @Before
   public void setUp() {
-    ScheduledThreadPoolExecutor poolMock = new PoolMock();
+    ScheduledExecutorService poolMock = new PoolMock();
     eventHandler = new EventHandler(storeMock, poolMock);
   }
 
diff --git a/src/test/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLStoreTest.java b/src/test/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLStoreTest.java
index e506e26..8a95c9a 100644
--- a/src/test/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLStoreTest.java
+++ b/src/test/java/com/ericsson/gerrit/plugins/eventslog/sql/SQLStoreTest.java
@@ -17,6 +17,7 @@
 import static com.ericsson.gerrit.plugins.eventslog.sql.SQLTable.TABLE_NAME;
 import static com.google.common.truth.Truth.assertThat;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -25,11 +26,11 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.reviewdb.client.Project.NameKey;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.events.ProjectEvent;
-import com.google.gerrit.server.project.NoSuchProjectException;
-import com.google.gerrit.server.project.ProjectControl;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackendException;
+import com.google.gerrit.server.permissions.ProjectPermission;
 import com.google.gson.Gson;
 import com.google.inject.Provider;
 
@@ -47,7 +48,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.IOException;
 import java.net.ConnectException;
 import java.sql.Connection;
 import java.sql.DriverManager;
@@ -58,6 +58,7 @@
 import java.util.List;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.TimeUnit;
 
 @RunWith(MockitoJUnitRunner.class)
@@ -71,21 +72,24 @@
   private static final String TERM_CONN_MSG = "terminating connection";
   private static final String MSG = "message";
   private static final String GENERIC_QUERY = "SELECT * FROM " + TABLE_NAME;
-  private static final boolean PROJECT_VISIBLE_TO_USER = true;
-  private static final boolean PROJECT_NOT_VISIBLE_TO_USER = false;
 
   @Mock
-  private ProjectControl.GenericFactory pcFactoryMock;
-  @Mock
   private Provider<CurrentUser> userProviderMock;
   @Mock
   private EventsLogConfig cfgMock;
+  @Mock
+  private PermissionBackend permissionBackendMock;
+  @Mock
+  private PermissionBackend.ForProject forProjectMock;
+  @Mock
+  private PermissionBackend.WithUser withUserMock;
+
   private SQLClient eventsDb;
   private SQLClient localEventsDb;
   private SQLStore store;
-  private ScheduledThreadPoolExecutor poolMock;
-
+  private ScheduledExecutorService poolMock;
   private Statement stat;
+  private MockEvent mockEvent;
 
   @Rule
   public TemporaryFolder testFolder = new TemporaryFolder();
@@ -94,6 +98,7 @@
   public void setUp() throws SQLException {
     Connection conn =
         DriverManager.getConnection(TEST_URL + ";" + TEST_OPTIONS);
+    mockEvent = new MockEvent();
     stat = conn.createStatement();
     poolMock = new PoolMock();
     when(cfgMock.getMaxAge()).thenReturn(5);
@@ -105,23 +110,13 @@
     store.stop();
   }
 
-  private void setUpClient() {
-    eventsDb = new SQLClient(TEST_DRIVER, TEST_URL, TEST_OPTIONS);
-    localEventsDb = new SQLClient(TEST_DRIVER, TEST_LOCAL_URL, TEST_OPTIONS);
-    store = new SQLStore(pcFactoryMock, userProviderMock, cfgMock, eventsDb,
-        localEventsDb, poolMock);
-    store.start();
-  }
-
-  private void setUpClientMock() throws SQLException {
-    eventsDb = mock(SQLClient.class);
-    localEventsDb = mock(SQLClient.class);
-    when(localEventsDb.dbExists()).thenReturn(true);
-  }
-
   @Test
   public void storeThenQueryVisible() throws Exception {
-    MockEvent mockEvent = setUpMocks(PROJECT_VISIBLE_TO_USER);
+    when(permissionBackendMock.user(userProviderMock)).thenReturn(withUserMock);
+    when(withUserMock.project(any(Project.NameKey.class)))
+        .thenReturn(forProjectMock);
+    doNothing().when(forProjectMock).check(ProjectPermission.ACCESS);
+    setUpClient();
     store.storeEvent(mockEvent);
     List<String> events = store.queryChangeEvents(GENERIC_QUERY);
     String json = new Gson().toJson(mockEvent);
@@ -131,26 +126,18 @@
 
   @Test
   public void storeThenQueryNotVisible() throws Exception {
-    MockEvent mockEvent = setUpMocks(PROJECT_NOT_VISIBLE_TO_USER);
+    when(permissionBackendMock.user(userProviderMock)).thenReturn(withUserMock);
+    when(withUserMock.project(any(Project.NameKey.class)))
+        .thenReturn(forProjectMock);
+    doThrow(new PermissionBackendException("")).when(forProjectMock)
+        .check(ProjectPermission.ACCESS);
+    setUpClient();
     store.storeEvent(mockEvent);
     List<String> events = store.queryChangeEvents(GENERIC_QUERY);
     assertThat(events).isEmpty();
     tearDown();
   }
 
-  private MockEvent setUpMocks(boolean isVisible)
-      throws NoSuchProjectException, IOException {
-    MockEvent mockEvent = new MockEvent();
-    ProjectControl pcMock = mock(ProjectControl.class);
-    CurrentUser userMock = mock(CurrentUser.class);
-    when(userProviderMock.get()).thenReturn(userMock);
-    when(pcFactoryMock.controlFor(mockEvent.getProjectNameKey(), userMock))
-        .thenReturn(pcMock);
-    when(pcMock.isVisible()).thenReturn(isVisible);
-    setUpClient();
-    return mockEvent;
-  }
-
   @Test(expected = MalformedQueryException.class)
   public void throwBadRequestTriggerOnBadQuery() throws Exception {
     setUpClient();
@@ -159,29 +146,12 @@
   }
 
   @Test
-  public void notReturnEventOfNonExistingProject() throws Exception {
-    MockEvent mockEvent = new MockEvent();
-    Project.NameKey projectMock = mock(Project.NameKey.class);
-    CurrentUser userMock = mock(CurrentUser.class);
-    when(userProviderMock.get()).thenReturn(userMock);
-    NameKey projectNameKey = mockEvent.getProjectNameKey();
-    doThrow(new NoSuchProjectException(projectMock)).when(pcFactoryMock)
-        .controlFor(projectNameKey, userMock);
-    setUpClient();
-    store.storeEvent(mockEvent);
-    List<String> events = store.queryChangeEvents(GENERIC_QUERY);
-    assertThat(events).isEmpty();
-    tearDown();
-  }
-
-  @Test
   public void notReturnEventWithNoVisibilityInfo() throws Exception {
-    MockEvent mockEvent = new MockEvent();
-    CurrentUser userMock = mock(CurrentUser.class);
-    when(userProviderMock.get()).thenReturn(userMock);
-    NameKey projectNameKey = mockEvent.getProjectNameKey();
-    doThrow(new IOException()).when(pcFactoryMock).controlFor(projectNameKey,
-        userMock);
+    when(permissionBackendMock.user(userProviderMock)).thenReturn(withUserMock);
+    when(withUserMock.project(any(Project.NameKey.class)))
+        .thenReturn(forProjectMock);
+    doThrow(new PermissionBackendException("")).when(forProjectMock)
+        .check(ProjectPermission.ACCESS);
     setUpClient();
     store.storeEvent(mockEvent);
     List<String> events = store.queryChangeEvents(GENERIC_QUERY);
@@ -191,15 +161,14 @@
 
   @Test
   public void retryOnConnectException() throws Exception {
-    MockEvent mockEvent = new MockEvent();
     when(cfgMock.getMaxTries()).thenReturn(3);
     Throwable[] exceptions = new Throwable[3];
     Arrays.fill(exceptions, new SQLException(new ConnectException()));
     setUpClientMock();
     doThrow(exceptions).doNothing().when(eventsDb).storeEvent(mockEvent);
     doThrow(exceptions).doNothing().when(eventsDb).queryOne();
-    store = new SQLStore(pcFactoryMock, userProviderMock, cfgMock, eventsDb,
-        localEventsDb, poolMock);
+    store = new SQLStore(userProviderMock, cfgMock, eventsDb,
+        localEventsDb, poolMock, permissionBackendMock);
     store.start();
     store.storeEvent(mockEvent);
     verify(eventsDb, times(3)).storeEvent(mockEvent);
@@ -208,15 +177,14 @@
 
   @Test
   public void retryOnMessage() throws Exception {
-    MockEvent mockEvent = new MockEvent();
     when(cfgMock.getMaxTries()).thenReturn(3);
     Throwable[] exceptions = new Throwable[3];
     Arrays.fill(exceptions, new SQLException(TERM_CONN_MSG));
     setUpClientMock();
     doThrow(exceptions).doNothing().when(eventsDb).storeEvent(mockEvent);
     doThrow(exceptions).doNothing().when(eventsDb).queryOne();
-    store = new SQLStore(pcFactoryMock, userProviderMock, cfgMock, eventsDb,
-        localEventsDb, poolMock);
+    store = new SQLStore(userProviderMock, cfgMock, eventsDb,
+        localEventsDb, poolMock, permissionBackendMock);
     store.start();
     store.storeEvent(mockEvent);
     verify(eventsDb, times(3)).storeEvent(mockEvent);
@@ -225,12 +193,11 @@
 
   @Test
   public void noRetryOnMessage() throws Exception {
-    MockEvent mockEvent = new MockEvent();
     when(cfgMock.getMaxTries()).thenReturn(3);
     setUpClientMock();
     doThrow(new SQLException(MSG)).when(eventsDb).storeEvent(mockEvent);
-    store = new SQLStore(pcFactoryMock, userProviderMock, cfgMock, eventsDb,
-        localEventsDb, poolMock);
+    store = new SQLStore(userProviderMock, cfgMock, eventsDb,
+        localEventsDb, poolMock, permissionBackendMock);
     store.start();
     store.storeEvent(mockEvent);
     verify(eventsDb, times(1)).storeEvent(mockEvent);
@@ -238,15 +205,14 @@
 
   @Test
   public void noRetryOnZeroMaxTries() throws Exception {
-    MockEvent mockEvent = new MockEvent();
     when(cfgMock.getMaxTries()).thenReturn(0);
     Throwable[] exceptions = new Throwable[3];
     Arrays.fill(exceptions, new SQLException(new ConnectException()));
     setUpClientMock();
     doThrow(exceptions).doNothing().when(eventsDb).storeEvent(mockEvent);
     doThrow(exceptions).doNothing().when(eventsDb).queryOne();
-    store = new SQLStore(pcFactoryMock, userProviderMock, cfgMock, eventsDb,
-        localEventsDb, poolMock);
+    store = new SQLStore(userProviderMock, cfgMock, eventsDb,
+        localEventsDb, poolMock, permissionBackendMock);
     store.start();
     store.storeEvent(mockEvent);
     verify(eventsDb, times(1)).storeEvent(mockEvent);
@@ -254,46 +220,36 @@
 
   @Test(expected = ServiceUnavailableException.class)
   public void throwSQLExceptionIfNotOnline() throws Exception {
-    MockEvent mockEvent = new MockEvent();
     setUpClientMock();
     doThrow(new SQLException(new ConnectException())).when(eventsDb)
         .createDBIfNotCreated();
     doThrow(new SQLException()).when(eventsDb).queryOne();
-    store = new SQLStore(pcFactoryMock, userProviderMock, cfgMock, eventsDb,
-        localEventsDb, poolMock);
+    store = new SQLStore(userProviderMock, cfgMock, eventsDb,
+        localEventsDb, poolMock, permissionBackendMock);
     store.start();
     store.storeEvent(mockEvent);
     store.queryChangeEvents(GENERIC_QUERY);
   }
 
   @Test
-  public void restoreFromLocalAndRemoveUnfoundProjectEvents() throws Exception {
+  public void restoreEventsFromLocalDb() throws Exception {
     MockEvent mockEvent = new MockEvent();
     MockEvent mockEvent2 = new MockEvent("proj");
-    MockEvent mockEvent3 = new MockEvent("unfound");
-
-    ProjectControl pc = mock(ProjectControl.class);
-    NoSuchProjectException e = mock(NoSuchProjectException.class);
-    CurrentUser userMock = mock(CurrentUser.class);
-    when(userProviderMock.get()).thenReturn(userMock);
-    when(pcFactoryMock.controlFor((mockEvent.getProjectNameKey()), userMock))
-        .thenReturn(pc);
-    when(pcFactoryMock.controlFor((mockEvent2.getProjectNameKey()), userMock))
-        .thenReturn(pc);
-    when(pc.isVisible()).thenReturn(true);
-    doThrow(e).when(pcFactoryMock).controlFor((mockEvent3.getProjectNameKey()),
-        userMock);
+    when(permissionBackendMock.user(userProviderMock)).thenReturn(withUserMock);
+    when(withUserMock.project(any(Project.NameKey.class)))
+        .thenReturn(forProjectMock);
+    doNothing().when(forProjectMock).check(ProjectPermission.ACCESS);
 
     eventsDb = new SQLClient(TEST_DRIVER, TEST_URL, TEST_OPTIONS);
     localEventsDb = new SQLClient(TEST_DRIVER, TEST_LOCAL_URL, TEST_OPTIONS);
-    store = new SQLStore(pcFactoryMock, userProviderMock, cfgMock, eventsDb,
-        localEventsDb, poolMock);
+    store = new SQLStore(userProviderMock, cfgMock, eventsDb,
+        localEventsDb, poolMock, permissionBackendMock);
 
     localEventsDb.createDBIfNotCreated();
     localEventsDb.storeEvent(mockEvent);
     localEventsDb.storeEvent(mockEvent2);
-    localEventsDb.storeEvent(mockEvent3);
     store.start();
+
     List<String> events = store.queryChangeEvents(GENERIC_QUERY);
     Gson gson = new Gson();
     String json = gson.toJson(mockEvent);
@@ -308,21 +264,20 @@
     doThrow(new SQLException(new ConnectException())).when(eventsDb)
         .createDBIfNotCreated();
     doThrow(new SQLException()).when(eventsDb).queryOne();
-    store = new SQLStore(pcFactoryMock, userProviderMock, cfgMock, eventsDb,
-        localEventsDb, poolMock);
+    store = new SQLStore(userProviderMock, cfgMock, eventsDb,
+        localEventsDb, poolMock, permissionBackendMock);
     store.start();
     verify(localEventsDb).createDBIfNotCreated();
   }
 
   @Test
   public void storeLocalOffline() throws Exception {
-    MockEvent mockEvent = new MockEvent();
     setUpClientMock();
     doThrow(new SQLException(new ConnectException())).when(eventsDb)
         .createDBIfNotCreated();
     doThrow(new SQLException()).when(eventsDb).queryOne();
-    store = new SQLStore(pcFactoryMock, userProviderMock, cfgMock, eventsDb,
-        localEventsDb, poolMock);
+    store = new SQLStore(userProviderMock, cfgMock, eventsDb,
+        localEventsDb, poolMock, permissionBackendMock);
     store.start();
     store.storeEvent(mockEvent);
     verify(localEventsDb).storeEvent(mockEvent);
@@ -330,19 +285,32 @@
 
   @Test
   public void storeLocalOfflineAfterNoRetry() throws Exception {
-    MockEvent mockEvent = new MockEvent();
     setUpClientMock();
     when(cfgMock.getMaxTries()).thenReturn(0);
     doThrow(new SQLException(new ConnectException())).when(eventsDb)
         .createDBIfNotCreated();
     doThrow(new SQLException()).when(eventsDb).queryOne();
-    store = new SQLStore(pcFactoryMock, userProviderMock, cfgMock, eventsDb,
-        localEventsDb, poolMock);
+    store = new SQLStore(userProviderMock, cfgMock, eventsDb,
+        localEventsDb, poolMock, permissionBackendMock);
     store.start();
     store.storeEvent(mockEvent);
     verify(localEventsDb).storeEvent(mockEvent);
   }
 
+  private void setUpClient() {
+    eventsDb = new SQLClient(TEST_DRIVER, TEST_URL, TEST_OPTIONS);
+    localEventsDb = new SQLClient(TEST_DRIVER, TEST_LOCAL_URL, TEST_OPTIONS);
+    store = new SQLStore(userProviderMock, cfgMock, eventsDb,
+        localEventsDb, poolMock, permissionBackendMock);
+    store.start();
+  }
+
+  private void setUpClientMock() throws SQLException {
+    eventsDb = mock(SQLClient.class);
+    localEventsDb = mock(SQLClient.class);
+    when(localEventsDb.dbExists()).thenReturn(true);
+  }
+
   /**
    * For this test we expect that if we can connect to main database, then we
    * should come back online and try setting up again. We just want to make sure
@@ -356,8 +324,8 @@
     when(localEventsDb.dbExists()).thenReturn(true);
     when(localEventsDb.getAll())
         .thenReturn(ImmutableList.of(mock(SQLEntry.class)));
-    store = new SQLStore(pcFactoryMock, userProviderMock, cfgMock, eventsDb,
-        localEventsDb, poolMock);
+    store = new SQLStore(userProviderMock, cfgMock, eventsDb,
+        localEventsDb, poolMock, permissionBackendMock);
     store.start();
     poolMock.scheduleWithFixedDelay(store.new CheckConnectionTask(), 0, 0,
         TimeUnit.MILLISECONDS);
@@ -375,7 +343,6 @@
   }
 
   private void checkConnectionAndRestore(boolean copy) throws Exception {
-    MockEvent mockEvent = new MockEvent();
     eventsDb = mock(SQLClient.class);
     localEventsDb = new SQLClient(TEST_DRIVER, TEST_LOCAL_URL, TEST_OPTIONS);
     localEventsDb.createDBIfNotCreated();
@@ -387,8 +354,8 @@
       when(cfgMock.getCopyLocal()).thenReturn(true);
     }
 
-    store = new SQLStore(pcFactoryMock, userProviderMock, cfgMock, eventsDb,
-        localEventsDb, poolMock);
+    store = new SQLStore(userProviderMock, cfgMock, eventsDb,
+        localEventsDb, poolMock, permissionBackendMock);
     store.start();
     verify(eventsDb).queryOne();
     verify(eventsDb).storeEvent(any(String.class), any(Timestamp.class),