diff --git a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcCallContext.java b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcCallContext.java index 3de00ec671..94099dd96b 100644 --- a/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcCallContext.java +++ b/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/GrpcCallContext.java @@ -154,12 +154,8 @@ private GrpcCallContext( this.retryableCodes = retryableCodes == null ? null : ImmutableSet.copyOf(retryableCodes); // Attempt to create an empty, non-functioning EndpointContext by default. The client will have // a valid EndpointContext with user configurations after the client has been initialized. - try { - this.endpointContext = - endpointContext == null ? EndpointContext.newBuilder().build() : endpointContext; - } catch (IOException ex) { - throw new RuntimeException(ex); - } + this.endpointContext = + endpointContext == null ? EndpointContext.getDefaultInstance() : endpointContext; } /** diff --git a/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpJsonCallContext.java b/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpJsonCallContext.java index bb20811058..bde0c432a8 100644 --- a/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpJsonCallContext.java +++ b/gax-java/gax-httpjson/src/main/java/com/google/api/gax/httpjson/HttpJsonCallContext.java @@ -135,12 +135,8 @@ private HttpJsonCallContext( defaultRetryableCodes == null ? null : ImmutableSet.copyOf(defaultRetryableCodes); // Attempt to create an empty, non-functioning EndpointContext by default. The client will have // a valid EndpointContext with user configurations after the client has been initialized. - try { - this.endpointContext = - endpointContext == null ? EndpointContext.newBuilder().build() : endpointContext; - } catch (IOException ex) { - throw new RuntimeException(ex); - } + this.endpointContext = + endpointContext == null ? EndpointContext.getDefaultInstance() : endpointContext; } /** diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java index afe6ab0655..26cf63eb85 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/ClientContext.java @@ -126,24 +126,20 @@ public abstract class ClientContext { /** Create a new ClientContext with default values */ public static Builder newBuilder() { - try { - return new AutoValue_ClientContext.Builder() - .setBackgroundResources(Collections.emptyList()) - .setExecutor(Executors.newScheduledThreadPool(0)) - .setHeaders(Collections.emptyMap()) - .setInternalHeaders(Collections.emptyMap()) - .setClock(NanoClock.getDefaultClock()) - .setStreamWatchdog(null) - .setStreamWatchdogCheckInterval(Duration.ZERO) - .setTracerFactory(BaseApiTracerFactory.getInstance()) - .setQuotaProjectId(null) - .setGdchApiAudience(null) - // Attempt to create an empty, non-functioning EndpointContext by default. This is - // not exposed to the user via getters/setters. - .setEndpointContext(EndpointContext.newBuilder().build()); - } catch (IOException e) { - throw new RuntimeException(e); - } + return new AutoValue_ClientContext.Builder() + .setBackgroundResources(Collections.emptyList()) + .setExecutor(Executors.newScheduledThreadPool(0)) + .setHeaders(Collections.emptyMap()) + .setInternalHeaders(Collections.emptyMap()) + .setClock(NanoClock.getDefaultClock()) + .setStreamWatchdog(null) + .setStreamWatchdogCheckInterval(Duration.ZERO) + .setTracerFactory(BaseApiTracerFactory.getInstance()) + .setQuotaProjectId(null) + .setGdchApiAudience(null) + // Attempt to create an empty, non-functioning EndpointContext by default. This is + // not exposed to the user via getters/setters. + .setEndpointContext(EndpointContext.getDefaultInstance()); } public abstract Builder toBuilder(); diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java index de99b01995..efe0f517f5 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/EndpointContext.java @@ -47,12 +47,28 @@ @InternalApi @AutoValue public abstract class EndpointContext { + + private static final EndpointContext INSTANCE; + + // static block initialization for exception handling + static { + try { + INSTANCE = EndpointContext.newBuilder().setServiceName("").build(); + } catch (IOException e) { + throw new RuntimeException("Unable to create a default empty EndpointContext", e); + } + } + public static final String GOOGLE_CLOUD_UNIVERSE_DOMAIN = "GOOGLE_CLOUD_UNIVERSE_DOMAIN"; public static final String INVALID_UNIVERSE_DOMAIN_ERROR_TEMPLATE = "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."; public static final String UNABLE_TO_RETRIEVE_CREDENTIALS_ERROR_MESSAGE = "Unable to retrieve the Universe Domain from the Credentials."; + public static EndpointContext getDefaultInstance() { + return INSTANCE; + } + /** * ServiceName is host URI for Google Cloud Services. It follows the format of * `{ServiceName}.googleapis.com`. For example, speech.googleapis.com would have a ServiceName of diff --git a/gax-java/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java b/gax-java/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java index 0e37c12cad..4dc67c9a2d 100644 --- a/gax-java/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java +++ b/gax-java/gax/src/main/java/com/google/api/gax/rpc/StubSettings.java @@ -266,6 +266,7 @@ public abstract static class Builder< @Nonnull private ApiTracerFactory tracerFactory; private boolean deprecatedExecutorProviderSet; private String universeDomain; + private final EndpointContext endpointContext; /** * Indicate when creating transport whether it is allowed to use mTLS endpoint instead of the @@ -300,6 +301,9 @@ protected Builder(StubSettings settings) { this.switchToMtlsEndpointAllowed = settings.getEndpointContext().switchToMtlsEndpointAllowed(); this.universeDomain = settings.getEndpointContext().universeDomain(); + // Store the EndpointContext that was already created. This is used to return the state + // of the EndpointContext prior to any new modifications + this.endpointContext = settings.getEndpointContext(); } /** Get Quota Project ID from Client Context * */ @@ -327,16 +331,22 @@ protected Builder(ClientContext clientContext) { this.headerProvider = new NoHeaderProvider(); this.internalHeaderProvider = new NoHeaderProvider(); this.clock = NanoClock.getDefaultClock(); - this.clientSettingsEndpoint = null; - this.transportChannelProviderEndpoint = null; - this.mtlsEndpoint = null; this.quotaProjectId = null; this.streamWatchdogProvider = InstantiatingWatchdogProvider.create(); this.streamWatchdogCheckInterval = Duration.ofSeconds(10); this.tracerFactory = BaseApiTracerFactory.getInstance(); this.deprecatedExecutorProviderSet = false; this.gdchApiAudience = null; + + this.clientSettingsEndpoint = null; + this.transportChannelProviderEndpoint = null; + this.mtlsEndpoint = null; + this.switchToMtlsEndpointAllowed = false; this.universeDomain = null; + // Attempt to create an empty, non-functioning EndpointContext by default. The client will + // have + // a valid EndpointContext with user configurations after the client has been initialized. + this.endpointContext = EndpointContext.getDefaultInstance(); } else { ExecutorProvider fixedExecutorProvider = FixedExecutorProvider.create(clientContext.getExecutor()); @@ -365,6 +375,9 @@ protected Builder(ClientContext clientContext) { this.switchToMtlsEndpointAllowed = clientContext.getEndpointContext().switchToMtlsEndpointAllowed(); this.universeDomain = clientContext.getEndpointContext().universeDomain(); + // Store the EndpointContext that was already created. This is used to return the state + // of the EndpointContext prior to any new modifications + this.endpointContext = clientContext.getEndpointContext(); } } @@ -584,8 +597,19 @@ public ApiClock getClock() { return clock; } + /** + * @return the resolved endpoint when the Builder was created. If invoked after + * `StubSettings.newBuilder()` is called, it will return the clientSettingsEndpoint value. + * If other parameters are then set in the builder, the resolved endpoint is not + * automatically updated. The resolved endpoint will only be recomputed when the + * StubSettings is built again. + */ public String getEndpoint() { - return clientSettingsEndpoint; + // For the `StubSettings.newBuilder()` case + if (endpointContext.equals(EndpointContext.getDefaultInstance())) { + return clientSettingsEndpoint; + } + return endpointContext.resolvedEndpoint(); } public String getMtlsEndpoint() { diff --git a/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeCallContext.java b/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeCallContext.java index 77ae3d1fca..a075e02cc1 100644 --- a/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeCallContext.java +++ b/gax-java/gax/src/test/java/com/google/api/gax/rpc/testing/FakeCallContext.java @@ -44,7 +44,6 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import java.io.IOException; import java.util.List; import java.util.Map; import java.util.Set; @@ -88,12 +87,8 @@ private FakeCallContext( this.tracer = tracer; this.retrySettings = retrySettings; this.retryableCodes = retryableCodes == null ? null : ImmutableSet.copyOf(retryableCodes); - try { - this.endpointContext = - endpointContext == null ? EndpointContext.newBuilder().build() : endpointContext; - } catch (IOException e) { - throw new RuntimeException(e); - } + this.endpointContext = + endpointContext == null ? EndpointContext.getDefaultInstance() : endpointContext; } public static FakeCallContext createDefault() { diff --git a/showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITEndpointContext.java b/showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITEndpointContext.java index ad44622471..812a52696b 100644 --- a/showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITEndpointContext.java +++ b/showcase/gapic-showcase/src/test/java/com/google/showcase/v1beta1/it/ITEndpointContext.java @@ -416,17 +416,33 @@ public void universeDomainValidation_noCredentials_userSetUniverseDomain() throw @Test public void endpointResolution_defaultViaBuilder() { EchoSettings.Builder echoSettingsBuilder = EchoSettings.newBuilder(); - // The getter in the builder returns the user set value. No configuration - // means the getter will return null + // `StubSettings.newBuilder()` will return the clientSettingsEndpoint Truth.assertThat(echoSettingsBuilder.getEndpoint()).isEqualTo(null); } // User configuration in Builder @Test public void endpointResolution_userConfigurationViaBuilder() { - String customEndpoint = "test.com:123"; EchoSettings.Builder echoSettingsBuilder = - EchoSettings.newBuilder().setEndpoint(customEndpoint); - Truth.assertThat(echoSettingsBuilder.getEndpoint()).isEqualTo(customEndpoint); + EchoSettings.newBuilder().setEndpoint("test.com:123"); + // `StubSettings.newBuilder()` will return the clientSettingsEndpoint + Truth.assertThat(echoSettingsBuilder.getEndpoint()).isEqualTo("test.com:123"); + } + + @Test + public void endpointResolution_builderBuilderBackToBuilder() throws IOException { + String customEndpoint = "test.com:123"; + EchoStubSettings.Builder echoStubSettingsBuilder = + EchoStubSettings.newBuilder().setEndpoint(customEndpoint); + // `StubSettings.newBuilder()` will return the clientSettingsEndpoint + Truth.assertThat(echoStubSettingsBuilder.getEndpoint()).isEqualTo(customEndpoint); + + // EndpointContext is recomputed when the Builder is re-built + EchoStubSettings echoStubSettings = echoStubSettingsBuilder.build(); + Truth.assertThat(echoStubSettings.getEndpoint()).isEqualTo(customEndpoint); + + // Calling toBuilder on StubSettings keeps the configurations the same + echoStubSettingsBuilder = echoStubSettings.toBuilder(); + Truth.assertThat(echoStubSettingsBuilder.getEndpoint()).isEqualTo(customEndpoint); } }