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 {
|
||||
libraries = [
|
||||
protobuf: 'com.google.protobuf:protobuf-java:3.0.0-pre',
|
||||
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
|
||||
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.
|
||||
// These must already be installed in the local maven repository.
|
||||
|
|
|
|||
|
|
@ -1,22 +1,19 @@
|
|||
grpc Examples
|
||||
==============================================
|
||||
|
||||
In order to run the examples simply execute one of the gradle tasks `mathserver`, `mathclient`,
|
||||
`stockserver` or `stockclient`.
|
||||
In order to run the examples simply execute one of the gradle tasks `routeGuideServer` or
|
||||
`routeGuideClient`.
|
||||
|
||||
For example, say you want to play around with the math examples. First you want to start
|
||||
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
|
||||
Assuming you are in the grpc-java root folder you would first start the server by running
|
||||
|
||||
```
|
||||
$ ./gradlew :grpc-examples:mathserver
|
||||
$ ./gradlew :grpc-examples:routeGuideServer
|
||||
```
|
||||
|
||||
and in a different terminal window then run the client by typing
|
||||
|
||||
```
|
||||
$ ./gradlew :grpc-examples:mathclient
|
||||
$ ./gradlew :grpc-examples:routeGuideClient
|
||||
```
|
||||
|
||||
That's it!
|
||||
|
|
|
|||
|
|
@ -16,32 +16,21 @@ dependencies {
|
|||
compile project(':grpc-core'),
|
||||
project(':grpc-netty'),
|
||||
project(':grpc-okhttp'),
|
||||
project(':grpc-stub')
|
||||
project(':grpc-stub'),
|
||||
libraries.jsonp
|
||||
}
|
||||
|
||||
protobufCodeGenPlugins = ["java_plugin:$rootDir/compiler/build/binaries/java_pluginExecutable/java_plugin"]
|
||||
generateProto.dependsOn ':grpc-compiler:java_pluginExecutable'
|
||||
|
||||
task mathserver(type: JavaExec) {
|
||||
main = "io.grpc.examples.MathServer"
|
||||
description = "Executes the math server."
|
||||
task routeGuideServer(type: JavaExec) {
|
||||
main = "io.grpc.examples.RouteGuideServer"
|
||||
description = "Executes the route guide server."
|
||||
classpath = sourceSets.main.runtimeClasspath
|
||||
}
|
||||
|
||||
task mathclient(type: JavaExec) {
|
||||
main = "io.grpc.examples.MathClient"
|
||||
description = "Executes the math 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."
|
||||
task routeGuideClient(type: JavaExec) {
|
||||
main = "io.grpc.examples.RouteGuideClient"
|
||||
description = "Executes the route guide client."
|
||||
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