examples: add kotlin and kotlin android examples (#4037)

Add kotlin version of HelloWorldClient and HelloWorldServer.
Add kotlin version of android example.
This commit is contained in:
zpencer 2018-05-01 14:54:34 -07:00 committed by GitHub
parent 3e43757efc
commit f8424f7b7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1388 additions and 0 deletions

View File

@ -72,6 +72,8 @@ $ VERSION_FILES=(
examples/android/clientcache/app/build.gradle examples/android/clientcache/app/build.gradle
examples/android/helloworld/app/build.gradle examples/android/helloworld/app/build.gradle
examples/android/routeguide/app/build.gradle examples/android/routeguide/app/build.gradle
examples/example-kotlin/build.gradle
examples/example-kotlin/android/helloworld/app/build.gradle
) )
``` ```

View File

@ -44,6 +44,8 @@ cd ../routeguide
cd ../helloworld cd ../helloworld
./gradlew build ./gradlew build
cd $BASE_DIR/github/grpc-java/examples/example-kotlin/android/helloworld/
./gradlew build
# Skip APK size and dex count comparisons for non-PR builds # Skip APK size and dex count comparisons for non-PR builds

View File

@ -56,11 +56,18 @@ fi
# Run tests # Run tests
./gradlew build $GRADLE_FLAGS ./gradlew build $GRADLE_FLAGS
./gradlew install
pushd examples pushd examples
./gradlew build $GRADLE_FLAGS ./gradlew build $GRADLE_FLAGS
# --batch-mode reduces log spam # --batch-mode reduces log spam
mvn verify --batch-mode mvn verify --batch-mode
popd popd
pushd examples/example-kotlin/
./gradlew build $GRADLE_FLAGS
popd
# TODO(zpencer): also build the GAE examples # TODO(zpencer): also build the GAE examples
LOCAL_MVN_TEMP=$(mktemp -d) LOCAL_MVN_TEMP=$(mktemp -d)

View File

@ -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.

View File

@ -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()
}

View File

@ -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

View File

@ -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>

View File

@ -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
}
}
}

View File

@ -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;
}

View File

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">GrpcHelloworldExample</string>
</resources>

View File

@ -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()
}
}

View File

@ -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

View File

@ -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" "$@"

View File

@ -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

View File

@ -0,0 +1 @@
include ':app'

View File

@ -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
}

Binary file not shown.

View File

@ -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

172
examples/example-kotlin/gradlew vendored Executable file
View File

@ -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" "$@"

84
examples/example-kotlin/gradlew.bat vendored Normal file
View File

@ -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

View File

@ -0,0 +1 @@
rootProject.name = 'examples'

View File

@ -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()
}
}
}
}

View File

@ -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()
}
}
}

View File

@ -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;
}

View File

@ -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)
}
}

View File

@ -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)
}
}