|
23 | 23 | import io.grpc.ManagedChannel; |
24 | 24 | import io.grpc.MethodDescriptor; |
25 | 25 | import io.grpc.StatusRuntimeException; |
26 | | -import io.grpc.netty.GrpcSslContexts; |
27 | 26 | import io.grpc.netty.NettyChannelBuilder; |
28 | 27 | import io.grpc.stub.ClientCallStreamObserver; |
29 | 28 | import io.grpc.stub.ClientCalls; |
30 | 29 | import io.grpc.stub.ClientResponseObserver; |
31 | 30 | import io.grpc.stub.StreamObserver; |
32 | | -import io.netty.channel.EventLoopGroup; |
33 | | -import io.netty.channel.ServerChannel; |
34 | | -import io.netty.handler.ssl.SslContextBuilder; |
35 | | -import io.netty.handler.ssl.util.InsecureTrustManagerFactory; |
36 | 31 | import java.io.IOException; |
37 | 32 | import java.io.InputStream; |
38 | | -import java.lang.reflect.InvocationTargetException; |
39 | 33 | import java.net.URISyntaxException; |
40 | 34 | import java.nio.ByteBuffer; |
41 | | -import java.util.ArrayList; |
42 | 35 | import java.util.Iterator; |
43 | 36 | import java.util.List; |
44 | 37 | import java.util.Optional; |
45 | 38 | import java.util.concurrent.ExecutionException; |
46 | 39 | import java.util.concurrent.TimeUnit; |
47 | 40 | import java.util.function.BooleanSupplier; |
48 | | -import javax.net.ssl.SSLException; |
49 | 41 | import org.apache.arrow.flight.FlightProducer.StreamListener; |
50 | 42 | import org.apache.arrow.flight.auth.BasicClientAuthHandler; |
51 | 43 | import org.apache.arrow.flight.auth.ClientAuthHandler; |
|
57 | 49 | import org.apache.arrow.flight.auth2.ClientIncomingAuthHeaderMiddleware; |
58 | 50 | import org.apache.arrow.flight.grpc.ClientInterceptorAdapter; |
59 | 51 | import org.apache.arrow.flight.grpc.CredentialCallOption; |
| 52 | +import org.apache.arrow.flight.grpc.NettyClientBuilder; |
60 | 53 | import org.apache.arrow.flight.grpc.StatusUtils; |
61 | 54 | import org.apache.arrow.flight.impl.Flight; |
62 | 55 | import org.apache.arrow.flight.impl.Flight.Empty; |
|
72 | 65 | /** Client for Flight services. */ |
73 | 66 | public class FlightClient implements AutoCloseable { |
74 | 67 | private static final int PENDING_REQUESTS = 5; |
75 | | - /** |
76 | | - * The maximum number of trace events to keep on the gRPC Channel. This value disables channel |
77 | | - * tracing. |
78 | | - */ |
79 | | - private static final int MAX_CHANNEL_TRACE_EVENTS = 0; |
80 | 68 |
|
81 | 69 | private final BufferAllocator allocator; |
82 | 70 | private final ManagedChannel channel; |
@@ -771,176 +759,71 @@ public static Builder builder(BufferAllocator allocator, Location location) { |
771 | 759 |
|
772 | 760 | /** A builder for Flight clients. */ |
773 | 761 | public static final class Builder { |
774 | | - private BufferAllocator allocator; |
775 | | - private Location location; |
776 | | - private boolean forceTls = false; |
777 | | - private int maxInboundMessageSize = FlightServer.MAX_GRPC_MESSAGE_SIZE; |
778 | | - private InputStream trustedCertificates = null; |
779 | | - private InputStream clientCertificate = null; |
780 | | - private InputStream clientKey = null; |
781 | | - private String overrideHostname = null; |
782 | | - private List<FlightClientMiddleware.Factory> middleware = new ArrayList<>(); |
783 | | - private boolean verifyServer = true; |
784 | | - |
785 | | - private Builder() {} |
| 762 | + private final NettyClientBuilder builder; |
| 763 | + |
| 764 | + private Builder() { |
| 765 | + this.builder = new NettyClientBuilder(); |
| 766 | + } |
786 | 767 |
|
787 | 768 | private Builder(BufferAllocator allocator, Location location) { |
788 | | - this.allocator = Preconditions.checkNotNull(allocator); |
789 | | - this.location = Preconditions.checkNotNull(location); |
| 769 | + this.builder = new NettyClientBuilder(allocator, location); |
790 | 770 | } |
791 | 771 |
|
792 | 772 | /** Force the client to connect over TLS. */ |
793 | 773 | public Builder useTls() { |
794 | | - this.forceTls = true; |
| 774 | + builder.useTls(); |
795 | 775 | return this; |
796 | 776 | } |
797 | 777 |
|
798 | 778 | /** Override the hostname checked for TLS. Use with caution in production. */ |
799 | 779 | public Builder overrideHostname(final String hostname) { |
800 | | - this.overrideHostname = hostname; |
| 780 | + builder.overrideHostname(hostname); |
801 | 781 | return this; |
802 | 782 | } |
803 | 783 |
|
804 | 784 | /** Set the maximum inbound message size. */ |
805 | 785 | public Builder maxInboundMessageSize(int maxSize) { |
806 | | - Preconditions.checkArgument(maxSize > 0); |
807 | | - this.maxInboundMessageSize = maxSize; |
| 786 | + builder.maxInboundMessageSize(maxSize); |
808 | 787 | return this; |
809 | 788 | } |
810 | 789 |
|
811 | 790 | /** Set the trusted TLS certificates. */ |
812 | 791 | public Builder trustedCertificates(final InputStream stream) { |
813 | | - this.trustedCertificates = Preconditions.checkNotNull(stream); |
| 792 | + builder.trustedCertificates(stream); |
814 | 793 | return this; |
815 | 794 | } |
816 | 795 |
|
817 | 796 | /** Set the trusted TLS certificates. */ |
818 | 797 | public Builder clientCertificate( |
819 | 798 | final InputStream clientCertificate, final InputStream clientKey) { |
820 | | - Preconditions.checkNotNull(clientKey); |
821 | | - this.clientCertificate = Preconditions.checkNotNull(clientCertificate); |
822 | | - this.clientKey = Preconditions.checkNotNull(clientKey); |
| 799 | + builder.clientCertificate(clientCertificate, clientKey); |
823 | 800 | return this; |
824 | 801 | } |
825 | 802 |
|
826 | 803 | public Builder allocator(BufferAllocator allocator) { |
827 | | - this.allocator = Preconditions.checkNotNull(allocator); |
| 804 | + builder.allocator(allocator); |
828 | 805 | return this; |
829 | 806 | } |
830 | 807 |
|
831 | 808 | public Builder location(Location location) { |
832 | | - this.location = Preconditions.checkNotNull(location); |
| 809 | + builder.location(location); |
833 | 810 | return this; |
834 | 811 | } |
835 | 812 |
|
836 | 813 | public Builder intercept(FlightClientMiddleware.Factory factory) { |
837 | | - middleware.add(factory); |
| 814 | + builder.intercept(factory); |
838 | 815 | return this; |
839 | 816 | } |
840 | 817 |
|
841 | 818 | public Builder verifyServer(boolean verifyServer) { |
842 | | - this.verifyServer = verifyServer; |
| 819 | + builder.verifyServer(verifyServer); |
843 | 820 | return this; |
844 | 821 | } |
845 | 822 |
|
846 | 823 | /** Create the client from this builder. */ |
847 | 824 | public FlightClient build() { |
848 | | - final NettyChannelBuilder builder; |
849 | | - |
850 | | - switch (location.getUri().getScheme()) { |
851 | | - case LocationSchemes.GRPC: |
852 | | - case LocationSchemes.GRPC_INSECURE: |
853 | | - case LocationSchemes.GRPC_TLS: |
854 | | - { |
855 | | - builder = NettyChannelBuilder.forAddress(location.toSocketAddress()); |
856 | | - break; |
857 | | - } |
858 | | - case LocationSchemes.GRPC_DOMAIN_SOCKET: |
859 | | - { |
860 | | - // The implementation is platform-specific, so we have to find the classes at runtime |
861 | | - builder = NettyChannelBuilder.forAddress(location.toSocketAddress()); |
862 | | - try { |
863 | | - try { |
864 | | - // Linux |
865 | | - builder.channelType( |
866 | | - Class.forName("io.netty.channel.epoll.EpollDomainSocketChannel") |
867 | | - .asSubclass(ServerChannel.class)); |
868 | | - final EventLoopGroup elg = |
869 | | - Class.forName("io.netty.channel.epoll.EpollEventLoopGroup") |
870 | | - .asSubclass(EventLoopGroup.class) |
871 | | - .getDeclaredConstructor() |
872 | | - .newInstance(); |
873 | | - builder.eventLoopGroup(elg); |
874 | | - } catch (ClassNotFoundException e) { |
875 | | - // BSD |
876 | | - builder.channelType( |
877 | | - Class.forName("io.netty.channel.kqueue.KQueueDomainSocketChannel") |
878 | | - .asSubclass(ServerChannel.class)); |
879 | | - final EventLoopGroup elg = |
880 | | - Class.forName("io.netty.channel.kqueue.KQueueEventLoopGroup") |
881 | | - .asSubclass(EventLoopGroup.class) |
882 | | - .getDeclaredConstructor() |
883 | | - .newInstance(); |
884 | | - builder.eventLoopGroup(elg); |
885 | | - } |
886 | | - } catch (ClassNotFoundException |
887 | | - | InstantiationException |
888 | | - | IllegalAccessException |
889 | | - | NoSuchMethodException |
890 | | - | InvocationTargetException e) { |
891 | | - throw new UnsupportedOperationException( |
892 | | - "Could not find suitable Netty native transport implementation for domain socket address."); |
893 | | - } |
894 | | - break; |
895 | | - } |
896 | | - default: |
897 | | - throw new IllegalArgumentException( |
898 | | - "Scheme is not supported: " + location.getUri().getScheme()); |
899 | | - } |
900 | | - |
901 | | - if (this.forceTls || LocationSchemes.GRPC_TLS.equals(location.getUri().getScheme())) { |
902 | | - builder.useTransportSecurity(); |
903 | | - |
904 | | - final boolean hasTrustedCerts = this.trustedCertificates != null; |
905 | | - final boolean hasKeyCertPair = this.clientCertificate != null && this.clientKey != null; |
906 | | - if (!this.verifyServer && (hasTrustedCerts || hasKeyCertPair)) { |
907 | | - throw new IllegalArgumentException( |
908 | | - "FlightClient has been configured to disable server verification, " |
909 | | - + "but certificate options have been specified."); |
910 | | - } |
911 | | - |
912 | | - final SslContextBuilder sslContextBuilder = GrpcSslContexts.forClient(); |
913 | | - |
914 | | - if (!this.verifyServer) { |
915 | | - sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE); |
916 | | - } else if (this.trustedCertificates != null |
917 | | - || this.clientCertificate != null |
918 | | - || this.clientKey != null) { |
919 | | - if (this.trustedCertificates != null) { |
920 | | - sslContextBuilder.trustManager(this.trustedCertificates); |
921 | | - } |
922 | | - if (this.clientCertificate != null && this.clientKey != null) { |
923 | | - sslContextBuilder.keyManager(this.clientCertificate, this.clientKey); |
924 | | - } |
925 | | - } |
926 | | - try { |
927 | | - builder.sslContext(sslContextBuilder.build()); |
928 | | - } catch (SSLException e) { |
929 | | - throw new RuntimeException(e); |
930 | | - } |
931 | | - |
932 | | - if (this.overrideHostname != null) { |
933 | | - builder.overrideAuthority(this.overrideHostname); |
934 | | - } |
935 | | - } else { |
936 | | - builder.usePlaintext(); |
937 | | - } |
938 | | - |
939 | | - builder |
940 | | - .maxTraceEvents(MAX_CHANNEL_TRACE_EVENTS) |
941 | | - .maxInboundMessageSize(maxInboundMessageSize) |
942 | | - .maxInboundMetadataSize(maxInboundMessageSize); |
943 | | - return new FlightClient(allocator, builder.build(), middleware); |
| 825 | + final NettyChannelBuilder channelBuilder = builder.build(); |
| 826 | + return new FlightClient(builder.allocator(), channelBuilder.build(), builder.middleware()); |
944 | 827 | } |
945 | 828 | } |
946 | 829 |
|
|
0 commit comments