├── examples ├── settings.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── src │ └── main │ │ ├── proto │ │ ├── helloworld.proto │ │ ├── route_guide.proto │ │ └── error_details.proto │ │ ├── java │ │ └── io │ │ │ └── grpc │ │ │ └── examples │ │ │ ├── header │ │ │ ├── HeaderServerInterceptor.java │ │ │ ├── HeaderClientInterceptor.java │ │ │ ├── CustomHeaderServer.java │ │ │ └── CustomHeaderClient.java │ │ │ └── helloworld │ │ │ ├── HelloWorldServer.java │ │ │ └── HelloWorldClient.java │ │ └── resources │ │ └── io │ │ └── grpc │ │ └── examples │ │ └── routeguide │ │ └── route_guide_db.json ├── gradlew.bat ├── pom.xml ├── build.gradle └── gradlew └── README.md /examples/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'examples' 2 | -------------------------------------------------------------------------------- /examples/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/makdharma/grpc-zookeeper-lb/HEAD/examples/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /examples/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Apr 06 10:19:48 PDT 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.4.1-bin.zip 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # grpc-zookeeper-lb 2 | This is a toy example of using Zookeeper for load balancing with gRPC. To run: 3 | 1. Compile HelloWorldClient and HelloWorldServer. 4 | 5 | ```git clone https://github.com/makdharma/grpc-zookeeper-lb``` 6 | 7 | ```cd grpc-zookeeper-lb/examples; ./gradelw installDist``` 8 | 9 | 2. Download zookeeper stock docker image and start zookeeper. 10 | 11 | ```docker pull zookeeper``` 12 | 13 | ```docker run -p 2181:2181 --restart always -d zookeeper``` 14 | 15 | 3. Start couple of servers 16 | 17 | ```./build/install/examples/bin/hello-world-server 50000 zk://localhost:2181``` 18 | 19 | ```./build/install/examples/bin/hello-world-server 50001 zk://localhost:2181``` 20 | 21 | 4. Run hello-world-client. It should alternate between two servers. 22 | 23 | ```./build/install/examples/bin/hello-world-client zk://localhost:2181``` 24 | 25 | -------------------------------------------------------------------------------- /examples/src/main/proto/helloworld.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | syntax = "proto3"; 31 | 32 | option java_multiple_files = true; 33 | option java_package = "io.grpc.examples.helloworld"; 34 | option java_outer_classname = "HelloWorldProto"; 35 | option objc_class_prefix = "HLW"; 36 | 37 | package helloworld; 38 | 39 | // The greeting service definition. 40 | service Greeter { 41 | // Sends a greeting 42 | rpc SayHello (HelloRequest) returns (HelloReply) {} 43 | } 44 | 45 | // The request message containing the user's name. 46 | message HelloRequest { 47 | string name = 1; 48 | } 49 | 50 | // The response message containing the greetings 51 | message HelloReply { 52 | string message = 1; 53 | } 54 | -------------------------------------------------------------------------------- /examples/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /examples/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | io.grpc 5 | examples 6 | jar 7 | 9 | 1.3.0 10 | examples 11 | http://maven.apache.org 12 | 13 | 1.3.0 14 | 15 | 16 | 17 | io.grpc 18 | grpc-netty 19 | ${grpc.version} 20 | 21 | 22 | io.grpc 23 | grpc-protobuf 24 | ${grpc.version} 25 | 26 | 27 | io.grpc 28 | grpc-stub 29 | ${grpc.version} 30 | 31 | 32 | junit 33 | junit 34 | 4.11 35 | test 36 | 37 | 38 | org.mockito 39 | mockito-core 40 | 1.9.5 41 | test 42 | 43 | 44 | 45 | 46 | 47 | kr.motd.maven 48 | os-maven-plugin 49 | 1.4.1.Final 50 | 51 | 52 | 53 | 54 | org.xolstice.maven.plugins 55 | protobuf-maven-plugin 56 | 0.5.0 57 | 58 | com.google.protobuf:protoc:3.2.0:exe:${os.detected.classifier} 59 | grpc-java 60 | io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier} 61 | 62 | 63 | 64 | 65 | compile 66 | compile-custom 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /examples/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'com.google.protobuf' 3 | 4 | buildscript { 5 | repositories { 6 | mavenCentral() 7 | } 8 | dependencies { 9 | // ASSUMES GRADLE 2.12 OR HIGHER. Use plugin version 0.7.5 with earlier 10 | // gradle versions 11 | classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0' 12 | } 13 | } 14 | 15 | repositories { 16 | mavenCentral() 17 | mavenLocal() 18 | } 19 | 20 | // IMPORTANT: You probably want the non-SNAPSHOT version of gRPC. Make sure you 21 | // are looking at a tagged version of the example and not "master"! 22 | 23 | // Feel free to delete the comment at the next line. It is just for safely 24 | // updating the version in our release process. 25 | def grpcVersion = '1.3.0' // CURRENT_GRPC_VERSION 26 | 27 | dependencies { 28 | compile "io.grpc:grpc-netty:${grpcVersion}" 29 | compile "io.grpc:grpc-protobuf:${grpcVersion}" 30 | compile "io.grpc:grpc-stub:${grpcVersion}" 31 | compile 'org.apache.zookeeper:zookeeper:3.4.8' 32 | 33 | testCompile "junit:junit:4.11" 34 | testCompile "org.mockito:mockito-core:1.9.5" 35 | } 36 | 37 | protobuf { 38 | protoc { 39 | artifact = 'com.google.protobuf:protoc:3.2.0' 40 | } 41 | plugins { 42 | grpc { 43 | artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" 44 | } 45 | } 46 | generateProtoTasks { 47 | all()*.plugins { 48 | grpc { 49 | // To generate deprecated interfaces and static bindService method, 50 | // turn the enable_deprecated option to true below: 51 | option 'enable_deprecated=false' 52 | } 53 | } 54 | } 55 | } 56 | 57 | // Inform IntelliJ projects about the generated code. 58 | apply plugin: 'idea' 59 | 60 | idea { 61 | module { 62 | // Not using generatedSourceDirs because of 63 | // https://discuss.gradle.org/t/support-for-intellij-2016/15294/8 64 | sourceDirs += file("${projectDir}/build/generated/source/proto/main/java"); 65 | sourceDirs += file("${projectDir}/build/generated/source/proto/main/grpc"); 66 | } 67 | } 68 | 69 | // Provide convenience executables for trying out the examples. 70 | apply plugin: 'application' 71 | 72 | startScripts.enabled = false 73 | 74 | task helloWorldServer(type: CreateStartScripts) { 75 | mainClassName = 'io.grpc.examples.helloworld.HelloWorldServer' 76 | applicationName = 'hello-world-server' 77 | outputDir = new File(project.buildDir, 'tmp') 78 | classpath = jar.outputs.files + project.configurations.runtime 79 | } 80 | 81 | task helloWorldClient(type: CreateStartScripts) { 82 | mainClassName = 'io.grpc.examples.helloworld.HelloWorldClient' 83 | applicationName = 'hello-world-client' 84 | outputDir = new File(project.buildDir, 'tmp') 85 | classpath = jar.outputs.files + project.configurations.runtime 86 | } 87 | 88 | applicationDistribution.into('bin') { 89 | from(helloWorldServer) 90 | from(helloWorldClient) 91 | fileMode = 0755 92 | } 93 | -------------------------------------------------------------------------------- /examples/src/main/java/io/grpc/examples/header/HeaderServerInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, Google Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * * Neither the name of Google Inc. nor the names of its 16 | * contributors may be used to endorse or promote products derived from 17 | * this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | package io.grpc.examples.header; 33 | 34 | import com.google.common.annotations.VisibleForTesting; 35 | import io.grpc.ForwardingServerCall.SimpleForwardingServerCall; 36 | import io.grpc.Metadata; 37 | import io.grpc.ServerCall; 38 | import io.grpc.ServerCallHandler; 39 | import io.grpc.ServerInterceptor; 40 | import java.util.logging.Logger; 41 | 42 | /** 43 | * A interceptor to handle server header. 44 | */ 45 | public class HeaderServerInterceptor implements ServerInterceptor { 46 | 47 | private static final Logger logger = Logger.getLogger(HeaderServerInterceptor.class.getName()); 48 | 49 | @VisibleForTesting 50 | static final Metadata.Key CUSTOM_HEADER_KEY = 51 | Metadata.Key.of("custom_server_header_key", Metadata.ASCII_STRING_MARSHALLER); 52 | 53 | 54 | @Override 55 | public ServerCall.Listener interceptCall( 56 | ServerCall call, 57 | final Metadata requestHeaders, 58 | ServerCallHandler next) { 59 | logger.info("header received from client:" + requestHeaders); 60 | return next.startCall(new SimpleForwardingServerCall(call) { 61 | @Override 62 | public void sendHeaders(Metadata responseHeaders) { 63 | responseHeaders.put(CUSTOM_HEADER_KEY, "customRespondValue"); 64 | super.sendHeaders(responseHeaders); 65 | } 66 | }, requestHeaders); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /examples/src/main/java/io/grpc/examples/header/HeaderClientInterceptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, Google Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * * Neither the name of Google Inc. nor the names of its 16 | * contributors may be used to endorse or promote products derived from 17 | * this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | package io.grpc.examples.header; 33 | 34 | import com.google.common.annotations.VisibleForTesting; 35 | import io.grpc.CallOptions; 36 | import io.grpc.Channel; 37 | import io.grpc.ClientCall; 38 | import io.grpc.ClientInterceptor; 39 | import io.grpc.ForwardingClientCall.SimpleForwardingClientCall; 40 | import io.grpc.ForwardingClientCallListener.SimpleForwardingClientCallListener; 41 | import io.grpc.Metadata; 42 | import io.grpc.MethodDescriptor; 43 | import java.util.logging.Logger; 44 | 45 | /** 46 | * A interceptor to handle client header. 47 | */ 48 | public class HeaderClientInterceptor implements ClientInterceptor { 49 | 50 | private static final Logger logger = Logger.getLogger(HeaderClientInterceptor.class.getName()); 51 | 52 | @VisibleForTesting 53 | static final Metadata.Key CUSTOM_HEADER_KEY = 54 | Metadata.Key.of("custom_client_header_key", Metadata.ASCII_STRING_MARSHALLER); 55 | 56 | @Override 57 | public ClientCall interceptCall(MethodDescriptor method, 58 | CallOptions callOptions, Channel next) { 59 | return new SimpleForwardingClientCall(next.newCall(method, callOptions)) { 60 | 61 | @Override 62 | public void start(Listener responseListener, Metadata headers) { 63 | /* put custom header */ 64 | headers.put(CUSTOM_HEADER_KEY, "customRequestValue"); 65 | super.start(new SimpleForwardingClientCallListener(responseListener) { 66 | @Override 67 | public void onHeaders(Metadata headers) { 68 | /** 69 | * if you don't need receive header from server, 70 | * you can use {@link io.grpc.stub.MetadataUtils#attachHeaders} 71 | * directly to send header 72 | */ 73 | logger.info("header received from server:" + headers); 74 | super.onHeaders(headers); 75 | } 76 | }, headers); 77 | } 78 | }; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /examples/src/main/java/io/grpc/examples/header/CustomHeaderServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, Google Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * * Neither the name of Google Inc. nor the names of its 16 | * contributors may be used to endorse or promote products derived from 17 | * this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | package io.grpc.examples.header; 33 | 34 | import io.grpc.Server; 35 | import io.grpc.ServerBuilder; 36 | import io.grpc.ServerInterceptors; 37 | import io.grpc.examples.helloworld.GreeterGrpc; 38 | import io.grpc.examples.helloworld.HelloReply; 39 | import io.grpc.examples.helloworld.HelloRequest; 40 | import io.grpc.stub.StreamObserver; 41 | import java.io.IOException; 42 | import java.util.logging.Logger; 43 | 44 | /** 45 | * A simple server that like {@link io.grpc.examples.helloworld.HelloWorldServer}. 46 | * You can get and response any header in {@link io.grpc.examples.header.HeaderServerInterceptor}. 47 | */ 48 | public class CustomHeaderServer { 49 | private static final Logger logger = Logger.getLogger(CustomHeaderServer.class.getName()); 50 | 51 | /* The port on which the server should run */ 52 | private static final int port = 50051; 53 | private Server server; 54 | 55 | private void start() throws IOException { 56 | server = ServerBuilder.forPort(port) 57 | .addService(ServerInterceptors.intercept(new GreeterImpl(), new HeaderServerInterceptor())) 58 | .build() 59 | .start(); 60 | logger.info("Server started, listening on " + port); 61 | Runtime.getRuntime().addShutdownHook(new Thread() { 62 | @Override 63 | public void run() { 64 | // Use stderr here since the logger may have been reset by its JVM shutdown hook. 65 | System.err.println("*** shutting down gRPC server since JVM is shutting down"); 66 | CustomHeaderServer.this.stop(); 67 | System.err.println("*** server shut down"); 68 | } 69 | }); 70 | } 71 | 72 | private void stop() { 73 | if (server != null) { 74 | server.shutdown(); 75 | } 76 | } 77 | 78 | /** 79 | * Await termination on the main thread since the grpc library uses daemon threads. 80 | */ 81 | private void blockUntilShutdown() throws InterruptedException { 82 | if (server != null) { 83 | server.awaitTermination(); 84 | } 85 | } 86 | 87 | /** 88 | * Main launches the server from the command line. 89 | */ 90 | public static void main(String[] args) throws IOException, InterruptedException { 91 | final CustomHeaderServer server = new CustomHeaderServer(); 92 | server.start(); 93 | server.blockUntilShutdown(); 94 | } 95 | 96 | private static class GreeterImpl extends GreeterGrpc.GreeterImplBase { 97 | 98 | @Override 99 | public void sayHello(HelloRequest req, StreamObserver responseObserver) { 100 | HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build(); 101 | responseObserver.onNext(reply); 102 | responseObserver.onCompleted(); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /examples/src/main/java/io/grpc/examples/header/CustomHeaderClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, Google Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * * Neither the name of Google Inc. nor the names of its 16 | * contributors may be used to endorse or promote products derived from 17 | * this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | package io.grpc.examples.header; 33 | 34 | import io.grpc.Channel; 35 | import io.grpc.ClientInterceptor; 36 | import io.grpc.ClientInterceptors; 37 | import io.grpc.ManagedChannel; 38 | import io.grpc.ManagedChannelBuilder; 39 | import io.grpc.StatusRuntimeException; 40 | import io.grpc.examples.helloworld.GreeterGrpc; 41 | import io.grpc.examples.helloworld.HelloReply; 42 | import io.grpc.examples.helloworld.HelloRequest; 43 | import java.util.concurrent.TimeUnit; 44 | import java.util.logging.Level; 45 | import java.util.logging.Logger; 46 | 47 | /** 48 | * A simple client that like {@link io.grpc.examples.helloworld.HelloWorldClient}. 49 | * This client can help you create custom headers. 50 | */ 51 | public class CustomHeaderClient { 52 | private static final Logger logger = Logger.getLogger(CustomHeaderClient.class.getName()); 53 | 54 | private final ManagedChannel originChannel; 55 | private final GreeterGrpc.GreeterBlockingStub blockingStub; 56 | 57 | /** 58 | * A custom client. 59 | */ 60 | private CustomHeaderClient(String host, int port) { 61 | originChannel = ManagedChannelBuilder.forAddress(host, port) 62 | .usePlaintext(true) 63 | .build(); 64 | ClientInterceptor interceptor = new HeaderClientInterceptor(); 65 | Channel channel = ClientInterceptors.intercept(originChannel, interceptor); 66 | blockingStub = GreeterGrpc.newBlockingStub(channel); 67 | } 68 | 69 | private void shutdown() throws InterruptedException { 70 | originChannel.shutdown().awaitTermination(5, TimeUnit.SECONDS); 71 | } 72 | 73 | /** 74 | * A simple client method that like {@link io.grpc.examples.helloworld.HelloWorldClient}. 75 | */ 76 | private void greet(String name) { 77 | logger.info("Will try to greet " + name + " ..."); 78 | HelloRequest request = HelloRequest.newBuilder().setName(name).build(); 79 | HelloReply response; 80 | try { 81 | response = blockingStub.sayHello(request); 82 | } catch (StatusRuntimeException e) { 83 | logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); 84 | return; 85 | } 86 | logger.info("Greeting: " + response.getMessage()); 87 | } 88 | 89 | /** 90 | * Main start the client from the command line. 91 | */ 92 | public static void main(String[] args) throws Exception { 93 | CustomHeaderClient client = new CustomHeaderClient("localhost", 50051); 94 | try { 95 | /* Access a service running on the local machine on port 50051 */ 96 | String user = "world"; 97 | if (args.length > 0) { 98 | user = args[0]; /* Use the arg as the name to greet if provided */ 99 | } 100 | client.greet(user); 101 | } finally { 102 | client.shutdown(); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /examples/src/main/proto/route_guide.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015, Google Inc. 2 | // All rights reserved. 3 | // 4 | // Redistribution and use in source and binary forms, with or without 5 | // modification, are permitted provided that the following conditions are 6 | // met: 7 | // 8 | // * Redistributions of source code must retain the above copyright 9 | // notice, this list of conditions and the following disclaimer. 10 | // * Redistributions in binary form must reproduce the above 11 | // copyright notice, this list of conditions and the following disclaimer 12 | // in the documentation and/or other materials provided with the 13 | // distribution. 14 | // * Neither the name of Google Inc. nor the names of its 15 | // contributors may be used to endorse or promote products derived from 16 | // this software without specific prior written permission. 17 | // 18 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | 30 | syntax = "proto3"; 31 | 32 | option java_multiple_files = true; 33 | option java_package = "io.grpc.examples.routeguide"; 34 | option java_outer_classname = "RouteGuideProto"; 35 | option objc_class_prefix = "RTG"; 36 | 37 | package routeguide; 38 | 39 | // Interface exported by the server. 40 | service RouteGuide { 41 | // A simple RPC. 42 | // 43 | // Obtains the feature at a given position. 44 | // 45 | // A feature with an empty name is returned if there's no feature at the given 46 | // position. 47 | rpc GetFeature(Point) returns (Feature) {} 48 | 49 | // A server-to-client streaming RPC. 50 | // 51 | // Obtains the Features available within the given Rectangle. Results are 52 | // streamed rather than returned at once (e.g. in a response message with a 53 | // repeated field), as the rectangle may cover a large area and contain a 54 | // huge number of features. 55 | rpc ListFeatures(Rectangle) returns (stream Feature) {} 56 | 57 | // A client-to-server streaming RPC. 58 | // 59 | // Accepts a stream of Points on a route being traversed, returning a 60 | // RouteSummary when traversal is completed. 61 | rpc RecordRoute(stream Point) returns (RouteSummary) {} 62 | 63 | // A Bidirectional streaming RPC. 64 | // 65 | // Accepts a stream of RouteNotes sent while a route is being traversed, 66 | // while receiving other RouteNotes (e.g. from other users). 67 | rpc RouteChat(stream RouteNote) returns (stream RouteNote) {} 68 | } 69 | 70 | // Points are represented as latitude-longitude pairs in the E7 representation 71 | // (degrees multiplied by 10**7 and rounded to the nearest integer). 72 | // Latitudes should be in the range +/- 90 degrees and longitude should be in 73 | // the range +/- 180 degrees (inclusive). 74 | message Point { 75 | int32 latitude = 1; 76 | int32 longitude = 2; 77 | } 78 | 79 | // A latitude-longitude rectangle, represented as two diagonally opposite 80 | // points "lo" and "hi". 81 | message Rectangle { 82 | // One corner of the rectangle. 83 | Point lo = 1; 84 | 85 | // The other corner of the rectangle. 86 | Point hi = 2; 87 | } 88 | 89 | // A feature names something at a given point. 90 | // 91 | // If a feature could not be named, the name is empty. 92 | message Feature { 93 | // The name of the feature. 94 | string name = 1; 95 | 96 | // The point where the feature is detected. 97 | Point location = 2; 98 | } 99 | 100 | // Not used in the RPC. Instead, this is here for the form serialized to disk. 101 | message FeatureDatabase { 102 | repeated Feature feature = 1; 103 | } 104 | 105 | // A RouteNote is a message sent while at a given point. 106 | message RouteNote { 107 | // The location from which the message is sent. 108 | Point location = 1; 109 | 110 | // The message to be sent. 111 | string message = 2; 112 | } 113 | 114 | // A RouteSummary is received in response to a RecordRoute rpc. 115 | // 116 | // It contains the number of individual points received, the number of 117 | // detected features, and the total distance covered as the cumulative sum of 118 | // the distance between each point. 119 | message RouteSummary { 120 | // The number of points received. 121 | int32 point_count = 1; 122 | 123 | // The number of known features passed while traversing the route. 124 | int32 feature_count = 2; 125 | 126 | // The distance covered in metres. 127 | int32 distance = 3; 128 | 129 | // The duration of the traversal in seconds. 130 | int32 elapsed_time = 4; 131 | } 132 | -------------------------------------------------------------------------------- /examples/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn ( ) { 37 | echo "$*" 38 | } 39 | 40 | die ( ) { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save ( ) { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /examples/src/main/proto/error_details.proto: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, Google Inc. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.rpc; 18 | 19 | import "google/protobuf/duration.proto"; 20 | 21 | option java_multiple_files = true; 22 | option java_outer_classname = "ErrorDetailsProto"; 23 | option java_package = "com.google.rpc"; 24 | 25 | 26 | // Describes when the clients can retry a failed request. Clients could ignore 27 | // the recommendation here or retry when this information is missing from error 28 | // responses. 29 | // 30 | // It's always recommended that clients should use exponential backoff when 31 | // retrying. 32 | // 33 | // Clients should wait until `retry_delay` amount of time has passed since 34 | // receiving the error response before retrying. If retrying requests also 35 | // fail, clients should use an exponential backoff scheme to gradually increase 36 | // the delay between retries based on `retry_delay`, until either a maximum 37 | // number of retires have been reached or a maximum retry delay cap has been 38 | // reached. 39 | message RetryInfo { 40 | // Clients should wait at least this long between retrying the same request. 41 | google.protobuf.Duration retry_delay = 1; 42 | } 43 | 44 | // Describes additional debugging info. 45 | message DebugInfo { 46 | // The stack trace entries indicating where the error occurred. 47 | repeated string stack_entries = 1; 48 | 49 | // Additional debugging information provided by the server. 50 | string detail = 2; 51 | } 52 | 53 | // Describes how a quota check failed. 54 | // 55 | // For example if a daily limit was exceeded for the calling project, 56 | // a service could respond with a QuotaFailure detail containing the project 57 | // id and the description of the quota limit that was exceeded. If the 58 | // calling project hasn't enabled the service in the developer console, then 59 | // a service could respond with the project id and set `service_disabled` 60 | // to true. 61 | // 62 | // Also see RetryDetail and Help types for other details about handling a 63 | // quota failure. 64 | message QuotaFailure { 65 | // A message type used to describe a single quota violation. For example, a 66 | // daily quota or a custom quota that was exceeded. 67 | message Violation { 68 | // The subject on which the quota check failed. 69 | // For example, "clientip:" or "project:". 71 | string subject = 1; 72 | 73 | // A description of how the quota check failed. Clients can use this 74 | // description to find more about the quota configuration in the service's 75 | // public documentation, or find the relevant quota limit to adjust through 76 | // developer console. 77 | // 78 | // For example: "Service disabled" or "Daily Limit for read operations 79 | // exceeded". 80 | string description = 2; 81 | } 82 | 83 | // Describes all quota violations. 84 | repeated Violation violations = 1; 85 | } 86 | 87 | // Describes violations in a client request. This error type focuses on the 88 | // syntactic aspects of the request. 89 | message BadRequest { 90 | // A message type used to describe a single bad request field. 91 | message FieldViolation { 92 | // A path leading to a field in the request body. The value will be a 93 | // sequence of dot-separated identifiers that identify a protocol buffer 94 | // field. E.g., "violations.field" would identify this field. 95 | string field = 1; 96 | 97 | // A description of why the request element is bad. 98 | string description = 2; 99 | } 100 | 101 | // Describes all violations in a client request. 102 | repeated FieldViolation field_violations = 1; 103 | } 104 | 105 | // Contains metadata about the request that clients can attach when filing a bug 106 | // or providing other forms of feedback. 107 | message RequestInfo { 108 | // An opaque string that should only be interpreted by the service generating 109 | // it. For example, it can be used to identify requests in the service's logs. 110 | string request_id = 1; 111 | 112 | // Any data that was used to serve this request. For example, an encrypted 113 | // stack trace that can be sent back to the service provider for debugging. 114 | string serving_data = 2; 115 | } 116 | 117 | // Describes the resource that is being accessed. 118 | message ResourceInfo { 119 | // A name for the type of resource being accessed, e.g. "sql table", 120 | // "cloud storage bucket", "file", "Google calendar"; or the type URL 121 | // of the resource: e.g. "type.googleapis.com/google.pubsub.v1.Topic". 122 | string resource_type = 1; 123 | 124 | // The name of the resource being accessed. For example, a shared calendar 125 | // name: "example.com_4fghdhgsrgh@group.calendar.google.com", if the current 126 | // error is [google.rpc.Code.PERMISSION_DENIED][google.rpc.Code.PERMISSION_DENIED]. 127 | string resource_name = 2; 128 | 129 | // The owner of the resource (optional). 130 | // For example, "user:" or "project:". 132 | string owner = 3; 133 | 134 | // Describes what error is encountered when accessing this resource. 135 | // For example, updating a cloud project may require the `writer` permission 136 | // on the developer console project. 137 | string description = 4; 138 | } 139 | 140 | // Provides links to documentation or for performing an out of band action. 141 | // 142 | // For example, if a quota check failed with an error indicating the calling 143 | // project hasn't enabled the accessed service, this can contain a URL pointing 144 | // directly to the right place in the developer console to flip the bit. 145 | message Help { 146 | // Describes a URL link. 147 | message Link { 148 | // Describes what the link offers. 149 | string description = 1; 150 | 151 | // The URL of the link. 152 | string url = 2; 153 | } 154 | 155 | // URL(s) pointing to additional information on handling the current error. 156 | repeated Link links = 1; 157 | } -------------------------------------------------------------------------------- /examples/src/main/java/io/grpc/examples/helloworld/HelloWorldServer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, Google Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * * Neither the name of Google Inc. nor the names of its 16 | * contributors may be used to endorse or promote products derived from 17 | * this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | package io.grpc.examples.helloworld; 33 | 34 | import io.grpc.Server; 35 | import io.grpc.ServerBuilder; 36 | import io.grpc.stub.StreamObserver; 37 | import java.io.IOException; 38 | import java.io.IOException; 39 | import java.net.URI; 40 | import java.util.concurrent.CountDownLatch; 41 | import java.util.Date; 42 | import java.util.logging.Logger; 43 | import java.text.SimpleDateFormat; 44 | import org.apache.zookeeper.AsyncCallback.StatCallback; 45 | import org.apache.zookeeper.CreateMode; 46 | import org.apache.zookeeper.data.Stat; 47 | import org.apache.zookeeper.KeeperException; 48 | import org.apache.zookeeper.KeeperException.Code; 49 | import org.apache.zookeeper.WatchedEvent; 50 | import org.apache.zookeeper.Watcher; 51 | import org.apache.zookeeper.Watcher.Event.KeeperState; 52 | import org.apache.zookeeper.ZooDefs; 53 | import org.apache.zookeeper.ZooKeeper; 54 | 55 | class ZookeeperConnection { 56 | private static final Logger logger = Logger.getLogger("ZooKeeper"); 57 | private ZooKeeper zoo; 58 | public void ZookeeperConnection() { 59 | } 60 | 61 | /** 62 | * Connects to a zookeeper ensemble in zkUriStr. 63 | * serverIp and portStr are the IP/Port of this server. 64 | */ 65 | public boolean connect(String zkUriStr, String serverIp, String portStr) 66 | throws IOException,InterruptedException { 67 | final CountDownLatch connectedSignal = new CountDownLatch(1); 68 | String zkhostport; 69 | try { 70 | URI zkUri = new URI(zkUriStr); 71 | zkhostport = zkUri.getHost().toString() + ":" + Integer.toString(zkUri.getPort()); 72 | } catch (Exception e) { 73 | logger.severe("Could not parse zk URI " + zkUriStr); 74 | return false; 75 | } 76 | 77 | zoo = new ZooKeeper(zkhostport, 5000, new Watcher() { 78 | public void process(WatchedEvent we) { 79 | if (we.getState() == KeeperState.SyncConnected) { 80 | connectedSignal.countDown(); 81 | } 82 | } 83 | }); 84 | /* Wait for zookeeper connection */ 85 | connectedSignal.await(); 86 | 87 | String path = "/grpc_hello_world_service"; 88 | Stat stat; 89 | String currTime = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss").format(new Date()); 90 | try { 91 | stat = zoo.exists(path, true); 92 | if (stat == null) { 93 | zoo.create(path, currTime.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); 94 | } 95 | } catch (Exception e) { 96 | logger.severe("Failed to create path"); 97 | return false; 98 | } 99 | 100 | String server_addr = path + "/" + serverIp + ":" + portStr; 101 | try { 102 | stat = zoo.exists(server_addr, true); 103 | if (stat == null) { 104 | try { 105 | zoo.create(server_addr, currTime.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL); 106 | } catch (Exception e) { 107 | logger.severe("Failed to create server_data"); 108 | return false; 109 | } 110 | } else { 111 | try { 112 | zoo.setData(server_addr, currTime.getBytes(), stat.getVersion()); 113 | } catch (Exception e) { 114 | logger.severe("Failed to update server_data"); 115 | return false; 116 | } 117 | } 118 | } catch (Exception e) { 119 | logger.severe("Failed to add server_data"); 120 | return false; 121 | } 122 | return true; 123 | } 124 | 125 | // Method to disconnect from zookeeper server 126 | public void close() throws InterruptedException { 127 | zoo.close(); 128 | } 129 | } 130 | 131 | /** 132 | * Server that manages startup/shutdown of a {@code Greeter} server. 133 | */ 134 | public class HelloWorldServer { 135 | static String portStr; 136 | private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName()); 137 | 138 | private Server server; 139 | 140 | private void start(String port) throws IOException { 141 | /* The port on which the server should run */ 142 | server = ServerBuilder.forPort(Integer.parseInt(port)) 143 | .addService(new GreeterImpl()) 144 | .build() 145 | .start(); 146 | logger.info("Server started, listening on " + port); 147 | Runtime.getRuntime().addShutdownHook(new Thread() { 148 | @Override 149 | public void run() { 150 | // Use stderr here since the logger may have been reset by its JVM shutdown hook. 151 | System.err.println("*** shutting down gRPC server since JVM is shutting down"); 152 | HelloWorldServer.this.stop(); 153 | System.err.println("*** server shut down"); 154 | } 155 | }); 156 | } 157 | 158 | private void stop() { 159 | if (server != null) { 160 | server.shutdown(); 161 | } 162 | } 163 | 164 | /** 165 | * Await termination on the main thread since the grpc library uses daemon threads. 166 | */ 167 | private void blockUntilShutdown() throws InterruptedException { 168 | if (server != null) { 169 | server.awaitTermination(); 170 | } 171 | } 172 | 173 | 174 | /** 175 | * Main launches the server from the command line. 176 | */ 177 | public static void main(String[] args) throws IOException, InterruptedException { 178 | /* Argument parsing */ 179 | if (args.length != 2) { 180 | System.out.println("Usage: helloworld_server PORT zk://ADDR:PORT"); 181 | return; 182 | } 183 | 184 | String zk_addr; 185 | 186 | try { 187 | portStr = new String(args[0]); 188 | zk_addr = new String(args[1]); 189 | } catch (Exception e) { 190 | System.out.println("Usage: helloworld_server PORT zk://ADDR:PORT"); 191 | return; 192 | } 193 | 194 | ZookeeperConnection zk_conn = new ZookeeperConnection(); 195 | if (!zk_conn.connect(zk_addr, "localhost", portStr)) { 196 | return; 197 | } 198 | 199 | final HelloWorldServer server = new HelloWorldServer(); 200 | server.start(portStr); 201 | server.blockUntilShutdown(); 202 | } 203 | 204 | static class GreeterImpl extends GreeterGrpc.GreeterImplBase { 205 | 206 | @Override 207 | public void sayHello(HelloRequest req, 208 | StreamObserverresponseObserver) { 209 | HelloReply reply = HelloReply.newBuilder().setMessage( 210 | "Hello " + req.getName() + " from " + portStr).build(); 211 | responseObserver.onNext(reply); 212 | responseObserver.onCompleted(); 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /examples/src/main/java/io/grpc/examples/helloworld/HelloWorldClient.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015, Google Inc. All rights reserved. 3 | * 4 | * Redistribution and use in source and binary forms, with or without 5 | * modification, are permitted provided that the following conditions are 6 | * met: 7 | * 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above 11 | * copyright notice, this list of conditions and the following disclaimer 12 | * in the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * * Neither the name of Google Inc. nor the names of its 16 | * contributors may be used to endorse or promote products derived from 17 | * this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | */ 31 | 32 | package io.grpc.examples.helloworld; 33 | 34 | import io.grpc.Attributes; 35 | import io.grpc.EquivalentAddressGroup; 36 | import io.grpc.ManagedChannel; 37 | import io.grpc.ManagedChannelBuilder; 38 | import io.grpc.NameResolver; 39 | import io.grpc.NameResolverProvider; 40 | import io.grpc.StatusRuntimeException; 41 | import io.grpc.util.RoundRobinLoadBalancerFactory; 42 | import java.net.InetSocketAddress; 43 | import java.net.SocketAddress; 44 | import java.net.URI; 45 | import java.util.concurrent.CountDownLatch; 46 | import java.util.concurrent.TimeUnit; 47 | import java.util.logging.Level; 48 | import java.util.logging.Logger; 49 | import java.util.Comparator; 50 | import java.util.List; 51 | import java.util.ArrayList; 52 | import javax.annotation.Nullable; 53 | import org.apache.zookeeper.AsyncCallback.StatCallback; 54 | import org.apache.zookeeper.CreateMode; 55 | import org.apache.zookeeper.data.Stat; 56 | import org.apache.zookeeper.KeeperException; 57 | import org.apache.zookeeper.KeeperException.Code; 58 | import org.apache.zookeeper.Watcher; 59 | import org.apache.zookeeper.Watcher.Event.KeeperState; 60 | import org.apache.zookeeper.WatchedEvent; 61 | import org.apache.zookeeper.ZooDefs; 62 | import org.apache.zookeeper.ZooKeeper; 63 | 64 | 65 | class ZkNameResolver extends NameResolver implements Watcher { 66 | /** Hard-coded path to the ZkNode that knows about servers. 67 | * Note this must match with the path used by HelloWorldServer */ 68 | public static final String PATH = "/grpc_hello_world_service"; 69 | /** 2 seconds to indicate that client disconnected */ 70 | public static final int TIMEOUT_MS = 2000; 71 | 72 | private URI zkUri; 73 | private ZooKeeper zoo; 74 | private Listener listener; 75 | private final Logger logger = Logger.getLogger("ZK"); 76 | 77 | /** 78 | * The callback from Zookeeper when servers are added/removed. 79 | */ 80 | @Override 81 | public void process(WatchedEvent we) { 82 | if (we.getType() == Event.EventType.None) { 83 | logger.info("Connection expired"); 84 | } else { 85 | try { 86 | List servers = zoo.getChildren(PATH, false); 87 | AddServersToListener(servers); 88 | zoo.getChildren(PATH, this); 89 | } catch(Exception ex) { 90 | logger.info(ex.getMessage()); 91 | } 92 | } 93 | } 94 | 95 | private void AddServersToListener(List servers) { 96 | List addrs = new ArrayList(); 97 | logger.info("Updating server list"); 98 | for (String child : servers) { 99 | try { 100 | logger.info("Online: " + child); 101 | URI uri = new URI("dummy://" + child); 102 | // Convert "host:port" into host and port 103 | String host = uri.getHost(); 104 | int port = uri.getPort(); 105 | List sockaddrs_list= new ArrayList(); 106 | sockaddrs_list.add(new InetSocketAddress(host, port)); 107 | addrs.add(new EquivalentAddressGroup(sockaddrs_list)); 108 | } catch(Exception ex) { 109 | logger.info("Unparsable server address: " + child); 110 | logger.info(ex.getMessage()); 111 | } 112 | } 113 | if (addrs.size() > 0) { 114 | listener.onAddresses(addrs, Attributes.EMPTY); 115 | } else { 116 | logger.info("No servers online. Keep looking"); 117 | } 118 | } 119 | 120 | 121 | public ZkNameResolver (URI zkUri) { 122 | this.zkUri = zkUri; 123 | } 124 | 125 | @Override 126 | public String getServiceAuthority() { 127 | return zkUri.getAuthority(); 128 | } 129 | 130 | @Override 131 | public void start(Listener listener) { 132 | this.listener = listener; 133 | final CountDownLatch connectedSignal = new CountDownLatch(1); 134 | try { 135 | String zkaddr = zkUri.getHost().toString() + ":" + Integer.toString(zkUri.getPort()); 136 | logger.info("Connecting to Zookeeper Address " + zkaddr); 137 | 138 | this.zoo = new ZooKeeper(zkaddr, TIMEOUT_MS, new Watcher() { 139 | public void process(WatchedEvent we) { 140 | if (we.getState() == KeeperState.SyncConnected) { 141 | connectedSignal.countDown(); 142 | } 143 | } 144 | }); 145 | connectedSignal.await(); 146 | logger.info("Connected!"); 147 | } catch (Exception e) { 148 | logger.info("Failed to connect"); 149 | return; 150 | } 151 | 152 | 153 | try { 154 | Stat stat = zoo.exists(PATH, true); 155 | if (stat == null) { 156 | logger.info("PATH does not exist."); 157 | } else { 158 | logger.info("PATH exists"); 159 | } 160 | } catch (Exception e) { 161 | logger.info("Failed to get stat"); 162 | return; 163 | } 164 | 165 | try { 166 | final CountDownLatch connectedSignal1 = new CountDownLatch(1); 167 | List servers = zoo.getChildren(PATH, this); 168 | AddServersToListener(servers); 169 | } catch(Exception e) { 170 | logger.info(e.getMessage()); 171 | } 172 | } 173 | 174 | @Override 175 | public void shutdown() { 176 | } 177 | } 178 | 179 | class ZkNameResolverProvider extends NameResolverProvider { 180 | @Nullable 181 | @Override 182 | public NameResolver newNameResolver(URI targetUri, Attributes params) { 183 | return new ZkNameResolver(targetUri); 184 | } 185 | 186 | @Override 187 | protected int priority() { 188 | return 5; 189 | } 190 | 191 | @Override 192 | protected boolean isAvailable() { 193 | return true; 194 | } 195 | 196 | @Override 197 | public String getDefaultScheme() { 198 | return "zk"; 199 | } 200 | } 201 | 202 | /** 203 | * A simple client that requests a greeting from the {@link HelloWorldServer}, 204 | * and round robin load-balances among all available servers. 205 | */ 206 | public class HelloWorldClient { 207 | private static final Logger logger = Logger.getLogger("Client"); 208 | 209 | private final ManagedChannel channel; 210 | private final GreeterGrpc.GreeterBlockingStub blockingStub; 211 | 212 | /** 213 | * Construct client connecting to HelloWorld server using Zookeeper name resolver 214 | * and Round Robin load balancer. 215 | */ 216 | public HelloWorldClient(String zkAddr) { 217 | this(ManagedChannelBuilder.forTarget(zkAddr) 218 | .loadBalancerFactory(RoundRobinLoadBalancerFactory.getInstance()) 219 | .nameResolverFactory(new ZkNameResolverProvider()) 220 | .usePlaintext(true)); 221 | } 222 | 223 | /** Construct client for accessing the server using the existing channel. */ 224 | HelloWorldClient(ManagedChannelBuilder channelBuilder) { 225 | channel = channelBuilder.build(); 226 | blockingStub = GreeterGrpc.newBlockingStub(channel); 227 | } 228 | 229 | public void shutdown() throws InterruptedException { 230 | channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); 231 | } 232 | 233 | /** Say hello to server. */ 234 | public void greet() { 235 | HelloRequest request = HelloRequest.newBuilder().setName("world").build(); 236 | HelloReply response; 237 | try { 238 | response = blockingStub.sayHello(request); 239 | } catch (StatusRuntimeException e) { 240 | logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); 241 | return; 242 | } 243 | logger.info("Greeting: " + response.getMessage()); 244 | } 245 | 246 | /** 247 | * Greeter client. First argument of {@code args} is the address of the 248 | * Zookeeper ensemble. The client keeps making simple RPCs until interrupted 249 | * with a Ctrl-C. 250 | */ 251 | public static void main(String[] args) throws Exception { 252 | if (args.length != 1) { 253 | System.out.println("Usage: helloworld_client zk://ADDR:PORT"); 254 | return; 255 | } 256 | HelloWorldClient client = new HelloWorldClient(args[0]); 257 | try { 258 | while(true) { 259 | client.greet(); 260 | Thread.sleep(1000); 261 | } 262 | } finally { 263 | client.shutdown(); 264 | } 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /examples/src/main/resources/io/grpc/examples/routeguide/route_guide_db.json: -------------------------------------------------------------------------------- 1 | { 2 | "feature": [{ 3 | "location": { 4 | "latitude": 407838351, 5 | "longitude": -746143763 6 | }, 7 | "name": "Patriots Path, Mendham, NJ 07945, USA" 8 | }, { 9 | "location": { 10 | "latitude": 408122808, 11 | "longitude": -743999179 12 | }, 13 | "name": "101 New Jersey 10, Whippany, NJ 07981, USA" 14 | }, { 15 | "location": { 16 | "latitude": 413628156, 17 | "longitude": -749015468 18 | }, 19 | "name": "U.S. 6, Shohola, PA 18458, USA" 20 | }, { 21 | "location": { 22 | "latitude": 419999544, 23 | "longitude": -740371136 24 | }, 25 | "name": "5 Conners Road, Kingston, NY 12401, USA" 26 | }, { 27 | "location": { 28 | "latitude": 414008389, 29 | "longitude": -743951297 30 | }, 31 | "name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA" 32 | }, { 33 | "location": { 34 | "latitude": 419611318, 35 | "longitude": -746524769 36 | }, 37 | "name": "287 Flugertown Road, Livingston Manor, NY 12758, USA" 38 | }, { 39 | "location": { 40 | "latitude": 406109563, 41 | "longitude": -742186778 42 | }, 43 | "name": "4001 Tremley Point Road, Linden, NJ 07036, USA" 44 | }, { 45 | "location": { 46 | "latitude": 416802456, 47 | "longitude": -742370183 48 | }, 49 | "name": "352 South Mountain Road, Wallkill, NY 12589, USA" 50 | }, { 51 | "location": { 52 | "latitude": 412950425, 53 | "longitude": -741077389 54 | }, 55 | "name": "Bailey Turn Road, Harriman, NY 10926, USA" 56 | }, { 57 | "location": { 58 | "latitude": 412144655, 59 | "longitude": -743949739 60 | }, 61 | "name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA" 62 | }, { 63 | "location": { 64 | "latitude": 415736605, 65 | "longitude": -742847522 66 | }, 67 | "name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA" 68 | }, { 69 | "location": { 70 | "latitude": 413843930, 71 | "longitude": -740501726 72 | }, 73 | "name": "162 Merrill Road, Highland Mills, NY 10930, USA" 74 | }, { 75 | "location": { 76 | "latitude": 410873075, 77 | "longitude": -744459023 78 | }, 79 | "name": "Clinton Road, West Milford, NJ 07480, USA" 80 | }, { 81 | "location": { 82 | "latitude": 412346009, 83 | "longitude": -744026814 84 | }, 85 | "name": "16 Old Brook Lane, Warwick, NY 10990, USA" 86 | }, { 87 | "location": { 88 | "latitude": 402948455, 89 | "longitude": -747903913 90 | }, 91 | "name": "3 Drake Lane, Pennington, NJ 08534, USA" 92 | }, { 93 | "location": { 94 | "latitude": 406337092, 95 | "longitude": -740122226 96 | }, 97 | "name": "6324 8th Avenue, Brooklyn, NY 11220, USA" 98 | }, { 99 | "location": { 100 | "latitude": 406421967, 101 | "longitude": -747727624 102 | }, 103 | "name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA" 104 | }, { 105 | "location": { 106 | "latitude": 416318082, 107 | "longitude": -749677716 108 | }, 109 | "name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA" 110 | }, { 111 | "location": { 112 | "latitude": 415301720, 113 | "longitude": -748416257 114 | }, 115 | "name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA" 116 | }, { 117 | "location": { 118 | "latitude": 402647019, 119 | "longitude": -747071791 120 | }, 121 | "name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA" 122 | }, { 123 | "location": { 124 | "latitude": 412567807, 125 | "longitude": -741058078 126 | }, 127 | "name": "New York State Reference Route 987E, Southfields, NY 10975, USA" 128 | }, { 129 | "location": { 130 | "latitude": 416855156, 131 | "longitude": -744420597 132 | }, 133 | "name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA" 134 | }, { 135 | "location": { 136 | "latitude": 404663628, 137 | "longitude": -744820157 138 | }, 139 | "name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA" 140 | }, { 141 | "location": { 142 | "latitude": 407113723, 143 | "longitude": -749746483 144 | }, 145 | "name": "" 146 | }, { 147 | "location": { 148 | "latitude": 402133926, 149 | "longitude": -743613249 150 | }, 151 | "name": "" 152 | }, { 153 | "location": { 154 | "latitude": 400273442, 155 | "longitude": -741220915 156 | }, 157 | "name": "" 158 | }, { 159 | "location": { 160 | "latitude": 411236786, 161 | "longitude": -744070769 162 | }, 163 | "name": "" 164 | }, { 165 | "location": { 166 | "latitude": 411633782, 167 | "longitude": -746784970 168 | }, 169 | "name": "211-225 Plains Road, Augusta, NJ 07822, USA" 170 | }, { 171 | "location": { 172 | "latitude": 415830701, 173 | "longitude": -742952812 174 | }, 175 | "name": "" 176 | }, { 177 | "location": { 178 | "latitude": 413447164, 179 | "longitude": -748712898 180 | }, 181 | "name": "165 Pedersen Ridge Road, Milford, PA 18337, USA" 182 | }, { 183 | "location": { 184 | "latitude": 405047245, 185 | "longitude": -749800722 186 | }, 187 | "name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA" 188 | }, { 189 | "location": { 190 | "latitude": 418858923, 191 | "longitude": -746156790 192 | }, 193 | "name": "" 194 | }, { 195 | "location": { 196 | "latitude": 417951888, 197 | "longitude": -748484944 198 | }, 199 | "name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA" 200 | }, { 201 | "location": { 202 | "latitude": 407033786, 203 | "longitude": -743977337 204 | }, 205 | "name": "26 East 3rd Street, New Providence, NJ 07974, USA" 206 | }, { 207 | "location": { 208 | "latitude": 417548014, 209 | "longitude": -740075041 210 | }, 211 | "name": "" 212 | }, { 213 | "location": { 214 | "latitude": 410395868, 215 | "longitude": -744972325 216 | }, 217 | "name": "" 218 | }, { 219 | "location": { 220 | "latitude": 404615353, 221 | "longitude": -745129803 222 | }, 223 | "name": "" 224 | }, { 225 | "location": { 226 | "latitude": 406589790, 227 | "longitude": -743560121 228 | }, 229 | "name": "611 Lawrence Avenue, Westfield, NJ 07090, USA" 230 | }, { 231 | "location": { 232 | "latitude": 414653148, 233 | "longitude": -740477477 234 | }, 235 | "name": "18 Lannis Avenue, New Windsor, NY 12553, USA" 236 | }, { 237 | "location": { 238 | "latitude": 405957808, 239 | "longitude": -743255336 240 | }, 241 | "name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA" 242 | }, { 243 | "location": { 244 | "latitude": 411733589, 245 | "longitude": -741648093 246 | }, 247 | "name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA" 248 | }, { 249 | "location": { 250 | "latitude": 412676291, 251 | "longitude": -742606606 252 | }, 253 | "name": "1270 Lakes Road, Monroe, NY 10950, USA" 254 | }, { 255 | "location": { 256 | "latitude": 409224445, 257 | "longitude": -748286738 258 | }, 259 | "name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA" 260 | }, { 261 | "location": { 262 | "latitude": 406523420, 263 | "longitude": -742135517 264 | }, 265 | "name": "652 Garden Street, Elizabeth, NJ 07202, USA" 266 | }, { 267 | "location": { 268 | "latitude": 401827388, 269 | "longitude": -740294537 270 | }, 271 | "name": "349 Sea Spray Court, Neptune City, NJ 07753, USA" 272 | }, { 273 | "location": { 274 | "latitude": 410564152, 275 | "longitude": -743685054 276 | }, 277 | "name": "13-17 Stanley Street, West Milford, NJ 07480, USA" 278 | }, { 279 | "location": { 280 | "latitude": 408472324, 281 | "longitude": -740726046 282 | }, 283 | "name": "47 Industrial Avenue, Teterboro, NJ 07608, USA" 284 | }, { 285 | "location": { 286 | "latitude": 412452168, 287 | "longitude": -740214052 288 | }, 289 | "name": "5 White Oak Lane, Stony Point, NY 10980, USA" 290 | }, { 291 | "location": { 292 | "latitude": 409146138, 293 | "longitude": -746188906 294 | }, 295 | "name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA" 296 | }, { 297 | "location": { 298 | "latitude": 404701380, 299 | "longitude": -744781745 300 | }, 301 | "name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA" 302 | }, { 303 | "location": { 304 | "latitude": 409642566, 305 | "longitude": -746017679 306 | }, 307 | "name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA" 308 | }, { 309 | "location": { 310 | "latitude": 408031728, 311 | "longitude": -748645385 312 | }, 313 | "name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA" 314 | }, { 315 | "location": { 316 | "latitude": 413700272, 317 | "longitude": -742135189 318 | }, 319 | "name": "367 Prospect Road, Chester, NY 10918, USA" 320 | }, { 321 | "location": { 322 | "latitude": 404310607, 323 | "longitude": -740282632 324 | }, 325 | "name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA" 326 | }, { 327 | "location": { 328 | "latitude": 409319800, 329 | "longitude": -746201391 330 | }, 331 | "name": "11 Ward Street, Mount Arlington, NJ 07856, USA" 332 | }, { 333 | "location": { 334 | "latitude": 406685311, 335 | "longitude": -742108603 336 | }, 337 | "name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA" 338 | }, { 339 | "location": { 340 | "latitude": 419018117, 341 | "longitude": -749142781 342 | }, 343 | "name": "43 Dreher Road, Roscoe, NY 12776, USA" 344 | }, { 345 | "location": { 346 | "latitude": 412856162, 347 | "longitude": -745148837 348 | }, 349 | "name": "Swan Street, Pine Island, NY 10969, USA" 350 | }, { 351 | "location": { 352 | "latitude": 416560744, 353 | "longitude": -746721964 354 | }, 355 | "name": "66 Pleasantview Avenue, Monticello, NY 12701, USA" 356 | }, { 357 | "location": { 358 | "latitude": 405314270, 359 | "longitude": -749836354 360 | }, 361 | "name": "" 362 | }, { 363 | "location": { 364 | "latitude": 414219548, 365 | "longitude": -743327440 366 | }, 367 | "name": "" 368 | }, { 369 | "location": { 370 | "latitude": 415534177, 371 | "longitude": -742900616 372 | }, 373 | "name": "565 Winding Hills Road, Montgomery, NY 12549, USA" 374 | }, { 375 | "location": { 376 | "latitude": 406898530, 377 | "longitude": -749127080 378 | }, 379 | "name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA" 380 | }, { 381 | "location": { 382 | "latitude": 407586880, 383 | "longitude": -741670168 384 | }, 385 | "name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA" 386 | }, { 387 | "location": { 388 | "latitude": 400106455, 389 | "longitude": -742870190 390 | }, 391 | "name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA" 392 | }, { 393 | "location": { 394 | "latitude": 400066188, 395 | "longitude": -746793294 396 | }, 397 | "name": "" 398 | }, { 399 | "location": { 400 | "latitude": 418803880, 401 | "longitude": -744102673 402 | }, 403 | "name": "40 Mountain Road, Napanoch, NY 12458, USA" 404 | }, { 405 | "location": { 406 | "latitude": 414204288, 407 | "longitude": -747895140 408 | }, 409 | "name": "" 410 | }, { 411 | "location": { 412 | "latitude": 414777405, 413 | "longitude": -740615601 414 | }, 415 | "name": "" 416 | }, { 417 | "location": { 418 | "latitude": 415464475, 419 | "longitude": -747175374 420 | }, 421 | "name": "48 North Road, Forestburgh, NY 12777, USA" 422 | }, { 423 | "location": { 424 | "latitude": 404062378, 425 | "longitude": -746376177 426 | }, 427 | "name": "" 428 | }, { 429 | "location": { 430 | "latitude": 405688272, 431 | "longitude": -749285130 432 | }, 433 | "name": "" 434 | }, { 435 | "location": { 436 | "latitude": 400342070, 437 | "longitude": -748788996 438 | }, 439 | "name": "" 440 | }, { 441 | "location": { 442 | "latitude": 401809022, 443 | "longitude": -744157964 444 | }, 445 | "name": "" 446 | }, { 447 | "location": { 448 | "latitude": 404226644, 449 | "longitude": -740517141 450 | }, 451 | "name": "9 Thompson Avenue, Leonardo, NJ 07737, USA" 452 | }, { 453 | "location": { 454 | "latitude": 410322033, 455 | "longitude": -747871659 456 | }, 457 | "name": "" 458 | }, { 459 | "location": { 460 | "latitude": 407100674, 461 | "longitude": -747742727 462 | }, 463 | "name": "" 464 | }, { 465 | "location": { 466 | "latitude": 418811433, 467 | "longitude": -741718005 468 | }, 469 | "name": "213 Bush Road, Stone Ridge, NY 12484, USA" 470 | }, { 471 | "location": { 472 | "latitude": 415034302, 473 | "longitude": -743850945 474 | }, 475 | "name": "" 476 | }, { 477 | "location": { 478 | "latitude": 411349992, 479 | "longitude": -743694161 480 | }, 481 | "name": "" 482 | }, { 483 | "location": { 484 | "latitude": 404839914, 485 | "longitude": -744759616 486 | }, 487 | "name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA" 488 | }, { 489 | "location": { 490 | "latitude": 414638017, 491 | "longitude": -745957854 492 | }, 493 | "name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA" 494 | }, { 495 | "location": { 496 | "latitude": 412127800, 497 | "longitude": -740173578 498 | }, 499 | "name": "" 500 | }, { 501 | "location": { 502 | "latitude": 401263460, 503 | "longitude": -747964303 504 | }, 505 | "name": "" 506 | }, { 507 | "location": { 508 | "latitude": 412843391, 509 | "longitude": -749086026 510 | }, 511 | "name": "" 512 | }, { 513 | "location": { 514 | "latitude": 418512773, 515 | "longitude": -743067823 516 | }, 517 | "name": "" 518 | }, { 519 | "location": { 520 | "latitude": 404318328, 521 | "longitude": -740835638 522 | }, 523 | "name": "42-102 Main Street, Belford, NJ 07718, USA" 524 | }, { 525 | "location": { 526 | "latitude": 419020746, 527 | "longitude": -741172328 528 | }, 529 | "name": "" 530 | }, { 531 | "location": { 532 | "latitude": 404080723, 533 | "longitude": -746119569 534 | }, 535 | "name": "" 536 | }, { 537 | "location": { 538 | "latitude": 401012643, 539 | "longitude": -744035134 540 | }, 541 | "name": "" 542 | }, { 543 | "location": { 544 | "latitude": 404306372, 545 | "longitude": -741079661 546 | }, 547 | "name": "" 548 | }, { 549 | "location": { 550 | "latitude": 403966326, 551 | "longitude": -748519297 552 | }, 553 | "name": "" 554 | }, { 555 | "location": { 556 | "latitude": 405002031, 557 | "longitude": -748407866 558 | }, 559 | "name": "" 560 | }, { 561 | "location": { 562 | "latitude": 409532885, 563 | "longitude": -742200683 564 | }, 565 | "name": "" 566 | }, { 567 | "location": { 568 | "latitude": 416851321, 569 | "longitude": -742674555 570 | }, 571 | "name": "" 572 | }, { 573 | "location": { 574 | "latitude": 406411633, 575 | "longitude": -741722051 576 | }, 577 | "name": "3387 Richmond Terrace, Staten Island, NY 10303, USA" 578 | }, { 579 | "location": { 580 | "latitude": 413069058, 581 | "longitude": -744597778 582 | }, 583 | "name": "261 Van Sickle Road, Goshen, NY 10924, USA" 584 | }, { 585 | "location": { 586 | "latitude": 418465462, 587 | "longitude": -746859398 588 | }, 589 | "name": "" 590 | }, { 591 | "location": { 592 | "latitude": 411733222, 593 | "longitude": -744228360 594 | }, 595 | "name": "" 596 | }, { 597 | "location": { 598 | "latitude": 410248224, 599 | "longitude": -747127767 600 | }, 601 | "name": "3 Hasta Way, Newton, NJ 07860, USA" 602 | }] 603 | } 604 | --------------------------------------------------------------------------------