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); ```