Skip to content

Commit 16ca9af

Browse files
authored
Codelabs for Java Intro and Java Intro Streaming (#5)
1 parent 40e0e04 commit 16ca9af

File tree

31 files changed

+5019
-0
lines changed

31 files changed

+5019
-0
lines changed
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
@@ -0,0 +1,24 @@
2+
# Getting Started with gRPC-Java
3+
4+
Get hands-on with gRPC for Java in this interactive codelab! <!-- TODO(larry-safran): Insert link once codelab is published. -->
5+
6+
Perfect for Java developers new to gRPC, those seeking a refresher, or anyone building distributed systems. No prior gRPC experience needed!
7+
8+
#### Build a complete gRPC service from scratch, learning:
9+
- Protocol Buffers (protobuf): Define service contracts & data.
10+
- gRPC Code Generation: Auto-generate Java code.
11+
- Client/Server Communication: Implement seamless interactions.
12+
13+
#### You'll gain:
14+
- A working gRPC service in Java.
15+
- Hands-on experience with Protocol Buffers and code generation.
16+
- Skills to design, build, & test gRPC clients and servers.
17+
- A strong foundation in gRPC for real-world projects.
18+
19+
## How to use this directory
20+
21+
- [start_here](start_here/) directory serves as a starting point for the
22+
codelab.
23+
- [complete](complete/) directory showcases the finished code, giving you a peak
24+
of how the final implementation should look like.
25+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Copyright 2024 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc.examples.routeguide;
18+
19+
import com.google.common.annotations.VisibleForTesting;
20+
import com.google.protobuf.Message;
21+
import io.grpc.Channel;
22+
import io.grpc.Grpc;
23+
import io.grpc.InsecureChannelCredentials;
24+
import io.grpc.ManagedChannel;
25+
import io.grpc.Status;
26+
import io.grpc.StatusRuntimeException;
27+
import io.grpc.examples.routeguide.RouteGuideGrpc.RouteGuideBlockingStub;
28+
import io.grpc.examples.routeguide.RouteGuideGrpc.RouteGuideStub;
29+
import io.grpc.stub.StreamObserver;
30+
import java.io.IOException;
31+
import java.util.Iterator;
32+
import java.util.List;
33+
import java.util.Random;
34+
import java.util.concurrent.CountDownLatch;
35+
import java.util.concurrent.TimeUnit;
36+
import java.util.logging.Level;
37+
import java.util.logging.Logger;
38+
39+
/**
40+
* Sample client code that makes gRPC calls to the server.
41+
*/
42+
public class RouteGuideClient {
43+
private static final Logger logger = Logger.getLogger(RouteGuideClient.class.getName());
44+
45+
private final RouteGuideBlockingStub blockingStub;
46+
47+
private Random random = new Random();
48+
private TestHelper testHelper;
49+
50+
/** Construct client for accessing RouteGuide server using the existing channel. */
51+
public RouteGuideClient(Channel channel) {
52+
blockingStub = RouteGuideGrpc.newBlockingStub(channel);
53+
}
54+
55+
/**
56+
* Blocking unary call example. Calls getFeature and prints the response.
57+
*/
58+
public void getFeature(int lat, int lon) {
59+
info("*** GetFeature: lat={0} lon={1}", lat, lon);
60+
61+
Point request = Point.newBuilder().setLatitude(lat).setLongitude(lon).build();
62+
63+
Feature feature;
64+
try {
65+
feature = blockingStub.getFeature(request);
66+
if (testHelper != null) {
67+
testHelper.onMessage(feature);
68+
}
69+
} catch (StatusRuntimeException e) {
70+
warning("RPC failed: {0}", e.getStatus());
71+
if (testHelper != null) {
72+
testHelper.onRpcError(e);
73+
}
74+
return;
75+
}
76+
if (RouteGuideUtil.exists(feature)) {
77+
info("Found feature called \"{0}\" at {1}, {2}",
78+
feature.getName(),
79+
RouteGuideUtil.getLatitude(feature.getLocation()),
80+
RouteGuideUtil.getLongitude(feature.getLocation()));
81+
} else {
82+
info("Found no feature at {0}, {1}",
83+
RouteGuideUtil.getLatitude(feature.getLocation()),
84+
RouteGuideUtil.getLongitude(feature.getLocation()));
85+
}
86+
}
87+
88+
/** Issues several different requests and then exits. */
89+
public static void main(String[] args) throws InterruptedException {
90+
String target = "localhost:8980";
91+
if (args.length > 0) {
92+
if ("--help".equals(args[0])) {
93+
System.err.println("Usage: [target]");
94+
System.err.println("");
95+
System.err.println(" target The server to connect to. Defaults to " + target);
96+
System.exit(1);
97+
}
98+
target = args[0];
99+
}
100+
101+
List<Feature> features;
102+
try {
103+
features = RouteGuideUtil.parseFeatures(RouteGuideUtil.getDefaultFeaturesFile());
104+
} catch (IOException ex) {
105+
ex.printStackTrace();
106+
return;
107+
}
108+
109+
ManagedChannel channel = Grpc.newChannelBuilder(target, InsecureChannelCredentials.create())
110+
.build();
111+
try {
112+
RouteGuideClient client = new RouteGuideClient(channel);
113+
// Looking for a valid feature
114+
client.getFeature(409146138, -746188906);
115+
116+
// Feature missing.
117+
client.getFeature(0, 0);
118+
} finally {
119+
channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
120+
}
121+
}
122+
123+
private void info(String msg, Object... params) {
124+
logger.log(Level.INFO, msg, params);
125+
}
126+
127+
private void warning(String msg, Object... params) {
128+
logger.log(Level.WARNING, msg, params);
129+
}
130+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/*
2+
* Copyright 2024 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc.examples.routeguide;
18+
19+
import static java.lang.Math.atan2;
20+
import static java.lang.Math.cos;
21+
import static java.lang.Math.max;
22+
import static java.lang.Math.min;
23+
import static java.lang.Math.sin;
24+
import static java.lang.Math.sqrt;
25+
import static java.lang.Math.toRadians;
26+
import static java.util.concurrent.TimeUnit.NANOSECONDS;
27+
28+
import io.grpc.Grpc;
29+
import io.grpc.InsecureServerCredentials;
30+
import io.grpc.Server;
31+
import io.grpc.ServerBuilder;
32+
import io.grpc.stub.StreamObserver;
33+
import java.io.IOException;
34+
import java.net.URL;
35+
import java.util.ArrayList;
36+
import java.util.Collection;
37+
import java.util.Collections;
38+
import java.util.List;
39+
import java.util.concurrent.ConcurrentHashMap;
40+
import java.util.concurrent.ConcurrentMap;
41+
import java.util.concurrent.TimeUnit;
42+
import java.util.logging.Level;
43+
import java.util.logging.Logger;
44+
45+
/**
46+
* A sample gRPC server that serve the RouteGuide (see route_guide.proto) service.
47+
*/
48+
public class RouteGuideServer {
49+
private static final Logger logger = Logger.getLogger(RouteGuideServer.class.getName());
50+
51+
private final int port;
52+
private final Server server;
53+
54+
public RouteGuideServer(int port) throws IOException {
55+
this(port, RouteGuideUtil.getDefaultFeaturesFile());
56+
}
57+
58+
/** Create a RouteGuide server listening on {@code port} using {@code featureFile} database. */
59+
public RouteGuideServer(int port, URL featureFile) throws IOException {
60+
this(Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()),
61+
port, RouteGuideUtil.parseFeatures(featureFile));
62+
}
63+
64+
/** Create a RouteGuide server using serverBuilder as a base and features as data. */
65+
public RouteGuideServer(ServerBuilder<?> serverBuilder, int port, Collection<Feature> features) {
66+
this.port = port;
67+
server = serverBuilder.addService(new RouteGuideService(features))
68+
.build();
69+
}
70+
71+
/** Start serving requests. */
72+
public void start() throws IOException {
73+
server.start();
74+
logger.info("Server started, listening on " + port);
75+
Runtime.getRuntime().addShutdownHook(new Thread() {
76+
@Override
77+
public void run() {
78+
// Use stderr here since the logger may have been reset by its JVM shutdown hook.
79+
System.err.println("*** shutting down gRPC server since JVM is shutting down");
80+
try {
81+
RouteGuideServer.this.stop();
82+
} catch (InterruptedException e) {
83+
e.printStackTrace(System.err);
84+
}
85+
System.err.println("*** server shut down");
86+
}
87+
});
88+
}
89+
90+
/** Stop serving requests and shutdown resources. */
91+
public void stop() throws InterruptedException {
92+
if (server != null) {
93+
server.shutdown().awaitTermination(30, TimeUnit.SECONDS);
94+
}
95+
}
96+
97+
/**
98+
* Await termination on the main thread since the grpc library uses daemon threads.
99+
*/
100+
private void blockUntilShutdown() throws InterruptedException {
101+
if (server != null) {
102+
server.awaitTermination();
103+
}
104+
}
105+
106+
/**
107+
* Main method. This comment makes the linter happy.
108+
*/
109+
public static void main(String[] args) throws Exception {
110+
RouteGuideServer server = new RouteGuideServer(8980);
111+
server.start();
112+
server.blockUntilShutdown();
113+
}
114+
115+
/**
116+
* Our implementation of RouteGuide service.
117+
*
118+
* <p>See route_guide.proto for details of the methods.
119+
*/
120+
private static class RouteGuideService extends RouteGuideGrpc.RouteGuideImplBase {
121+
private final Collection<Feature> features;
122+
123+
RouteGuideService(Collection<Feature> features) {
124+
this.features = features;
125+
}
126+
127+
/**
128+
* Gets the {@link Feature} at the requested {@link Point}. If no feature at that location
129+
* exists, an unnamed feature is returned at the provided location.
130+
*
131+
* @param request the requested location for the feature.
132+
* @param responseObserver the observer that will receive the feature at the requested point.
133+
*/
134+
@Override
135+
public void getFeature(Point request, StreamObserver<Feature> responseObserver) {
136+
responseObserver.onNext(checkFeature(request));
137+
responseObserver.onCompleted();
138+
}
139+
140+
/**
141+
* Gets the feature at the given point.
142+
*
143+
* @param location the location to check.
144+
* @return The feature object at the point. Note that an empty name indicates no feature.
145+
*/
146+
private Feature checkFeature(Point location) {
147+
for (Feature feature : features) {
148+
if (feature.getLocation().getLatitude() == location.getLatitude()
149+
&& feature.getLocation().getLongitude() == location.getLongitude()) {
150+
return feature;
151+
}
152+
}
153+
154+
// No feature was found, return an unnamed feature.
155+
return Feature.newBuilder().setName("").setLocation(location).build();
156+
}
157+
}
158+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright 2015 The gRPC Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.grpc.examples.routeguide;
18+
19+
import com.google.protobuf.util.JsonFormat;
20+
import java.io.IOException;
21+
import java.io.InputStream;
22+
import java.io.InputStreamReader;
23+
import java.io.Reader;
24+
import java.net.URL;
25+
import java.nio.charset.Charset;
26+
import java.util.List;
27+
28+
/**
29+
* Common utilities for the RouteGuide demo.
30+
*/
31+
public class RouteGuideUtil {
32+
private static final double COORD_FACTOR = 1e7;
33+
34+
/**
35+
* Gets the latitude for the given point.
36+
*/
37+
public static double getLatitude(Point location) {
38+
return location.getLatitude() / COORD_FACTOR;
39+
}
40+
41+
/**
42+
* Gets the longitude for the given point.
43+
*/
44+
public static double getLongitude(Point location) {
45+
return location.getLongitude() / COORD_FACTOR;
46+
}
47+
48+
/**
49+
* Gets the default features file from classpath.
50+
*/
51+
public static URL getDefaultFeaturesFile() {
52+
return RouteGuideServer.class.getResource("route_guide_db.json");
53+
}
54+
55+
/**
56+
* Parses the JSON input file containing the list of features.
57+
*/
58+
public static List<Feature> parseFeatures(URL file) throws IOException {
59+
InputStream input = file.openStream();
60+
try {
61+
Reader reader = new InputStreamReader(input, Charset.forName("UTF-8"));
62+
try {
63+
FeatureDatabase.Builder database = FeatureDatabase.newBuilder();
64+
JsonFormat.parser().merge(reader, database);
65+
return database.getFeatureList();
66+
} finally {
67+
reader.close();
68+
}
69+
} finally {
70+
input.close();
71+
}
72+
}
73+
74+
/**
75+
* Indicates whether the given feature exists (i.e. has a valid name).
76+
*/
77+
public static boolean exists(Feature feature) {
78+
return feature != null && !feature.getName().isEmpty();
79+
}
80+
}

0 commit comments

Comments
 (0)