From c100db29541317ee226785475c673b988ab35c37 Mon Sep 17 00:00:00 2001 From: Tom Reznik Date: Fri, 15 May 2015 11:01:38 +0200 Subject: [PATCH 1/2] Support optional no links mode --- .../com/contentful/java/cda/ArrayParser.java | 14 ++--- .../com/contentful/java/cda/CDAClient.java | 28 +++++++-- .../contentful/java/cda/ClientContext.java | 5 +- .../com/contentful/java/cda/AndroidTests.kt | 2 +- .../com/contentful/java/cda/BaseTest.kt | 2 +- .../com/contentful/java/cda/ClientTests.kt | 59 +++++++++++++------ .../contentful/java/cda/ContentTypeTests.kt | 17 +++--- .../com/contentful/java/cda/EntryTests.kt | 4 +- .../contentful/java/cda/SerializationTests.kt | 4 +- .../com/contentful/java/cda/SyncTests.kt | 2 +- 10 files changed, 90 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/contentful/java/cda/ArrayParser.java b/src/main/java/com/contentful/java/cda/ArrayParser.java index 4f870038..6884f2ca 100644 --- a/src/main/java/com/contentful/java/cda/ArrayParser.java +++ b/src/main/java/com/contentful/java/cda/ArrayParser.java @@ -47,7 +47,7 @@ public ArrayParser(T source, ClientContext context) { this.context = context; } - @Override public T call() throws Exception { + public T call() throws Exception { HashMap assets = new HashMap(); HashMap entries = new HashMap(); boolean sync = source instanceof CDASyncedSpace; @@ -94,12 +94,12 @@ public ArrayParser(T source, ClientContext context) { } } - // Iterate through all entries and attempt to resolve contained links. - for (Map.Entry entry : entries.entrySet()) { - CDAResource item = entry.getValue(); - - if (item instanceof ResourceWithMap) { - resolveResourceLinks((ResourceWithMap) item, assets, entries); + if (!context.skipLinks) { + // Iterate through all entries and attempt to resolve contained links. + for (CDAResource resource : entries.values()) { + if (resource instanceof ResourceWithMap) { + resolveResourceLinks((ResourceWithMap) resource, assets, entries); + } } } diff --git a/src/main/java/com/contentful/java/cda/CDAClient.java b/src/main/java/com/contentful/java/cda/CDAClient.java index 05968f0d..51429ea7 100644 --- a/src/main/java/com/contentful/java/cda/CDAClient.java +++ b/src/main/java/com/contentful/java/cda/CDAClient.java @@ -84,8 +84,9 @@ private CDAClient(Builder builder) { this.service = createRetrofitService(builder); // Modules - ClientContext context = new ClientContext(service, callbackExecutor, spaceKey, - gson, spaceWrapper, classMap, builder.nullifyUnresolved); + ClientContext context = + new ClientContext(service, callbackExecutor, spaceKey, gson, spaceWrapper, classMap, + builder.skipLinks, builder.nullifyUnresolved); this.moduleAssets = new ModuleAssets(context); this.moduleContentTypes = new ModuleContentTypes(context); @@ -237,7 +238,7 @@ private void setEndPoint(Builder builder, RestAdapter.Builder restBuilder) { private RequestInterceptor createInterceptor() { return new RequestInterceptor() { - @Override public void intercept(RequestFacade requestFacade) { + public void intercept(RequestFacade requestFacade) { if (accessToken != null && !accessToken.isEmpty()) { requestFacade.addHeader(HTTP_HEADER_AUTH, String.format(HTTP_OAUTH_PATTERN, accessToken)); } @@ -247,6 +248,11 @@ private RequestInterceptor createInterceptor() { }; } + /** Creates a new {@link Builder} instance. */ + public static Builder builder() { + return new Builder(); + } + /** * Client builder. * @@ -267,11 +273,11 @@ public static class Builder { Map> classMap; boolean secure; boolean nullifyUnresolved; + boolean skipLinks; - public Builder() { + private Builder() { // Defaults this.secure = true; - this.nullifyUnresolved = false; } /** @@ -344,7 +350,7 @@ public Builder setClient(final Client client) { } return setClientProvider(new Client.Provider() { - @Override public Client get() { + public Client get() { return client; } }); @@ -429,6 +435,16 @@ public Builder preview() { return setEndpoint(Constants.ENDPOINT_PREVIEW); } + /** + * Sets the behavior of this client to never resolve any links. + * + * @return this {@code Builder} instance + */ + public Builder skipLinks() { + this.skipLinks = true; + return this; + } + /** * By default, unresolved links will point to a {@code Map} instance containing all the links * details. This changes the default behaviour to remove any unresolved links. diff --git a/src/main/java/com/contentful/java/cda/ClientContext.java b/src/main/java/com/contentful/java/cda/ClientContext.java index 268dc469..4d345988 100644 --- a/src/main/java/com/contentful/java/cda/ClientContext.java +++ b/src/main/java/com/contentful/java/cda/ClientContext.java @@ -30,16 +30,19 @@ final class ClientContext { final Gson gson; final SpaceWrapper spaceWrapper; final Map> customTypesMap; + final boolean skipLinks; final boolean nullifyUnresolved; public ClientContext(CDAService service, Executor callbackExecutor, String spaceId, Gson gson, - SpaceWrapper spaceWrapper, Map> customTypesMap, boolean nullifyUnresolved) { + SpaceWrapper spaceWrapper, Map> customTypesMap, boolean skipLinks, + boolean nullifyUnresolved) { this.service = service; this.callbackExecutor = callbackExecutor; this.spaceId = spaceId; this.gson = gson; this.spaceWrapper = spaceWrapper; this.customTypesMap = customTypesMap; + this.skipLinks = skipLinks; this.nullifyUnresolved = nullifyUnresolved; } } diff --git a/src/test/kotlin/com/contentful/java/cda/AndroidTests.kt b/src/test/kotlin/com/contentful/java/cda/AndroidTests.kt index 77f2b73d..ea3e87d8 100644 --- a/src/test/kotlin/com/contentful/java/cda/AndroidTests.kt +++ b/src/test/kotlin/com/contentful/java/cda/AndroidTests.kt @@ -69,7 +69,7 @@ class AndroidTests : BaseTest() { } } - val androidClient = CDAClient.Builder() + val androidClient = CDAClient.builder() .setSpaceKey("space") .setAccessToken("token") .setEndpoint(getIntent().getStringExtra("EXTRA_URL")) diff --git a/src/test/kotlin/com/contentful/java/cda/BaseTest.kt b/src/test/kotlin/com/contentful/java/cda/BaseTest.kt index c8484483..c75b09b7 100644 --- a/src/test/kotlin/com/contentful/java/cda/BaseTest.kt +++ b/src/test/kotlin/com/contentful/java/cda/BaseTest.kt @@ -39,7 +39,7 @@ open class BaseTest { server!!.play() // Client - client = CDAClient.Builder() + client = CDAClient.builder() .setAccessToken("token") .setSpaceKey("spaceid") .setEndpoint(getServerUrl()) diff --git a/src/test/kotlin/com/contentful/java/cda/ClientTests.kt b/src/test/kotlin/com/contentful/java/cda/ClientTests.kt index dc45839d..431c944c 100644 --- a/src/test/kotlin/com/contentful/java/cda/ClientTests.kt +++ b/src/test/kotlin/com/contentful/java/cda/ClientTests.kt @@ -16,25 +16,48 @@ package com.contentful.java.cda -import kotlin.test.assertEquals import com.contentful.java.cda.lib.TestCallback +import com.contentful.java.cda.model.CDAEntry +import com.contentful.java.cda.model.CDAResource +import com.contentful.java.cda.model.CDASpace +import com.squareup.okhttp.mockwebserver.MockResponse +import org.mockito.Mockito +import retrofit.RestAdapter import retrofit.RetrofitError +import rx.Observable +import java.io.IOException import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit -import com.squareup.okhttp.mockwebserver.MockResponse +import kotlin.test.assertEquals import kotlin.test.assertFalse -import java.io.IOException import kotlin.test.assertNotNull import kotlin.test.assertTrue -import rx.Observable import org.junit.Test as test -import com.contentful.java.cda.model.CDASpace -import org.mockito.Mockito /** * Client Tests. */ class ClientTests : BaseTest() { + test fun testDontResolveLinks() { + enqueue("space_fetch_response.json") + enqueue("entry_fetch_all_response.json") + + val cli = CDAClient.builder() + .setAccessToken("token") + .setSpaceKey("spaceid") + .setEndpoint(getServerUrl()) + .setLogLevel(RestAdapter.LogLevel.FULL) + .skipLinks() + .noSSL() + .build() + + val array = cli.entries().fetchAll() + var jake = array.getItems()[0] as? CDAEntry + assertNotNull(jake) + assertEquals("Jake", jake!!.getFields()["name"]) + assertFalse(jake!!.getFields()["image"] is CDAResource) + } + test fun testCancelledCallback() { enqueue("space_fetch_response.json") @@ -61,7 +84,7 @@ class ClientTests : BaseTest() { } test fun testCallbackRetrofitError() { - val badClient = CDAClient.Builder() + val badClient = CDAClient.builder() .setSpaceKey("space") .setAccessToken("token") .setCallbackExecutor { it.run() } @@ -100,7 +123,7 @@ class ClientTests : BaseTest() { } test fun testPreview() { - val cli = CDAClient.Builder() + val cli = CDAClient.builder() .setSpaceKey("cfexampleapi") .setAccessToken("e5e8d4c5c122cf28fc1af3ff77d28bef78a3952957f15067bbc29f2f0dde0b50") .preview() @@ -150,7 +173,7 @@ class ClientTests : BaseTest() { test(expected = javaClass()) fun failsNoAccessToken() { try { - CDAClient.Builder().build() + CDAClient.builder().build() } catch (e: IllegalArgumentException) { assertEquals("Access token must be defined.", e.getMessage()) throw e @@ -160,7 +183,7 @@ class ClientTests : BaseTest() { test(expected = javaClass()) fun failsNoSpace() { try { - CDAClient.Builder().setAccessToken("token").build() + CDAClient.builder().setAccessToken("token").build() } catch (e: IllegalArgumentException) { assertEquals("Space ID must be defined.", e.getMessage()) throw e @@ -170,7 +193,7 @@ class ClientTests : BaseTest() { test(expected = javaClass()) fun failsSetNullAccessToken() { try { - CDAClient.Builder().setAccessToken(null) + CDAClient.builder().setAccessToken(null) } catch (e: IllegalArgumentException) { assertEquals("Cannot call setAccessToken() with null.", e.getMessage()) throw e @@ -180,7 +203,7 @@ class ClientTests : BaseTest() { test(expected = javaClass()) fun failsSetSpaceKey() { try { - CDAClient.Builder().setSpaceKey(null) + CDAClient.builder().setSpaceKey(null) } catch (e: IllegalArgumentException) { assertEquals("Cannot call setSpaceKey() with null.", e.getMessage()) throw e @@ -190,7 +213,7 @@ class ClientTests : BaseTest() { test(expected = javaClass()) fun failsSetNullCallbackExecutor() { try { - CDAClient.Builder().setCallbackExecutor(null) + CDAClient.builder().setCallbackExecutor(null) } catch (e: IllegalArgumentException) { assertEquals("Cannot call setCallbackExecutor() with null.", e.getMessage()) throw e @@ -200,7 +223,7 @@ class ClientTests : BaseTest() { test(expected = javaClass()) fun failsSetNullCustomClasses() { try { - CDAClient.Builder().setCustomClasses(null) + CDAClient.builder().setCustomClasses(null) } catch (e: IllegalArgumentException) { assertEquals("Cannot call setCustomClasses() with null.", e.getMessage()) throw e @@ -210,7 +233,7 @@ class ClientTests : BaseTest() { test(expected = javaClass()) fun failsSetNullClient() { try { - CDAClient.Builder().setClient(null) + CDAClient.builder().setClient(null) } catch (e: IllegalArgumentException) { assertEquals("Cannot call setClient() with null.", e.getMessage()) throw e @@ -220,7 +243,7 @@ class ClientTests : BaseTest() { test(expected = javaClass()) fun failsSetNullLogLevel() { try { - CDAClient.Builder().setLogLevel(null) + CDAClient.builder().setLogLevel(null) } catch (e: IllegalArgumentException) { assertEquals("Cannot call setLogLevel() with null.", e.getMessage()) throw e @@ -230,7 +253,7 @@ class ClientTests : BaseTest() { test(expected = javaClass()) fun failsSetNullClientProvider() { try { - CDAClient.Builder().setClientProvider(null) + CDAClient.builder().setClientProvider(null) } catch (e: IllegalArgumentException) { assertEquals("Cannot call setClientProvider() with null.", e.getMessage()) throw e @@ -240,7 +263,7 @@ class ClientTests : BaseTest() { test(expected = javaClass()) fun failsSetNullEndPoint() { try { - CDAClient.Builder().setEndpoint(null) + CDAClient.builder().setEndpoint(null) } catch (e: IllegalArgumentException) { assertEquals("Cannot call setEndpoint() with null.", e.getMessage()) throw e diff --git a/src/test/kotlin/com/contentful/java/cda/ContentTypeTests.kt b/src/test/kotlin/com/contentful/java/cda/ContentTypeTests.kt index 7331853e..f8e5bcbb 100644 --- a/src/test/kotlin/com/contentful/java/cda/ContentTypeTests.kt +++ b/src/test/kotlin/com/contentful/java/cda/ContentTypeTests.kt @@ -34,7 +34,7 @@ class ContentTypeTests : BaseTest() { client!!.contentTypes().async().fetchAll(TestCallback())) assertEquals(1, result.getTotal()) - assertEquals(1, result.getItems().size) + assertEquals(1, result.getItems().size()) assertTrue(result.getItems()[0] is CDAContentType) val city = result.getItems()[0] as CDAContentType @@ -44,7 +44,7 @@ class ContentTypeTests : BaseTest() { // Fields val fields = city.getFields() - assertEquals(2, fields.size) + assertEquals(2, fields.size()) // Field: Name assertEquals("Name", fields[0].get("name")) @@ -91,7 +91,7 @@ class ContentTypeTests : BaseTest() { // Fields val fields = result.getFields() - assertEquals(10, fields.size) + assertEquals(10, fields.size()) val fieldTypes = listOf( CDAFieldType.Text, @@ -105,11 +105,12 @@ class ContentTypeTests : BaseTest() { CDAFieldType.Object, CDAFieldType.Array) - fieldTypes.withIndices().forEach { - val field = fields[it.first] - assertEquals("id${it.first}", field["id"]) - assertEquals("name${it.first}", field["name"]) - it.second.assertFrom(field["type"]!!) + fieldTypes.withIndex().forEach { + val i = it.index + val field = fields[i] + assertEquals("id${i}", field["id"]) + assertEquals("name${i}", field["name"]) + it.value.assertFrom(field["type"]!!) } // Request diff --git a/src/test/kotlin/com/contentful/java/cda/EntryTests.kt b/src/test/kotlin/com/contentful/java/cda/EntryTests.kt index 8b1ab8d2..b068cdcc 100644 --- a/src/test/kotlin/com/contentful/java/cda/EntryTests.kt +++ b/src/test/kotlin/com/contentful/java/cda/EntryTests.kt @@ -42,7 +42,7 @@ class EntryTests : BaseTest() { } test fun testNullifyUnresolvedLinks() { - val cli = CDAClient.Builder() + val cli = CDAClient.builder() .setAccessToken("token") .setSpaceKey("spaceid") .setEndpoint(getServerUrl()) @@ -63,7 +63,7 @@ class EntryTests : BaseTest() { } test fun testCustomClass() { - val cli = CDAClient.Builder() + val cli = CDAClient.builder() .setAccessToken("token") .setSpaceKey("space") .setEndpoint(getServerUrl()) diff --git a/src/test/kotlin/com/contentful/java/cda/SerializationTests.kt b/src/test/kotlin/com/contentful/java/cda/SerializationTests.kt index 2563f200..57a606cb 100644 --- a/src/test/kotlin/com/contentful/java/cda/SerializationTests.kt +++ b/src/test/kotlin/com/contentful/java/cda/SerializationTests.kt @@ -44,7 +44,7 @@ class SerializationTests : BaseTest() { test(expected = javaClass()) fun testTypeAdapterInstantiationException() { - val cli = CDAClient.Builder() + val cli = CDAClient.builder() .setSpaceKey("space") .setAccessToken("token") .setCustomClasses(hashMapOf( @@ -63,7 +63,7 @@ class SerializationTests : BaseTest() { test(expected = javaClass()) fun testTypeAdapterIllegalAccessException() { - val cli = CDAClient.Builder() + val cli = CDAClient.builder() .setSpaceKey("space") .setAccessToken("token") .setCustomClasses(hashMapOf( diff --git a/src/test/kotlin/com/contentful/java/cda/SyncTests.kt b/src/test/kotlin/com/contentful/java/cda/SyncTests.kt index 842d3b46..24e626a3 100644 --- a/src/test/kotlin/com/contentful/java/cda/SyncTests.kt +++ b/src/test/kotlin/com/contentful/java/cda/SyncTests.kt @@ -45,7 +45,7 @@ class SyncTests : BaseTest() { } test fun testRemoteSynchronization() { - val cli = CDAClient.Builder() + val cli = CDAClient.builder() .setAccessToken("9caa9b36fbb4250508b8e3322861dbddd7527bc02ba28f44b926c5d99f22d2ab") .setSpaceKey("hvjkfbzcwrfn") .build() From e2c2493b4be3b53b5bc49a5403b2c500eaf05856 Mon Sep 17 00:00:00 2001 From: Tom Reznik Date: Fri, 15 May 2015 11:15:50 +0200 Subject: [PATCH 2/2] Use builder for `ClientContext` --- .../com/contentful/java/cda/CDAClient.java | 23 +++-- .../contentful/java/cda/ClientContext.java | 86 ++++++++++++++++--- 2 files changed, 93 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/contentful/java/cda/CDAClient.java b/src/main/java/com/contentful/java/cda/CDAClient.java index 51429ea7..6c334948 100644 --- a/src/main/java/com/contentful/java/cda/CDAClient.java +++ b/src/main/java/com/contentful/java/cda/CDAClient.java @@ -56,6 +56,7 @@ public class CDAClient { final Gson gson; final SpaceWrapper spaceWrapper; final Executor callbackExecutor; + final boolean skipLinks; // Modules final ModuleAssets moduleAssets; @@ -63,6 +64,7 @@ public class CDAClient { final ModuleEntries moduleEntries; final ModuleSpaces moduleSpaces; final ModuleSync moduleSync; + final boolean nullifyUnresolved; private CDAClient(Builder builder) { if (builder.accessToken == null) { @@ -82,12 +84,10 @@ private CDAClient(Builder builder) { this.callbackExecutor = createCallbackExecutor(builder); this.gson = createGson(); this.service = createRetrofitService(builder); + this.skipLinks = builder.skipLinks; + this.nullifyUnresolved = builder.nullifyUnresolved; - // Modules - ClientContext context = - new ClientContext(service, callbackExecutor, spaceKey, gson, spaceWrapper, classMap, - builder.skipLinks, builder.nullifyUnresolved); - + ClientContext context = createContext(); this.moduleAssets = new ModuleAssets(context); this.moduleContentTypes = new ModuleContentTypes(context); this.moduleEntries = new ModuleEntries(context); @@ -95,6 +95,19 @@ private CDAClient(Builder builder) { this.moduleSync = new ModuleSync(context); } + private ClientContext createContext() { + return ClientContext.builder() + .setService(service) + .setCallbackExecutor(callbackExecutor) + .setSpaceId(spaceKey) + .setGson(gson) + .setSpaceWrapper(spaceWrapper) + .setCustomTypesMap(classMap) + .setSkipLinks(skipLinks) + .setNullifyUnresolved(nullifyUnresolved) + .build(); + } + /** * Returns the {@code CDASpace} object associated with this client. Note that a Space is attached * to a client only after it's first request was successfully executed. diff --git a/src/main/java/com/contentful/java/cda/ClientContext.java b/src/main/java/com/contentful/java/cda/ClientContext.java index 4d345988..6f9efa4c 100644 --- a/src/main/java/com/contentful/java/cda/ClientContext.java +++ b/src/main/java/com/contentful/java/cda/ClientContext.java @@ -33,16 +33,80 @@ final class ClientContext { final boolean skipLinks; final boolean nullifyUnresolved; - public ClientContext(CDAService service, Executor callbackExecutor, String spaceId, Gson gson, - SpaceWrapper spaceWrapper, Map> customTypesMap, boolean skipLinks, - boolean nullifyUnresolved) { - this.service = service; - this.callbackExecutor = callbackExecutor; - this.spaceId = spaceId; - this.gson = gson; - this.spaceWrapper = spaceWrapper; - this.customTypesMap = customTypesMap; - this.skipLinks = skipLinks; - this.nullifyUnresolved = nullifyUnresolved; + private ClientContext() { + throw new AssertionError(); + } + + public ClientContext(Builder builder) { + this.service = builder.service; + this.callbackExecutor = builder.callbackExecutor; + this.spaceId = builder.spaceId; + this.gson = builder.gson; + this.spaceWrapper = builder.spaceWrapper; + this.customTypesMap = builder.customTypesMap; + this.skipLinks = builder.skipLinks; + this.nullifyUnresolved = builder.nullifyUnresolved; + } + + static Builder builder() { + return new Builder(); + } + + static class Builder { + private CDAService service; + private Executor callbackExecutor; + private String spaceId; + private Gson gson; + private SpaceWrapper spaceWrapper; + private Map> customTypesMap; + private boolean skipLinks; + private boolean nullifyUnresolved; + + private Builder() { + } + + public Builder setService(CDAService service) { + this.service = service; + return this; + } + + public Builder setCallbackExecutor(Executor callbackExecutor) { + this.callbackExecutor = callbackExecutor; + return this; + } + + public Builder setSpaceId(String spaceId) { + this.spaceId = spaceId; + return this; + } + + public Builder setGson(Gson gson) { + this.gson = gson; + return this; + } + + public Builder setSpaceWrapper(SpaceWrapper spaceWrapper) { + this.spaceWrapper = spaceWrapper; + return this; + } + + public Builder setCustomTypesMap(Map> customTypesMap) { + this.customTypesMap = customTypesMap; + return this; + } + + public Builder setSkipLinks(boolean skipLinks) { + this.skipLinks = skipLinks; + return this; + } + + public Builder setNullifyUnresolved(boolean nullifyUnresolved) { + this.nullifyUnresolved = nullifyUnresolved; + return this; + } + + public ClientContext build() { + return new ClientContext(this); + } } }