The cf-java-client
project is a Java language binding for interacting with a Cloud Foundry instance. The project is broken up into a number of components which expose different levels of abstraction depending on need.
cloudfoundry-client
– Interfaces, request, and response objects mapping to the Cloud Foundry REST APIs. This project has no implementation and therefore cannot connect a Cloud Foundry instance on its own.cloudfoundry-client-spring
– The default implementation of thecloudfoundry-client
project. This implementation is based on the Spring FrameworkRestTemplate
.cloudfoundry-operations
– An API and implementation that corresponds to the Cloud Foundry CLI operations. This project builds on thecloudfoundry-cli
and therefore has a single implementation.cloudfoundry-maven-plugin
/cloudfoundry-gradle-plugin
– Build plugins for Maven and Gradle. These projects build oncloudfoundry-operations
and therefore have single implementations.
Most projects will need two dependencies; the Operations API and an implementation of the Client API. For Maven, the dependencies would be defined like this:
<dependencies>
<dependency>
<groupId>org.cloudfoundry</groupId>
<artifactId>cloudfoundry-client-spring</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.cloudfoundry</groupId>
<artifactId>cloudfoundry-operations</artifactId>
<version>2.0.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>2.5.0.BUILD-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-netty</artifactId>
<version>2.5.0.BUILD-SNAPSHOT</version>
</dependency>
...
</dependencies>
The artifacts can be found in the Spring release and snapshot repositories:
<repositories>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>http://repo.spring.io/release</url>
</repository>
...
</repositories>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>http://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
...
</repositories>
For Gradle, the dependencies would be defined like this:
dependencies {
compile 'org.cloudfoundry:cloudfoundry-client-spring:2.0.0.BUILD-SNAPSHOT'
compile 'org.cloudfoundry:cloudfoundry-operations:2.0.0.BUILD-SNAPSHOT'
compile 'io.projectreactor:reactor-core:2.5.0.BUILD-SNAPSHOT'
compile 'io.projectreactor:reactor-netty:2.5.0.BUILD-SNAPSHOT'
...
}
The artifacts can be found in the Spring release and snapshot repositories:
repositories {
maven { url 'http://repo.spring.io/release' }
...
}
repositories {
maven { url 'http://repo.spring.io/snapshot' }
...
}
Both the cloudfoundry-operations
and cloudfoundry-client
projects follow a "Reactive" design pattern and expose their responses with Project Reactor Monos
s and Flux
s.
The lowest-level building block of the API is a CloudFoundryClient
. This is only an interface and the default implementation of this is the SpringCloudFoundryClient
. To instantiate one, you configure it with a builder:
SpringCloudFoundryClient.builder()
.host("api.run.pivotal.io")
.username("example-username")
.password("example-password")
.build();
In Spring-based applications, you'll want to encapsulate this in a bean definition:
@Bean
CloudFoundryClient cloudFoundryClient(@Value("${cf.host}") String host,
@Value("${cf.username}") String username,
@Value("${cf.password}") String password) {
return SpringCloudFoundryClient.builder()
.host(host)
.username(username)
.password(password)
.build();
}
The CloudFoundryClient
provides direct access to the raw REST APIs. This level of abstraction provides the most detailed and powerful access to the Cloud Foundry instance, but also requires users to perform quite a lot of orchestration on their own. Most users will instead want to work at the CloudFoundryOperations
layer. Once again this is only an interface and the default implementation of this is the DefaultCloudFoundryOperations
. To instantiate one, you configure it with a builder:
new CloudFoundryOperationsBuilder()
.cloudFoundryClient(cloudFoundryClient)
.target("example-organization", "example-space")
.build();
In Spring-based applications, you'll want to encapsulate this in a bean definition as well:
@Bean
CloudFoundryOperations cloudFoundryOperations(CloudFoundryClient cloudFoundryClient,
@Value("${cf.organization}") String organization,
@Value("${cf.space}") String space) {
return new CloudFoundryOperationsBuilder()
.cloudFoundryClient(cloudFoundryClient)
.target(organization, space)
.build();
}
Once you've got a reference to the CloudFoundryOperations
, it's time to start making calls to the Cloud Foundry instance. One of the simplest possible operations is list all of the organizations the user is a member of. The following example does three things:
- Requests a list of all organizations
- Extracts the name of each organization
- Prints the name of the each organization to
System.out
cloudFoundryOperations.organizations()
.list()
.map(Organization::getName)
.subscribe(System.out::println);
To relate the example to the description above the following happens:
.list()
– Lists the Cloud Foundry organizations as aFlux
of elements of typeOrganization
..map(...)
– Maps each organization to its name (typeString
). This example uses a method reference; the equivalent lambda would look likeorganization -> organization.getName()
.subscribe...
– The terminal operation that receives each name in theFlux
. Again, this example uses a method reference and the equivalent lambda would look likename -> System.out.println(name)
.
As mentioned earlier, the cloudfoundry-operations
implementation builds upon the cloudfoundry-client
API. That implementation takes advantage of the same reactive style in the lower-level API. The implementation of the Organizations.list()
method (which was demonstrated above) looks like the following (roughly):
cloudFoundryClient.organizations()
.list(ListOrganizationsRequest.builder()
.page(1)
.build())
.flatMap(response -> Flux.fromIterable(response.getResources))
.map(resource -> Organization.builder()
.id(resource.getMetadata().getId())
.name(resource.getEntity().getName())
.build());
The above example is more complicated:
.list(...)
– Retrieves a page of Cloud Foundry organizations..flatMap(...)
– Substitutes the originalMono
with aFlux
of theResource
s returned by the requested page..map(...)
– Maps theResource
to anOrganization
type.
TODO: Document once implemented
TODO: Document once implemented
API Documentation for each module can be found at the following locations:
cloudfoundry-client
–release
,milestone
,snapshot
cloudfoundry-client-spring
–release
,milestone
,snapshot
cloudfoundry-operations
–release
,milestone
,snapshot
cloudfoundry-util
–release
,milestone
,snapshot
The project depends on Java 8. To build from source and install to your local Maven cache, run the following:
$ ./mvnw clean install
To run the integration tests, run the following:
$ ./mvnw -Pintegration-test clean test
IMPORTANT Integration tests should be run against an empty Cloud Foundry instance. The integration tests are destructive, nearly everything on an instance given the chance.
The integration tests require a running instance of Cloud Foundry to test against. We recommend using PCF Dev to start a local instance to test with. To configure the integration tests with the appropriate connection information use the following environment variables:
Name | Description |
---|---|
TEST_HOST |
The host of Cloud Foundry instance. Typically something like api.local.pcfdev.io . |
TEST_PASSWORD |
The test user's password |
TEST_PROTECTED_DOMAIN |
A domain that will not be cleaned up |
TEST_PROTECTED_FEATUREFLAGS |
A list of feature flags that will not be (re)set to standard values on cleanup |
TEST_PROTECTED_ORGANIZATION |
An organization who's contents will not be cleaned up |
TEST_SKIPSSLVALIDATION |
Whether to skip SSL validation when connecting to the Cloud Foundry instance. Typically true when connecting to a PCF Dev instance. |
TEST_USERNAME |
The test user's username |
Pull requests and Issues are welcome.
This project is released under version 2.0 of the Apache License.