Skip to content

Commit

Permalink
Introduce HttpProviders and GrpcProviders (#2137)
Browse files Browse the repository at this point in the history
Motivation:

Allow users to intercept static factories that create client/server
builders to enhance builders' behavior. Users can use these providers
to override default values on the builders or to intercept builders for
metrics purposes.

Modifications:

- Add `HttpProviders` and `GrpcProviders` that define provider
interfaces for `ServiceLoader`;
- Test how users can intercept builders;

Result:

Users can change the default builders using providers that are
automatically loaded via `ServiceLoader`.
  • Loading branch information
idelpivnitskiy authored Mar 24, 2022
1 parent 0124d9f commit 13107f8
Show file tree
Hide file tree
Showing 26 changed files with 1,798 additions and 43 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright © 2022 Apple Inc. and the ServiceTalk project authors
*
* 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 io.servicetalk.grpc.api;

import java.time.Duration;

import static java.util.Objects.requireNonNull;

/**
* A {@link GrpcClientBuilder} that delegates all methods to another {@link GrpcClientBuilder}.
*
* @param <U> the type of address before resolution (unresolved address)
* @param <R> the type of address after resolution (resolved address)
*/
public class DelegatingGrpcClientBuilder<U, R> implements GrpcClientBuilder<U, R> {

private GrpcClientBuilder<U, R> delegate;

public DelegatingGrpcClientBuilder(final GrpcClientBuilder<U, R> delegate) {
this.delegate = requireNonNull(delegate);
}

/**
* Returns the {@link GrpcClientBuilder} delegate.
*
* @return Delegate {@link GrpcClientBuilder}.
*/
protected final GrpcClientBuilder<U, R> delegate() {
return delegate;
}

@Override
public String toString() {
return this.getClass().getSimpleName() + "{delegate=" + delegate() + '}';
}

@Override
public GrpcClientBuilder<U, R> initializeHttp(final HttpInitializer<U, R> initializer) {
delegate = delegate.initializeHttp(initializer);
return this;
}

@Override
public GrpcClientBuilder<U, R> defaultTimeout(final Duration defaultTimeout) {
delegate = delegate.defaultTimeout(defaultTimeout);
return this;
}

@Override
public <Client extends GrpcClient<?>> Client build(final GrpcClientFactory<Client, ?> clientFactory) {
return delegate.build(clientFactory);
}

@Override
public <BlockingClient extends BlockingGrpcClient<?>> BlockingClient buildBlocking(
final GrpcClientFactory<?, BlockingClient> clientFactory) {
return delegate.buildBlocking(clientFactory);
}

@Override
public MultiClientBuilder buildMulti() {
return delegate.buildMulti();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright © 2022 Apple Inc. and the ServiceTalk project authors
*
* 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 io.servicetalk.grpc.api;

import io.servicetalk.concurrent.api.Single;

import java.time.Duration;

import static java.util.Objects.requireNonNull;

/**
* A {@link GrpcServerBuilder} that delegates all methods to another {@link GrpcServerBuilder}.
*/
public class DelegatingGrpcServerBuilder implements GrpcServerBuilder {

private GrpcServerBuilder delegate;

public DelegatingGrpcServerBuilder(final GrpcServerBuilder delegate) {
this.delegate = requireNonNull(delegate);
}

/**
* Returns the {@link GrpcServerBuilder} delegate.
*
* @return Delegate {@link GrpcServerBuilder}.
*/
protected final GrpcServerBuilder delegate() {
return delegate;
}

@Override
public String toString() {
return this.getClass().getSimpleName() + "{delegate=" + delegate() + '}';
}

@Override
public GrpcServerBuilder initializeHttp(final HttpInitializer initializer) {
delegate = delegate.initializeHttp(initializer);
return this;
}

@Override
public GrpcServerBuilder defaultTimeout(final Duration defaultTimeout) {
delegate = delegate.defaultTimeout(defaultTimeout);
return this;
}

@Override
public GrpcServerBuilder lifecycleObserver(final GrpcLifecycleObserver lifecycleObserver) {
delegate = delegate.lifecycleObserver(lifecycleObserver);
return this;
}

@Override
public Single<GrpcServerContext> listen(final GrpcBindableService<?>... services) {
return delegate.listen(services);
}

@Override
public Single<GrpcServerContext> listen(final GrpcServiceFactory<?>... serviceFactories) {
return delegate.listen(serviceFactories);
}

@Override
public GrpcServerContext listenAndAwait(final GrpcServiceFactory<?>... serviceFactories) throws Exception {
return delegate.listenAndAwait(serviceFactories);
}

@Override
public GrpcServerContext listenAndAwait(final GrpcBindableService<?>... services) throws Exception {
return delegate.listenAndAwait(services);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright © 2022 Apple Inc. and the ServiceTalk project authors
*
* 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 io.servicetalk.grpc.api;

import io.servicetalk.http.api.HttpProviders;
import io.servicetalk.http.api.HttpProviders.HttpServerBuilderProvider;
import io.servicetalk.http.api.HttpProviders.SingleAddressHttpClientBuilderProvider;

import java.net.SocketAddress;
import java.util.ServiceLoader;

/**
* A holder for all gRPC-specific providers that can be registered using {@link ServiceLoader}.
*
* @see HttpProviders
*/
public final class GrpcProviders {

private GrpcProviders() {
// No instances.
}

/**
* Provider for {@link GrpcClientBuilder}.
* <p>
* An HTTP layer should use {@link SingleAddressHttpClientBuilderProvider}.
*/
@FunctionalInterface
public interface GrpcClientBuilderProvider {

/**
* Returns a {@link GrpcClientBuilder} based on the address and pre-initialized {@link GrpcClientBuilder}.
* <p>
* This method may return the pre-initialized {@code builder} as-is, or apply custom builder settings before
* returning it, or wrap it ({@link DelegatingGrpcClientBuilder} may be helpful).
*
* @param address a remote address used to create a {@link GrpcClientBuilder}, it can be resolved or unresolved
* based on the factory used
* @param builder pre-initialized {@link GrpcClientBuilder}
* @param <U> the type of address before resolution (unresolved address)
* @param <R> the type of address after resolution (resolved address)
* @return a {@link GrpcClientBuilder} based on the address and pre-initialized {@link GrpcClientBuilder}.
* @see DelegatingGrpcClientBuilder
*/
<U, R> GrpcClientBuilder<U, R> newBuilder(U address, GrpcClientBuilder<U, R> builder);
}

/**
* Provider for {@link GrpcServerBuilder}.
* <p>
* An HTTP layer should use {@link HttpServerBuilderProvider}.
*/
@FunctionalInterface
public interface GrpcServerBuilderProvider {

/**
* Returns a {@link GrpcServerBuilder} based on the address and pre-initialized {@link GrpcServerBuilder}.
* <p>
* This method may return the pre-initialized {@code builder} as-is, or apply custom builder settings before
* returning it, or wrap it ({@link DelegatingGrpcServerBuilder} may be helpful).
*
* @param address a server address used to create a {@link GrpcServerBuilder}
* @param builder pre-initialized {@link GrpcServerBuilder}
* @return a {@link GrpcServerBuilder} based on the address and pre-initialized{@link GrpcServerBuilder}.
* @see DelegatingGrpcServerBuilder
*/
GrpcServerBuilder newBuilder(SocketAddress address, GrpcServerBuilder builder);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ final class DefaultGrpcClientBuilder<U, R> implements GrpcClientBuilder<U, R> {

private final Supplier<SingleAddressHttpClientBuilder<U, R>> httpClientBuilderSupplier;

// Do not use this ctor directly, GrpcClients is the entry point for creating a new builder.
DefaultGrpcClientBuilder(final Supplier<SingleAddressHttpClientBuilder<U, R>> httpClientBuilderSupplier) {
this.httpClientBuilderSupplier = httpClientBuilderSupplier;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ final class DefaultGrpcServerBuilder implements GrpcServerBuilder, ServerBinder
@Nullable
private Duration defaultTimeout;

// Do not use this ctor directly, GrpcServers is the entry point for creating a new builder.
DefaultGrpcServerBuilder(final Supplier<HttpServerBuilder> httpServerBuilderSupplier) {
this.httpServerBuilderSupplier = () -> httpServerBuilderSupplier.get()
.protocols(h2Default()).allowDropRequestTrailers(true);
Expand Down
Loading

0 comments on commit 13107f8

Please sign in to comment.