Skip to content
This repository was archived by the owner on Apr 7, 2026. It is now read-only.

Commit 09c1e63

Browse files
committed
updates from PR review
1 parent 4ed2f0b commit 09c1e63

6 files changed

Lines changed: 58 additions & 53 deletions

File tree

google-cloud-spanner/src/main/java/com/google/cloud/spanner/connection/MutableCredentials.java renamed to google-cloud-spanner/src/main/java/com/google/cloud/spanner/MutableCredentials.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package com.google.cloud.spanner.connection;
16+
package com.google.cloud.spanner;
1717

1818
import com.google.auth.CredentialTypeForMetrics;
1919
import com.google.auth.Credentials;
2020
import com.google.auth.RequestMetadataCallback;
2121
import com.google.auth.oauth2.ServiceAccountCredentials;
22-
import com.google.cloud.spanner.SpannerOptions;
22+
2323
import java.io.IOException;
2424
import java.net.URI;
2525
import java.util.List;
@@ -33,7 +33,7 @@
3333
* {@link ServiceAccountCredentials} instance.
3434
*
3535
* <p>This class is intended for scenarios where an application needs to replace the underlying
36-
* service account credentials for a long running Spanner Client.
36+
* service account credentials for a long-running Spanner Client.
3737
*
3838
* <p>All operations inherited from {@link Credentials} are forwarded to the current delegate,
3939
* including request metadata retrieval and token refresh. Calling {@link
@@ -45,6 +45,7 @@ public class MutableCredentials extends Credentials {
4545
private volatile ServiceAccountCredentials delegate;
4646
private final Set<String> scopes;
4747

48+
/** Creates a MutableCredentials instance with default spanner scopes {@link SpannerOptions.SCOPES} */
4849
public MutableCredentials(ServiceAccountCredentials credentials) {
4950
this(credentials, SpannerOptions.SCOPES);
5051
}

google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerOptions.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ public class SpannerOptions extends ServiceOptions<Spanner, SpannerOptions> {
128128
private static final String GOOGLE_DEFAULT_UNIVERSE = "googleapis.com";
129129
private static final String EXPERIMENTAL_HOST_PROJECT_ID = "default";
130130

131-
public static final ImmutableSet<String> SCOPES =
131+
static final ImmutableSet<String> SCOPES =
132132
ImmutableSet.of(
133133
"https://www.googleapis.com/auth/spanner.admin",
134134
"https://www.googleapis.com/auth/spanner.data");

google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/MutableCredentialsTest.java renamed to google-cloud-spanner/src/test/java/com/google/cloud/spanner/MutableCredentialsTest.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
package com.google.cloud.spanner.connection;
17+
package com.google.cloud.spanner;
1818

1919
import static org.junit.Assert.assertEquals;
2020
import static org.junit.Assert.assertFalse;
@@ -29,10 +29,16 @@
2929
import com.google.auth.CredentialTypeForMetrics;
3030
import com.google.auth.RequestMetadataCallback;
3131
import com.google.auth.oauth2.ServiceAccountCredentials;
32-
import com.google.cloud.spanner.SpannerOptions;
32+
3333
import java.io.IOException;
3434
import java.net.URI;
35-
import java.util.*;
35+
36+
import java.util.Arrays;
37+
import java.util.Collections;
38+
import java.util.HashSet;
39+
import java.util.List;
40+
import java.util.Map;
41+
import java.util.Set;
3642
import java.util.concurrent.Executor;
3743
import org.junit.Test;
3844
import org.junit.runner.RunWith;

google-cloud-spanner/src/test/java/com/google/cloud/spanner/connection/it/ITMutableCredentialsTest.java

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,19 @@
1616

1717
package com.google.cloud.spanner.connection.it;
1818

19-
import static org.junit.Assert.*;
19+
20+
import static org.junit.Assert.assertTrue;
21+
import static org.junit.Assert.fail;
2022
import static org.junit.Assume.assumeTrue;
2123

2224
import com.google.auth.oauth2.GoogleCredentials;
2325
import com.google.auth.oauth2.ServiceAccountCredentials;
24-
import com.google.cloud.spanner.*;
26+
27+
import com.google.cloud.spanner.SerialIntegrationTest;
28+
import com.google.cloud.spanner.Spanner;
29+
import com.google.cloud.spanner.SpannerOptions;
2530
import com.google.cloud.spanner.admin.instance.v1.InstanceAdminClient;
26-
import com.google.cloud.spanner.connection.MutableCredentials;
31+
import com.google.cloud.spanner.MutableCredentials;
2732
import com.google.spanner.admin.instance.v1.ProjectName;
2833
import java.io.IOException;
2934
import java.io.InputStream;
@@ -73,15 +78,15 @@ public void testMutableCredentialsUpdateAuthorizationForRunningClient() throws I
7378

7479
SpannerOptions options =
7580
SpannerOptions.newBuilder()
76-
.setEmulatorHost(
77-
null) // this setting is required otherwise SpannerOptions overrides credentials to
78-
// NoCredentials
81+
// this setting is required in the scenario SPANNER_EMULATOR_HOST is set otherwise
82+
// SpannerOptions overrides credentials to NoCredentials
83+
.setEmulatorHost(null)
7984
.setCredentials(mutableCredentials)
8085
.build();
8186

8287
ProjectName projectName = ProjectName.of(options.getProjectId());
8388
try (Spanner spanner = options.getService();
84-
InstanceAdminClient instanceAdminClient = spanner.createInstanceAdminClient()) {
89+
InstanceAdminClient instanceAdminClient = spanner.createInstanceAdminClient()) {
8590
instanceAdminClient.listInstances(projectName);
8691

8792
// update mutableCredentials now to use an invalid credentials

google-cloud-spanner/src/test/resources/com/google/cloud/spanner/connection/test-key-missing-permissions.json

Lines changed: 0 additions & 13 deletions
This file was deleted.

samples/snippets/src/main/java/com/example/spanner/MutableCredentialsExample.java

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,13 @@
1616

1717
package com.example.spanner;
1818

19-
//[START mutable_credentials]
19+
// [START spanner_mutable_credentials]
2020

2121
import com.google.auth.oauth2.ServiceAccountCredentials;
2222
import com.google.cloud.spanner.Spanner;
2323
import com.google.cloud.spanner.SpannerOptions;
2424
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
2525
import com.google.cloud.spanner.connection.MutableCredentials;
26-
import com.google.spanner.admin.database.v1.DatabaseName;
27-
import com.google.spanner.admin.database.v1.GetDatabaseDdlResponse;
2826
import java.io.FileInputStream;
2927
import java.io.IOException;
3028
import java.nio.file.Files;
@@ -33,16 +31,16 @@
3331
import java.nio.file.attribute.FileTime;
3432
import java.util.concurrent.Executors;
3533
import java.util.concurrent.ScheduledExecutorService;
34+
import java.util.concurrent.ThreadFactory;
3635
import java.util.concurrent.TimeUnit;
3736

3837
public class MutableCredentialsExample {
3938

40-
4139
static void createClientWithMutableCredentials() throws IOException {
4240
final String credentialsPath = "location_of_service_account_credential_json";
4341
Path path = Paths.get(credentialsPath);
4442
// Use an array to hold the mutable lastModifiedTime so it can be accessed in the lambda
45-
FileTime[] lastModifiedTime = new FileTime[]{ Files.getLastModifiedTime(path) };
43+
FileTime[] lastModifiedTime = new FileTime[] {Files.getLastModifiedTime(path)};
4644

4745
// 1 - create service account credentials
4846
ServiceAccountCredentials serviceAccountCredentials;
@@ -54,32 +52,40 @@ static void createClientWithMutableCredentials() throws IOException {
5452
MutableCredentials mutableCredentials = new MutableCredentials(serviceAccountCredentials);
5553

5654
// 3 - set credentials on your SpannerOptions builder to your mutableCredentials
57-
SpannerOptions options = SpannerOptions.newBuilder()
58-
.setCredentials(mutableCredentials)
59-
.build();
55+
SpannerOptions options = SpannerOptions.newBuilder().setCredentials(mutableCredentials).build();
6056

61-
// 4 - include logic for when to how your mutableCredentials
57+
// 4 - include logic for when/how to update your mutableCredentials
6258
// In this example we'll use a SchedulerExecutorService to periodically check for updates
63-
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
64-
executorService.scheduleAtFixedRate(() -> {
65-
try {
66-
FileTime currentModifiedTime = Files.getLastModifiedTime(path);
67-
if (currentModifiedTime.compareTo(lastModifiedTime[0]) > 0) {
68-
lastModifiedTime[0] = currentModifiedTime;
69-
try (FileInputStream is = new FileInputStream(credentialsPath)) {
70-
ServiceAccountCredentials credentials = ServiceAccountCredentials.fromStream(is);
71-
mutableCredentials.updateCredentials(credentials);
72-
System.out.println("Credentials rotated.");
59+
ThreadFactory daemonThreadFactory =
60+
runnable -> {
61+
Thread thread = new Thread(runnable, "spanner-mutable-credentials-rotator");
62+
thread.setDaemon(true);
63+
return thread;
64+
};
65+
ScheduledExecutorService executorService =
66+
Executors.newSingleThreadScheduledExecutor(daemonThreadFactory);
67+
executorService.scheduleAtFixedRate(
68+
() -> {
69+
try {
70+
FileTime currentModifiedTime = Files.getLastModifiedTime(path);
71+
if (currentModifiedTime.compareTo(lastModifiedTime[0]) > 0) {
72+
lastModifiedTime[0] = currentModifiedTime;
73+
try (FileInputStream is = new FileInputStream(credentialsPath)) {
74+
ServiceAccountCredentials credentials = ServiceAccountCredentials.fromStream(is);
75+
mutableCredentials.updateCredentials(credentials);
76+
}
77+
}
78+
} catch (IOException e) {
79+
System.err.println("Failed to check or update credentials: " + e.getMessage());
7380
}
74-
}
75-
} catch (IOException e) {
76-
System.err.println("Failed to check or update credentials: " + e.getMessage());
77-
}
78-
}, 15, 15, TimeUnit.MINUTES);
81+
},
82+
15,
83+
15,
84+
TimeUnit.MINUTES);
7985

8086
// 5. Use the client
8187
try (Spanner spanner = options.getService();
82-
DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
88+
DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
8389
// Perform operations...
8490
// long running client operations will always use the latest credentials wrapped in
8591
// mutableCredentials
@@ -89,4 +95,4 @@ static void createClientWithMutableCredentials() throws IOException {
8995
}
9096
}
9197
}
92-
//[END mutable_credentials]
98+
// [END spanner_mutable_credentials]

0 commit comments

Comments
 (0)