@@ -126,7 +126,8 @@ public class SpannerOptions extends ServiceOptions<Spanner, SpannerOptions> {
126126 private static final String API_SHORT_NAME = "Spanner" ;
127127 private static final String SPANNER_SERVICE_NAME = "spanner" ;
128128 private static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com" ;
129- private static final String EXPERIMENTAL_HOST_PROJECT_ID = "default" ;
129+ public static final String SPANNER_OMNI_PROJECT_ID = "default" ;
130+ public static final String DEFAULT_SPANNER_OMNI_INSTANCE_ID = "default" ;
130131
131132 static final ImmutableSet <String > SCOPES =
132133 ImmutableSet .of (
@@ -314,6 +315,18 @@ enum TracingFramework {
314315 OPEN_TELEMETRY
315316 }
316317
318+ /**
319+ * Specifies the type of Spanner instance to connect to (CLOUD, OMNI, or EMULATOR). Currently,
320+ * this is a no-op for most types, but setting it to OMNI is mandatory when connecting to a
321+ * Spanner Omni instance.
322+ */
323+ public enum InstanceType {
324+ UNSPECIFIED ,
325+ CLOUD ,
326+ OMNI ,
327+ EMULATOR
328+ }
329+
317330 private static final Object lock = new Object ();
318331
319332 @ GuardedBy ("lock" )
@@ -924,16 +937,17 @@ protected SpannerOptions(Builder builder) {
924937
925938 // Dynamic channel pooling is disabled by default.
926939 // It is only enabled when:
927- // 1. enableDynamicChannelPool() was explicitly called (or experimentalHost is set and DCP was
940+ // 1. enableDynamicChannelPool() was explicitly called (or instance is set to OMNI and DCP was
928941 // not explicitly disabled), AND
929942 // 2. grpc-gcp extension is enabled, AND
930943 // 3. numChannels was not explicitly set
931944 boolean dcpRequested =
932945 builder .dynamicChannelPoolEnabled != null
933946 ? builder .dynamicChannelPoolEnabled
934- : builder .experimentalHost != null ;
947+ : builder .instanceType == InstanceType . OMNI ;
935948 if (dcpRequested ) {
936- // DCP was enabled (explicitly or via experimentalHost), but respect numChannels if set
949+ // DCP was enabled (explicitly or via instance type being OMNI), but respect numChannels if
950+ // set
937951 dynamicChannelPoolEnabled = grpcGcpExtensionEnabled && !builder .numChannelsExplicitlySet ;
938952 } else {
939953 // DCP is disabled by default, or was explicitly disabled
@@ -976,14 +990,14 @@ protected SpannerOptions(Builder builder) {
976990 openTelemetry = builder .openTelemetry ;
977991 enableApiTracing = builder .enableApiTracing ;
978992 enableExtendedTracing = builder .enableExtendedTracing ;
979- if (builder .experimentalHost != null ) {
993+ if (builder .instanceType == InstanceType . OMNI ) {
980994 enableBuiltInMetrics = false ;
981995 } else {
982996 enableBuiltInMetrics = builder .enableBuiltInMetrics ;
983997 }
984- // Enable location API when experimental host is set , unless explicitly disabled
998+ // Enable location API when InstanceType is OMNI , unless explicitly disabled
985999 // via GOOGLE_SPANNER_EXPERIMENTAL_LOCATION_API=false.
986- if (builder .experimentalHost != null ) {
1000+ if (builder .instanceType == InstanceType . OMNI ) {
9871001 String locationApiEnvValue = System .getenv (EXPERIMENTAL_LOCATION_API_ENV_VAR );
9881002 enableLocationApi = locationApiEnvValue == null || Boolean .parseBoolean (locationApiEnvValue );
9891003 } else {
@@ -1072,13 +1086,12 @@ default String getMonitoringHost() {
10721086 return null ;
10731087 }
10741088
1075- default GoogleCredentials getDefaultExperimentalHostCredentials () {
1089+ default GoogleCredentials getDefaultSpannerOmniCredentials () {
10761090 return null ;
10771091 }
10781092 }
10791093
1080- static final String DEFAULT_SPANNER_EXPERIMENTAL_HOST_CREDENTIALS =
1081- "SPANNER_EXPERIMENTAL_HOST_AUTH_TOKEN" ;
1094+ static final String DEFAULT_SPANNER_OMNI_CREDENTIALS = "SPANNER_OMNI_AUTH_TOKEN" ;
10821095
10831096 /**
10841097 * Default implementation of {@link SpannerEnvironment}. Reads all configuration from environment
@@ -1174,8 +1187,8 @@ public String getMonitoringHost() {
11741187 }
11751188
11761189 @ Override
1177- public GoogleCredentials getDefaultExperimentalHostCredentials () {
1178- return getOAuthTokenFromFile (System .getenv (DEFAULT_SPANNER_EXPERIMENTAL_HOST_CREDENTIALS ));
1190+ public GoogleCredentials getDefaultSpannerOmniCredentials () {
1191+ return getOAuthTokenFromFile (System .getenv (DEFAULT_SPANNER_OMNI_CREDENTIALS ));
11791192 }
11801193 }
11811194
@@ -1252,10 +1265,11 @@ public static class Builder
12521265 private boolean enableLocationApi = SpannerOptions .environment .isEnableLocationApi ();
12531266 private String monitoringHost = SpannerOptions .environment .getMonitoringHost ();
12541267 private SslContext mTLSContext = null ;
1255- private String experimentalHost = null ;
12561268 private boolean usePlainText = false ;
12571269 private TransactionOptions defaultTransactionOptions = TransactionOptions .getDefaultInstance ();
12581270 private RequestOptions .ClientContext clientContext ;
1271+ private InstanceType instanceType = InstanceType .UNSPECIFIED ;
1272+ private String host = null ;
12591273
12601274 private static String createCustomClientLibToken (String token ) {
12611275 return token + " " + ServiceOptions .getGoogApiClientLibName ();
@@ -1795,26 +1809,49 @@ public Builder setDecodeMode(DecodeMode decodeMode) {
17951809 @ Override
17961810 public Builder setHost (String host ) {
17971811 super .setHost (host );
1812+ this .host = host ;
17981813 // Setting a host should override any SPANNER_EMULATOR_HOST setting.
17991814 setEmulatorHost (null );
18001815 return this ;
18011816 }
18021817
1818+ /** @deprecated Use {@link #setType(InstanceType)} instead. */
1819+ @ Deprecated
1820+ @ ObsoleteApi ("Use setHost(String).setType(InstanceType.OMNI) instead" )
18031821 @ ExperimentalApi ("https://github.com/googleapis/java-spanner/pull/3676" )
18041822 public Builder setExperimentalHost (String host ) {
1805- if (this .usePlainText ) {
1806- Preconditions .checkArgument (
1807- !host .startsWith ("https:" ),
1808- "Please remove the 'https:' protocol prefix from the host string when using plain text"
1809- + " communication" );
1810- if (!host .startsWith ("http" )) {
1811- host = "http://" + host ;
1823+ setHost (host );
1824+ if (!Strings .isNullOrEmpty (host )) {
1825+ setType (InstanceType .OMNI );
1826+ }
1827+ return this ;
1828+ }
1829+
1830+ /**
1831+ * Specifies the type of Spanner instance to connect to (CLOUD, OMNI, or EMULATOR). Currently,
1832+ * this is a no-op for most types, but setting it to OMNI is mandatory when connecting to a
1833+ * Spanner Omni instance.
1834+ */
1835+ public Builder setType (InstanceType instanceType ) {
1836+ this .instanceType = instanceType ;
1837+ if (instanceType == InstanceType .OMNI ) {
1838+ if (Strings .isNullOrEmpty (this .host )) {
1839+ throw new IllegalStateException ("Host must be set before setting Type to OMNI" );
1840+ }
1841+ if (this .usePlainText ) {
1842+ Preconditions .checkArgument (
1843+ !this .host .startsWith ("https:" ),
1844+ "Please remove the 'https:' protocol prefix from the host string when using plain text"
1845+ + " communication" );
1846+ if (!this .host .startsWith ("http" )) {
1847+ this .host = "http://" + this .host ;
1848+ setHost (this .host );
1849+ }
18121850 }
1851+ setBuiltInMetricsEnabled (false );
1852+ super .setProjectId (SPANNER_OMNI_PROJECT_ID );
1853+ setSessionPoolOption (SessionPoolOptions .newBuilder ().setExperimentalHost ().build ());
18131854 }
1814- super .setHost (host );
1815- super .setProjectId (EXPERIMENTAL_HOST_PROJECT_ID );
1816- setSessionPoolOption (SessionPoolOptions .newBuilder ().setExperimentalHost ().build ());
1817- this .experimentalHost = host ;
18181855 return this ;
18191856 }
18201857
@@ -1916,14 +1953,13 @@ public Builder setEmulatorHost(String emulatorHost) {
19161953 }
19171954
19181955 /**
1919- * Configures mTLS authentication using the provided client certificate and key files. mTLS is
1920- * only supported for experimental spanner hosts .
1956+ * Configures mTLS authentication using the provided client certificate and key files. mTLS via
1957+ * useClientCert is only supported for Spanner Omni instances .
19211958 *
19221959 * @param clientCertificate Path to the client certificate file.
19231960 * @param clientCertificateKey Path to the client private key file.
19241961 * @throws SpannerException If an error occurs while configuring the mTLS context
19251962 */
1926- @ ExperimentalApi ("https://github.com/googleapis/java-spanner/pull/3574" )
19271963 public Builder useClientCert (String clientCertificate , String clientCertificateKey ) {
19281964 try {
19291965 this .mTLSContext =
@@ -1941,14 +1977,13 @@ public Builder useClientCert(String clientCertificate, String clientCertificateK
19411977 * credentials to {@link com.google.cloud.NoCredentials} to avoid sending authentication over an
19421978 * unsecured channel.
19431979 */
1944- @ ExperimentalApi ("https://github.com/googleapis/java-spanner/pull/4264" )
19451980 public Builder usePlainText () {
19461981 this .usePlainText = true ;
19471982 this .setChannelConfigurator (ManagedChannelBuilder ::usePlaintext )
19481983 .setCredentials (NoCredentials .getInstance ());
1949- if (this .experimentalHost != null ) {
1984+ if (this .instanceType == InstanceType . OMNI && ! Strings . isNullOrEmpty ( this . host ) ) {
19501985 // Re-apply host settings to ensure http:// is prepended.
1951- setExperimentalHost ( this . experimentalHost );
1986+ setType ( InstanceType . OMNI );
19521987 }
19531988 return this ;
19541989 }
@@ -2124,7 +2159,7 @@ public Builder setDefaultClientContext(RequestOptions.ClientContext clientContex
21242159 @ Override
21252160 public SpannerOptions build () {
21262161 // Set the host of emulator has been set.
2127- if (emulatorHost != null && experimentalHost == null ) {
2162+ if (emulatorHost != null && this . instanceType != InstanceType . OMNI ) {
21282163 if (!emulatorHost .startsWith ("http" )) {
21292164 emulatorHost = "http://" + emulatorHost ;
21302165 }
@@ -2134,8 +2169,8 @@ public SpannerOptions build() {
21342169 this .setChannelConfigurator (ManagedChannelBuilder ::usePlaintext );
21352170 // As we are using plain text, we should never send any credentials.
21362171 this .setCredentials (NoCredentials .getInstance ());
2137- } else if (experimentalHost != null && credentials == null ) {
2138- credentials = environment .getDefaultExperimentalHostCredentials ();
2172+ } else if (this . instanceType == InstanceType . OMNI && credentials == null ) {
2173+ credentials = environment .getDefaultSpannerOmniCredentials ();
21392174 }
21402175 if (this .numChannels == null ) {
21412176 this .numChannels =
@@ -2177,8 +2212,8 @@ public static void useDefaultEnvironment() {
21772212 }
21782213
21792214 @ InternalApi
2180- public static GoogleCredentials getDefaultExperimentalCredentialsFromSysEnv () {
2181- return getOAuthTokenFromFile (System .getenv (DEFAULT_SPANNER_EXPERIMENTAL_HOST_CREDENTIALS ));
2215+ public static GoogleCredentials getDefaultSpannerOmniCredentialsFromSysEnv () {
2216+ return getOAuthTokenFromFile (System .getenv (DEFAULT_SPANNER_OMNI_CREDENTIALS ));
21822217 }
21832218
21842219 private static @ Nullable GoogleCredentials getOAuthTokenFromFile (@ Nullable String file ) {
0 commit comments