diff --git a/endpoints/getting-started-grpc/.gitignore b/endpoints/getting-started-grpc/.gitignore new file mode 100644 index 00000000000..27d742d3e37 --- /dev/null +++ b/endpoints/getting-started-grpc/.gitignore @@ -0,0 +1,5 @@ +.gradle/ +api/build/ +client/build/ +out.pb +server/build/ diff --git a/endpoints/getting-started-grpc/Dockerfile b/endpoints/getting-started-grpc/Dockerfile new file mode 100644 index 00000000000..3ed2caea49a --- /dev/null +++ b/endpoints/getting-started-grpc/Dockerfile @@ -0,0 +1,24 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# https://github.com/GoogleCloudPlatform/openjdk-runtime +FROM gcr.io/google_appengine/openjdk8 + +RUN apt-get update \ + && apt-get -y -q upgrade \ + && rm -rf /var/lib/apt/lists/* + +ADD ./server/build/libs/server.jar /hello/server.jar + +ENTRYPOINT ["java", "-jar", "/hello/server.jar"] diff --git a/endpoints/getting-started-grpc/README.md b/endpoints/getting-started-grpc/README.md new file mode 100644 index 00000000000..97cd055de01 --- /dev/null +++ b/endpoints/getting-started-grpc/README.md @@ -0,0 +1,135 @@ +# Endpoints Getting Started with gRPC & Java Quickstart + +It is assumed that you have a +working +[gRPC](http://www.grpc.io/docs/), +[ProtoBuf](https://github.com/google/protobuf#protocol-compiler-installation) and +Java environment, a Google Cloud account +and [SDK](https://cloud.google.com/sdk/) configured. + +1. Build the code: + + ```bash + ./gradlew build + ``` + +1. Test running the code, optional: + + ```bash + # In the background or another terminal run the server: + java -jar server/build/libs/server.jar + + # Check the client parameters: + java -jar client/build/libs/client.jar --help + + # Run the client + java -jar client/build/libs/client.jar --greetee 'Endpoints!' + ``` + +1. Generate the `out.pb` from the proto file. + + ```bash + protoc --include_imports --include_source_info api/src/main/proto/helloworld.proto --descriptor_set_out out.pb + ``` + +1. Edit, `api_config.yaml`. Replace `MY_PROJECT_ID` with your project id. + +1. Deploy your service config to Service Management: + + ```bash + gcloud service-management deploy out.pb api_config.yaml + # The Config ID should be printed out, looks like: 2017-02-01r0, remember this + + # set your project to make commands easier + GCLOUD_PROJECT= + + # Print out your Config ID again, in case you missed it + gcloud service-management configs list --service hellogrpc.endpoints.${GCLOUD_PROJECT}.cloud.goog + ``` + +1. Also get an API key from the Console's API Manager for use in the client later. (https://console.cloud.google.com/apis/credentials) + +1. Build a docker image for your gRPC server, store in your Registry + + ```bash + gcloud container builds submit --tag gcr.io/${GCLOUD_PROJECT}/java-grpc-hello:1.0 . + ``` + +1. Either deploy to GCE (below) or GKE (further down) + +### GCE + +1. Create your instance and ssh in. + + ```bash + gcloud compute instances create grpc-host --image-family gci-stable --image-project google-containers --tags=http-server + gcloud compute ssh grpc-host + ``` + +1. Set some variables to make commands easier + + ```bash + GCLOUD_PROJECT=$(curl -s "http://metadata.google.internal/computeMetadata/v1/project/project-id" -H "Metadata-Flavor: Google") + SERVICE_NAME=hellogrpc.endpoints.${GCLOUD_PROJECT}.cloud.goog + SERVICE_CONFIG_ID= + ``` + +1. Pull your credentials to access Container Registry, and run your gRPC server container + + ```bash + /usr/share/google/dockercfg_update.sh + docker run -d --name=grpc-hello gcr.io/${GCLOUD_PROJECT}/java-grpc-hello:1.0 + ``` + +1. Run the Endpoints proxy + + ```bash + docker run --detach --name=esp \ + -p 80:9000 \ + --link=grpc-hello:grpc-hello \ + gcr.io/endpoints-release/endpoints-runtime:1 \ + -s ${SERVICE_NAME} \ + -v ${SERVICE_CONFIG_ID} \ + -P 9000 \ + -a grpc://grpc-hello:50051 + ``` + +1. Back on your local machine, get the external IP of your GCE instance. + + ```bash + gcloud compute instances list + ``` + +1. Run the client + + ```bash + java -jar client/build/libs/client.jar --host :80 --api_key + ``` + +### GKE + +1. Create a cluster + + ```bash + gcloud container clusters create my-cluster + ``` + +1. Edit `container-engine.yaml`. Replace `SERVICE_NAME`, `SERVICE_CONFIG_ID`, and `GCLOUD_PROJECT` with your values. + +1. Deploy to GKE + + ```bash + kubectl create -f ./container-engine.yaml + ``` + +1. Get IP of load balancer, run until you see an External IP. + + ```bash + kubectl get svc grpc-hello + ``` + +1. Run the client + + ```bash + java -jar client/build/libs/client.jar --host :80 --api_key + ``` diff --git a/endpoints/getting-started-grpc/api/build.gradle b/endpoints/getting-started-grpc/api/build.gradle new file mode 100644 index 00000000000..7cc6a424e2a --- /dev/null +++ b/endpoints/getting-started-grpc/api/build.gradle @@ -0,0 +1,56 @@ +// Copyright 2017 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +apply plugin: 'java' +apply plugin: 'com.google.protobuf' + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0' + + } +} + +def grpcVersion = '1.0.3' + +dependencies { + repositories { + mavenCentral() + } + compile "io.grpc:grpc-netty:${grpcVersion}" + compile "io.grpc:grpc-protobuf:${grpcVersion}" + compile "io.grpc:grpc-stub:${grpcVersion}" +} + +protobuf { + protoc { + artifact = 'com.google.protobuf:protoc:3.0.2' + } + + plugins { + grpc { + artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}" + } + } + generateProtoTasks { + all()*.plugins { + grpc {} + } + } +} diff --git a/endpoints/getting-started-grpc/api/src/main/proto/helloworld.proto b/endpoints/getting-started-grpc/api/src/main/proto/helloworld.proto new file mode 100644 index 00000000000..8f358ce6e26 --- /dev/null +++ b/endpoints/getting-started-grpc/api/src/main/proto/helloworld.proto @@ -0,0 +1,51 @@ +// Copyright 2015, Google Inc. +// +// 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_multiple_files = true; +option java_package = "com.google.endpoints.examples.hello"; +option java_outer_classname = "HelloWorldProto"; + +package helloworld; + +// The greeting service definition. +service Greeter { + // Sends a greeting + rpc SayHello (HelloRequest) returns (HelloReply) {} +} + +// The request message containing the user's name. +message HelloRequest { + string name = 1; +} + +// The response message containing the greetings +message HelloReply { + string message = 1; +} diff --git a/endpoints/getting-started-grpc/api_config.yaml b/endpoints/getting-started-grpc/api_config.yaml new file mode 100644 index 00000000000..7d4fcf763e4 --- /dev/null +++ b/endpoints/getting-started-grpc/api_config.yaml @@ -0,0 +1,36 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# +# An example API configuration. +# +# Below, replace MY_PROJECT_ID with your Google Cloud Project ID. +# + +# The configuration schema is defined by service.proto file +# https://github.com/googleapis/googleapis/blob/master/google/api/service.proto +type: google.api.Service +config_version: 3 + +# +# Name of the service configuration. +# +name: hellogrpc.endpoints.jeffs-test-deploy-1.cloud.goog + +# +# API title to appear in the user interface (Google Cloud Console). +# +title: Hello gRPC API +apis: +- name: helloworld.Greeter diff --git a/endpoints/getting-started-grpc/build.gradle b/endpoints/getting-started-grpc/build.gradle new file mode 100644 index 00000000000..6cf40137b01 --- /dev/null +++ b/endpoints/getting-started-grpc/build.gradle @@ -0,0 +1,23 @@ +// Copyright 2017 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +subprojects { + apply plugin: 'java' + + repositories { + mavenCentral() + } +} diff --git a/endpoints/getting-started-grpc/client/build.gradle b/endpoints/getting-started-grpc/client/build.gradle new file mode 100644 index 00000000000..4794341f399 --- /dev/null +++ b/endpoints/getting-started-grpc/client/build.gradle @@ -0,0 +1,33 @@ +// Copyright 2017 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +apply plugin: 'application' + +mainClassName = "com.google.endpoints.examples.hello.HelloWorldClient" + +jar { + manifest { + attributes "Main-Class": "$mainClassName" + } + from { + configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } + } +} + +dependencies { + compile project(':api') + compile 'commons-cli:commons-cli:1.3' +} diff --git a/endpoints/getting-started-grpc/client/src/main/java/com/google/endpoints/examples/hello/HelloWorldClient.java b/endpoints/getting-started-grpc/client/src/main/java/com/google/endpoints/examples/hello/HelloWorldClient.java new file mode 100644 index 00000000000..8c5f2d22f23 --- /dev/null +++ b/endpoints/getting-started-grpc/client/src/main/java/com/google/endpoints/examples/hello/HelloWorldClient.java @@ -0,0 +1,194 @@ +/* + * Copyright 2015, Google Inc. + * + * 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 com.google.endpoints.examples.hello; + +import io.grpc.CallOptions; +import io.grpc.Channel; +import io.grpc.ClientCall; +import io.grpc.ClientInterceptor; +import io.grpc.ClientInterceptors; +import io.grpc.ForwardingClientCall; +import io.grpc.ManagedChannel; +import io.grpc.ManagedChannelBuilder; +import io.grpc.Metadata; +import io.grpc.MethodDescriptor; +import io.grpc.StatusRuntimeException; + +import java.util.concurrent.TimeUnit; +import java.util.logging.Level; +import java.util.logging.Logger; + +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +/** + * A simple client that requests a greeting from the {@link HelloWorldServer}. + */ +public class HelloWorldClient { + private static final Logger logger = Logger.getLogger(HelloWorldClient.class.getName()); + private static final String DEFAULT_ADDRESS = "localhost:50051"; + + private final ManagedChannel channel; + private final GreeterGrpc.GreeterBlockingStub blockingStub; + + /** Construct client connecting to HelloWorld server at {@code host:port}. */ + public HelloWorldClient(String address, String apiKey) { + channel = ManagedChannelBuilder.forTarget(address) + // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid + // needing certificates. + .usePlaintext(true) + .build(); + Channel ch = ClientInterceptors.intercept(channel, new Interceptor(apiKey)); + + blockingStub = GreeterGrpc.newBlockingStub(ch); + } + + public void shutdown() throws InterruptedException { + channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); + } + + /** Say hello to server. */ + public void greet(String name) { + logger.info("Will try to greet " + name + " ..."); + HelloRequest request = HelloRequest.newBuilder().setName(name).build(); + HelloReply response; + try { + response = blockingStub.sayHello(request); + } catch (StatusRuntimeException e) { + logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); + return; + } + logger.info("Greeting: " + response.getMessage()); + } + + private static final class Interceptor implements ClientInterceptor { + private final String apiKey; + + private static Logger LOGGER = Logger.getLogger("InfoLogging"); + + private static Metadata.Key API_KEY_HEADER = + Metadata.Key.of("x-api-key", Metadata.ASCII_STRING_MARSHALLER); + + public Interceptor(String apiKey) { + this.apiKey = apiKey; + } + + @Override + public ClientCall interceptCall( + MethodDescriptor method, CallOptions callOptions, Channel next) { + LOGGER.info("Intercepted " + method.getFullMethodName()); + ClientCall call = next.newCall(method, callOptions); + + call = new ForwardingClientCall.SimpleForwardingClientCall(call) { + @Override + public void start(Listener responseListener, Metadata headers) { + if (apiKey != null && !apiKey.isEmpty()) { + LOGGER.info("Attaching API Key: " + apiKey); + headers.put(API_KEY_HEADER, apiKey); + } + super.start(responseListener, headers); + } + }; + return call; + } + } + + /** + * Greet server. If provided, the first element of {@code args} is the name to use in the + * greeting. + */ + public static void main(String[] args) throws Exception { + Options options = createOptions(); + CommandLineParser parser = new DefaultParser(); + CommandLine params; + try { + params = parser.parse(options, args); + } catch (ParseException e) { + System.err.println("Invalid command line: " + e.getMessage()); + printUsage(options); + return; + } + + String address = params.getOptionValue("host", DEFAULT_ADDRESS); + String apiKey = params.getOptionValue("api_key"); + String greetee = params.getOptionValue("greetee", "world"); + + HelloWorldClient client = new HelloWorldClient(address, apiKey); + try { + client.greet(greetee); + } finally { + client.shutdown(); + } + } + + private static Options createOptions() { + Options options = new Options(); + + options.addOption(Option.builder() + .longOpt("host") + .desc("The address of the gRPC server") + .hasArg() + .argName("host") + .type(String.class) + .build()); + + options.addOption(Option.builder() + .longOpt("api_key") + .desc("The API key to use for RPC calls") + .hasArg() + .argName("key") + .type(String.class) + .build()); + + options.addOption(Option.builder() + .longOpt("greetee") + .desc("Who or what to greet") + .hasArg() + .argName("greetee") + .type(String.class) + .build()); + + return options; + } + + private static void printUsage(Options options) { + HelpFormatter formatter = new HelpFormatter(); + formatter.printHelp("client", + "A simple gRPC client for use with Endpoints.", options, "", true); + } + +} diff --git a/endpoints/getting-started-grpc/container-engine.yaml b/endpoints/getting-started-grpc/container-engine.yaml new file mode 100644 index 00000000000..ae6563adcf6 --- /dev/null +++ b/endpoints/getting-started-grpc/container-engine.yaml @@ -0,0 +1,54 @@ +# Copyright 2017 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +apiVersion: v1 +kind: Service +metadata: + name: grpc-hello +spec: + ports: + - port: 80 + targetPort: 9000 + protocol: TCP + name: http + selector: + app: grpc-hello + type: LoadBalancer +--- +apiVersion: extensions/v1beta1 +kind: Deployment +metadata: + name: grpc-hello +spec: + replicas: 1 + template: + metadata: + labels: + app: grpc-hello + spec: + containers: + - name: esp + image: gcr.io/endpoints-release/endpoints-runtime:1 + args: [ + "-P", "9000", + "-a", "grpc://127.0.0.1:50051", + "-s", "SERVICE_NAME", + "-v", "SERVICE_CONFIG_ID", + ] + ports: + - containerPort: 9000 + - name: java-grpc-hello + image: gcr.io/GCLOUD_PROJECT/java-grpc-hello:1.0 + ports: + - containerPort: 50051 diff --git a/endpoints/getting-started-grpc/gradle/wrapper/gradle-wrapper.jar b/endpoints/getting-started-grpc/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..5ccda13e9cb Binary files /dev/null and b/endpoints/getting-started-grpc/gradle/wrapper/gradle-wrapper.jar differ diff --git a/endpoints/getting-started-grpc/gradle/wrapper/gradle-wrapper.properties b/endpoints/getting-started-grpc/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..ae20da0b897 --- /dev/null +++ b/endpoints/getting-started-grpc/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Sat May 07 11:11:12 PDT 2016 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.13-bin.zip diff --git a/endpoints/getting-started-grpc/gradlew b/endpoints/getting-started-grpc/gradlew new file mode 100755 index 00000000000..27309d92314 --- /dev/null +++ b/endpoints/getting-started-grpc/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/endpoints/getting-started-grpc/gradlew.bat b/endpoints/getting-started-grpc/gradlew.bat new file mode 100644 index 00000000000..f6d5974e72f --- /dev/null +++ b/endpoints/getting-started-grpc/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/endpoints/getting-started-grpc/server/build.gradle b/endpoints/getting-started-grpc/server/build.gradle new file mode 100644 index 00000000000..c5816792c8d --- /dev/null +++ b/endpoints/getting-started-grpc/server/build.gradle @@ -0,0 +1,32 @@ +// Copyright 2017 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////////// + +apply plugin: 'application' + +mainClassName = "com.google.endpoints.examples.hello.HelloWorldServer" + +jar { + manifest { + attributes "Main-Class": "$mainClassName" + } + from { + configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } + } +} + +dependencies { + compile project(':api') +} diff --git a/endpoints/getting-started-grpc/server/src/main/java/com/google/endpoints/examples/hello/HelloWorldServer.java b/endpoints/getting-started-grpc/server/src/main/java/com/google/endpoints/examples/hello/HelloWorldServer.java new file mode 100644 index 00000000000..c8f5f6fd99f --- /dev/null +++ b/endpoints/getting-started-grpc/server/src/main/java/com/google/endpoints/examples/hello/HelloWorldServer.java @@ -0,0 +1,101 @@ +/* + * Copyright 2015, Google Inc. + * + * 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 com.google.endpoints.examples.hello; + +import io.grpc.Server; +import io.grpc.ServerBuilder; +import io.grpc.stub.StreamObserver; + +import java.io.IOException; +import java.util.logging.Logger; + +/** + * Server that manages startup/shutdown of a {@code Greeter} server. + */ +public class HelloWorldServer { + private static final Logger logger = Logger.getLogger(HelloWorldServer.class.getName()); + + /* The port on which the server should run */ + private int port = 50051; + private Server server; + + private void start() throws IOException { + server = ServerBuilder.forPort(port) + .addService(new GreeterImpl()) + .build() + .start(); + logger.info("Server started, listening on " + port); + Runtime.getRuntime().addShutdownHook(new Thread() { + @Override + public void run() { + // Use stderr here since the logger may have been reset by its JVM shutdown hook. + System.err.println("*** shutting down gRPC server since JVM is shutting down"); + HelloWorldServer.this.stop(); + System.err.println("*** server shut down"); + } + }); + } + + private void stop() { + if (server != null) { + server.shutdown(); + } + } + + /** + * Await termination on the main thread since the grpc library uses daemon threads. + */ + private void blockUntilShutdown() throws InterruptedException { + if (server != null) { + server.awaitTermination(); + } + } + + /** + * Main launches the server from the command line. + */ + public static void main(String[] args) throws IOException, InterruptedException { + final HelloWorldServer server = new HelloWorldServer(); + server.start(); + server.blockUntilShutdown(); + } + + private class GreeterImpl extends GreeterGrpc.GreeterImplBase { + + @Override + public void sayHello(HelloRequest req, StreamObserver responseObserver) { + HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build(); + responseObserver.onNext(reply); + responseObserver.onCompleted(); + } + } +} diff --git a/endpoints/getting-started-grpc/settings.gradle b/endpoints/getting-started-grpc/settings.gradle new file mode 100644 index 00000000000..9ebbb2e1738 --- /dev/null +++ b/endpoints/getting-started-grpc/settings.gradle @@ -0,0 +1 @@ +include "api", "client", "server"