From a21d09057e52807e6936b27fa03b0ab45128ee6d Mon Sep 17 00:00:00 2001 From: Georg Lokowandt Date: Fri, 5 Jun 2026 13:00:04 +0200 Subject: [PATCH] implement Service Route binging from v3 API. #1361 This code was developed with support from Claude AI. --- .../client/_ReactorCloudFoundryClient.java | 7 + .../ReactorServiceRouteBindingsV3.java | 142 +++++ .../ReactorServiceRouteBindingsV3Test.java | 371 +++++++++++++ .../v3/serviceroutebindings/GET_response.json | 99 ++++ .../GET_{id}_parameters_response.json | 4 + .../GET_{id}_response.json | 42 ++ .../PATCH_{id}_request.json | 6 + .../PATCH_{id}_response.json | 44 ++ .../v3/serviceroutebindings/POST_request.json | 14 + .../client/CloudFoundryClient.java | 7 + .../ServiceRouteBinding.java | 58 ++ .../ServiceRouteBindingsV3.java | 76 +++ .../_CreateServiceRouteBindingRequest.java | 56 ++ .../_CreateServiceRouteBindingResponse.java | 39 ++ .../_DeleteServiceRouteBindingRequest.java | 29 + .../_DeleteServiceRouteBindingResponse.java | 34 ++ ...tServiceRouteBindingParametersRequest.java | 35 ++ ...ServiceRouteBindingParametersResponse.java | 65 +++ .../_GetServiceRouteBindingRequest.java | 35 ++ .../_GetServiceRouteBindingResponse.java | 31 ++ .../_ListServiceRouteBindingsRequest.java | 64 +++ .../_ListServiceRouteBindingsResponse.java | 33 ++ .../_ServiceRouteBindingRelationships.java | 42 ++ .../_ServiceRouteBindingResource.java | 27 + .../_UpdateServiceRouteBindingRequest.java | 47 ++ .../_UpdateServiceRouteBindingResponse.java | 31 ++ .../CreateServiceRouteBindingRequestTest.java | 56 ++ .../DeleteServiceRouteBindingRequestTest.java | 38 ++ ...viceRouteBindingParametersRequestTest.java | 38 ++ .../GetServiceRouteBindingRequestTest.java | 37 ++ .../ListServiceRouteBindingsRequestTest.java | 27 + .../RelationshipsTest.java | 66 +++ .../UpdateServiceRouteBindingRequestTest.java | 38 ++ .../client/v3/ServiceRouteBindingsTest.java | 499 ++++++++++++++++++ 34 files changed, 2237 insertions(+) create mode 100644 cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/serviceroutebindings/ReactorServiceRouteBindingsV3.java create mode 100644 cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/serviceroutebindings/ReactorServiceRouteBindingsV3Test.java create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/GET_response.json create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/GET_{id}_parameters_response.json create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/GET_{id}_response.json create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/PATCH_{id}_request.json create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/PATCH_{id}_response.json create mode 100644 cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/POST_request.json create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/ServiceRouteBinding.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/ServiceRouteBindingsV3.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_CreateServiceRouteBindingRequest.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_CreateServiceRouteBindingResponse.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_DeleteServiceRouteBindingRequest.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_DeleteServiceRouteBindingResponse.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingParametersRequest.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingParametersResponse.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingRequest.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingResponse.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ListServiceRouteBindingsRequest.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ListServiceRouteBindingsResponse.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ServiceRouteBindingRelationships.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ServiceRouteBindingResource.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_UpdateServiceRouteBindingRequest.java create mode 100644 cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_UpdateServiceRouteBindingResponse.java create mode 100644 cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/CreateServiceRouteBindingRequestTest.java create mode 100644 cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/DeleteServiceRouteBindingRequestTest.java create mode 100644 cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/GetServiceRouteBindingParametersRequestTest.java create mode 100644 cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/GetServiceRouteBindingRequestTest.java create mode 100644 cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/ListServiceRouteBindingsRequestTest.java create mode 100644 cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/RelationshipsTest.java create mode 100644 cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/UpdateServiceRouteBindingRequestTest.java create mode 100644 integration-test/src/test/java/org/cloudfoundry/client/v3/ServiceRouteBindingsTest.java diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/_ReactorCloudFoundryClient.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/_ReactorCloudFoundryClient.java index d646300f28..cccc479071 100644 --- a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/_ReactorCloudFoundryClient.java +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/_ReactorCloudFoundryClient.java @@ -73,6 +73,7 @@ import org.cloudfoundry.client.v3.serviceinstances.ServiceInstancesV3; import org.cloudfoundry.client.v3.serviceofferings.ServiceOfferingsV3; import org.cloudfoundry.client.v3.serviceplans.ServicePlansV3; +import org.cloudfoundry.client.v3.serviceroutebindings.ServiceRouteBindingsV3; import org.cloudfoundry.client.v3.quotas.spaces.SpaceQuotasV3; import org.cloudfoundry.client.v3.spaces.SpacesV3; import org.cloudfoundry.client.v3.stacks.StacksV3; @@ -133,6 +134,7 @@ import org.cloudfoundry.reactor.client.v3.serviceinstances.ReactorServiceInstancesV3; import org.cloudfoundry.reactor.client.v3.serviceofferings.ReactorServiceOfferingsV3; import org.cloudfoundry.reactor.client.v3.serviceplans.ReactorServicePlansV3; +import org.cloudfoundry.reactor.client.v3.serviceroutebindings.ReactorServiceRouteBindingsV3; import org.cloudfoundry.reactor.client.v3.quotas.spaces.ReactorSpaceQuotasV3; import org.cloudfoundry.reactor.client.v3.spaces.ReactorSpacesV3; import org.cloudfoundry.reactor.client.v3.stacks.ReactorStacksV3; @@ -546,4 +548,9 @@ Mono getRootV3() { */ abstract TokenProvider getTokenProvider(); + @Override + @Value.Derived + public ServiceRouteBindingsV3 serviceRouteBindingsV3() { + return new ReactorServiceRouteBindingsV3(getConnectionContext(), getRootV3(), getTokenProvider(), getRequestTags()); + } } diff --git a/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/serviceroutebindings/ReactorServiceRouteBindingsV3.java b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/serviceroutebindings/ReactorServiceRouteBindingsV3.java new file mode 100644 index 0000000000..482d0d881e --- /dev/null +++ b/cloudfoundry-client-reactor/src/main/java/org/cloudfoundry/reactor/client/v3/serviceroutebindings/ReactorServiceRouteBindingsV3.java @@ -0,0 +1,142 @@ +/* + * Copyright 2013-2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.reactor.client.v3.serviceroutebindings; + +import java.util.Map; +import java.util.Optional; +import org.cloudfoundry.client.v3.serviceroutebindings.CreateServiceRouteBindingRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.CreateServiceRouteBindingResponse; +import org.cloudfoundry.client.v3.serviceroutebindings.DeleteServiceRouteBindingRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.DeleteServiceRouteBindingResponse; +import org.cloudfoundry.client.v3.serviceroutebindings.GetServiceRouteBindingParametersRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.GetServiceRouteBindingParametersResponse; +import org.cloudfoundry.client.v3.serviceroutebindings.GetServiceRouteBindingRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.GetServiceRouteBindingResponse; +import org.cloudfoundry.client.v3.serviceroutebindings.ListServiceRouteBindingsRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.ListServiceRouteBindingsResponse; +import org.cloudfoundry.client.v3.serviceroutebindings.ServiceRouteBindingResource; +import org.cloudfoundry.client.v3.serviceroutebindings.ServiceRouteBindingsV3; +import org.cloudfoundry.client.v3.serviceroutebindings.UpdateServiceRouteBindingRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.UpdateServiceRouteBindingResponse; +import org.cloudfoundry.reactor.ConnectionContext; +import org.cloudfoundry.reactor.TokenProvider; +import org.cloudfoundry.reactor.client.v3.AbstractClientV3Operations; +import reactor.core.publisher.Mono; + +/** + * The Reactor-based implementation of {@link ServiceRouteBindingsV3} + */ +public class ReactorServiceRouteBindingsV3 extends AbstractClientV3Operations + implements ServiceRouteBindingsV3 { + + public ReactorServiceRouteBindingsV3( + ConnectionContext connectionContext, + Mono root, + TokenProvider tokenProvider, + Map requestTags) { + super(connectionContext, root, tokenProvider, requestTags); + } + + @Override + public Mono create( + CreateServiceRouteBindingRequest request) { + return postWithResponse( + request, + ServiceRouteBindingResource.class, + builder -> builder.pathSegment("service_route_bindings")) + .map( + responseTuple -> + CreateServiceRouteBindingResponse.builder() + .serviceRouteBinding(responseTuple.getBody()) + .jobId( + Optional.ofNullable( + extractJobId(responseTuple.getResponse()))) + .build()) + .checkpoint(); + } + + @Override + public Mono delete( + DeleteServiceRouteBindingRequest request) { + return createOperator() + .flatMap( + operator -> + operator.delete() + .uri( + builder -> + builder.pathSegment( + "service_route_bindings", + request.getServiceRouteBindingId())) + .send(request) + .response() + .get()) + .map( + response -> + DeleteServiceRouteBindingResponse.builder() + .jobId(Optional.ofNullable(extractJobId(response))) + .build()) + .checkpoint(); + } + + @Override + public Mono get(GetServiceRouteBindingRequest request) { + return get( + request, + GetServiceRouteBindingResponse.class, + builder -> + builder.pathSegment( + "service_route_bindings", + request.getServiceRouteBindingId())) + .checkpoint(); + } + + @Override + public Mono getParameters( + GetServiceRouteBindingParametersRequest request) { + return get( + request, + GetServiceRouteBindingParametersResponse.class, + builder -> + builder.pathSegment( + "service_route_bindings", + request.getServiceRouteBindingId(), + "parameters")) + .checkpoint(); + } + + @Override + public Mono list(ListServiceRouteBindingsRequest request) { + return get( + request, + ListServiceRouteBindingsResponse.class, + builder -> builder.pathSegment("service_route_bindings")) + .checkpoint(); + } + + @Override + public Mono update( + UpdateServiceRouteBindingRequest request) { + return patch( + request, + UpdateServiceRouteBindingResponse.class, + builder -> + builder.pathSegment( + "service_route_bindings", + request.getServiceRouteBindingId())) + .checkpoint(); + } +} diff --git a/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/serviceroutebindings/ReactorServiceRouteBindingsV3Test.java b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/serviceroutebindings/ReactorServiceRouteBindingsV3Test.java new file mode 100644 index 0000000000..5e507c2aeb --- /dev/null +++ b/cloudfoundry-client-reactor/src/test/java/org/cloudfoundry/reactor/client/v3/serviceroutebindings/ReactorServiceRouteBindingsV3Test.java @@ -0,0 +1,371 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.reactor.client.v3.serviceroutebindings; + +import static io.netty.handler.codec.http.HttpMethod.DELETE; +import static io.netty.handler.codec.http.HttpMethod.GET; +import static io.netty.handler.codec.http.HttpMethod.PATCH; +import static io.netty.handler.codec.http.HttpMethod.POST; +import static io.netty.handler.codec.http.HttpResponseStatus.ACCEPTED; +import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT; +import static io.netty.handler.codec.http.HttpResponseStatus.OK; + +import java.time.Duration; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.cloudfoundry.client.v3.LastOperation; +import org.cloudfoundry.client.v3.Link; +import org.cloudfoundry.client.v3.Metadata; +import org.cloudfoundry.client.v3.Pagination; +import org.cloudfoundry.client.v3.Relationship; +import org.cloudfoundry.client.v3.ToOneRelationship; +import org.cloudfoundry.client.v3.serviceroutebindings.CreateServiceRouteBindingRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.CreateServiceRouteBindingResponse; +import org.cloudfoundry.client.v3.serviceroutebindings.DeleteServiceRouteBindingRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.DeleteServiceRouteBindingResponse; +import org.cloudfoundry.client.v3.serviceroutebindings.GetServiceRouteBindingParametersRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.GetServiceRouteBindingParametersResponse; +import org.cloudfoundry.client.v3.serviceroutebindings.GetServiceRouteBindingRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.GetServiceRouteBindingResponse; +import org.cloudfoundry.client.v3.serviceroutebindings.ListServiceRouteBindingsRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.ListServiceRouteBindingsResponse; +import org.cloudfoundry.client.v3.serviceroutebindings.ServiceRouteBindingRelationships; +import org.cloudfoundry.client.v3.serviceroutebindings.ServiceRouteBindingResource; +import org.cloudfoundry.client.v3.serviceroutebindings.UpdateServiceRouteBindingRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.UpdateServiceRouteBindingResponse; +import org.cloudfoundry.reactor.InteractionContext; +import org.cloudfoundry.reactor.TestRequest; +import org.cloudfoundry.reactor.TestResponse; +import org.cloudfoundry.reactor.client.AbstractClientApiTest; +import org.junit.jupiter.api.Test; +import reactor.test.StepVerifier; + +final class ReactorServiceRouteBindingsV3Test extends AbstractClientApiTest { + + private static final String ROUTE_ID = "7304bc3c-7010-11ea-8840-48bf6bec2d78"; + private static final String SERVICE_INSTANCE_ID_1 = "e0e4417c-74ee-11ea-a604-48bf6bec2d78"; + private static final String SERVICE_INSTANCE_ID_2 = "f0a63e60-74ee-11ea-a604-48bf6bec2d78"; + private static final String BINDING_ID_1 = "dde5ad2a-d8f4-44dc-a56f-0452d744f1c3"; + private static final String BINDING_ID_2 = "7aa37bad-6ccb-4ef9-ba48-9ce3a91b2b62"; + private static final String CREATED_AT = "2020-03-10T15:49:29Z"; + private static final String UPDATED_AT = "2020-03-10T15:49:32Z"; + + private final ReactorServiceRouteBindingsV3 serviceRouteBindings = + new ReactorServiceRouteBindingsV3( + CONNECTION_CONTEXT, this.root, TOKEN_PROVIDER, Collections.emptyMap()); + + @Test + void create() { + mockRequest( + InteractionContext.builder() + .request( + TestRequest.builder() + .method(POST) + .path("/service_route_bindings") + .payload( + "fixtures/client/v3/serviceroutebindings/POST_request.json") + .build()) + .response( + TestResponse.builder() + .status(ACCEPTED) + .header( + "Location", + "https://api.example.org/v3/jobs/af5c57f6-8769-41fa-a499-2c84ed896788") + .build()) + .build()); + + this.serviceRouteBindings + .create( + CreateServiceRouteBindingRequest.builder() + .relationships(relationships(SERVICE_INSTANCE_ID_1)) + .build()) + .as(StepVerifier::create) + .expectNext( + CreateServiceRouteBindingResponse.builder() + .jobId("af5c57f6-8769-41fa-a499-2c84ed896788") + .build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + + @Test + void delete() { + mockRequest( + InteractionContext.builder() + .request( + TestRequest.builder() + .method(DELETE) + .path( + "/service_route_bindings/test-service-route-binding-id") + .build()) + .response(TestResponse.builder().status(NO_CONTENT).build()) + .build()); + + this.serviceRouteBindings + .delete( + DeleteServiceRouteBindingRequest.builder() + .serviceRouteBindingId("test-service-route-binding-id") + .build()) + .as(StepVerifier::create) + .expectNext(DeleteServiceRouteBindingResponse.builder().build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + + @Test + void get() { + mockRequest( + InteractionContext.builder() + .request( + TestRequest.builder() + .method(GET) + .path( + "/service_route_bindings/test-service-route-binding-id") + .build()) + .response( + TestResponse.builder() + .status(OK) + .payload( + "fixtures/client/v3/serviceroutebindings/GET_{id}_response.json") + .build()) + .build()); + + this.serviceRouteBindings + .get( + GetServiceRouteBindingRequest.builder() + .serviceRouteBindingId("test-service-route-binding-id") + .build()) + .as(StepVerifier::create) + .expectNext( + GetServiceRouteBindingResponse.builder() + .id(BINDING_ID_1) + .createdAt(CREATED_AT) + .updatedAt(UPDATED_AT) + .lastOperation(lastOperation("create")) + .relationships(relationships(SERVICE_INSTANCE_ID_1)) + .link("self", link(bindingHref(BINDING_ID_1))) + .link( + "service_instance", + link(serviceInstanceHref(SERVICE_INSTANCE_ID_1))) + .link("route", link(routeHref())) + .link("parameters", link(parametersHref(BINDING_ID_1))) + .metadata(emptyMetadata()) + .build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + + @Test + void getParameters() { + Map parameters = new HashMap<>(); + parameters.put("key1", "value1"); + parameters.put("key2", "value2"); + + mockRequest( + InteractionContext.builder() + .request( + TestRequest.builder() + .method(GET) + .path( + "/service_route_bindings/test-service-route-binding-id/parameters") + .build()) + .response( + TestResponse.builder() + .status(OK) + .payload( + "fixtures/client/v3/serviceroutebindings/GET_{id}_parameters_response.json") + .build()) + .build()); + + this.serviceRouteBindings + .getParameters( + GetServiceRouteBindingParametersRequest.builder() + .serviceRouteBindingId("test-service-route-binding-id") + .build()) + .as(StepVerifier::create) + .expectNext( + GetServiceRouteBindingParametersResponse.builder() + .parameters(parameters) + .build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + + @Test + void list() { + mockRequest( + InteractionContext.builder() + .request( + TestRequest.builder() + .method(GET) + .path( + "/service_route_bindings?route_guids=7304bc3c-7010-11ea-8840-48bf6bec2d78&order_by=%2Bcreated_at&page=1") + .build()) + .response( + TestResponse.builder() + .status(OK) + .payload( + "fixtures/client/v3/serviceroutebindings/GET_response.json") + .build()) + .build()); + + this.serviceRouteBindings + .list( + ListServiceRouteBindingsRequest.builder() + .page(1) + .orderBy("+created_at") + .routeId(ROUTE_ID) + .build()) + .as(StepVerifier::create) + .expectNext( + ListServiceRouteBindingsResponse.builder() + .pagination( + Pagination.builder() + .totalResults(2) + .first( + link( + "https://api.example.org/v3/service_route_bindings?page=1&per_page=50")) + .last( + link( + "https://api.example.org/v3/service_route_bindings?page=1&per_page=50")) + .build()) + .resource( + bindingResource( + BINDING_ID_1, SERVICE_INSTANCE_ID_1, "create")) + .resource( + bindingResource( + BINDING_ID_2, SERVICE_INSTANCE_ID_2, "create")) + .build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + + @Test + void update() { + mockRequest( + InteractionContext.builder() + .request( + TestRequest.builder() + .method(PATCH) + .path( + "/service_route_bindings/test-service-route-binding-id") + .payload( + "fixtures/client/v3/serviceroutebindings/PATCH_{id}_request.json") + .build()) + .response( + TestResponse.builder() + .status(OK) + .payload( + "fixtures/client/v3/serviceroutebindings/PATCH_{id}_response.json") + .build()) + .build()); + + this.serviceRouteBindings + .update( + UpdateServiceRouteBindingRequest.builder() + .serviceRouteBindingId("test-service-route-binding-id") + .metadata(metadataWithLabel("env", "production")) + .build()) + .as(StepVerifier::create) + .expectNext( + UpdateServiceRouteBindingResponse.builder() + .id(BINDING_ID_1) + .createdAt(CREATED_AT) + .updatedAt(UPDATED_AT) + .lastOperation(lastOperation("update")) + .relationships(relationships(SERVICE_INSTANCE_ID_1)) + .link("self", link(bindingHref(BINDING_ID_1))) + .link( + "service_instance", + link(serviceInstanceHref(SERVICE_INSTANCE_ID_1))) + .link("route", link(routeHref())) + .link("parameters", link(parametersHref(BINDING_ID_1))) + .metadata(metadataWithLabel("env", "production")) + .build()) + .expectComplete() + .verify(Duration.ofSeconds(5)); + } + + private static LastOperation lastOperation(String type) { + return LastOperation.builder() + .type(type) + .state("succeeded") + .description("Operation succeeded") + .createdAt(CREATED_AT) + .updatedAt(UPDATED_AT) + .build(); + } + + private static ToOneRelationship toOneRelationship(String id) { + return ToOneRelationship.builder().data(Relationship.builder().id(id).build()).build(); + } + + private static ServiceRouteBindingRelationships relationships(String serviceInstanceId) { + return ServiceRouteBindingRelationships.builder() + .route(toOneRelationship(ROUTE_ID)) + .serviceInstance(toOneRelationship(serviceInstanceId)) + .build(); + } + + private static Link link(String href) { + return Link.builder().href(href).build(); + } + + private static String bindingHref(String bindingId) { + return "https://api.example.org/v3/service_route_bindings/" + bindingId; + } + + private static String serviceInstanceHref(String serviceInstanceId) { + return "https://api.example.org/v3/service_instances/" + serviceInstanceId; + } + + private static String routeHref() { + return "https://api.example.org/v3/routes/" + ROUTE_ID; + } + + private static String parametersHref(String bindingId) { + return "https://api.example.org/v3/service_route_bindings/" + bindingId + "/parameters"; + } + + private static Metadata emptyMetadata() { + return Metadata.builder() + .labels(Collections.emptyMap()) + .annotations(Collections.emptyMap()) + .build(); + } + + private static Metadata metadataWithLabel(String key, String value) { + return Metadata.builder().label(key, value).annotations(Collections.emptyMap()).build(); + } + + private static ServiceRouteBindingResource bindingResource( + String bindingId, String serviceInstanceId, String lastOperationType) { + return ServiceRouteBindingResource.builder() + .id(bindingId) + .createdAt(CREATED_AT) + .updatedAt(UPDATED_AT) + .lastOperation(lastOperation(lastOperationType)) + .relationships(relationships(serviceInstanceId)) + .link("self", link(bindingHref(bindingId))) + .link("service_instance", link(serviceInstanceHref(serviceInstanceId))) + .link("route", link(routeHref())) + .link("parameters", link(parametersHref(bindingId))) + .metadata(emptyMetadata()) + .build(); + } +} diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/GET_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/GET_response.json new file mode 100644 index 0000000000..b1e91ee93e --- /dev/null +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/GET_response.json @@ -0,0 +1,99 @@ +{ + "pagination": { + "total_results": 2, + "first": { + "href": "https://api.example.org/v3/service_route_bindings?page=1&per_page=50" + }, + "last": { + "href": "https://api.example.org/v3/service_route_bindings?page=1&per_page=50" + }, + "next": null, + "previous": null + }, + "resources": [ + { + "guid": "dde5ad2a-d8f4-44dc-a56f-0452d744f1c3", + "created_at": "2020-03-10T15:49:29Z", + "updated_at": "2020-03-10T15:49:32Z", + "last_operation": { + "type": "create", + "state": "succeeded", + "description": "Operation succeeded", + "created_at": "2020-03-10T15:49:29Z", + "updated_at": "2020-03-10T15:49:32Z" + }, + "relationships": { + "route": { + "data": { + "guid": "7304bc3c-7010-11ea-8840-48bf6bec2d78" + } + }, + "service_instance": { + "data": { + "guid": "e0e4417c-74ee-11ea-a604-48bf6bec2d78" + } + } + }, + "links": { + "self": { + "href": "https://api.example.org/v3/service_route_bindings/dde5ad2a-d8f4-44dc-a56f-0452d744f1c3" + }, + "service_instance": { + "href": "https://api.example.org/v3/service_instances/e0e4417c-74ee-11ea-a604-48bf6bec2d78" + }, + "route": { + "href": "https://api.example.org/v3/routes/7304bc3c-7010-11ea-8840-48bf6bec2d78" + }, + "parameters": { + "href": "https://api.example.org/v3/service_route_bindings/dde5ad2a-d8f4-44dc-a56f-0452d744f1c3/parameters" + } + }, + "metadata": { + "labels": {}, + "annotations": {} + } + }, + { + "guid": "7aa37bad-6ccb-4ef9-ba48-9ce3a91b2b62", + "created_at": "2020-03-10T15:49:29Z", + "updated_at": "2020-03-10T15:49:32Z", + "last_operation": { + "type": "create", + "state": "succeeded", + "description": "Operation succeeded", + "created_at": "2020-03-10T15:49:29Z", + "updated_at": "2020-03-10T15:49:32Z" + }, + "relationships": { + "route": { + "data": { + "guid": "7304bc3c-7010-11ea-8840-48bf6bec2d78" + } + }, + "service_instance": { + "data": { + "guid": "f0a63e60-74ee-11ea-a604-48bf6bec2d78" + } + } + }, + "links": { + "self": { + "href": "https://api.example.org/v3/service_route_bindings/7aa37bad-6ccb-4ef9-ba48-9ce3a91b2b62" + }, + "service_instance": { + "href": "https://api.example.org/v3/service_instances/f0a63e60-74ee-11ea-a604-48bf6bec2d78" + }, + "route": { + "href": "https://api.example.org/v3/routes/7304bc3c-7010-11ea-8840-48bf6bec2d78" + }, + "parameters": { + "href": "https://api.example.org/v3/service_route_bindings/7aa37bad-6ccb-4ef9-ba48-9ce3a91b2b62/parameters" + } + }, + "metadata": { + "labels": {}, + "annotations": {} + } + } + ] +} diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/GET_{id}_parameters_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/GET_{id}_parameters_response.json new file mode 100644 index 0000000000..7afc33d536 --- /dev/null +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/GET_{id}_parameters_response.json @@ -0,0 +1,4 @@ +{ + "key1": "value1", + "key2": "value2" +} diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/GET_{id}_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/GET_{id}_response.json new file mode 100644 index 0000000000..82ddbb78b0 --- /dev/null +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/GET_{id}_response.json @@ -0,0 +1,42 @@ +{ + "guid": "dde5ad2a-d8f4-44dc-a56f-0452d744f1c3", + "created_at": "2020-03-10T15:49:29Z", + "updated_at": "2020-03-10T15:49:32Z", + "last_operation": { + "type": "create", + "state": "succeeded", + "description": "Operation succeeded", + "created_at": "2020-03-10T15:49:29Z", + "updated_at": "2020-03-10T15:49:32Z" + }, + "relationships": { + "route": { + "data": { + "guid": "7304bc3c-7010-11ea-8840-48bf6bec2d78" + } + }, + "service_instance": { + "data": { + "guid": "e0e4417c-74ee-11ea-a604-48bf6bec2d78" + } + } + }, + "links": { + "self": { + "href": "https://api.example.org/v3/service_route_bindings/dde5ad2a-d8f4-44dc-a56f-0452d744f1c3" + }, + "service_instance": { + "href": "https://api.example.org/v3/service_instances/e0e4417c-74ee-11ea-a604-48bf6bec2d78" + }, + "route": { + "href": "https://api.example.org/v3/routes/7304bc3c-7010-11ea-8840-48bf6bec2d78" + }, + "parameters": { + "href": "https://api.example.org/v3/service_route_bindings/dde5ad2a-d8f4-44dc-a56f-0452d744f1c3/parameters" + } + }, + "metadata": { + "labels": {}, + "annotations": {} + } +} diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/PATCH_{id}_request.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/PATCH_{id}_request.json new file mode 100644 index 0000000000..229ea92c51 --- /dev/null +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/PATCH_{id}_request.json @@ -0,0 +1,6 @@ +{ + "metadata": { + "labels": {"env": "production"}, + "annotations": {} + } +} diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/PATCH_{id}_response.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/PATCH_{id}_response.json new file mode 100644 index 0000000000..b8f4266b7c --- /dev/null +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/PATCH_{id}_response.json @@ -0,0 +1,44 @@ +{ + "guid": "dde5ad2a-d8f4-44dc-a56f-0452d744f1c3", + "created_at": "2020-03-10T15:49:29Z", + "updated_at": "2020-03-10T15:49:32Z", + "last_operation": { + "type": "update", + "state": "succeeded", + "description": "Operation succeeded", + "created_at": "2020-03-10T15:49:29Z", + "updated_at": "2020-03-10T15:49:32Z" + }, + "relationships": { + "route": { + "data": { + "guid": "7304bc3c-7010-11ea-8840-48bf6bec2d78" + } + }, + "service_instance": { + "data": { + "guid": "e0e4417c-74ee-11ea-a604-48bf6bec2d78" + } + } + }, + "links": { + "self": { + "href": "https://api.example.org/v3/service_route_bindings/dde5ad2a-d8f4-44dc-a56f-0452d744f1c3" + }, + "service_instance": { + "href": "https://api.example.org/v3/service_instances/e0e4417c-74ee-11ea-a604-48bf6bec2d78" + }, + "route": { + "href": "https://api.example.org/v3/routes/7304bc3c-7010-11ea-8840-48bf6bec2d78" + }, + "parameters": { + "href": "https://api.example.org/v3/service_route_bindings/dde5ad2a-d8f4-44dc-a56f-0452d744f1c3/parameters" + } + }, + "metadata": { + "labels": { + "env": "production" + }, + "annotations": {} + } +} diff --git a/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/POST_request.json b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/POST_request.json new file mode 100644 index 0000000000..9796cc3138 --- /dev/null +++ b/cloudfoundry-client-reactor/src/test/resources/fixtures/client/v3/serviceroutebindings/POST_request.json @@ -0,0 +1,14 @@ +{ + "relationships": { + "route": { + "data": { + "guid": "7304bc3c-7010-11ea-8840-48bf6bec2d78" + } + }, + "service_instance": { + "data": { + "guid": "e0e4417c-74ee-11ea-a604-48bf6bec2d78" + } + } + } +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/CloudFoundryClient.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/CloudFoundryClient.java index 171dd5d284..397a4fff60 100644 --- a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/CloudFoundryClient.java +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/CloudFoundryClient.java @@ -71,6 +71,7 @@ import org.cloudfoundry.client.v3.serviceinstances.ServiceInstancesV3; import org.cloudfoundry.client.v3.serviceofferings.ServiceOfferingsV3; import org.cloudfoundry.client.v3.serviceplans.ServicePlansV3; +import org.cloudfoundry.client.v3.serviceroutebindings.ServiceRouteBindingsV3; import org.cloudfoundry.client.v3.spaces.SpacesV3; import org.cloudfoundry.client.v3.stacks.StacksV3; import org.cloudfoundry.client.v3.tasks.Tasks; @@ -382,4 +383,10 @@ public interface CloudFoundryClient { * Main entry point to the Cloud Foundry Users Client API */ Users users(); + + /** + * Main entry point to the Cloud Foundry Service Route Bindings V3 Client API + * See https://v3-apidocs.cloudfoundry.org/index.html#service-route-binding + */ + ServiceRouteBindingsV3 serviceRouteBindingsV3(); } diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/ServiceRouteBinding.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/ServiceRouteBinding.java new file mode 100644 index 0000000000..01f1ac35e1 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/ServiceRouteBinding.java @@ -0,0 +1,58 @@ +/* + * Copyright 2013-2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import com.fasterxml.jackson.annotation.JsonProperty; +import org.cloudfoundry.Nullable; +import org.cloudfoundry.client.v3.LastOperation; +import org.cloudfoundry.client.v3.Metadata; +import org.cloudfoundry.client.v3.Resource; + +/** + * Base class for responses that are service route bindings + * + * see https://v3-apidocs.cloudfoundry.org/index.html#service-route-binding + */ +public abstract class ServiceRouteBinding extends Resource { + + /** + * The last operation + */ + @JsonProperty("last_operation") + @Nullable + public abstract LastOperation getLastOperation(); + + /** + * The metadata + */ + @JsonProperty("metadata") + @Nullable + public abstract Metadata getMetadata(); + + /** + * The relationships + */ + @JsonProperty("relationships") + public abstract ServiceRouteBindingRelationships getRelationships(); + + /** + * The URL of the service that will intercept traffic to the route + */ + @JsonProperty("route_service_url") + @Nullable + public abstract String getRouteServiceUrl(); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/ServiceRouteBindingsV3.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/ServiceRouteBindingsV3.java new file mode 100644 index 0000000000..cd1c1055ea --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/ServiceRouteBindingsV3.java @@ -0,0 +1,76 @@ +/* + * Copyright 2013-2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import reactor.core.publisher.Mono; + +/** + * Main entry point to the Cloud Foundry Service Route Bindings V3 Client API + * + * see https://v3-apidocs.cloudfoundry.org/index.html#service-route-binding + */ +public interface ServiceRouteBindingsV3 { + + /** + * Makes the Create a service route binding request + * + * @param request the Create Service Route Binding request + * @return the response from the Create Service Route Binding request + */ + Mono create(CreateServiceRouteBindingRequest request); + + /** + * Makes the Delete a service route binding request + * + * @param request the Delete Service Route Binding request + * @return the response from the Delete Service Route Binding request + */ + Mono delete(DeleteServiceRouteBindingRequest request); + + /** + * Makes the Get a service route binding request + * + * @param request the Get Service Route Binding request + * @return the response from the Get Service Route Binding request + */ + Mono get(GetServiceRouteBindingRequest request); + + /** + * Makes the Get parameters for a service route binding request + * + * @param request the Get Service Route Binding Parameters request + * @return the response from the Get Service Route Binding Parameters request + */ + Mono getParameters( + GetServiceRouteBindingParametersRequest request); + + /** + * Makes the List service route bindings request + * + * @param request the List Service Route Bindings request + * @return the response from the List Service Route Bindings request + */ + Mono list(ListServiceRouteBindingsRequest request); + + /** + * Makes the Update a service route binding request + * + * @param request the Update Service Route Binding request + * @return the response from the Update Service Route Binding request + */ + Mono update(UpdateServiceRouteBindingRequest request); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_CreateServiceRouteBindingRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_CreateServiceRouteBindingRequest.java new file mode 100644 index 0000000000..d77297d2a2 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_CreateServiceRouteBindingRequest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.cloudfoundry.AllowNulls; +import org.cloudfoundry.Nullable; +import org.cloudfoundry.client.v3.Metadata; +import org.immutables.value.Value; + +import java.util.Map; + +/** + * The request payload for the Create Service Route Binding operation. + * see https://v3-apidocs.cloudfoundry.org/index.html#create-a-service-route-binding + */ +@JsonSerialize +@Value.Immutable +abstract class _CreateServiceRouteBindingRequest { + + /** + * The metadata + */ + @JsonProperty("metadata") + @Nullable + abstract Metadata getMetadata(); + + /** + * The parameters + */ + @JsonProperty("parameters") + @Nullable + @AllowNulls + abstract Map getParameters(); + + /** + * The relationships + */ + @JsonProperty("relationships") + abstract ServiceRouteBindingRelationships getRelationships(); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_CreateServiceRouteBindingResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_CreateServiceRouteBindingResponse.java new file mode 100644 index 0000000000..d4cf5a98d4 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_CreateServiceRouteBindingResponse.java @@ -0,0 +1,39 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import org.immutables.value.Value; + +import java.util.Optional; + +/** + * The response payload for the Create Service Route Binding operation. + * see https://v3-apidocs.cloudfoundry.org/#create-a-service-credential-binding + */ +@Value.Immutable +abstract class _CreateServiceRouteBindingResponse { + + /** + * The job id (present when the binding is created asynchronously, managed service instance) + */ + public abstract Optional getJobId(); + + /** + * The service route binding (present when the binding is created synchronously, user provided service instance) + */ + public abstract Optional getServiceRouteBinding(); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_DeleteServiceRouteBindingRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_DeleteServiceRouteBindingRequest.java new file mode 100644 index 0000000000..584564baa1 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_DeleteServiceRouteBindingRequest.java @@ -0,0 +1,29 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import org.immutables.value.Value; + +/** + * The request payload for the Delete Service Route Binding operation. + * see https://v3-apidocs.cloudfoundry.org/index.html#delete-a-service-route-binding + */ +@Value.Immutable +abstract class _DeleteServiceRouteBindingRequest { + + abstract String getServiceRouteBindingId(); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_DeleteServiceRouteBindingResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_DeleteServiceRouteBindingResponse.java new file mode 100644 index 0000000000..809cc27c3a --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_DeleteServiceRouteBindingResponse.java @@ -0,0 +1,34 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import org.immutables.value.Value; + +import java.util.Optional; + +/** + * The response payload for the Delete Service Route Binding operation. + * see https://v3-apidocs.cloudfoundry.org/index.html#delete-a-service-route-binding + */ +@Value.Immutable +abstract class _DeleteServiceRouteBindingResponse { + + /** + * The job id (present when the binding is deleted asynchronously, managed service instance) + */ + public abstract Optional getJobId(); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingParametersRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingParametersRequest.java new file mode 100644 index 0000000000..e23402562f --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingParametersRequest.java @@ -0,0 +1,35 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.immutables.value.Value; + +/** + * The request payload for the Get Service Route Binding Parameters operation + * + * see https://v3-apidocs.cloudfoundry.org/index.html#get-parameters-for-a-route-binding + */ +@Value.Immutable +abstract class _GetServiceRouteBindingParametersRequest { + + /** + * The service route binding id + */ + @JsonIgnore + abstract String getServiceRouteBindingId(); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingParametersResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingParametersResponse.java new file mode 100644 index 0000000000..2832398a8f --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingParametersResponse.java @@ -0,0 +1,65 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.cloudfoundry.AllowNulls; +import org.immutables.value.Value; + +import java.io.IOException; +import java.util.Map; + +/** + * The response payload for the Get Service Route Binding Parameters operation + * + * see https://v3-apidocs.cloudfoundry.org/index.html#get-parameters-for-a-route-binding + */ +@JsonDeserialize( + using = + _GetServiceRouteBindingParametersResponse + .ServiceRouteBindingParametersResponseDeserializer.class) +@Value.Immutable +abstract class _GetServiceRouteBindingParametersResponse { + + /** + * The parameters + */ + @AllowNulls + abstract Map getParameters(); + + static final class ServiceRouteBindingParametersResponseDeserializer + extends StdDeserializer { + + private static final long serialVersionUID = 1L; + + ServiceRouteBindingParametersResponseDeserializer() { + super(GetServiceRouteBindingParametersResponse.class); + } + + @Override + public GetServiceRouteBindingParametersResponse deserialize( + JsonParser p, DeserializationContext ctxt) throws IOException { + return GetServiceRouteBindingParametersResponse.builder() + .parameters(p.readValueAs(new TypeReference>() {})) + .build(); + } + } +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingRequest.java new file mode 100644 index 0000000000..166c33bb91 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingRequest.java @@ -0,0 +1,35 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import org.immutables.value.Value; + +/** + * The request payload for the Get Service Route Binding operation. + * + * see https://v3-apidocs.cloudfoundry.org/index.html#get-a-service-route-binding + */ +@Value.Immutable +abstract class _GetServiceRouteBindingRequest { + + /** + * The service route binding id + */ + @JsonIgnore + abstract String getServiceRouteBindingId(); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingResponse.java new file mode 100644 index 0000000000..8465e2fb60 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_GetServiceRouteBindingResponse.java @@ -0,0 +1,31 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.immutables.value.Value; + +/** + * The response payload for the Get Service Route Binding operation + * + * see https://v3-apidocs.cloudfoundry.org/index.html#get-a-service-route-binding + */ +@JsonDeserialize +@Value.Immutable +abstract class _GetServiceRouteBindingResponse extends ServiceRouteBinding { + +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ListServiceRouteBindingsRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ListServiceRouteBindingsRequest.java new file mode 100644 index 0000000000..bafe9e1196 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ListServiceRouteBindingsRequest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2013-2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import org.cloudfoundry.Nullable; +import org.cloudfoundry.client.v3.FilterParameter; +import org.cloudfoundry.client.v3.PaginatedRequest; +import org.immutables.value.Value; + +import java.util.List; + +/** + * The request payload for the List Service Route Bindings operation + * + * see https://v3-apidocs.cloudfoundry.org/index.html#list-service-route-bindings + */ +@Value.Immutable +abstract class _ListServiceRouteBindingsRequest extends PaginatedRequest { + + /** + * The ids + */ + @FilterParameter("guids") + abstract List getIds(); + + /** + * A query string containing a list of label selector requirements + */ + @FilterParameter("label_selector") + @Nullable + abstract String getLabelSelector(); + + /** + * The route ids + */ + @FilterParameter("route_guids") + abstract List getRouteIds(); + + /** + * The service instance ids + */ + @FilterParameter("service_instance_guids") + abstract List getServiceInstanceIds(); + + /** + * The service instance names + */ + @FilterParameter("service_instance_names") + abstract List getServiceInstanceNames(); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ListServiceRouteBindingsResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ListServiceRouteBindingsResponse.java new file mode 100644 index 0000000000..d86323be83 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ListServiceRouteBindingsResponse.java @@ -0,0 +1,33 @@ +/* + * Copyright 2013-2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.cloudfoundry.client.v3.PaginatedResponse; +import org.immutables.value.Value; + +/** + * The response payload for the List Service Route Bindings operation + * + * see https://v3-apidocs.cloudfoundry.org/index.html#list-service-route-bindings + */ +@JsonDeserialize +@Value.Immutable +public abstract class _ListServiceRouteBindingsResponse + extends PaginatedResponse { + +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ServiceRouteBindingRelationships.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ServiceRouteBindingRelationships.java new file mode 100644 index 0000000000..373a5508af --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ServiceRouteBindingRelationships.java @@ -0,0 +1,42 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.cloudfoundry.client.v3.ToOneRelationship; +import org.immutables.value.Value; + +/** + * The relationships for a service route binding + */ +@Value.Immutable +@JsonDeserialize +abstract class _ServiceRouteBindingRelationships { + + /** + * The route relationship + */ + @JsonProperty("route") + abstract ToOneRelationship getRoute(); + + /** + * The service instance relationship + */ + @JsonProperty("service_instance") + abstract ToOneRelationship getServiceInstance(); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ServiceRouteBindingResource.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ServiceRouteBindingResource.java new file mode 100644 index 0000000000..f0ba3553b0 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_ServiceRouteBindingResource.java @@ -0,0 +1,27 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.immutables.value.Value; + +/** + * The Resource response payload for the List Service Route Bindings operation + */ +@JsonDeserialize +@Value.Immutable +abstract class _ServiceRouteBindingResource extends ServiceRouteBinding {} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_UpdateServiceRouteBindingRequest.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_UpdateServiceRouteBindingRequest.java new file mode 100644 index 0000000000..bafdc7ba6e --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_UpdateServiceRouteBindingRequest.java @@ -0,0 +1,47 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.cloudfoundry.Nullable; +import org.cloudfoundry.client.v3.Metadata; +import org.immutables.value.Value; + +/** + * The request payload for the Update Service Route Binding operation + * + * see https://v3-apidocs.cloudfoundry.org/index.html#update-a-service-route-binding + */ +@JsonSerialize +@Value.Immutable +abstract class _UpdateServiceRouteBindingRequest { + + /** + * The service route binding id + */ + @JsonIgnore + abstract String getServiceRouteBindingId(); + + /** + * The metadata + */ + @JsonProperty("metadata") + @Nullable + abstract Metadata getMetadata(); +} diff --git a/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_UpdateServiceRouteBindingResponse.java b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_UpdateServiceRouteBindingResponse.java new file mode 100644 index 0000000000..76d03d5796 --- /dev/null +++ b/cloudfoundry-client/src/main/java/org/cloudfoundry/client/v3/serviceroutebindings/_UpdateServiceRouteBindingResponse.java @@ -0,0 +1,31 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import org.immutables.value.Value; + +/** + * The response payload for the Update Service Route Binding operation + * + * see https://v3-apidocs.cloudfoundry.org/index.html#update-a-service-route-binding + */ +@JsonDeserialize +@Value.Immutable +abstract class _UpdateServiceRouteBindingResponse extends ServiceRouteBinding { + +} diff --git a/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/CreateServiceRouteBindingRequestTest.java b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/CreateServiceRouteBindingRequestTest.java new file mode 100644 index 0000000000..bb320e107b --- /dev/null +++ b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/CreateServiceRouteBindingRequestTest.java @@ -0,0 +1,56 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.cloudfoundry.client.v3.Relationship; +import org.cloudfoundry.client.v3.ToOneRelationship; +import org.junit.jupiter.api.Test; + +final class CreateServiceRouteBindingRequestTest { + + @Test + void noRelationships() { + assertThrows( + IllegalStateException.class, + () -> CreateServiceRouteBindingRequest.builder().build()); + } + + @Test + void valid() { + CreateServiceRouteBindingRequest.builder() + .relationships( + ServiceRouteBindingRelationships.builder() + .route( + ToOneRelationship.builder() + .data( + Relationship.builder() + .id("test-route-id") + .build()) + .build()) + .serviceInstance( + ToOneRelationship.builder() + .data( + Relationship.builder() + .id("test-service-instance-id") + .build()) + .build()) + .build()) + .build(); + } +} diff --git a/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/DeleteServiceRouteBindingRequestTest.java b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/DeleteServiceRouteBindingRequestTest.java new file mode 100644 index 0000000000..63ad678fb9 --- /dev/null +++ b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/DeleteServiceRouteBindingRequestTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +final class DeleteServiceRouteBindingRequestTest { + + @Test + void noServiceRouteBindingId() { + assertThrows( + IllegalStateException.class, + () -> DeleteServiceRouteBindingRequest.builder().build()); + } + + @Test + void valid() { + DeleteServiceRouteBindingRequest.builder() + .serviceRouteBindingId("test-service-route-binding-id") + .build(); + } +} diff --git a/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/GetServiceRouteBindingParametersRequestTest.java b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/GetServiceRouteBindingParametersRequestTest.java new file mode 100644 index 0000000000..0b1880a830 --- /dev/null +++ b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/GetServiceRouteBindingParametersRequestTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +final class GetServiceRouteBindingParametersRequestTest { + + @Test + void noServiceRouteBindingId() { + assertThrows( + IllegalStateException.class, + () -> GetServiceRouteBindingParametersRequest.builder().build()); + } + + @Test + void valid() { + GetServiceRouteBindingParametersRequest.builder() + .serviceRouteBindingId("test-service-route-binding-id") + .build(); + } +} diff --git a/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/GetServiceRouteBindingRequestTest.java b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/GetServiceRouteBindingRequestTest.java new file mode 100644 index 0000000000..e18d6e76cb --- /dev/null +++ b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/GetServiceRouteBindingRequestTest.java @@ -0,0 +1,37 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +final class GetServiceRouteBindingRequestTest { + + @Test + void noServiceRouteBindingId() { + assertThrows( + IllegalStateException.class, () -> GetServiceRouteBindingRequest.builder().build()); + } + + @Test + void valid() { + GetServiceRouteBindingRequest.builder() + .serviceRouteBindingId("test-service-route-binding-id") + .build(); + } +} diff --git a/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/ListServiceRouteBindingsRequestTest.java b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/ListServiceRouteBindingsRequestTest.java new file mode 100644 index 0000000000..f6056cb11a --- /dev/null +++ b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/ListServiceRouteBindingsRequestTest.java @@ -0,0 +1,27 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import org.junit.jupiter.api.Test; + +final class ListServiceRouteBindingsRequestTest { + + @Test + void valid() { + ListServiceRouteBindingsRequest.builder().build(); + } +} diff --git a/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/RelationshipsTest.java b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/RelationshipsTest.java new file mode 100644 index 0000000000..da5cfce0d6 --- /dev/null +++ b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/RelationshipsTest.java @@ -0,0 +1,66 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.cloudfoundry.client.v3.Relationship; +import org.cloudfoundry.client.v3.ToOneRelationship; +import org.junit.jupiter.api.Test; + +final class RelationshipsTest { + + @Test + void noRoute() { + assertThrows( + IllegalStateException.class, + () -> + ServiceRouteBindingRelationships.builder() + .serviceInstance( + ToOneRelationship.builder() + .data(Relationship.builder().id("test-id").build()) + .build()) + .build()); + } + + @Test + void noServiceInstance() { + assertThrows( + IllegalStateException.class, + () -> + ServiceRouteBindingRelationships.builder() + .route( + ToOneRelationship.builder() + .data(Relationship.builder().id("test-id").build()) + .build()) + .build()); + } + + @Test + void valid() { + ServiceRouteBindingRelationships.builder() + .route( + ToOneRelationship.builder() + .data(Relationship.builder().id("test-route-id").build()) + .build()) + .serviceInstance( + ToOneRelationship.builder() + .data(Relationship.builder().id("test-service-instance-id").build()) + .build()) + .build(); + } +} diff --git a/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/UpdateServiceRouteBindingRequestTest.java b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/UpdateServiceRouteBindingRequestTest.java new file mode 100644 index 0000000000..dab5942935 --- /dev/null +++ b/cloudfoundry-client/src/test/java/org/cloudfoundry/client/v3/serviceroutebindings/UpdateServiceRouteBindingRequestTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3.serviceroutebindings; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import org.junit.jupiter.api.Test; + +final class UpdateServiceRouteBindingRequestTest { + + @Test + void noServiceRouteBindingId() { + assertThrows( + IllegalStateException.class, + () -> UpdateServiceRouteBindingRequest.builder().build()); + } + + @Test + void valid() { + UpdateServiceRouteBindingRequest.builder() + .serviceRouteBindingId("test-service-route-binding-id") + .build(); + } +} diff --git a/integration-test/src/test/java/org/cloudfoundry/client/v3/ServiceRouteBindingsTest.java b/integration-test/src/test/java/org/cloudfoundry/client/v3/ServiceRouteBindingsTest.java new file mode 100644 index 0000000000..133a0c83a8 --- /dev/null +++ b/integration-test/src/test/java/org/cloudfoundry/client/v3/ServiceRouteBindingsTest.java @@ -0,0 +1,499 @@ +/* + * Copyright 2013-2026 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.cloudfoundry.client.v3; + +import static org.cloudfoundry.util.tuple.TupleUtils.function; + +import java.time.Duration; +import java.util.Collections; +import org.cloudfoundry.AbstractIntegrationTest; +import org.cloudfoundry.CloudFoundryVersion; +import org.cloudfoundry.IfCloudFoundryVersion; +import org.cloudfoundry.client.CloudFoundryClient; +import org.cloudfoundry.client.v3.domains.CreateDomainRequest; +import org.cloudfoundry.client.v3.domains.CreateDomainResponse; +import org.cloudfoundry.client.v3.domains.DomainRelationships; +import org.cloudfoundry.client.v3.routes.CreateRouteRequest; +import org.cloudfoundry.client.v3.routes.CreateRouteResponse; +import org.cloudfoundry.client.v3.routes.RouteRelationships; +import org.cloudfoundry.client.v3.serviceinstances.CreateServiceInstanceRequest; +import org.cloudfoundry.client.v3.serviceinstances.CreateServiceInstanceResponse; +import org.cloudfoundry.client.v3.serviceinstances.ServiceInstance; +import org.cloudfoundry.client.v3.serviceinstances.ServiceInstanceRelationships; +import org.cloudfoundry.client.v3.serviceinstances.ServiceInstanceType; +import org.cloudfoundry.client.v3.serviceroutebindings.CreateServiceRouteBindingRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.CreateServiceRouteBindingResponse; +import org.cloudfoundry.client.v3.serviceroutebindings.DeleteServiceRouteBindingRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.GetServiceRouteBindingRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.ListServiceRouteBindingsRequest; +import org.cloudfoundry.client.v3.serviceroutebindings.ServiceRouteBinding; +import org.cloudfoundry.client.v3.serviceroutebindings.ServiceRouteBindingRelationships; +import org.cloudfoundry.client.v3.serviceroutebindings.ServiceRouteBindingResource; +import org.cloudfoundry.client.v3.serviceroutebindings.UpdateServiceRouteBindingRequest; +import org.cloudfoundry.util.JobUtils; +import org.cloudfoundry.util.PaginationUtils; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +@IfCloudFoundryVersion(greaterThanOrEqualTo = CloudFoundryVersion.PCF_2_11) +public class ServiceRouteBindingsTest extends AbstractIntegrationTest { + + @Autowired private CloudFoundryClient cloudFoundryClient; + + @Autowired private Mono organizationId; + + @Autowired private Mono spaceId; + + @Test + public void create() { + String domainName = this.nameFactory.getDomainName(); + String serviceInstanceName = this.nameFactory.getServiceInstanceName(); + + this.organizationId + .flatMap( + organizationId -> + Mono.zip( + createDomainId( + this.cloudFoundryClient, + domainName, + organizationId), + this.spaceId)) + .flatMap( + function( + (domainId, spaceId) -> + Mono.zip( + createRouteId( + this.cloudFoundryClient, domainId, spaceId), + createUserProvidedServiceInstanceId( + this.cloudFoundryClient, + serviceInstanceName, + spaceId)))) + .flatMap( + function( + (routeId, serviceInstanceId) -> + this.cloudFoundryClient + .serviceRouteBindingsV3() + .create( + CreateServiceRouteBindingRequest.builder() + .relationships( + ServiceRouteBindingRelationships + .builder() + .route( + ToOneRelationship + .builder() + .data( + Relationship + .builder() + .id( + routeId) + .build()) + .build()) + .serviceInstance( + ToOneRelationship + .builder() + .data( + Relationship + .builder() + .id( + serviceInstanceId) + .build()) + .build()) + .build()) + .build()))) + .map(response -> response.getServiceRouteBinding().isPresent()) + .as(StepVerifier::create) + .expectNext(true) + .expectComplete() + .verify(Duration.ofMinutes(5)); + } + + @Test + public void delete() { + String domainName = this.nameFactory.getDomainName(); + String serviceInstanceName = this.nameFactory.getServiceInstanceName(); + + this.organizationId + .flatMap( + organizationId -> + Mono.zip( + createDomainId( + this.cloudFoundryClient, + domainName, + organizationId), + this.spaceId)) + .flatMap( + function( + (domainId, spaceId) -> + Mono.zip( + createRouteId( + this.cloudFoundryClient, domainId, spaceId), + createUserProvidedServiceInstanceId( + this.cloudFoundryClient, + serviceInstanceName, + spaceId)))) + .flatMap( + function( + (routeId, serviceInstanceId) -> + createServiceRouteBinding( + this.cloudFoundryClient, + routeId, + serviceInstanceId))) + .map(ServiceRouteBinding::getId) + .flatMap( + bindingId -> + this.cloudFoundryClient + .serviceRouteBindingsV3() + .delete( + DeleteServiceRouteBindingRequest.builder() + .serviceRouteBindingId(bindingId) + .build())) + .hasElement() + .as(StepVerifier::create) + .expectNext(true) + .expectComplete() + .verify(Duration.ofMinutes(5)); + } + + @Test + public void get() { + String domainName = this.nameFactory.getDomainName(); + String serviceInstanceName = this.nameFactory.getServiceInstanceName(); + + this.organizationId + .flatMap( + organizationId -> + Mono.zip( + createDomainId( + this.cloudFoundryClient, + domainName, + organizationId), + this.spaceId)) + .flatMap( + function( + (domainId, spaceId) -> + Mono.zip( + createRouteId( + this.cloudFoundryClient, domainId, spaceId), + createUserProvidedServiceInstanceId( + this.cloudFoundryClient, + serviceInstanceName, + spaceId)))) + .flatMap( + function( + (routeId, serviceInstanceId) -> + createServiceRouteBinding( + this.cloudFoundryClient, + routeId, + serviceInstanceId) + .map(ServiceRouteBinding::getId) + .flatMap( + bindingId -> + this.cloudFoundryClient + .serviceRouteBindingsV3() + .get( + GetServiceRouteBindingRequest + .builder() + .serviceRouteBindingId( + bindingId) + .build())) + .map( + binding -> + binding.getRelationships() + .getServiceInstance() + .getData() + .getId()) + .zipWith(Mono.just(serviceInstanceId)))) + .as(StepVerifier::create) + .consumeNextWith(tupleEquality()) + .expectComplete() + .verify(Duration.ofMinutes(5)); + } + + @Test + public void list() { + String domainName = this.nameFactory.getDomainName(); + String serviceInstanceName = this.nameFactory.getServiceInstanceName(); + + this.organizationId + .flatMap( + organizationId -> + Mono.zip( + createDomainId( + this.cloudFoundryClient, + domainName, + organizationId), + this.spaceId)) + .flatMap( + function( + (domainId, spaceId) -> + Mono.zip( + createRouteId( + this.cloudFoundryClient, domainId, spaceId), + createUserProvidedServiceInstanceId( + this.cloudFoundryClient, + serviceInstanceName, + spaceId)))) + .flatMap( + function( + (routeId, serviceInstanceId) -> + createServiceRouteBinding( + this.cloudFoundryClient, + routeId, + serviceInstanceId) + .thenMany( + requestListServiceRouteBindings( + this.cloudFoundryClient, routeId)) + .map(ServiceRouteBindingResource::getRelationships) + .map( + relationships -> + relationships + .getServiceInstance() + .getData() + .getId()) + .single() + .zipWith(Mono.just(serviceInstanceId)))) + .as(StepVerifier::create) + .consumeNextWith(tupleEquality()) + .expectComplete() + .verify(Duration.ofMinutes(5)); + } + + @Test + public void update() { + String domainName = this.nameFactory.getDomainName(); + String serviceInstanceName = this.nameFactory.getServiceInstanceName(); + + this.organizationId + .flatMap( + organizationId -> + Mono.zip( + createDomainId( + this.cloudFoundryClient, + domainName, + organizationId), + this.spaceId)) + .flatMap( + function( + (domainId, spaceId) -> + Mono.zip( + createRouteId( + this.cloudFoundryClient, domainId, spaceId), + createUserProvidedServiceInstanceId( + this.cloudFoundryClient, + serviceInstanceName, + spaceId)))) + .flatMap( + function( + (routeId, serviceInstanceId) -> + createServiceRouteBinding( + this.cloudFoundryClient, + routeId, + serviceInstanceId))) + .map(ServiceRouteBinding::getId) + .flatMap( + bindingId -> + this.cloudFoundryClient + .serviceRouteBindingsV3() + .update( + UpdateServiceRouteBindingRequest.builder() + .serviceRouteBindingId(bindingId) + .metadata( + Metadata.builder() + .label( + "test-label", + "test-label-value") + .build()) + .build())) + .map(binding -> binding.getMetadata().getLabels()) + .as(StepVerifier::create) + .expectNext(Collections.singletonMap("test-label", "test-label-value")) + .expectComplete() + .verify(Duration.ofMinutes(5)); + } + + private static Mono createDomainId( + CloudFoundryClient cloudFoundryClient, String domainName, String organizationId) { + return requestCreateDomain(cloudFoundryClient, domainName, organizationId) + .map(CreateDomainResponse::getId); + } + + private static Mono createRouteId( + CloudFoundryClient cloudFoundryClient, String domainId, String spaceId) { + return requestCreateRoute(cloudFoundryClient, domainId, spaceId) + .map(CreateRouteResponse::getId); + } + + private static Mono createUserProvidedServiceInstanceId( + CloudFoundryClient cloudFoundryClient, String serviceInstanceName, String spaceId) { + return requestCreateUserProvidedServiceInstance( + cloudFoundryClient, serviceInstanceName, spaceId) + .map( + response -> + response.getServiceInstance() + .map(ServiceInstance::getId) + .orElseThrow( + () -> + new IllegalStateException( + "Service instance not returned" + + " synchronously"))); + } + + private static Mono createServiceRouteBinding( + CloudFoundryClient cloudFoundryClient, String routeId, String serviceInstanceId) { + return requestCreateServiceRouteBinding(cloudFoundryClient, routeId, serviceInstanceId) + .flatMap( + response -> { + if (response.getJobId().isPresent()) { + return JobUtils.waitForCompletion( + cloudFoundryClient, + Duration.ofMinutes(5), + response.getJobId().get()) + .thenMany( + requestListServiceRouteBindingsByServiceInstance( + cloudFoundryClient, serviceInstanceId)) + .single(); + } + return Mono.just(response.getServiceRouteBinding().get()); + }); + } + + private static Mono requestCreateDomain( + CloudFoundryClient cloudFoundryClient, String domainName, String organizationId) { + return cloudFoundryClient + .domainsV3() + .create( + CreateDomainRequest.builder() + .internal(false) + .name(domainName) + .relationships( + DomainRelationships.builder() + .organization( + ToOneRelationship.builder() + .data( + Relationship.builder() + .id(organizationId) + .build()) + .build()) + .build()) + .build()); + } + + private static Mono requestCreateRoute( + CloudFoundryClient cloudFoundryClient, String domainId, String spaceId) { + return cloudFoundryClient + .routesV3() + .create( + CreateRouteRequest.builder() + .relationships( + RouteRelationships.builder() + .domain( + ToOneRelationship.builder() + .data( + Relationship.builder() + .id(domainId) + .build()) + .build()) + .space( + ToOneRelationship.builder() + .data( + Relationship.builder() + .id(spaceId) + .build()) + .build()) + .build()) + .build()); + } + + private static Mono requestCreateUserProvidedServiceInstance( + CloudFoundryClient cloudFoundryClient, String serviceInstanceName, String spaceId) { + return cloudFoundryClient + .serviceInstancesV3() + .create( + CreateServiceInstanceRequest.builder() + .type(ServiceInstanceType.USER_PROVIDED) + .name(serviceInstanceName) + .routeServiceUrl("https://route-service.example.com") + .relationships( + ServiceInstanceRelationships.builder() + .space( + ToOneRelationship.builder() + .data( + Relationship.builder() + .id(spaceId) + .build()) + .build()) + .build()) + .build()); + } + + private static Mono requestCreateServiceRouteBinding( + CloudFoundryClient cloudFoundryClient, String routeId, String serviceInstanceId) { + return cloudFoundryClient + .serviceRouteBindingsV3() + .create( + CreateServiceRouteBindingRequest.builder() + .relationships( + ServiceRouteBindingRelationships.builder() + .route( + ToOneRelationship.builder() + .data( + Relationship.builder() + .id(routeId) + .build()) + .build()) + .serviceInstance( + ToOneRelationship.builder() + .data( + Relationship.builder() + .id( + serviceInstanceId) + .build()) + .build()) + .build()) + .build()); + } + + private static Flux requestListServiceRouteBindings( + CloudFoundryClient cloudFoundryClient, String routeId) { + return PaginationUtils.requestClientV3Resources( + page -> + cloudFoundryClient + .serviceRouteBindingsV3() + .list( + ListServiceRouteBindingsRequest.builder() + .page(page) + .routeId(routeId) + .build())); + } + + private static Flux + requestListServiceRouteBindingsByServiceInstance( + CloudFoundryClient cloudFoundryClient, String serviceInstanceId) { + return PaginationUtils.requestClientV3Resources( + page -> + cloudFoundryClient + .serviceRouteBindingsV3() + .list( + ListServiceRouteBindingsRequest.builder() + .page(page) + .serviceInstanceId(serviceInstanceId) + .build())); + } +}