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 e5a1628..30e8245 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/AdminApiFactory.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/AdminApiFactory.java
@@ -19,37 +19,49 @@
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;
- private final GerritRestApi.Factory gerritRestApiFactory;
+ @Singleton
+ static class DefaultAdminApiFactory implements AdminApiFactory {
+ protected final SshHelper sshHelper;
+ private final GerritRestApi.Factory gerritRestApiFactory;
- @Inject
- AdminApiFactory(SshHelper sshHelper, GerritRestApi.Factory gerritRestApiFactory) {
- this.sshHelper = sshHelper;
- this.gerritRestApiFactory = gerritRestApiFactory;
- }
-
- 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));
- } else if (isGerritHttp(uri)) {
- return Optional.of(gerritRestApiFactory.create(uri));
+ @Inject
+ public DefaultAdminApiFactory(SshHelper sshHelper, GerritRestApi.Factory gerritRestApiFactory) {
+ this.sshHelper = sshHelper;
+ this.gerritRestApiFactory = gerritRestApiFactory;
}
- 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));
+ } else if (isGerritHttp(uri)) {
+ return Optional.of(gerritRestApiFactory.create(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/CreateProjectTask.java b/src/main/java/com/googlesource/gerrit/plugins/replication/CreateProjectTask.java
index e3d57de..a8dede3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/CreateProjectTask.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/CreateProjectTask.java
@@ -16,6 +16,7 @@
import static com.googlesource.gerrit.plugins.replication.ReplicationQueue.repLog;
+import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.reviewdb.client.Project;
import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;
@@ -31,7 +32,7 @@
private final RemoteConfig config;
private final ReplicationConfig replicationConfig;
- private final AdminApiFactory adminApiFactory;
+ private final DynamicItem<AdminApiFactory> adminApiFactory;
private final Project.NameKey project;
private final String head;
@@ -39,7 +40,7 @@
CreateProjectTask(
RemoteConfig config,
ReplicationConfig replicationConfig,
- AdminApiFactory adminApiFactory,
+ DynamicItem<AdminApiFactory> adminApiFactory,
@Assisted Project.NameKey project,
@Assisted String head) {
this.config = config;
@@ -58,7 +59,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;
}
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/DeleteProjectTask.java b/src/main/java/com/googlesource/gerrit/plugins/replication/DeleteProjectTask.java
index 96d8c70..f9b2ad7 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/DeleteProjectTask.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/DeleteProjectTask.java
@@ -16,6 +16,7 @@
import static com.googlesource.gerrit.plugins.replication.ReplicationQueue.repLog;
+import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.ioutil.HexFormat;
import com.google.gerrit.server.util.IdGenerator;
@@ -29,14 +30,14 @@
DeleteProjectTask create(URIish replicateURI, Project.NameKey project);
}
- private final AdminApiFactory adminApiFactory;
+ private final DynamicItem<AdminApiFactory> adminApiFactory;
private final int id;
private final URIish replicateURI;
private final Project.NameKey project;
@Inject
DeleteProjectTask(
- AdminApiFactory adminApiFactory,
+ DynamicItem<AdminApiFactory> adminApiFactory,
IdGenerator ig,
@Assisted URIish replicateURI,
@Assisted Project.NameKey project) {
@@ -48,7 +49,7 @@
@Override
public void run() {
- Optional<AdminApi> adminApi = adminApiFactory.create(replicateURI);
+ Optional<AdminApi> adminApi = adminApiFactory.get().create(replicateURI);
if (adminApi.isPresent()) {
adminApi.get().deleteProject(project);
return;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
index 2677152..0a6d9d2 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/Destination.java
@@ -173,7 +173,11 @@
install(new FactoryModuleBuilder().build(CreateProjectTask.Factory.class));
install(new FactoryModuleBuilder().build(DeleteProjectTask.Factory.class));
install(new FactoryModuleBuilder().build(UpdateHeadTask.Factory.class));
- bind(AdminApiFactory.class);
+
+ DynamicItem.itemOf(binder(), AdminApiFactory.class);
+ DynamicItem.bind(binder(), AdminApiFactory.class)
+ .to(AdminApiFactory.DefaultAdminApiFactory.class);
+
install(new FactoryModuleBuilder().build(GerritRestApi.Factory.class));
bind(CloseableHttpClient.class)
.toProvider(HttpClientProvider.class)
diff --git a/src/main/java/com/googlesource/gerrit/plugins/replication/UpdateHeadTask.java b/src/main/java/com/googlesource/gerrit/plugins/replication/UpdateHeadTask.java
index db58f49..70452b4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/replication/UpdateHeadTask.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/replication/UpdateHeadTask.java
@@ -16,6 +16,7 @@
import static com.googlesource.gerrit.plugins.replication.ReplicationQueue.repLog;
+import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.ioutil.HexFormat;
import com.google.gerrit.server.util.IdGenerator;
@@ -25,7 +26,7 @@
import org.eclipse.jgit.transport.URIish;
public class UpdateHeadTask implements Runnable {
- private final AdminApiFactory adminApiFactory;
+ private final DynamicItem<AdminApiFactory> adminApiFactory;
private final int id;
private final URIish replicateURI;
private final Project.NameKey project;
@@ -37,7 +38,7 @@
@Inject
UpdateHeadTask(
- AdminApiFactory adminApiFactory,
+ DynamicItem<AdminApiFactory> adminApiFactory,
IdGenerator ig,
@Assisted URIish replicateURI,
@Assisted Project.NameKey project,
@@ -51,7 +52,7 @@
@Override
public void run() {
- Optional<AdminApi> adminApi = adminApiFactory.create(replicateURI);
+ Optional<AdminApi> adminApi = adminApiFactory.get().create(replicateURI);
if (adminApi.isPresent()) {
adminApi.get().updateHead(project, 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);
```