Allow AdminApiFactory to be replaced dynamically
Since change Ie760bf3e1 the GerritSshApi class is no longer a singleton,
and is instead instantiated on demand by a new AdminApiFactory.
This breaks implementations that consume the replication plugin as a
library and extend the GerritSshApi, since the extended class no longer
gets instantiated in place of GerritSshApi.
Refactor it so that AdminApiFactory is an interface with a default
implementation that gets bound as a dynamic item, which can be replaced
by derived implementations.
Change-Id: Ia150d6802e11015fa00ee9144b3dfbfa696c7a0d
Signed-off-by: David Pursehouse <dpursehouse@collab.net>
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/AdminApiFactory.java b/src/main/java/com/googlesource/gerrit/plugins/replication/AdminApiFactory.java
index 528aff2..de6e91e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/AdminApiFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/AdminApiFactory.java
@@ -19,33 +19,45 @@
import java.util.Optional;
import org.eclipse.jgit.transport.URIish;
-@Singleton
-public class AdminApiFactory {
+/** Factory for creating an {@link AdminApi} instance for a remote URI. */
+public interface AdminApiFactory {
+ /**
+ * Create an {@link AdminApi} for the given remote URI.
+ *
+ * @param uri the remote URI.
+ * @return An API for the given remote URI, or {@code Optional.empty} if there is no appropriate
+ * API for the URI.
+ */
+ Optional<AdminApi> create(URIish uri);
- private final SshHelper sshHelper;
+ @Singleton
+ static class DefaultAdminApiFactory implements AdminApiFactory {
+ protected final SshHelper sshHelper;
- @Inject
- AdminApiFactory(SshHelper sshHelper) {
- this.sshHelper = sshHelper;
- }
-
- public Optional<AdminApi> create(URIish uri) {
- if (isGerrit(uri)) {
- return Optional.of(new GerritSshApi(sshHelper, uri));
- } else if (!uri.isRemote()) {
- return Optional.of(new LocalFS(uri));
- } else if (isSSH(uri)) {
- return Optional.of(new RemoteSsh(sshHelper, uri));
+ @Inject
+ public DefaultAdminApiFactory(SshHelper sshHelper) {
+ this.sshHelper = sshHelper;
}
- return Optional.empty();
+
+ @Override
+ public Optional<AdminApi> create(URIish uri) {
+ if (isGerrit(uri)) {
+ return Optional.of(new GerritSshApi(sshHelper, uri));
+ } else if (!uri.isRemote()) {
+ return Optional.of(new LocalFS(uri));
+ } else if (isSSH(uri)) {
+ return Optional.of(new RemoteSsh(sshHelper, uri));
+ }
+ return Optional.empty();
+ }
}
- public static boolean isGerrit(URIish uri) {
+ static boolean isGerrit(URIish uri) {
String scheme = uri.getScheme();
return scheme != null && scheme.toLowerCase().equals("gerrit+ssh");
}
- public static boolean isSSH(URIish uri) {
+ static boolean isSSH(URIish uri) {
if (!uri.isRemote()) {
return false;
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationModule.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationModule.java
index 1898a4f..4162973 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationModule.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationModule.java
@@ -22,6 +22,7 @@
import com.google.gerrit.extensions.events.HeadUpdatedListener;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.extensions.events.ProjectDeletedListener;
+import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.extensions.registration.DynamicSet;
import com.google.gerrit.server.events.EventTypes;
import com.google.inject.AbstractModule;
@@ -67,7 +68,9 @@
EventTypes.register(ReplicationScheduledEvent.TYPE, ReplicationScheduledEvent.class);
bind(SshSessionFactory.class).toProvider(ReplicationSshSessionFactoryProvider.class);
- bind(AdminApiFactory.class);
+ DynamicItem.itemOf(binder(), AdminApiFactory.class);
+ DynamicItem.bind(binder(), AdminApiFactory.class)
+ .to(AdminApiFactory.DefaultAdminApiFactory.class);
bind(TransportFactory.class).to(TransportFactoryImpl.class).in(Scopes.SINGLETON);
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java
index 203bc2f..60604db 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/ReplicationQueue.java
@@ -65,7 +65,7 @@
private final WorkQueue workQueue;
private final DynamicItem<EventDispatcher> dispatcher;
private final ReplicationConfig config;
- private final AdminApiFactory adminApiFactory;
+ private final DynamicItem<AdminApiFactory> adminApiFactory;
private final ReplicationState.Factory replicationStateFactory;
private final EventsStorage eventsStorage;
private volatile boolean running;
@@ -74,7 +74,7 @@
@Inject
ReplicationQueue(
WorkQueue wq,
- AdminApiFactory aaf,
+ DynamicItem<AdminApiFactory> aaf,
ReplicationConfig rc,
DynamicItem<EventDispatcher> dis,
ReplicationStateListeners sl,
@@ -260,7 +260,7 @@
}
private boolean createProject(URIish replicateURI, Project.NameKey projectName, String head) {
- Optional<AdminApi> adminApi = adminApiFactory.create(replicateURI);
+ Optional<AdminApi> adminApi = adminApiFactory.get().create(replicateURI);
if (adminApi.isPresent() && adminApi.get().createProject(projectName, head)) {
return true;
}
@@ -270,7 +270,7 @@
}
private void deleteProject(URIish replicateURI, Project.NameKey projectName) {
- Optional<AdminApi> adminApi = adminApiFactory.create(replicateURI);
+ Optional<AdminApi> adminApi = adminApiFactory.get().create(replicateURI);
if (adminApi.isPresent()) {
adminApi.get().deleteProject(projectName);
return;
@@ -280,7 +280,7 @@
}
private void updateHead(URIish replicateURI, Project.NameKey projectName, String newHead) {
- Optional<AdminApi> adminApi = adminApiFactory.create(replicateURI);
+ Optional<AdminApi> adminApi = adminApiFactory.get().create(replicateURI);
if (adminApi.isPresent()) {
adminApi.get().updateHead(projectName, newHead);
return;
diff --git a/src/main/resources/Documentation/extension-point.md b/src/main/resources/Documentation/extension-point.md
index 345fd8f..076aded 100644
--- a/src/main/resources/Documentation/extension-point.md
+++ b/src/main/resources/Documentation/extension-point.md
@@ -1,7 +1,7 @@
@PLUGIN@ extension points
==============
-The replication plugin exposes an extension point to allow influencing the behaviour of the replication events from another plugin or a script.
+The replication plugin exposes an extension point to allow influencing its behaviour from another plugin or a script.
Extension points can be defined from the replication plugin only when it is loaded as [libModule](/config-gerrit.html#gerrit.installModule) and
implemented by another plugin by declaring a `provided` dependency from the replication plugin.
@@ -35,5 +35,19 @@
Example:
```
- DynamicItem.bind(binder(),ReplicationPushFilter.class).to(ReplicationPushFilterImpl.class);
+ DynamicItem.bind(binder(), ReplicationPushFilter.class).to(ReplicationPushFilterImpl.class);
+ ```
+
+* `com.googlesource.gerrit.plugins.replication.AdminApiFactory`
+
+ Create an instance of `AdminApi` for a given remote URL. The default implementation
+ provides API instances for local FS, remote SSH, and remote Gerrit.
+
+ Only one factory at a time is supported. The implementation needs to be bound as a
+ `DynamicItem`.
+
+ Example:
+
+ ```
+ DynamicItem.bind(binder(), AdminApiFactory.class).to(AdminApiFactoryImpl.class);
```