From 18ef8002a3aa3bb350c2b5298f10dddc024905fb Mon Sep 17 00:00:00 2001 From: Olav Loite Date: Wed, 3 Apr 2019 12:48:31 +0200 Subject: [PATCH 1/2] refactor SpannerImpl: move InstanceAdminClient to separate file --- .../spanner/InstanceAdminClientImpl.java | 206 +++++++++++++++++ .../com/google/cloud/spanner/SpannerImpl.java | 212 ------------------ .../spanner/InstanceAdminClientImplTest.java | 4 +- 3 files changed, 208 insertions(+), 214 deletions(-) create mode 100644 google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceAdminClientImpl.java diff --git a/google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceAdminClientImpl.java b/google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceAdminClientImpl.java new file mode 100644 index 000000000000..e065d7f2ffb7 --- /dev/null +++ b/google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/InstanceAdminClientImpl.java @@ -0,0 +1,206 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.cloud.spanner; + +import com.google.api.core.ApiFunction; +import com.google.api.gax.grpc.ProtoOperationTransformers; +import com.google.api.gax.longrunning.OperationFuture; +import com.google.api.gax.longrunning.OperationFutureImpl; +import com.google.api.gax.longrunning.OperationSnapshot; +import com.google.api.gax.paging.Page; +import com.google.api.pathtemplate.PathTemplate; +import com.google.cloud.spanner.Options.ListOption; +import com.google.cloud.spanner.SpannerImpl.PageFetcher; +import com.google.cloud.spanner.spi.v1.SpannerRpc; +import com.google.cloud.spanner.spi.v1.SpannerRpc.Paginated; +import com.google.common.base.Preconditions; +import com.google.protobuf.FieldMask; +import com.google.spanner.admin.instance.v1.CreateInstanceMetadata; +import com.google.spanner.admin.instance.v1.UpdateInstanceMetadata; +import java.util.concurrent.Callable; + +/** Default implementation of {@link InstanceAdminClient} */ +class InstanceAdminClientImpl implements InstanceAdminClient { + private static final PathTemplate PROJECT_NAME_TEMPLATE = + PathTemplate.create("projects/{project}"); + private final DatabaseAdminClient dbClient; + private final String projectId; + private final SpannerRpc rpc; + + InstanceAdminClientImpl(String projectId, SpannerRpc rpc, DatabaseAdminClient dbClient) { + this.projectId = projectId; + this.rpc = rpc; + this.dbClient = dbClient; + } + + @Override + public InstanceConfig getInstanceConfig(String configId) throws SpannerException { + final String instanceConfigName = new InstanceConfigId(projectId, configId).getName(); + return SpannerImpl.runWithRetries( + new Callable() { + @Override + public InstanceConfig call() { + return InstanceConfig.fromProto( + rpc.getInstanceConfig(instanceConfigName), InstanceAdminClientImpl.this); + } + }); + } + + @Override + public Page listInstanceConfigs(ListOption... options) { + final Options listOptions = Options.fromListOptions(options); + Preconditions.checkArgument( + !listOptions.hasFilter(), "Filter option is not supported by listInstanceConfigs"); + final int pageSize = listOptions.hasPageSize() ? listOptions.pageSize() : 0; + PageFetcher pageFetcher = + new PageFetcher() { + @Override + public Paginated getNextPage( + String nextPageToken) { + return rpc.listInstanceConfigs(pageSize, nextPageToken); + } + + @Override + public InstanceConfig fromProto( + com.google.spanner.admin.instance.v1.InstanceConfig proto) { + return InstanceConfig.fromProto(proto, InstanceAdminClientImpl.this); + } + }; + if (listOptions.hasPageToken()) { + pageFetcher.setNextPageToken(listOptions.pageToken()); + } + return pageFetcher.getNextPage(); + } + + @Override + public OperationFuture createInstance(InstanceInfo instance) + throws SpannerException { + String projectName = PROJECT_NAME_TEMPLATE.instantiate("project", projectId); + OperationFuture + rawOperationFuture = + rpc.createInstance(projectName, instance.getId().getInstance(), instance.toProto()); + + return new OperationFutureImpl( + rawOperationFuture.getPollingFuture(), + rawOperationFuture.getInitialFuture(), + new ApiFunction() { + @Override + public Instance apply(OperationSnapshot snapshot) { + return Instance.fromProto( + ProtoOperationTransformers.ResponseTransformer.create( + com.google.spanner.admin.instance.v1.Instance.class) + .apply(snapshot), + InstanceAdminClientImpl.this, + dbClient); + } + }, + ProtoOperationTransformers.MetadataTransformer.create(CreateInstanceMetadata.class), + new ApiFunction() { + @Override + public Instance apply(Exception e) { + throw SpannerExceptionFactory.newSpannerException(e); + } + }); + } + + @Override + public Instance getInstance(String instanceId) throws SpannerException { + final String instanceName = new InstanceId(projectId, instanceId).getName(); + return SpannerImpl.runWithRetries( + new Callable() { + @Override + public Instance call() { + return Instance.fromProto( + rpc.getInstance(instanceName), InstanceAdminClientImpl.this, dbClient); + } + }); + } + + @Override + public Page listInstances(ListOption... options) throws SpannerException { + final Options listOptions = Options.fromListOptions(options); + final int pageSize = listOptions.hasPageSize() ? listOptions.pageSize() : 0; + final String filter = listOptions.filter(); + PageFetcher pageFetcher = + new PageFetcher() { + @Override + public Paginated getNextPage( + String nextPageToken) { + return rpc.listInstances(pageSize, nextPageToken, filter); + } + + @Override + public Instance fromProto(com.google.spanner.admin.instance.v1.Instance proto) { + return Instance.fromProto(proto, InstanceAdminClientImpl.this, dbClient); + } + }; + if (listOptions.hasPageToken()) { + pageFetcher.setNextPageToken(listOptions.pageToken()); + } + return pageFetcher.getNextPage(); + } + + @Override + public void deleteInstance(final String instanceId) throws SpannerException { + SpannerImpl.runWithRetries( + new Callable() { + @Override + public Void call() { + rpc.deleteInstance(new InstanceId(projectId, instanceId).getName()); + return null; + } + }); + } + + @Override + public OperationFuture updateInstance( + InstanceInfo instance, InstanceInfo.InstanceField... fieldsToUpdate) { + FieldMask fieldMask = + fieldsToUpdate.length == 0 + ? InstanceInfo.InstanceField.toFieldMask(InstanceInfo.InstanceField.values()) + : InstanceInfo.InstanceField.toFieldMask(fieldsToUpdate); + + OperationFuture + rawOperationFuture = rpc.updateInstance(instance.toProto(), fieldMask); + return new OperationFutureImpl( + rawOperationFuture.getPollingFuture(), + rawOperationFuture.getInitialFuture(), + new ApiFunction() { + @Override + public Instance apply(OperationSnapshot snapshot) { + return Instance.fromProto( + ProtoOperationTransformers.ResponseTransformer.create( + com.google.spanner.admin.instance.v1.Instance.class) + .apply(snapshot), + InstanceAdminClientImpl.this, + dbClient); + } + }, + ProtoOperationTransformers.MetadataTransformer.create(UpdateInstanceMetadata.class), + new ApiFunction() { + @Override + public Instance apply(Exception e) { + throw SpannerExceptionFactory.newSpannerException(e); + } + }); + } + + @Override + public Instance.Builder newInstanceBuilder(InstanceId id) { + return new Instance.Builder(this, dbClient, id); + } +} diff --git a/google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java b/google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java index c45a10c8fdc2..1fb1f5796851 100644 --- a/google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java +++ b/google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java @@ -25,23 +25,13 @@ import com.google.api.client.util.BackOff; import com.google.api.client.util.ExponentialBackOff; -import com.google.api.core.ApiFunction; -import com.google.api.gax.grpc.ProtoOperationTransformers; -import com.google.api.gax.longrunning.OperationFuture; -import com.google.api.gax.longrunning.OperationFutureImpl; -import com.google.api.gax.longrunning.OperationSnapshot; -import com.google.api.gax.paging.Page; import com.google.api.pathtemplate.PathTemplate; import com.google.cloud.BaseService; -import com.google.cloud.PageImpl; -import com.google.cloud.PageImpl.NextPageFetcher; import com.google.cloud.Timestamp; import com.google.cloud.spanner.AbstractReadContext.MultiUseReadOnlyTransaction; import com.google.cloud.spanner.AbstractReadContext.SingleReadContext; import com.google.cloud.spanner.AbstractReadContext.SingleUseReadOnlyTransaction; -import com.google.cloud.spanner.Options.ListOption; import com.google.cloud.spanner.spi.v1.SpannerRpc; -import com.google.cloud.spanner.spi.v1.SpannerRpc.Paginated; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; @@ -52,11 +42,8 @@ import com.google.common.util.concurrent.ListenableFuture; import com.google.protobuf.Any; import com.google.protobuf.ByteString; -import com.google.protobuf.FieldMask; import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.Message; -import com.google.spanner.admin.instance.v1.CreateInstanceMetadata; -import com.google.spanner.admin.instance.v1.UpdateInstanceMetadata; import com.google.spanner.v1.BeginTransactionRequest; import com.google.spanner.v1.CommitRequest; import com.google.spanner.v1.CommitResponse; @@ -387,205 +374,6 @@ private static T unpack(Any response, Class clazz) } } - abstract static class PageFetcher implements NextPageFetcher { - private String nextPageToken; - - @Override - public Page getNextPage() { - Paginated nextPage = - runWithRetries( - new Callable>() { - @Override - public Paginated call() { - return getNextPage(nextPageToken); - } - }); - this.nextPageToken = nextPage.getNextPageToken(); - List results = new ArrayList<>(); - for (T proto : nextPage.getResults()) { - results.add(fromProto(proto)); - } - return new PageImpl(this, nextPageToken, results); - } - - void setNextPageToken(String nextPageToken) { - this.nextPageToken = nextPageToken; - } - - abstract Paginated getNextPage(@Nullable String nextPageToken); - - abstract S fromProto(T proto); - } - - static class InstanceAdminClientImpl implements InstanceAdminClient { - final DatabaseAdminClient dbClient; - final String projectId; - final SpannerRpc rpc; - - InstanceAdminClientImpl(String projectId, SpannerRpc rpc, DatabaseAdminClient dbClient) { - this.projectId = projectId; - this.rpc = rpc; - this.dbClient = dbClient; - } - - @Override - public InstanceConfig getInstanceConfig(String configId) throws SpannerException { - final String instanceConfigName = new InstanceConfigId(projectId, configId).getName(); - return runWithRetries( - new Callable() { - @Override - public InstanceConfig call() { - return InstanceConfig.fromProto( - rpc.getInstanceConfig(instanceConfigName), InstanceAdminClientImpl.this); - } - }); - } - - @Override - public Page listInstanceConfigs(ListOption... options) { - final Options listOptions = Options.fromListOptions(options); - Preconditions.checkArgument( - !listOptions.hasFilter(), "Filter option is not supported by listInstanceConfigs"); - final int pageSize = listOptions.hasPageSize() ? listOptions.pageSize() : 0; - PageFetcher pageFetcher = - new PageFetcher() { - @Override - public Paginated getNextPage( - String nextPageToken) { - return rpc.listInstanceConfigs(pageSize, nextPageToken); - } - - @Override - public InstanceConfig fromProto( - com.google.spanner.admin.instance.v1.InstanceConfig proto) { - return InstanceConfig.fromProto(proto, InstanceAdminClientImpl.this); - } - }; - if (listOptions.hasPageToken()) { - pageFetcher.nextPageToken = listOptions.pageToken(); - } - return pageFetcher.getNextPage(); - } - - @Override - public OperationFuture createInstance(InstanceInfo instance) - throws SpannerException { - String projectName = PROJECT_NAME_TEMPLATE.instantiate("project", projectId); - OperationFuture - rawOperationFuture = - rpc.createInstance(projectName, instance.getId().getInstance(), instance.toProto()); - - return new OperationFutureImpl( - rawOperationFuture.getPollingFuture(), - rawOperationFuture.getInitialFuture(), - new ApiFunction() { - @Override - public Instance apply(OperationSnapshot snapshot) { - return Instance.fromProto( - ProtoOperationTransformers.ResponseTransformer.create( - com.google.spanner.admin.instance.v1.Instance.class) - .apply(snapshot), - InstanceAdminClientImpl.this, - dbClient); - } - }, - ProtoOperationTransformers.MetadataTransformer.create(CreateInstanceMetadata.class), - new ApiFunction() { - @Override - public Instance apply(Exception e) { - throw SpannerExceptionFactory.newSpannerException(e); - } - }); - } - - @Override - public Instance getInstance(String instanceId) throws SpannerException { - final String instanceName = new InstanceId(projectId, instanceId).getName(); - return runWithRetries( - new Callable() { - @Override - public Instance call() { - return Instance.fromProto( - rpc.getInstance(instanceName), InstanceAdminClientImpl.this, dbClient); - } - }); - } - - @Override - public Page listInstances(ListOption... options) throws SpannerException { - final Options listOptions = Options.fromListOptions(options); - final int pageSize = listOptions.hasPageSize() ? listOptions.pageSize() : 0; - final String filter = listOptions.filter(); - PageFetcher pageFetcher = - new PageFetcher() { - @Override - public Paginated getNextPage( - String nextPageToken) { - return rpc.listInstances(pageSize, nextPageToken, filter); - } - - @Override - public Instance fromProto(com.google.spanner.admin.instance.v1.Instance proto) { - return Instance.fromProto(proto, InstanceAdminClientImpl.this, dbClient); - } - }; - if (listOptions.hasPageToken()) { - pageFetcher.nextPageToken = listOptions.pageToken(); - } - return pageFetcher.getNextPage(); - } - - @Override - public void deleteInstance(final String instanceId) throws SpannerException { - runWithRetries( - new Callable() { - @Override - public Void call() { - rpc.deleteInstance(new InstanceId(projectId, instanceId).getName()); - return null; - } - }); - } - - @Override - public OperationFuture updateInstance( - InstanceInfo instance, InstanceInfo.InstanceField... fieldsToUpdate) { - FieldMask fieldMask = - fieldsToUpdate.length == 0 - ? InstanceInfo.InstanceField.toFieldMask(InstanceInfo.InstanceField.values()) - : InstanceInfo.InstanceField.toFieldMask(fieldsToUpdate); - - OperationFuture - rawOperationFuture = rpc.updateInstance(instance.toProto(), fieldMask); - return new OperationFutureImpl( - rawOperationFuture.getPollingFuture(), - rawOperationFuture.getInitialFuture(), - new ApiFunction() { - @Override - public Instance apply(OperationSnapshot snapshot) { - return Instance.fromProto( - ProtoOperationTransformers.ResponseTransformer.create( - com.google.spanner.admin.instance.v1.Instance.class) - .apply(snapshot), - InstanceAdminClientImpl.this, - dbClient); - } - }, - ProtoOperationTransformers.MetadataTransformer.create(UpdateInstanceMetadata.class), - new ApiFunction() { - @Override - public Instance apply(Exception e) { - throw SpannerExceptionFactory.newSpannerException(e); - } - }); - } - - @Override - public Instance.Builder newInstanceBuilder(InstanceId id) { - return new Instance.Builder(this, dbClient, id); - } - } - class SessionImpl implements Session { private final String name; private SessionTransaction activeTransaction; diff --git a/google-cloud-clients/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminClientImplTest.java b/google-cloud-clients/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminClientImplTest.java index 7fb451f508c5..0170ada64bd9 100644 --- a/google-cloud-clients/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminClientImplTest.java +++ b/google-cloud-clients/google-cloud-spanner/src/test/java/com/google/cloud/spanner/InstanceAdminClientImplTest.java @@ -50,12 +50,12 @@ public class InstanceAdminClientImplTest { @Mock SpannerRpc rpc; @Mock DatabaseAdminClient dbClient; - SpannerImpl.InstanceAdminClientImpl client; + InstanceAdminClientImpl client; @Before public void setUp() { initMocks(this); - client = new SpannerImpl.InstanceAdminClientImpl(PROJECT_ID, rpc, dbClient); + client = new InstanceAdminClientImpl(PROJECT_ID, rpc, dbClient); } @Test From 9e1e5059bb35b26d70900da1afdeece1f3d9968c Mon Sep 17 00:00:00 2001 From: Olav Loite Date: Tue, 9 Apr 2019 10:46:51 +0200 Subject: [PATCH 2/2] fixed merge conflicts --- .../com/google/cloud/spanner/SpannerImpl.java | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java b/google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java index 1fb1f5796851..b0229b69347b 100644 --- a/google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java +++ b/google-cloud-clients/google-cloud-spanner/src/main/java/com/google/cloud/spanner/SpannerImpl.java @@ -25,13 +25,17 @@ import com.google.api.client.util.BackOff; import com.google.api.client.util.ExponentialBackOff; +import com.google.api.gax.paging.Page; import com.google.api.pathtemplate.PathTemplate; import com.google.cloud.BaseService; +import com.google.cloud.PageImpl; +import com.google.cloud.PageImpl.NextPageFetcher; import com.google.cloud.Timestamp; import com.google.cloud.spanner.AbstractReadContext.MultiUseReadOnlyTransaction; import com.google.cloud.spanner.AbstractReadContext.SingleReadContext; import com.google.cloud.spanner.AbstractReadContext.SingleUseReadOnlyTransaction; import com.google.cloud.spanner.spi.v1.SpannerRpc; +import com.google.cloud.spanner.spi.v1.SpannerRpc.Paginated; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; @@ -374,6 +378,36 @@ private static T unpack(Any response, Class clazz) } } + abstract static class PageFetcher implements NextPageFetcher { + private String nextPageToken; + + @Override + public Page getNextPage() { + Paginated nextPage = + runWithRetries( + new Callable>() { + @Override + public Paginated call() { + return getNextPage(nextPageToken); + } + }); + this.nextPageToken = nextPage.getNextPageToken(); + List results = new ArrayList<>(); + for (T proto : nextPage.getResults()) { + results.add(fromProto(proto)); + } + return new PageImpl(this, nextPageToken, results); + } + + void setNextPageToken(String nextPageToken) { + this.nextPageToken = nextPageToken; + } + + abstract Paginated getNextPage(@Nullable String nextPageToken); + + abstract S fromProto(T proto); + } + class SessionImpl implements Session { private final String name; private SessionTransaction activeTransaction;