From 63db06850e3defb167067bc6a9c56dc7f9fbe69c Mon Sep 17 00:00:00 2001 From: zhaohaifeng Date: Mon, 16 Mar 2015 18:32:39 +0800 Subject: [PATCH] Add simple HelloWord example handling custom header --- .../examples/header/CustomHeaderClient.java | 104 ++++++++++++++++++ .../examples/header/CustomHeaderServer.java | 94 ++++++++++++++++ .../header/HeaderClientInterceptor.java | 77 +++++++++++++ .../header/HeaderServerInterceptor.java | 85 ++++++++++++++ 4 files changed, 360 insertions(+) create mode 100644 examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java create mode 100644 examples/src/main/java/io/grpc/examples/header/CustomHeaderServer.java create mode 100644 examples/src/main/java/io/grpc/examples/header/HeaderClientInterceptor.java create mode 100644 examples/src/main/java/io/grpc/examples/header/HeaderServerInterceptor.java diff --git a/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java b/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java new file mode 100644 index 0000000000..02a3d92e81 --- /dev/null +++ b/examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java @@ -0,0 +1,104 @@ +/* + * Copyright 2015, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.grpc.examples.header; + +import io.grpc.Channel; +import io.grpc.ChannelImpl; +import io.grpc.ClientInterceptor; +import io.grpc.ClientInterceptors; +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloRequest; +import io.grpc.examples.helloworld.HelloResponse; +import io.grpc.transport.netty.NegotiationType; +import io.grpc.transport.netty.NettyChannelBuilder; + +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A simple client that like {@link io.grpc.examples.helloworld.HelloWorldClient}. + * This client can help you create custom headers. + */ +public class CustomHeaderClient { + private static final Logger logger = Logger.getLogger(CustomHeaderClient.class.getName()); + + private final ChannelImpl originChannel; + private final GreeterGrpc.GreeterBlockingStub blockingStub; + + /** + * A custom client. + */ + private CustomHeaderClient(String host, int port) { + originChannel = + NettyChannelBuilder.forAddress(host, port).negotiationType(NegotiationType.PLAINTEXT) + .build(); + ClientInterceptor interceptor = new HeaderClientInterceptor(); + Channel channel = ClientInterceptors.intercept(originChannel, interceptor); + blockingStub = GreeterGrpc.newBlockingStub(channel); + } + + private void shutdown() throws InterruptedException { + originChannel.shutdown().awaitTerminated(5, TimeUnit.SECONDS); + } + + /** + * A simple client method that like {@link io.grpc.examples.helloworld.HelloWorldClient}. + */ + private void greet(String name) { + try { + logger.info("Will try to greet " + name + " ..."); + HelloRequest request = HelloRequest.newBuilder().setName(name).build(); + HelloResponse response = blockingStub.sayHello(request); + logger.info("Greeting: " + response.getMessage()); + } catch (RuntimeException e) { + logger.log(Level.WARNING, "RPC failed", e); + } + } + + /** + * Main start the client from the command line. + */ + public static void main(String[] args) throws Exception { + CustomHeaderClient client = new CustomHeaderClient("localhost", 50051); + try { + /* Access a service running on the local machine on port 50051 */ + String user = "world"; + if (args.length > 0) { + user = args[0]; /* Use the arg as the name to greet if provided */ + } + client.greet(user); + } finally { + client.shutdown(); + } + } +} diff --git a/examples/src/main/java/io/grpc/examples/header/CustomHeaderServer.java b/examples/src/main/java/io/grpc/examples/header/CustomHeaderServer.java new file mode 100644 index 0000000000..1659e0e868 --- /dev/null +++ b/examples/src/main/java/io/grpc/examples/header/CustomHeaderServer.java @@ -0,0 +1,94 @@ +/* + * Copyright 2015, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.grpc.examples.header; + +import io.grpc.ServerImpl; +import io.grpc.ServerInterceptors; +import io.grpc.examples.helloworld.GreeterGrpc; +import io.grpc.examples.helloworld.HelloRequest; +import io.grpc.examples.helloworld.HelloResponse; +import io.grpc.stub.StreamObserver; +import io.grpc.transport.netty.NettyServerBuilder; + +import java.util.logging.Logger; + +/** + * A simple server that like {@link io.grpc.examples.helloworld.HelloWorldServer}. + * You can get and response any header in {@link io.grpc.examples.header.HeaderServerInterceptor}. + */ +public class CustomHeaderServer { + private static final Logger logger = Logger.getLogger(CustomHeaderServer.class.getName()); + + /* The port on which the server should run */ + private static final int port = 50051; + private ServerImpl server; + + private void start() throws Exception { + server = NettyServerBuilder.forPort(port).addService(ServerInterceptors + .intercept(GreeterGrpc.bindService(new GreeterImpl()), new HeaderServerInterceptor())) + .build().start(); + logger.info("Server started, listening on " + port); + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + // Use stderr here since the logger may have been reset by its JVM shutdown hook. + System.err.println("*** shutting down gRPC server since JVM is shutting down"); + CustomHeaderServer.this.stop(); + System.err.println("*** server shut down"); + } + }); + } + + private void stop() { + if (server != null) { + server.shutdown(); + } + } + + /** + * Main launches the server from the command line. + */ + public static void main(String[] args) throws Exception { + final CustomHeaderServer server = new CustomHeaderServer(); + server.start(); + } + + private class GreeterImpl implements GreeterGrpc.Greeter { + + @Override + public void sayHello(HelloRequest req, StreamObserver responseObserver) { + HelloResponse reply = HelloResponse.newBuilder().setMessage("Hello " + req.getName()).build(); + responseObserver.onValue(reply); + responseObserver.onCompleted(); + } + } +} diff --git a/examples/src/main/java/io/grpc/examples/header/HeaderClientInterceptor.java b/examples/src/main/java/io/grpc/examples/header/HeaderClientInterceptor.java new file mode 100644 index 0000000000..cafec72ea6 --- /dev/null +++ b/examples/src/main/java/io/grpc/examples/header/HeaderClientInterceptor.java @@ -0,0 +1,77 @@ +/* + * Copyright 2015, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.grpc.examples.header; + +import io.grpc.Call; +import io.grpc.Channel; +import io.grpc.ClientInterceptor; +import io.grpc.ClientInterceptors; +import io.grpc.Metadata; +import io.grpc.MethodDescriptor; + +import java.util.logging.Logger; + +/** + * A interceptor to handle client header. + */ +public class HeaderClientInterceptor implements ClientInterceptor { + + private static final Logger logger = Logger.getLogger(HeaderClientInterceptor.class.getName()); + + private static Metadata.Key customHeadKey = + Metadata.Key.of("custom_client_header_key", Metadata.ASCII_STRING_MARSHALLER); + + @Override + public Call interceptCall(MethodDescriptor method, + Channel next) { + return new ClientInterceptors.ForwardingCall(next.newCall(method)) { + + @Override + public void start(Listener responseListener, Metadata.Headers headers) { + /* put custom header */ + headers.put(customHeadKey, "customRequestValue"); + super.start(new ClientInterceptors.ForwardingListener(responseListener) { + @Override + public void onHeaders(Metadata.Headers headers) { + /** + * if you don't need receive header from server, + * you can use {@link io.grpc.stub.MetadataUtils attachHeaders} + * directly to send header + */ + logger.info("header received from server:" + headers.toString()); + super.onHeaders(headers); + } + }, headers); + } + }; + } +} diff --git a/examples/src/main/java/io/grpc/examples/header/HeaderServerInterceptor.java b/examples/src/main/java/io/grpc/examples/header/HeaderServerInterceptor.java new file mode 100644 index 0000000000..bc8e7b630f --- /dev/null +++ b/examples/src/main/java/io/grpc/examples/header/HeaderServerInterceptor.java @@ -0,0 +1,85 @@ +/* + * Copyright 2015, Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package io.grpc.examples.header; + +import io.grpc.Metadata; +import io.grpc.ServerCall; +import io.grpc.ServerCallHandler; +import io.grpc.ServerInterceptor; +import io.grpc.ServerInterceptors; +import io.grpc.Status; + +import java.util.logging.Logger; + +/** + * A interceptor to handle server header. + */ +public class HeaderServerInterceptor implements ServerInterceptor { + + private static final Logger logger = Logger.getLogger(HeaderServerInterceptor.class.getName()); + + private static Metadata.Key customHeadKey = + Metadata.Key.of("custom_server_header_key", Metadata.ASCII_STRING_MARSHALLER); + + + @Override + public ServerCall.Listener interceptCall( + String method, + ServerCall call, + final Metadata.Headers requestHeaders, + ServerCallHandler next) { + logger.info("header received from client:" + requestHeaders.toString()); + return next.startCall(method, new ServerInterceptors.ForwardingServerCall(call) { + boolean sentHeaders = false; + + @Override + public void sendHeaders(Metadata.Headers responseHeaders) { + responseHeaders.put(customHeadKey, "customRespondValue"); + super.sendHeaders(responseHeaders); + sentHeaders = true; + } + + @Override + public void sendPayload(RespT payload) { + if (!sentHeaders) { + sendHeaders(new Metadata.Headers()); + } + super.sendPayload(payload); + } + + @Override + public void close(Status status, Metadata.Trailers trailers) { + super.close(status, trailers); + } + }, requestHeaders); + } +}