From 312f6a585bdfb6a6d9b77b6ed555c67a223564f7 Mon Sep 17 00:00:00 2001 From: Xiao Hang Date: Wed, 25 Feb 2015 16:21:24 -0800 Subject: [PATCH 1/4] gRPC Android Helloworld example --- android/GreeterGrpc.java | 184 ++++++++++++++++++++++++++++++++ android/Helloworld.java | 175 ++++++++++++++++++++++++++++++ android/HelloworldActivity.java | 92 ++++++++++++++++ android/README.md | 72 +++++++++++++ android/activity_helloworld.xml | 54 ++++++++++ 5 files changed, 577 insertions(+) create mode 100644 android/GreeterGrpc.java create mode 100644 android/Helloworld.java create mode 100644 android/HelloworldActivity.java create mode 100644 android/README.md create mode 100644 android/activity_helloworld.xml diff --git a/android/GreeterGrpc.java b/android/GreeterGrpc.java new file mode 100644 index 00000000000..eaef3679d2d --- /dev/null +++ b/android/GreeterGrpc.java @@ -0,0 +1,184 @@ +package io.grpc.examples; + +import static io.grpc.stub.Calls.createMethodDescriptor; +import static io.grpc.stub.Calls.asyncUnaryCall; +import static io.grpc.stub.Calls.asyncServerStreamingCall; +import static io.grpc.stub.Calls.asyncClientStreamingCall; +import static io.grpc.stub.Calls.duplexStreamingCall; +import static io.grpc.stub.Calls.blockingUnaryCall; +import static io.grpc.stub.Calls.blockingServerStreamingCall; +import static io.grpc.stub.Calls.unaryFutureCall; +import static io.grpc.stub.ServerCalls.createMethodDefinition; +import static io.grpc.stub.ServerCalls.asyncUnaryRequestCall; +import static io.grpc.stub.ServerCalls.asyncStreamingRequestCall; + +import java.io.IOException; + +public class GreeterGrpc { + + private static final io.grpc.stub.Method METHOD_SAY_HELLO = + io.grpc.stub.Method.create( + io.grpc.MethodType.UNARY, "SayHello", + io.grpc.nano.NanoUtils.marshaller( + new io.grpc.nano.Parser() { + @Override + public io.grpc.examples.Helloworld.HelloRequest parse(com.google.protobuf.nano.CodedInputByteBufferNano input) throws IOException { + return io.grpc.examples.Helloworld.HelloRequest.parseFrom(input); + } + }), + io.grpc.nano.NanoUtils.marshaller( + new io.grpc.nano.Parser() { + @Override + public io.grpc.examples.Helloworld.HelloReply parse(com.google.protobuf.nano.CodedInputByteBufferNano input) throws IOException { + return io.grpc.examples.Helloworld.HelloReply.parseFrom(input); + } + })); + + public static GreeterStub newStub(io.grpc.Channel channel) { + return new GreeterStub(channel, CONFIG); + } + + public static GreeterBlockingStub newBlockingStub( + io.grpc.Channel channel) { + return new GreeterBlockingStub(channel, CONFIG); + } + + public static GreeterFutureStub newFutureStub( + io.grpc.Channel channel) { + return new GreeterFutureStub(channel, CONFIG); + } + + public static final GreeterServiceDescriptor CONFIG = + new GreeterServiceDescriptor(); + + public static class GreeterServiceDescriptor extends + io.grpc.stub.AbstractServiceDescriptor { + public final io.grpc.MethodDescriptor sayHello; + + private GreeterServiceDescriptor() { + sayHello = createMethodDescriptor( + "helloworld.Greeter", METHOD_SAY_HELLO); + } + + private GreeterServiceDescriptor( + java.util.Map> methodMap) { + sayHello = (io.grpc.MethodDescriptor) methodMap.get( + CONFIG.sayHello.getName()); + } + + @java.lang.Override + protected GreeterServiceDescriptor build( + java.util.Map> methodMap) { + return new GreeterServiceDescriptor(methodMap); + } + + @java.lang.Override + public com.google.common.collect.ImmutableList> methods() { + return com.google.common.collect.ImmutableList.>of( + sayHello); + } + } + + public static interface Greeter { + + public void sayHello(io.grpc.examples.Helloworld.HelloRequest request, + io.grpc.stub.StreamObserver responseObserver); + } + + public static interface GreeterBlockingClient { + + public io.grpc.examples.Helloworld.HelloReply sayHello(io.grpc.examples.Helloworld.HelloRequest request); + } + + public static interface GreeterFutureClient { + + public com.google.common.util.concurrent.ListenableFuture sayHello( + io.grpc.examples.Helloworld.HelloRequest request); + } + + public static class GreeterStub extends + io.grpc.stub.AbstractStub + implements Greeter { + private GreeterStub(io.grpc.Channel channel, + GreeterServiceDescriptor config) { + super(channel, config); + } + + @java.lang.Override + protected GreeterStub build(io.grpc.Channel channel, + GreeterServiceDescriptor config) { + return new GreeterStub(channel, config); + } + + @java.lang.Override + public void sayHello(io.grpc.examples.Helloworld.HelloRequest request, + io.grpc.stub.StreamObserver responseObserver) { + asyncUnaryCall( + channel.newCall(config.sayHello), request, responseObserver); + } + } + + public static class GreeterBlockingStub extends + io.grpc.stub.AbstractStub + implements GreeterBlockingClient { + private GreeterBlockingStub(io.grpc.Channel channel, + GreeterServiceDescriptor config) { + super(channel, config); + } + + @java.lang.Override + protected GreeterBlockingStub build(io.grpc.Channel channel, + GreeterServiceDescriptor config) { + return new GreeterBlockingStub(channel, config); + } + + @java.lang.Override + public io.grpc.examples.Helloworld.HelloReply sayHello(io.grpc.examples.Helloworld.HelloRequest request) { + return blockingUnaryCall( + channel.newCall(config.sayHello), request); + } + } + + public static class GreeterFutureStub extends + io.grpc.stub.AbstractStub + implements GreeterFutureClient { + private GreeterFutureStub(io.grpc.Channel channel, + GreeterServiceDescriptor config) { + super(channel, config); + } + + @java.lang.Override + protected GreeterFutureStub build(io.grpc.Channel channel, + GreeterServiceDescriptor config) { + return new GreeterFutureStub(channel, config); + } + + @java.lang.Override + public com.google.common.util.concurrent.ListenableFuture sayHello( + io.grpc.examples.Helloworld.HelloRequest request) { + return unaryFutureCall( + channel.newCall(config.sayHello), request); + } + } + + public static io.grpc.ServerServiceDefinition bindService( + final Greeter serviceImpl) { + return io.grpc.ServerServiceDefinition.builder("helloworld.Greeter") + .addMethod(createMethodDefinition( + METHOD_SAY_HELLO, + asyncUnaryRequestCall( + new io.grpc.stub.ServerCalls.UnaryRequestMethod< + io.grpc.examples.Helloworld.HelloRequest, + io.grpc.examples.Helloworld.HelloReply>() { + @java.lang.Override + public void invoke( + io.grpc.examples.Helloworld.HelloRequest request, + io.grpc.stub.StreamObserver responseObserver) { + serviceImpl.sayHello(request, responseObserver); + } + }))).build(); + } +} diff --git a/android/Helloworld.java b/android/Helloworld.java new file mode 100644 index 00000000000..35dd5345129 --- /dev/null +++ b/android/Helloworld.java @@ -0,0 +1,175 @@ +// Generated by the protocol buffer compiler. DO NOT EDIT! + +package io.grpc.examples; + +@SuppressWarnings("hiding") +public interface Helloworld { + + public static final class HelloRequest extends + com.google.protobuf.nano.MessageNano { + + private static volatile HelloRequest[] _emptyArray; + public static HelloRequest[] emptyArray() { + // Lazily initializes the empty array + if (_emptyArray == null) { + synchronized ( + com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) { + if (_emptyArray == null) { + _emptyArray = new HelloRequest[0]; + } + } + } + return _emptyArray; + } + + // optional string name = 1; + public java.lang.String name; + + public HelloRequest() { + clear(); + } + + public HelloRequest clear() { + name = ""; + cachedSize = -1; + return this; + } + + @Override + public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output) + throws java.io.IOException { + if (!this.name.equals("")) { + output.writeString(1, this.name); + } + super.writeTo(output); + } + + @Override + protected int computeSerializedSize() { + int size = super.computeSerializedSize(); + if (!this.name.equals("")) { + size += com.google.protobuf.nano.CodedOutputByteBufferNano + .computeStringSize(1, this.name); + } + return size; + } + + @Override + public HelloRequest mergeFrom( + com.google.protobuf.nano.CodedInputByteBufferNano input) + throws java.io.IOException { + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + return this; + default: { + if (!com.google.protobuf.nano.WireFormatNano.parseUnknownField(input, tag)) { + return this; + } + break; + } + case 10: { + this.name = input.readString(); + break; + } + } + } + } + + public static HelloRequest parseFrom(byte[] data) + throws com.google.protobuf.nano.InvalidProtocolBufferNanoException { + return com.google.protobuf.nano.MessageNano.mergeFrom(new HelloRequest(), data); + } + + public static HelloRequest parseFrom( + com.google.protobuf.nano.CodedInputByteBufferNano input) + throws java.io.IOException { + return new HelloRequest().mergeFrom(input); + } + } + + public static final class HelloReply extends + com.google.protobuf.nano.MessageNano { + + private static volatile HelloReply[] _emptyArray; + public static HelloReply[] emptyArray() { + // Lazily initializes the empty array + if (_emptyArray == null) { + synchronized ( + com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) { + if (_emptyArray == null) { + _emptyArray = new HelloReply[0]; + } + } + } + return _emptyArray; + } + + // optional string message = 1; + public java.lang.String message; + + public HelloReply() { + clear(); + } + + public HelloReply clear() { + message = ""; + cachedSize = -1; + return this; + } + + @Override + public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output) + throws java.io.IOException { + if (!this.message.equals("")) { + output.writeString(1, this.message); + } + super.writeTo(output); + } + + @Override + protected int computeSerializedSize() { + int size = super.computeSerializedSize(); + if (!this.message.equals("")) { + size += com.google.protobuf.nano.CodedOutputByteBufferNano + .computeStringSize(1, this.message); + } + return size; + } + + @Override + public HelloReply mergeFrom( + com.google.protobuf.nano.CodedInputByteBufferNano input) + throws java.io.IOException { + while (true) { + int tag = input.readTag(); + switch (tag) { + case 0: + return this; + default: { + if (!com.google.protobuf.nano.WireFormatNano.parseUnknownField(input, tag)) { + return this; + } + break; + } + case 10: { + this.message = input.readString(); + break; + } + } + } + } + + public static HelloReply parseFrom(byte[] data) + throws com.google.protobuf.nano.InvalidProtocolBufferNanoException { + return com.google.protobuf.nano.MessageNano.mergeFrom(new HelloReply(), data); + } + + public static HelloReply parseFrom( + com.google.protobuf.nano.CodedInputByteBufferNano input) + throws java.io.IOException { + return new HelloReply().mergeFrom(input); + } + } +} diff --git a/android/HelloworldActivity.java b/android/HelloworldActivity.java new file mode 100644 index 00000000000..eb4e93b5552 --- /dev/null +++ b/android/HelloworldActivity.java @@ -0,0 +1,92 @@ +package io.grpc.helloworld; + +import android.content.Context; +import android.support.v7.app.ActionBarActivity; +import android.os.Bundle; +import android.os.AsyncTask; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.inputmethod.InputMethodManager; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import io.grpc.ChannelImpl; +import ex.grpc.GreeterGrpc; +import ex.grpc.Helloworld.HelloRequest; +import ex.grpc.Helloworld.HelloReply; +import io.grpc.transport.okhttp.OkHttpChannelBuilder; + +import java.util.concurrent.TimeUnit; + +public class Helloworld extends ActionBarActivity { + private Button mSendButton; + private EditText mHostEdit; + private EditText mPortEdit; + private EditText mMessageEdit; + private TextView mResultText; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_helloworld); + mSendButton = (Button) findViewById(R.id.send_button); + mHostEdit = (EditText) findViewById(R.id.host_edit_text); + mPortEdit = (EditText) findViewById(R.id.port_edit_text); + mMessageEdit = (EditText) findViewById(R.id.message_edit_text); + mResultText = (TextView) findViewById(R.id.grpc_response_text); + } + + public void sendMessage(View view) { + ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)) + .hideSoftInputFromWindow(mHostEdit.getWindowToken(), 0); + mSendButton.setEnabled(false); + new GrpcTask().execute(); + } + + private class GrpcTask extends AsyncTask { + private String mHost; + private String mMessage; + private int mPort; + private ChannelImpl mChannel; + + @Override + protected void onPreExecute() { + mHost = mHostEdit.getText().toString(); + mMessage = mMessageEdit.getText().toString(); + String portStr = mPortEdit.getText().toString(); + mPort = TextUtils.isEmpty(portStr) ? 0 : Integer.valueOf(portStr); + mResultText.setText(""); + } + + private String sayHello(ChannelImpl channel) { + GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel); + HelloRequest message = new HelloRequest(); + message.name = mMessage; + HelloReply reply = stub.sayHello(message); + return reply.message; + } + + @Override + protected String doInBackground(Void... nothing) { + try { + mChannel = OkHttpChannelBuilder.forAddress(mHost, mPort).build(); + return sayHello(mChannel); + } catch (Exception e) { + return "Failed... : " + e.getMessage(); + } + } + + @Override + protected void onPostExecute(String result) { + try { + mChannel.shutdown().awaitTerminated(1, TimeUnit.SECONDS); + } catch (InterruptedException e) { + } + mResultText.setText(result); + mSendButton.setEnabled(true); + } + } +} \ No newline at end of file diff --git a/android/README.md b/android/README.md new file mode 100644 index 00000000000..013e20c754a --- /dev/null +++ b/android/README.md @@ -0,0 +1,72 @@ +gRPC Hello World Tutorial (gRPC Java on Android) +======================== + +BACKGROUND +------------- +For this sample, we've already generated the server and client stubs from [helloworld.proto](https://github.com/grpc/grpc-common/blob/master/protos/helloworld.proto). + +PREREQUISITES +------------- +- [Java gRPC](https://github.com/grpc/grpc-java) + +- [Android Tutorial](https://developer.android.com/training/basics/firstapp/index.html) If you're new to Android development + +- We only have Android gRPC client in this example. Please follow examples in other languages to build and run a gRPC server. + +INSTALL +------- +1 Clone the gRPC Java git repo +```sh +$ cd $grpc_java_dir$ +$ git clone https://github.com/grpc/grpc-java +``` + +2 Install gRPC Java, as described in [How to Build](https://github.com/grpc/grpc-java#how-to-build) +```sh +$ # from this dir +$ cd grpc-java +$ # follow the instructions in 'How to Build' +``` + +3 [Create an Android project](https://developer.android.com/training/basics/firstapp/creating-project.html) under your working directory. +- Set Application name to "Helloworld Example" and set Company Domain to "grpc.io". Make sure your package name is "io.grpc.helloworldexample" +- Choose appropriate minimum SDK +- Use Blank Activity +- Set Activity Name to HelloworldActivity +- Set Layout Name to activity_helloworld + +4 Prepare the app +- Clone this git repo +```sh +$ git clone https://github.com/grpc/grpc-common + +``` +- Replace the generated HelloworldActivity.java and activity_helloworld.xml with the two files in this repo +- Copy GreeterGrpc.java and Helloworld.java under $working_dir$/app/src/main/java/io/grpc/examples/ +- In your AndroidManifest.xml, make sure you have +```sh + +``` +added outside your appplication tag + +5 Add dependencies. gRPC Java on Android depends on grpc-java, protobuf nano, okhttp +- Copy grpc-java .jar files to $working_dir$/app/libs/: + - $grpc-java-dir$/core/build/libs/*.jar + - $grpc-java-dir$/stub/build/libs/*.jar + - $grpc-java-dir$/nano/build/libs/*.jar + - $grpc-java-dir$/okhttp/build/libs/*.jar +- Copy or download other dependencies to $working_dir$/app/libs/: + - protobuf nano: +```sh +$ cp ~/.m2/repository/com/google/protobuf/nano/protobuf-javanano/2.6.2-pre/protobuf-javanano-2.6.2-pre.jar $working_dir$/app/libs/ +``` + - [Guava 18](http://search.maven.org/remotecontent?filepath=com/google/guava/guava/18.0/guava-18.0.jar) + - [okhttp 2.2.0](http://repo1.maven.org/maven2/com/squareup/okhttp/okhttp/2.2.0/okhttp-2.2.0.jar) +- Make sure your app/build.gradle contains: +```sh +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) +} +``` + +6 [Run your example app](https://developer.android.com/training/basics/firstapp/running-app.html) diff --git a/android/activity_helloworld.xml b/android/activity_helloworld.xml new file mode 100644 index 00000000000..41411d11aa5 --- /dev/null +++ b/android/activity_helloworld.xml @@ -0,0 +1,54 @@ + + + + + + + + + + +