Skip to content

Commit

Permalink
Merge pull request #1726 from stripe/richardm/merge-java-beta
Browse files Browse the repository at this point in the history
Merge java beta
  • Loading branch information
richardm-stripe authored Jan 17, 2024
2 parents e8bd408 + 39432ab commit 8ffb825
Show file tree
Hide file tree
Showing 143 changed files with 718 additions and 82 deletions.
4 changes: 4 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ tasks.withType(JavaCompile) {
// com.stripe.param.AccountUpdateParams.Individual.Address] within this file.)
// We should fix this by having autogen use the fully-qualified class to eliminate ambiguity.
check("SameNameButDifferent", net.ltgt.gradle.errorprone.CheckSeverity.OFF)

// InlineMe (https://errorprone.info/docs/inlineme) seems neat, but in order to add these annotations
// we would be imposing another dependency on `errorprone` to our users, not worth it.
check("InlineMeSuggester", net.ltgt.gradle.errorprone.CheckSeverity.OFF)
}
}

Expand Down
33 changes: 31 additions & 2 deletions src/main/java/com/stripe/net/ApiRequest.java
Original file line number Diff line number Diff line change
@@ -1,20 +1,49 @@
package com.stripe.net;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import lombok.Getter;

@Getter
public class ApiRequest extends BaseApiRequest {
private Map<String, Object> params;

private ApiRequest(
BaseAddress baseAddress,
ApiResource.RequestMethod method,
String path,
RequestOptions options,
ApiMode apiMode,
List<String> usage,
Map<String, Object> params) {
super(baseAddress, method, path, options, apiMode, usage);
this.params = params;
}

public ApiRequest(
BaseAddress baseAddress,
ApiResource.RequestMethod method,
String path,
Map<String, Object> params,
RequestOptions options,
ApiMode apiMode) {
super(baseAddress, method, path, options, apiMode);
this.params = params;
this(baseAddress, method, path, options, apiMode, null, params);
}

public ApiRequest addUsage(String usage) {
List<String> newUsage = new ArrayList<>();
if (this.getUsage() != null) {
newUsage.addAll(this.getUsage());
}
newUsage.add(usage);
return new ApiRequest(
this.getBaseAddress(),
this.getMethod(),
this.getPath(),
this.getOptions(),
this.getApiMode(),
newUsage,
this.getParams());
}
}
32 changes: 14 additions & 18 deletions src/main/java/com/stripe/net/BaseApiRequest.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
package com.stripe.net;

import java.util.List;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;

@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
class BaseApiRequest {
private BaseAddress baseAddress;
private ApiResource.RequestMethod method;
private String path;
private RequestOptions options;
private ApiMode apiMode;
private final BaseAddress baseAddress;
private final ApiResource.RequestMethod method;
private final String path;
private final RequestOptions options;
private final ApiMode apiMode;

@Setter private List<String> usage;
// TODO (major): Remove setter and make final
private List<String> usage;

public BaseApiRequest(
BaseAddress baseAddress,
ApiResource.RequestMethod method,
String path,
RequestOptions options,
ApiMode apiMode) {
this.baseAddress = baseAddress;
this.method = method;
this.path = path;
this.options = options;
this.apiMode = apiMode;
/** @deprecated Use {@link com.stripe.net.ApiRequest#addUsage(String)} instead. */
@Deprecated
public void setUsage(List<String> usage) {
this.usage = usage;
}
}
41 changes: 8 additions & 33 deletions src/main/java/com/stripe/net/HttpClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,11 @@
import com.stripe.Stripe;
import com.stripe.exception.ApiConnectionException;
import com.stripe.exception.StripeException;
import com.stripe.util.Stopwatch;
import java.net.ConnectException;
import java.net.SocketTimeoutException;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ThreadLocalRandom;

/** Base abstract class for HTTP clients used to send requests to Stripe's API. */
Expand All @@ -20,8 +18,6 @@ public abstract class HttpClient {
/** Minimum sleep time between tries to send HTTP requests after network failure. */
public static final Duration minNetworkRetriesDelay = Duration.ofMillis(500);

private final RequestTelemetry requestTelemetry = new RequestTelemetry();

/** A value indicating whether the client should sleep between automatic request retries. */
boolean networkRetriesSleep = true;

Expand Down Expand Up @@ -52,48 +48,27 @@ public StripeResponseStream requestStream(StripeRequest request) throws StripeEx
private interface RequestSendFunction<R> {
R apply(StripeRequest request) throws StripeException;
}

private <T extends AbstractStripeResponse<?>> T sendWithTelemetry(
StripeRequest request, RequestSendFunction<T> send) throws StripeException {
Optional<String> telemetryHeaderValue = requestTelemetry.getHeaderValue(request.headers());
if (telemetryHeaderValue.isPresent()) {
request =
request.withAdditionalHeader(RequestTelemetry.HEADER_NAME, telemetryHeaderValue.get());
}

Stopwatch stopwatch = Stopwatch.startNew();

T response = send.apply(request);

stopwatch.stop();

requestTelemetry.maybeEnqueueMetrics(response, stopwatch.getElapsed());

return response;
}

/**
* Sends the given request to Stripe's API, handling telemetry if not disabled.
*
* @param request the request
* @return the response
* @throws StripeException If the request fails for any reason
* @deprecated Use {@link #request(StripeRequest)} instead.
*/
@Deprecated
public StripeResponse requestWithTelemetry(StripeRequest request) throws StripeException {
return sendWithTelemetry(request, this::request);
return this.request(request);
}

/**
* Sends the given request to Stripe's API, streaming the response, and handling telemetry if not
* disabled.
*
* @param request the request
* @return the response
* @throws StripeException If the request fails for any reason
* @deprecated Use {@link #requestStream(StripeRequest)} instead.
*/
@Deprecated
public StripeResponseStream requestStreamWithTelemetry(StripeRequest request)
throws StripeException {
return sendWithTelemetry(request, this::requestStream);
return this.requestStream(request);
}

public <T extends AbstractStripeResponse<?>> T sendWithRetries(
Expand Down Expand Up @@ -142,7 +117,7 @@ public <T extends AbstractStripeResponse<?>> T sendWithRetries(
* @throws StripeException If the request fails for any reason
*/
public StripeResponse requestWithRetries(StripeRequest request) throws StripeException {
return sendWithRetries(request, (r) -> this.requestWithTelemetry(r));
return sendWithRetries(request, (r) -> this.request(r));
}

/**
Expand All @@ -155,7 +130,7 @@ public StripeResponse requestWithRetries(StripeRequest request) throws StripeExc
*/
public StripeResponseStream requestStreamWithRetries(StripeRequest request)
throws StripeException {
return sendWithRetries(request, (r) -> this.requestStreamWithTelemetry(r));
return sendWithRetries(request, (r) -> this.requestStream(r));
}

/**
Expand Down
61 changes: 51 additions & 10 deletions src/main/java/com/stripe/net/LiveStripeResponseGetter.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,40 @@
import com.stripe.exception.oauth.UnsupportedResponseTypeException;
import com.stripe.model.*;
import com.stripe.model.oauth.OAuthError;
import com.stripe.util.Stopwatch;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class LiveStripeResponseGetter implements StripeResponseGetter {
private final HttpClient httpClient;
private final StripeResponseGetterOptions options;

private final RequestTelemetry requestTelemetry = new RequestTelemetry();

@FunctionalInterface
private interface RequestSendFunction<R> {
R apply(StripeRequest request) throws StripeException;
}

private <T extends AbstractStripeResponse<?>> T sendWithTelemetry(
StripeRequest request, List<String> usage, RequestSendFunction<T> send)
throws StripeException {

Stopwatch stopwatch = Stopwatch.startNew();

T response = send.apply(request);

stopwatch.stop();

requestTelemetry.maybeEnqueueMetrics(response, stopwatch.getElapsed(), usage);

return response;
}

/**
* Initializes a new instance of the {@link LiveStripeResponseGetter} class with default
* parameters.
Expand All @@ -46,17 +71,26 @@ public LiveStripeResponseGetter(StripeResponseGetterOptions options, HttpClient
private StripeRequest toStripeRequest(ApiRequest apiRequest) throws StripeException {
String fullUrl = fullUrl(apiRequest);

return new StripeRequest(
apiRequest.getMethod(),
fullUrl,
apiRequest.getParams(),
RequestOptions.merge(this.options, apiRequest.getOptions()));
Optional<String> telemetryHeaderValue = requestTelemetry.pollPayload();
StripeRequest request =
new StripeRequest(
apiRequest.getMethod(),
fullUrl,
apiRequest.getParams(),
RequestOptions.merge(this.options, apiRequest.getOptions()));

if (telemetryHeaderValue.isPresent()) {
request =
request.withAdditionalHeader(RequestTelemetry.HEADER_NAME, telemetryHeaderValue.get());
}
return request;
}

private StripeRequest toRawStripeRequest(RawApiRequest apiRequest) throws StripeException {
String fullUrl = fullUrl(apiRequest);

StripeRequest stripeRequest =
Optional<String> telemetryHeaderValue = requestTelemetry.pollPayload();
StripeRequest request =
StripeRequest.createWithStringContent(
apiRequest.getMethod(),
fullUrl,
Expand All @@ -65,9 +99,13 @@ private StripeRequest toRawStripeRequest(RawApiRequest apiRequest) throws Stripe
apiRequest.getApiMode() == ApiMode.PREVIEW);

if (apiRequest.getApiMode() == ApiMode.PREVIEW) {
return stripeRequest.withAdditionalHeader("Stripe-Version", Stripe.PREVIEW_API_VERSION);
request = request.withAdditionalHeader("Stripe-Version", Stripe.PREVIEW_API_VERSION);
}
return stripeRequest;
if (telemetryHeaderValue.isPresent()) {
request =
request.withAdditionalHeader(RequestTelemetry.HEADER_NAME, telemetryHeaderValue.get());
}
return request;
}

@Override
Expand All @@ -76,7 +114,8 @@ public <T extends StripeObjectInterface> T request(ApiRequest apiRequest, Type t
throws StripeException {

StripeRequest request = toStripeRequest(apiRequest);
StripeResponse response = httpClient.requestWithRetries(request);
StripeResponse response =
sendWithTelemetry(request, apiRequest.getUsage(), r -> httpClient.requestWithRetries(r));

int responseCode = response.code();
String responseBody = response.body();
Expand Down Expand Up @@ -106,7 +145,9 @@ public <T extends StripeObjectInterface> T request(ApiRequest apiRequest, Type t
@Override
public InputStream requestStream(ApiRequest apiRequest) throws StripeException {
StripeRequest request = toStripeRequest(apiRequest);
StripeResponseStream responseStream = httpClient.requestStreamWithRetries(request);
StripeResponseStream responseStream =
sendWithTelemetry(
request, apiRequest.getUsage(), r -> httpClient.requestStreamWithRetries(r));

int responseCode = responseStream.code();

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/stripe/net/RawApiRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public RawApiRequest(
String rawContent,
RawRequestOptions options,
ApiMode apiMode) {
super(baseAddress, method, path, options, apiMode);
super(baseAddress, method, path, options, apiMode, null);
this.rawContent = rawContent;
this.options = options;
}
Expand Down
30 changes: 28 additions & 2 deletions src/main/java/com/stripe/net/RequestTelemetry.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.google.gson.annotations.SerializedName;
import com.stripe.Stripe;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ConcurrentLinkedQueue;
import lombok.Data;
Expand All @@ -26,12 +28,18 @@ class RequestTelemetry {
* metrics, or if telemetry is disabled, then the returned {@code Optional} is empty.
*
* @param headers the request headers
* @deprecated Use {$ling {@link #pollPayload()} instead.
*/
@Deprecated
public Optional<String> getHeaderValue(HttpHeaders headers) {
if (headers.firstValue(HEADER_NAME).isPresent()) {
return Optional.empty();
}

return this.pollPayload();
}

public Optional<String> pollPayload() {
RequestMetrics requestMetrics = prevRequestMetrics.poll();
if (requestMetrics == null) {
return Optional.empty();
Expand All @@ -45,14 +53,25 @@ public Optional<String> getHeaderValue(HttpHeaders headers) {
return Optional.of(gson.toJson(payload));
}

// TODO (major) remove this overload
/**
* @deprecated use {@link #maybeEnqueueMetrics(AbstractStripeResponse, Duration, List)} instead.
*/
@Deprecated
public void maybeEnqueueMetrics(AbstractStripeResponse<?> response, Duration duration) {
maybeEnqueueMetrics(response, duration, new ArrayList<String>());
}

/**
* If telemetry is enabled and the queue is not full, then enqueue a new metrics item; otherwise,
* do nothing.
*
* @param response the Stripe response
* @param duration the request duration
* @param usage a list of tracked features used by the corresponding request
*/
public void maybeEnqueueMetrics(AbstractStripeResponse<?> response, Duration duration) {
public void maybeEnqueueMetrics(
AbstractStripeResponse<?> response, Duration duration, List<String> usage) {
if (!Stripe.enableTelemetry) {
return;
}
Expand All @@ -65,7 +84,11 @@ public void maybeEnqueueMetrics(AbstractStripeResponse<?> response, Duration dur
return;
}

RequestMetrics metrics = new RequestMetrics(response.requestId(), duration.toMillis());
if (usage != null && usage.size() == 0) {
usage = null;
}

RequestMetrics metrics = new RequestMetrics(response.requestId(), duration.toMillis(), usage);
prevRequestMetrics.add(metrics);
}

Expand All @@ -82,5 +105,8 @@ private static class RequestMetrics {

@SerializedName("request_duration_ms")
private final long requestDurationMs;

@SerializedName("usage")
private final List<String> usage;
}
}
Loading

0 comments on commit 8ffb825

Please sign in to comment.