From a5a17aef9446102d1ab3e1dafcfe5a1e07d5c3dd Mon Sep 17 00:00:00 2001 From: QSD_igor Date: Mon, 18 Jul 2022 13:25:47 +0200 Subject: [PATCH 01/14] Add ObjectCopyUtil for making a copy of objects to increase mutability with config files --- .../main/java/io/ably/lib/rest/AblyBase.java | 14 +++--- .../java/io/ably/lib/util/ObjectCopyUtil.java | 43 +++++++++++++++++++ 2 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 lib/src/main/java/io/ably/lib/util/ObjectCopyUtil.java diff --git a/lib/src/main/java/io/ably/lib/rest/AblyBase.java b/lib/src/main/java/io/ably/lib/rest/AblyBase.java index e19195d4c..2c92fa14f 100644 --- a/lib/src/main/java/io/ably/lib/rest/AblyBase.java +++ b/lib/src/main/java/io/ably/lib/rest/AblyBase.java @@ -33,6 +33,7 @@ import io.ably.lib.util.Crypto; import io.ably.lib.util.InternalMap; import io.ably.lib.util.Log; +import io.ably.lib.util.ObjectCopyUtil; import io.ably.lib.util.PlatformAgentProvider; import io.ably.lib.util.Serialisation; @@ -83,17 +84,18 @@ public AblyBase(ClientOptions options, PlatformAgentProvider platformAgentProvid Log.e(getClass().getName(), msg); throw AblyException.fromErrorInfo(new ErrorInfo(msg, 400, 40000)); } - this.options = options; + + this.options = ObjectCopyUtil.copy(options); /* process options */ - Log.setLevel(options.logLevel); - Log.setHandler(options.logHandler); + Log.setLevel(this.options.logLevel); + Log.setHandler(this.options.logHandler); Log.i(getClass().getName(), "started"); this.platformAgentProvider = platformAgentProvider; - auth = new Auth(this, options); - httpCore = new HttpCore(options, auth, this.platformAgentProvider); - http = new Http(new AsyncHttpScheduler(httpCore, options), new SyncHttpScheduler(httpCore)); + auth = new Auth(this, this.options); + httpCore = new HttpCore(this.options, auth, this.platformAgentProvider); + http = new Http(new AsyncHttpScheduler(httpCore, this.options), new SyncHttpScheduler(httpCore)); channels = (Channels) new InternalChannels(); diff --git a/lib/src/main/java/io/ably/lib/util/ObjectCopyUtil.java b/lib/src/main/java/io/ably/lib/util/ObjectCopyUtil.java new file mode 100644 index 000000000..779d60ae5 --- /dev/null +++ b/lib/src/main/java/io/ably/lib/util/ObjectCopyUtil.java @@ -0,0 +1,43 @@ +package io.ably.lib.util; + +import io.ably.lib.types.ClientOptions; + +public class ObjectCopyUtil { + + public static ClientOptions copy(ClientOptions options) { + ClientOptions copyOptions = new ClientOptions(); + copyOptions.clientId = options.clientId; + copyOptions.logLevel = options.logLevel; + copyOptions.logHandler = options.logHandler; + copyOptions.tls = options.tls; + copyOptions.headers = options.headers; //maybe deep copy this + copyOptions.restHost = options.restHost; + copyOptions.realtimeHost = options.realtimeHost; + copyOptions.port = options.port; + copyOptions.tlsPort = options.tlsPort; + copyOptions.autoConnect = options.autoConnect; + copyOptions.useBinaryProtocol = options.useBinaryProtocol; + copyOptions.queueMessages = options.queueMessages; + copyOptions.echoMessages = options.echoMessages; + copyOptions.recover = options.recover; + copyOptions.proxy = options.proxy; //maybe deep copy this + copyOptions.idempotentRestPublishing = options.idempotentRestPublishing; + copyOptions.httpOpenTimeout = options.httpOpenTimeout; + copyOptions.httpRequestTimeout = options.httpRequestTimeout; + copyOptions.httpMaxRetryCount = options.httpMaxRetryCount; + copyOptions.realtimeRequestTimeout = options.realtimeRequestTimeout; + copyOptions.fallbackHosts = options.fallbackHosts; //maybe deep copy this + copyOptions.fallbackHostsUseDefault = options.fallbackHostsUseDefault; + copyOptions.fallbackRetryTimeout = options.fallbackRetryTimeout; + copyOptions.defaultTokenParams = options.defaultTokenParams; //maybe deep copy this + copyOptions.channelRetryTimeout = options.channelRetryTimeout; + copyOptions.transportParams = options.transportParams; //maybe deep copy this + copyOptions.asyncHttpThreadpoolSize = options.asyncHttpThreadpoolSize; + copyOptions.pushFullWait = options.pushFullWait; + copyOptions.localStorage = options.localStorage; + copyOptions.addRequestIds = options.addRequestIds; + copyOptions.agents = options.agents; //maybe deep copy this + + return copyOptions; + } +} From a1e1d734ba4765f75c2cf48508c0583bf8400caf Mon Sep 17 00:00:00 2001 From: QSD_igor Date: Tue, 19 Jul 2022 16:43:47 +0200 Subject: [PATCH 02/14] Make TokenParams copy() method public Fix TokenDetails equals() method by checking instance before casting --- lib/src/main/java/io/ably/lib/rest/Auth.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/src/main/java/io/ably/lib/rest/Auth.java b/lib/src/main/java/io/ably/lib/rest/Auth.java index c9d7eec2f..34a7fce29 100644 --- a/lib/src/main/java/io/ably/lib/rest/Auth.java +++ b/lib/src/main/java/io/ably/lib/rest/Auth.java @@ -269,6 +269,9 @@ public String asJson() { */ @Override public boolean equals(Object obj) { + if (!(obj instanceof TokenDetails)) { + return false; + } TokenDetails details = (TokenDetails)obj; return equalNullableStrings(this.token, details.token) & equalNullableStrings(this.capability, details.capability) & @@ -360,7 +363,7 @@ private TokenParams storedValues() { * * @return copied object */ - private TokenParams copy() { + public TokenParams copy() { TokenParams result = new TokenParams(); result.ttl = this.ttl; result.capability = this.capability; From 45a2a742ab72a088c5bff32ca83da274bd38005e Mon Sep 17 00:00:00 2001 From: QSD_igor Date: Tue, 19 Jul 2022 16:45:04 +0200 Subject: [PATCH 03/14] Improve copy of ClientOptions by copying all variables --- .../java/io/ably/lib/util/ObjectCopyUtil.java | 66 +++++++++++++++++-- 1 file changed, 60 insertions(+), 6 deletions(-) diff --git a/lib/src/main/java/io/ably/lib/util/ObjectCopyUtil.java b/lib/src/main/java/io/ably/lib/util/ObjectCopyUtil.java index 779d60ae5..9b0ee4435 100644 --- a/lib/src/main/java/io/ably/lib/util/ObjectCopyUtil.java +++ b/lib/src/main/java/io/ably/lib/util/ObjectCopyUtil.java @@ -1,6 +1,11 @@ package io.ably.lib.util; +import java.util.Arrays; +import java.util.HashMap; + +import io.ably.lib.rest.Auth; import io.ably.lib.types.ClientOptions; +import io.ably.lib.types.ProxyOptions; public class ObjectCopyUtil { @@ -10,7 +15,6 @@ public static ClientOptions copy(ClientOptions options) { copyOptions.logLevel = options.logLevel; copyOptions.logHandler = options.logHandler; copyOptions.tls = options.tls; - copyOptions.headers = options.headers; //maybe deep copy this copyOptions.restHost = options.restHost; copyOptions.realtimeHost = options.realtimeHost; copyOptions.port = options.port; @@ -20,23 +24,73 @@ public static ClientOptions copy(ClientOptions options) { copyOptions.queueMessages = options.queueMessages; copyOptions.echoMessages = options.echoMessages; copyOptions.recover = options.recover; - copyOptions.proxy = options.proxy; //maybe deep copy this copyOptions.idempotentRestPublishing = options.idempotentRestPublishing; copyOptions.httpOpenTimeout = options.httpOpenTimeout; copyOptions.httpRequestTimeout = options.httpRequestTimeout; copyOptions.httpMaxRetryCount = options.httpMaxRetryCount; copyOptions.realtimeRequestTimeout = options.realtimeRequestTimeout; - copyOptions.fallbackHosts = options.fallbackHosts; //maybe deep copy this copyOptions.fallbackHostsUseDefault = options.fallbackHostsUseDefault; copyOptions.fallbackRetryTimeout = options.fallbackRetryTimeout; - copyOptions.defaultTokenParams = options.defaultTokenParams; //maybe deep copy this + copyOptions.defaultTokenParams = options.defaultTokenParams.copy(); copyOptions.channelRetryTimeout = options.channelRetryTimeout; - copyOptions.transportParams = options.transportParams; //maybe deep copy this copyOptions.asyncHttpThreadpoolSize = options.asyncHttpThreadpoolSize; copyOptions.pushFullWait = options.pushFullWait; copyOptions.localStorage = options.localStorage; copyOptions.addRequestIds = options.addRequestIds; - copyOptions.agents = options.agents; //maybe deep copy this + copyOptions.environment = options.environment; + + //params from AuthOptions + copyOptions.authCallback = options.authCallback; + copyOptions.authUrl = options.authUrl; + copyOptions.authMethod = options.authMethod; + copyOptions.key = options.key; + copyOptions.token = options.token; + copyOptions.queryTime = options.queryTime; + copyOptions.useTokenAuth = options.useTokenAuth; + + if (options.headers != null) { + copyOptions.headers = new HashMap<>(options.headers); + } + + if (options.agents != null) { + copyOptions.agents = new HashMap<>(options.agents); + } + + if (options.authParams != null) { + copyOptions.authParams = Arrays.copyOf(options.authParams, options.authParams.length); + } + + if (options.authHeaders != null) { + copyOptions.authHeaders = Arrays.copyOf(options.authHeaders, options.authHeaders.length); + } + + if (options.transportParams != null) { + copyOptions.transportParams = Arrays.copyOf(options.transportParams, options.transportParams.length); + } + + if (options.fallbackHosts != null) { + copyOptions.fallbackHosts = Arrays.copyOf(options.fallbackHosts, options.fallbackHosts.length); + } + + if (options.proxy != null) { + ProxyOptions po = new ProxyOptions(); + po.host = options.proxy.host; + po.port = options.proxy.port; + po.username = options.proxy.username; + po.password = options.proxy.password; + po.nonProxyHosts = options.proxy.nonProxyHosts; + po.prefAuthType = options.proxy.prefAuthType; //maybe deep copy this + copyOptions.proxy = po; + } + + if (options.tokenDetails != null) { + Auth.TokenDetails tokenDetails = new Auth.TokenDetails(); + tokenDetails.token = options.tokenDetails.token; + tokenDetails.expires = options.tokenDetails.expires; + tokenDetails.issued = options.tokenDetails.issued; + tokenDetails.capability = options.tokenDetails.capability; + tokenDetails.clientId = options.tokenDetails.clientId; + } return copyOptions; } From 85110d9de2ed8d696d192bc8948d72231e71f1ad Mon Sep 17 00:00:00 2001 From: QSD_igor Date: Tue, 19 Jul 2022 16:46:36 +0200 Subject: [PATCH 04/14] Add test for ClientOptions mutability --- .../lib/test/realtime/RealtimeAuthTest.java | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/lib/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java b/lib/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java index 13bb55020..ce5d65d5e 100644 --- a/lib/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java +++ b/lib/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java @@ -24,17 +24,22 @@ import io.ably.lib.types.Message; import io.ably.lib.types.Param; import io.ably.lib.types.ProtocolMessage; +import io.ably.lib.util.Log; + import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.Timeout; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.util.HashMap; + public abstract class RealtimeAuthTest extends ParameterizedTest { @Rule @@ -956,4 +961,64 @@ public Object getTokenRequest(Auth.TokenParams params) throws AblyException { } } + /** + * Verify that instance of ClientOptions cannot change AblyRealtime options once it is provided to constructor + */ + @Test + public void auth_client_options_immutable() { + try { + /* create token with clientId */ + ClientOptions optsForToken = createOptions(testVars.keys[0].keyStr); + optsForToken.clientId = "token_clientId"; + AblyBase ablyForToken = createAblyRest(optsForToken); + TokenDetails tokenDetails = ablyForToken.auth.requestToken(null, null); + + /* create ably realtime */ + ClientOptions opts = createOptions(); + opts.clientId = null; + opts.token = tokenDetails.token; + opts.autoConnect = false; + opts.headers = new HashMap<>(); + //opts.headers.put("old_key", "old_value"); + AblyRealtimeBase ablyRealtime = createAblyRealtime(opts); + + opts.clientId = "my_new_clientId"; + assertNotEquals("Verify if clientId has changed", opts.clientId, ablyRealtime.options.clientId); + opts.logLevel = 33; + assertNotEquals("Verify if logLevel has changed", opts.logLevel, ablyRealtime.options.logLevel); + opts.autoConnect = true; + assertNotEquals("Verify if autoConnect has changed", opts.autoConnect, ablyRealtime.options.autoConnect); + opts.logHandler = new Log.DefaultHandler(); + assertNotEquals("Verify if logHandler has changed", opts.logHandler, ablyRealtime.options.logHandler); + + assertEquals("Verify if logHandler has changed", opts.authCallback, ablyRealtime.options.authCallback); + opts.authCallback = new Auth.TokenCallback() { + @Override + public Object getTokenRequest(Auth.TokenParams params) { + return null; + } + }; + assertNotEquals("Verify if logHandler has changed", opts.authCallback, ablyRealtime.options.authCallback); + + opts.token = "my_new_token"; + assertNotEquals("Verify if logHandler has changed", opts.token, ablyRealtime.options.token); + + opts.tokenDetails = new TokenDetails("my_new_details_token"); + assertNotEquals("Verify if tokenDetails has changed", opts.tokenDetails, ablyRealtime.options.tokenDetails); + + opts.headers = new HashMap<>(); + opts.headers.put("new_key", "new_value"); + assertNotEquals("Verify if headers has changed", opts.headers, ablyRealtime.options.headers); + + opts.authHeaders = new Param[1]; + opts.authHeaders[0] = new Param("new_key","new_key"); + assertNotEquals("Verify if headers has changed", opts.authHeaders, ablyRealtime.options.authHeaders); + + ablyRealtime.close(); + } catch (AblyException e) { + e.printStackTrace(); + fail(); + } + } + } From a36420aa3e58d2e1687c6452fde099de31aebe4f Mon Sep 17 00:00:00 2001 From: QSD_igor Date: Wed, 20 Jul 2022 14:43:27 +0200 Subject: [PATCH 05/14] Extend client options immutable test --- .../lib/test/realtime/RealtimeAuthTest.java | 44 ++++++++++++++++--- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/lib/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java b/lib/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java index ce5d65d5e..f6c6dbe5e 100644 --- a/lib/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java +++ b/lib/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java @@ -24,6 +24,7 @@ import io.ably.lib.types.Message; import io.ably.lib.types.Param; import io.ably.lib.types.ProtocolMessage; +import io.ably.lib.types.ProxyOptions; import io.ably.lib.util.Log; import org.junit.Ignore; @@ -31,6 +32,7 @@ import org.junit.Test; import org.junit.rules.Timeout; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; @@ -974,45 +976,73 @@ public void auth_client_options_immutable() { TokenDetails tokenDetails = ablyForToken.auth.requestToken(null, null); /* create ably realtime */ - ClientOptions opts = createOptions(); + ClientOptions opts = new ClientOptions(); opts.clientId = null; opts.token = tokenDetails.token; opts.autoConnect = false; opts.headers = new HashMap<>(); - //opts.headers.put("old_key", "old_value"); + opts.headers.put("old_key", "old_value"); + opts.tokenDetails = new TokenDetails("my_old_details_token"); + opts.logHandler = new Log.DefaultHandler(); + opts.authCallback = new Auth.TokenCallback() { + @Override + public Object getTokenRequest(Auth.TokenParams params) { + return null; + } + }; + opts.authHeaders = new Param[1]; + opts.authHeaders[0] = new Param("old_key", "old_key"); + opts.proxy = new ProxyOptions(); + opts.proxy.host = "https://ably.com"; + opts.proxy.port = 8080; AblyRealtimeBase ablyRealtime = createAblyRealtime(opts); + assertEquals("Verify if clientId has changed", opts.clientId, ablyRealtime.options.clientId); opts.clientId = "my_new_clientId"; assertNotEquals("Verify if clientId has changed", opts.clientId, ablyRealtime.options.clientId); + + assertEquals("Verify if logLevel has changed", opts.logLevel, ablyRealtime.options.logLevel); opts.logLevel = 33; assertNotEquals("Verify if logLevel has changed", opts.logLevel, ablyRealtime.options.logLevel); + + assertEquals("Verify if autoConnect has changed", opts.autoConnect, ablyRealtime.options.autoConnect); opts.autoConnect = true; assertNotEquals("Verify if autoConnect has changed", opts.autoConnect, ablyRealtime.options.autoConnect); + + assertEquals("Verify if logHandler has changed", opts.logHandler, ablyRealtime.options.logHandler); opts.logHandler = new Log.DefaultHandler(); assertNotEquals("Verify if logHandler has changed", opts.logHandler, ablyRealtime.options.logHandler); - assertEquals("Verify if logHandler has changed", opts.authCallback, ablyRealtime.options.authCallback); + assertEquals("Verify if authCallback has changed", opts.authCallback, ablyRealtime.options.authCallback); opts.authCallback = new Auth.TokenCallback() { @Override public Object getTokenRequest(Auth.TokenParams params) { return null; } }; - assertNotEquals("Verify if logHandler has changed", opts.authCallback, ablyRealtime.options.authCallback); + assertNotEquals("Verify if authCallback has changed", opts.authCallback, ablyRealtime.options.authCallback); + assertEquals("Verify if token has changed", opts.token, ablyRealtime.options.token); opts.token = "my_new_token"; - assertNotEquals("Verify if logHandler has changed", opts.token, ablyRealtime.options.token); + assertNotEquals("Verify if token has changed", opts.token, ablyRealtime.options.token); + assertEquals("Verify if tokenDetails has changed", opts.tokenDetails, ablyRealtime.options.tokenDetails); opts.tokenDetails = new TokenDetails("my_new_details_token"); assertNotEquals("Verify if tokenDetails has changed", opts.tokenDetails, ablyRealtime.options.tokenDetails); + assertEquals("Verify if headers has changed", opts.headers, ablyRealtime.options.headers); opts.headers = new HashMap<>(); opts.headers.put("new_key", "new_value"); assertNotEquals("Verify if headers has changed", opts.headers, ablyRealtime.options.headers); + assertArrayEquals("Verify if authHeaders has changed", opts.authHeaders, ablyRealtime.options.authHeaders); opts.authHeaders = new Param[1]; - opts.authHeaders[0] = new Param("new_key","new_key"); - assertNotEquals("Verify if headers has changed", opts.authHeaders, ablyRealtime.options.authHeaders); + opts.authHeaders[0] = new Param("new_key", "new_key"); + assertNotEquals("Verify if authHeaders has changed", opts.authHeaders, ablyRealtime.options.authHeaders); + + assertEquals("Verify if proxy.port has changed", opts.proxy.port, ablyRealtime.options.proxy.port); + opts.proxy.port = 9090; + assertNotEquals("Verify if proxy.port has changed", opts.proxy.port, ablyRealtime.options.proxy.port); ablyRealtime.close(); } catch (AblyException e) { From c6ead3161a64ad3ef52d24fb67bf53f957b04389 Mon Sep 17 00:00:00 2001 From: QSD_igor Date: Wed, 20 Jul 2022 14:46:22 +0200 Subject: [PATCH 06/14] Disable object clone for DebugOptions Fix ClientOptions copy method --- lib/src/main/java/io/ably/lib/rest/AblyBase.java | 7 ++++++- lib/src/main/java/io/ably/lib/util/ObjectCopyUtil.java | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/src/main/java/io/ably/lib/rest/AblyBase.java b/lib/src/main/java/io/ably/lib/rest/AblyBase.java index 2c92fa14f..8f3df33d8 100644 --- a/lib/src/main/java/io/ably/lib/rest/AblyBase.java +++ b/lib/src/main/java/io/ably/lib/rest/AblyBase.java @@ -1,6 +1,7 @@ package io.ably.lib.rest; import io.ably.annotation.Experimental; +import io.ably.lib.debug.DebugOptions; import io.ably.lib.http.AsyncHttpScheduler; import io.ably.lib.http.Http; import io.ably.lib.http.HttpCore; @@ -85,7 +86,11 @@ public AblyBase(ClientOptions options, PlatformAgentProvider platformAgentProvid throw AblyException.fromErrorInfo(new ErrorInfo(msg, 400, 40000)); } - this.options = ObjectCopyUtil.copy(options); + if (options instanceof DebugOptions) { + this.options = options; + } else { + this.options = ObjectCopyUtil.copy(options); + } /* process options */ Log.setLevel(this.options.logLevel); diff --git a/lib/src/main/java/io/ably/lib/util/ObjectCopyUtil.java b/lib/src/main/java/io/ably/lib/util/ObjectCopyUtil.java index 9b0ee4435..417bd6407 100644 --- a/lib/src/main/java/io/ably/lib/util/ObjectCopyUtil.java +++ b/lib/src/main/java/io/ably/lib/util/ObjectCopyUtil.java @@ -90,6 +90,7 @@ public static ClientOptions copy(ClientOptions options) { tokenDetails.issued = options.tokenDetails.issued; tokenDetails.capability = options.tokenDetails.capability; tokenDetails.clientId = options.tokenDetails.clientId; + copyOptions.tokenDetails = tokenDetails; } return copyOptions; From 88f798dfa47f3702018fedc426bcdb6f21011487 Mon Sep 17 00:00:00 2001 From: QSD_igor Date: Fri, 22 Jul 2022 09:22:03 +0200 Subject: [PATCH 07/14] Add new line in TokenDetails equals for better readability Remove comment about deep copy as we do not need it --- core/src/main/java/io/ably/lib/rest/Auth.java | 1 + core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/io/ably/lib/rest/Auth.java b/core/src/main/java/io/ably/lib/rest/Auth.java index 34a7fce29..73a98be4a 100644 --- a/core/src/main/java/io/ably/lib/rest/Auth.java +++ b/core/src/main/java/io/ably/lib/rest/Auth.java @@ -272,6 +272,7 @@ public boolean equals(Object obj) { if (!(obj instanceof TokenDetails)) { return false; } + TokenDetails details = (TokenDetails)obj; return equalNullableStrings(this.token, details.token) & equalNullableStrings(this.capability, details.capability) & diff --git a/core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java b/core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java index 417bd6407..d972c9110 100644 --- a/core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java +++ b/core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java @@ -79,7 +79,7 @@ public static ClientOptions copy(ClientOptions options) { po.username = options.proxy.username; po.password = options.proxy.password; po.nonProxyHosts = options.proxy.nonProxyHosts; - po.prefAuthType = options.proxy.prefAuthType; //maybe deep copy this + po.prefAuthType = options.proxy.prefAuthType; copyOptions.proxy = po; } From 0cb95a57b5fc3efaabd2d5665d1b71cebe9f9f5b Mon Sep 17 00:00:00 2001 From: QSD_igor Date: Fri, 22 Jul 2022 09:36:47 +0200 Subject: [PATCH 08/14] Change text of auth_client_options_immutable tests for better description --- .../lib/test/realtime/RealtimeAuthTest.java | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/core/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java b/core/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java index f6c6dbe5e..11e3bceff 100644 --- a/core/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java +++ b/core/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java @@ -997,52 +997,52 @@ public Object getTokenRequest(Auth.TokenParams params) { opts.proxy.port = 8080; AblyRealtimeBase ablyRealtime = createAblyRealtime(opts); - assertEquals("Verify if clientId has changed", opts.clientId, ablyRealtime.options.clientId); + assertEquals("clientId should be equal before change", opts.clientId, ablyRealtime.options.clientId); opts.clientId = "my_new_clientId"; - assertNotEquals("Verify if clientId has changed", opts.clientId, ablyRealtime.options.clientId); + assertNotEquals("clientId should not be equal after change", opts.clientId, ablyRealtime.options.clientId); - assertEquals("Verify if logLevel has changed", opts.logLevel, ablyRealtime.options.logLevel); + assertEquals("logLevel should be equal before change", opts.logLevel, ablyRealtime.options.logLevel); opts.logLevel = 33; - assertNotEquals("Verify if logLevel has changed", opts.logLevel, ablyRealtime.options.logLevel); + assertNotEquals("logLevel should not be equal after change", opts.logLevel, ablyRealtime.options.logLevel); - assertEquals("Verify if autoConnect has changed", opts.autoConnect, ablyRealtime.options.autoConnect); + assertEquals("autoConnect should be equal before change", opts.autoConnect, ablyRealtime.options.autoConnect); opts.autoConnect = true; - assertNotEquals("Verify if autoConnect has changed", opts.autoConnect, ablyRealtime.options.autoConnect); + assertNotEquals("autoConnect should not be equal after change", opts.autoConnect, ablyRealtime.options.autoConnect); - assertEquals("Verify if logHandler has changed", opts.logHandler, ablyRealtime.options.logHandler); + assertEquals("logHandler should be equal before change", opts.logHandler, ablyRealtime.options.logHandler); opts.logHandler = new Log.DefaultHandler(); - assertNotEquals("Verify if logHandler has changed", opts.logHandler, ablyRealtime.options.logHandler); + assertNotEquals("logHandler should not be equal after change", opts.logHandler, ablyRealtime.options.logHandler); - assertEquals("Verify if authCallback has changed", opts.authCallback, ablyRealtime.options.authCallback); + assertEquals("authCallback should be equal before change", opts.authCallback, ablyRealtime.options.authCallback); opts.authCallback = new Auth.TokenCallback() { @Override public Object getTokenRequest(Auth.TokenParams params) { return null; } }; - assertNotEquals("Verify if authCallback has changed", opts.authCallback, ablyRealtime.options.authCallback); + assertNotEquals("authCallback should not be equal after change", opts.authCallback, ablyRealtime.options.authCallback); - assertEquals("Verify if token has changed", opts.token, ablyRealtime.options.token); + assertEquals("token should be equal before change", opts.token, ablyRealtime.options.token); opts.token = "my_new_token"; - assertNotEquals("Verify if token has changed", opts.token, ablyRealtime.options.token); + assertNotEquals("token should not be equal after change", opts.token, ablyRealtime.options.token); - assertEquals("Verify if tokenDetails has changed", opts.tokenDetails, ablyRealtime.options.tokenDetails); + assertEquals("tokenDetails should be equal before change", opts.tokenDetails, ablyRealtime.options.tokenDetails); opts.tokenDetails = new TokenDetails("my_new_details_token"); - assertNotEquals("Verify if tokenDetails has changed", opts.tokenDetails, ablyRealtime.options.tokenDetails); + assertNotEquals("tokenDetails should not be equal after change", opts.tokenDetails, ablyRealtime.options.tokenDetails); - assertEquals("Verify if headers has changed", opts.headers, ablyRealtime.options.headers); + assertEquals("headers should be equal before change", opts.headers, ablyRealtime.options.headers); opts.headers = new HashMap<>(); opts.headers.put("new_key", "new_value"); - assertNotEquals("Verify if headers has changed", opts.headers, ablyRealtime.options.headers); + assertNotEquals("headers should not be equal after change", opts.headers, ablyRealtime.options.headers); - assertArrayEquals("Verify if authHeaders has changed", opts.authHeaders, ablyRealtime.options.authHeaders); + assertArrayEquals("authHeaders should be equal before change", opts.authHeaders, ablyRealtime.options.authHeaders); opts.authHeaders = new Param[1]; opts.authHeaders[0] = new Param("new_key", "new_key"); - assertNotEquals("Verify if authHeaders has changed", opts.authHeaders, ablyRealtime.options.authHeaders); + assertNotEquals("authHeaders should not be equal after change", opts.authHeaders, ablyRealtime.options.authHeaders); - assertEquals("Verify if proxy.port has changed", opts.proxy.port, ablyRealtime.options.proxy.port); + assertEquals("proxy.port should be equal before change", opts.proxy.port, ablyRealtime.options.proxy.port); opts.proxy.port = 9090; - assertNotEquals("Verify if proxy.port has changed", opts.proxy.port, ablyRealtime.options.proxy.port); + assertNotEquals("proxy.port should not be equal after change", opts.proxy.port, ablyRealtime.options.proxy.port); ablyRealtime.close(); } catch (AblyException e) { From 66c5a5caf04982849003a6cdac296c72718384d3 Mon Sep 17 00:00:00 2001 From: Igor QSD Date: Mon, 25 Jul 2022 12:54:25 +0200 Subject: [PATCH 09/14] Update core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java Co-authored-by: Ikbal Kaya --- core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java b/core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java index d972c9110..d64b95e9d 100644 --- a/core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java +++ b/core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java @@ -10,7 +10,7 @@ public class ObjectCopyUtil { public static ClientOptions copy(ClientOptions options) { - ClientOptions copyOptions = new ClientOptions(); + final ClientOptions copyOptions = new ClientOptions(); copyOptions.clientId = options.clientId; copyOptions.logLevel = options.logLevel; copyOptions.logHandler = options.logHandler; From e1e414244841b9c4b99c8743ce734193a197336c Mon Sep 17 00:00:00 2001 From: Igor QSD Date: Tue, 26 Jul 2022 12:25:56 +0200 Subject: [PATCH 10/14] Update core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java Co-authored-by: Ikbal Kaya --- core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java b/core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java index d64b95e9d..8bfadd8cb 100644 --- a/core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java +++ b/core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java @@ -7,7 +7,7 @@ import io.ably.lib.types.ClientOptions; import io.ably.lib.types.ProxyOptions; -public class ObjectCopyUtil { +public class AblyObjectsCopyUtil { public static ClientOptions copy(ClientOptions options) { final ClientOptions copyOptions = new ClientOptions(); From 92ed336450db8f08554f4355f93a582db1d3d8e4 Mon Sep 17 00:00:00 2001 From: QSD_igor Date: Tue, 26 Jul 2022 12:32:17 +0200 Subject: [PATCH 11/14] Rename ObjectCopyUtil to AblyObjectsCopyUtil --- core/src/main/java/io/ably/lib/rest/AblyBase.java | 4 ++-- .../util/{ObjectCopyUtil.java => AblyObjectsCopyUtil.java} | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename core/src/main/java/io/ably/lib/util/{ObjectCopyUtil.java => AblyObjectsCopyUtil.java} (100%) diff --git a/core/src/main/java/io/ably/lib/rest/AblyBase.java b/core/src/main/java/io/ably/lib/rest/AblyBase.java index 8f3df33d8..4e858bca5 100644 --- a/core/src/main/java/io/ably/lib/rest/AblyBase.java +++ b/core/src/main/java/io/ably/lib/rest/AblyBase.java @@ -31,10 +31,10 @@ import io.ably.lib.types.PublishResponse; import io.ably.lib.types.Stats; import io.ably.lib.types.StatsReader; +import io.ably.lib.util.AblyObjectsCopyUtil; import io.ably.lib.util.Crypto; import io.ably.lib.util.InternalMap; import io.ably.lib.util.Log; -import io.ably.lib.util.ObjectCopyUtil; import io.ably.lib.util.PlatformAgentProvider; import io.ably.lib.util.Serialisation; @@ -89,7 +89,7 @@ public AblyBase(ClientOptions options, PlatformAgentProvider platformAgentProvid if (options instanceof DebugOptions) { this.options = options; } else { - this.options = ObjectCopyUtil.copy(options); + this.options = AblyObjectsCopyUtil.copy(options); } /* process options */ diff --git a/core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java b/core/src/main/java/io/ably/lib/util/AblyObjectsCopyUtil.java similarity index 100% rename from core/src/main/java/io/ably/lib/util/ObjectCopyUtil.java rename to core/src/main/java/io/ably/lib/util/AblyObjectsCopyUtil.java From e9fa9409729ad4ea6b925f6fea118e9afbbfca24 Mon Sep 17 00:00:00 2001 From: QSD_igor Date: Tue, 26 Jul 2022 14:52:17 +0200 Subject: [PATCH 12/14] Improve mutability test with original values to compare --- .../lib/test/realtime/RealtimeAuthTest.java | 65 +++++++++++++------ 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/core/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java b/core/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java index 11e3bceff..5a94bcc64 100644 --- a/core/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java +++ b/core/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java @@ -41,6 +41,7 @@ import static org.junit.Assert.fail; import java.util.HashMap; +import java.util.Map; public abstract class RealtimeAuthTest extends ParameterizedTest { @@ -997,52 +998,76 @@ public Object getTokenRequest(Auth.TokenParams params) { opts.proxy.port = 8080; AblyRealtimeBase ablyRealtime = createAblyRealtime(opts); - assertEquals("clientId should be equal before change", opts.clientId, ablyRealtime.options.clientId); + assertEquals("clientId given for options must be equal to the one in in AblyRealtime before change", opts.clientId, ablyRealtime.options.clientId); + String origClientId = ablyRealtime.options.clientId; opts.clientId = "my_new_clientId"; - assertNotEquals("clientId should not be equal after change", opts.clientId, ablyRealtime.options.clientId); + assertNotEquals("clientId given for options should not be equal to the one in in AblyRealtime after change", opts.clientId, ablyRealtime.options.clientId); + assertEquals("clientId in AblyRealtime should be equal to original one after ClientOptions change", origClientId, ablyRealtime.options.clientId); - assertEquals("logLevel should be equal before change", opts.logLevel, ablyRealtime.options.logLevel); + assertEquals("logLevel given for options must be equal to the one in in AblyRealtime before change", opts.logLevel, ablyRealtime.options.logLevel); + int origLogLevel = ablyRealtime.options.logLevel; opts.logLevel = 33; - assertNotEquals("logLevel should not be equal after change", opts.logLevel, ablyRealtime.options.logLevel); + assertNotEquals("logLevel given for options should not be equal to the one in in AblyRealtime after change", opts.logLevel, ablyRealtime.options.logLevel); + assertEquals("logLevel in AblyRealtime should be equal to original one after ClientOptions change", origLogLevel, ablyRealtime.options.logLevel); - assertEquals("autoConnect should be equal before change", opts.autoConnect, ablyRealtime.options.autoConnect); + assertEquals("autoConnect given for options must be equal to the one in in AblyRealtime before change", opts.autoConnect, ablyRealtime.options.autoConnect); + boolean origAutoConnect = ablyRealtime.options.autoConnect; opts.autoConnect = true; - assertNotEquals("autoConnect should not be equal after change", opts.autoConnect, ablyRealtime.options.autoConnect); + assertNotEquals("autoConnect given for options should not be equal to the one in in AblyRealtime after change", opts.autoConnect, ablyRealtime.options.autoConnect); + assertEquals("autoConnect in AblyRealtime should be equal to original one after ClientOptions change", origAutoConnect, ablyRealtime.options.autoConnect); - assertEquals("logHandler should be equal before change", opts.logHandler, ablyRealtime.options.logHandler); + assertEquals("logHandler given for options must be equal to the one in in AblyRealtime before change", opts.logHandler, ablyRealtime.options.logHandler); + Log.LogHandler origHandler = ablyRealtime.options.logHandler; opts.logHandler = new Log.DefaultHandler(); - assertNotEquals("logHandler should not be equal after change", opts.logHandler, ablyRealtime.options.logHandler); + assertNotEquals("logHandler given for options should not be equal to the one in in AblyRealtime after change", opts.logHandler, ablyRealtime.options.logHandler); + assertEquals("logHandler in AblyRealtime should be equal to original one after ClientOptions change", origHandler, ablyRealtime.options.logHandler); - assertEquals("authCallback should be equal before change", opts.authCallback, ablyRealtime.options.authCallback); + assertEquals("authCallback given for options must be equal to the one in in AblyRealtime before change", opts.authCallback, ablyRealtime.options.authCallback); + Auth.TokenCallback origTokenCallback = ablyRealtime.options.authCallback; opts.authCallback = new Auth.TokenCallback() { @Override public Object getTokenRequest(Auth.TokenParams params) { return null; } }; - assertNotEquals("authCallback should not be equal after change", opts.authCallback, ablyRealtime.options.authCallback); + assertNotEquals("authCallback given for options should not be equal to the one in in AblyRealtime after change", opts.authCallback, ablyRealtime.options.authCallback); + assertEquals("authCallback in AblyRealtime should be equal to original one after ClientOptions change", origTokenCallback, ablyRealtime.options.authCallback); - assertEquals("token should be equal before change", opts.token, ablyRealtime.options.token); + assertEquals("token given for options must be equal to the one in in AblyRealtime before change", opts.token, ablyRealtime.options.token); + String origToken = ablyRealtime.options.token; opts.token = "my_new_token"; - assertNotEquals("token should not be equal after change", opts.token, ablyRealtime.options.token); + assertNotEquals("token given for options should not be equal to the one in in AblyRealtime after change", opts.token, ablyRealtime.options.token); + assertEquals("token in AblyRealtime should be equal to original one after ClientOptions change", origToken, ablyRealtime.options.token); - assertEquals("tokenDetails should be equal before change", opts.tokenDetails, ablyRealtime.options.tokenDetails); + assertEquals("tokenDetails given for options must be equal to the one in in AblyRealtime before change", opts.tokenDetails, ablyRealtime.options.tokenDetails); + TokenDetails origTokenDetails = ablyRealtime.options.tokenDetails; opts.tokenDetails = new TokenDetails("my_new_details_token"); - assertNotEquals("tokenDetails should not be equal after change", opts.tokenDetails, ablyRealtime.options.tokenDetails); + assertNotEquals("tokenDetails given for options should not be equal to the one in in AblyRealtime after change", opts.tokenDetails, ablyRealtime.options.tokenDetails); + assertEquals("tokenDetails in AblyRealtime should be equal to original one after ClientOptions change", origTokenDetails, ablyRealtime.options.tokenDetails); - assertEquals("headers should be equal before change", opts.headers, ablyRealtime.options.headers); + assertEquals("headers given for options must be equal to the one in in AblyRealtime before change", opts.headers, ablyRealtime.options.headers); + Map origHeaders = ablyRealtime.options.headers; + String origHeaderElementValue = origHeaders.entrySet().iterator().next().getValue(); opts.headers = new HashMap<>(); opts.headers.put("new_key", "new_value"); - assertNotEquals("headers should not be equal after change", opts.headers, ablyRealtime.options.headers); + assertNotEquals("headers given for options should not be equal to the one in in AblyRealtime after change", opts.headers, ablyRealtime.options.headers); + assertEquals("headers in AblyRealtime should be equal to original one after ClientOptions change", origHeaders, ablyRealtime.options.headers); + assertEquals("first header in AblyRealtime should be equal to original one after ClientOptions change", origHeaderElementValue, ablyRealtime.options.headers.entrySet().iterator().next().getValue()); - assertArrayEquals("authHeaders should be equal before change", opts.authHeaders, ablyRealtime.options.authHeaders); + assertArrayEquals("authHeaders given for options must be equal to the one in in AblyRealtime before change", opts.authHeaders, ablyRealtime.options.authHeaders); + Param[] origParams = ablyRealtime.options.authHeaders; + String origParamValue = ablyRealtime.options.authHeaders[0].value; opts.authHeaders = new Param[1]; opts.authHeaders[0] = new Param("new_key", "new_key"); - assertNotEquals("authHeaders should not be equal after change", opts.authHeaders, ablyRealtime.options.authHeaders); + assertNotEquals("authHeaders given for options should not be equal to the one in in AblyRealtime after change", opts.authHeaders, ablyRealtime.options.authHeaders); + assertArrayEquals("authHeaders in AblyRealtime should be equal to original one after ClientOptions change", origParams, ablyRealtime.options.authHeaders); + assertEquals("first authHeader in AblyRealtime should be equal to original one after ClientOptions change", origParamValue, ablyRealtime.options.authHeaders[0].value); - assertEquals("proxy.port should be equal before change", opts.proxy.port, ablyRealtime.options.proxy.port); + assertEquals("proxy.port given for options must be equal to the one in in AblyRealtime before change", opts.proxy.port, ablyRealtime.options.proxy.port); + int origProxyPort = ablyRealtime.options.proxy.port; opts.proxy.port = 9090; - assertNotEquals("proxy.port should not be equal after change", opts.proxy.port, ablyRealtime.options.proxy.port); + assertNotEquals("proxy.port given for options should not be equal to the one in in AblyRealtime after change", opts.proxy.port, ablyRealtime.options.proxy.port); + assertEquals("proxy.port in AblyRealtime should be equal to original one after ClientOptions change", origProxyPort, ablyRealtime.options.proxy.port); ablyRealtime.close(); } catch (AblyException e) { From 9e64671d47bb7513805e7c52b454d274ee82ddd5 Mon Sep 17 00:00:00 2001 From: QSD_igor Date: Tue, 26 Jul 2022 15:59:08 +0200 Subject: [PATCH 13/14] Remove reinitialization of hashmap and array in immutable test --- .../test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java b/core/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java index 5a94bcc64..3c2a72c01 100644 --- a/core/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java +++ b/core/src/test/java/io/ably/lib/test/realtime/RealtimeAuthTest.java @@ -1048,7 +1048,7 @@ public Object getTokenRequest(Auth.TokenParams params) { assertEquals("headers given for options must be equal to the one in in AblyRealtime before change", opts.headers, ablyRealtime.options.headers); Map origHeaders = ablyRealtime.options.headers; String origHeaderElementValue = origHeaders.entrySet().iterator().next().getValue(); - opts.headers = new HashMap<>(); + opts.headers.clear(); opts.headers.put("new_key", "new_value"); assertNotEquals("headers given for options should not be equal to the one in in AblyRealtime after change", opts.headers, ablyRealtime.options.headers); assertEquals("headers in AblyRealtime should be equal to original one after ClientOptions change", origHeaders, ablyRealtime.options.headers); @@ -1057,7 +1057,6 @@ public Object getTokenRequest(Auth.TokenParams params) { assertArrayEquals("authHeaders given for options must be equal to the one in in AblyRealtime before change", opts.authHeaders, ablyRealtime.options.authHeaders); Param[] origParams = ablyRealtime.options.authHeaders; String origParamValue = ablyRealtime.options.authHeaders[0].value; - opts.authHeaders = new Param[1]; opts.authHeaders[0] = new Param("new_key", "new_key"); assertNotEquals("authHeaders given for options should not be equal to the one in in AblyRealtime after change", opts.authHeaders, ablyRealtime.options.authHeaders); assertArrayEquals("authHeaders in AblyRealtime should be equal to original one after ClientOptions change", origParams, ablyRealtime.options.authHeaders); From afbaf74b1ee3e9906f3203676c2d9c7ec0694062 Mon Sep 17 00:00:00 2001 From: QSD_igor Date: Wed, 27 Jul 2022 16:02:29 +0200 Subject: [PATCH 14/14] Move copy method from AblyObjectsCopyUtil to ClientOptions --- .../main/java/io/ably/lib/rest/AblyBase.java | 3 +- .../java/io/ably/lib/types/ClientOptions.java | 94 ++++++++++++++++++ .../io/ably/lib/util/AblyObjectsCopyUtil.java | 98 ------------------- 3 files changed, 95 insertions(+), 100 deletions(-) delete mode 100644 core/src/main/java/io/ably/lib/util/AblyObjectsCopyUtil.java diff --git a/core/src/main/java/io/ably/lib/rest/AblyBase.java b/core/src/main/java/io/ably/lib/rest/AblyBase.java index 4e858bca5..15e3ba5a2 100644 --- a/core/src/main/java/io/ably/lib/rest/AblyBase.java +++ b/core/src/main/java/io/ably/lib/rest/AblyBase.java @@ -31,7 +31,6 @@ import io.ably.lib.types.PublishResponse; import io.ably.lib.types.Stats; import io.ably.lib.types.StatsReader; -import io.ably.lib.util.AblyObjectsCopyUtil; import io.ably.lib.util.Crypto; import io.ably.lib.util.InternalMap; import io.ably.lib.util.Log; @@ -89,7 +88,7 @@ public AblyBase(ClientOptions options, PlatformAgentProvider platformAgentProvid if (options instanceof DebugOptions) { this.options = options; } else { - this.options = AblyObjectsCopyUtil.copy(options); + this.options = options.copy(); } /* process options */ diff --git a/core/src/main/java/io/ably/lib/types/ClientOptions.java b/core/src/main/java/io/ably/lib/types/ClientOptions.java index c97a426ee..9f095b3f8 100644 --- a/core/src/main/java/io/ably/lib/types/ClientOptions.java +++ b/core/src/main/java/io/ably/lib/types/ClientOptions.java @@ -1,12 +1,15 @@ package io.ably.lib.types; import io.ably.lib.push.Storage; +import io.ably.lib.rest.Auth; import io.ably.lib.rest.Auth.AuthOptions; import io.ably.lib.rest.Auth.TokenParams; import io.ably.lib.transport.Defaults; import io.ably.lib.util.Log; import io.ably.lib.util.Log.LogHandler; +import java.util.Arrays; +import java.util.HashMap; import java.util.Map; /** @@ -220,4 +223,95 @@ public ClientOptions(String key) throws AblyException { * Agent versions are optional, if you don't want to specify it pass `null` as the map entry value. */ public Map agents; + + /** + * Creates new copy of this object + * @return copy of ClientOptions + */ + public ClientOptions copy() { + final ClientOptions copyOptions = new ClientOptions(); + copyOptions.clientId = this.clientId; + copyOptions.logLevel = this.logLevel; + copyOptions.logHandler = this.logHandler; + copyOptions.tls = this.tls; + copyOptions.restHost = this.restHost; + copyOptions.realtimeHost = this.realtimeHost; + copyOptions.port = this.port; + copyOptions.tlsPort = this.tlsPort; + copyOptions.autoConnect = this.autoConnect; + copyOptions.useBinaryProtocol = this.useBinaryProtocol; + copyOptions.queueMessages = this.queueMessages; + copyOptions.echoMessages = this.echoMessages; + copyOptions.recover = this.recover; + copyOptions.idempotentRestPublishing = this.idempotentRestPublishing; + copyOptions.httpOpenTimeout = this.httpOpenTimeout; + copyOptions.httpRequestTimeout = this.httpRequestTimeout; + copyOptions.httpMaxRetryCount = this.httpMaxRetryCount; + copyOptions.realtimeRequestTimeout = this.realtimeRequestTimeout; + copyOptions.fallbackHostsUseDefault = this.fallbackHostsUseDefault; + copyOptions.fallbackRetryTimeout = this.fallbackRetryTimeout; + copyOptions.defaultTokenParams = this.defaultTokenParams.copy(); + copyOptions.channelRetryTimeout = this.channelRetryTimeout; + copyOptions.asyncHttpThreadpoolSize = this.asyncHttpThreadpoolSize; + copyOptions.pushFullWait = this.pushFullWait; + copyOptions.localStorage = this.localStorage; + copyOptions.addRequestIds = this.addRequestIds; + copyOptions.environment = this.environment; + + //params from AuthOptions + copyOptions.authCallback = this.authCallback; + copyOptions.authUrl = this.authUrl; + copyOptions.authMethod = this.authMethod; + copyOptions.key = this.key; + copyOptions.token = this.token; + copyOptions.queryTime = this.queryTime; + copyOptions.useTokenAuth = this.useTokenAuth; + + if (this.headers != null) { + copyOptions.headers = new HashMap<>(this.headers); + } + + if (this.agents != null) { + copyOptions.agents = new HashMap<>(this.agents); + } + + if (this.authParams != null) { + copyOptions.authParams = Arrays.copyOf(this.authParams, this.authParams.length); + } + + if (this.authHeaders != null) { + copyOptions.authHeaders = Arrays.copyOf(this.authHeaders, this.authHeaders.length); + } + + if (this.transportParams != null) { + copyOptions.transportParams = Arrays.copyOf(this.transportParams, this.transportParams.length); + } + + if (this.fallbackHosts != null) { + copyOptions.fallbackHosts = Arrays.copyOf(this.fallbackHosts, this.fallbackHosts.length); + } + + if (this.proxy != null) { + ProxyOptions po = new ProxyOptions(); + po.host = this.proxy.host; + po.port = this.proxy.port; + po.username = this.proxy.username; + po.password = this.proxy.password; + po.nonProxyHosts = this.proxy.nonProxyHosts; + po.prefAuthType = this.proxy.prefAuthType; + copyOptions.proxy = po; + } + + if (this.tokenDetails != null) { + Auth.TokenDetails tokenDetails = new Auth.TokenDetails(); + tokenDetails.token = this.tokenDetails.token; + tokenDetails.expires = this.tokenDetails.expires; + tokenDetails.issued = this.tokenDetails.issued; + tokenDetails.capability = this.tokenDetails.capability; + tokenDetails.clientId = this.tokenDetails.clientId; + copyOptions.tokenDetails = tokenDetails; + } + + return copyOptions; + } } diff --git a/core/src/main/java/io/ably/lib/util/AblyObjectsCopyUtil.java b/core/src/main/java/io/ably/lib/util/AblyObjectsCopyUtil.java deleted file mode 100644 index 8bfadd8cb..000000000 --- a/core/src/main/java/io/ably/lib/util/AblyObjectsCopyUtil.java +++ /dev/null @@ -1,98 +0,0 @@ -package io.ably.lib.util; - -import java.util.Arrays; -import java.util.HashMap; - -import io.ably.lib.rest.Auth; -import io.ably.lib.types.ClientOptions; -import io.ably.lib.types.ProxyOptions; - -public class AblyObjectsCopyUtil { - - public static ClientOptions copy(ClientOptions options) { - final ClientOptions copyOptions = new ClientOptions(); - copyOptions.clientId = options.clientId; - copyOptions.logLevel = options.logLevel; - copyOptions.logHandler = options.logHandler; - copyOptions.tls = options.tls; - copyOptions.restHost = options.restHost; - copyOptions.realtimeHost = options.realtimeHost; - copyOptions.port = options.port; - copyOptions.tlsPort = options.tlsPort; - copyOptions.autoConnect = options.autoConnect; - copyOptions.useBinaryProtocol = options.useBinaryProtocol; - copyOptions.queueMessages = options.queueMessages; - copyOptions.echoMessages = options.echoMessages; - copyOptions.recover = options.recover; - copyOptions.idempotentRestPublishing = options.idempotentRestPublishing; - copyOptions.httpOpenTimeout = options.httpOpenTimeout; - copyOptions.httpRequestTimeout = options.httpRequestTimeout; - copyOptions.httpMaxRetryCount = options.httpMaxRetryCount; - copyOptions.realtimeRequestTimeout = options.realtimeRequestTimeout; - copyOptions.fallbackHostsUseDefault = options.fallbackHostsUseDefault; - copyOptions.fallbackRetryTimeout = options.fallbackRetryTimeout; - copyOptions.defaultTokenParams = options.defaultTokenParams.copy(); - copyOptions.channelRetryTimeout = options.channelRetryTimeout; - copyOptions.asyncHttpThreadpoolSize = options.asyncHttpThreadpoolSize; - copyOptions.pushFullWait = options.pushFullWait; - copyOptions.localStorage = options.localStorage; - copyOptions.addRequestIds = options.addRequestIds; - copyOptions.environment = options.environment; - - //params from AuthOptions - copyOptions.authCallback = options.authCallback; - copyOptions.authUrl = options.authUrl; - copyOptions.authMethod = options.authMethod; - copyOptions.key = options.key; - copyOptions.token = options.token; - copyOptions.queryTime = options.queryTime; - copyOptions.useTokenAuth = options.useTokenAuth; - - if (options.headers != null) { - copyOptions.headers = new HashMap<>(options.headers); - } - - if (options.agents != null) { - copyOptions.agents = new HashMap<>(options.agents); - } - - if (options.authParams != null) { - copyOptions.authParams = Arrays.copyOf(options.authParams, options.authParams.length); - } - - if (options.authHeaders != null) { - copyOptions.authHeaders = Arrays.copyOf(options.authHeaders, options.authHeaders.length); - } - - if (options.transportParams != null) { - copyOptions.transportParams = Arrays.copyOf(options.transportParams, options.transportParams.length); - } - - if (options.fallbackHosts != null) { - copyOptions.fallbackHosts = Arrays.copyOf(options.fallbackHosts, options.fallbackHosts.length); - } - - if (options.proxy != null) { - ProxyOptions po = new ProxyOptions(); - po.host = options.proxy.host; - po.port = options.proxy.port; - po.username = options.proxy.username; - po.password = options.proxy.password; - po.nonProxyHosts = options.proxy.nonProxyHosts; - po.prefAuthType = options.proxy.prefAuthType; - copyOptions.proxy = po; - } - - if (options.tokenDetails != null) { - Auth.TokenDetails tokenDetails = new Auth.TokenDetails(); - tokenDetails.token = options.tokenDetails.token; - tokenDetails.expires = options.tokenDetails.expires; - tokenDetails.issued = options.tokenDetails.issued; - tokenDetails.capability = options.tokenDetails.capability; - tokenDetails.clientId = options.tokenDetails.clientId; - copyOptions.tokenDetails = tokenDetails; - } - - return copyOptions; - } -}