aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorzpencer <spencerfang@google.com>2018-05-01 14:54:34 -0700
committerGitHub <noreply@github.com>2018-05-01 14:54:34 -0700
commitf8424f7b7baba45bacd22622e9a35054a4ce41b6 (patch)
treeb8129527b953c63096e3b9a893710e698f0dea81 /examples
parent3e43757efc98a177218919304d62114569fec9ea (diff)
downloadgrpc-grpc-java-f8424f7b7baba45bacd22622e9a35054a4ce41b6.tar.gz
examples: add kotlin and kotlin android examples (#4037)
Add kotlin version of HelloWorldClient and HelloWorldServer. Add kotlin version of android example.
Diffstat (limited to 'examples')
-rw-r--r--examples/example-kotlin/README.md59
-rw-r--r--examples/example-kotlin/android/helloworld/app/build.gradle91
-rw-r--r--examples/example-kotlin/android/helloworld/app/proguard-rules.pro17
-rw-r--r--examples/example-kotlin/android/helloworld/app/src/main/AndroidManifest.xml22
-rw-r--r--examples/example-kotlin/android/helloworld/app/src/main/kotlin/io/grpc/helloworldexample/HelloworldActivity.kt100
-rw-r--r--examples/example-kotlin/android/helloworld/app/src/main/proto/helloworld.proto38
-rw-r--r--examples/example-kotlin/android/helloworld/app/src/main/res/layout/activity_helloworld.xml54
-rw-r--r--examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.pngbin0 -> 3418 bytes
-rw-r--r--examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2206 bytes
-rw-r--r--examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4842 bytes
-rw-r--r--examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 7718 bytes
-rw-r--r--examples/example-kotlin/android/helloworld/app/src/main/res/values/strings.xml3
-rw-r--r--examples/example-kotlin/android/helloworld/build.gradle27
-rw-r--r--examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.jarbin0 -> 54727 bytes
-rw-r--r--examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xexamples/example-kotlin/android/helloworld/gradlew172
-rw-r--r--examples/example-kotlin/android/helloworld/gradlew.bat84
-rw-r--r--examples/example-kotlin/android/helloworld/settings.gradle1
-rw-r--r--examples/example-kotlin/build.gradle88
-rw-r--r--examples/example-kotlin/gradle/wrapper/gradle-wrapper.jarbin0 -> 54727 bytes
-rw-r--r--examples/example-kotlin/gradle/wrapper/gradle-wrapper.properties5
-rwxr-xr-xexamples/example-kotlin/gradlew172
-rw-r--r--examples/example-kotlin/gradlew.bat84
-rw-r--r--examples/example-kotlin/settings.gradle1
-rw-r--r--examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldClient.kt83
-rw-r--r--examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldServer.kt89
-rw-r--r--examples/example-kotlin/src/main/proto/helloworld.proto38
-rw-r--r--examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldClientTest.kt81
-rw-r--r--examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldServerTest.kt63
29 files changed, 1377 insertions, 0 deletions
diff --git a/examples/example-kotlin/README.md b/examples/example-kotlin/README.md
new file mode 100644
index 000000000..aec61f7dd
--- /dev/null
+++ b/examples/example-kotlin/README.md
@@ -0,0 +1,59 @@
+grpc Kotlin example
+==============================================
+
+The examples require grpc-java to already be built. You are strongly encouraged
+to check out a git release tag, since there will already be a build of grpc
+available. Otherwise you must follow COMPILING.md.
+
+You may want to read through the
+[Quick Start Guide](https://grpc.io/docs/quickstart/java.html)
+before trying out the examples.
+
+To build the examples, run in this directory:
+
+```
+$ ./gradlew installDist
+```
+
+This creates the scripts `hello-world-server`, `hello-world-client`,
+`route-guide-server`, and `route-guide-client` in the
+`build/install/examples/bin/` directory that run the examples. Each
+example requires the server to be running before starting the client.
+
+For example, to try the hello world example first run:
+
+```
+$ ./build/install/examples/bin/hello-world-server
+```
+
+And in a different terminal window run:
+
+```
+$ ./build/install/examples/bin/hello-world-client
+```
+
+That's it!
+
+Please refer to gRPC Java's [README](../README.md) and
+[tutorial](https://grpc.io/docs/tutorials/basic/java.html) for more
+information.
+
+Unit test examples
+==============================================
+
+Examples for unit testing gRPC clients and servers are located in [./src/test](./src/test).
+
+In general, we DO NOT allow overriding the client stub.
+We encourage users to leverage `InProcessTransport` as demonstrated in the examples to
+write unit tests. `InProcessTransport` is light-weight and runs the server
+and client in the same process without any socket/TCP connection.
+
+For testing a gRPC client, create the client with a real stub
+using an InProcessChannelBuilder.java and test it against an InProcessServer.java
+with a mock/fake service implementation.
+
+For testing a gRPC server, create the server as an InProcessServer,
+and test it against a real client stub with an InProcessChannel.
+
+The gRPC-java library also provides a JUnit rule, GrpcServerRule.java, to do the starting
+up and shutting down boilerplate for you.
diff --git a/examples/example-kotlin/android/helloworld/app/build.gradle b/examples/example-kotlin/android/helloworld/app/build.gradle
new file mode 100644
index 000000000..ba05ae621
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/app/build.gradle
@@ -0,0 +1,91 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-android-extensions'
+apply plugin: 'com.google.protobuf'
+
+android {
+ compileSdkVersion 27
+
+ defaultConfig {
+ applicationId "io.grpc.helloworldexample"
+ // API level 14+ is required for TLS since Google Play Services v10.2
+ minSdkVersion 14
+ targetSdkVersion 27
+ versionCode 1
+ versionName "1.0"
+ }
+ buildTypes {
+ debug {
+ minifyEnabled false
+ }
+ release {
+ minifyEnabled true
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+ lintOptions {
+ disable 'GoogleAppIndexingWarning', 'HardcodedText', 'InvalidPackage'
+ textReport true
+ textOutput "stdout"
+ }
+ // Android Studio 3.1 does not automatically pick up '<src_set>/kotlin' as source input
+ sourceSets {
+ main.java.srcDirs += 'src/main/kotlin'
+ main.java.srcDirs += 'src/test/kotlin'
+ androidTest.java.srcDirs += 'src/androidTest/kotlin'
+ }
+
+ lintOptions {
+ // Do not complain about outdated deps, so that this can javax.annotation-api can be same
+ // as other projects in this repo. Your project is not required to do this, and can
+ // upgrade the dep.
+ disable 'GradleDependency'
+ // The Android linter does not correctly detect resources used in Kotlin.
+ // See:
+ // - https://youtrack.jetbrains.com/issue/KT-7729
+ // - https://youtrack.jetbrains.com/issue/KT-12499
+ disable 'UnusedResources'
+ textReport true
+ textOutput "stdout"
+ }
+}
+
+protobuf {
+ protoc {
+ artifact = 'com.google.protobuf:protoc:3.5.1-1'
+ }
+ plugins {
+ javalite {
+ artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0"
+ }
+ grpc {
+ artifact = 'io.grpc:protoc-gen-grpc-java:1.13.0-SNAPSHOT' // CURRENT_GRPC_VERSION
+ }
+ }
+ generateProtoTasks {
+ all().each { task ->
+ task.plugins {
+ javalite {}
+ grpc {
+ // Options added to --grpc_out
+ option 'lite'
+ }
+ }
+ }
+ }
+}
+
+dependencies {
+ compile 'com.android.support:appcompat-v7:27.0.2'
+ compile 'javax.annotation:javax.annotation-api:1.2'
+ compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+
+ // You need to build grpc-java to obtain these libraries below.
+ compile 'io.grpc:grpc-okhttp:1.13.0-SNAPSHOT' // CURRENT_GRPC_VERSION
+ compile 'io.grpc:grpc-protobuf-lite:1.13.0-SNAPSHOT' // CURRENT_GRPC_VERSION
+ compile 'io.grpc:grpc-stub:1.13.0-SNAPSHOT' // CURRENT_GRPC_VERSION
+}
+
+repositories {
+ mavenCentral()
+}
diff --git a/examples/example-kotlin/android/helloworld/app/proguard-rules.pro b/examples/example-kotlin/android/helloworld/app/proguard-rules.pro
new file mode 100644
index 000000000..1507a5267
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/app/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in $ANDROID_HOME/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+-dontwarn com.google.common.**
+# Ignores: can't find referenced class javax.lang.model.element.Modifier
+-dontwarn com.google.errorprone.annotations.**
+-dontwarn javax.naming.**
+-dontwarn okio.**
+-dontwarn sun.misc.Unsafe
diff --git a/examples/example-kotlin/android/helloworld/app/src/main/AndroidManifest.xml b/examples/example-kotlin/android/helloworld/app/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..eee4057cd
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/app/src/main/AndroidManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="io.grpc.helloworldexample" >
+
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application
+ android:allowBackup="false"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/Base.V7.Theme.AppCompat.Light" >
+ <activity
+ android:name=".HelloworldActivity"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/examples/example-kotlin/android/helloworld/app/src/main/kotlin/io/grpc/helloworldexample/HelloworldActivity.kt b/examples/example-kotlin/android/helloworld/app/src/main/kotlin/io/grpc/helloworldexample/HelloworldActivity.kt
new file mode 100644
index 000000000..bcc6d0f28
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/app/src/main/kotlin/io/grpc/helloworldexample/HelloworldActivity.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2015, gRPC Authors All rights reserved.
+ *
+ * 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.
+ */
+
+package io.grpc.helloworldexample
+
+import android.app.Activity
+import android.content.Context
+import android.os.AsyncTask
+import android.os.Bundle
+import android.support.v7.app.AppCompatActivity
+import android.text.TextUtils
+import android.text.method.ScrollingMovementMethod
+import android.view.View
+import android.view.inputmethod.InputMethodManager
+import android.widget.Button
+import android.widget.TextView
+import io.grpc.ManagedChannel
+import io.grpc.ManagedChannelBuilder
+import io.grpc.examples.helloworld.GreeterGrpc
+import io.grpc.examples.helloworld.HelloRequest
+import java.io.PrintWriter
+import java.io.StringWriter
+import java.lang.ref.WeakReference
+import java.util.concurrent.TimeUnit
+import kotlinx.android.synthetic.main.activity_helloworld.*
+
+class HelloworldActivity : AppCompatActivity(), View.OnClickListener {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_helloworld)
+ grpc_response_text!!.movementMethod = ScrollingMovementMethod()
+ send_button!!.setOnClickListener(this)
+ }
+
+ override fun onClick(view: View) {
+ (getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager)
+ .hideSoftInputFromWindow(host_edit_text!!.windowToken, 0)
+ send_button!!.isEnabled = false
+ grpc_response_text!!.text = ""
+ GrpcTask(this)
+ .execute(
+ host_edit_text!!.text.toString(),
+ message_edit_text!!.text.toString(),
+ port_edit_text!!.text.toString())
+ }
+
+ private class GrpcTask constructor(activity: Activity) : AsyncTask<String, Void, String>() {
+ private val activityReference: WeakReference<Activity> = WeakReference(activity)
+ private var channel: ManagedChannel? = null
+
+ override fun doInBackground(vararg params: String): String {
+ val host = params[0]
+ val message = params[1]
+ val portStr = params[2]
+ val port = if (TextUtils.isEmpty(portStr)) 0 else Integer.valueOf(portStr)
+ return try {
+ channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext().build()
+ val stub = GreeterGrpc.newBlockingStub(channel)
+ val request = HelloRequest.newBuilder().setName(message).build()
+ val reply = stub.sayHello(request)
+ reply.message
+ } catch (e: Exception) {
+ val sw = StringWriter()
+ val pw = PrintWriter(sw)
+ e.printStackTrace(pw)
+ pw.flush()
+
+ "Failed... : %s".format(sw)
+ }
+ }
+
+ override fun onPostExecute(result: String) {
+ try {
+ channel?.shutdown()?.awaitTermination(1, TimeUnit.SECONDS)
+ } catch (e: InterruptedException) {
+ Thread.currentThread().interrupt()
+ }
+
+ val activity = activityReference.get() ?: return
+ val resultText: TextView = activity.findViewById(R.id.grpc_response_text)
+ val sendButton: Button = activity.findViewById(R.id.send_button)
+
+ resultText.text = result
+ sendButton.isEnabled = true
+ }
+ }
+}
diff --git a/examples/example-kotlin/android/helloworld/app/src/main/proto/helloworld.proto b/examples/example-kotlin/android/helloworld/app/src/main/proto/helloworld.proto
new file mode 100644
index 000000000..78441b2d5
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/app/src/main/proto/helloworld.proto
@@ -0,0 +1,38 @@
+// Copyright 2015, gRPC Authors
+// All rights reserved.
+//
+// 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.
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "io.grpc.examples.helloworld";
+option java_outer_classname = "HelloWorldProto";
+option objc_class_prefix = "HLW";
+
+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/examples/example-kotlin/android/helloworld/app/src/main/res/layout/activity_helloworld.xml b/examples/example-kotlin/android/helloworld/app/src/main/res/layout/activity_helloworld.xml
new file mode 100644
index 000000000..e9f41f466
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/app/src/main/res/layout/activity_helloworld.xml
@@ -0,0 +1,54 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity"
+ android:orientation="vertical" >
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+ <EditText
+ android:id="@+id/host_edit_text"
+ android:layout_weight="2"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:hint="Enter Host" />
+ <EditText
+ android:id="@+id/port_edit_text"
+ android:layout_weight="1"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:inputType="numberDecimal"
+ android:hint="Enter Port" />
+ </LinearLayout>
+
+
+ <EditText
+ android:id="@+id/message_edit_text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:hint="Enter message to send" />
+
+ <Button
+ android:id="@+id/send_button"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Send Grpc Request" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="12dp"
+ android:paddingBottom="12dp"
+ android:textSize="16sp"
+ android:text="Response:" />
+
+ <TextView
+ android:id="@+id/grpc_response_text"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scrollbars = "vertical"
+ android:textSize="16sp" />
+
+</LinearLayout>
diff --git a/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.png b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..cde69bccc
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.png b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..c133a0cbd
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..bfa42f0e7
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..324e72cdd
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/examples/example-kotlin/android/helloworld/app/src/main/res/values/strings.xml b/examples/example-kotlin/android/helloworld/app/src/main/res/values/strings.xml
new file mode 100644
index 000000000..64cb312d5
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+<resources>
+ <string name="app_name">GrpcHelloworldExample</string>
+</resources>
diff --git a/examples/example-kotlin/android/helloworld/build.gradle b/examples/example-kotlin/android/helloworld/build.gradle
new file mode 100644
index 000000000..ef4b2a199
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/build.gradle
@@ -0,0 +1,27 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ ext.kotlin_version = '1.2.21'
+
+ repositories {
+ google()
+ jcenter()
+ mavenLocal()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.0.1'
+ classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ mavenLocal()
+ }
+}
diff --git a/examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.jar b/examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..27768f1bb
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.properties b/examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..92165eede
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-bin.zip
diff --git a/examples/example-kotlin/android/helloworld/gradlew b/examples/example-kotlin/android/helloworld/gradlew
new file mode 100755
index 000000000..cccdd3d51
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## 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
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/examples/example-kotlin/android/helloworld/gradlew.bat b/examples/example-kotlin/android/helloworld/gradlew.bat
new file mode 100644
index 000000000..e95643d6a
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/gradlew.bat
@@ -0,0 +1,84 @@
+@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
+
+: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=%*
+
+: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/examples/example-kotlin/android/helloworld/settings.gradle b/examples/example-kotlin/android/helloworld/settings.gradle
new file mode 100644
index 000000000..e7b4def49
--- /dev/null
+++ b/examples/example-kotlin/android/helloworld/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/examples/example-kotlin/build.gradle b/examples/example-kotlin/build.gradle
new file mode 100644
index 000000000..150ea179b
--- /dev/null
+++ b/examples/example-kotlin/build.gradle
@@ -0,0 +1,88 @@
+apply plugin: 'kotlin'
+apply plugin: 'com.google.protobuf'
+
+// Generate IntelliJ IDEA's .idea & .iml project files
+// Starting with 0.8.4 of protobuf-gradle-plugin, *.proto and the gen output files are added
+// to IntelliJ as sources. It is no longer necessary to add them manually to the idea {} block
+// to jump to definitions from Java and Kotlin files.
+// For best results, install the Protobuf and Kotlin plugins for IntelliJ.
+apply plugin: 'idea'
+
+// Provide convenience executables for trying out the examples.
+apply plugin: 'application'
+
+
+buildscript {
+ ext.kotlin_version = '1.2.21'
+
+ repositories {
+ mavenCentral()
+ mavenLocal()
+ }
+ dependencies {
+ classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.5'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ }
+}
+
+repositories {
+ mavenCentral()
+ mavenLocal()
+}
+
+// IMPORTANT: You probably want the non-SNAPSHOT version of gRPC. Make sure you
+// are looking at a tagged version of the example and not "master"!
+
+// Feel free to delete the comment at the next line. It is just for safely
+// updating the version in our release process.
+def grpcVersion = '1.13.0-SNAPSHOT' // CURRENT_GRPC_VERSION
+
+dependencies {
+ compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
+ compile "com.google.api.grpc:proto-google-common-protos:1.0.0"
+ compile "io.grpc:grpc-netty:${grpcVersion}"
+ compile "io.grpc:grpc-protobuf:${grpcVersion}"
+ compile "io.grpc:grpc-stub:${grpcVersion}"
+
+ testCompile "io.grpc:grpc-testing:${grpcVersion}" // gRCP testing utilities
+ testCompile "junit:junit:4.12"
+ testCompile "org.mockito:mockito-core:1.9.5"
+}
+
+protobuf {
+ protoc {
+ artifact = 'com.google.protobuf:protoc:3.5.1-1'
+ }
+ plugins {
+ grpc {
+ artifact = "io.grpc:protoc-gen-grpc-java:${grpcVersion}"
+ }
+ }
+ generateProtoTasks {
+ all()*.plugins {
+ grpc {}
+ }
+ }
+}
+
+startScripts.enabled = false
+
+task helloWorldServer(type: CreateStartScripts) {
+ mainClassName = 'io.grpc.examples.helloworld.HelloWorldServer'
+ applicationName = 'hello-world-server'
+ outputDir = new File(project.buildDir, 'tmp')
+ classpath = jar.outputs.files + project.configurations.runtime
+}
+
+task helloWorldClient(type: CreateStartScripts) {
+ mainClassName = 'io.grpc.examples.helloworld.HelloWorldClient'
+ applicationName = 'hello-world-client'
+ outputDir = new File(project.buildDir, 'tmp')
+ classpath = jar.outputs.files + project.configurations.runtime
+}
+
+applicationDistribution.into('bin') {
+ from(helloWorldServer)
+ from(helloWorldClient)
+ fileMode = 0755
+}
diff --git a/examples/example-kotlin/gradle/wrapper/gradle-wrapper.jar b/examples/example-kotlin/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 000000000..27768f1bb
--- /dev/null
+++ b/examples/example-kotlin/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/examples/example-kotlin/gradle/wrapper/gradle-wrapper.properties b/examples/example-kotlin/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..92165eede
--- /dev/null
+++ b/examples/example-kotlin/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.3-bin.zip
diff --git a/examples/example-kotlin/gradlew b/examples/example-kotlin/gradlew
new file mode 100755
index 000000000..cccdd3d51
--- /dev/null
+++ b/examples/example-kotlin/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## 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
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/examples/example-kotlin/gradlew.bat b/examples/example-kotlin/gradlew.bat
new file mode 100644
index 000000000..e95643d6a
--- /dev/null
+++ b/examples/example-kotlin/gradlew.bat
@@ -0,0 +1,84 @@
+@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
+
+: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=%*
+
+: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/examples/example-kotlin/settings.gradle b/examples/example-kotlin/settings.gradle
new file mode 100644
index 000000000..9512a19f3
--- /dev/null
+++ b/examples/example-kotlin/settings.gradle
@@ -0,0 +1 @@
+rootProject.name = 'examples'
diff --git a/examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldClient.kt b/examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldClient.kt
new file mode 100644
index 000000000..74fe7c993
--- /dev/null
+++ b/examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldClient.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2015, gRPC Authors All rights reserved.
+ *
+ * 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.
+ */
+
+package io.grpc.examples.helloworld
+
+import io.grpc.ManagedChannel
+import io.grpc.ManagedChannelBuilder
+import io.grpc.StatusRuntimeException
+import java.util.concurrent.TimeUnit
+import java.util.logging.Level
+import java.util.logging.Logger
+
+/**
+ * A simple client that requests a greeting from the [HelloWorldServer].
+ */
+class HelloWorldClient
+/** Construct client for accessing RouteGuide server using the existing channel. */
+internal constructor(private val channel: ManagedChannel) {
+ private val blockingStub: GreeterGrpc.GreeterBlockingStub
+ = GreeterGrpc.newBlockingStub(channel)
+
+ /** Construct client connecting to HelloWorld server at `host:port`. */
+ constructor(host: String, port: Int) : this(ManagedChannelBuilder.forAddress(host, port)
+ // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid
+ // needing certificates.
+ .usePlaintext()
+ .build()) {
+ }
+
+
+ @Throws(InterruptedException::class)
+ fun shutdown() {
+ channel.shutdown().awaitTermination(5, TimeUnit.SECONDS)
+ }
+
+ /** Say hello to server. */
+ fun greet(name: String) {
+ logger.log(Level.INFO, "Will try to greet {0}...", name)
+ val request = HelloRequest.newBuilder().setName(name).build()
+ val response: HelloReply = try {
+ blockingStub.sayHello(request)
+ } catch (e: StatusRuntimeException) {
+ logger.log(Level.WARNING, "RPC failed: {0}", e.status)
+ return
+ }
+
+ logger.info("Greeting: ${response.message}")
+ }
+
+ companion object {
+ private val logger = Logger.getLogger(HelloWorldClient::class.java.name)
+
+ /**
+ * Greet server. If provided, the first element of `args` is the name to use in the
+ * greeting.
+ */
+ @Throws(Exception::class)
+ @JvmStatic
+ fun main(args: Array<String>) {
+ val client = HelloWorldClient("localhost", 50051)
+ try {
+ /* Access a service running on the local machine on port 50051 */
+ val user = if (args.size > 0) "world" else "world"
+ client.greet(user)
+ } finally {
+ client.shutdown()
+ }
+ }
+ }
+}
diff --git a/examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldServer.kt b/examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldServer.kt
new file mode 100644
index 000000000..ae0d8de82
--- /dev/null
+++ b/examples/example-kotlin/src/main/kotlin/io/grpc/examples/helloworld/HelloWorldServer.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2015, gRPC Authors All rights reserved.
+ *
+ * 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.
+ */
+
+package io.grpc.examples.helloworld
+
+import io.grpc.Server
+import io.grpc.ServerBuilder
+import io.grpc.stub.StreamObserver
+import java.io.IOException
+import java.util.logging.Level
+import java.util.logging.Logger
+
+/**
+ * Server that manages startup/shutdown of a `Greeter` server.
+ *
+ * Note: this file was automatically converted from Java
+ */
+class HelloWorldServer {
+
+ private var server: Server? = null
+
+ @Throws(IOException::class)
+ private fun start() {
+ /* The port on which the server should run */
+ val port = 50051
+ server = ServerBuilder.forPort(port)
+ .addService(GreeterImpl())
+ .build()
+ .start()
+ logger.log(Level.INFO, "Server started, listening on {0}", port)
+ Runtime.getRuntime().addShutdownHook(object : Thread() {
+ override fun 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")
+ this@HelloWorldServer.stop()
+ System.err.println("*** server shut down")
+ }
+ })
+ }
+
+ private fun stop() {
+ server?.shutdown()
+ }
+
+ /**
+ * Await termination on the main thread since the grpc library uses daemon threads.
+ */
+ @Throws(InterruptedException::class)
+ private fun blockUntilShutdown() {
+ server?.awaitTermination()
+ }
+
+ internal class GreeterImpl : GreeterGrpc.GreeterImplBase() {
+
+ override fun sayHello(req: HelloRequest, responseObserver: StreamObserver<HelloReply>) {
+ val reply = HelloReply.newBuilder().setMessage("Hello ${req.name}").build()
+ responseObserver.onNext(reply)
+ responseObserver.onCompleted()
+ }
+ }
+
+ companion object {
+ private val logger = Logger.getLogger(HelloWorldServer::class.java.name)
+
+ /**
+ * Main launches the server from the command line.
+ */
+ @Throws(IOException::class, InterruptedException::class)
+ @JvmStatic
+ fun main(args: Array<String>) {
+ val server = HelloWorldServer()
+ server.start()
+ server.blockUntilShutdown()
+ }
+ }
+}
diff --git a/examples/example-kotlin/src/main/proto/helloworld.proto b/examples/example-kotlin/src/main/proto/helloworld.proto
new file mode 100644
index 000000000..78441b2d5
--- /dev/null
+++ b/examples/example-kotlin/src/main/proto/helloworld.proto
@@ -0,0 +1,38 @@
+// Copyright 2015, gRPC Authors
+// All rights reserved.
+//
+// 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.
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "io.grpc.examples.helloworld";
+option java_outer_classname = "HelloWorldProto";
+option objc_class_prefix = "HLW";
+
+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/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldClientTest.kt b/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldClientTest.kt
new file mode 100644
index 000000000..3d096c920
--- /dev/null
+++ b/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldClientTest.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2015, gRPC Authors All rights reserved.
+ *
+ * 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.
+ */
+
+package io.grpc.examples.helloworld
+
+import org.junit.Assert.assertEquals
+import org.mockito.AdditionalAnswers.delegatesTo
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
+
+import io.grpc.stub.StreamObserver
+import io.grpc.testing.GrpcServerRule
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentCaptor
+import org.mockito.Matchers
+
+/**
+ * Unit tests for [HelloWorldClient].
+ * For demonstrating how to write gRPC unit test only.
+ * Not intended to provide a high code coverage or to test every major usecase.
+ *
+ *
+ * For more unit test examples see [io.grpc.examples.routeguide.RouteGuideClientTest] and
+ * [io.grpc.examples.routeguide.RouteGuideServerTest].
+ */
+@RunWith(JUnit4::class)
+class HelloWorldClientTest {
+ /**
+ * This creates and starts an in-process server, and creates a client with an in-process channel.
+ * When the test is done, it also shuts down the in-process client and server.
+ */
+ @get:Rule
+ val grpcServerRule = GrpcServerRule().directExecutor()
+
+ private val serviceImpl = mock(GreeterGrpc.GreeterImplBase::class.java, delegatesTo<Any>(object : GreeterGrpc.GreeterImplBase() {
+
+ }))
+ private var client: HelloWorldClient? = null
+
+ @Before
+ @Throws(Exception::class)
+ fun setUp() {
+ // Add service.
+ grpcServerRule.serviceRegistry.addService(serviceImpl)
+ // Create a HelloWorldClient using the in-process channel;
+ client = HelloWorldClient(grpcServerRule.channel)
+ }
+
+ /**
+ * To test the client, call from the client against the fake server, and verify behaviors or state
+ * changes from the server side.
+ */
+ @Test
+ fun greet_messageDeliveredToServer() {
+ val requestCaptor = ArgumentCaptor.forClass(HelloRequest::class.java)
+ val testName = "test name"
+
+ client!!.greet(testName)
+
+ verify<GreeterGrpc.GreeterImplBase>(serviceImpl)
+ .sayHello(requestCaptor.capture(), Matchers.any<StreamObserver<HelloReply>>())
+ assertEquals(testName, requestCaptor.value.name)
+ }
+}
diff --git a/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldServerTest.kt b/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldServerTest.kt
new file mode 100644
index 000000000..4512b34ac
--- /dev/null
+++ b/examples/example-kotlin/src/test/kotlin/io/grpc/examples/helloworld/HelloWorldServerTest.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2016, gRPC Authors All rights reserved.
+ *
+ * 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.
+ */
+
+package io.grpc.examples.helloworld
+
+import org.junit.Assert.assertEquals
+
+import io.grpc.examples.helloworld.HelloWorldServer.GreeterImpl
+import io.grpc.testing.GrpcServerRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+/**
+ * Unit tests for [HelloWorldServer].
+ * For demonstrating how to write gRPC unit test only.
+ * Not intended to provide a high code coverage or to test every major usecase.
+ *
+ *
+ * For more unit test examples see [io.grpc.examples.routeguide.RouteGuideClientTest] and
+ * [io.grpc.examples.routeguide.RouteGuideServerTest].
+ */
+@RunWith(JUnit4::class)
+class HelloWorldServerTest {
+ /**
+ * This creates and starts an in-process server, and creates a client with an in-process channel.
+ * When the test is done, it also shuts down the in-process client and server.
+ */
+ @get:Rule
+ val grpcServerRule = GrpcServerRule().directExecutor()
+
+ /**
+ * To test the server, make calls with a real stub using the in-process channel, and verify
+ * behaviors or state changes from the client side.
+ */
+ @Test
+ @Throws(Exception::class)
+ fun greeterImpl_replyMessage() {
+ // Add the service to the in-process server.
+ grpcServerRule.serviceRegistry.addService(GreeterImpl())
+
+ val blockingStub = GreeterGrpc.newBlockingStub(grpcServerRule.channel)
+ val testName = "test name"
+
+ val reply = blockingStub.sayHello(HelloRequest.newBuilder().setName(testName).build())
+
+ assertEquals("Hello $testName", reply.message)
+ }
+}