mirror of https://github.com/grpc/grpc-java.git
Adding RouteGuide example and deleting others.
This commit is contained in:
parent
494d273b05
commit
b897a89e78
15
build.gradle
15
build.gradle
|
|
@ -20,16 +20,17 @@ subprojects {
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
libraries = [
|
libraries = [
|
||||||
protobuf: 'com.google.protobuf:protobuf-java:3.0.0-pre',
|
|
||||||
guava: 'com.google.guava:guava:18.0',
|
guava: 'com.google.guava:guava:18.0',
|
||||||
jsr305: 'com.google.code.findbugs:jsr305:3.0.0',
|
|
||||||
oauth_client: 'com.google.oauth-client:google-oauth-client:1.18.0-rc',
|
|
||||||
javaee_api: 'javax:javaee-api:7.0',
|
|
||||||
hpack: 'com.twitter:hpack:0.9.1',
|
|
||||||
protobuf_plugin: 'ws.antonov.gradle.plugins:gradle-plugin-protobuf:0.9.1',
|
|
||||||
okhttp: 'com.squareup.okhttp:okhttp:2.2.0',
|
|
||||||
// used to collect benchmark results
|
// used to collect benchmark results
|
||||||
hdrhistogram: 'org.hdrhistogram:HdrHistogram:2.1.4',
|
hdrhistogram: 'org.hdrhistogram:HdrHistogram:2.1.4',
|
||||||
|
hpack: 'com.twitter:hpack:0.9.1',
|
||||||
|
javaee_api: 'javax:javaee-api:7.0',
|
||||||
|
jsonp: 'org.glassfish:javax.json:1.0.4',
|
||||||
|
jsr305: 'com.google.code.findbugs:jsr305:3.0.0',
|
||||||
|
oauth_client: 'com.google.oauth-client:google-oauth-client:1.18.0-rc',
|
||||||
|
okhttp: 'com.squareup.okhttp:okhttp:2.2.0',
|
||||||
|
protobuf: 'com.google.protobuf:protobuf-java:3.0.0-pre',
|
||||||
|
protobuf_plugin: 'ws.antonov.gradle.plugins:gradle-plugin-protobuf:0.9.1',
|
||||||
|
|
||||||
// TODO: Unreleased dependencies.
|
// TODO: Unreleased dependencies.
|
||||||
// These must already be installed in the local maven repository.
|
// These must already be installed in the local maven repository.
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,19 @@
|
||||||
grpc Examples
|
grpc Examples
|
||||||
==============================================
|
==============================================
|
||||||
|
|
||||||
In order to run the examples simply execute one of the gradle tasks `mathserver`, `mathclient`,
|
In order to run the examples simply execute one of the gradle tasks `routeGuideServer` or
|
||||||
`stockserver` or `stockclient`.
|
`routeGuideClient`.
|
||||||
|
|
||||||
For example, say you want to play around with the math examples. First you want to start
|
Assuming you are in the grpc-java root folder you would first start the server by running
|
||||||
the server and then have the client connect to it and do some fun calculations.
|
|
||||||
|
|
||||||
Assuming you are in the grpc-java root folder you would first start the math server by running
|
|
||||||
|
|
||||||
```
|
```
|
||||||
$ ./gradlew :grpc-examples:mathserver
|
$ ./gradlew :grpc-examples:routeGuideServer
|
||||||
```
|
```
|
||||||
|
|
||||||
and in a different terminal window then run the client by typing
|
and in a different terminal window then run the client by typing
|
||||||
|
|
||||||
```
|
```
|
||||||
$ ./gradlew :grpc-examples:mathclient
|
$ ./gradlew :grpc-examples:routeGuideClient
|
||||||
```
|
```
|
||||||
|
|
||||||
That's it!
|
That's it!
|
||||||
|
|
|
||||||
|
|
@ -16,32 +16,21 @@ dependencies {
|
||||||
compile project(':grpc-core'),
|
compile project(':grpc-core'),
|
||||||
project(':grpc-netty'),
|
project(':grpc-netty'),
|
||||||
project(':grpc-okhttp'),
|
project(':grpc-okhttp'),
|
||||||
project(':grpc-stub')
|
project(':grpc-stub'),
|
||||||
|
libraries.jsonp
|
||||||
}
|
}
|
||||||
|
|
||||||
protobufCodeGenPlugins = ["java_plugin:$rootDir/compiler/build/binaries/java_pluginExecutable/java_plugin"]
|
protobufCodeGenPlugins = ["java_plugin:$rootDir/compiler/build/binaries/java_pluginExecutable/java_plugin"]
|
||||||
generateProto.dependsOn ':grpc-compiler:java_pluginExecutable'
|
generateProto.dependsOn ':grpc-compiler:java_pluginExecutable'
|
||||||
|
|
||||||
task mathserver(type: JavaExec) {
|
task routeGuideServer(type: JavaExec) {
|
||||||
main = "io.grpc.examples.MathServer"
|
main = "io.grpc.examples.RouteGuideServer"
|
||||||
description = "Executes the math server."
|
description = "Executes the route guide server."
|
||||||
classpath = sourceSets.main.runtimeClasspath
|
classpath = sourceSets.main.runtimeClasspath
|
||||||
}
|
}
|
||||||
|
|
||||||
task mathclient(type: JavaExec) {
|
task routeGuideClient(type: JavaExec) {
|
||||||
main = "io.grpc.examples.MathClient"
|
main = "io.grpc.examples.RouteGuideClient"
|
||||||
description = "Executes the math client."
|
description = "Executes the route guide client."
|
||||||
classpath = sourceSets.main.runtimeClasspath
|
|
||||||
}
|
|
||||||
|
|
||||||
task stockserver(type: JavaExec) {
|
|
||||||
main = "io.grpc.examples.StockServer"
|
|
||||||
description = "Executes the stock server."
|
|
||||||
classpath = sourceSets.main.runtimeClasspath
|
|
||||||
}
|
|
||||||
|
|
||||||
task stockclient(type: JavaExec) {
|
|
||||||
main = "io.grpc.examples.StockClient"
|
|
||||||
description = "Executes the stock client."
|
|
||||||
classpath = sourceSets.main.runtimeClasspath
|
classpath = sourceSets.main.runtimeClasspath
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,251 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2014, 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;
|
|
||||||
|
|
||||||
import com.google.common.util.concurrent.SettableFuture;
|
|
||||||
import io.grpc.examples.CalcGrpc;
|
|
||||||
import io.grpc.examples.CalcGrpc.CalcBlockingStub;
|
|
||||||
import io.grpc.examples.CalcGrpc.CalcStub;
|
|
||||||
import io.grpc.examples.Math.DivArgs;
|
|
||||||
import io.grpc.examples.Math.DivReply;
|
|
||||||
import io.grpc.examples.Math.FibArgs;
|
|
||||||
import io.grpc.examples.Math.Num;
|
|
||||||
|
|
||||||
import io.grpc.ChannelImpl;
|
|
||||||
import io.grpc.stub.StreamObserver;
|
|
||||||
import io.grpc.transport.netty.NegotiationType;
|
|
||||||
import io.grpc.transport.netty.NettyChannelBuilder;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.ExecutionException;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sample client code that makes gRPC calls to the server.
|
|
||||||
*/
|
|
||||||
public class MathClient {
|
|
||||||
private final Logger logger = Logger.getLogger(MathClient.class.getName());
|
|
||||||
private final Random rand = new Random();
|
|
||||||
private final ChannelImpl channel;
|
|
||||||
private final CalcBlockingStub blockingStub;
|
|
||||||
private final CalcStub asyncStub;
|
|
||||||
|
|
||||||
public MathClient(String host, int port) {
|
|
||||||
channel = NettyChannelBuilder.forAddress(host, port)
|
|
||||||
.negotiationType(NegotiationType.PLAINTEXT)
|
|
||||||
.build();
|
|
||||||
blockingStub = CalcGrpc.newBlockingStub(channel);
|
|
||||||
asyncStub = CalcGrpc.newStub(channel);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void shutdown() throws InterruptedException {
|
|
||||||
channel.shutdown().awaitTerminated(5, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This example shows how to make a blocking unary call.
|
|
||||||
*/
|
|
||||||
public void blockingDiv(long dividend, long divisor) {
|
|
||||||
logger.info("*** Blocking Div: Dividend=" + dividend + ", Divisor=" + divisor);
|
|
||||||
DivReply reply;
|
|
||||||
try {
|
|
||||||
reply = blockingStub.div(
|
|
||||||
DivArgs.newBuilder().setDividend(dividend).setDivisor(divisor).build());
|
|
||||||
} catch (RuntimeException e) {
|
|
||||||
logger.log(Level.WARNING, "RPC failed", e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
logger.info("Result: Quotient=" + reply.getQuotient() + ", remainder=" + reply.getRemainder());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This example shows how to make an asynchronous unary call.
|
|
||||||
*/
|
|
||||||
public void asyncDiv(long dividend, long divisor) {
|
|
||||||
logger.info("*** Async Div: Dividend=" + dividend + ", Divisor=" + divisor);
|
|
||||||
DivArgs request = DivArgs.newBuilder().setDividend(dividend).setDivisor(divisor).build();
|
|
||||||
final SettableFuture<DivReply> responseFuture = SettableFuture.create();
|
|
||||||
asyncStub.div(request, new StreamObserver<DivReply> (){
|
|
||||||
DivReply reply;
|
|
||||||
@Override
|
|
||||||
public void onValue(DivReply value) {
|
|
||||||
reply = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
responseFuture.setException(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCompleted() {
|
|
||||||
responseFuture.set(reply);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
logger.info("Waiting for result...");
|
|
||||||
try {
|
|
||||||
DivReply reply = responseFuture.get();
|
|
||||||
logger.info(
|
|
||||||
"Result: Quotient=" + reply.getQuotient() + ", remainder=" + reply.getRemainder());
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.log(Level.WARNING, "Interrupted while waiting for result...", e);
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
logger.log(Level.WARNING, "RPC failed", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This example shows how to make a bi-directional streaming call, which can only be asynchronous.
|
|
||||||
*/
|
|
||||||
public void divMany() {
|
|
||||||
logger.info("*** DivMany");
|
|
||||||
final SettableFuture<Void> finishFuture = SettableFuture.create();
|
|
||||||
StreamObserver<DivArgs> requestSink = asyncStub.divMany(new StreamObserver<DivReply>() {
|
|
||||||
int count = 0;
|
|
||||||
@Override
|
|
||||||
public void onValue(DivReply value) {
|
|
||||||
count++;
|
|
||||||
logger.info("Result " + count + ": Quotient=" + value.getQuotient() + ", remainder="
|
|
||||||
+ value.getRemainder());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
finishFuture.setException(t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCompleted() {
|
|
||||||
finishFuture.set(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
int count = 5;
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
long dividend = rand.nextLong();
|
|
||||||
long divisor = rand.nextInt() + 1; // plus 1 to avoid 0 divisor.
|
|
||||||
logger.info("Request " + (i + 1) + ": Dividend=" + dividend + ", Divisor=%d" + divisor);
|
|
||||||
requestSink.onValue(
|
|
||||||
DivArgs.newBuilder().setDividend(dividend).setDivisor(divisor).build());
|
|
||||||
}
|
|
||||||
requestSink.onCompleted();
|
|
||||||
|
|
||||||
try {
|
|
||||||
finishFuture.get();
|
|
||||||
logger.info("Finished " + count + " div requests");
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
logger.log(Level.WARNING, "Interrupted while waiting for result...", e);
|
|
||||||
} catch (ExecutionException e) {
|
|
||||||
logger.log(Level.WARNING, "RPC failed", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This example shows how to make a client streaming call.
|
|
||||||
*/
|
|
||||||
public void sum() throws InterruptedException {
|
|
||||||
final CountDownLatch completed = new CountDownLatch(1);
|
|
||||||
logger.info("*** Sum");
|
|
||||||
int count = 5;
|
|
||||||
StreamObserver<Num> responseObserver = new StreamObserver<Num>() {
|
|
||||||
@Override
|
|
||||||
public void onValue(Num value) {
|
|
||||||
logger.info("Sum=" + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
logger.log(Level.SEVERE, "Error receiving response", t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCompleted() {
|
|
||||||
completed.countDown();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
StreamObserver<Num> requestObserver = asyncStub.sum(responseObserver);
|
|
||||||
StringBuilder numMsg = new StringBuilder();
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
int value = rand.nextInt();
|
|
||||||
requestObserver.onValue(Num.newBuilder().setNum(value).build());
|
|
||||||
numMsg.append(value);
|
|
||||||
if (i != count - 1) {
|
|
||||||
numMsg.append(" + ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
logger.info(numMsg.toString());
|
|
||||||
requestObserver.onCompleted();
|
|
||||||
completed.await();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This example shows how to make a blocking server streaming call.
|
|
||||||
*
|
|
||||||
* <p> The asynchronous usage is similar to {@link #divMany}.
|
|
||||||
*/
|
|
||||||
public void blockingFib() {
|
|
||||||
// TODO(madongfly): Support "send until cancel". Currently, client application can not
|
|
||||||
// cancel a server streaming call.
|
|
||||||
int limit = rand.nextInt(20) + 10;
|
|
||||||
logger.info("*** Blocking Fib, print the first " + limit + " fibonacci numbers.");
|
|
||||||
Iterator<Num> iterator = blockingStub.fib(FibArgs.newBuilder().setLimit(limit).build());
|
|
||||||
StringBuilder resultMsg = new StringBuilder();
|
|
||||||
int realCount = 0;
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
realCount++;
|
|
||||||
resultMsg.append(iterator.next().getNum());
|
|
||||||
resultMsg.append(", ");
|
|
||||||
}
|
|
||||||
logger.info("The first " + realCount + " fibonacci numbers: " + resultMsg.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws InterruptedException {
|
|
||||||
MathClient client = new MathClient("localhost", 8980);
|
|
||||||
try {
|
|
||||||
client.blockingDiv(2014, 4);
|
|
||||||
// Note: This call should be failed, but we can not get the server specified error info
|
|
||||||
// currently, so the error message logged is not clear.
|
|
||||||
client.blockingDiv(73, 0);
|
|
||||||
client.asyncDiv(1986, 12);
|
|
||||||
client.divMany();
|
|
||||||
client.sum();
|
|
||||||
client.blockingFib();
|
|
||||||
} finally {
|
|
||||||
client.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,184 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2014, 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;
|
|
||||||
|
|
||||||
import io.grpc.examples.CalcGrpc;
|
|
||||||
import io.grpc.examples.Math.DivArgs;
|
|
||||||
import io.grpc.examples.Math.DivReply;
|
|
||||||
import io.grpc.examples.Math.FibArgs;
|
|
||||||
import io.grpc.examples.Math.Num;
|
|
||||||
|
|
||||||
import io.grpc.ServerImpl;
|
|
||||||
import io.grpc.stub.StreamObserver;
|
|
||||||
import io.grpc.transport.netty.NettyServerBuilder;
|
|
||||||
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A sample gRPC server that serve the Calc (see math.proto) service.
|
|
||||||
*/
|
|
||||||
public class MathServer {
|
|
||||||
private final Logger logger = Logger.getLogger(MathServer.class.getName());
|
|
||||||
private final int port;
|
|
||||||
private ServerImpl gRpcServer;
|
|
||||||
|
|
||||||
public MathServer(int port) {
|
|
||||||
this.port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start() {
|
|
||||||
gRpcServer = NettyServerBuilder.forPort(port)
|
|
||||||
.addService(CalcGrpc.bindService(new CalcService()))
|
|
||||||
.build().start();
|
|
||||||
logger.info("Server started, listening on " + port);
|
|
||||||
// TODO(madongfly): gRPC server should register JVM shutdown hook to shutdown itself, remove this
|
|
||||||
// after we support that.
|
|
||||||
Runtime.getRuntime().addShutdownHook(new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
// Use stderr here since the logger may has been reset by its JVM shutdown hook.
|
|
||||||
System.err.println("*** shutting down gRPC server since JVM is shutting down");
|
|
||||||
MathServer.this.stop();
|
|
||||||
System.err.println("*** server shut down");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
if (gRpcServer != null) {
|
|
||||||
gRpcServer.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
MathServer server = new MathServer(8980);
|
|
||||||
server.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Our implementation of Calc service.
|
|
||||||
*
|
|
||||||
* <p> See math.proto for details of the methods.
|
|
||||||
*/
|
|
||||||
private class CalcService implements CalcGrpc.Calc {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void div(DivArgs request, StreamObserver<DivReply> responseObserver) {
|
|
||||||
if (request.getDivisor() == 0) {
|
|
||||||
responseObserver.onError(new IllegalArgumentException("divisor is 0"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
responseObserver.onValue(div(request));
|
|
||||||
responseObserver.onCompleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public StreamObserver<DivArgs> divMany(final StreamObserver<DivReply> responseObserver) {
|
|
||||||
return new StreamObserver<DivArgs>() {
|
|
||||||
@Override
|
|
||||||
public void onValue(DivArgs value) {
|
|
||||||
if (value.getDivisor() == 0) {
|
|
||||||
responseObserver.onError(new IllegalArgumentException("divisor is 0"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
responseObserver.onValue(div(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
logger.log(Level.WARNING, "Encountered error in divMany", t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCompleted() {
|
|
||||||
responseObserver.onCompleted();
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void fib(FibArgs request, StreamObserver<Num> responseObserver) {
|
|
||||||
int limit = (int) request.getLimit();
|
|
||||||
if (limit <= 0) {
|
|
||||||
// TODO(madongfly): Support "send until cancel". Currently, client application can not
|
|
||||||
// cancel a server streaming call.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
long preLast = 1;
|
|
||||||
long last = 1;
|
|
||||||
for (int i = 0; i < limit; i++) {
|
|
||||||
if (i < 2) {
|
|
||||||
responseObserver.onValue(Num.newBuilder().setNum(1).build());
|
|
||||||
} else {
|
|
||||||
long fib = preLast + last;
|
|
||||||
responseObserver.onValue(Num.newBuilder().setNum(fib).build());
|
|
||||||
preLast = last;
|
|
||||||
last = fib;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
responseObserver.onCompleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public StreamObserver<Num> sum(final StreamObserver<Num> responseObserver) {
|
|
||||||
return new StreamObserver<Num>() {
|
|
||||||
long sum = 0;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onValue(Num value) {
|
|
||||||
sum += value.getNum();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
logger.log(Level.WARNING, "Encountered error in sum", t);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCompleted() {
|
|
||||||
responseObserver.onValue(Num.newBuilder().setNum(sum).build());
|
|
||||||
responseObserver.onCompleted();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private DivReply div(DivArgs request) {
|
|
||||||
long divisor = request.getDivisor();
|
|
||||||
long dividend = request.getDividend();
|
|
||||||
return DivReply.newBuilder()
|
|
||||||
.setQuotient(dividend / divisor)
|
|
||||||
.setRemainder(dividend % divisor)
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,255 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.SettableFuture;
|
||||||
|
|
||||||
|
import io.grpc.ChannelImpl;
|
||||||
|
import io.grpc.examples.RouteGuideGrpc.RouteGuideBlockingStub;
|
||||||
|
import io.grpc.examples.RouteGuideGrpc.RouteGuideStub;
|
||||||
|
import io.grpc.examples.RouteGuideOuterClass.Feature;
|
||||||
|
import io.grpc.examples.RouteGuideOuterClass.Point;
|
||||||
|
import io.grpc.examples.RouteGuideOuterClass.Rectangle;
|
||||||
|
import io.grpc.examples.RouteGuideOuterClass.RouteNote;
|
||||||
|
import io.grpc.examples.RouteGuideOuterClass.RouteSummary;
|
||||||
|
import io.grpc.stub.StreamObserver;
|
||||||
|
import io.grpc.transport.netty.NegotiationType;
|
||||||
|
import io.grpc.transport.netty.NettyChannelBuilder;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sample client code that makes gRPC calls to the server.
|
||||||
|
*/
|
||||||
|
public class RouteGuideClient {
|
||||||
|
private static final Logger logger = Logger.getLogger(RouteGuideClient.class.getName());
|
||||||
|
|
||||||
|
private final ChannelImpl channel;
|
||||||
|
private final RouteGuideBlockingStub blockingStub;
|
||||||
|
private final RouteGuideStub asyncStub;
|
||||||
|
|
||||||
|
public RouteGuideClient(String host, int port) {
|
||||||
|
channel = NettyChannelBuilder.forAddress(host, port)
|
||||||
|
.negotiationType(NegotiationType.PLAINTEXT)
|
||||||
|
.build();
|
||||||
|
blockingStub = RouteGuideGrpc.newBlockingStub(channel);
|
||||||
|
asyncStub = RouteGuideGrpc.newStub(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shutdown() throws InterruptedException {
|
||||||
|
channel.shutdown().awaitTerminated(5, TimeUnit.SECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This example shows how to make a blocking unary call.
|
||||||
|
*/
|
||||||
|
public void getFeature(int lat, int lon) {
|
||||||
|
try {
|
||||||
|
info("*** GetFeature: lat={0} lon={1}", lat, lon);
|
||||||
|
|
||||||
|
Point request = Point.newBuilder().setLatitude(lat).setLongitude(lon).build();
|
||||||
|
Feature feature = blockingStub.getFeature(request);
|
||||||
|
if (RouteGuideUtil.exists(feature)) {
|
||||||
|
info("Found feature called \"{0}\" at {1}, {2}",
|
||||||
|
feature.getName(),
|
||||||
|
RouteGuideUtil.getLatitude(feature.getLocation()),
|
||||||
|
RouteGuideUtil.getLongitude(feature.getLocation()));
|
||||||
|
} else {
|
||||||
|
info("Found no feature at {0}, {1}",
|
||||||
|
RouteGuideUtil.getLatitude(feature.getLocation()),
|
||||||
|
RouteGuideUtil.getLongitude(feature.getLocation()));
|
||||||
|
}
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
logger.log(Level.WARNING, "RPC failed", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This example shows how to make a blocking unary call.
|
||||||
|
*/
|
||||||
|
public void listFeatures(int lowLat, int lowLon, int hiLat, int hiLon) {
|
||||||
|
try {
|
||||||
|
info("*** ListFeatures: lowLat={0} lowLon={1} hiLat={2} hiLon={3}", lowLat, lowLon, hiLat,
|
||||||
|
hiLon);
|
||||||
|
|
||||||
|
Rectangle request =
|
||||||
|
Rectangle.newBuilder()
|
||||||
|
.setLo(Point.newBuilder().setLatitude(lowLat).setLongitude(lowLon).build())
|
||||||
|
.setHi(Point.newBuilder().setLatitude(hiLat).setLongitude(hiLon).build()).build();
|
||||||
|
Iterator<Feature> features = blockingStub.listFeatures(request);
|
||||||
|
|
||||||
|
StringBuilder responseLog = new StringBuilder("Result: ");
|
||||||
|
while (features.hasNext()) {
|
||||||
|
Feature feature = features.next();
|
||||||
|
responseLog.append(feature);
|
||||||
|
}
|
||||||
|
info(responseLog.toString());
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
logger.log(Level.WARNING, "RPC failed", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void recordRoute(List<Feature> features, int numPoints) throws Exception {
|
||||||
|
info("*** RecordRoute");
|
||||||
|
final SettableFuture<Void> finishFuture = SettableFuture.create();
|
||||||
|
StreamObserver<RouteSummary> responseObserver = new StreamObserver<RouteSummary>() {
|
||||||
|
@Override
|
||||||
|
public void onValue(RouteSummary summary) {
|
||||||
|
info("Finished trip with {0} points. Passed {1} features. "
|
||||||
|
+ "Travelled {2} meters. It took {3} seconds.", summary.getPointCount(),
|
||||||
|
summary.getFeatureCount(), summary.getDistance(), summary.getElapsedTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable t) {
|
||||||
|
finishFuture.setException(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCompleted() {
|
||||||
|
finishFuture.set(null);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
StreamObserver<Point> requestObserver = asyncStub.recordRoute(responseObserver);
|
||||||
|
try {
|
||||||
|
// Send numPoints points randomly selected from the features list.
|
||||||
|
StringBuilder numMsg = new StringBuilder();
|
||||||
|
Random rand = new Random();
|
||||||
|
for (int i = 0; i < numPoints; ++i) {
|
||||||
|
int index = rand.nextInt(features.size());
|
||||||
|
Point point = features.get(index).getLocation();
|
||||||
|
info("Visiting point {0}, {1}", RouteGuideUtil.getLatitude(point),
|
||||||
|
RouteGuideUtil.getLongitude(point));
|
||||||
|
requestObserver.onValue(point);
|
||||||
|
// Sleep for a bit before sending the next one.
|
||||||
|
Thread.sleep(rand.nextInt(1000) + 500);
|
||||||
|
if (finishFuture.isDone()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info(numMsg.toString());
|
||||||
|
requestObserver.onCompleted();
|
||||||
|
|
||||||
|
finishFuture.get();
|
||||||
|
info("Finished RecordRoute");
|
||||||
|
} catch (Exception e) {
|
||||||
|
requestObserver.onError(e);
|
||||||
|
logger.log(Level.WARNING, "RecordRoute Failed", e);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This example shows how to make a bi-directional streaming call, which can only be asynchronous.
|
||||||
|
*/
|
||||||
|
public void routeChat() throws Exception {
|
||||||
|
info("*** RoutChat");
|
||||||
|
final SettableFuture<Void> finishFuture = SettableFuture.create();
|
||||||
|
StreamObserver<RouteNote> requestObserver =
|
||||||
|
asyncStub.routeChat(new StreamObserver<RouteNote>() {
|
||||||
|
@Override
|
||||||
|
public void onValue(RouteNote note) {
|
||||||
|
info("Got message \"{0}\" at {1}, {2}", note.getMessage(), note.getLocation()
|
||||||
|
.getLatitude(), note.getLocation().getLongitude());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable t) {
|
||||||
|
finishFuture.setException(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCompleted() {
|
||||||
|
finishFuture.set(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
RouteNote[] requests =
|
||||||
|
{newNote("First message", 0, 0), newNote("Second message", 0, 1),
|
||||||
|
newNote("Third message", 1, 0), newNote("Fourth message", 1, 1)};
|
||||||
|
|
||||||
|
for (RouteNote request : requests) {
|
||||||
|
info("Sending message \"{0}\" at {1}, {2}", request.getMessage(), request.getLocation()
|
||||||
|
.getLatitude(), request.getLocation().getLongitude());
|
||||||
|
requestObserver.onValue(request);
|
||||||
|
}
|
||||||
|
requestObserver.onCompleted();
|
||||||
|
|
||||||
|
finishFuture.get();
|
||||||
|
info("Finished RouteChat");
|
||||||
|
} catch (Exception t) {
|
||||||
|
requestObserver.onError(t);
|
||||||
|
logger.log(Level.WARNING, "RouteChat Failed", t);
|
||||||
|
throw t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
RouteGuideClient client = new RouteGuideClient("localhost", 8980);
|
||||||
|
try {
|
||||||
|
// Looking for a valid feature
|
||||||
|
client.getFeature(409146138, -746188906);
|
||||||
|
|
||||||
|
// Feature missing.
|
||||||
|
client.getFeature(0, 0);
|
||||||
|
|
||||||
|
// Looking for features between 40, -75 and 42, -73.
|
||||||
|
client.listFeatures(400000000, -750000000, 420000000, -730000000);
|
||||||
|
|
||||||
|
// Record a few randomly selected points from the features file.
|
||||||
|
client.recordRoute(RouteGuideUtil.parseFeatures(RouteGuideUtil.getDefaultFeaturesFile()), 10);
|
||||||
|
|
||||||
|
// Send and receive some notes.
|
||||||
|
client.routeChat();
|
||||||
|
} finally {
|
||||||
|
client.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void info(String msg, Object... params) {
|
||||||
|
logger.log(Level.INFO, msg, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RouteNote newNote(String message, int lat, int lon) {
|
||||||
|
return RouteNote.newBuilder().setMessage(message)
|
||||||
|
.setLocation(Point.newBuilder().setLatitude(lat).setLongitude(lon).build()).build();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,302 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import static java.lang.Math.atan2;
|
||||||
|
import static java.lang.Math.cos;
|
||||||
|
import static java.lang.Math.max;
|
||||||
|
import static java.lang.Math.min;
|
||||||
|
import static java.lang.Math.sin;
|
||||||
|
import static java.lang.Math.sqrt;
|
||||||
|
import static java.lang.Math.toRadians;
|
||||||
|
import static java.util.concurrent.TimeUnit.NANOSECONDS;
|
||||||
|
|
||||||
|
import io.grpc.ServerImpl;
|
||||||
|
import io.grpc.examples.RouteGuideOuterClass.Feature;
|
||||||
|
import io.grpc.examples.RouteGuideOuterClass.Point;
|
||||||
|
import io.grpc.examples.RouteGuideOuterClass.Rectangle;
|
||||||
|
import io.grpc.examples.RouteGuideOuterClass.RouteNote;
|
||||||
|
import io.grpc.examples.RouteGuideOuterClass.RouteSummary;
|
||||||
|
import io.grpc.stub.StreamObserver;
|
||||||
|
import io.grpc.transport.netty.NettyServerBuilder;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A sample gRPC server that serve the RouteGuide (see route_guide.proto) service.
|
||||||
|
*/
|
||||||
|
public class RouteGuideServer {
|
||||||
|
private static final Logger logger = Logger.getLogger(RouteGuideServer.class.getName());
|
||||||
|
|
||||||
|
private final int port;
|
||||||
|
private final Collection<Feature> features;
|
||||||
|
private ServerImpl gRpcServer;
|
||||||
|
|
||||||
|
public RouteGuideServer(int port) {
|
||||||
|
this(port, RouteGuideUtil.getDefaultFeaturesFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
public RouteGuideServer(int port, URL featureFile) {
|
||||||
|
try {
|
||||||
|
this.port = port;
|
||||||
|
features = RouteGuideUtil.parseFeatures(featureFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
gRpcServer = NettyServerBuilder.forPort(port)
|
||||||
|
.addService(RouteGuideGrpc.bindService(new RouteGuideService(features)))
|
||||||
|
.build().start();
|
||||||
|
logger.info("Server started, listening on " + port);
|
||||||
|
// TODO(simonma): gRPC server should register JVM shutdown hook to shutdown itself, remove this
|
||||||
|
// after we support that.
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Use stderr here since the logger may has been reset by its JVM shutdown hook.
|
||||||
|
System.err.println("*** shutting down gRPC server since JVM is shutting down");
|
||||||
|
RouteGuideServer.this.stop();
|
||||||
|
System.err.println("*** server shut down");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (gRpcServer != null) {
|
||||||
|
gRpcServer.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
RouteGuideServer server = new RouteGuideServer(8980);
|
||||||
|
server.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Our implementation of RouteGuide service.
|
||||||
|
*
|
||||||
|
* <p> See route_guide.proto for details of the methods.
|
||||||
|
*/
|
||||||
|
private static class RouteGuideService implements RouteGuideGrpc.RouteGuide {
|
||||||
|
private final Collection<Feature> features;
|
||||||
|
private final ConcurrentMap<Point, List<RouteNote>> routeNotes =
|
||||||
|
new ConcurrentHashMap<Point, List<RouteNote>>();
|
||||||
|
|
||||||
|
RouteGuideService(Collection<Feature> features) {
|
||||||
|
this.features = features;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the {@link Feature} at the requested {@link Point}. If no feature at that location
|
||||||
|
* exists, an unnammed feature is returned at the provided location.
|
||||||
|
*
|
||||||
|
* @param request the requested location for the feature.
|
||||||
|
* @param responseObserver the observer that will receive the feature at the requested point.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void getFeature(Point request, StreamObserver<Feature> responseObserver) {
|
||||||
|
responseObserver.onValue(getFeature(request));
|
||||||
|
responseObserver.onCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all features contained within the given bounding {@link Rectangle}.
|
||||||
|
*
|
||||||
|
* @param request the bounding rectangle for the requested features.
|
||||||
|
* @param responseObserver the observer that will receive the features.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void listFeatures(Rectangle request, StreamObserver<Feature> responseObserver) {
|
||||||
|
int left = min(request.getLo().getLongitude(), request.getHi().getLongitude());
|
||||||
|
int right = max(request.getLo().getLongitude(), request.getHi().getLongitude());
|
||||||
|
int top = max(request.getLo().getLatitude(), request.getHi().getLatitude());
|
||||||
|
int bottom = min(request.getLo().getLatitude(), request.getHi().getLatitude());
|
||||||
|
|
||||||
|
for (Feature feature : features) {
|
||||||
|
if (!RouteGuideUtil.exists(feature)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lat = feature.getLocation().getLatitude();
|
||||||
|
int lon = feature.getLocation().getLongitude();
|
||||||
|
if (lon >= left && lon <= right && lat >= bottom && lat <= top) {
|
||||||
|
responseObserver.onValue(feature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
responseObserver.onCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a stream of points, and responds with statistics about the "trip": number of points,
|
||||||
|
* number of known features visited, total distance traveled, and total time spent.
|
||||||
|
*
|
||||||
|
* @param responseObserver an observer to receive the response summary.
|
||||||
|
* @return an observer to receive the requested route points.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public StreamObserver<Point> recordRoute(final StreamObserver<RouteSummary> responseObserver) {
|
||||||
|
return new StreamObserver<Point>() {
|
||||||
|
int pointCount;
|
||||||
|
int featureCount;
|
||||||
|
int distance;
|
||||||
|
Point previous;
|
||||||
|
long startTime = System.nanoTime();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onValue(Point point) {
|
||||||
|
pointCount++;
|
||||||
|
if (RouteGuideUtil.exists(getFeature(point))) {
|
||||||
|
featureCount++;
|
||||||
|
}
|
||||||
|
// For each point after the first, add the incremental distance from the previous point to
|
||||||
|
// the total distance value.
|
||||||
|
if (previous != null) {
|
||||||
|
distance += calcDistance(previous, point);
|
||||||
|
}
|
||||||
|
previous = point;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable t) {
|
||||||
|
logger.log(Level.WARNING, "Encountered error in recordRoute", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCompleted() {
|
||||||
|
long seconds = NANOSECONDS.toSeconds(System.nanoTime() - startTime);
|
||||||
|
responseObserver.onValue(RouteSummary.newBuilder().setPointCount(pointCount)
|
||||||
|
.setFeatureCount(featureCount).setDistance(distance)
|
||||||
|
.setElapsedTime((int) seconds).build());
|
||||||
|
responseObserver.onCompleted();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receives a stream of message/location pairs, and responds with a stream of all previous
|
||||||
|
* messages at each of those locations.
|
||||||
|
*
|
||||||
|
* @param responseObserver an observer to receive the stream of previous messages.
|
||||||
|
* @return an observer to handle requested message/location pairs.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public StreamObserver<RouteNote> routeChat(final StreamObserver<RouteNote> responseObserver) {
|
||||||
|
return new StreamObserver<RouteNote>() {
|
||||||
|
@Override
|
||||||
|
public void onValue(RouteNote note) {
|
||||||
|
List<RouteNote> notes = getOrCreateNotes(note.getLocation());
|
||||||
|
|
||||||
|
// Respond with all previous notes at this location.
|
||||||
|
for (RouteNote prevNote : notes.toArray(new RouteNote[0])) {
|
||||||
|
responseObserver.onValue(prevNote);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now add the new note to the list
|
||||||
|
notes.add(note);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onError(Throwable t) {
|
||||||
|
logger.log(Level.WARNING, "Encountered error in routeChat", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCompleted() {
|
||||||
|
responseObserver.onCompleted();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the notes list for the given location. If missing, create it.
|
||||||
|
*/
|
||||||
|
private List<RouteNote> getOrCreateNotes(Point location) {
|
||||||
|
List<RouteNote> notes = Collections.synchronizedList(new ArrayList<RouteNote>());
|
||||||
|
List<RouteNote> prevNotes = routeNotes.putIfAbsent(location, notes);
|
||||||
|
return prevNotes != null ? prevNotes : notes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the feature at the given point.
|
||||||
|
*
|
||||||
|
* @param location the location to check.
|
||||||
|
* @return The feature object at the point. Note that an empty name indicates no feature.
|
||||||
|
*/
|
||||||
|
private Feature getFeature(Point location) {
|
||||||
|
for (Feature feature : features) {
|
||||||
|
if (feature.getLocation().getLatitude() == location.getLatitude()
|
||||||
|
&& feature.getLocation().getLongitude() == location.getLongitude()) {
|
||||||
|
return feature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No feature was found, return an unnamed feature.
|
||||||
|
return Feature.newBuilder().setName("").setLocation(location).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the distance between two points using the "haversine" formula.
|
||||||
|
* This code was taken from http://www.movable-type.co.uk/scripts/latlong.html.
|
||||||
|
*
|
||||||
|
* @param start The starting point
|
||||||
|
* @param end The end point
|
||||||
|
* @return The distance between the points in meters
|
||||||
|
*/
|
||||||
|
private static double calcDistance(Point start, Point end) {
|
||||||
|
double lat1 = RouteGuideUtil.getLatitude(start);
|
||||||
|
double lat2 = RouteGuideUtil.getLatitude(end);
|
||||||
|
double lon1 = RouteGuideUtil.getLongitude(start);
|
||||||
|
double lon2 = RouteGuideUtil.getLongitude(end);
|
||||||
|
int R = 6371000; // metres
|
||||||
|
double φ1 = toRadians(lat1);
|
||||||
|
double φ2 = toRadians(lat2);
|
||||||
|
double Δφ = toRadians(lat2-lat1);
|
||||||
|
double Δλ = toRadians(lon2-lon1);
|
||||||
|
|
||||||
|
double a = sin(Δφ/2) * sin(Δφ/2) + cos(φ1) * cos(φ2) * sin(Δλ/2) * sin(Δλ/2);
|
||||||
|
double c = 2 * atan2(sqrt(a), sqrt(1-a));
|
||||||
|
|
||||||
|
return R * c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,111 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import io.grpc.examples.RouteGuideOuterClass.Feature;
|
||||||
|
import io.grpc.examples.RouteGuideOuterClass.Point;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonObject;
|
||||||
|
import javax.json.JsonReader;
|
||||||
|
import javax.json.JsonValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common utilities for the RouteGuide demo.
|
||||||
|
*/
|
||||||
|
public class RouteGuideUtil {
|
||||||
|
private static final double COORD_FACTOR = 1e7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the latitude for the given point.
|
||||||
|
*/
|
||||||
|
public static double getLatitude(Point location) {
|
||||||
|
return location.getLatitude() / COORD_FACTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the longitude for the given point.
|
||||||
|
*/
|
||||||
|
public static double getLongitude(Point location) {
|
||||||
|
return location.getLongitude() / COORD_FACTOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the default features file from classpath.
|
||||||
|
*/
|
||||||
|
public static URL getDefaultFeaturesFile() {
|
||||||
|
return RouteGuideServer.class.getResource("route_guide_db.json");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the JSON input file containing the list of features.
|
||||||
|
*/
|
||||||
|
public static List<Feature> parseFeatures(URL file) throws IOException {
|
||||||
|
InputStream input = file.openStream();
|
||||||
|
try {
|
||||||
|
JsonReader reader = Json.createReader(input);
|
||||||
|
List<Feature> features = new ArrayList<Feature>();
|
||||||
|
for (JsonValue value : reader.readArray()) {
|
||||||
|
JsonObject obj = (JsonObject) value;
|
||||||
|
String name = obj.getString("name", "");
|
||||||
|
JsonObject location = obj.getJsonObject("location");
|
||||||
|
int lat = location.getInt("latitude");
|
||||||
|
int lon = location.getInt("longitude");
|
||||||
|
Feature feature =
|
||||||
|
Feature
|
||||||
|
.newBuilder()
|
||||||
|
.setName(name)
|
||||||
|
.setLocation(
|
||||||
|
Point.newBuilder().setLatitude(lat)
|
||||||
|
.setLongitude(lon).build()).build();
|
||||||
|
features.add(feature);
|
||||||
|
}
|
||||||
|
|
||||||
|
return features;
|
||||||
|
} finally {
|
||||||
|
input.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates whether the given feature exists (i.e. has a valid name).
|
||||||
|
*/
|
||||||
|
public static boolean exists(Feature feature) {
|
||||||
|
return feature != null && !feature.getName().isEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,214 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2014, 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;
|
|
||||||
|
|
||||||
import io.grpc.examples.StockGrpc;
|
|
||||||
import io.grpc.examples.StockGrpc.StockBlockingStub;
|
|
||||||
import io.grpc.examples.StockGrpc.StockStub;
|
|
||||||
import io.grpc.examples.StockOuterClass.StockReply;
|
|
||||||
import io.grpc.examples.StockOuterClass.StockRequest;
|
|
||||||
|
|
||||||
import io.grpc.ChannelImpl;
|
|
||||||
import io.grpc.stub.StreamObserver;
|
|
||||||
import io.grpc.transport.netty.NegotiationType;
|
|
||||||
import io.grpc.transport.netty.NettyChannelBuilder;
|
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.concurrent.CountDownLatch;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sample client code that makes GRPC calls to the server.
|
|
||||||
*/
|
|
||||||
public class StockClient {
|
|
||||||
|
|
||||||
private final ChannelImpl channel = NettyChannelBuilder.forAddress("localhost", 8980)
|
|
||||||
.negotiationType(NegotiationType.PLAINTEXT)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
public void shutdown() throws InterruptedException {
|
|
||||||
channel.shutdown().awaitTerminated(5, TimeUnit.SECONDS);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void makeBlockingSimpleCall() {
|
|
||||||
StockBlockingStub stub = StockGrpc.newBlockingStub(channel)
|
|
||||||
.configureNewStub().setTimeout(2, TimeUnit.SECONDS).build();
|
|
||||||
StockRequest request = StockRequest.newBuilder().setSymbol("GOOG").build();
|
|
||||||
System.out.println("***Blocking simple call, request=" + request);
|
|
||||||
StockReply reply = stub.getLastTradePrice(request);
|
|
||||||
System.out.println("response=" + reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void makeAsyncSimpleCall() {
|
|
||||||
StockStub stub = StockGrpc.newStub(channel)
|
|
||||||
.configureNewStub().setTimeout(2, TimeUnit.SECONDS).build();
|
|
||||||
StockRequest request = StockRequest.newBuilder().setSymbol("MSFT").build();
|
|
||||||
System.out.println("***Async simple call, request=" + request);
|
|
||||||
stub.getLastTradePrice(request, new StreamObserver<StockReply>() {
|
|
||||||
StockReply response;
|
|
||||||
@Override
|
|
||||||
public void onValue(StockReply response) {
|
|
||||||
this.response = response;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCompleted() {
|
|
||||||
System.out.println("Completed, response=" + response);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void makeSequentialCalls() {
|
|
||||||
StockBlockingStub stub = StockGrpc.newBlockingStub(channel)
|
|
||||||
.configureNewStub().setTimeout(2, TimeUnit.SECONDS).build();
|
|
||||||
System.out.println("***Making sequential calls");
|
|
||||||
StockRequest request1 = StockRequest.newBuilder().setSymbol("AMZN").build();
|
|
||||||
System.out.println("First request=" + request1);
|
|
||||||
StockReply response1 = stub.getLastTradePrice(request1);
|
|
||||||
System.out.println("First response=" + response1);
|
|
||||||
StockRequest request2 = StockRequest.newBuilder().setSymbol(response1.getSymbol()).build();
|
|
||||||
System.out.println("Second request=" + request2);
|
|
||||||
StockReply response2 = stub.getLastTradePrice(request2);
|
|
||||||
System.out.println("Second response=" + response2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void makeAsyncCalls() throws InterruptedException {
|
|
||||||
StockStub stub = StockGrpc.newStub(channel)
|
|
||||||
.configureNewStub().setTimeout(2, TimeUnit.SECONDS).build();
|
|
||||||
System.out.println("***Making two calls in parallel");
|
|
||||||
final StockRequest request1 = StockRequest.newBuilder().setSymbol("IBM").build();
|
|
||||||
final StockRequest request2 = StockRequest.newBuilder().setSymbol("APPL").build();
|
|
||||||
final CountDownLatch completeLatch = new CountDownLatch(2);
|
|
||||||
stub.getLastTradePrice(request1, new StreamObserver<StockReply>() {
|
|
||||||
StockReply response;
|
|
||||||
@Override
|
|
||||||
public void onValue(StockReply response) {
|
|
||||||
this.response = response;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCompleted() {
|
|
||||||
System.out.println("Completed for first request=" + request1 + ", response=" + response);
|
|
||||||
completeLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
stub.getLastTradePrice(request2, new StreamObserver<StockReply>() {
|
|
||||||
StockReply response;
|
|
||||||
@Override
|
|
||||||
public void onValue(StockReply response) {
|
|
||||||
this.response = response;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCompleted() {
|
|
||||||
System.out.println("Completed for second request=" + request2 + ", response=" + response);
|
|
||||||
completeLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
completeLatch.await();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void makeServerStreamingCall() {
|
|
||||||
StockBlockingStub stub = StockGrpc.newBlockingStub(channel)
|
|
||||||
.configureNewStub().setTimeout(2, TimeUnit.SECONDS).build();
|
|
||||||
StockRequest request = StockRequest.newBuilder().setSymbol("FB").setNumTradesToWatch(5).build();
|
|
||||||
System.out.println("***Making a server streaming call, request=" + request);
|
|
||||||
for (Iterator<StockReply> responses = stub.watchFutureTrades(request); responses.hasNext(); ) {
|
|
||||||
StockReply response = responses.next();
|
|
||||||
System.out.println("Response=" + response);
|
|
||||||
}
|
|
||||||
System.out.println("Completed");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void makeClientStreamingCall() throws InterruptedException {
|
|
||||||
StockStub stub = StockGrpc.newStub(channel)
|
|
||||||
.configureNewStub().setTimeout(2, TimeUnit.SECONDS).build();
|
|
||||||
System.out.println("***Making a client streaming call");
|
|
||||||
final CountDownLatch completeLatch = new CountDownLatch(1);
|
|
||||||
StreamObserver<StockRequest> requestSink = stub.getHighestTradePrice(
|
|
||||||
new StreamObserver<StockReply>() {
|
|
||||||
StockReply response;
|
|
||||||
@Override
|
|
||||||
public void onValue(StockReply response) {
|
|
||||||
this.response = response;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
t.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCompleted() {
|
|
||||||
System.out.println("Completed. response=" + response);
|
|
||||||
completeLatch.countDown();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
for (String symbol : new String[] {"ORCL", "TWTR", "QQQ", "SIRI", "ZNGA", "RAD"}) {
|
|
||||||
StockRequest request = StockRequest.newBuilder().setSymbol(symbol).build();
|
|
||||||
System.out.println("request=" + request);
|
|
||||||
requestSink.onValue(request);
|
|
||||||
}
|
|
||||||
requestSink.onCompleted();
|
|
||||||
completeLatch.await();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws InterruptedException {
|
|
||||||
StockClient client = new StockClient();
|
|
||||||
try {
|
|
||||||
client.makeBlockingSimpleCall();
|
|
||||||
client.makeAsyncSimpleCall();
|
|
||||||
client.makeSequentialCalls();
|
|
||||||
client.makeAsyncCalls();
|
|
||||||
client.makeServerStreamingCall();
|
|
||||||
client.makeClientStreamingCall();
|
|
||||||
System.out.println("***All done");
|
|
||||||
} finally {
|
|
||||||
client.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,140 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2014, 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;
|
|
||||||
|
|
||||||
import io.grpc.examples.StockGrpc;
|
|
||||||
import io.grpc.examples.StockOuterClass.StockReply;
|
|
||||||
import io.grpc.examples.StockOuterClass.StockRequest;
|
|
||||||
|
|
||||||
import io.grpc.ServerImpl;
|
|
||||||
import io.grpc.stub.StreamObserver;
|
|
||||||
import io.grpc.transport.netty.NettyServerBuilder;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A sample GRPC server that implements the Stock service.
|
|
||||||
*/
|
|
||||||
public class StockServer implements StockGrpc.Stock {
|
|
||||||
|
|
||||||
private final Random rand = new Random();
|
|
||||||
|
|
||||||
private float getStockPrice(String symbol) {
|
|
||||||
return rand.nextFloat() * 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simple request-response RPC
|
|
||||||
@Override
|
|
||||||
public void getLastTradePrice(StockRequest request, StreamObserver<StockReply> responseObserver) {
|
|
||||||
String symbol = request.getSymbol();
|
|
||||||
float price = getStockPrice(symbol);
|
|
||||||
responseObserver.onValue(
|
|
||||||
StockReply.newBuilder().setSymbol(symbol).setPrice(price).build());
|
|
||||||
responseObserver.onCompleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bi-directional streaming
|
|
||||||
@Override
|
|
||||||
public StreamObserver<StockRequest> getLastTradePriceMultiple(
|
|
||||||
final StreamObserver<StockReply> responseObserver) {
|
|
||||||
return new StreamObserver<StockRequest>() {
|
|
||||||
@Override
|
|
||||||
public void onValue(StockRequest request) {
|
|
||||||
String symbol = request.getSymbol();
|
|
||||||
float price = getStockPrice(symbol);
|
|
||||||
responseObserver.onValue(
|
|
||||||
StockReply.newBuilder().setSymbol(symbol).setPrice(price).build());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCompleted() {
|
|
||||||
responseObserver.onCompleted();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Server streaming
|
|
||||||
@Override
|
|
||||||
public void watchFutureTrades(StockRequest request, StreamObserver<StockReply> responseObserver) {
|
|
||||||
String symbol = request.getSymbol();
|
|
||||||
for (int i = 0; i < request.getNumTradesToWatch(); i++) {
|
|
||||||
float price = getStockPrice(symbol);
|
|
||||||
responseObserver.onValue(
|
|
||||||
StockReply.newBuilder().setSymbol(symbol).setPrice(price).build());
|
|
||||||
}
|
|
||||||
responseObserver.onCompleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Client streaming
|
|
||||||
@Override
|
|
||||||
public StreamObserver<StockRequest> getHighestTradePrice(
|
|
||||||
final StreamObserver<StockReply> responseObserver) {
|
|
||||||
return new StreamObserver<StockRequest>() {
|
|
||||||
String highestSymbol;
|
|
||||||
float highestPrice;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onValue(StockRequest request) {
|
|
||||||
String symbol = request.getSymbol();
|
|
||||||
float price = getStockPrice(symbol);
|
|
||||||
if (highestSymbol == null || price > highestPrice) {
|
|
||||||
highestPrice = price;
|
|
||||||
highestSymbol = symbol;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onError(Throwable t) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onCompleted() {
|
|
||||||
if (highestSymbol != null) {
|
|
||||||
responseObserver.onValue(
|
|
||||||
StockReply.newBuilder().setSymbol(highestSymbol).setPrice(highestPrice).build());
|
|
||||||
}
|
|
||||||
responseObserver.onCompleted();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
ServerImpl server = NettyServerBuilder.forPort(8980)
|
|
||||||
.addService(StockGrpc.bindService(new StockServer()))
|
|
||||||
.build().start();
|
|
||||||
System.out.println("Server started");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
syntax = "proto2";
|
|
||||||
|
|
||||||
package io.grpc.examples;
|
|
||||||
option java_package = "io.grpc.examples";
|
|
||||||
option java_outer_classname = "Math";
|
|
||||||
|
|
||||||
message DivArgs {
|
|
||||||
required int64 dividend = 1;
|
|
||||||
required int64 divisor = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message DivReply {
|
|
||||||
required int64 quotient = 1;
|
|
||||||
required int64 remainder = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message FibArgs {
|
|
||||||
optional int64 limit = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message Num {
|
|
||||||
required int64 num = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message FibReply {
|
|
||||||
required int64 count = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
service Calc {
|
|
||||||
// Div divides args.dividend by args.divisor and returns the quotient and
|
|
||||||
// remainder.
|
|
||||||
rpc Div (DivArgs) returns (DivReply) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// DivMany accepts an arbitrary number of division args from the client stream
|
|
||||||
// and sends back the results in the reply stream. The stream continues until
|
|
||||||
// the client closes its end; the server does the same after sending all the
|
|
||||||
// replies. The stream ends immediately if either end aborts.
|
|
||||||
rpc DivMany (stream DivArgs) returns (stream DivReply) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib
|
|
||||||
// generates up to limit numbers; otherwise it continues until the call is
|
|
||||||
// canceled. Unlike Fib above, Fib has no final FibReply.
|
|
||||||
rpc Fib (FibArgs) returns (stream Num) {
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sum sums a stream of numbers, returning the final result once the stream
|
|
||||||
// is closed.
|
|
||||||
rpc Sum (stream Num) returns (Num) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,120 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option java_package = "io.grpc.examples";
|
||||||
|
|
||||||
|
package examples;
|
||||||
|
|
||||||
|
// Interface exported by the server.
|
||||||
|
service RouteGuide {
|
||||||
|
// A simple RPC.
|
||||||
|
//
|
||||||
|
// Obtains the feature at a given position.
|
||||||
|
rpc GetFeature(Point) returns (Feature) {}
|
||||||
|
|
||||||
|
// A server-to-client streaming RPC.
|
||||||
|
//
|
||||||
|
// Obtains the Features available within the given Rectangle. Results are
|
||||||
|
// streamed rather than returned at once (e.g. in a response message with a
|
||||||
|
// repeated field), as the rectangle may cover a large area and contain a
|
||||||
|
// huge number of features.
|
||||||
|
rpc ListFeatures(Rectangle) returns (stream Feature) {}
|
||||||
|
|
||||||
|
// A client-to-server streaming RPC.
|
||||||
|
//
|
||||||
|
// Accepts a stream of Points on a route being traversed, returning a
|
||||||
|
// RouteSummary when traversal is completed.
|
||||||
|
rpc RecordRoute(stream Point) returns (RouteSummary) {}
|
||||||
|
|
||||||
|
// A Bidirectional streaming RPC.
|
||||||
|
//
|
||||||
|
// Accepts a stream of RouteNotes sent while a route is being traversed,
|
||||||
|
// while receiving other RouteNotes (e.g. from other users).
|
||||||
|
rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Points are represented as latitude-longitude pairs in the E7 representation
|
||||||
|
// (degrees multiplied by 10**7 and rounded to the nearest integer).
|
||||||
|
// Latitudes should be in the range +/- 90 degrees and longitude should be in
|
||||||
|
// the range +/- 180 degrees (inclusive).
|
||||||
|
message Point {
|
||||||
|
optional int32 latitude = 1;
|
||||||
|
optional int32 longitude = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A latitude-longitude rectangle, represented as two diagonally opposite
|
||||||
|
// points "lo" and "hi".
|
||||||
|
message Rectangle {
|
||||||
|
// One corner of the rectangle.
|
||||||
|
optional Point lo = 1;
|
||||||
|
|
||||||
|
// The other corner of the rectangle.
|
||||||
|
optional Point hi = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A feature names something at a given point.
|
||||||
|
//
|
||||||
|
// If a feature could not be named, the name is empty.
|
||||||
|
message Feature {
|
||||||
|
// The name of the feature.
|
||||||
|
optional string name = 1;
|
||||||
|
|
||||||
|
// The point where the feature is detected.
|
||||||
|
optional Point location = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A RouteNote is a message sent while at a given point.
|
||||||
|
message RouteNote {
|
||||||
|
// The location from which the message is sent.
|
||||||
|
optional Point location = 1;
|
||||||
|
|
||||||
|
// The message to be sent.
|
||||||
|
optional string message = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A RouteSummary is received in response to a RecordRoute rpc.
|
||||||
|
//
|
||||||
|
// It contains the number of individual points received, the number of
|
||||||
|
// detected features, and the total distance covered as the cumulative sum of
|
||||||
|
// the distance between each point.
|
||||||
|
message RouteSummary {
|
||||||
|
// The number of points received.
|
||||||
|
optional int32 point_count = 1;
|
||||||
|
|
||||||
|
// The number of known features passed while traversing the route.
|
||||||
|
optional int32 feature_count = 2;
|
||||||
|
|
||||||
|
// The distance covered in metres.
|
||||||
|
optional int32 distance = 3;
|
||||||
|
|
||||||
|
// The duration of the traversal in seconds.
|
||||||
|
optional int32 elapsed_time = 4;
|
||||||
|
}
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
syntax = "proto2";
|
|
||||||
|
|
||||||
package io.grpc.examples;
|
|
||||||
option java_package = "io.grpc.examples";
|
|
||||||
|
|
||||||
// Protocol type definitions
|
|
||||||
message StockRequest {
|
|
||||||
optional string symbol = 1;
|
|
||||||
optional int32 num_trades_to_watch = 2 [default=0];
|
|
||||||
};
|
|
||||||
|
|
||||||
message StockReply {
|
|
||||||
optional float price = 1;
|
|
||||||
optional string symbol = 2;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Interface exported by the server
|
|
||||||
service Stock {
|
|
||||||
// Simple blocking RPC
|
|
||||||
rpc GetLastTradePrice(StockRequest) returns (StockReply) {
|
|
||||||
};
|
|
||||||
// Bidirectional streaming RPC
|
|
||||||
rpc GetLastTradePriceMultiple(stream StockRequest) returns
|
|
||||||
(stream StockReply) {
|
|
||||||
};
|
|
||||||
// Unidirectional server-to-client streaming RPC
|
|
||||||
rpc WatchFutureTrades(StockRequest) returns (stream StockReply) {
|
|
||||||
};
|
|
||||||
// Unidirectional client-to-server streaming RPC
|
|
||||||
rpc GetHighestTradePrice(stream StockRequest) returns (StockReply) {
|
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
@ -0,0 +1,601 @@
|
||||||
|
[{
|
||||||
|
"location": {
|
||||||
|
"latitude": 407838351,
|
||||||
|
"longitude": -746143763
|
||||||
|
},
|
||||||
|
"name": "Patriots Path, Mendham, NJ 07945, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 408122808,
|
||||||
|
"longitude": -743999179
|
||||||
|
},
|
||||||
|
"name": "101 New Jersey 10, Whippany, NJ 07981, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 413628156,
|
||||||
|
"longitude": -749015468
|
||||||
|
},
|
||||||
|
"name": "U.S. 6, Shohola, PA 18458, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 419999544,
|
||||||
|
"longitude": -740371136
|
||||||
|
},
|
||||||
|
"name": "5 Conners Road, Kingston, NY 12401, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 414008389,
|
||||||
|
"longitude": -743951297
|
||||||
|
},
|
||||||
|
"name": "Mid Hudson Psychiatric Center, New Hampton, NY 10958, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 419611318,
|
||||||
|
"longitude": -746524769
|
||||||
|
},
|
||||||
|
"name": "287 Flugertown Road, Livingston Manor, NY 12758, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 406109563,
|
||||||
|
"longitude": -742186778
|
||||||
|
},
|
||||||
|
"name": "4001 Tremley Point Road, Linden, NJ 07036, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 416802456,
|
||||||
|
"longitude": -742370183
|
||||||
|
},
|
||||||
|
"name": "352 South Mountain Road, Wallkill, NY 12589, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 412950425,
|
||||||
|
"longitude": -741077389
|
||||||
|
},
|
||||||
|
"name": "Bailey Turn Road, Harriman, NY 10926, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 412144655,
|
||||||
|
"longitude": -743949739
|
||||||
|
},
|
||||||
|
"name": "193-199 Wawayanda Road, Hewitt, NJ 07421, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 415736605,
|
||||||
|
"longitude": -742847522
|
||||||
|
},
|
||||||
|
"name": "406-496 Ward Avenue, Pine Bush, NY 12566, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 413843930,
|
||||||
|
"longitude": -740501726
|
||||||
|
},
|
||||||
|
"name": "162 Merrill Road, Highland Mills, NY 10930, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 410873075,
|
||||||
|
"longitude": -744459023
|
||||||
|
},
|
||||||
|
"name": "Clinton Road, West Milford, NJ 07480, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 412346009,
|
||||||
|
"longitude": -744026814
|
||||||
|
},
|
||||||
|
"name": "16 Old Brook Lane, Warwick, NY 10990, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 402948455,
|
||||||
|
"longitude": -747903913
|
||||||
|
},
|
||||||
|
"name": "3 Drake Lane, Pennington, NJ 08534, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 406337092,
|
||||||
|
"longitude": -740122226
|
||||||
|
},
|
||||||
|
"name": "6324 8th Avenue, Brooklyn, NY 11220, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 406421967,
|
||||||
|
"longitude": -747727624
|
||||||
|
},
|
||||||
|
"name": "1 Merck Access Road, Whitehouse Station, NJ 08889, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 416318082,
|
||||||
|
"longitude": -749677716
|
||||||
|
},
|
||||||
|
"name": "78-98 Schalck Road, Narrowsburg, NY 12764, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 415301720,
|
||||||
|
"longitude": -748416257
|
||||||
|
},
|
||||||
|
"name": "282 Lakeview Drive Road, Highland Lake, NY 12743, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 402647019,
|
||||||
|
"longitude": -747071791
|
||||||
|
},
|
||||||
|
"name": "330 Evelyn Avenue, Hamilton Township, NJ 08619, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 412567807,
|
||||||
|
"longitude": -741058078
|
||||||
|
},
|
||||||
|
"name": "New York State Reference Route 987E, Southfields, NY 10975, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 416855156,
|
||||||
|
"longitude": -744420597
|
||||||
|
},
|
||||||
|
"name": "103-271 Tempaloni Road, Ellenville, NY 12428, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 404663628,
|
||||||
|
"longitude": -744820157
|
||||||
|
},
|
||||||
|
"name": "1300 Airport Road, North Brunswick Township, NJ 08902, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 407113723,
|
||||||
|
"longitude": -749746483
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 402133926,
|
||||||
|
"longitude": -743613249
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 400273442,
|
||||||
|
"longitude": -741220915
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 411236786,
|
||||||
|
"longitude": -744070769
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 411633782,
|
||||||
|
"longitude": -746784970
|
||||||
|
},
|
||||||
|
"name": "211-225 Plains Road, Augusta, NJ 07822, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 415830701,
|
||||||
|
"longitude": -742952812
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 413447164,
|
||||||
|
"longitude": -748712898
|
||||||
|
},
|
||||||
|
"name": "165 Pedersen Ridge Road, Milford, PA 18337, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 405047245,
|
||||||
|
"longitude": -749800722
|
||||||
|
},
|
||||||
|
"name": "100-122 Locktown Road, Frenchtown, NJ 08825, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 418858923,
|
||||||
|
"longitude": -746156790
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 417951888,
|
||||||
|
"longitude": -748484944
|
||||||
|
},
|
||||||
|
"name": "650-652 Willi Hill Road, Swan Lake, NY 12783, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 407033786,
|
||||||
|
"longitude": -743977337
|
||||||
|
},
|
||||||
|
"name": "26 East 3rd Street, New Providence, NJ 07974, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 417548014,
|
||||||
|
"longitude": -740075041
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 410395868,
|
||||||
|
"longitude": -744972325
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 404615353,
|
||||||
|
"longitude": -745129803
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 406589790,
|
||||||
|
"longitude": -743560121
|
||||||
|
},
|
||||||
|
"name": "611 Lawrence Avenue, Westfield, NJ 07090, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 414653148,
|
||||||
|
"longitude": -740477477
|
||||||
|
},
|
||||||
|
"name": "18 Lannis Avenue, New Windsor, NY 12553, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 405957808,
|
||||||
|
"longitude": -743255336
|
||||||
|
},
|
||||||
|
"name": "82-104 Amherst Avenue, Colonia, NJ 07067, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 411733589,
|
||||||
|
"longitude": -741648093
|
||||||
|
},
|
||||||
|
"name": "170 Seven Lakes Drive, Sloatsburg, NY 10974, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 412676291,
|
||||||
|
"longitude": -742606606
|
||||||
|
},
|
||||||
|
"name": "1270 Lakes Road, Monroe, NY 10950, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 409224445,
|
||||||
|
"longitude": -748286738
|
||||||
|
},
|
||||||
|
"name": "509-535 Alphano Road, Great Meadows, NJ 07838, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 406523420,
|
||||||
|
"longitude": -742135517
|
||||||
|
},
|
||||||
|
"name": "652 Garden Street, Elizabeth, NJ 07202, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 401827388,
|
||||||
|
"longitude": -740294537
|
||||||
|
},
|
||||||
|
"name": "349 Sea Spray Court, Neptune City, NJ 07753, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 410564152,
|
||||||
|
"longitude": -743685054
|
||||||
|
},
|
||||||
|
"name": "13-17 Stanley Street, West Milford, NJ 07480, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 408472324,
|
||||||
|
"longitude": -740726046
|
||||||
|
},
|
||||||
|
"name": "47 Industrial Avenue, Teterboro, NJ 07608, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 412452168,
|
||||||
|
"longitude": -740214052
|
||||||
|
},
|
||||||
|
"name": "5 White Oak Lane, Stony Point, NY 10980, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 409146138,
|
||||||
|
"longitude": -746188906
|
||||||
|
},
|
||||||
|
"name": "Berkshire Valley Management Area Trail, Jefferson, NJ, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 404701380,
|
||||||
|
"longitude": -744781745
|
||||||
|
},
|
||||||
|
"name": "1007 Jersey Avenue, New Brunswick, NJ 08901, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 409642566,
|
||||||
|
"longitude": -746017679
|
||||||
|
},
|
||||||
|
"name": "6 East Emerald Isle Drive, Lake Hopatcong, NJ 07849, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 408031728,
|
||||||
|
"longitude": -748645385
|
||||||
|
},
|
||||||
|
"name": "1358-1474 New Jersey 57, Port Murray, NJ 07865, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 413700272,
|
||||||
|
"longitude": -742135189
|
||||||
|
},
|
||||||
|
"name": "367 Prospect Road, Chester, NY 10918, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 404310607,
|
||||||
|
"longitude": -740282632
|
||||||
|
},
|
||||||
|
"name": "10 Simon Lake Drive, Atlantic Highlands, NJ 07716, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 409319800,
|
||||||
|
"longitude": -746201391
|
||||||
|
},
|
||||||
|
"name": "11 Ward Street, Mount Arlington, NJ 07856, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 406685311,
|
||||||
|
"longitude": -742108603
|
||||||
|
},
|
||||||
|
"name": "300-398 Jefferson Avenue, Elizabeth, NJ 07201, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 419018117,
|
||||||
|
"longitude": -749142781
|
||||||
|
},
|
||||||
|
"name": "43 Dreher Road, Roscoe, NY 12776, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 412856162,
|
||||||
|
"longitude": -745148837
|
||||||
|
},
|
||||||
|
"name": "Swan Street, Pine Island, NY 10969, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 416560744,
|
||||||
|
"longitude": -746721964
|
||||||
|
},
|
||||||
|
"name": "66 Pleasantview Avenue, Monticello, NY 12701, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 405314270,
|
||||||
|
"longitude": -749836354
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 414219548,
|
||||||
|
"longitude": -743327440
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 415534177,
|
||||||
|
"longitude": -742900616
|
||||||
|
},
|
||||||
|
"name": "565 Winding Hills Road, Montgomery, NY 12549, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 406898530,
|
||||||
|
"longitude": -749127080
|
||||||
|
},
|
||||||
|
"name": "231 Rocky Run Road, Glen Gardner, NJ 08826, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 407586880,
|
||||||
|
"longitude": -741670168
|
||||||
|
},
|
||||||
|
"name": "100 Mount Pleasant Avenue, Newark, NJ 07104, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 400106455,
|
||||||
|
"longitude": -742870190
|
||||||
|
},
|
||||||
|
"name": "517-521 Huntington Drive, Manchester Township, NJ 08759, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 400066188,
|
||||||
|
"longitude": -746793294
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 418803880,
|
||||||
|
"longitude": -744102673
|
||||||
|
},
|
||||||
|
"name": "40 Mountain Road, Napanoch, NY 12458, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 414204288,
|
||||||
|
"longitude": -747895140
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 414777405,
|
||||||
|
"longitude": -740615601
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 415464475,
|
||||||
|
"longitude": -747175374
|
||||||
|
},
|
||||||
|
"name": "48 North Road, Forestburgh, NY 12777, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 404062378,
|
||||||
|
"longitude": -746376177
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 405688272,
|
||||||
|
"longitude": -749285130
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 400342070,
|
||||||
|
"longitude": -748788996
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 401809022,
|
||||||
|
"longitude": -744157964
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 404226644,
|
||||||
|
"longitude": -740517141
|
||||||
|
},
|
||||||
|
"name": "9 Thompson Avenue, Leonardo, NJ 07737, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 410322033,
|
||||||
|
"longitude": -747871659
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 407100674,
|
||||||
|
"longitude": -747742727
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 418811433,
|
||||||
|
"longitude": -741718005
|
||||||
|
},
|
||||||
|
"name": "213 Bush Road, Stone Ridge, NY 12484, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 415034302,
|
||||||
|
"longitude": -743850945
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 411349992,
|
||||||
|
"longitude": -743694161
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 404839914,
|
||||||
|
"longitude": -744759616
|
||||||
|
},
|
||||||
|
"name": "1-17 Bergen Court, New Brunswick, NJ 08901, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 414638017,
|
||||||
|
"longitude": -745957854
|
||||||
|
},
|
||||||
|
"name": "35 Oakland Valley Road, Cuddebackville, NY 12729, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 412127800,
|
||||||
|
"longitude": -740173578
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 401263460,
|
||||||
|
"longitude": -747964303
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 412843391,
|
||||||
|
"longitude": -749086026
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 418512773,
|
||||||
|
"longitude": -743067823
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 404318328,
|
||||||
|
"longitude": -740835638
|
||||||
|
},
|
||||||
|
"name": "42-102 Main Street, Belford, NJ 07718, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 419020746,
|
||||||
|
"longitude": -741172328
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 404080723,
|
||||||
|
"longitude": -746119569
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 401012643,
|
||||||
|
"longitude": -744035134
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 404306372,
|
||||||
|
"longitude": -741079661
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 403966326,
|
||||||
|
"longitude": -748519297
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 405002031,
|
||||||
|
"longitude": -748407866
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 409532885,
|
||||||
|
"longitude": -742200683
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 416851321,
|
||||||
|
"longitude": -742674555
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 406411633,
|
||||||
|
"longitude": -741722051
|
||||||
|
},
|
||||||
|
"name": "3387 Richmond Terrace, Staten Island, NY 10303, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 413069058,
|
||||||
|
"longitude": -744597778
|
||||||
|
},
|
||||||
|
"name": "261 Van Sickle Road, Goshen, NY 10924, USA"
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 418465462,
|
||||||
|
"longitude": -746859398
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 411733222,
|
||||||
|
"longitude": -744228360
|
||||||
|
},
|
||||||
|
"name": ""
|
||||||
|
}, {
|
||||||
|
"location": {
|
||||||
|
"latitude": 410248224,
|
||||||
|
"longitude": -747127767
|
||||||
|
},
|
||||||
|
"name": "3 Hasta Way, Newton, NJ 07860, USA"
|
||||||
|
}]
|
||||||
Loading…
Reference in New Issue