Skip to content

Commit

Permalink
Merge pull request googleapis#25 from garrettjonesgoogle/master
Browse files Browse the repository at this point in the history
Splitting ServiceApiSettings back out of ApiCallSettings
  • Loading branch information
garrettjonesgoogle committed Mar 11, 2016
2 parents 8a1d7a2 + 5285af4 commit 7df9c01
Show file tree
Hide file tree
Showing 3 changed files with 212 additions and 271 deletions.
235 changes: 6 additions & 229 deletions src/main/java/com/google/api/gax/grpc/ApiCallSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,221 +31,22 @@

package com.google.api.gax.grpc;

import com.google.api.gax.core.ConnectionSettings;
import com.google.api.gax.core.RetryParams;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.MoreExecutors;

import io.grpc.ClientInterceptor;
import io.grpc.ManagedChannel;
import io.grpc.Status;
import io.grpc.auth.ClientAuthInterceptor;
import io.grpc.netty.NegotiationType;
import io.grpc.netty.NettyChannelBuilder;

import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;

// TODO(pongad): Don't close the channel if the user gives one to us
/**
* A settings class to configure API method calls for either a single method or a
* whole service.
*
* A note on channels: whichever service API class that this instance of ServiceApiSettings
* is passed to will call shutdown() on the channel provided by {@link getChannel}.
* Setting a channel is intended for use by unit tests to override the channel,
* and should not be used in production.
* A settings class to configure an API method.
*/
public class ApiCallSettings {

private ChannelProvider channelProvider;
private ExecutorProvider executorProvider;

private Set<Status.Code> defaultRetryableCodes = null;
private Set<Status.Code> retryableCodes = null;

private RetryParams defaultRetryParams = null;
private Set<Status.Code> retryableCodes = new HashSet<>();
private RetryParams retryParams = null;

public static final int DEFAULT_EXECUTOR_THREADS = 4;

/**
* Constructs an instance of ApiCallSettings.
*/
public ApiCallSettings() {
channelProvider = new ChannelProvider() {
@Override
public ManagedChannel getChannel(Executor executor) {
throw new RuntimeException("No Channel or ConnectionSettings provided.");
}

@Override
public boolean isOverridden() {
return false;
}
};
executorProvider = new ExecutorProvider() {
private ScheduledExecutorService executor = null;
@Override
public ScheduledExecutorService getExecutor() {
if (executor != null) {
return executor;
}
executor = MoreExecutors.getExitingScheduledExecutorService(
new ScheduledThreadPoolExecutor(DEFAULT_EXECUTOR_THREADS));
return executor;
}

@Override
public boolean isOverridden() {
return false;
}
};
retryableCodes = new HashSet<>();
}

private interface ChannelProvider {
ManagedChannel getChannel(Executor executor) throws IOException;
boolean isOverridden();
}

/**
* Sets a channel for this ApiCallSettings to use. This prevents a channel
* from being created.
*
* See class documentation for more details on channels.
*/
public ApiCallSettings provideChannelWith(final ManagedChannel channel) {
channelProvider = new ChannelProvider() {
@Override
public ManagedChannel getChannel(Executor executor) {
return channel;
}

@Override
public boolean isOverridden() {
return true;
}
};
return this;
}

/**
* Provides the connection settings necessary to create a channel.
*/
public ApiCallSettings provideChannelWith(final ConnectionSettings settings) {
channelProvider = new ChannelProvider() {
private ManagedChannel channel = null;
@Override
public ManagedChannel getChannel(Executor executor) throws IOException {
if (channel != null) {
return channel;
}

List<ClientInterceptor> interceptors = Lists.newArrayList();
interceptors.add(new ClientAuthInterceptor(settings.getCredentials(), executor));

channel = NettyChannelBuilder.forAddress(settings.getServiceAddress(), settings.getPort())
.negotiationType(NegotiationType.TLS)
.intercept(interceptors)
.build();
return channel;
}

@Override
public boolean isOverridden() {
return true;
}
};
return this;
}

/**
* The channel used to send requests to the service.
*
* If no channel was set, a default channel will be instantiated, using
* the connection settings provided.
*
* See class documentation for more details on channels.
*/
public ManagedChannel getChannel() throws IOException {
return channelProvider.getChannel(getExecutor());
}

/**
* Returns true if either a channel was set or connection settings were
* provided to create a channel.
*/
public boolean isChannelOverridden() {
return channelProvider.isOverridden();
}

private interface ExecutorProvider {
ScheduledExecutorService getExecutor();
boolean isOverridden();
}

/**
* Sets the executor to use for channels, retries, and bundling.
*
* It is up to the user to terminate the {@code Executor} when it is no longer needed.
*/
public ApiCallSettings setExecutor(final ScheduledExecutorService executor) {
executorProvider = new ExecutorProvider() {
@Override
public ScheduledExecutorService getExecutor() {
return executor;
}

@Override
public boolean isOverridden() {
return true;
}
};
return this;
}

/**
* The executor to be used by the client.
*
* If no executor was set, a default {@link java.util.concurrent.ScheduledThreadPoolExecutor}
* with {@link DEFAULT_EXECUTOR_THREADS} will be instantiated.
*
* The default executor is guaranteed to not prevent JVM from normally exiting,
* but may wait for up to 120 seconds after all non-daemon threads exit to give received tasks
* time to complete.
*
* If this behavior is not desirable, the user may specify a custom {@code Executor}.
*/
public ScheduledExecutorService getExecutor() {
return executorProvider.getExecutor();
}

/**
* Returns true if an executor was set.
*/
public boolean isExecutorOverridden() {
return executorProvider.isOverridden();
}

/**
* Sets the defaults to use for retryable codes and retry params.
*
* If setRetryableCodes is not called, the default retryableCodes provided here will be returned
* from getRetryableCodes. Likewise, if setRetryParams is not called, the default retryParams
* provided here will be returned from getRetryParams.
*/
public void setRetryDefaults(Set<Status.Code> retryableCodes, RetryParams retryParams) {
this.defaultRetryableCodes = retryableCodes;
this.retryParams = retryParams;
}

/**
* Sets the retryable codes.
*/
Expand All @@ -263,22 +64,10 @@ public ApiCallSettings setRetryableCodes(Status.Code... codes) {
}

/**
* Gets the retryable codes that were set previously, or if they were not, then returns
* the default retryable codes provided previously.
* Gets the retryable codes.
*/
public Set<Status.Code> getRetryableCodes() {
if (isRetryableCodesOverridden()) {
return retryableCodes;
} else {
return defaultRetryableCodes;
}
}

/**
* Returns true if the retryable codes were set.
*/
public boolean isRetryableCodesOverridden() {
return retryableCodes != null;
return retryableCodes;
}

/**
Expand All @@ -290,21 +79,9 @@ public ApiCallSettings setRetryParams(RetryParams retryParams) {
}

/**
* Returns the retry params that were set previously, or if they were not, then returns
* the default retry params provided previously.
* Returns the retry params.
*/
public RetryParams getRetryParams() {
if (isRetryParamsOverridden()) {
return retryParams;
} else {
return defaultRetryParams;
}
}

/**
* Returns true if the retry params were set.
*/
public boolean isRetryParamsOverridden() {
return retryParams != null;
return retryParams;
}
}
55 changes: 13 additions & 42 deletions src/main/java/com/google/api/gax/grpc/ApiCallable.java
Original file line number Diff line number Diff line change
Expand Up @@ -244,45 +244,20 @@ public ApiCallableBuilder(MethodDescriptor<RequestT, ResponseT> grpcMethodDescri
/**
* Builds an ApiCallable using the settings provided.
*
* @param serviceLevelSettings Settings provided in serviceLevelSettings override default
* values from this ApiCallableBuilder, but explicitly-set values set on this
* ApiCallableBuilder override both.
* @param serviceApiSettings Provides the channel and executor.
*/
public ApiCallable<RequestT, ResponseT> build(ApiCallSettings serviceLevelSettings)
public ApiCallable<RequestT, ResponseT> build(ServiceApiSettings serviceApiSettings)
throws IOException {
ApiCallable<RequestT, ResponseT> callable = baseCallable;

ManagedChannel channel = null;
if (isChannelOverridden()) {
channel = getChannel();
} else {
channel = serviceLevelSettings.getChannel();
}
ManagedChannel channel = serviceApiSettings.getChannel();
ScheduledExecutorService executor = serviceApiSettings.getExecutor();

ScheduledExecutorService executor = null;
if (isExecutorOverridden()) {
executor = getExecutor();
} else {
executor = serviceLevelSettings.getExecutor();
if (getRetryableCodes() != null) {
callable = callable.retryableOn(ImmutableSet.copyOf(getRetryableCodes()));
}

ImmutableSet<Status.Code> retryableCodes = null;
if (isRetryableCodesOverridden() || !serviceLevelSettings.isRetryableCodesOverridden()) {
retryableCodes = ImmutableSet.copyOf(getRetryableCodes());
} else {
retryableCodes = ImmutableSet.copyOf(serviceLevelSettings.getRetryableCodes());
}
if (retryableCodes != null) {
callable = callable.retryableOn(retryableCodes);
}

RetryParams retryParams = null;
if (isRetryParamsOverridden() || !serviceLevelSettings.isRetryParamsOverridden()) {
retryParams = getRetryParams();
} else {
retryParams = serviceLevelSettings.getRetryParams();
}
if (retryParams != null) {
if (getRetryParams() != null) {
callable = callable.retrying(getRetryParams(), executor);
}

Expand Down Expand Up @@ -318,13 +293,11 @@ public PageStreamingApiCallableBuilder(
/**
* Builds an ApiCallable with an Iterable response using the settings provided.
*
* @param serviceLevelSettings Settings provided in serviceLevelSettings override default
* values from this ApiCallableBuilder, but explicitly-set values set on this
* ApiCallableBuilder override both.
* @param serviceApiSettings Provides the channel and executor.
*/
public ApiCallable<RequestT, Iterable<ResourceT>> buildPageStreaming(
ApiCallSettings serviceLevelSettings) throws IOException {
return build(serviceLevelSettings).pageStreaming(pageDescriptor);
ServiceApiSettings serviceApiSettings) throws IOException {
return build(serviceApiSettings).pageStreaming(pageDescriptor);
}
}

Expand Down Expand Up @@ -394,13 +367,11 @@ public BundlingSettings<RequestT, ResponseT> getBundlingSettings() {
/**
* Builds an ApiCallable which supports bundling, using the settings provided.
*
* @param serviceLevelSettings Settings provided in serviceLevelSettings override default
* values from this ApiCallableBuilder, but explicitly-set values set on this
* ApiCallableBuilder override both.
* @param serviceApiSettings Provides the channel and executor.
*/
public BundlableApiCallableInfo<RequestT, ResponseT> buildBundlable(
ApiCallSettings serviceLevelSettings) throws IOException {
ApiCallable<RequestT, ResponseT> callable = build(serviceLevelSettings);
ServiceApiSettings serviceApiSettings) throws IOException {
ApiCallable<RequestT, ResponseT> callable = build(serviceApiSettings);
BundlerFactory<RequestT, ResponseT> bundlerFactory = null;
if (bundlingSettings != null) {
bundlerFactory = new BundlerFactory<>(bundlingDescriptor, bundlingSettings);
Expand Down
Loading

0 comments on commit 7df9c01

Please sign in to comment.