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..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,11 +25,6 @@ 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; @@ -39,7 +34,6 @@ 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; @@ -52,11 +46,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; @@ -417,175 +408,6 @@ void setNextPageToken(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