Skip to content

Commit 32c9995

Browse files
authored
fix: Return resolved endpoint from StubSettings' Builder (#2715)
1 parent 8f21be6 commit 32c9995

File tree

7 files changed

+85
-46
lines changed

7 files changed

+85
-46
lines changed

gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcCallContext.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,8 @@ private GrpcCallContext(
154154
this.retryableCodes = retryableCodes == null ? null : ImmutableSet.copyOf(retryableCodes);
155155
// Attempt to create an empty, non-functioning EndpointContext by default. The client will have
156156
// a valid EndpointContext with user configurations after the client has been initialized.
157-
try {
158-
this.endpointContext =
159-
endpointContext == null ? EndpointContext.newBuilder().build() : endpointContext;
160-
} catch (IOException ex) {
161-
throw new RuntimeException(ex);
162-
}
157+
this.endpointContext =
158+
endpointContext == null ? EndpointContext.getDefaultInstance() : endpointContext;
163159
}
164160

165161
/**

gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpJsonCallContext.java

+2-6
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,8 @@ private HttpJsonCallContext(
135135
defaultRetryableCodes == null ? null : ImmutableSet.copyOf(defaultRetryableCodes);
136136
// Attempt to create an empty, non-functioning EndpointContext by default. The client will have
137137
// a valid EndpointContext with user configurations after the client has been initialized.
138-
try {
139-
this.endpointContext =
140-
endpointContext == null ? EndpointContext.newBuilder().build() : endpointContext;
141-
} catch (IOException ex) {
142-
throw new RuntimeException(ex);
143-
}
138+
this.endpointContext =
139+
endpointContext == null ? EndpointContext.getDefaultInstance() : endpointContext;
144140
}
145141

146142
/**

gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java

+14-18
Original file line numberDiff line numberDiff line change
@@ -126,24 +126,20 @@ public abstract class ClientContext {
126126

127127
/** Create a new ClientContext with default values */
128128
public static Builder newBuilder() {
129-
try {
130-
return new AutoValue_ClientContext.Builder()
131-
.setBackgroundResources(Collections.<BackgroundResource>emptyList())
132-
.setExecutor(Executors.newScheduledThreadPool(0))
133-
.setHeaders(Collections.<String, String>emptyMap())
134-
.setInternalHeaders(Collections.<String, String>emptyMap())
135-
.setClock(NanoClock.getDefaultClock())
136-
.setStreamWatchdog(null)
137-
.setStreamWatchdogCheckInterval(Duration.ZERO)
138-
.setTracerFactory(BaseApiTracerFactory.getInstance())
139-
.setQuotaProjectId(null)
140-
.setGdchApiAudience(null)
141-
// Attempt to create an empty, non-functioning EndpointContext by default. This is
142-
// not exposed to the user via getters/setters.
143-
.setEndpointContext(EndpointContext.newBuilder().build());
144-
} catch (IOException e) {
145-
throw new RuntimeException(e);
146-
}
129+
return new AutoValue_ClientContext.Builder()
130+
.setBackgroundResources(Collections.<BackgroundResource>emptyList())
131+
.setExecutor(Executors.newScheduledThreadPool(0))
132+
.setHeaders(Collections.<String, String>emptyMap())
133+
.setInternalHeaders(Collections.<String, String>emptyMap())
134+
.setClock(NanoClock.getDefaultClock())
135+
.setStreamWatchdog(null)
136+
.setStreamWatchdogCheckInterval(Duration.ZERO)
137+
.setTracerFactory(BaseApiTracerFactory.getInstance())
138+
.setQuotaProjectId(null)
139+
.setGdchApiAudience(null)
140+
// Attempt to create an empty, non-functioning EndpointContext by default. This is
141+
// not exposed to the user via getters/setters.
142+
.setEndpointContext(EndpointContext.getDefaultInstance());
147143
}
148144

149145
public abstract Builder toBuilder();

gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java

+16
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,28 @@
4747
@InternalApi
4848
@AutoValue
4949
public abstract class EndpointContext {
50+
51+
private static final EndpointContext INSTANCE;
52+
53+
// static block initialization for exception handling
54+
static {
55+
try {
56+
INSTANCE = EndpointContext.newBuilder().setServiceName("").build();
57+
} catch (IOException e) {
58+
throw new RuntimeException("Unable to create a default empty EndpointContext", e);
59+
}
60+
}
61+
5062
public static final String GOOGLE_CLOUD_UNIVERSE_DOMAIN = "GOOGLE_CLOUD_UNIVERSE_DOMAIN";
5163
public static final String INVALID_UNIVERSE_DOMAIN_ERROR_TEMPLATE =
5264
"The configured universe domain (%s) does not match the universe domain found in the credentials (%s). If you haven't configured the universe domain explicitly, `googleapis.com` is the default.";
5365
public static final String UNABLE_TO_RETRIEVE_CREDENTIALS_ERROR_MESSAGE =
5466
"Unable to retrieve the Universe Domain from the Credentials.";
5567

68+
public static EndpointContext getDefaultInstance() {
69+
return INSTANCE;
70+
}
71+
5672
/**
5773
* ServiceName is host URI for Google Cloud Services. It follows the format of
5874
* `{ServiceName}.googleapis.com`. For example, speech.googleapis.com would have a ServiceName of

gax-java/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java

+28-4
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ public abstract static class Builder<
266266
@Nonnull private ApiTracerFactory tracerFactory;
267267
private boolean deprecatedExecutorProviderSet;
268268
private String universeDomain;
269+
private final EndpointContext endpointContext;
269270

270271
/**
271272
* Indicate when creating transport whether it is allowed to use mTLS endpoint instead of the
@@ -300,6 +301,9 @@ protected Builder(StubSettings settings) {
300301
this.switchToMtlsEndpointAllowed =
301302
settings.getEndpointContext().switchToMtlsEndpointAllowed();
302303
this.universeDomain = settings.getEndpointContext().universeDomain();
304+
// Store the EndpointContext that was already created. This is used to return the state
305+
// of the EndpointContext prior to any new modifications
306+
this.endpointContext = settings.getEndpointContext();
303307
}
304308

305309
/** Get Quota Project ID from Client Context * */
@@ -327,16 +331,22 @@ protected Builder(ClientContext clientContext) {
327331
this.headerProvider = new NoHeaderProvider();
328332
this.internalHeaderProvider = new NoHeaderProvider();
329333
this.clock = NanoClock.getDefaultClock();
330-
this.clientSettingsEndpoint = null;
331-
this.transportChannelProviderEndpoint = null;
332-
this.mtlsEndpoint = null;
333334
this.quotaProjectId = null;
334335
this.streamWatchdogProvider = InstantiatingWatchdogProvider.create();
335336
this.streamWatchdogCheckInterval = Duration.ofSeconds(10);
336337
this.tracerFactory = BaseApiTracerFactory.getInstance();
337338
this.deprecatedExecutorProviderSet = false;
338339
this.gdchApiAudience = null;
340+
341+
this.clientSettingsEndpoint = null;
342+
this.transportChannelProviderEndpoint = null;
343+
this.mtlsEndpoint = null;
344+
this.switchToMtlsEndpointAllowed = false;
339345
this.universeDomain = null;
346+
// Attempt to create an empty, non-functioning EndpointContext by default. The client will
347+
// have
348+
// a valid EndpointContext with user configurations after the client has been initialized.
349+
this.endpointContext = EndpointContext.getDefaultInstance();
340350
} else {
341351
ExecutorProvider fixedExecutorProvider =
342352
FixedExecutorProvider.create(clientContext.getExecutor());
@@ -365,6 +375,9 @@ protected Builder(ClientContext clientContext) {
365375
this.switchToMtlsEndpointAllowed =
366376
clientContext.getEndpointContext().switchToMtlsEndpointAllowed();
367377
this.universeDomain = clientContext.getEndpointContext().universeDomain();
378+
// Store the EndpointContext that was already created. This is used to return the state
379+
// of the EndpointContext prior to any new modifications
380+
this.endpointContext = clientContext.getEndpointContext();
368381
}
369382
}
370383

@@ -584,8 +597,19 @@ public ApiClock getClock() {
584597
return clock;
585598
}
586599

600+
/**
601+
* @return the resolved endpoint when the Builder was created. If invoked after
602+
* `StubSettings.newBuilder()` is called, it will return the clientSettingsEndpoint value.
603+
* If other parameters are then set in the builder, the resolved endpoint is not
604+
* automatically updated. The resolved endpoint will only be recomputed when the
605+
* StubSettings is built again.
606+
*/
587607
public String getEndpoint() {
588-
return clientSettingsEndpoint;
608+
// For the `StubSettings.newBuilder()` case
609+
if (endpointContext.equals(EndpointContext.getDefaultInstance())) {
610+
return clientSettingsEndpoint;
611+
}
612+
return endpointContext.resolvedEndpoint();
589613
}
590614

591615
public String getMtlsEndpoint() {

gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeCallContext.java

+2-7
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import com.google.common.base.Preconditions;
4545
import com.google.common.collect.ImmutableMap;
4646
import com.google.common.collect.ImmutableSet;
47-
import java.io.IOException;
4847
import java.util.List;
4948
import java.util.Map;
5049
import java.util.Set;
@@ -88,12 +87,8 @@ private FakeCallContext(
8887
this.tracer = tracer;
8988
this.retrySettings = retrySettings;
9089
this.retryableCodes = retryableCodes == null ? null : ImmutableSet.copyOf(retryableCodes);
91-
try {
92-
this.endpointContext =
93-
endpointContext == null ? EndpointContext.newBuilder().build() : endpointContext;
94-
} catch (IOException e) {
95-
throw new RuntimeException(e);
96-
}
90+
this.endpointContext =
91+
endpointContext == null ? EndpointContext.getDefaultInstance() : endpointContext;
9792
}
9893

9994
public static FakeCallContext createDefault() {

showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITEndpointContext.java

+21-5
Original file line numberDiff line numberDiff line change
@@ -416,17 +416,33 @@ public void universeDomainValidation_noCredentials_userSetUniverseDomain() throw
416416
@Test
417417
public void endpointResolution_defaultViaBuilder() {
418418
EchoSettings.Builder echoSettingsBuilder = EchoSettings.newBuilder();
419-
// The getter in the builder returns the user set value. No configuration
420-
// means the getter will return null
419+
// `StubSettings.newBuilder()` will return the clientSettingsEndpoint
421420
Truth.assertThat(echoSettingsBuilder.getEndpoint()).isEqualTo(null);
422421
}
423422

424423
// User configuration in Builder
425424
@Test
426425
public void endpointResolution_userConfigurationViaBuilder() {
427-
String customEndpoint = "test.com:123";
428426
EchoSettings.Builder echoSettingsBuilder =
429-
EchoSettings.newBuilder().setEndpoint(customEndpoint);
430-
Truth.assertThat(echoSettingsBuilder.getEndpoint()).isEqualTo(customEndpoint);
427+
EchoSettings.newBuilder().setEndpoint("test.com:123");
428+
// `StubSettings.newBuilder()` will return the clientSettingsEndpoint
429+
Truth.assertThat(echoSettingsBuilder.getEndpoint()).isEqualTo("test.com:123");
430+
}
431+
432+
@Test
433+
public void endpointResolution_builderBuilderBackToBuilder() throws IOException {
434+
String customEndpoint = "test.com:123";
435+
EchoStubSettings.Builder echoStubSettingsBuilder =
436+
EchoStubSettings.newBuilder().setEndpoint(customEndpoint);
437+
// `StubSettings.newBuilder()` will return the clientSettingsEndpoint
438+
Truth.assertThat(echoStubSettingsBuilder.getEndpoint()).isEqualTo(customEndpoint);
439+
440+
// EndpointContext is recomputed when the Builder is re-built
441+
EchoStubSettings echoStubSettings = echoStubSettingsBuilder.build();
442+
Truth.assertThat(echoStubSettings.getEndpoint()).isEqualTo(customEndpoint);
443+
444+
// Calling toBuilder on StubSettings keeps the configurations the same
445+
echoStubSettingsBuilder = echoStubSettings.toBuilder();
446+
Truth.assertThat(echoStubSettingsBuilder.getEndpoint()).isEqualTo(customEndpoint);
431447
}
432448
}

0 commit comments

Comments
 (0)