Question
recipes.proto // Users can post their own recipes that contain ingredients, their name and the recipe's name. Users can get a list of recipes and
recipes.proto
// Users can post their own recipes that contain ingredients, their name and the recipe's name. Users can get a list of recipes and a rating system (1-5) incorporated into the service. The system will return the mean value of a recipe when the recipe is shown. EchoClient.java I ran out of characters for these two. If you cannot do this part without it, sorry Node.java
import io.grpc.Server; import io.grpc.ServerBuilder; import io.grpc.ServerMethodDefinition; import java.io.IOException; import java.util.concurrent.TimeUnit;
import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList;
public class Node { static private Server server; int port;
ServerSocket serv = null; InputStream in = null; OutputStream out = null; Socket clientSocket = null;
net.Network network = null;
Node(int port) { this.port = port; this.network = new net.proto.Network(); }
private void start() throws IOException { ArrayList
for (var service : server.getServices()) { for (ServerMethodDefinition, ?> method : service.getMethods()) { services.add(method.getMethodDescriptor().getFullMethodName()); System.out.println(method.getMethodDescriptor().getFullMethodName()); } }
System.out.println("Server running ..."); Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { System.err.println("*** shutting down gRPC server since JVM is shutting down"); try { Node.this.stop(); } catch (InterruptedException e) { e.printStackTrace(System.err); } System.err.println("*** server shut down"); } }); }
private void stop() throws InterruptedException { if (server != null) { server.shutdown().awaitTermination(30, TimeUnit.SECONDS); } } private void blockUntilShutdown() throws InterruptedException { if (server != null) { server.awaitTermination(); } }
public static void main(String[] args) throws IOException, InterruptedException { if (args.length != 6) { System.out.println("Expected arguments:
System.out.println(args[4]);
// Comment the next 2 lines for your local client server development (Activity 2 task 1, you need this part again for Task 2) if (args[5].equals("true")) {
Register regThread = new Register(args[0], regPort, args[2], nodePort, args[4]); regThread.start(); } server.start();
server.blockUntilShutdown(); }
}
build.gradle
plugins { id 'java' id "com.google.protobuf" version "0.8.18" apply true } description = "Protocol Buffers Socket Example" repositories { mavenCentral() } repositories { flatDir { dirs 'lib' } }
// json and protobuf dependencies dependencies { implementation("io.grpc:grpc-stub:1.40.1") implementation (name:'Registry', ext:'jar') implementation group: 'org.json', name: 'json', version: '20200518' implementation 'io.grpc:grpc-netty-shaded:1.33.1' implementation 'io.grpc:grpc-protobuf:1.33.1' implementation 'io.grpc:grpc-stub:1.33.1' compileOnly 'org.apache.tomcat:annotations-api:6.0.53' // necessary for Java 9+ implementation group: 'com.google.protobuf', name: 'protobuf-java', version: '3.18.0' }
protobuf { protoc { artifact = 'com.google.protobuf:protoc:3.21.1' } plugins { grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.49.1' } } generateProtoTasks { all()*.plugins { grpc {} } } }
sourceSets { main { java { srcDirs 'build/generated/source/proto/main/grpc' srcDirs 'build/generated/source/proto/main/java' } } } def registryHost = "localhost" // for reaching the classes registry node use "ser321test.duckdns.org" def protobufPort = 9000 // port where the protobuf registry runs on -- for reaching the classes registry node use 8080 def jsonPort = 9001 // port where the json registry runs on def grpcPort = 9002 // port where the json registry runs on
def servicePort = 8000; // port for the service node def serviceHost = 'localhost'; // host for the service node def nodeName = "test" // Name of node to be registered def discoveryPort = 10000 // port where the node runs a registry thread for the registry to call getSerices def message = "Hello you"
def regOn = false task arguments { if (project.hasProperty("nodeName")) { nodeName = project.getProperty("nodeName") } if (project.hasProperty("jsonPort")) { jsonPort = project.getProperty("jsonPort") } if (project.hasProperty("registryHost")) { registryHost = project.getProperty("registryHost") } if (project.hasProperty("grpcPort")) { grpcPort = project.getProperty("grpcPort") } if (project.hasProperty("protobufPort")) { protobufPort = project.getProperty("protobufPort") } if (project.hasProperty("servicePort")) { servicePort = project.getProperty("servicePort") } if (project.hasProperty("discoveryPort")) { discoveryPort = project.getProperty("discoveryPort") } if (project.hasProperty("message")) { messase = project.getProperty("message") } if (project.hasProperty("serviceHost")) { serviceHost = project.getProperty("serviceHost") } if (project.hasProperty("regOn")) { regOn = project.getProperty("regOn") } } task runRegistryServer(type: JavaExec) { group "registry" classpath = sourceSets.main.runtimeClasspath description = "Run Server" main = 'registry.Server' // default args protobufPort args jsonPort args grpcPort } task runDiscovery(type: JavaExec) { group "registry" classpath = sourceSets.main.runtimeClasspath description = "Run ProtoBuf Discovery" main = 'test.DiscoveryServers' } task testJsonRegistration(type: JavaExec) { group "registry" classpath = sourceSets.main.runtimeClasspath description = "Run JSON Discovery" main = 'test.TestJson' } task testProtobufRegistration(type: JavaExec) { group "registry" classpath = sourceSets.main.runtimeClasspath description = "Run Protobuf Discovery" main = 'test.TestProtobuf' } task runClient(type: JavaExec) { dependsOn arguments classpath = sourceSets.main.runtimeClasspath description = "Run Client" main = 'example.grpcclient.EchoClient' standardInput = System.in // default args args serviceHost args servicePort args registryHost args grpcPort args message args regOn }
task runNode(type: JavaExec) { dependsOn arguments classpath = sourceSets.main.runtimeClasspath description = "Run Server" main = 'example.grpcclient.Node' // default args args registryHost args grpcPort args serviceHost args servicePort args nodeName args regOn }
For this activity we will use sample code provided on Canvas, please watch the given video. The code shows you a server (Node.java) that provides 2 services already: echo and returning jokes (and adding a new joke). The EchoClient calls gRPC services from this server. The server will automatically register with the Registry Server (see video and upcoming tasks), the EchoClient will also call the Registry Server and ask for services. Before getting started: I would advise you to run the Registry, Node and Client on your system locally, so you see how it actually works together before starting to make changes. For Task 1 I would advise you to comment out the Registry parts in the server and client so you can develop a simple client server application first. The registration comes later! Your task will be to enhance this server with more services and also adjust the client so that the user can choose which services to use. You can change the code in any way you want or start from scratch if you prefer. You can leave the joke and echo service in there or remove them. That is up to you. You do need to use the Protobuf files and the given protocol/services so we have compatibility between the clients and servers. Task 1: Starting your services locally (60 points) First analyze, understand and run the given code (see the provided video). You should see that there are already some simple services included to show you how to integrate different services into a server node with gRPC. In the given code you will also see some more .proto files with defined services. Please read through the headers of these to understand what they are supposed to do. You are not allowed to change the .proto files! Your server/client need to implement these services as is. Your task is now to create a client server application where the server implements at least 2 of the services not yet included. Constraints 1. ( 3 points) Must have: We need to be able to run the service node through 'gradle runNode" which should use default arguments, and the client through 'gradle runClient.Java" using the correct default values to connect to the started service node!!!! If this does not work we will not run things. 2. (20 points each service) Implement 2 from the 4 services that are given in the .proto files, choose from these 4 protos: recipe, weather, password, hometownsRead through the Protobuf files for more details on how the services are supposed to work. 3. (8 points) Your client should let the user decide what they want to do with some nice terminal input easy to understand, e.g. first showing all the available services, then asking the user which service they want to use, then asking for the input the service needs. Good overall client that does not crash. 4. (4 points) Give the option that we can run 'gradle runClient -Phost=host -Pport=port -Pauto =1 " which will run all requests on its own with input data you hardcode and give good output results and also of course shows what was called. This will call the server directly without using any registry. So basically shows your test cases running successfully. See video about Task 1 for more details. 5. (5 points) Server and Client should be robust and not crash. Task 2: Inventing your own service ( 30 points) Now it is time to create your own proto file and come up with a new service. For this you can work together with 1-3 of your peers to design the new proto file and service. You are only allowed to design the proto file with its service together not the implementation in your client/server. But if you design a protocol together then you can use each others service, which might be fun. The service should be something small and fun (or big and fun) that fulfills at least 3 out of the following requirements: - Service allows at least 2 different requests - Each request needs at least 1 input - Response returns different data for different requests - Response returns a repeated field - Data is held persistent on the server Do not just do an add/sub but come up with something yourself. You can pitch ideas on Slack as well if you like. Then of course implement your service into your client and server as another option. 10 points protocol design, 10 points client, 10 points server (all this robust, working and well described in your Readme and shown in your screencast). Task 3: Building a network together (10) Now we want to create a network of nodes and register them so others can access your services. Task 3.1: Register things locally The given code gives you a Registry where servers can register. You can run this through "gradle runRegistry" (which will run it on localhost). See the video for some more details on the Registry. In the end it provides 3 ports for 3 different protocols that it can handle, we will only use the grpe port!!! Do the following: 1. MUST: Create a new version of your Node.java ==> NodeService.java and your EchoClient.java ==> Client.java. You should be able to call them through 'gradle registerServiceNode' and "gradle runClient2" asking for the same parameters as the calls that were already in the given Gradle file for the original files. This call will use the Registry again, so is not the same as runClient from the previous task. These should use default values so that they connect correctly! 2. The things you commented in Node.java (The registry parts in the server and client that are mentioned in the Background before Task1) should now be put back into the code in your NodeService.java code. This should allow your Node to be registered with its service with the Registry. 3. Test this: Run your Registry, run your node (you need to provide the correct host and port of course) - you should set this as default values for us. You should see a println on the Registry side that the service is registered. If you do not, try to figure out what happened (or did not happen). 4. Now, you should run your Client (also with the parts included which you need to uncomment now) and see if it will find the registered services correctly. 5. (8 points) If all this works, adapt your client so it does not just call the service on the node you provide directly as was done in Task 1 but that the client can choose between all services registered on the Registry (in this case locally it will still just be your services. For testing purposes you can run a couple server nodes and register all of them to your local registry. You do not hard code which server to talk to anymore but use the following workflow: a) Client contacts Registry to check for available services b) List all registered services in the terminal and the client can choose one (preferably through numbering) c) (You should basically have this already) Based on what the client chooses the terminal should ask for input d) The request should be sent to one of the available service nodes with the following workflow: 1) client should call the registry again and ask for a Server providing the chosen service 2) the returned server should then be used, 3) should send the request to the server that was returned, 4) return the response in a good way to the client e) Make sure that your Client does not crash in case the Server did not respond or crashed. Make it as robust as possibleStep by Step Solution
There are 3 Steps involved in it
Step: 1
Get Instant Access to Expert-Tailored Solutions
See step-by-step solutions with expert insights and AI powered tools for academic success
Step: 2
Step: 3
Ace Your Homework with AI
Get the answers you need in no time with our AI-driven, step-by-step assistance
Get Started