Skip to content

Commit a9b80c9

Browse files
authored
Re-implement V3 Service Bindings (#1158)
1 parent 72b6b6b commit a9b80c9

25 files changed

+883
-182
lines changed

cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/AbstractClientV3Operations.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ protected final Mono<String> delete(Object requestPayload, Function<UriComponent
6262
.send(requestPayload)
6363
.response()
6464
.get())
65-
.map(AbstractClientV3Operations::extractJobId);
65+
.flatMap(response -> Mono.justOrEmpty(extractJobId(response)));
6666
}
6767

6868
protected final <T> Mono<HttpClientResponseWithParsedBody<T>> deleteWithResponse(Object requestPayload, Class<T> responseType,
@@ -141,7 +141,7 @@ protected <T> Mono<T> post(Object requestPayload, Class<T> responseType, Functio
141141
}
142142

143143
protected final <T> Mono<HttpClientResponseWithParsedBody<T>> postWithResponse(Object requestPayload, Class<T> responseType,
144-
Function<UriComponentsBuilder, UriComponentsBuilder> uriTransformer) {
144+
Function<UriComponentsBuilder, UriComponentsBuilder> uriTransformer) {
145145
return createOperator()
146146
.flatMap(operator -> operator.post()
147147
.uri(queryTransformer(requestPayload).andThen(uriTransformer))
@@ -157,7 +157,7 @@ protected final Mono<String> post(Object requestPayload, Function<UriComponentsB
157157
.send(requestPayload)
158158
.response()
159159
.get())
160-
.map(AbstractClientV3Operations::extractJobId);
160+
.flatMap(response -> Mono.justOrEmpty(extractJobId(response)));
161161
}
162162

163163
protected final <T> Mono<T> put(Object requestPayload, Class<T> responseType, Function<UriComponentsBuilder, UriComponentsBuilder> uriTransformer) {

cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/servicebindings/ReactorServiceBindingsV3.java

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,25 @@
1919
import org.cloudfoundry.client.v3.servicebindings.CreateServiceBindingRequest;
2020
import org.cloudfoundry.client.v3.servicebindings.CreateServiceBindingResponse;
2121
import org.cloudfoundry.client.v3.servicebindings.DeleteServiceBindingRequest;
22+
import org.cloudfoundry.client.v3.servicebindings.GetServiceBindingDetailsRequest;
23+
import org.cloudfoundry.client.v3.servicebindings.GetServiceBindingDetailsResponse;
24+
import org.cloudfoundry.client.v3.servicebindings.GetServiceBindingParametersRequest;
25+
import org.cloudfoundry.client.v3.servicebindings.GetServiceBindingParametersResponse;
2226
import org.cloudfoundry.client.v3.servicebindings.GetServiceBindingRequest;
2327
import org.cloudfoundry.client.v3.servicebindings.GetServiceBindingResponse;
2428
import org.cloudfoundry.client.v3.servicebindings.ListServiceBindingsRequest;
2529
import org.cloudfoundry.client.v3.servicebindings.ListServiceBindingsResponse;
30+
import org.cloudfoundry.client.v3.servicebindings.ServiceBindingResource;
2631
import org.cloudfoundry.client.v3.servicebindings.ServiceBindingsV3;
32+
import org.cloudfoundry.client.v3.servicebindings.UpdateServiceBindingRequest;
33+
import org.cloudfoundry.client.v3.servicebindings.UpdateServiceBindingResponse;
2734
import org.cloudfoundry.reactor.ConnectionContext;
2835
import org.cloudfoundry.reactor.TokenProvider;
2936
import org.cloudfoundry.reactor.client.v3.AbstractClientV3Operations;
3037
import reactor.core.publisher.Mono;
3138

3239
import java.util.Map;
40+
import java.util.Optional;
3341

3442
/**
3543
* The Reactor-based implementation of {@link ServiceBindingsV3}
@@ -50,25 +58,47 @@ public ReactorServiceBindingsV3(ConnectionContext connectionContext, Mono<String
5058

5159
@Override
5260
public Mono<CreateServiceBindingResponse> create(CreateServiceBindingRequest request) {
53-
return post(request, CreateServiceBindingResponse.class, builder -> builder.pathSegment("service_bindings"))
61+
return postWithResponse(request, ServiceBindingResource.class, builder -> builder.pathSegment("service_credential_bindings"))
62+
.map(responseTuple -> CreateServiceBindingResponse.builder()
63+
.serviceBinding(responseTuple.getBody())
64+
.jobId(Optional.ofNullable(extractJobId(responseTuple.getResponse())))
65+
.build())
5466
.checkpoint();
5567
}
5668

5769
@Override
58-
public Mono<Void> delete(DeleteServiceBindingRequest request) {
59-
return delete(request, Void.class, builder -> builder.pathSegment("service_bindings", request.getServiceBindingId()))
70+
public Mono<String> delete(DeleteServiceBindingRequest request) {
71+
return delete(request, builder -> builder.pathSegment("service_credential_bindings", request.getServiceBindingId()))
6072
.checkpoint();
6173
}
6274

6375
@Override
6476
public Mono<GetServiceBindingResponse> get(GetServiceBindingRequest request) {
65-
return get(request, GetServiceBindingResponse.class, builder -> builder.pathSegment("service_bindings", request.getServiceBindingId()))
77+
return get(request, GetServiceBindingResponse.class, builder -> builder.pathSegment("service_credential_bindings", request.getServiceBindingId()))
78+
.checkpoint();
79+
}
80+
81+
@Override
82+
public Mono<GetServiceBindingDetailsResponse> getDetails(GetServiceBindingDetailsRequest request) {
83+
return get(request, GetServiceBindingDetailsResponse.class, builder -> builder.pathSegment("service_credential_bindings", request.getServiceBindingId(), "details"))
84+
.checkpoint();
85+
}
86+
87+
@Override
88+
public Mono<GetServiceBindingParametersResponse> getParameters(GetServiceBindingParametersRequest request) {
89+
return get(request, GetServiceBindingParametersResponse.class, builder -> builder.pathSegment("service_credential_bindings", request.getServiceBindingId(), "parameters"))
6690
.checkpoint();
6791
}
6892

6993
@Override
7094
public Mono<ListServiceBindingsResponse> list(ListServiceBindingsRequest request) {
71-
return get(request, ListServiceBindingsResponse.class, builder -> builder.pathSegment("service_bindings"))
95+
return get(request, ListServiceBindingsResponse.class, builder -> builder.pathSegment("service_credential_bindings"))
96+
.checkpoint();
97+
}
98+
99+
@Override
100+
public Mono<UpdateServiceBindingResponse> update(UpdateServiceBindingRequest request) {
101+
return patch(request, UpdateServiceBindingResponse.class, builder -> builder.pathSegment("service_credential_bindings", request.getServiceBindingId()))
72102
.checkpoint();
73103
}
74104

cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/servicebindings/ReactorServiceBindingsV3Test.java

Lines changed: 59 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,14 @@
1919
import org.cloudfoundry.client.v3.Link;
2020
import org.cloudfoundry.client.v3.Pagination;
2121
import org.cloudfoundry.client.v3.Relationship;
22-
import org.cloudfoundry.client.v3.servicebindings.CreateServiceBindingData;
22+
import org.cloudfoundry.client.v3.ToOneRelationship;
2323
import org.cloudfoundry.client.v3.servicebindings.CreateServiceBindingRequest;
2424
import org.cloudfoundry.client.v3.servicebindings.CreateServiceBindingResponse;
2525
import org.cloudfoundry.client.v3.servicebindings.DeleteServiceBindingRequest;
2626
import org.cloudfoundry.client.v3.servicebindings.GetServiceBindingRequest;
2727
import org.cloudfoundry.client.v3.servicebindings.GetServiceBindingResponse;
2828
import org.cloudfoundry.client.v3.servicebindings.ListServiceBindingsRequest;
2929
import org.cloudfoundry.client.v3.servicebindings.ListServiceBindingsResponse;
30-
import org.cloudfoundry.client.v3.servicebindings.ServiceBindingData;
3130
import org.cloudfoundry.client.v3.servicebindings.ServiceBindingRelationships;
3231
import org.cloudfoundry.client.v3.servicebindings.ServiceBindingResource;
3332
import org.cloudfoundry.client.v3.servicebindings.ServiceBindingType;
@@ -44,7 +43,7 @@
4443
import static io.netty.handler.codec.http.HttpMethod.DELETE;
4544
import static io.netty.handler.codec.http.HttpMethod.GET;
4645
import static io.netty.handler.codec.http.HttpMethod.POST;
47-
import static io.netty.handler.codec.http.HttpResponseStatus.CREATED;
46+
import static io.netty.handler.codec.http.HttpResponseStatus.ACCEPTED;
4847
import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT;
4948
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
5049

@@ -56,48 +55,34 @@ public final class ReactorServiceBindingsV3Test extends AbstractClientApiTest {
5655
public void create() {
5756
mockRequest(InteractionContext.builder()
5857
.request(TestRequest.builder()
59-
.method(POST).path("/service_bindings")
58+
.method(POST).path("/service_credential_bindings")
6059
.payload("fixtures/client/v3/servicebindings/POST_request.json")
6160
.build())
6261
.response(TestResponse.builder()
63-
.status(CREATED)
64-
.payload("fixtures/client/v3/servicebindings/POST_response.json")
62+
.status(ACCEPTED)
63+
.header("Location", "https://api.example.org/v3/jobs/af5c57f6-8769-41fa-a499-2c84ed896788")
6564
.build())
6665
.build());
6766

6867
this.serviceBindings
6968
.create(CreateServiceBindingRequest.builder()
70-
.data(CreateServiceBindingData.builder()
71-
.parameter("some_object_id", "for_the_service_broker")
72-
.build())
7369
.relationships(ServiceBindingRelationships.builder()
74-
.application(Relationship.builder()
75-
.id("74f7c078-0934-470f-9883-4fddss5b8f13")
70+
.application(ToOneRelationship.builder()
71+
.data(Relationship.builder()
72+
.id("74f7c078-0934-470f-9883-4fddss5b8f13")
73+
.build())
7674
.build())
77-
.serviceInstance(Relationship.builder()
78-
.id("8bfe4c1b-9e18-45b1-83be-124163f31f9e")
75+
.serviceInstance(ToOneRelationship.builder()
76+
.data(Relationship.builder()
77+
.id("8bfe4c1b-9e18-45b1-83be-124163f31f9e")
78+
.build())
7979
.build())
8080
.build())
8181
.type(ServiceBindingType.APPLICATION)
8282
.build())
8383
.as(StepVerifier::create)
8484
.expectNext(CreateServiceBindingResponse.builder()
85-
.id("dde5ad2a-d8f4-44dc-a56f-0452d744f1c3")
86-
.type("app")
87-
.data(ServiceBindingData.builder()
88-
.credential("super-secret", "password")
89-
.syslogDrainUrl("syslog://drain.url.com")
90-
.build())
91-
.createdAt("2015-11-13T17:02:56Z")
92-
.link("self", Link.builder()
93-
.href("/v3/service_bindings/dde5ad2a-d8f4-44dc-a56f-0452d744f1c3")
94-
.build())
95-
.link("service_instance", Link.builder()
96-
.href("/v3/service_instances/8bfe4c1b-9e18-45b1-83be-124163f31f9e")
97-
.build())
98-
.link("app", Link.builder()
99-
.href("/v3/apps/74f7c078-0934-470f-9883-4fddss5b8f13")
100-
.build())
85+
.jobId("af5c57f6-8769-41fa-a499-2c84ed896788")
10186
.build())
10287
.expectComplete()
10388
.verify(Duration.ofSeconds(5));
@@ -107,7 +92,7 @@ public void create() {
10792
public void delete() {
10893
mockRequest(InteractionContext.builder()
10994
.request(TestRequest.builder()
110-
.method(DELETE).path("/service_bindings/test-service-binding-id")
95+
.method(DELETE).path("/service_credential_bindings/test-service-binding-id")
11196
.build())
11297
.response(TestResponse.builder()
11398
.status(NO_CONTENT)
@@ -127,7 +112,7 @@ public void delete() {
127112
public void get() {
128113
mockRequest(InteractionContext.builder()
129114
.request(TestRequest.builder()
130-
.method(GET).path("/service_bindings/test-service-binding-id")
115+
.method(GET).path("/service_credential_bindings/test-service-binding-id")
131116
.build())
132117
.response(TestResponse.builder()
133118
.status(OK)
@@ -142,14 +127,22 @@ public void get() {
142127
.as(StepVerifier::create)
143128
.expectNext(GetServiceBindingResponse.builder()
144129
.id("dde5ad2a-d8f4-44dc-a56f-0452d744f1c3")
145-
.type("app")
146-
.data(ServiceBindingData.builder()
147-
.credential("super-secret", "password")
148-
.syslogDrainUrl("syslog://drain.url.com")
130+
.type(ServiceBindingType.APPLICATION)
131+
.relationships(ServiceBindingRelationships.builder()
132+
.application(ToOneRelationship.builder()
133+
.data(Relationship.builder()
134+
.id("74f7c078-0934-470f-9883-4fddss5b8f13")
135+
.build())
136+
.build())
137+
.serviceInstance(ToOneRelationship.builder()
138+
.data(Relationship.builder()
139+
.id("8bfe4c1b-9e18-45b1-83be-124163f31f9e")
140+
.build())
141+
.build())
149142
.build())
150143
.createdAt("2015-11-13T17:02:56Z")
151144
.link("self", Link.builder()
152-
.href("/v3/service_bindings/dde5ad2a-d8f4-44dc-a56f-0452d744f1c3")
145+
.href("/v3/service_credential_bindings/dde5ad2a-d8f4-44dc-a56f-0452d744f1c3")
153146
.build())
154147
.link("service_instance", Link.builder()
155148
.href("/v3/service_instances/8bfe4c1b-9e18-45b1-83be-124163f31f9e")
@@ -166,7 +159,7 @@ public void get() {
166159
public void list() {
167160
mockRequest(InteractionContext.builder()
168161
.request(TestRequest.builder()
169-
.method(GET).path("/service_bindings?app_guids=test-application-id&order_by=%2Bcreated_at&page=1")
162+
.method(GET).path("/service_credential_bindings?app_guids=test-application-id&order_by=%2Bcreated_at&page=1")
170163
.build())
171164
.response(TestResponse.builder()
172165
.status(OK)
@@ -185,25 +178,33 @@ public void list() {
185178
.pagination(Pagination.builder()
186179
.totalResults(3)
187180
.first(Link.builder()
188-
.href("/v3/service_bindings?page=1&per_page=2")
181+
.href("/v3/service_credential_bindings?page=1&per_page=2")
189182
.build())
190183
.last(Link.builder()
191-
.href("/v3/service_bindings?page=2&per_page=2")
184+
.href("/v3/service_credential_bindings?page=2&per_page=2")
192185
.build())
193186
.next(Link.builder()
194-
.href("/v3/service_bindings?page=2&per_page=2")
187+
.href("/v3/service_credential_bindings?page=2&per_page=2")
195188
.build())
196189
.build())
197190
.resource(ServiceBindingResource.builder()
198191
.id("dde5ad2a-d8f4-44dc-a56f-0452d744f1c3")
199-
.type("app")
200-
.data(ServiceBindingData.builder()
201-
.credential("super-secret", "password")
202-
.syslogDrainUrl("syslog://drain.url.com")
192+
.type(ServiceBindingType.APPLICATION)
193+
.relationships(ServiceBindingRelationships.builder()
194+
.application(ToOneRelationship.builder()
195+
.data(Relationship.builder()
196+
.id("74f7c078-0934-470f-9883-4fddss5b8f13")
197+
.build())
198+
.build())
199+
.serviceInstance(ToOneRelationship.builder()
200+
.data(Relationship.builder()
201+
.id("8bfe4c1b-9e18-45b1-83be-124163f31f9e")
202+
.build())
203+
.build())
203204
.build())
204205
.createdAt("2015-11-13T17:02:56Z")
205206
.link("self", Link.builder()
206-
.href("/v3/service_bindings/dde5ad2a-d8f4-44dc-a56f-0452d744f1c3")
207+
.href("/v3/service_credential_bindings/dde5ad2a-d8f4-44dc-a56f-0452d744f1c3")
207208
.build())
208209
.link("service_instance", Link.builder()
209210
.href("/v3/service_instances/8bfe4c1b-9e18-45b1-83be-124163f31f9e")
@@ -214,14 +215,22 @@ public void list() {
214215
.build())
215216
.resource(ServiceBindingResource.builder()
216217
.id("7aa37bad-6ccb-4ef9-ba48-9ce3a91b2b62")
217-
.type("app")
218-
.data(ServiceBindingData.builder()
219-
.credential("super-secret", "password")
220-
.syslogDrainUrl("syslog://drain.url.com")
218+
.type(ServiceBindingType.APPLICATION)
219+
.relationships(ServiceBindingRelationships.builder()
220+
.application(ToOneRelationship.builder()
221+
.data(Relationship.builder()
222+
.id("74f7c078-0934-470f-9883-4fddss5b8f13")
223+
.build())
224+
.build())
225+
.serviceInstance(ToOneRelationship.builder()
226+
.data(Relationship.builder()
227+
.id("8bf356j3-9e18-45b1-3333-124163f31f9e")
228+
.build())
229+
.build())
221230
.build())
222231
.createdAt("2015-11-13T17:02:56Z")
223232
.link("self", Link.builder()
224-
.href("/v3/service_bindings/7aa37bad-6ccb-4ef9-ba48-9ce3a91b2b62")
233+
.href("/v3/service_credential_bindings/7aa37bad-6ccb-4ef9-ba48-9ce3a91b2b62")
225234
.build())
226235
.link("service_instance", Link.builder()
227236
.href("/v3/service_instances/8bf356j3-9e18-45b1-3333-124163f31f9e")

cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/servicebindings/GET_response.json

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,37 @@
22
"pagination": {
33
"total_results": 3,
44
"first": {
5-
"href": "/v3/service_bindings?page=1&per_page=2"
5+
"href": "/v3/service_credential_bindings?page=1&per_page=2"
66
},
77
"last": {
8-
"href": "/v3/service_bindings?page=2&per_page=2"
8+
"href": "/v3/service_credential_bindings?page=2&per_page=2"
99
},
1010
"next": {
11-
"href": "/v3/service_bindings?page=2&per_page=2"
11+
"href": "/v3/service_credential_bindings?page=2&per_page=2"
1212
},
1313
"previous": null
1414
},
1515
"resources": [
1616
{
1717
"guid": "dde5ad2a-d8f4-44dc-a56f-0452d744f1c3",
1818
"type": "app",
19-
"data": {
20-
"credentials": {
21-
"super-secret": "password"
19+
"relationships": {
20+
"app": {
21+
"data": {
22+
"guid": "74f7c078-0934-470f-9883-4fddss5b8f13"
23+
}
2224
},
23-
"syslog_drain_url": "syslog://drain.url.com"
25+
"service_instance": {
26+
"data": {
27+
"guid": "8bfe4c1b-9e18-45b1-83be-124163f31f9e"
28+
}
29+
}
2430
},
2531
"created_at": "2015-11-13T17:02:56Z",
2632
"updated_at": null,
2733
"links": {
2834
"self": {
29-
"href": "/v3/service_bindings/dde5ad2a-d8f4-44dc-a56f-0452d744f1c3"
35+
"href": "/v3/service_credential_bindings/dde5ad2a-d8f4-44dc-a56f-0452d744f1c3"
3036
},
3137
"service_instance": {
3238
"href": "/v3/service_instances/8bfe4c1b-9e18-45b1-83be-124163f31f9e"
@@ -39,17 +45,23 @@
3945
{
4046
"guid": "7aa37bad-6ccb-4ef9-ba48-9ce3a91b2b62",
4147
"type": "app",
42-
"data": {
43-
"credentials": {
44-
"super-secret": "password"
48+
"relationships": {
49+
"app": {
50+
"data": {
51+
"guid": "74f7c078-0934-470f-9883-4fddss5b8f13"
52+
}
4553
},
46-
"syslog_drain_url": "syslog://drain.url.com"
54+
"service_instance": {
55+
"data": {
56+
"guid": "8bf356j3-9e18-45b1-3333-124163f31f9e"
57+
}
58+
}
4759
},
4860
"created_at": "2015-11-13T17:02:56Z",
4961
"updated_at": null,
5062
"links": {
5163
"self": {
52-
"href": "/v3/service_bindings/7aa37bad-6ccb-4ef9-ba48-9ce3a91b2b62"
64+
"href": "/v3/service_credential_bindings/7aa37bad-6ccb-4ef9-ba48-9ce3a91b2b62"
5365
},
5466
"service_instance": {
5567
"href": "/v3/service_instances/8bf356j3-9e18-45b1-3333-124163f31f9e"

0 commit comments

Comments
 (0)