From bd732717538f4cc702ded76a58214b13b90e1aa9 Mon Sep 17 00:00:00 2001 From: Eric Kok Date: Tue, 31 Jan 2017 17:06:30 +0100 Subject: [PATCH] Reworked the client/spec/config/builder on how features are implemented and called. --- .../org/transdroid/connect/Configuration.java | 64 ++++++++++++++++--- .../transdroid/connect/clients/Client.java | 38 +++++++---- .../connect/clients/ClientDelegate.java | 42 ++++++++++++ .../connect/clients/ClientSpec.java | 15 ++--- .../transdroid/connect/clients/Feature.java | 54 ++++++++++++++-- .../clients/UnsupportedFeatureException.java | 22 +++++++ .../connect/clients/rtorrent/Rtorrent.java | 19 ++---- .../clients/transmission/Transmission.java | 5 ++ .../clients/rtorrent/RtorrentTest.java | 21 ++++-- 9 files changed, 225 insertions(+), 55 deletions(-) create mode 100644 connect/src/main/java/org/transdroid/connect/clients/ClientDelegate.java create mode 100644 connect/src/main/java/org/transdroid/connect/clients/UnsupportedFeatureException.java create mode 100644 connect/src/main/java/org/transdroid/connect/clients/transmission/Transmission.java diff --git a/connect/src/main/java/org/transdroid/connect/Configuration.java b/connect/src/main/java/org/transdroid/connect/Configuration.java index 6ab67213..93ce18bb 100644 --- a/connect/src/main/java/org/transdroid/connect/Configuration.java +++ b/connect/src/main/java/org/transdroid/connect/Configuration.java @@ -4,22 +4,66 @@ import com.burgstaller.okhttp.digest.Credentials; import org.transdroid.connect.clients.Client; import org.transdroid.connect.clients.ClientSpec; -import org.transdroid.connect.util.StringUtil; +/** + * Configuration settings to connect to a torrent client. + */ public final class Configuration { private final Client client; private final String baseUrl; - private final String endpoint; - private final Credentials credentials; - private final boolean loggingEnabled; + private String endpoint; + private Credentials credentials; + private boolean loggingEnabled; - public Configuration(Client client, String baseUrl, String endpoint, String user, String password, boolean loggingEnabled) { + public static class Builder { + + private final Client client; + private String baseUrl; + private String endpoint; + private Credentials credentials; + private boolean loggingEnabled; + + public Builder(Client client) { + this.client = client; + } + + public Builder baseUrl(String baseUrl) { + this.baseUrl = baseUrl; + return this; + } + + public Builder endpoint(String endpoint) { + this.endpoint = endpoint; + return this; + } + + public Builder credentials(String user, String password) { + this.credentials = new Credentials(user, password); + return this; + } + + public Builder loggingEnabled(boolean loggingEnabled) { + this.loggingEnabled = loggingEnabled; + return this; + } + + public Configuration build() { + Configuration configuration = new Configuration(client, baseUrl); + configuration.endpoint = this.endpoint; + configuration.credentials = this.credentials; + return configuration; + } + + } + + private Configuration(Client client, String baseUrl) { this.client = client; this.baseUrl = baseUrl; - this.endpoint = endpoint; - this.credentials = (!StringUtil.isEmpty(user) && password != null) ? new Credentials(user, password) : null; - this.loggingEnabled = loggingEnabled; + } + + public Client client() { + return client; } public String baseUrl() { @@ -38,8 +82,8 @@ public final class Configuration { return credentials; } - public ClientSpec create() { - return client.create(this); + public ClientSpec createClient() { + return client.createClient(this); } } diff --git a/connect/src/main/java/org/transdroid/connect/clients/Client.java b/connect/src/main/java/org/transdroid/connect/clients/Client.java index e00b6a5f..7e8abfbd 100644 --- a/connect/src/main/java/org/transdroid/connect/clients/Client.java +++ b/connect/src/main/java/org/transdroid/connect/clients/Client.java @@ -2,29 +2,45 @@ package org.transdroid.connect.clients; import org.transdroid.connect.Configuration; import org.transdroid.connect.clients.rtorrent.Rtorrent; +import org.transdroid.connect.clients.transmission.Transmission; -import java.util.Set; - +/** + * Support clients enum, allowing you to create instances (given a configuration) and query for feature support. + */ +@SuppressWarnings("unchecked") public enum Client { - RTORRENT { + RTORRENT(Rtorrent.class) { @Override - public ClientSpec create(Configuration configuration) { + public Rtorrent create(Configuration configuration) { return new Rtorrent(configuration); } - + }, + TRANSMISSION(Transmission.class) { @Override - Set features() { - return Rtorrent.FEATURES; + public Transmission create(Configuration configuration) { + return new Transmission(); } }; - public abstract ClientSpec create(Configuration configuration); + final Class type; + + Client(Class type) { + this.type = type; + } + + public final Class type() { + return type; + } + + abstract Object create(Configuration configuration); - abstract Set features(); + public final ClientSpec createClient(Configuration configuration) { + return new ClientDelegate(configuration.client(), create(configuration)); + } - public boolean supports(Feature feature) { - return features().contains(feature); + public final boolean supports(Feature feature) { + return feature.type().isAssignableFrom(type); } } diff --git a/connect/src/main/java/org/transdroid/connect/clients/ClientDelegate.java b/connect/src/main/java/org/transdroid/connect/clients/ClientDelegate.java new file mode 100644 index 00000000..71b1690c --- /dev/null +++ b/connect/src/main/java/org/transdroid/connect/clients/ClientDelegate.java @@ -0,0 +1,42 @@ +package org.transdroid.connect.clients; + +import org.transdroid.connect.model.Torrent; + +import io.reactivex.Flowable; + +/** + * Wraps an actual client implementation by calling through the appropriate method only if it is supported. This allows the final + * {@link ClientSpec} API to expose all methods without forcing the individual implementations to implement unsupported featured with a no-op. + */ +final class ClientDelegate implements ClientSpec { + + private final Client client; + private final Object actual; + + ClientDelegate(Client client, Object actual) { + this.client = client; + this.actual = actual; + } + + @Override + public Flowable torrents() { + if (client.supports(Feature.LISTING)) + return ((Feature.Listing) actual).torrents(); + throw new UnsupportedFeatureException(client, Feature.LISTING); + } + + @Override + public Flowable clientVersion() { + if (client.supports(Feature.VERSION)) + return ((Feature.Version) actual).clientVersion(); + throw new UnsupportedFeatureException(client, Feature.VERSION); + } + + @Override + public Flowable forceStartTorrent() { + if (client.supports(Feature.FORCE_STARTING)) + return ((Feature.ForceStarting) actual).forceStartTorrent(); + throw new UnsupportedFeatureException(client, Feature.FORCE_STARTING); + } + +} diff --git a/connect/src/main/java/org/transdroid/connect/clients/ClientSpec.java b/connect/src/main/java/org/transdroid/connect/clients/ClientSpec.java index accf2bc1..0d020b9f 100644 --- a/connect/src/main/java/org/transdroid/connect/clients/ClientSpec.java +++ b/connect/src/main/java/org/transdroid/connect/clients/ClientSpec.java @@ -1,13 +1,10 @@ package org.transdroid.connect.clients; -import org.transdroid.connect.model.Torrent; - -import io.reactivex.Flowable; - -public interface ClientSpec { - - Flowable clientVersion(); - - Flowable torrents(); +public interface ClientSpec extends + Feature.Version, + Feature.Listing, + Feature.StartingStopping, + Feature.ResumingPausing, + Feature.ForceStarting { } diff --git a/connect/src/main/java/org/transdroid/connect/clients/Feature.java b/connect/src/main/java/org/transdroid/connect/clients/Feature.java index 8b7f736e..580cd0dd 100644 --- a/connect/src/main/java/org/transdroid/connect/clients/Feature.java +++ b/connect/src/main/java/org/transdroid/connect/clients/Feature.java @@ -1,11 +1,55 @@ package org.transdroid.connect.clients; +import org.transdroid.connect.model.Torrent; + +import io.reactivex.Flowable; + +/** + * Available feature enum which can be implemented by clients. Use {@link Client#supports(Feature)} to see if a certain {@link Client} support a + * {@link Feature}. + */ public enum Feature { - VERSION, - STARTING, - STOPPING, - RESUMING, - PAUSING + VERSION(Version.class), + LISTING(Listing.class), + STARTING_STOPPING(StartingStopping.class), + RESUMING_PAUSING(ResumingPausing.class), + FORCE_STARTING(ForceStarting.class); + + private final Class type; + + Feature(Class type) { + this.type = type; + } + + public Class type() { + return type; + } + + public interface Version { + + Flowable clientVersion(); + + } + + public interface Listing { + + Flowable torrents(); + + } + + public interface StartingStopping { + + } + + public interface ResumingPausing { + + } + + public interface ForceStarting { + + Flowable forceStartTorrent(); + + } } diff --git a/connect/src/main/java/org/transdroid/connect/clients/UnsupportedFeatureException.java b/connect/src/main/java/org/transdroid/connect/clients/UnsupportedFeatureException.java new file mode 100644 index 00000000..fade06db --- /dev/null +++ b/connect/src/main/java/org/transdroid/connect/clients/UnsupportedFeatureException.java @@ -0,0 +1,22 @@ +package org.transdroid.connect.clients; + +import sun.reflect.generics.reflectiveObjects.NotImplementedException; + +/** + * Thrown when trying to call into a client method for a feature which the client does not support. + */ +public class UnsupportedFeatureException extends NotImplementedException { + + private final Client client; + private final Feature feature; + + UnsupportedFeatureException(Client client, Feature feature) { + this.client = client; + this.feature = feature; + } + + public String getMessage() { + return client.name() + " does not support " + feature.name(); + } + +} diff --git a/connect/src/main/java/org/transdroid/connect/clients/rtorrent/Rtorrent.java b/connect/src/main/java/org/transdroid/connect/clients/rtorrent/Rtorrent.java index eb82cbdd..71b6f139 100644 --- a/connect/src/main/java/org/transdroid/connect/clients/rtorrent/Rtorrent.java +++ b/connect/src/main/java/org/transdroid/connect/clients/rtorrent/Rtorrent.java @@ -3,7 +3,6 @@ package org.transdroid.connect.clients.rtorrent; import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory; import org.transdroid.connect.Configuration; -import org.transdroid.connect.clients.ClientSpec; import org.transdroid.connect.clients.Feature; import org.transdroid.connect.model.Torrent; import org.transdroid.connect.model.TorrentStatus; @@ -11,8 +10,6 @@ import org.transdroid.connect.util.OkHttpBuilder; import org.transdroid.connect.util.RxUtil; import java.util.Date; -import java.util.HashSet; -import java.util.Set; import io.reactivex.Flowable; import io.reactivex.functions.Function; @@ -20,17 +17,11 @@ import nl.nl2312.xmlrpc.Nothing; import nl.nl2312.xmlrpc.XmlRpcConverterFactory; import retrofit2.Retrofit; -public final class Rtorrent implements ClientSpec { - - public static final Set FEATURES = new HashSet<>(); - - { - FEATURES.add(Feature.VERSION); - FEATURES.add(Feature.STARTING); - FEATURES.add(Feature.STOPPING); - FEATURES.add(Feature.RESUMING); - FEATURES.add(Feature.PAUSING); - } +public final class Rtorrent implements + Feature.Version, + Feature.Listing, + Feature.StartingStopping, + Feature.ResumingPausing { private final Configuration configuration; private final Service service; diff --git a/connect/src/main/java/org/transdroid/connect/clients/transmission/Transmission.java b/connect/src/main/java/org/transdroid/connect/clients/transmission/Transmission.java new file mode 100644 index 00000000..bde548a4 --- /dev/null +++ b/connect/src/main/java/org/transdroid/connect/clients/transmission/Transmission.java @@ -0,0 +1,5 @@ +package org.transdroid.connect.clients.transmission; + +public final class Transmission { + +} diff --git a/connect/src/test/java/org/transdroid/connect/clients/rtorrent/RtorrentTest.java b/connect/src/test/java/org/transdroid/connect/clients/rtorrent/RtorrentTest.java index 2cad4806..7a04b756 100644 --- a/connect/src/test/java/org/transdroid/connect/clients/rtorrent/RtorrentTest.java +++ b/connect/src/test/java/org/transdroid/connect/clients/rtorrent/RtorrentTest.java @@ -6,6 +6,7 @@ import org.transdroid.connect.Configuration; import org.transdroid.connect.clients.Client; import org.transdroid.connect.clients.ClientSpec; import org.transdroid.connect.clients.Feature; +import org.transdroid.connect.clients.UnsupportedFeatureException; import org.transdroid.connect.model.Torrent; import java.io.IOException; @@ -21,17 +22,19 @@ public final class RtorrentTest { @Before public void setUp() { - Configuration configuration = new Configuration(Client.RTORRENT, "http://localhost:8008/", "RPC2", null, null, true); - rtorrent = configuration.create(); + rtorrent = new Configuration.Builder(Client.RTORRENT) + .baseUrl("http://localhost:8008/") + .endpoint("/RPC2") + .build() + .createClient(); } @Test public void features() { assertThat(Client.RTORRENT.supports(Feature.VERSION)).isTrue(); - assertThat(Client.RTORRENT.supports(Feature.STARTING)).isTrue(); - assertThat(Client.RTORRENT.supports(Feature.STOPPING)).isTrue(); - assertThat(Client.RTORRENT.supports(Feature.RESUMING)).isTrue(); - assertThat(Client.RTORRENT.supports(Feature.PAUSING)).isTrue(); + assertThat(Client.RTORRENT.supports(Feature.STARTING_STOPPING)).isTrue(); + assertThat(Client.RTORRENT.supports(Feature.RESUMING_PAUSING)).isTrue(); + assertThat(Client.RTORRENT.supports(Feature.FORCE_STARTING)).isFalse(); } @Test @@ -54,4 +57,10 @@ public final class RtorrentTest { }); } + @Test(expected = UnsupportedFeatureException.class) + public void forceStart() throws IOException { + rtorrent.forceStartTorrent() + .test(); + } + }