Skip to content
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,59 @@ The `cf-java-client` project is a Java language binding for interacting with a C
## Versions
The Cloud Foundry Java Client has two active versions. The `5.x` line is compatible with Spring Boot `2.4.x - 2.6.x` just to manage its dependencies, while the `4.x` line uses Spring Boot `2.3.x`.

## Deprecations

### `DopplerClient.recentLogs()` — Recent Logs via Doppler

> [!WARNING]
> **Deprecated since cf-java-client `5.17.x`**
>
> The `DopplerClient.recentLogs()` endpoint (and the related `RecentLogsRequest` / `LogMessage` types from the `org.cloudfoundry.doppler` package) are **deprecated** and will be removed in a future release.
>
> This API relies on the [Loggregator][loggregator] Doppler/Traffic Controller endpoint `/apps/{id}/recentlogs`, which was removed in **Loggregator ≥ 107.0**.
> The affected platform versions are:
>
> | Platform | Last version with Doppler recent-logs support |
> | -------- | --------------------------------------------- |
> | CF Deployment (CFD) | `< 24.3` |
> | Tanzu Application Service (TAS) | `< 4.0` |
>
> **Migration:** Replace any call to `DopplerClient.recentLogs()` with [`LogCacheClient.read()`][log-cache-api] (available via `org.cloudfoundry.logcache.v1.LogCacheClient`).
>
> ```java
> // Before (deprecated)
> dopplerClient.recentLogs(RecentLogsRequest.builder()
> .applicationId(appId)
> .build());
>
> // After
> logCacheClient.read(ReadRequest.builder()
> .sourceId(appId)
> .envelopeTypes(EnvelopeType.LOG)
> .build());
> ```
>
> The return type and envelope objects differ between the two APIs:
>
> | | Doppler (`org.cloudfoundry.doppler`) | Log Cache (`org.cloudfoundry.logcache.v1`) |
> |---|---|---|
> | **Return type** | `Flux<Envelope>` | `Mono<ReadResponse>` → unpack via `response.getEnvelopes().getBatch()` |
> | **Log access** | `envelope.getLogMessage()` → `LogMessage` | `envelope.getLog()` → `Log` |
> | **Message text** | `logMessage.getMessage()` | `log.getPayloadAsText()` |
> | **Message type** | `MessageType.OUT` / `ERR` | `LogType.OUT` / `ERR` |
> | **Source metadata** | `logMessage.getSourceType()`, `.getSourceInstance()` | `envelope.getTags().get("source_type")`, `envelope.getInstanceId()` |
>
> See the [`org.cloudfoundry.doppler`][doppler-pkg] and [`org.cloudfoundry.logcache.v1`][logcache-pkg] Javadoc for full type details.

[doppler-pkg]: https://javadoc.io/doc/org.cloudfoundry/cloudfoundry-client/latest/org/cloudfoundry/doppler/package-summary.html
[logcache-pkg]: https://javadoc.io/doc/org.cloudfoundry/cloudfoundry-client/latest/org/cloudfoundry/logcache/v1/package-summary.html

> [!NOTE]
> **Operations API users:** `Applications.logs(ApplicationLogsRequest)` now uses Log Cache under the hood for recent logs (the default). No migration is needed at the Operations layer.

[loggregator]: https://github.com/cloudfoundry/loggregator
[log-cache-api]: https://github.com/cloudfoundry/log-cache

## Dependencies
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:

Expand Down Expand Up @@ -76,6 +129,9 @@ Both the `cloudfoundry-operations` and `cloudfoundry-client` projects follow a [

### `CloudFoundryClient`, `DopplerClient`, `UaaClient` Builders

> [!NOTE]
> **`DopplerClient` — partial deprecation:** The `recentLogs()` method on `DopplerClient` is deprecated and only works against Loggregator \< 107.0 (CFD \< 24.3 / TAS \< 4.0). See the [Deprecations](#deprecations) section above for the migration path to `LogCacheClient`.

The lowest-level building blocks of the API are `ConnectionContext` and `TokenProvider`. These types are intended to be shared between instances of the clients, and come with out of the box implementations. To instantiate them, you configure them with builders:

```java
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static org.cloudfoundry.uaa.tokens.GrantType.AUTHORIZATION_CODE;
import static org.cloudfoundry.uaa.tokens.GrantType.CLIENT_CREDENTIALS;
import static org.cloudfoundry.uaa.tokens.GrantType.JWT_BEARER;
import static org.cloudfoundry.uaa.tokens.GrantType.REFRESH_TOKEN;

import java.time.Duration;
Expand Down Expand Up @@ -620,6 +621,7 @@ void get() {
.allowedProviders("uaa", "ldap", "my-saml-provider")
.authorities("clients.read", "clients.write")
.authorizedGrantType(CLIENT_CREDENTIALS)
.authorizedGrantType(JWT_BEARER)
.autoApprove("true")
.clientId("4Z3t1r")
.lastModified(1468364445592L)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,8 @@ void list() {
+ " /passcode)")
.build())
.ldapDiscoveryEnabled(false)
.defaultIdentityProvider(
"test-identity-provider")
.accountChooserEnabled(false)
.build())
.name("The Twiglet Zone")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ void getInfo() {
.showLoginLinks(true)
.timestamp("2017-09-08T23:11:58+0000")
.zoneName("uaa")
.defaultIdpName("test-idp-name")
.build())
.expectComplete()
.verify(Duration.ofSeconds(5));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"none"
],
"authorized_grant_types": [
"client_credentials"
"client_credentials",
"urn:ietf:params:oauth:grant-type:jwt-bearer"
],
"redirect_uri": [
"http*://ant.path.wildcard/**/passback/*",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
"text": "One Time Code (Get on at /passcode)"
}
],
"defaultIdentityProvider": "test-identity-provider",
"idpDiscoveryEnabled": false,
"accountChooserEnabled": false
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@
"One Time Code ( Get one at http://localhost:8080/uaa/passcode )"
]
},
"timestamp": "2017-09-08T23:11:58+0000"
"timestamp": "2017-09-08T23:11:58+0000",
"defaultIdpName": "test-idp-name"
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,15 @@ public interface DopplerClient {
/**
* Makes the <a href="https://github.com/cloudfoundry/loggregator/tree/develop/src/trafficcontroller#endpoints">Recent Logs</a> request
*
* @deprecated Use {@link org.cloudfoundry.logcache.v1.LogCacheClient#read(org.cloudfoundry.logcache.v1.ReadRequest)} instead.
* Only works with {@code Loggregator < 107.0}, shipped in {@code CFD < 24.3} and {@code TAS < 4.0}.
* @param request the Recent Logs request
* @return the events from the recent logs
* @return a flux of events from the recent logs
* @see <a href="https://github.com/cloudfoundry/loggregator">Loggregator</a>
* @see <a href="https://github.com/cloudfoundry/log-cache">Log Cache</a>
* @see org.cloudfoundry.logcache.v1.LogCacheClient#read(org.cloudfoundry.logcache.v1.ReadRequest)
*/
@Deprecated
Flux<Envelope> recentLogs(RecentLogsRequest request);

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ abstract class _IdentityZoneConfiguration {
@Nullable
abstract CorsPolicy getCorsPolicy();

/**
* The default identity provider for this zone
*/
@JsonProperty("defaultIdentityProvider")
@Nullable
abstract String getDefaultIdentityProvider();

/**
* The issuer of this zone
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,12 @@ abstract class _GetInfoResponse {
@Nullable
abstract String getZoneName();

/**
* The default identity provider name
*/
@JsonProperty("defaultIdpName")
@Nullable
abstract String getDefaultIdpName();


}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ public enum GrantType {
*/
IMPLICIT("implicit"),

/**
* The JWT bearer grant type
*/
JWT_BEARER("urn:ietf:params:oauth:grant-type:jwt-bearer"),

/**
* The password grant type
*/
Expand Down Expand Up @@ -68,6 +73,8 @@ public static GrantType from(String s) {
return PASSWORD;
case "refresh_token":
return REFRESH_TOKEN;
case "urn:ietf:params:oauth:grant-type:jwt-bearer":
return JWT_BEARER;
default:
throw new IllegalArgumentException(String.format("Unknown grant type: %s", s));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.cloudfoundry.client.v3.spaces.ListSpacesRequest;
import org.cloudfoundry.client.v3.spaces.SpaceResource;
import org.cloudfoundry.doppler.DopplerClient;
import org.cloudfoundry.logcache.v1.LogCacheClient;
import org.cloudfoundry.networking.NetworkingClient;
import org.cloudfoundry.operations.advanced.Advanced;
import org.cloudfoundry.operations.advanced.DefaultAdvanced;
Expand Down Expand Up @@ -79,7 +80,7 @@ public Advanced advanced() {
@Override
@Value.Derived
public Applications applications() {
return new DefaultApplications(getCloudFoundryClientPublisher(), getDopplerClientPublisher(), getSpaceId());
return new DefaultApplications(getCloudFoundryClientPublisher(), getDopplerClientPublisher(), getLogCacheClientPublisher(), getSpaceId());
}

@Override
Expand Down Expand Up @@ -197,6 +198,19 @@ Mono<DopplerClient> getDopplerClientPublisher() {
.orElse(Mono.error(new IllegalStateException("DopplerClient must be set")));
}

/**
* The {@link LogCacheClient} to use for operations functionality
*/
@Nullable
abstract LogCacheClient getLogCacheClient();

@Value.Derived
Mono<LogCacheClient> getLogCacheClientPublisher() {
return Optional.ofNullable(getLogCacheClient())
.map(Mono::just)
.orElse(Mono.error(new IllegalStateException("LogCacheClient must be set")));
}

/**
* The {@link NetworkingClient} to use for operations functionality
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,9 @@ public interface Applications {

/**
* List the applications logs.
* Only works with {@code Loggregator < 107.0}, shipped in {@code CFD < 24.3}
* and {@code TAS < 4.0}.
* Uses Log Cache under the hood when {@link ApplicationLogsRequest#getRecent()} is {@code true}.
* Log streaming still uses Doppler, which is not available in CF deployments following
* <a href="https://docs.cloudfoundry.org/loggregator/architecture.html#shared-nothing-architecture">shared-nothing architecture</a>.
*
* @param request the application logs request
* @return the applications logs
Expand Down
Loading
Loading