Consider a sample use case - Given an application id I need to find a little more detail of this application, more details of the application along with the details of the organization and the space that it belongs to.
To start with, the basis of all API operations with cf-java-client is a type unsurprisingly called the CloudFoundryClient(org.cloudfoundry.client.CloudFoundryClient), cf-java-client's github page has details on how to get hold of an instance of this type.
Given a CloudFoundryClient instance, the details of an application given its id can be obtained as follows:
Mono<GetApplicationResponse> applicationResponseMono = this.cloudFoundryClient .applicationsV2().get(GetApplicationRequest.builder().applicationId(applicationId).build());
Note that the API returns a reactor "Mono" type, this is in general the behavior of all the API calls of cf-java-client.
- If an API returns one item then typically a Mono type is returned
- If the API is expected to return more than one item then a Flux type is returned, and
- If the API is called purely for side effects - say printing some information then it returns a Mono<Void> type
The next step is to retrieve the space identifier from the response and make an API call to retrieve the details of the space and looks like this:
Mono<Tuple2<GetApplicationResponse, GetSpaceResponse>> appAndSpaceMono = applicationResponseMono .and(appResponse -> this.cloudFoundryClient.spaces() .get(GetSpaceRequest.builder() .spaceId(appResponse.getEntity().getSpaceId()).build()));
Here I am using an "and" operator to combine the application response with another Mono that returns the space information, the result is a "Tuple2" type holding both the pieces of information - the application detail and the detail of the space that it is in.
Finally to retrieve the Organization that the app is deployed in:
Mono<Tuple3<GetApplicationResponse, GetSpaceResponse, GetOrganizationResponse>> t3 = appAndSpaceMono.then(tup2 -> this.cloudFoundryClient.organizations() .get(GetOrganizationRequest.builder() .organizationId(tup2.getT2().getEntity() .getOrganizationId()) .build()) .map(orgResp -> Tuples.of(tup2.getT1(), tup2.getT2(), orgResp)));
Here a "then" operation is being used to retrieve the organization detail given the id from the previous step and the result added onto the previous tuple to create a Tuple3 type holding the "Application Detail", "Space Detail" and the "Organization Detail". "then" is the equivalent of flatMap operator familiar in the Scala and ReactiveX world.
This essentially covers the way you would typically deal with "cf-java-client" library and use the fact that it is built on the excellent "Reactor" library and its collection of very useful operators to get results together. Just to take the final step of transforming the result to a type that may be more relevant to your domain and to handle any errors along the way:
Mono<AppDetail> appDetail = t3.map(tup3 -> { String appName = tup3.getT1().getEntity().getName(); String spaceName = tup3.getT2().getEntity().getName(); String orgName = tup3.getT3().getEntity().getName(); return new AppDetail(appName, orgName, spaceName); }).otherwiseReturn(new AppDetail("", "", ""));
If you are interested in trying out a working sample, I have an example available in my github repo here - https://github.com/bijukunjummen/boot-firehose-to-syslog
And the code shown in the article is available here - https://github.com/bijukunjummen/boot-firehose-to-syslog/blob/master/src/main/java/io.pivotal.cf.nozzle/service/CfAppDetailsService.java
No comments:
Post a Comment