diff --git a/README.md b/README.md
index a0114e9..58c2ee9 100644
--- a/README.md
+++ b/README.md
@@ -4,10 +4,10 @@ Crud HTTP
This project provides an implementation of the [Crud API](https://github.com/rickbw/crud-api) for HTTP, based on [Jersey](https://jersey.java.net).
The four primary HTTP methods are all supported:
-* `GET`: [JerseyReadableResource](https://github.com/rickbw/crud-http/blob/master/src/main/java/rickbw/crud/http/JerseyReadableResource.java), a [ReadableResource](https://github.com/rickbw/crud-api/blob/master/src/main/java/rickbw/crud/ReadableResource.java)
-* `PUT`: [JerseyWritableResource](https://github.com/rickbw/crud-http/blob/master/src/main/java/rickbw/crud/http/JerseyWritableResource.java), a [WritableResource](https://github.com/rickbw/crud-api/blob/master/src/main/java/rickbw/crud/WritableResource.java)
-* `POST`: [JerseyUpdatableResource](https://github.com/rickbw/crud-http/blob/master/src/main/java/rickbw/crud/http/JerseyUpdatableResource.java), an [UpdatableResource](https://github.com/rickbw/crud-api/blob/master/src/main/java/rickbw/crud/UpdatableResource.java)
-* `DELETE`: [JerseyDeletableResource](https://github.com/rickbw/crud-http/blob/master/src/main/java/rickbw/crud/http/JerseyDeletableResource.java), a [DeletableResource](https://github.com/rickbw/crud-api/blob/master/src/main/java/rickbw/crud/DeletableResource.java)
+* `GET`: [JerseyReadableResource](https://github.com/rickbw/crud-http/blob/master/src/main/java/rickbw/crud/http/JerseyReadableResource.java), a [ReadableResource](https://github.com/rickbw/crud-api/blob/master/src/main/java/rickbw/crud/spi/ReadableResource.java)
+* `PUT`: [JerseyWritableResource](https://github.com/rickbw/crud-http/blob/master/src/main/java/rickbw/crud/http/JerseyWritableResource.java), a [WritableResource](https://github.com/rickbw/crud-api/blob/master/src/main/java/rickbw/crud/spi/WritableResource.java)
+* `POST`: [JerseyUpdatableResource](https://github.com/rickbw/crud-http/blob/master/src/main/java/rickbw/crud/http/JerseyUpdatableResource.java), an [UpdatableResource](https://github.com/rickbw/crud-api/blob/master/src/main/java/rickbw/crud/spi/UpdatableResource.java)
+* `DELETE`: [JerseyDeletableResource](https://github.com/rickbw/crud-http/blob/master/src/main/java/rickbw/crud/http/JerseyDeletableResource.java), a [DeletableResource](https://github.com/rickbw/crud-api/blob/master/src/main/java/rickbw/crud/spi/DeletableResource.java)
Most applications will not use these `Resource` implementation classes directly. Instead, they will start with the corresponding `ResourceProviders`, which implement URI-based lookup of particular `Resources`. For example, [JerseyReadableResourceProvider](https://github.com/rickbw/crud-http/blob/master/src/main/java/rickbw/crud/http/JerseyReadableResourceProvider.java) provides instances of `JerseyReadableResource` on demand.
diff --git a/pom.xml b/pom.xml
index f433ea2..ec10362 100644
--- a/pom.xml
+++ b/pom.xml
@@ -22,7 +22,7 @@ the License.
rickbw
crud-http
- 0.5-SNAPSHOT
+ 0.6-SNAPSHOT
jar
Crud HTTP Implementation
@@ -65,7 +65,7 @@ the License.
1.18
- 0.5-SNAPSHOT
+ 0.6-SNAPSHOT
4.11
1.8.5
diff --git a/src/main/java/crud/http/ClientRequest.java b/src/main/java/crud/http/ClientRequest.java
index 566de2b..e1fef3f 100644
--- a/src/main/java/crud/http/ClientRequest.java
+++ b/src/main/java/crud/http/ClientRequest.java
@@ -32,12 +32,12 @@
import com.google.common.collect.Sets;
import com.sun.jersey.api.client.PartialRequestBuilder;
-import crud.ResourceProvider;
+import crud.spi.ResourceSet;
/**
* A container for the state used to initialize HTTP
- * {@link ResourceProvider}s.
+ * {@link ResourceSet}s.
*/
public class ClientRequest {
diff --git a/src/main/java/crud/http/HttpResource.java b/src/main/java/crud/http/HttpResource.java
index 4a8af90..d4ec9b7 100644
--- a/src/main/java/crud/http/HttpResource.java
+++ b/src/main/java/crud/http/HttpResource.java
@@ -20,12 +20,13 @@
import com.sun.jersey.api.client.AsyncWebResource;
import com.sun.jersey.api.client.ClientResponse;
-import crud.DeletableResource;
-import crud.ReadableResource;
-import crud.Resource;
-import crud.UpdatableResource;
-import crud.WritableResource;
+import crud.spi.DeletableSpec;
+import crud.spi.GettableSpec;
+import crud.spi.Resource;
+import crud.spi.SettableSpec;
+import crud.spi.UpdatableSpec;
import rx.Observable;
+import rx.Observer;
import rx.Subscriber;
import rx.subscriptions.Subscriptions;
@@ -35,10 +36,10 @@
* reading, writing, updating, and deleting.
*/
public class HttpResource
-implements ReadableResource,
- DeletableResource,
- WritableResource,
- UpdatableResource {
+implements GettableSpec,
+ DeletableSpec,
+ SettableSpec,
+ UpdatableSpec {
private final AsyncWebResource resource;
private final ClientRequest requestTemplate;
@@ -62,25 +63,49 @@ public Observable delete() {
}
/**
- * Create a new request, as from a copy of the default request, overlaying
+ * For each request emitted by the given {@link Observable}, create a new
+ * request, as from a copy of the default request, overlaying
* the properties of the given request. Send the resulting message as an
- * HTTP {@code PUT} request.
+ * HTTP {@code PUT} request. Emit all of the results.
*
* @param resourceState The request to {@code PUT}, expressed as an
* addition to the default request. If there is no addition, pass
* {@link ClientRequest#empty()}.
*/
@Override
- public Observable write(final ClientRequest resourceState) {
+ public Observable set(final Observable resourceState) {
final Observable.OnSubscribe subscribeAction = new Observable.OnSubscribe() {
@Override
public void call(final Subscriber super ClientResponse> subscriber) {
- final AsyncWebResource.Builder request = HttpResource.this.resource.getRequestBuilder();
- HttpResource.this.requestTemplate.updateResource(request);
- resourceState.updateResource(request);
- // Don't pass resourceState to put(): already in request
- final Future response = request.put(ResponseListener.adapt(subscriber));
- subscriber.add(Subscriptions.from(response));
+ final ResponseListener listener = ResponseListener.adapt(subscriber);
+ resourceState.subscribe(new Observer() {
+ @Override
+ public void onNext(final ClientRequest next) {
+ if (!subscriber.isUnsubscribed()) {
+ // FIXME: Fix correlation between request and response
+ final AsyncWebResource.Builder request = HttpResource.this.resource.getRequestBuilder();
+ HttpResource.this.requestTemplate.updateResource(request);
+ next.updateResource(request);
+ // Don't pass resourceState to put(): already in request
+ final Future response = request.put(listener);
+ subscriber.add(Subscriptions.from(response));
+ }
+ }
+
+ @Override
+ public void onError(final Throwable e) {
+ if (!subscriber.isUnsubscribed()) {
+ subscriber.onError(e);
+ }
+ }
+
+ @Override
+ public void onCompleted() {
+ if (!subscriber.isUnsubscribed()) {
+ subscriber.onCompleted();
+ }
+ }
+ });
}
};
final Observable obs = Observable.create(subscribeAction)
@@ -98,16 +123,39 @@ public void call(final Subscriber super ClientResponse> subscriber) {
* {@link ClientRequest#empty()}.
*/
@Override
- public Observable update(final ClientRequest update) {
+ public Observable update(final Observable update) {
final Observable.OnSubscribe subscribeAction = new Observable.OnSubscribe() {
@Override
public void call(final Subscriber super ClientResponse> subscriber) {
- final AsyncWebResource.Builder request = HttpResource.this.resource.getRequestBuilder();
- HttpResource.this.requestTemplate.updateResource(request);
- update.updateResource(request);
- // Don't pass resourceState to post(): already in request
- final Future response = request.post(ResponseListener.adapt(subscriber));
- subscriber.add(Subscriptions.from(response));
+ final ResponseListener listener = ResponseListener.adapt(subscriber);
+ update.subscribe(new Observer() {
+ @Override
+ public void onNext(final ClientRequest next) {
+ if (!subscriber.isUnsubscribed()) {
+ // FIXME: Fix correlation between request and response
+ final AsyncWebResource.Builder request = HttpResource.this.resource.getRequestBuilder();
+ HttpResource.this.requestTemplate.updateResource(request);
+ next.updateResource(request);
+ // Don't pass resourceState to put(): already in request
+ final Future response = request.post(listener);
+ subscriber.add(Subscriptions.from(response));
+ }
+ }
+
+ @Override
+ public void onError(final Throwable e) {
+ if (!subscriber.isUnsubscribed()) {
+ subscriber.onError(e);
+ }
+ }
+
+ @Override
+ public void onCompleted() {
+ if (!subscriber.isUnsubscribed()) {
+ subscriber.onCompleted();
+ }
+ }
+ });
}
};
final Observable obs = Observable.create(subscribeAction)
diff --git a/src/main/java/crud/http/HttpResourceProvider.java b/src/main/java/crud/http/HttpResourceProvider.java
index 3d9a10e..2223c17 100644
--- a/src/main/java/crud/http/HttpResourceProvider.java
+++ b/src/main/java/crud/http/HttpResourceProvider.java
@@ -21,30 +21,34 @@
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
-import crud.DeletableResourceProvider;
-import crud.ReadableResourceProvider;
-import crud.ResourceProvider;
-import crud.UpdatableResourceProvider;
-import crud.WritableResourceProvider;
+import crud.rsrc.Deletable;
+import crud.rsrc.Gettable;
+import crud.rsrc.Updatable;
+import crud.rsrc.Settable;
+import crud.spi.DeletableSetSpec;
+import crud.spi.GettableSetSpec;
+import crud.spi.ResourceSet;
+import crud.spi.UpdatableSetSpec;
+import crud.spi.SettableSetSpec;
/**
- * A {@link ResourceProvider} based on Jersey that provides
+ * A {@link ResourceSet} based on Jersey that provides
* {@link HttpResource}s at given {@link URI}s. These resources are capable of
* all four CRUD actions: reading, writing, updating, and deleting.
*/
public final class HttpResourceProvider
-implements ReadableResourceProvider,
- DeletableResourceProvider,
- WritableResourceProvider,
- UpdatableResourceProvider {
+implements GettableSetSpec,
+ DeletableSetSpec,
+ SettableSetSpec,
+ UpdatableSetSpec {
private final Client restClient;
private final ClientRequest requestTemplate;
/**
- * Create a new {@link ResourceProvider} backed by the given
+ * Create a new {@link ResourceSet} backed by the given
* {@link Client}.
*/
public static HttpResourceProvider forClient(final Client restClient) {
@@ -52,7 +56,7 @@ public static HttpResourceProvider forClient(final Client restClient) {
}
/**
- * Create a new {@link ResourceProvider} backed by the given
+ * Create a new {@link ResourceSet} backed by the given
* {@link Client}. Each request will include all of the elements of the
* given request. For example, if all communication should use JSON, you
* might pass the result of the following:
@@ -71,7 +75,26 @@ public static HttpResourceProvider forClientWithTemplate(
}
@Override
- public HttpResource get(final URI uri) {
+ public Gettable getter(final URI key) {
+ return Gettable.from(create(key));
+ }
+
+ @Override
+ public Deletable deleter(final URI key) {
+ return Deletable.from(create(key));
+ }
+
+ @Override
+ public Settable setter(final URI key) {
+ return Settable.from(create(key));
+ }
+
+ @Override
+ public Updatable updater(final URI key) {
+ return Updatable.from(create(key));
+ }
+
+ private HttpResource create(final URI uri) {
final AsyncWebResource resource = this.restClient.asyncResource(uri);
return new HttpResource(resource, this.requestTemplate);
}
diff --git a/src/main/java/crud/http/package-info.java b/src/main/java/crud/http/package-info.java
index d3f9341..540aba1 100644
--- a/src/main/java/crud/http/package-info.java
+++ b/src/main/java/crud/http/package-info.java
@@ -1,7 +1,6 @@
/**
* This package contains implementations of the interfaces in the package
- * {@link crud} in terms of the Jersey HTTP
- * library.
+ * {@link crud.spi} in terms of the Jersey HTTP library.
* Resources are asynchronous, and use the
* {@link java.util.concurrent.ExecutorService} from the
* {@link com.sun.jersey.api.client.Client} itself.
diff --git a/src/main/java/crud/http/util/FailedResponseOperator.java b/src/main/java/crud/http/util/FailedResponseOperator.java
index 8859999..74a6df7 100644
--- a/src/main/java/crud/http/util/FailedResponseOperator.java
+++ b/src/main/java/crud/http/util/FailedResponseOperator.java
@@ -23,8 +23,8 @@
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.UniformInterfaceException;
-import crud.fluent.FluentReadableResource;
-import crud.fluent.FluentReadableResourceProvider;
+import crud.rsrc.Gettable;
+import crud.rsrc.GettableSet;
import rx.Observable;
import rx.Observer;
import rx.Subscriber;
@@ -43,11 +43,13 @@
* that will be detected and retried are those that result in exceptions from
* Jersey.
*
+ * TODO: Build this into {@link crud.http.HttpResource} in a better way.
+ *
* @see UniformInterfaceException#getResponse()
- * @see FluentReadableResource#lift(rx.Observable.Operator)
- * @see FluentReadableResourceProvider#lift(rx.Observable.Operator)
- * @see FluentReadableResource#retry(int)
- * @see FluentReadableResourceProvider#retry(int)
+ * @see Gettable#lift(rx.Observable.Operator)
+ * @see GettableSet#lift(rx.Observable.Operator)
+ * @see Gettable#retry(int)
+ * @see GettableSet#retry(int)
*/
public final class FailedResponseOperator
implements Observable.Operator {
diff --git a/src/test/java/crud/http/HttpDeletableResourceTest.java b/src/test/java/crud/http/HttpDeletableResourceTest.java
index 9d978b7..7dd3dbe 100644
--- a/src/test/java/crud/http/HttpDeletableResourceTest.java
+++ b/src/test/java/crud/http/HttpDeletableResourceTest.java
@@ -40,11 +40,11 @@
import com.sun.jersey.api.client.async.ITypeListener;
import com.sun.jersey.core.header.InBoundHeaders;
-import crud.DeletableResourceTest;
+import crud.spi.DeletableSpecTest;
import rx.Observer;
-public class HttpDeletableResourceTest extends DeletableResourceTest {
+public class HttpDeletableResourceTest extends DeletableSpecTest {
private final AsyncWebResource mockResource = mock(AsyncWebResource.class);
private final AsyncWebResource.Builder mockResourceBuilder = mock(AsyncWebResource.Builder.class);
diff --git a/src/test/java/crud/http/HttpReadableResourceTest.java b/src/test/java/crud/http/HttpReadableResourceTest.java
index ab9a0ac..2c3cd84 100644
--- a/src/test/java/crud/http/HttpReadableResourceTest.java
+++ b/src/test/java/crud/http/HttpReadableResourceTest.java
@@ -40,11 +40,11 @@
import com.sun.jersey.api.client.async.ITypeListener;
import com.sun.jersey.core.header.InBoundHeaders;
-import crud.ReadableResourceTest;
+import crud.spi.GettableSpecTest;
import rx.Observer;
-public class HttpReadableResourceTest extends ReadableResourceTest {
+public class HttpReadableResourceTest extends GettableSpecTest {
private final AsyncWebResource mockResource = mock(AsyncWebResource.class);
private final AsyncWebResource.Builder mockResourceBuilder = mock(AsyncWebResource.Builder.class);
diff --git a/src/test/java/crud/http/HttpUpdatableResourceTest.java b/src/test/java/crud/http/HttpUpdatableResourceTest.java
index 04fdb7c..a8b70f9 100644
--- a/src/test/java/crud/http/HttpUpdatableResourceTest.java
+++ b/src/test/java/crud/http/HttpUpdatableResourceTest.java
@@ -40,11 +40,12 @@
import com.sun.jersey.api.client.async.ITypeListener;
import com.sun.jersey.core.header.InBoundHeaders;
-import crud.UpdatableResourceTest;
+import crud.spi.UpdatableSpecTest;
+import rx.Observable;
import rx.Observer;
-public class HttpUpdatableResourceTest extends UpdatableResourceTest {
+public class HttpUpdatableResourceTest extends UpdatableSpecTest {
private final AsyncWebResource mockResource = mock(AsyncWebResource.class);
private final AsyncWebResource.Builder mockResourceBuilder = mock(AsyncWebResource.Builder.class);
@@ -68,7 +69,7 @@ public void setup() {
public void subscribeCallsMocks() {
// given:
final HttpResource resource = createDefaultResource();
- final ClientRequest update = createDefaultUpdate();
+ final Observable update = createDefaultUpdate();
// when:
final ClientResponse response = resource.update(update).toBlocking().single();
@@ -81,8 +82,8 @@ public void subscribeCallsMocks() {
@Test
public void clientRequestsCopied() {
// given:
- final ClientRequest mockRequestTemplate = createDefaultUpdate();
- final ClientRequest mockRequest = createDefaultUpdate();
+ final ClientRequest mockRequestTemplate = createDefaultUpdate().toBlocking().single();
+ final Observable mockRequest = createDefaultUpdate();
final HttpResource resource = new HttpResource(this.mockResource, mockRequestTemplate);
// when:
@@ -90,7 +91,7 @@ public void clientRequestsCopied() {
// then:
verify(mockRequestTemplate).updateResource(this.mockResourceBuilder);
- verify(mockRequest).updateResource(this.mockResourceBuilder);
+ verify(mockRequest.toBlocking().single()).updateResource(this.mockResourceBuilder);
}
@Test
@@ -99,7 +100,7 @@ public void httpPostErrorCallsOnError() throws InterruptedException {
// given:
final RuntimeException expectedException = new IllegalStateException("mock failure");
final HttpResource resource = createDefaultResource();
- final ClientRequest update = createDefaultUpdate();
+ final Observable update = createDefaultUpdate();
final AtomicBoolean failed = new AtomicBoolean();
@@ -134,7 +135,7 @@ public void futureGetErrorCallsOnError() throws InterruptedException {
// given:
final RuntimeException expectedException = new IllegalStateException("mock exception");
final HttpResource resource = createDefaultResource();
- final ClientRequest update = createDefaultUpdate();
+ final Observable update = createDefaultUpdate();
final String success = "success";
final AtomicReference successOrFail = new AtomicReference<>("never called");
@@ -174,7 +175,7 @@ public void observerOnNextErrorClosesResponse() throws InterruptedException {
// given:
final HttpResource resource = createDefaultResource();
final ClientResponse mockResponse = mock(ClientResponse.class);
- final ClientRequest update = createDefaultUpdate();
+ final Observable update = createDefaultUpdate();
// when:
whenResourceUpdateThenReturn(mockResponse);
@@ -189,7 +190,7 @@ public void observerOnCompletedErrorClosesResponse() throws InterruptedException
// given:
final HttpResource resource = createDefaultResource();
final ClientResponse mockResponse = mock(ClientResponse.class);
- final ClientRequest update = createDefaultUpdate();
+ final Observable update = createDefaultUpdate();
// when:
whenResourceUpdateThenReturn(mockResponse);
@@ -204,7 +205,7 @@ public void observerOnNextAndOnErrorErrorsClosesResponse() throws InterruptedExc
// given:
final HttpResource resource = createDefaultResource();
final ClientResponse mockResponse = mock(ClientResponse.class);
- final ClientRequest update = createDefaultUpdate();
+ final Observable update = createDefaultUpdate();
// when:
whenResourceUpdateThenReturn(mockResponse);
@@ -219,7 +220,7 @@ public void observerOnCompletedAndOnErrorErrorsClosesResponse() throws Interrupt
// given:
final HttpResource resource = createDefaultResource();
final ClientResponse mockResponse = mock(ClientResponse.class);
- final ClientRequest update = createDefaultUpdate();
+ final Observable update = createDefaultUpdate();
// when:
whenResourceUpdateThenReturn(mockResponse);
@@ -235,8 +236,8 @@ protected HttpResource createDefaultResource() {
}
@Override
- protected ClientRequest createDefaultUpdate() {
- return mock(ClientRequest.class);
+ protected Observable createDefaultUpdate() {
+ return Observable.just(mock(ClientRequest.class));
}
private static ClientResponse createResponse() {
diff --git a/src/test/java/crud/http/HttpWritableResourceTest.java b/src/test/java/crud/http/HttpWritableResourceTest.java
index f6a0486..9a4fb36 100644
--- a/src/test/java/crud/http/HttpWritableResourceTest.java
+++ b/src/test/java/crud/http/HttpWritableResourceTest.java
@@ -41,11 +41,12 @@
import com.sun.jersey.api.client.async.ITypeListener;
import com.sun.jersey.core.header.InBoundHeaders;
-import crud.WritableResourceTest;
+import crud.spi.SettableSpecTest;
+import rx.Observable;
import rx.Observer;
-public class HttpWritableResourceTest extends WritableResourceTest {
+public class HttpWritableResourceTest extends SettableSpecTest {
private final AsyncWebResource mockResource = mock(AsyncWebResource.class);
private final AsyncWebResource.Builder mockResourceBuilder = mock(AsyncWebResource.Builder.class);
@@ -69,10 +70,10 @@ public void setup() {
public void subscribeCallsMocks() {
// given:
final HttpResource resource = createDefaultResource();
- final ClientRequest newValue = createDefaultResourceState();
+ final Observable newValue = createDefaultResourceState();
// when:
- final ClientResponse response = resource.write(newValue).toBlocking().single();
+ final ClientResponse response = resource.set(newValue).toBlocking().single();
// then:
assertSame(this.expectedResponse, response);
@@ -82,16 +83,16 @@ public void subscribeCallsMocks() {
@Test
public void clientRequestsCopied() {
// given:
- final ClientRequest mockRequestTemplate = createDefaultResourceState();
- final ClientRequest mockRequest = createDefaultResourceState();
+ final ClientRequest mockRequestTemplate = createDefaultResourceState().toBlocking().single();
+ final Observable mockRequest = createDefaultResourceState();
final HttpResource resource = new HttpResource(this.mockResource, mockRequestTemplate);
// when:
- resource.write(mockRequest).subscribe();
+ resource.set(mockRequest).subscribe();
// then:
verify(mockRequestTemplate).updateResource(this.mockResourceBuilder);
- verify(mockRequest).updateResource(this.mockResourceBuilder);
+ verify(mockRequest.toBlocking().single()).updateResource(this.mockResourceBuilder);
}
@Test
@@ -100,7 +101,7 @@ public void httpPutErrorCallsOnError() throws InterruptedException {
// given:
final RuntimeException expectedException = new IllegalStateException("mock failure");
final HttpResource resource = createDefaultResource();
- final ClientRequest newState = createDefaultResourceState();
+ final Observable newState = createDefaultResourceState();
final AtomicBoolean failed = new AtomicBoolean();
@@ -108,7 +109,7 @@ public void httpPutErrorCallsOnError() throws InterruptedException {
// when:
when(this.mockResourceBuilder.put(any(ITypeListener.class))).thenThrow(expectedException);
- subscribeAndWait(resource.write(newState), 1, new Observer() {
+ subscribeAndWait(resource.set(newState), 1, new Observer() {
@Override
public void onNext(final ClientResponse response) {
failed.set(true);
@@ -135,7 +136,7 @@ public void futureGetErrorCallsOnError() throws InterruptedException {
// given:
final RuntimeException expectedException = new IllegalStateException("mock exception");
final HttpResource resource = createDefaultResource();
- final ClientRequest newState = createDefaultResourceState();
+ final Observable newState = createDefaultResourceState();
final String success = "success";
final AtomicReference successOrFail = new AtomicReference<>("never called");
@@ -145,7 +146,7 @@ public void futureGetErrorCallsOnError() throws InterruptedException {
// when:
when(this.mockResourceBuilder.put(any(ITypeListener.class)))
.thenAnswer(new ListenerInvokingAnswer(expectedException));
- subscribeAndWait(resource.write(newState), 1, new Observer() {
+ subscribeAndWait(resource.set(newState), 1, new Observer() {
@Override
public void onNext(final ClientResponse response) {
successOrFail.set("onNext called");
@@ -175,11 +176,11 @@ public void observerOnNextErrorClosesResponse() throws InterruptedException {
// given:
final HttpResource resource = createDefaultResource();
final ClientResponse mockResponse = mock(ClientResponse.class);
- final ClientRequest newState = createDefaultResourceState();
+ final Observable newState = createDefaultResourceState();
// when:
whenResourceWriteThenReturn(mockResponse);
- subscribeWithOnNextFailure(resource.write(newState));
+ subscribeWithOnNextFailure(resource.set(newState));
// then:
verify(mockResponse).close();
@@ -190,11 +191,11 @@ public void observerOnCompletedErrorClosesResponse() throws InterruptedException
// given:
final HttpResource resource = createDefaultResource();
final ClientResponse mockResponse = mock(ClientResponse.class);
- final ClientRequest newState = createDefaultResourceState();
+ final Observable newState = createDefaultResourceState();
// when:
whenResourceWriteThenReturn(mockResponse);
- subscribeWithOnCompletedFailure(resource.write(newState));
+ subscribeWithOnCompletedFailure(resource.set(newState));
// then:
verify(mockResponse).close();
@@ -205,11 +206,11 @@ public void observerOnNextAndOnErrorErrorsClosesResponse() throws InterruptedExc
// given:
final HttpResource resource = createDefaultResource();
final ClientResponse mockResponse = mock(ClientResponse.class);
- final ClientRequest newState = createDefaultResourceState();
+ final Observable newState = createDefaultResourceState();
// when:
whenResourceWriteThenReturn(mockResponse);
- subscribeWithOnNextAndOnErrorFailures(resource.write(newState));
+ subscribeWithOnNextAndOnErrorFailures(resource.set(newState));
// then:
verify(mockResponse).close();
@@ -220,11 +221,11 @@ public void observerOnCompletedAndOnErrorErrorsClosesResponse() throws Interrupt
// given:
final HttpResource resource = createDefaultResource();
final ClientResponse mockResponse = mock(ClientResponse.class);
- final ClientRequest newState = createDefaultResourceState();
+ final Observable newState = createDefaultResourceState();
// when:
whenResourceWriteThenReturn(mockResponse);
- subscribeWithOnCompletedAndOnErrorFailures(resource.write(newState));
+ subscribeWithOnCompletedAndOnErrorFailures(resource.set(newState));
// then:
verify(mockResponse).close();
@@ -236,8 +237,8 @@ protected HttpResource createDefaultResource() {
}
@Override
- protected ClientRequest createDefaultResourceState() {
- return mock(ClientRequest.class);
+ protected Observable createDefaultResourceState() {
+ return Observable.just(mock(ClientRequest.class));
}
private static ClientResponse createResponse() {
diff --git a/src/test/java/crud/http/example/AssetApplication.java b/src/test/java/crud/http/example/AssetApplication.java
index 8b3e621..05d31a7 100644
--- a/src/test/java/crud/http/example/AssetApplication.java
+++ b/src/test/java/crud/http/example/AssetApplication.java
@@ -16,6 +16,9 @@
import java.util.UUID;
+import crud.rsrc.Gettable;
+import crud.rsrc.Settable;
+import rx.Observable;
import rx.Observer;
@@ -24,21 +27,22 @@
*/
class AssetApplication {
- private final AssetResourceProvider assetProvider;
+ private final AssetSet assetProvider;
- public AssetApplication(final AssetResourceProvider isThisAWebServiceIDontCare) {
+ public AssetApplication(final AssetSet isThisAWebServiceIDontCare) {
this.assetProvider = isThisAWebServiceIDontCare;
}
public void processAsset(final UUID assetId) {
- final AssetResource resource = this.assetProvider.get(assetId);
- resource.get().subscribe(new Observer() {
+ final Gettable reader = this.assetProvider.getter(assetId);
+ final Settable writer = this.assetProvider.setter(assetId);
+ reader.get().subscribe(new Observer() {
@Override
public void onNext(final Asset asset) {
System.out.println("Got the asset " + assetId);
- final Asset betterAsset = new Asset(assetId, 42L);
- resource.write(betterAsset).subscribe();
+ final Observable betterAsset = Observable.just(new Asset(assetId, 42L));
+ writer.set(betterAsset).subscribe();
}
@Override
diff --git a/src/test/java/crud/http/example/AssetResource.java b/src/test/java/crud/http/example/AssetResource.java
index cc9382b..f3c3800 100644
--- a/src/test/java/crud/http/example/AssetResource.java
+++ b/src/test/java/crud/http/example/AssetResource.java
@@ -14,9 +14,9 @@
*/
package crud.http.example;
-import crud.ReadableResource;
-import crud.Resource;
-import crud.WritableResource;
+import crud.spi.GettableSpec;
+import crud.spi.Resource;
+import crud.spi.SettableSpec;
/**
@@ -24,6 +24,6 @@
* particular {@link Asset}. Assets do not support partial updates or
* deletion.
*/
-interface AssetResource extends ReadableResource, WritableResource {
+interface AssetResource extends GettableSpec, SettableSpec {
// empty
}
diff --git a/src/test/java/crud/http/example/AssetResourceProvider.java b/src/test/java/crud/http/example/AssetSet.java
similarity index 52%
rename from src/test/java/crud/http/example/AssetResourceProvider.java
rename to src/test/java/crud/http/example/AssetSet.java
index 12109e4..024fb2f 100644
--- a/src/test/java/crud/http/example/AssetResourceProvider.java
+++ b/src/test/java/crud/http/example/AssetSet.java
@@ -16,32 +16,34 @@
import java.util.UUID;
-import crud.ReadableResource;
-import crud.ReadableResourceProvider;
-import crud.Resource;
-import crud.ResourceProvider;
-import crud.WritableResource;
-import crud.WritableResourceProvider;
-import crud.fluent.FluentReadableResourceProvider;
-import crud.fluent.FluentWritableResourceProvider;
+import crud.rsrc.Gettable;
+import crud.rsrc.GettableSet;
+import crud.rsrc.Settable;
+import crud.rsrc.SettableSet;
+import crud.spi.GettableSetSpec;
+import crud.spi.GettableSpec;
+import crud.spi.Resource;
+import crud.spi.ResourceSet;
+import crud.spi.SettableSetSpec;
+import crud.spi.SettableSpec;
import rx.Observable;
import rx.functions.Func1;
/**
- * A {@link ResourceProvider} for retrieving readable and writable
+ * A {@link ResourceSet} for retrieving readable and writable
* {@link Asset}s, encapsulated by {@link AssetResource}.
*/
-class AssetResourceProvider
-implements ReadableResourceProvider, WritableResourceProvider {
+class AssetSet
+implements GettableSetSpec, SettableSetSpec {
- private final ReadableResourceProvider readDelegate;
- private final WritableResourceProvider writeDelegate;
+ private final GettableSetSpec readDelegate;
+ private final SettableSetSpec writeDelegate;
/**
- * Wrap a pair of {@link ResourceProvider}s with a new
- * AssetResourceProvider. These input providers might be, for example, a
+ * Wrap a pair of {@link ResourceSet}s with a new
+ * AssetSet. These input providers might be, for example, a
* {@link crud.http.HttpResourceProvider}, if the Assets are to
* be backed by a web service. However, any backing providers will do,
* provided there is some way to transform their inputs and outputs
@@ -52,23 +54,48 @@ class AssetResourceProvider
* @param The type of the values written by the write delegate.
* @param The type of the response from the write delegate.
*/
- public static AssetResourceProvider create(
- final ReadableResourceProvider readDelegate,
- final WritableResourceProvider writeDelegate,
+ public static AssetSet create(
+ final GettableSetSpec readDelegate,
+ final SettableSetSpec writeDelegate,
final Func1 super UUID, ? extends K> keyAdapter,
final Func1 super RV, ? extends Asset> assetReadMapper,
final Func1 super Asset, ? extends WV> assetWriteMapper,
final Func1 super R, ? extends Boolean> responseMapper) {
- final FluentReadableResourceProvider reader
- = FluentReadableResourceProvider.from(readDelegate)
+ final GettableSet reader
+ = GettableSet.from(readDelegate)
.adaptKey(keyAdapter)
- .mapValue(assetReadMapper);
- final FluentWritableResourceProvider writer
- = FluentWritableResourceProvider.from(writeDelegate)
+ .mapValue(new Func1, Observable>() {
+ @Override
+ public Observable call(final Observable value) {
+ return value.map(assetReadMapper);
+ }
+ });
+ final SettableSet writer
+ = SettableSet.from(writeDelegate)
.adaptKey(keyAdapter)
- .adaptNewValue(assetWriteMapper)
- .mapResponse(responseMapper);
- return new AssetResourceProvider(reader, writer);
+ .adaptNewValue(new Func1, Observable>() {
+ @Override
+ public Observable call(final Observable asset) {
+ return asset.map(assetWriteMapper);
+ }
+ })
+ .mapResponse(new Func1, Observable>() {
+ @Override
+ public Observable call(final Observable t1) {
+ return t1.map(responseMapper);
+ }
+ });
+ return new AssetSet(reader, writer);
+ }
+
+ @Override
+ public Settable setter(final UUID key) {
+ return Settable.from(create(key));
+ }
+
+ @Override
+ public Gettable getter(final UUID key) {
+ return Gettable.from(create(key));
}
/**
@@ -76,28 +103,27 @@ public static AssetResourceProvider create(
* given ID. The state of that Asset may be read or written using
* that Resource.
*/
- @Override
- public AssetResource get(final UUID assetId) {
- final ReadableResource readRsrc = this.readDelegate.get(assetId);
- final WritableResource writeRsrc = this.writeDelegate.get(assetId);
+ private AssetResource create(final UUID assetId) {
+ final GettableSpec readRsrc = this.readDelegate.getter(assetId);
+ final SettableSpec writeRsrc = this.writeDelegate.setter(assetId);
return new AssetResourceImpl(writeRsrc, readRsrc);
}
- private AssetResourceProvider(
- final ReadableResourceProvider readDelegate,
- final WritableResourceProvider writeDelegate) {
+ private AssetSet(
+ final GettableSetSpec readDelegate,
+ final SettableSetSpec writeDelegate) {
this.readDelegate = readDelegate;
this.writeDelegate = writeDelegate;
}
private static final class AssetResourceImpl implements AssetResource {
- private final WritableResource writeRsrc;
- private final ReadableResource readRsrc;
+ private final SettableSpec writeRsrc;
+ private final GettableSpec readRsrc;
private AssetResourceImpl(
- final WritableResource writeRsrc,
- final ReadableResource readRsrc) {
+ final SettableSpec writeRsrc,
+ final GettableSpec readRsrc) {
this.writeRsrc = writeRsrc;
this.readRsrc = readRsrc;
}
@@ -108,8 +134,8 @@ public Observable get() {
}
@Override
- public Observable write(final Asset newValue) {
- return this.writeRsrc.write(newValue);
+ public Observable set(final Observable newValue) {
+ return this.writeRsrc.set(newValue);
}
// Every concrete Resource class should override equals() and hashCode().
diff --git a/src/test/java/crud/http/example/ExampleApplicationContext.java b/src/test/java/crud/http/example/ExampleApplicationContext.java
index ba9b4ac..6ab921c 100644
--- a/src/test/java/crud/http/example/ExampleApplicationContext.java
+++ b/src/test/java/crud/http/example/ExampleApplicationContext.java
@@ -23,12 +23,13 @@
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
-import crud.ResourceProvider;
-import crud.fluent.FluentReadableResourceProvider;
-import crud.fluent.FluentWritableResourceProvider;
import crud.http.ClientRequest;
import crud.http.HttpResourceProvider;
import crud.http.util.FailedResponseOperator;
+import crud.rsrc.GettableSet;
+import crud.rsrc.SettableSet;
+import crud.spi.ResourceSet;
+import rx.Observable;
import rx.functions.Func1;
@@ -114,8 +115,15 @@ public Boolean call(final ClientResponse input) {
}
};
+ private final Func1, Observable> retryServerErrors = new Func1, Observable>() {
+ @Override
+ public Observable call(final Observable t1) {
+ return t1.lift(FailedResponseOperator.serverErrors()).retry(3);
+ }
+ };
+
/**
- * Assemble the {@link ResourceProvider} for {@link Asset}s by indicating:
+ * Assemble the {@link ResourceSet} for {@link Asset}s by indicating:
*
* - how to read them (i.e. from a web service),
* - how to write them (i.e. to a web service),
@@ -123,11 +131,11 @@ public Boolean call(final ClientResponse input) {
* providers and our application-specific language of "assets".
*
*/
- public final AssetResourceProvider assetProvider = AssetResourceProvider.create(
+ public final AssetSet assetProvider = AssetSet.create(
// Retry all server errors on GET up to 3 times:
- FluentReadableResourceProvider.from(restResource).lift(FailedResponseOperator.serverErrors()).retry(3),
+ GettableSet.from(restResource).mapValue(retryServerErrors),
// Retry all server errors on PUT up to 3 times:
- FluentWritableResourceProvider.from(restResource).lift(FailedResponseOperator.serverErrors()).retry(3),
+ SettableSet.from(restResource).mapResponse(retryServerErrors),
urlBuilder,
assetDecoder,
assetEncoder,