├── .gitignore ├── LICENSE ├── README.md ├── calculator ├── calculator │ ├── Dockerfile │ ├── build.gradle │ └── src │ │ └── main │ │ ├── java │ │ └── calculator │ │ │ ├── Application.java │ │ │ └── Calculator.java │ │ ├── proto │ │ └── calculator.proto │ │ └── resources │ │ └── application.properties ├── client │ ├── Dockerfile │ ├── build.gradle │ └── src │ │ └── main │ │ ├── java │ │ └── client │ │ │ ├── Application.java │ │ │ └── Client.java │ │ ├── proto │ │ └── calculator.proto │ │ └── resources │ │ └── application.properties └── docker-compose.yml ├── greeter-bean-with-interceptors ├── client │ ├── Dockerfile │ ├── build.gradle │ └── src │ │ └── main │ │ ├── java │ │ └── client │ │ │ ├── Application.java │ │ │ └── Client.java │ │ ├── proto │ │ └── greeter.proto │ │ └── resources │ │ └── application.properties ├── docker-compose.yml └── server │ ├── Dockerfile │ ├── build.gradle │ └── src │ └── main │ ├── java │ └── server │ │ ├── Application.java │ │ ├── LogInterceptor.java │ │ ├── NonBeanInterceptor.java │ │ └── Server.java │ ├── proto │ └── greeter.proto │ └── resources │ └── application.properties ├── greeter-with-interceptors ├── client │ ├── Dockerfile │ ├── build.gradle │ └── src │ │ └── main │ │ ├── java │ │ └── client │ │ │ ├── Application.java │ │ │ └── Client.java │ │ ├── proto │ │ └── greeter.proto │ │ └── resources │ │ └── application.properties ├── docker-compose.yml └── server │ ├── Dockerfile │ ├── build.gradle │ └── src │ └── main │ ├── java │ └── server │ │ ├── Application.java │ │ ├── LogInterceptor.java │ │ ├── NonBeanInterceptor.java │ │ └── Server.java │ ├── proto │ └── greeter.proto │ └── resources │ └── application.properties ├── greeter ├── client │ ├── Dockerfile │ ├── build.gradle │ └── src │ │ └── main │ │ ├── java │ │ └── client │ │ │ ├── Application.java │ │ │ └── Client.java │ │ ├── proto │ │ └── greeter.proto │ │ └── resources │ │ └── application.properties ├── docker-compose.yml └── server │ ├── Dockerfile │ ├── build.gradle │ └── src │ └── main │ ├── java │ └── server │ │ ├── Application.java │ │ └── Server.java │ ├── proto │ └── greeter.proto │ └── resources │ └── application.properties ├── health-check ├── client │ ├── Dockerfile │ ├── build.gradle │ └── src │ │ └── main │ │ ├── java │ │ └── client │ │ │ ├── Application.java │ │ │ └── Client.java │ │ ├── proto │ │ └── health_check.proto │ │ └── resources │ │ └── application.properties ├── docker-compose.yml └── server │ ├── Dockerfile │ ├── build.gradle │ └── src │ └── main │ ├── java │ └── server │ │ ├── Application.java │ │ └── Server.java │ ├── proto │ └── health_check.proto │ └── resources │ └── application.properties └── infinite-ping-pong ├── docker-compose.yml ├── ping ├── Dockerfile ├── build.gradle └── src │ └── main │ ├── java │ └── ping │ │ ├── Application.java │ │ └── Ping.java │ ├── proto │ └── echo.proto │ └── resources │ └── application.properties └── pong ├── Dockerfile ├── build.gradle └── src └── main ├── java └── pong │ ├── Application.java │ └── Pong.java ├── proto └── echo.proto └── resources └── application.properties /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | **/generated 3 | classes 4 | .gradle 5 | 6 | .DS_Store 7 | target/ 8 | !.mvn/wrapper/maven-wrapper.jar 9 | 10 | ### IntelliJ IDEA ### 11 | .idea 12 | *.iws 13 | *.iml 14 | *.ipr 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | COPYRIGHT (c) 2018 João Ferreira Loff 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gRPC Spring Boot Examples 2 | 3 | Collection of working examples of [gRPC](http://www.grpc.io)-based applications running on top of [Spring Boot](https://projects.spring.io/spring-boot/). We used the [LogNet/grpc-spring-boot-starter](https://github.com/LogNet/grpc-spring-boot-starter) gradle plugin, and ported available examples to work OOTB. 4 | 5 | Although the provided examples have unit tests that work as clients, we adopt a more in-action example and add a client service. This is useful when you want to bootstrap microservices. We also setup a Docker-ready deployment. 6 | 7 | **Feel free to submit a PR for other examples or improvements existing ones!** 8 | 9 | ## Run 10 | Running examples is easy peasy lemon squeezy! Just go into one of the examples subfolders, and **run `docker-compose up`**! That's it! 11 | 12 | 13 | ## Examples 14 | * **`greeter`**: client sends a name for the server, and the server replies with a greeting. Client name is passed as an env variable in the `docker-compose.yml`. Based on [LogNet/grpc-spring-boot-starter examples](https://github.com/LogNet/grpc-spring-boot-starter/tree/master/grpc-spring-boot-starter-demo). 15 | 16 | * **`greeter-interceptors`**: same as greeter but we add an interceptor to the server(`NonBeanInterceptor.java`) even though server is not a `@Bean`. Based on [LogNet/grpc-spring-boot-starter examples](https://github.com/LogNet/grpc-spring-boot-starter/tree/master/grpc-spring-boot-starter-demo). 17 | 18 | * **`greeter-bean-interceptors`**: same as greeter but we add an interceptor to the server(`LogInterceptor.java`). Based on [LogNet/grpc-spring-boot-starter examples](https://github.com/LogNet/grpc-spring-boot-starter/tree/master/grpc-spring-boot-starter-demo). 19 | 20 | * **`calculator`**: standard calculator, we parse the calculation form an env variable on the client, and then we send the parcels over to the server. Based on [LogNet/grpc-spring-boot-starter examples](https://github.com/LogNet/grpc-spring-boot-starter/tree/master/grpc-spring-boot-starter-demo). 21 | 22 | * **`health-check`**: implementation of gRPC health checking protocol. Each 5 seconds the server randomly answers with one of the possible status. Proto definition at [oficial grpc documentation](https://github.com/grpc/grpc/blob/master/doc/health-checking.md). 23 | 24 | * **`infinite-pingpong`**: an infinite ping-pong between *two* gRPC services. This emulates the microservice ecosystem where services are both clients and servers at the same time. 25 | 26 | ## Requirements 27 | 28 | Our Docker images are based on [jfloff/docker-thrike](https://github.com/jfloff/docker-thrike) which already everything we need set up, namely: Tomcat, Gradle, Protobuf and gRPC. If you want to bypass Docker and deploy on our own machine, check the [Dockerfile at jfloff/docker-thrike](https://github.com/jfloff/docker-thrike/blob/master/8.5/Dockerfile) for some hints on how to setup your system. 29 | 30 | 31 | ## More infomation 32 | Please refer to the following links for more information: 33 | * [LogNet/grpc-spring-boot-starter](https://github.com/LogNet/grpc-spring-boot-starter) 34 | * [grpc/grpc-java](https://github.com/grpc/grpc-java) 35 | * [google/protobuf-gradle-plugin](https://github.com/google/protobuf-gradle-plugin) 36 | * [gRPC](www.grpc.io) and its [java tutorial](http://www.grpc.io/docs/tutorials/basic/java.html) 37 | * [google/protobuf](https://github.com/google/protobuf) 38 | 39 | 40 | ## License 41 | The code in this repository, unless otherwise noted, is MIT licensed. See the LICENSE file in this repository. -------------------------------------------------------------------------------- /calculator/calculator/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jfloff/thrike:8.5 2 | 3 | LABEL maintainer="jfloff@inesc-id.pt" 4 | 5 | ################### 6 | # Build Server 7 | # 8 | WORKDIR /home/calculator 9 | # cache gradle build dependencies - is less often changed than code 10 | ADD build.gradle /home/calculator 11 | RUN gradle getDependencies 12 | # add all code and build 13 | ADD . /home/calculator 14 | RUN gradle build && \ 15 | cp build/libs/calculator.war /usr/local/tomcat/webapps/ -------------------------------------------------------------------------------- /calculator/calculator/build.gradle: -------------------------------------------------------------------------------- 1 | //////////////////////// 2 | // VARIABLES 3 | // 4 | def gradleVersion = "$System.env.GRADLE_VERSION" 5 | def grpcVersion = "$System.env.GRPC_JAVA_VERSION" 6 | def protobufVersion = "$System.env.PROTOBUF_VERSION" 7 | def protocPath = "$System.env.PROTOC_HOME" 8 | def grpcPluginPath = "$System.env.GRPC_JAVA_PLUGIN_HOME" 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'war' 12 | apply plugin: 'application' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'com.google.protobuf' 15 | 16 | buildscript { 17 | repositories { 18 | mavenCentral() 19 | jcenter() 20 | maven { url "https://plugins.gradle.org/m2/" } 21 | } 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.10.RELEASE" 24 | classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5" 25 | } 26 | } 27 | 28 | repositories { 29 | maven { url "http://repo.springsource.org/libs-snapshot" } 30 | maven { url "http://repo.springsource.org/plugins-release" } 31 | } 32 | 33 | sourceCompatibility = 1.8 34 | targetCompatibility = 1.8 35 | 36 | 37 | dependencies { 38 | // spring 39 | compile "org.springframework.boot:spring-boot-starter-web" 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | 42 | // grpc 43 | compile group: 'io.grpc', name: 'grpc-netty', version: "$grpcVersion" 44 | compile group: 'io.grpc', name: 'grpc-protobuf', version: "$grpcVersion" 45 | compile group: 'io.grpc', name: 'grpc-stub', version: "$grpcVersion" 46 | compile group: 'com.google.api.grpc', name: 'proto-google-common-protos', version: '1.5.0' 47 | compile 'org.lognet:grpc-spring-boot-starter:2.2.0' 48 | 49 | // for application itself 50 | compile group: 'org.projectlombok', name: 'lombok', version: '1.16.20' 51 | 52 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 53 | } 54 | 55 | sourceSets { 56 | main { 57 | proto { 58 | srcDir 'src/main/proto' 59 | } 60 | } 61 | } 62 | 63 | protobuf { 64 | protoc { 65 | path = "${protocPath}" 66 | } 67 | plugins { 68 | grpc { 69 | path = "${grpcPluginPath}" 70 | } 71 | } 72 | 73 | generateProtoTasks { 74 | all().each { task -> 75 | task.builtins { 76 | java { 77 | outputSubDir = 'generated' 78 | } 79 | } 80 | task.plugins { 81 | grpc { 82 | outputSubDir = 'generated' 83 | } 84 | } 85 | } 86 | } 87 | generatedFilesBaseDir = "$projectDir/src/" 88 | } 89 | 90 | task cleanGenerated{ 91 | doFirst{ 92 | delete("$projectDir/src/main/generated") 93 | } 94 | } 95 | clean.dependsOn cleanGenerated 96 | 97 | task getDependencies(type: Exec) { 98 | configurations.testRuntime.files 99 | commandLine 'echo', 'Downloaded all dependencies' 100 | } 101 | 102 | task wrapper(type: Wrapper) { 103 | description = 'Generates gradlew[.bat] scripts' 104 | gradleVersion = "$gradleVersion" 105 | } 106 | 107 | jar { 108 | baseName = 'calculator-service' 109 | version = '0.1.0' 110 | } 111 | 112 | mainClassName = 'calculator.Application' 113 | 114 | defaultTasks 'build' -------------------------------------------------------------------------------- /calculator/calculator/src/main/java/calculator/Application.java: -------------------------------------------------------------------------------- 1 | package calculator; 2 | 3 | 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.boot.builder.SpringApplicationBuilder; 8 | import org.springframework.boot.web.support.SpringBootServletInitializer; 9 | 10 | 11 | @SpringBootApplication 12 | public class Application extends SpringBootServletInitializer { 13 | 14 | @Override 15 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 16 | return application.sources(Application.class); 17 | } 18 | 19 | public static void main(String[] args) throws Exception { 20 | SpringApplication.run(Application.class,args); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /calculator/calculator/src/main/java/calculator/Calculator.java: -------------------------------------------------------------------------------- 1 | package calculator; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | 8 | import io.grpc.stub.StreamObserver; 9 | 10 | import calculator.grpc.CalculatorGrpc; 11 | import calculator.grpc.CalculatorOuterClass; 12 | 13 | @Slf4j 14 | @GRpcService 15 | public class Calculator extends CalculatorGrpc.CalculatorImplBase { 16 | 17 | @Override 18 | public void calculate(CalculatorOuterClass.Math math, StreamObserver result) { 19 | CalculatorOuterClass.Result.Builder resultBuilder = CalculatorOuterClass.Result.newBuilder(); 20 | switch (math.getOperation()){ 21 | case ADD: 22 | resultBuilder.setResult(math.getNumber1()+math.getNumber2()); 23 | break; 24 | case SUBTRACT: 25 | resultBuilder.setResult(math.getNumber1()-math.getNumber2()); 26 | break; 27 | case MULTIPLY: 28 | resultBuilder.setResult(math.getNumber1()*math.getNumber2()); 29 | break; 30 | case DIVIDE: 31 | resultBuilder.setResult(math.getNumber1()/math.getNumber2()); 32 | break; 33 | case UNRECOGNIZED: 34 | break; 35 | } 36 | result.onNext(resultBuilder.build()); 37 | result.onCompleted(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /calculator/calculator/src/main/proto/calculator.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "calculator.grpc"; 4 | 5 | service Calculator { 6 | rpc calculate(Math) returns (Result) {} 7 | } 8 | 9 | message Math { 10 | double number1 = 1; 11 | double number2 = 2; 12 | OperationType operation = 3; 13 | 14 | enum OperationType { 15 | ADD = 0; 16 | SUBTRACT = 1; 17 | MULTIPLY = 2; 18 | DIVIDE = 3; 19 | } 20 | } 21 | 22 | message Result { 23 | double result = 1; 24 | } -------------------------------------------------------------------------------- /calculator/calculator/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | security.basic.enabled=false 2 | management.security.enabled=false -------------------------------------------------------------------------------- /calculator/client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jfloff/thrike:8.5 2 | 3 | LABEL maintainer="jfloff@inesc-id.pt" 4 | 5 | ################### 6 | # Build Server 7 | # 8 | WORKDIR /home/client 9 | # cache gradle build dependencies - is less often changed than code 10 | ADD build.gradle /home/client 11 | RUN gradle getDependencies 12 | # add all code and build 13 | ADD . /home/client 14 | RUN gradle build && \ 15 | cp build/libs/client.war /usr/local/tomcat/webapps/ 16 | -------------------------------------------------------------------------------- /calculator/client/build.gradle: -------------------------------------------------------------------------------- 1 | //////////////////////// 2 | // VARIABLES 3 | // 4 | def gradleVersion = "$System.env.GRADLE_VERSION" 5 | def grpcVersion = "$System.env.GRPC_JAVA_VERSION" 6 | def protobufVersion = "$System.env.PROTOBUF_VERSION" 7 | def protocPath = "$System.env.PROTOC_HOME" 8 | def grpcPluginPath = "$System.env.GRPC_JAVA_PLUGIN_HOME" 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'war' 12 | apply plugin: 'application' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'com.google.protobuf' 15 | 16 | buildscript { 17 | repositories { 18 | mavenCentral() 19 | jcenter() 20 | maven { url "https://plugins.gradle.org/m2/" } 21 | } 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.10.RELEASE" 24 | classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5" 25 | } 26 | } 27 | 28 | repositories { 29 | maven { url "http://repo.springsource.org/libs-snapshot" } 30 | maven { url "http://repo.springsource.org/plugins-release" } 31 | } 32 | 33 | sourceCompatibility = 1.8 34 | targetCompatibility = 1.8 35 | 36 | 37 | dependencies { 38 | // spring 39 | compile "org.springframework.boot:spring-boot-starter-web" 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | 42 | // grpc 43 | compile group: 'io.grpc', name: 'grpc-netty', version: "$grpcVersion" 44 | compile group: 'io.grpc', name: 'grpc-protobuf', version: "$grpcVersion" 45 | compile group: 'io.grpc', name: 'grpc-stub', version: "$grpcVersion" 46 | compile group: 'com.google.api.grpc', name: 'proto-google-common-protos', version: '1.5.0' 47 | compile 'org.lognet:grpc-spring-boot-starter:2.2.0' 48 | 49 | // for application itself 50 | compile group: 'org.projectlombok', name: 'lombok', version: '1.16.20' 51 | 52 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 53 | } 54 | 55 | sourceSets { 56 | main { 57 | proto { 58 | srcDir 'src/main/proto' 59 | } 60 | } 61 | } 62 | 63 | protobuf { 64 | protoc { 65 | path = "${protocPath}" 66 | } 67 | plugins { 68 | grpc { 69 | path = "${grpcPluginPath}" 70 | } 71 | } 72 | 73 | generateProtoTasks { 74 | ofSourceSet('main').each { task -> 75 | task.builtins { 76 | java{ 77 | outputSubDir = 'generated' 78 | } 79 | } 80 | task.plugins { 81 | grpc { 82 | outputSubDir = 'generated' 83 | } 84 | } 85 | } 86 | } 87 | generatedFilesBaseDir = "$projectDir/src/" 88 | } 89 | 90 | task cleanGenerated{ 91 | doFirst{ 92 | delete("$projectDir/src/main/generated") 93 | } 94 | } 95 | clean.dependsOn cleanGenerated 96 | 97 | task getDependencies(type: Exec) { 98 | configurations.testRuntime.files 99 | commandLine 'echo', 'Downloaded all dependencies' 100 | } 101 | 102 | task wrapper(type: Wrapper) { 103 | description = 'Generates gradlew[.bat] scripts' 104 | gradleVersion = "$gradleVersion" 105 | } 106 | 107 | jar { 108 | baseName = 'client-service' 109 | version = '0.1.0' 110 | } 111 | 112 | mainClassName = 'client.Application' 113 | 114 | defaultTasks 'build' -------------------------------------------------------------------------------- /calculator/client/src/main/java/client/Application.java: -------------------------------------------------------------------------------- 1 | package client; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.boot.web.support.SpringBootServletInitializer; 7 | 8 | import org.lognet.springboot.grpc.GRpcService; 9 | import io.grpc.stub.StreamObserver; 10 | 11 | 12 | @SpringBootApplication 13 | public class Application extends SpringBootServletInitializer { 14 | 15 | // @Override 16 | // protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 17 | // return application.sources(Application.class); 18 | // } 19 | 20 | public static void main(String[] args) throws Exception { 21 | SpringApplication.run(Application.class,args); 22 | } 23 | } -------------------------------------------------------------------------------- /calculator/client/src/main/java/client/Client.java: -------------------------------------------------------------------------------- 1 | package client; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.boot.context.event.ApplicationReadyEvent; 7 | import org.springframework.context.event.EventListener; 8 | 9 | import io.grpc.stub.StreamObserver; 10 | import io.grpc.ManagedChannel; 11 | import io.grpc.ManagedChannelBuilder; 12 | import io.grpc.StatusRuntimeException; 13 | 14 | import calculator.grpc.CalculatorGrpc; 15 | import calculator.grpc.CalculatorOuterClass; 16 | 17 | 18 | @Slf4j 19 | @Component 20 | public class Client { 21 | private final ManagedChannel channel; 22 | private final CalculatorGrpc.CalculatorBlockingStub stub; 23 | private String calculation; 24 | 25 | public Client() { 26 | this.calculation = System.getenv("CALCULATION"); 27 | this.channel = ManagedChannelBuilder.forAddress("calculator", 6565) 28 | // Channels are secure by default (via SSL/TLS). 29 | // For the example we disable TLS to avoid needing certificates. 30 | .usePlaintext(true) 31 | .build(); 32 | this.stub = CalculatorGrpc.newBlockingStub(channel); 33 | } 34 | 35 | // this simulates a new client sending a message 36 | // realistic these clients come all the time 37 | @EventListener(ApplicationReadyEvent.class) 38 | public void startup() throws InterruptedException { 39 | this.math(this.calculation); 40 | System.exit(0); 41 | } 42 | 43 | private CalculatorOuterClass.Math.OperationType stringToOperationType(String s) { 44 | switch (s) { 45 | case "+": 46 | return CalculatorOuterClass.Math.OperationType.ADD; 47 | case "-": 48 | return CalculatorOuterClass.Math.OperationType.SUBTRACT; 49 | case "*": 50 | return CalculatorOuterClass.Math.OperationType.MULTIPLY; 51 | case "/": 52 | return CalculatorOuterClass.Math.OperationType.DIVIDE; 53 | default: 54 | System.exit(-1); 55 | return null; 56 | } 57 | } 58 | 59 | public void math(String calculation) throws InterruptedException { 60 | String[] tokens = calculation.split("((?<=\\+)|(?=\\+))|((?<=-)|(?=-))|((?<=\\*)|(?=\\*))|((?<=/)|(?=/))"); 61 | 62 | CalculatorOuterClass.Math math = CalculatorOuterClass.Math.newBuilder() 63 | .setNumber1(Integer.parseInt(tokens[0])) 64 | .setNumber2(Integer.parseInt(tokens[2])) 65 | .setOperation(stringToOperationType(tokens[1])) 66 | .build(); 67 | 68 | // this should be either replaced by a health-checking or 69 | // even better a eureka/zookeeper service discovery system 70 | while(true){ 71 | try { 72 | CalculatorOuterClass.Result result = stub.calculate(math); 73 | log.info(calculation + " = " + result.getResult()); 74 | return; 75 | } catch (StatusRuntimeException e) { 76 | log.info("[ERROR] " + e.getMessage()); 77 | Thread.sleep(1000); 78 | } 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /calculator/client/src/main/proto/calculator.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "calculator.grpc"; 4 | 5 | service Calculator { 6 | rpc calculate(Math) returns (Result) {} 7 | } 8 | 9 | message Math { 10 | double number1 = 1; 11 | double number2 = 2; 12 | OperationType operation = 3; 13 | 14 | enum OperationType { 15 | ADD = 0; 16 | SUBTRACT = 1; 17 | MULTIPLY = 2; 18 | DIVIDE = 3; 19 | } 20 | } 21 | 22 | message Result { 23 | double result = 1; 24 | } -------------------------------------------------------------------------------- /calculator/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | security.basic.enabled=false 2 | management.security.enabled=false -------------------------------------------------------------------------------- /calculator/docker-compose.yml: -------------------------------------------------------------------------------- 1 | 2 | version: '3' 3 | services: 4 | calculator: 5 | build: ./calculator 6 | volumes: 7 | - './calculator:/home/calculator' 8 | expose: 9 | - '6565' 10 | 11 | client: 12 | build: ./client 13 | # command: bash -c "sleep 30 && catalina.sh run" 14 | volumes: 15 | - './client:/home/client' 16 | environment: 17 | CALCULATION: '10/2' 18 | -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jfloff/thrike:8.5 2 | 3 | LABEL maintainer="jfloff@inesc-id.pt" 4 | 5 | ################### 6 | # Build Server 7 | # 8 | WORKDIR /home/client 9 | # cache gradle build dependencies - is less often changed than code 10 | ADD build.gradle /home/client 11 | RUN gradle getDependencies 12 | # add all code and build 13 | ADD . /home/client 14 | RUN gradle build && \ 15 | cp build/libs/client.war /usr/local/tomcat/webapps/ 16 | -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/client/build.gradle: -------------------------------------------------------------------------------- 1 | //////////////////////// 2 | // VARIABLES 3 | // 4 | def gradleVersion = "$System.env.GRADLE_VERSION" 5 | def grpcVersion = "$System.env.GRPC_JAVA_VERSION" 6 | def protobufVersion = "$System.env.PROTOBUF_VERSION" 7 | def protocPath = "$System.env.PROTOC_HOME" 8 | def grpcPluginPath = "$System.env.GRPC_JAVA_PLUGIN_HOME" 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'war' 12 | apply plugin: 'application' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'com.google.protobuf' 15 | 16 | buildscript { 17 | repositories { 18 | mavenCentral() 19 | jcenter() 20 | maven { url "https://plugins.gradle.org/m2/" } 21 | } 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.10.RELEASE" 24 | classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5" 25 | } 26 | } 27 | 28 | repositories { 29 | maven { url "http://repo.springsource.org/libs-snapshot" } 30 | maven { url "http://repo.springsource.org/plugins-release" } 31 | } 32 | 33 | sourceCompatibility = 1.8 34 | targetCompatibility = 1.8 35 | 36 | 37 | dependencies { 38 | // spring 39 | compile "org.springframework.boot:spring-boot-starter-web" 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | 42 | // grpc 43 | compile group: 'io.grpc', name: 'grpc-netty', version: "$grpcVersion" 44 | compile group: 'io.grpc', name: 'grpc-protobuf', version: "$grpcVersion" 45 | compile group: 'io.grpc', name: 'grpc-stub', version: "$grpcVersion" 46 | compile group: 'com.google.api.grpc', name: 'proto-google-common-protos', version: '1.5.0' 47 | compile 'org.lognet:grpc-spring-boot-starter:2.2.0' 48 | 49 | // for application itself 50 | compile group: 'org.projectlombok', name: 'lombok', version: '1.16.20' 51 | 52 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 53 | } 54 | 55 | sourceSets { 56 | main { 57 | proto { 58 | srcDir 'src/main/proto' 59 | } 60 | } 61 | } 62 | 63 | protobuf { 64 | protoc { 65 | path = "${protocPath}" 66 | } 67 | plugins { 68 | grpc { 69 | path = "${grpcPluginPath}" 70 | } 71 | } 72 | 73 | generateProtoTasks { 74 | ofSourceSet('main').each { task -> 75 | task.builtins { 76 | java{ 77 | outputSubDir = 'generated' 78 | } 79 | } 80 | task.plugins { 81 | grpc { 82 | outputSubDir = 'generated' 83 | } 84 | } 85 | } 86 | } 87 | generatedFilesBaseDir = "$projectDir/src/" 88 | } 89 | 90 | task cleanGenerated{ 91 | doFirst{ 92 | delete("$projectDir/src/main/generated") 93 | } 94 | } 95 | clean.dependsOn cleanGenerated 96 | 97 | task getDependencies(type: Exec) { 98 | configurations.testRuntime.files 99 | commandLine 'echo', 'Downloaded all dependencies' 100 | } 101 | 102 | task wrapper(type: Wrapper) { 103 | description = 'Generates gradlew[.bat] scripts' 104 | gradleVersion = "$gradleVersion" 105 | } 106 | 107 | jar { 108 | baseName = 'client-service' 109 | version = '0.1.0' 110 | } 111 | 112 | mainClassName = 'client.Application' 113 | 114 | defaultTasks 'build' -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/client/src/main/java/client/Application.java: -------------------------------------------------------------------------------- 1 | package client; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.boot.web.support.SpringBootServletInitializer; 7 | 8 | import org.lognet.springboot.grpc.GRpcService; 9 | import io.grpc.stub.StreamObserver; 10 | 11 | 12 | @SpringBootApplication 13 | public class Application extends SpringBootServletInitializer { 14 | 15 | @Override 16 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 17 | return application.sources(Application.class); 18 | } 19 | 20 | public static void main(String[] args) throws Exception { 21 | SpringApplication.run(Application.class,args); 22 | } 23 | } -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/client/src/main/java/client/Client.java: -------------------------------------------------------------------------------- 1 | package client; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.boot.context.event.ApplicationReadyEvent; 7 | import org.springframework.context.event.EventListener; 8 | 9 | import io.grpc.stub.StreamObserver; 10 | import io.grpc.ManagedChannel; 11 | import io.grpc.ManagedChannelBuilder; 12 | import io.grpc.StatusRuntimeException; 13 | 14 | import greet.grpc.GreeterGrpc; 15 | import greet.grpc.GreeterOuterClass; 16 | 17 | 18 | @Slf4j 19 | @Component 20 | public class Client { 21 | private final ManagedChannel channel; 22 | private final GreeterGrpc.GreeterBlockingStub stub; 23 | private String name; 24 | 25 | public Client() { 26 | this.name = System.getenv("GREET_NAME"); 27 | // we should get this info from a service like eureka 28 | this.channel = ManagedChannelBuilder.forAddress("server", 6565) 29 | // Channels are secure by default (via SSL/TLS). 30 | // For the example we disable TLS to avoid needing certificates. 31 | .usePlaintext(true) 32 | .build(); 33 | this.stub = GreeterGrpc.newBlockingStub(channel); 34 | } 35 | 36 | // this simulates a new client sending a message 37 | // realistic these clients come all the time 38 | @EventListener(ApplicationReadyEvent.class) 39 | public void startup() throws InterruptedException { 40 | this.greet(this.name); 41 | System.exit(0); 42 | } 43 | 44 | public void greet(String name) throws InterruptedException { 45 | log.info("Will try to greet " + name + " ..."); 46 | 47 | // build message 48 | GreeterOuterClass.Name greetName = GreeterOuterClass.Name.newBuilder().setName(name).build(); 49 | 50 | // this should be either replaced by a health-checking or 51 | // even better a eureka/zookeeper service discovery system 52 | while(true){ 53 | try { 54 | GreeterOuterClass.Greeting greeting = stub.greet(greetName); 55 | log.info(greeting.getMessage()); 56 | return; 57 | } catch (StatusRuntimeException e) { 58 | log.info("ERROR ON GREET: " + e.getMessage()); 59 | Thread.sleep(1000); 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/client/src/main/proto/greeter.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "greet.grpc"; 4 | 5 | // The greeter service definition. 6 | service Greeter { 7 | rpc greet ( Name ) returns ( Greeting ) {} 8 | } 9 | 10 | message Name { 11 | string name = 1; 12 | } 13 | 14 | message Greeting { 15 | string message = 1; 16 | } 17 | -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | security.basic.enabled=false 2 | management.security.enabled=false -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/docker-compose.yml: -------------------------------------------------------------------------------- 1 | 2 | version: '3' 3 | services: 4 | server: 5 | build: ./server 6 | volumes: 7 | - './server:/home/server' 8 | expose: 9 | - '6565' 10 | 11 | client: 12 | build: ./client 13 | # command: bash -c "sleep 30 && catalina.sh run" 14 | volumes: 15 | - './client:/home/client' 16 | environment: 17 | GREET_NAME: 'Kenobi' 18 | -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jfloff/thrike:8.5 2 | 3 | LABEL maintainer="jfloff@inesc-id.pt" 4 | 5 | ################### 6 | # Build Server 7 | # 8 | WORKDIR /home/server 9 | # cache gradle build dependencies - is less often changed than code 10 | ADD build.gradle /home/server 11 | RUN gradle getDependencies 12 | # add all code and build 13 | ADD . /home/server 14 | RUN gradle build && \ 15 | cp build/libs/server.war /usr/local/tomcat/webapps/ -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/server/build.gradle: -------------------------------------------------------------------------------- 1 | //////////////////////// 2 | // VARIABLES 3 | // 4 | def gradleVersion = "$System.env.GRADLE_VERSION" 5 | def grpcVersion = "$System.env.GRPC_JAVA_VERSION" 6 | def protobufVersion = "$System.env.PROTOBUF_VERSION" 7 | def protocPath = "$System.env.PROTOC_HOME" 8 | def grpcPluginPath = "$System.env.GRPC_JAVA_PLUGIN_HOME" 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'war' 12 | apply plugin: 'application' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'com.google.protobuf' 15 | 16 | buildscript { 17 | repositories { 18 | mavenCentral() 19 | jcenter() 20 | maven { url "https://plugins.gradle.org/m2/" } 21 | } 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.10.RELEASE" 24 | classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5" 25 | } 26 | } 27 | 28 | repositories { 29 | maven { url "http://repo.springsource.org/libs-snapshot" } 30 | maven { url "http://repo.springsource.org/plugins-release" } 31 | } 32 | 33 | sourceCompatibility = 1.8 34 | targetCompatibility = 1.8 35 | 36 | 37 | dependencies { 38 | // spring 39 | compile "org.springframework.boot:spring-boot-starter-web" 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | 42 | // grpc 43 | compile group: 'io.grpc', name: 'grpc-netty', version: "$grpcVersion" 44 | compile group: 'io.grpc', name: 'grpc-protobuf', version: "$grpcVersion" 45 | compile group: 'io.grpc', name: 'grpc-stub', version: "$grpcVersion" 46 | compile group: 'com.google.api.grpc', name: 'proto-google-common-protos', version: '1.5.0' 47 | compile 'org.lognet:grpc-spring-boot-starter:2.2.0' 48 | 49 | // for application itself 50 | compile group: 'org.projectlombok', name: 'lombok', version: '1.16.20' 51 | 52 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 53 | } 54 | 55 | sourceSets { 56 | main { 57 | proto { 58 | srcDir 'src/main/proto' 59 | } 60 | } 61 | } 62 | 63 | protobuf { 64 | protoc { 65 | path = "${protocPath}" 66 | } 67 | plugins { 68 | grpc { 69 | path = "${grpcPluginPath}" 70 | } 71 | } 72 | 73 | generateProtoTasks { 74 | all().each { task -> 75 | task.builtins { 76 | java { 77 | outputSubDir = 'generated' 78 | } 79 | } 80 | task.plugins { 81 | grpc { 82 | outputSubDir = 'generated' 83 | } 84 | } 85 | } 86 | } 87 | generatedFilesBaseDir = "$projectDir/src/" 88 | } 89 | 90 | task cleanGenerated{ 91 | doFirst{ 92 | delete("$projectDir/src/main/generated") 93 | } 94 | } 95 | clean.dependsOn cleanGenerated 96 | 97 | task getDependencies(type: Exec) { 98 | configurations.testRuntime.files 99 | commandLine 'echo', 'Downloaded all dependencies' 100 | } 101 | 102 | task wrapper(type: Wrapper) { 103 | description = 'Generates gradlew[.bat] scripts' 104 | gradleVersion = "$gradleVersion" 105 | } 106 | 107 | jar { 108 | baseName = 'server-service' 109 | version = '0.1.0' 110 | } 111 | 112 | mainClassName = 'server.Application' 113 | 114 | defaultTasks 'build' -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/server/src/main/java/server/Application.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.boot.builder.SpringApplicationBuilder; 8 | import org.springframework.boot.web.support.SpringBootServletInitializer; 9 | import org.springframework.context.annotation.Bean; 10 | 11 | 12 | @SpringBootApplication 13 | public class Application extends SpringBootServletInitializer { 14 | 15 | @Bean 16 | public Server startServer() { 17 | return new Server(); 18 | } 19 | 20 | @Override 21 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 22 | return application.sources(Application.class); 23 | } 24 | 25 | public static void main(String[] args) throws Exception { 26 | SpringApplication.run(Application.class,args); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/server/src/main/java/server/LogInterceptor.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.stereotype.Component; 5 | 6 | import io.grpc.Metadata; 7 | import io.grpc.ServerCall; 8 | import io.grpc.ServerCallHandler; 9 | import io.grpc.ServerInterceptor; 10 | 11 | import org.lognet.springboot.grpc.GRpcGlobalInterceptor; 12 | 13 | 14 | @Slf4j 15 | @Component 16 | public class LogInterceptor implements ServerInterceptor { 17 | 18 | @Override 19 | public ServerCall.Listener interceptCall( 20 | ServerCall call, Metadata headers, 21 | ServerCallHandler next) 22 | { 23 | log.info("I AM a Spring bean interceptor ..."); 24 | log.info(call.getMethodDescriptor().getFullMethodName()); 25 | log.info(call.getMethodDescriptor().getFullMethodName()); 26 | return next.startCall(call, headers); 27 | } 28 | } -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/server/src/main/java/server/NonBeanInterceptor.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | import io.grpc.Metadata; 4 | import io.grpc.ServerCall; 5 | import io.grpc.ServerCallHandler; 6 | import io.grpc.ServerInterceptor; 7 | 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | @Slf4j 11 | public class NonBeanInterceptor implements ServerInterceptor { 12 | 13 | @Override 14 | public ServerCall.Listener interceptCall( 15 | ServerCall call, Metadata headers, 16 | ServerCallHandler next) 17 | { 18 | log.info("I am NOT a Spring bean interceptor and still being invoked..."); 19 | log.info(call.getMethodDescriptor().getFullMethodName()); 20 | log.info(call.getMethodDescriptor().getFullMethodName()); 21 | return next.startCall(call, headers); 22 | } 23 | } -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/server/src/main/java/server/Server.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | 8 | import greet.grpc.GreeterGrpc; 9 | import greet.grpc.GreeterOuterClass; 10 | import io.grpc.stub.StreamObserver; 11 | 12 | @Slf4j 13 | @GRpcService(interceptors = { LogInterceptor.class, NonBeanInterceptor.class }) 14 | public class Server extends GreeterGrpc.GreeterImplBase { 15 | 16 | @Override 17 | public void greet(GreeterOuterClass.Name request, StreamObserver responseObserver) { 18 | log.info(request.getName() + ": Hello there!"); 19 | String message = "General Grievous: General " + request.getName() + "! You are a bold one..."; 20 | final GreeterOuterClass.Greeting.Builder replyBuilder = GreeterOuterClass.Greeting.newBuilder().setMessage(message); 21 | responseObserver.onNext(replyBuilder.build()); 22 | responseObserver.onCompleted(); 23 | } 24 | } -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/server/src/main/proto/greeter.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "greet.grpc"; 4 | 5 | // The greeter service definition. 6 | service Greeter { 7 | rpc greet ( Name ) returns ( Greeting ) {} 8 | } 9 | 10 | message Name { 11 | string name = 1; 12 | } 13 | 14 | message Greeting { 15 | string message = 1; 16 | } 17 | -------------------------------------------------------------------------------- /greeter-bean-with-interceptors/server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | security.basic.enabled=false 2 | management.security.enabled=false -------------------------------------------------------------------------------- /greeter-with-interceptors/client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jfloff/thrike:8.5 2 | 3 | LABEL maintainer="jfloff@inesc-id.pt" 4 | 5 | ################### 6 | # Build Server 7 | # 8 | WORKDIR /home/client 9 | # cache gradle build dependencies - is less often changed than code 10 | ADD build.gradle /home/client 11 | RUN gradle getDependencies 12 | # add all code and build 13 | ADD . /home/client 14 | RUN gradle build && \ 15 | cp build/libs/client.war /usr/local/tomcat/webapps/ 16 | -------------------------------------------------------------------------------- /greeter-with-interceptors/client/build.gradle: -------------------------------------------------------------------------------- 1 | //////////////////////// 2 | // VARIABLES 3 | // 4 | def gradleVersion = "$System.env.GRADLE_VERSION" 5 | def grpcVersion = "$System.env.GRPC_JAVA_VERSION" 6 | def protobufVersion = "$System.env.PROTOBUF_VERSION" 7 | def protocPath = "$System.env.PROTOC_HOME" 8 | def grpcPluginPath = "$System.env.GRPC_JAVA_PLUGIN_HOME" 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'war' 12 | apply plugin: 'application' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'com.google.protobuf' 15 | 16 | buildscript { 17 | repositories { 18 | mavenCentral() 19 | jcenter() 20 | maven { url "https://plugins.gradle.org/m2/" } 21 | } 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.10.RELEASE" 24 | classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5" 25 | } 26 | } 27 | 28 | repositories { 29 | maven { url "http://repo.springsource.org/libs-snapshot" } 30 | maven { url "http://repo.springsource.org/plugins-release" } 31 | } 32 | 33 | sourceCompatibility = 1.8 34 | targetCompatibility = 1.8 35 | 36 | 37 | dependencies { 38 | // spring 39 | compile "org.springframework.boot:spring-boot-starter-web" 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | 42 | // grpc 43 | compile group: 'io.grpc', name: 'grpc-netty', version: "$grpcVersion" 44 | compile group: 'io.grpc', name: 'grpc-protobuf', version: "$grpcVersion" 45 | compile group: 'io.grpc', name: 'grpc-stub', version: "$grpcVersion" 46 | compile group: 'com.google.api.grpc', name: 'proto-google-common-protos', version: '1.5.0' 47 | compile 'org.lognet:grpc-spring-boot-starter:2.2.0' 48 | 49 | // for application itself 50 | compile group: 'org.projectlombok', name: 'lombok', version: '1.16.20' 51 | 52 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 53 | } 54 | 55 | sourceSets { 56 | main { 57 | proto { 58 | srcDir 'src/main/proto' 59 | } 60 | } 61 | } 62 | 63 | protobuf { 64 | protoc { 65 | path = "${protocPath}" 66 | } 67 | plugins { 68 | grpc { 69 | path = "${grpcPluginPath}" 70 | } 71 | } 72 | 73 | generateProtoTasks { 74 | ofSourceSet('main').each { task -> 75 | task.builtins { 76 | java{ 77 | outputSubDir = 'generated' 78 | } 79 | } 80 | task.plugins { 81 | grpc { 82 | outputSubDir = 'generated' 83 | } 84 | } 85 | } 86 | } 87 | generatedFilesBaseDir = "$projectDir/src/" 88 | } 89 | 90 | task cleanGenerated{ 91 | doFirst{ 92 | delete("$projectDir/src/main/generated") 93 | } 94 | } 95 | clean.dependsOn cleanGenerated 96 | 97 | task getDependencies(type: Exec) { 98 | configurations.testRuntime.files 99 | commandLine 'echo', 'Downloaded all dependencies' 100 | } 101 | 102 | task wrapper(type: Wrapper) { 103 | description = 'Generates gradlew[.bat] scripts' 104 | gradleVersion = "$gradleVersion" 105 | } 106 | 107 | jar { 108 | baseName = 'client-service' 109 | version = '0.1.0' 110 | } 111 | 112 | mainClassName = 'client.Application' 113 | 114 | defaultTasks 'build' -------------------------------------------------------------------------------- /greeter-with-interceptors/client/src/main/java/client/Application.java: -------------------------------------------------------------------------------- 1 | package client; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.boot.web.support.SpringBootServletInitializer; 7 | 8 | import org.lognet.springboot.grpc.GRpcService; 9 | import io.grpc.stub.StreamObserver; 10 | 11 | 12 | @SpringBootApplication 13 | public class Application extends SpringBootServletInitializer { 14 | 15 | @Override 16 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 17 | return application.sources(Application.class); 18 | } 19 | 20 | public static void main(String[] args) throws Exception { 21 | SpringApplication.run(Application.class,args); 22 | } 23 | } -------------------------------------------------------------------------------- /greeter-with-interceptors/client/src/main/java/client/Client.java: -------------------------------------------------------------------------------- 1 | package client; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.boot.context.event.ApplicationReadyEvent; 7 | import org.springframework.context.event.EventListener; 8 | 9 | import io.grpc.stub.StreamObserver; 10 | import io.grpc.ManagedChannel; 11 | import io.grpc.ManagedChannelBuilder; 12 | import io.grpc.StatusRuntimeException; 13 | 14 | import greet.grpc.GreeterGrpc; 15 | import greet.grpc.GreeterOuterClass; 16 | 17 | 18 | @Slf4j 19 | @Component 20 | public class Client { 21 | private final ManagedChannel channel; 22 | private final GreeterGrpc.GreeterBlockingStub stub; 23 | private String name; 24 | 25 | public Client() { 26 | this.name = System.getenv("GREET_NAME"); 27 | // we should get this info from a service like eureka 28 | this.channel = ManagedChannelBuilder.forAddress("server", 6565) 29 | // Channels are secure by default (via SSL/TLS). 30 | // For the example we disable TLS to avoid needing certificates. 31 | .usePlaintext(true) 32 | .build(); 33 | this.stub = GreeterGrpc.newBlockingStub(channel); 34 | } 35 | 36 | // this simulates a new client sending a message 37 | // realistic these clients come all the time 38 | @EventListener(ApplicationReadyEvent.class) 39 | public void startup() throws InterruptedException { 40 | this.greet(this.name); 41 | System.exit(0); 42 | } 43 | 44 | public void greet(String name) throws InterruptedException { 45 | log.info("Will try to greet " + name + " ..."); 46 | 47 | // build message 48 | GreeterOuterClass.Name greetName = GreeterOuterClass.Name.newBuilder().setName(name).build(); 49 | 50 | // this should be either replaced by a health-checking or 51 | // even better a eureka/zookeeper service discovery system 52 | while(true){ 53 | try { 54 | GreeterOuterClass.Greeting greeting = stub.greet(greetName); 55 | log.info(greeting.getMessage()); 56 | return; 57 | } catch (StatusRuntimeException e) { 58 | log.info("ERROR ON GREET: " + e.getMessage()); 59 | Thread.sleep(1000); 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /greeter-with-interceptors/client/src/main/proto/greeter.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "greet.grpc"; 4 | 5 | // The greeter service definition. 6 | service Greeter { 7 | rpc greet ( Name ) returns ( Greeting ) {} 8 | } 9 | 10 | message Name { 11 | string name = 1; 12 | } 13 | 14 | message Greeting { 15 | string message = 1; 16 | } 17 | -------------------------------------------------------------------------------- /greeter-with-interceptors/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | security.basic.enabled=false 2 | management.security.enabled=false -------------------------------------------------------------------------------- /greeter-with-interceptors/docker-compose.yml: -------------------------------------------------------------------------------- 1 | 2 | version: '3' 3 | services: 4 | server: 5 | build: ./server 6 | volumes: 7 | - './server:/home/server' 8 | expose: 9 | - '6565' 10 | 11 | client: 12 | build: ./client 13 | # command: bash -c "sleep 30 && catalina.sh run" 14 | volumes: 15 | - './client:/home/client' 16 | environment: 17 | GREET_NAME: 'Kenobi' 18 | -------------------------------------------------------------------------------- /greeter-with-interceptors/server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jfloff/thrike:8.5 2 | 3 | LABEL maintainer="jfloff@inesc-id.pt" 4 | 5 | ################### 6 | # Build Server 7 | # 8 | WORKDIR /home/server 9 | # cache gradle build dependencies - is less often changed than code 10 | ADD build.gradle /home/server 11 | RUN gradle getDependencies 12 | # add all code and build 13 | ADD . /home/server 14 | RUN gradle build && \ 15 | cp build/libs/server.war /usr/local/tomcat/webapps/ -------------------------------------------------------------------------------- /greeter-with-interceptors/server/build.gradle: -------------------------------------------------------------------------------- 1 | //////////////////////// 2 | // VARIABLES 3 | // 4 | def gradleVersion = "$System.env.GRADLE_VERSION" 5 | def grpcVersion = "$System.env.GRPC_JAVA_VERSION" 6 | def protobufVersion = "$System.env.PROTOBUF_VERSION" 7 | def protocPath = "$System.env.PROTOC_HOME" 8 | def grpcPluginPath = "$System.env.GRPC_JAVA_PLUGIN_HOME" 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'war' 12 | apply plugin: 'application' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'com.google.protobuf' 15 | 16 | buildscript { 17 | repositories { 18 | mavenCentral() 19 | jcenter() 20 | maven { url "https://plugins.gradle.org/m2/" } 21 | } 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.10.RELEASE" 24 | classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5" 25 | } 26 | } 27 | 28 | repositories { 29 | maven { url "http://repo.springsource.org/libs-snapshot" } 30 | maven { url "http://repo.springsource.org/plugins-release" } 31 | } 32 | 33 | sourceCompatibility = 1.8 34 | targetCompatibility = 1.8 35 | 36 | 37 | dependencies { 38 | // spring 39 | compile "org.springframework.boot:spring-boot-starter-web" 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | 42 | // grpc 43 | compile group: 'io.grpc', name: 'grpc-netty', version: "$grpcVersion" 44 | compile group: 'io.grpc', name: 'grpc-protobuf', version: "$grpcVersion" 45 | compile group: 'io.grpc', name: 'grpc-stub', version: "$grpcVersion" 46 | compile group: 'com.google.api.grpc', name: 'proto-google-common-protos', version: '1.5.0' 47 | compile 'org.lognet:grpc-spring-boot-starter:2.2.0' 48 | 49 | // for application itself 50 | compile group: 'org.projectlombok', name: 'lombok', version: '1.16.20' 51 | 52 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 53 | } 54 | 55 | sourceSets { 56 | main { 57 | proto { 58 | srcDir 'src/main/proto' 59 | } 60 | } 61 | } 62 | 63 | protobuf { 64 | protoc { 65 | path = "${protocPath}" 66 | } 67 | plugins { 68 | grpc { 69 | path = "${grpcPluginPath}" 70 | } 71 | } 72 | 73 | generateProtoTasks { 74 | all().each { task -> 75 | task.builtins { 76 | java { 77 | outputSubDir = 'generated' 78 | } 79 | } 80 | task.plugins { 81 | grpc { 82 | outputSubDir = 'generated' 83 | } 84 | } 85 | } 86 | } 87 | generatedFilesBaseDir = "$projectDir/src/" 88 | } 89 | 90 | task cleanGenerated{ 91 | doFirst{ 92 | delete("$projectDir/src/main/generated") 93 | } 94 | } 95 | clean.dependsOn cleanGenerated 96 | 97 | task getDependencies(type: Exec) { 98 | configurations.testRuntime.files 99 | commandLine 'echo', 'Downloaded all dependencies' 100 | } 101 | 102 | task wrapper(type: Wrapper) { 103 | description = 'Generates gradlew[.bat] scripts' 104 | gradleVersion = "$gradleVersion" 105 | } 106 | 107 | jar { 108 | baseName = 'server-service' 109 | version = '0.1.0' 110 | } 111 | 112 | mainClassName = 'server.Application' 113 | 114 | defaultTasks 'build' -------------------------------------------------------------------------------- /greeter-with-interceptors/server/src/main/java/server/Application.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.boot.builder.SpringApplicationBuilder; 8 | import org.springframework.boot.web.support.SpringBootServletInitializer; 9 | import org.springframework.context.annotation.Bean; 10 | 11 | 12 | @SpringBootApplication 13 | public class Application extends SpringBootServletInitializer { 14 | 15 | // @Bean 16 | // public Server service() { 17 | // return new Server(); 18 | // } 19 | 20 | @Override 21 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 22 | return application.sources(Application.class); 23 | } 24 | 25 | public static void main(String[] args) throws Exception { 26 | SpringApplication.run(Application.class,args); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /greeter-with-interceptors/server/src/main/java/server/LogInterceptor.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.springframework.stereotype.Component; 5 | 6 | import io.grpc.Metadata; 7 | import io.grpc.ServerCall; 8 | import io.grpc.ServerCallHandler; 9 | import io.grpc.ServerInterceptor; 10 | 11 | import org.lognet.springboot.grpc.GRpcGlobalInterceptor; 12 | 13 | 14 | @Slf4j 15 | @Component 16 | public class LogInterceptor implements ServerInterceptor { 17 | 18 | @Override 19 | public ServerCall.Listener interceptCall( 20 | ServerCall call, Metadata headers, 21 | ServerCallHandler next) 22 | { 23 | log.info("I AM a Spring bean interceptor ..."); 24 | log.info(call.getMethodDescriptor().getFullMethodName()); 25 | log.info(call.getMethodDescriptor().getFullMethodName()); 26 | return next.startCall(call, headers); 27 | } 28 | } -------------------------------------------------------------------------------- /greeter-with-interceptors/server/src/main/java/server/NonBeanInterceptor.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | import io.grpc.Metadata; 4 | import io.grpc.ServerCall; 5 | import io.grpc.ServerCallHandler; 6 | import io.grpc.ServerInterceptor; 7 | 8 | import lombok.extern.slf4j.Slf4j; 9 | 10 | @Slf4j 11 | public class NonBeanInterceptor implements ServerInterceptor { 12 | 13 | @Override 14 | public ServerCall.Listener interceptCall( 15 | ServerCall call, Metadata headers, 16 | ServerCallHandler next) 17 | { 18 | log.info("I am NOT a Spring bean interceptor and still being invoked..."); 19 | log.info(call.getMethodDescriptor().getFullMethodName()); 20 | log.info(call.getMethodDescriptor().getFullMethodName()); 21 | return next.startCall(call, headers); 22 | } 23 | } -------------------------------------------------------------------------------- /greeter-with-interceptors/server/src/main/java/server/Server.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | 8 | import greet.grpc.GreeterGrpc; 9 | import greet.grpc.GreeterOuterClass; 10 | import io.grpc.stub.StreamObserver; 11 | 12 | @Slf4j 13 | @GRpcService(interceptors = { LogInterceptor.class , NonBeanInterceptor.class }) 14 | public class Server extends GreeterGrpc.GreeterImplBase { 15 | 16 | @Override 17 | public void greet(GreeterOuterClass.Name request, StreamObserver responseObserver) { 18 | log.info(request.getName() + ": Hello there!"); 19 | String message = "General Grievous: General " + request.getName() + "! You are a bold one..."; 20 | final GreeterOuterClass.Greeting.Builder replyBuilder = GreeterOuterClass.Greeting.newBuilder().setMessage(message); 21 | responseObserver.onNext(replyBuilder.build()); 22 | responseObserver.onCompleted(); 23 | } 24 | } -------------------------------------------------------------------------------- /greeter-with-interceptors/server/src/main/proto/greeter.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "greet.grpc"; 4 | 5 | // The greeter service definition. 6 | service Greeter { 7 | rpc greet ( Name ) returns ( Greeting ) {} 8 | } 9 | 10 | message Name { 11 | string name = 1; 12 | } 13 | 14 | message Greeting { 15 | string message = 1; 16 | } 17 | -------------------------------------------------------------------------------- /greeter-with-interceptors/server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | security.basic.enabled=false 2 | management.security.enabled=false -------------------------------------------------------------------------------- /greeter/client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jfloff/thrike:8.5 2 | 3 | LABEL maintainer="jfloff@inesc-id.pt" 4 | 5 | ################### 6 | # Build Server 7 | # 8 | WORKDIR /home/client 9 | # cache gradle build dependencies - is less often changed than code 10 | ADD build.gradle /home/client 11 | RUN gradle getDependencies 12 | # add all code and build 13 | ADD . /home/client 14 | RUN gradle build && \ 15 | cp build/libs/client.war /usr/local/tomcat/webapps/ 16 | -------------------------------------------------------------------------------- /greeter/client/build.gradle: -------------------------------------------------------------------------------- 1 | //////////////////////// 2 | // VARIABLES 3 | // 4 | def gradleVersion = "$System.env.GRADLE_VERSION" 5 | def grpcVersion = "$System.env.GRPC_JAVA_VERSION" 6 | def protobufVersion = "$System.env.PROTOBUF_VERSION" 7 | def protocPath = "$System.env.PROTOC_HOME" 8 | def grpcPluginPath = "$System.env.GRPC_JAVA_PLUGIN_HOME" 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'war' 12 | apply plugin: 'application' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'com.google.protobuf' 15 | 16 | buildscript { 17 | repositories { 18 | mavenCentral() 19 | jcenter() 20 | maven { url "https://plugins.gradle.org/m2/" } 21 | } 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.10.RELEASE" 24 | classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5" 25 | } 26 | } 27 | 28 | repositories { 29 | maven { url "http://repo.springsource.org/libs-snapshot" } 30 | maven { url "http://repo.springsource.org/plugins-release" } 31 | } 32 | 33 | sourceCompatibility = 1.8 34 | targetCompatibility = 1.8 35 | 36 | 37 | dependencies { 38 | // spring 39 | compile "org.springframework.boot:spring-boot-starter-web" 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | 42 | // grpc 43 | compile group: 'io.grpc', name: 'grpc-netty', version: "$grpcVersion" 44 | compile group: 'io.grpc', name: 'grpc-protobuf', version: "$grpcVersion" 45 | compile group: 'io.grpc', name: 'grpc-stub', version: "$grpcVersion" 46 | compile group: 'com.google.api.grpc', name: 'proto-google-common-protos', version: '1.5.0' 47 | compile 'org.lognet:grpc-spring-boot-starter:2.2.0' 48 | 49 | // for application itself 50 | compile group: 'org.projectlombok', name: 'lombok', version: '1.16.20' 51 | 52 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 53 | } 54 | 55 | sourceSets { 56 | main { 57 | proto { 58 | srcDir 'src/main/proto' 59 | } 60 | } 61 | } 62 | 63 | protobuf { 64 | protoc { 65 | path = "${protocPath}" 66 | } 67 | plugins { 68 | grpc { 69 | path = "${grpcPluginPath}" 70 | } 71 | } 72 | 73 | generateProtoTasks { 74 | ofSourceSet('main').each { task -> 75 | task.builtins { 76 | java{ 77 | outputSubDir = 'generated' 78 | } 79 | } 80 | task.plugins { 81 | grpc { 82 | outputSubDir = 'generated' 83 | } 84 | } 85 | } 86 | } 87 | generatedFilesBaseDir = "$projectDir/src/" 88 | } 89 | 90 | task cleanGenerated{ 91 | doFirst{ 92 | delete("$projectDir/src/main/generated") 93 | } 94 | } 95 | clean.dependsOn cleanGenerated 96 | 97 | task getDependencies(type: Exec) { 98 | configurations.testRuntime.files 99 | commandLine 'echo', 'Downloaded all dependencies' 100 | } 101 | 102 | task wrapper(type: Wrapper) { 103 | description = 'Generates gradlew[.bat] scripts' 104 | gradleVersion = "$gradleVersion" 105 | } 106 | 107 | jar { 108 | baseName = 'client-service' 109 | version = '0.1.0' 110 | } 111 | 112 | mainClassName = 'client.Application' 113 | 114 | defaultTasks 'build' -------------------------------------------------------------------------------- /greeter/client/src/main/java/client/Application.java: -------------------------------------------------------------------------------- 1 | package client; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.boot.web.support.SpringBootServletInitializer; 7 | 8 | import org.lognet.springboot.grpc.GRpcService; 9 | import io.grpc.stub.StreamObserver; 10 | 11 | 12 | @SpringBootApplication 13 | public class Application extends SpringBootServletInitializer { 14 | 15 | @Override 16 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 17 | return application.sources(Application.class); 18 | } 19 | 20 | public static void main(String[] args) throws Exception { 21 | SpringApplication.run(Application.class,args); 22 | } 23 | } -------------------------------------------------------------------------------- /greeter/client/src/main/java/client/Client.java: -------------------------------------------------------------------------------- 1 | package client; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.boot.context.event.ApplicationReadyEvent; 7 | import org.springframework.context.event.EventListener; 8 | 9 | import io.grpc.stub.StreamObserver; 10 | import io.grpc.ManagedChannel; 11 | import io.grpc.ManagedChannelBuilder; 12 | import io.grpc.StatusRuntimeException; 13 | 14 | import greet.grpc.GreeterGrpc; 15 | import greet.grpc.GreeterOuterClass; 16 | 17 | 18 | @Slf4j 19 | @Component 20 | public class Client { 21 | private final ManagedChannel channel; 22 | private final GreeterGrpc.GreeterBlockingStub stub; 23 | private String name; 24 | 25 | public Client() { 26 | this.name = System.getenv("GREET_NAME"); 27 | // we should get this info from a service like eureka 28 | this.channel = ManagedChannelBuilder.forAddress("server", 6565) 29 | // Channels are secure by default (via SSL/TLS). 30 | // For the example we disable TLS to avoid needing certificates. 31 | .usePlaintext(true) 32 | .build(); 33 | this.stub = GreeterGrpc.newBlockingStub(channel); 34 | } 35 | 36 | // this simulates a new client sending a message 37 | // realistic these clients come all the time 38 | @EventListener(ApplicationReadyEvent.class) 39 | public void startup() throws InterruptedException { 40 | this.greet(this.name); 41 | System.exit(0); 42 | } 43 | 44 | public void greet(String name) throws InterruptedException { 45 | log.info("Will try to greet " + name + " ..."); 46 | 47 | // build message 48 | GreeterOuterClass.Name greetName = GreeterOuterClass.Name.newBuilder().setName(name).build(); 49 | 50 | // this should be either replaced by a health-checking or 51 | // even better a eureka/zookeeper service discovery system 52 | while(true){ 53 | try { 54 | GreeterOuterClass.Greeting greeting = stub.greet(greetName); 55 | log.info(greeting.getMessage()); 56 | return; 57 | } catch (StatusRuntimeException e) { 58 | log.info("ERROR ON GREET: " + e.getMessage()); 59 | Thread.sleep(1000); 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /greeter/client/src/main/proto/greeter.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "greet.grpc"; 4 | 5 | // The greeter service definition. 6 | service Greeter { 7 | rpc greet ( Name ) returns ( Greeting ) {} 8 | } 9 | 10 | message Name { 11 | string name = 1; 12 | } 13 | 14 | message Greeting { 15 | string message = 1; 16 | } 17 | -------------------------------------------------------------------------------- /greeter/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | security.basic.enabled=false 2 | management.security.enabled=false -------------------------------------------------------------------------------- /greeter/docker-compose.yml: -------------------------------------------------------------------------------- 1 | 2 | version: '3' 3 | services: 4 | server: 5 | build: ./server 6 | volumes: 7 | - './server:/home/server' 8 | expose: 9 | - '6565' 10 | 11 | client: 12 | build: ./client 13 | # command: bash -c "sleep 30 && catalina.sh run" 14 | volumes: 15 | - './client:/home/client' 16 | environment: 17 | GREET_NAME: 'Kenobi' 18 | -------------------------------------------------------------------------------- /greeter/server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jfloff/thrike:8.5 2 | 3 | LABEL maintainer="jfloff@inesc-id.pt" 4 | 5 | ################### 6 | # Build Server 7 | # 8 | WORKDIR /home/server 9 | # cache gradle build dependencies - is less often changed than code 10 | ADD build.gradle /home/server 11 | RUN gradle getDependencies 12 | # add all code and build 13 | ADD . /home/server 14 | RUN gradle build && \ 15 | cp build/libs/server.war /usr/local/tomcat/webapps/ -------------------------------------------------------------------------------- /greeter/server/build.gradle: -------------------------------------------------------------------------------- 1 | //////////////////////// 2 | // VARIABLES 3 | // 4 | def gradleVersion = "$System.env.GRADLE_VERSION" 5 | def grpcVersion = "$System.env.GRPC_JAVA_VERSION" 6 | def protobufVersion = "$System.env.PROTOBUF_VERSION" 7 | def protocPath = "$System.env.PROTOC_HOME" 8 | def grpcPluginPath = "$System.env.GRPC_JAVA_PLUGIN_HOME" 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'war' 12 | apply plugin: 'application' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'com.google.protobuf' 15 | 16 | buildscript { 17 | repositories { 18 | mavenCentral() 19 | jcenter() 20 | maven { url "https://plugins.gradle.org/m2/" } 21 | } 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.10.RELEASE" 24 | classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5" 25 | } 26 | } 27 | 28 | repositories { 29 | maven { url "http://repo.springsource.org/libs-snapshot" } 30 | maven { url "http://repo.springsource.org/plugins-release" } 31 | } 32 | 33 | sourceCompatibility = 1.8 34 | targetCompatibility = 1.8 35 | 36 | 37 | dependencies { 38 | // spring 39 | compile "org.springframework.boot:spring-boot-starter-web" 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | 42 | // grpc 43 | compile group: 'io.grpc', name: 'grpc-netty', version: "$grpcVersion" 44 | compile group: 'io.grpc', name: 'grpc-protobuf', version: "$grpcVersion" 45 | compile group: 'io.grpc', name: 'grpc-stub', version: "$grpcVersion" 46 | compile group: 'com.google.api.grpc', name: 'proto-google-common-protos', version: '1.5.0' 47 | compile 'org.lognet:grpc-spring-boot-starter:2.2.0' 48 | 49 | // for application itself 50 | compile group: 'org.projectlombok', name: 'lombok', version: '1.16.20' 51 | 52 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 53 | } 54 | 55 | sourceSets { 56 | main { 57 | proto { 58 | srcDir 'src/main/proto' 59 | } 60 | } 61 | } 62 | 63 | protobuf { 64 | protoc { 65 | path = "${protocPath}" 66 | } 67 | plugins { 68 | grpc { 69 | path = "${grpcPluginPath}" 70 | } 71 | } 72 | 73 | generateProtoTasks { 74 | all().each { task -> 75 | task.builtins { 76 | java { 77 | outputSubDir = 'generated' 78 | } 79 | } 80 | task.plugins { 81 | grpc { 82 | outputSubDir = 'generated' 83 | } 84 | } 85 | } 86 | } 87 | generatedFilesBaseDir = "$projectDir/src/" 88 | } 89 | 90 | task cleanGenerated{ 91 | doFirst{ 92 | delete("$projectDir/src/main/generated") 93 | } 94 | } 95 | clean.dependsOn cleanGenerated 96 | 97 | task getDependencies(type: Exec) { 98 | configurations.testRuntime.files 99 | commandLine 'echo', 'Downloaded all dependencies' 100 | } 101 | 102 | task wrapper(type: Wrapper) { 103 | description = 'Generates gradlew[.bat] scripts' 104 | gradleVersion = "$gradleVersion" 105 | } 106 | 107 | jar { 108 | baseName = 'server-service' 109 | version = '0.1.0' 110 | } 111 | 112 | mainClassName = 'server.Application' 113 | 114 | defaultTasks 'build' -------------------------------------------------------------------------------- /greeter/server/src/main/java/server/Application.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.boot.builder.SpringApplicationBuilder; 8 | import org.springframework.boot.web.support.SpringBootServletInitializer; 9 | 10 | 11 | @SpringBootApplication 12 | public class Application extends SpringBootServletInitializer { 13 | 14 | @Override 15 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 16 | return application.sources(Application.class); 17 | } 18 | 19 | public static void main(String[] args) throws Exception { 20 | SpringApplication.run(Application.class,args); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /greeter/server/src/main/java/server/Server.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | 8 | import greet.grpc.GreeterGrpc; 9 | import greet.grpc.GreeterOuterClass; 10 | import io.grpc.stub.StreamObserver; 11 | 12 | @Slf4j 13 | @GRpcService 14 | public class Server extends GreeterGrpc.GreeterImplBase { 15 | 16 | @Override 17 | public void greet(GreeterOuterClass.Name request, StreamObserver responseObserver) { 18 | log.info(request.getName() + ": Hello there!"); 19 | String message = "General Grievous: General " + request.getName() + "! You are a bold one..."; 20 | final GreeterOuterClass.Greeting.Builder replyBuilder = GreeterOuterClass.Greeting.newBuilder().setMessage(message); 21 | responseObserver.onNext(replyBuilder.build()); 22 | responseObserver.onCompleted(); 23 | } 24 | } -------------------------------------------------------------------------------- /greeter/server/src/main/proto/greeter.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "greet.grpc"; 4 | 5 | // The greeter service definition. 6 | service Greeter { 7 | rpc greet ( Name ) returns ( Greeting ) {} 8 | } 9 | 10 | message Name { 11 | string name = 1; 12 | } 13 | 14 | message Greeting { 15 | string message = 1; 16 | } 17 | -------------------------------------------------------------------------------- /greeter/server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | security.basic.enabled=false 2 | management.security.enabled=false -------------------------------------------------------------------------------- /health-check/client/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jfloff/thrike:8.5 2 | 3 | LABEL maintainer="jfloff@inesc-id.pt" 4 | 5 | ################### 6 | # Build Server 7 | # 8 | WORKDIR /home/client 9 | # cache gradle build dependencies - is less often changed than code 10 | ADD build.gradle /home/client 11 | RUN gradle getDependencies 12 | # add all code and build 13 | ADD . /home/client 14 | RUN gradle build && \ 15 | cp build/libs/client.war /usr/local/tomcat/webapps/ 16 | -------------------------------------------------------------------------------- /health-check/client/build.gradle: -------------------------------------------------------------------------------- 1 | //////////////////////// 2 | // VARIABLES 3 | // 4 | def gradleVersion = "$System.env.GRADLE_VERSION" 5 | def grpcVersion = "$System.env.GRPC_JAVA_VERSION" 6 | def protobufVersion = "$System.env.PROTOBUF_VERSION" 7 | def protocPath = "$System.env.PROTOC_HOME" 8 | def grpcPluginPath = "$System.env.GRPC_JAVA_PLUGIN_HOME" 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'war' 12 | apply plugin: 'application' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'com.google.protobuf' 15 | 16 | buildscript { 17 | repositories { 18 | mavenCentral() 19 | jcenter() 20 | maven { url "https://plugins.gradle.org/m2/" } 21 | } 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.10.RELEASE" 24 | classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5" 25 | } 26 | } 27 | 28 | repositories { 29 | maven { url "http://repo.springsource.org/libs-snapshot" } 30 | maven { url "http://repo.springsource.org/plugins-release" } 31 | } 32 | 33 | sourceCompatibility = 1.8 34 | targetCompatibility = 1.8 35 | 36 | 37 | dependencies { 38 | // spring 39 | compile "org.springframework.boot:spring-boot-starter-web" 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | 42 | // grpc 43 | compile group: 'io.grpc', name: 'grpc-netty', version: "$grpcVersion" 44 | compile group: 'io.grpc', name: 'grpc-protobuf', version: "$grpcVersion" 45 | compile group: 'io.grpc', name: 'grpc-stub', version: "$grpcVersion" 46 | compile group: 'com.google.api.grpc', name: 'proto-google-common-protos', version: '1.5.0' 47 | compile 'org.lognet:grpc-spring-boot-starter:2.2.0' 48 | 49 | // for application itself 50 | compile group: 'org.projectlombok', name: 'lombok', version: '1.16.20' 51 | 52 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 53 | } 54 | 55 | sourceSets { 56 | main { 57 | proto { 58 | srcDir 'src/main/proto' 59 | } 60 | } 61 | } 62 | 63 | protobuf { 64 | protoc { 65 | path = "${protocPath}" 66 | } 67 | plugins { 68 | grpc { 69 | path = "${grpcPluginPath}" 70 | } 71 | } 72 | 73 | generateProtoTasks { 74 | ofSourceSet('main').each { task -> 75 | task.builtins { 76 | java{ 77 | outputSubDir = 'generated' 78 | } 79 | } 80 | task.plugins { 81 | grpc { 82 | outputSubDir = 'generated' 83 | } 84 | } 85 | } 86 | } 87 | generatedFilesBaseDir = "$projectDir/src/" 88 | } 89 | 90 | task cleanGenerated{ 91 | doFirst{ 92 | delete("$projectDir/src/main/generated") 93 | } 94 | } 95 | clean.dependsOn cleanGenerated 96 | 97 | task getDependencies(type: Exec) { 98 | configurations.testRuntime.files 99 | commandLine 'echo', 'Downloaded all dependencies' 100 | } 101 | 102 | task wrapper(type: Wrapper) { 103 | description = 'Generates gradlew[.bat] scripts' 104 | gradleVersion = "$gradleVersion" 105 | } 106 | 107 | jar { 108 | baseName = 'client-service' 109 | version = '0.1.0' 110 | } 111 | 112 | mainClassName = 'client.Application' 113 | 114 | defaultTasks 'build' -------------------------------------------------------------------------------- /health-check/client/src/main/java/client/Application.java: -------------------------------------------------------------------------------- 1 | package client; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.builder.SpringApplicationBuilder; 6 | import org.springframework.boot.web.support.SpringBootServletInitializer; 7 | 8 | import org.lognet.springboot.grpc.GRpcService; 9 | import io.grpc.stub.StreamObserver; 10 | 11 | 12 | @SpringBootApplication 13 | public class Application extends SpringBootServletInitializer { 14 | 15 | @Override 16 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 17 | return application.sources(Application.class); 18 | } 19 | 20 | public static void main(String[] args) throws Exception { 21 | SpringApplication.run(Application.class,args); 22 | } 23 | } -------------------------------------------------------------------------------- /health-check/client/src/main/java/client/Client.java: -------------------------------------------------------------------------------- 1 | package client; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | 5 | import org.springframework.stereotype.Component; 6 | import org.springframework.boot.context.event.ApplicationReadyEvent; 7 | import org.springframework.context.event.EventListener; 8 | 9 | import io.grpc.stub.StreamObserver; 10 | import io.grpc.ManagedChannel; 11 | import io.grpc.ManagedChannelBuilder; 12 | import io.grpc.StatusRuntimeException; 13 | 14 | import grpc.health.v1.HealthCheckGrpc; 15 | import grpc.health.v1.HealthCheckOuterClass; 16 | 17 | 18 | @Slf4j 19 | @Component 20 | public class Client { 21 | private final ManagedChannel channel; 22 | private final HealthCheckGrpc.HealthCheckBlockingStub stub; 23 | private String name; 24 | 25 | public Client() { 26 | // we should get this info from a service like eureka 27 | this.channel = ManagedChannelBuilder.forAddress("server", 6565) 28 | // Channels are secure by default (via SSL/TLS). 29 | // For the example we disable TLS to avoid needing certificates. 30 | .usePlaintext(true) 31 | .build(); 32 | this.stub = HealthCheckGrpc.newBlockingStub(channel); 33 | } 34 | 35 | // this simulates a new client sending a message 36 | // realistic these clients come all the time 37 | @EventListener(ApplicationReadyEvent.class) 38 | public void startup() throws InterruptedException { 39 | this.healthcheck(); 40 | System.exit(0); 41 | } 42 | 43 | public void healthcheck() throws InterruptedException { 44 | log.info("Health checking server ..."); 45 | 46 | // build message 47 | HealthCheckOuterClass.Service service = HealthCheckOuterClass.Service.newBuilder().setService("server").build(); 48 | 49 | // this should be either replaced by a health-checking or 50 | // even better a eureka/zookeeper service discovery system 51 | while(true){ 52 | try { 53 | HealthCheckOuterClass.Status status = stub.check(service); 54 | log.info("Server status: " + status.getStatus()); 55 | Thread.sleep(5000); 56 | } catch (StatusRuntimeException e) { 57 | log.info("ERROR ON GREET: " + e.getMessage()); 58 | Thread.sleep(1000); 59 | } catch (InterruptedException ie) { 60 | return; 61 | } 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /health-check/client/src/main/proto/health_check.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "grpc.health.v1"; 4 | 5 | service HealthCheck { 6 | rpc check(Service) returns (Status); 7 | } 8 | 9 | message Service { 10 | string service = 1; 11 | } 12 | 13 | message Status { 14 | enum ServingStatus { 15 | UNKNOWN = 0; 16 | SERVING = 1; 17 | NOT_SERVING = 2; 18 | } 19 | ServingStatus status = 1; 20 | } 21 | -------------------------------------------------------------------------------- /health-check/client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | security.basic.enabled=false 2 | management.security.enabled=false -------------------------------------------------------------------------------- /health-check/docker-compose.yml: -------------------------------------------------------------------------------- 1 | 2 | version: '3' 3 | services: 4 | server: 5 | build: ./server 6 | volumes: 7 | - './server:/home/server' 8 | expose: 9 | - '6565' 10 | 11 | client: 12 | build: ./client 13 | volumes: 14 | - './client:/home/client' 15 | -------------------------------------------------------------------------------- /health-check/server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jfloff/thrike:8.5 2 | 3 | LABEL maintainer="jfloff@inesc-id.pt" 4 | 5 | ################### 6 | # Build Server 7 | # 8 | WORKDIR /home/server 9 | # cache gradle build dependencies - is less often changed than code 10 | ADD build.gradle /home/server 11 | RUN gradle getDependencies 12 | # add all code and build 13 | ADD . /home/server 14 | RUN gradle build && \ 15 | cp build/libs/server.war /usr/local/tomcat/webapps/ -------------------------------------------------------------------------------- /health-check/server/build.gradle: -------------------------------------------------------------------------------- 1 | //////////////////////// 2 | // VARIABLES 3 | // 4 | def gradleVersion = "$System.env.GRADLE_VERSION" 5 | def grpcVersion = "$System.env.GRPC_JAVA_VERSION" 6 | def protobufVersion = "$System.env.PROTOBUF_VERSION" 7 | def protocPath = "$System.env.PROTOC_HOME" 8 | def grpcPluginPath = "$System.env.GRPC_JAVA_PLUGIN_HOME" 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'war' 12 | apply plugin: 'application' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'com.google.protobuf' 15 | 16 | buildscript { 17 | repositories { 18 | mavenCentral() 19 | jcenter() 20 | maven { url "https://plugins.gradle.org/m2/" } 21 | } 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.10.RELEASE" 24 | classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5" 25 | } 26 | } 27 | 28 | repositories { 29 | maven { url "http://repo.springsource.org/libs-snapshot" } 30 | maven { url "http://repo.springsource.org/plugins-release" } 31 | } 32 | 33 | sourceCompatibility = 1.8 34 | targetCompatibility = 1.8 35 | 36 | 37 | dependencies { 38 | // spring 39 | compile "org.springframework.boot:spring-boot-starter-web" 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | 42 | // grpc 43 | compile group: 'io.grpc', name: 'grpc-netty', version: "$grpcVersion" 44 | compile group: 'io.grpc', name: 'grpc-protobuf', version: "$grpcVersion" 45 | compile group: 'io.grpc', name: 'grpc-stub', version: "$grpcVersion" 46 | compile group: 'com.google.api.grpc', name: 'proto-google-common-protos', version: '1.5.0' 47 | compile 'org.lognet:grpc-spring-boot-starter:2.2.0' 48 | 49 | // for application itself 50 | compile group: 'org.projectlombok', name: 'lombok', version: '1.16.20' 51 | 52 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 53 | } 54 | 55 | sourceSets { 56 | main { 57 | proto { 58 | srcDir 'src/main/proto' 59 | } 60 | } 61 | } 62 | 63 | protobuf { 64 | protoc { 65 | path = "${protocPath}" 66 | } 67 | plugins { 68 | grpc { 69 | path = "${grpcPluginPath}" 70 | } 71 | } 72 | 73 | generateProtoTasks { 74 | all().each { task -> 75 | task.builtins { 76 | java { 77 | outputSubDir = 'generated' 78 | } 79 | } 80 | task.plugins { 81 | grpc { 82 | outputSubDir = 'generated' 83 | } 84 | } 85 | } 86 | } 87 | generatedFilesBaseDir = "$projectDir/src/" 88 | } 89 | 90 | task cleanGenerated{ 91 | doFirst{ 92 | delete("$projectDir/src/main/generated") 93 | } 94 | } 95 | clean.dependsOn cleanGenerated 96 | 97 | task getDependencies(type: Exec) { 98 | configurations.testRuntime.files 99 | commandLine 'echo', 'Downloaded all dependencies' 100 | } 101 | 102 | task wrapper(type: Wrapper) { 103 | description = 'Generates gradlew[.bat] scripts' 104 | gradleVersion = "$gradleVersion" 105 | } 106 | 107 | jar { 108 | baseName = 'server-service' 109 | version = '0.1.0' 110 | } 111 | 112 | mainClassName = 'server.Application' 113 | 114 | defaultTasks 'build' -------------------------------------------------------------------------------- /health-check/server/src/main/java/server/Application.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.boot.builder.SpringApplicationBuilder; 8 | import org.springframework.boot.web.support.SpringBootServletInitializer; 9 | 10 | 11 | @SpringBootApplication 12 | public class Application extends SpringBootServletInitializer { 13 | 14 | @Override 15 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 16 | return application.sources(Application.class); 17 | } 18 | 19 | public static void main(String[] args) throws Exception { 20 | SpringApplication.run(Application.class,args); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /health-check/server/src/main/java/server/Server.java: -------------------------------------------------------------------------------- 1 | package server; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | 8 | import grpc.health.v1.HealthCheckGrpc; 9 | import grpc.health.v1.HealthCheckOuterClass; 10 | import io.grpc.stub.StreamObserver; 11 | import java.util.Random; 12 | 13 | @Slf4j 14 | @GRpcService 15 | public class Server extends HealthCheckGrpc.HealthCheckImplBase { 16 | 17 | @Override 18 | public void check(HealthCheckOuterClass.Service request, StreamObserver responseObserver) { 19 | HealthCheckOuterClass.Status.ServingStatus status = HealthCheckOuterClass.Status.ServingStatus.forNumber(new Random().nextInt(3)); 20 | final HealthCheckOuterClass.Status.Builder replyBuilder = HealthCheckOuterClass.Status.newBuilder().setStatus(status); 21 | responseObserver.onNext(replyBuilder.build()); 22 | responseObserver.onCompleted(); 23 | } 24 | } -------------------------------------------------------------------------------- /health-check/server/src/main/proto/health_check.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "grpc.health.v1"; 4 | 5 | service HealthCheck { 6 | rpc check(Service) returns (Status); 7 | } 8 | 9 | message Service { 10 | string service = 1; 11 | } 12 | 13 | message Status { 14 | enum ServingStatus { 15 | UNKNOWN = 0; 16 | SERVING = 1; 17 | NOT_SERVING = 2; 18 | } 19 | ServingStatus status = 1; 20 | } 21 | -------------------------------------------------------------------------------- /health-check/server/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | security.basic.enabled=false 2 | management.security.enabled=false -------------------------------------------------------------------------------- /infinite-ping-pong/docker-compose.yml: -------------------------------------------------------------------------------- 1 | 2 | version: '3' 3 | services: 4 | pong: 5 | build: ./pong 6 | volumes: 7 | - './pong:/home/pong' 8 | expose: 9 | - '6565' 10 | 11 | ping: 12 | build: ./ping 13 | volumes: 14 | - './ping:/home/ping' 15 | expose: 16 | - '6565' 17 | -------------------------------------------------------------------------------- /infinite-ping-pong/ping/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jfloff/thrike:8.5 2 | 3 | LABEL maintainer="jfloff@inesc-id.pt" 4 | 5 | ################### 6 | # Build ping 7 | # 8 | WORKDIR /home/ping 9 | # cache gradle build dependencies - is less often changed than code 10 | ADD build.gradle /home/ping 11 | RUN gradle getDependencies 12 | # add all code and build 13 | ADD . /home/ping 14 | RUN gradle build && \ 15 | cp build/libs/ping.war /usr/local/tomcat/webapps/ -------------------------------------------------------------------------------- /infinite-ping-pong/ping/build.gradle: -------------------------------------------------------------------------------- 1 | //////////////////////// 2 | // VARIABLES 3 | // 4 | def gradleVersion = "$System.env.GRADLE_VERSION" 5 | def grpcVersion = "$System.env.GRPC_JAVA_VERSION" 6 | def protobufVersion = "$System.env.PROTOBUF_VERSION" 7 | def protocPath = "$System.env.PROTOC_HOME" 8 | def grpcPluginPath = "$System.env.GRPC_JAVA_PLUGIN_HOME" 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'war' 12 | apply plugin: 'application' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'com.google.protobuf' 15 | 16 | buildscript { 17 | repositories { 18 | mavenCentral() 19 | jcenter() 20 | maven { url "https://plugins.gradle.org/m2/" } 21 | } 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.10.RELEASE" 24 | classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5" 25 | } 26 | } 27 | 28 | repositories { 29 | maven { url "http://repo.springsource.org/libs-snapshot" } 30 | maven { url "http://repo.springsource.org/plugins-release" } 31 | } 32 | 33 | sourceCompatibility = 1.8 34 | targetCompatibility = 1.8 35 | 36 | 37 | dependencies { 38 | // spring 39 | compile "org.springframework.boot:spring-boot-starter-web" 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | 42 | // grpc 43 | compile group: 'io.grpc', name: 'grpc-netty', version: "$grpcVersion" 44 | compile group: 'io.grpc', name: 'grpc-protobuf', version: "$grpcVersion" 45 | compile group: 'io.grpc', name: 'grpc-stub', version: "$grpcVersion" 46 | compile group: 'com.google.api.grpc', name: 'proto-google-common-protos', version: '1.5.0' 47 | compile 'org.lognet:grpc-spring-boot-starter:2.2.0' 48 | 49 | // for application itself 50 | compile group: 'org.projectlombok', name: 'lombok', version: '1.16.20' 51 | 52 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 53 | } 54 | 55 | sourceSets { 56 | main { 57 | proto { 58 | srcDir 'src/main/proto' 59 | } 60 | } 61 | } 62 | 63 | protobuf { 64 | protoc { 65 | path = "${protocPath}" 66 | } 67 | plugins { 68 | grpc { 69 | path = "${grpcPluginPath}" 70 | } 71 | } 72 | 73 | generateProtoTasks { 74 | all().each { task -> 75 | task.builtins { 76 | java { 77 | outputSubDir = 'generated' 78 | } 79 | } 80 | task.plugins { 81 | grpc { 82 | outputSubDir = 'generated' 83 | } 84 | } 85 | } 86 | } 87 | generatedFilesBaseDir = "$projectDir/src/" 88 | } 89 | 90 | task cleanGenerated{ 91 | doFirst{ 92 | delete("$projectDir/src/main/generated") 93 | } 94 | } 95 | clean.dependsOn cleanGenerated 96 | 97 | task getDependencies(type: Exec) { 98 | configurations.testRuntime.files 99 | commandLine 'echo', 'Downloaded all dependencies' 100 | } 101 | 102 | task wrapper(type: Wrapper) { 103 | description = 'Generates gradlew[.bat] scripts' 104 | gradleVersion = "$gradleVersion" 105 | } 106 | 107 | jar { 108 | baseName = 'ping-service' 109 | version = '0.1.0' 110 | } 111 | 112 | mainClassName = 'ping.Application' 113 | 114 | defaultTasks 'build' -------------------------------------------------------------------------------- /infinite-ping-pong/ping/src/main/java/ping/Application.java: -------------------------------------------------------------------------------- 1 | package ping; 2 | 3 | 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.boot.builder.SpringApplicationBuilder; 8 | import org.springframework.boot.web.support.SpringBootServletInitializer; 9 | 10 | 11 | @SpringBootApplication 12 | public class Application extends SpringBootServletInitializer { 13 | 14 | @Override 15 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 16 | return application.sources(Application.class); 17 | } 18 | 19 | public static void main(String[] args) throws Exception { 20 | SpringApplication.run(Application.class,args); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /infinite-ping-pong/ping/src/main/java/ping/Ping.java: -------------------------------------------------------------------------------- 1 | package ping; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.event.EventListener; 8 | import org.springframework.boot.context.event.ApplicationReadyEvent; 9 | 10 | import echo.grpc.EchoGrpc; 11 | import echo.grpc.EchoOuterClass; 12 | import io.grpc.stub.StreamObserver; 13 | import io.grpc.ManagedChannel; 14 | import io.grpc.ManagedChannelBuilder; 15 | import io.grpc.StatusRuntimeException; 16 | 17 | import java.util.concurrent.locks.ReentrantLock; 18 | 19 | 20 | @Slf4j 21 | @GRpcService 22 | public class Ping extends EchoGrpc.EchoImplBase { 23 | 24 | private final ManagedChannel pongChannel; 25 | private final EchoGrpc.EchoBlockingStub stub; 26 | private final ReentrantLock lock = new ReentrantLock(); 27 | 28 | public Ping() { 29 | super(); 30 | // we should get this info from a service like eureka 31 | this.pongChannel = ManagedChannelBuilder.forAddress("pong", 6565) 32 | // Channels are secure by default (via SSL/TLS). 33 | // For the example we disable TLS to avoid needing certificates. 34 | .usePlaintext(true) 35 | .build(); 36 | this.stub = EchoGrpc.newBlockingStub(pongChannel); 37 | } 38 | 39 | // this simulates a new ping sending a message 40 | // realistic these clients come all the time 41 | @EventListener(ApplicationReadyEvent.class) 42 | public void startup() { 43 | // send first ping 44 | pingEcho(); 45 | } 46 | 47 | @Override 48 | public void echo(EchoOuterClass.Message request, StreamObserver responseObserver){ 49 | // receives message and prints 50 | log.info(request.getMessage()); 51 | responseObserver.onNext(pingMessage()); 52 | responseObserver.onCompleted(); 53 | // and then makes a new request 54 | pingEcho(); 55 | } 56 | 57 | // builds ping message used for both answers to GRPC and new communications 58 | private EchoOuterClass.Message pingMessage() { 59 | return EchoOuterClass.Message.newBuilder().setMessage("PING").build(); 60 | } 61 | 62 | private void pingEcho() { 63 | lock.lock(); 64 | try { 65 | // this should be either replaced by a health-checking or 66 | // even better a eureka/zookeeper service discovery system 67 | while(true){ 68 | try { 69 | EchoOuterClass.Message echo = stub.echo(pingMessage()); 70 | log.info(echo.getMessage()); 71 | return; 72 | } catch (StatusRuntimeException e) { 73 | log.info("ERROR ON ECHO: " + e.getMessage()); 74 | coolOff(5); 75 | } finally { 76 | coolOff(2); 77 | } 78 | } 79 | } finally { 80 | lock.unlock(); 81 | } 82 | } 83 | 84 | private void coolOff(int s) { 85 | // always wait 2 seconds for next message 86 | log.info("Just hold on " + s + " seconds ..."); 87 | try { 88 | Thread.sleep(s * 1000); 89 | } catch (InterruptedException ie) { } 90 | } 91 | } -------------------------------------------------------------------------------- /infinite-ping-pong/ping/src/main/proto/echo.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "echo.grpc"; 4 | 5 | // The echo service definition. 6 | service Echo { 7 | rpc echo ( Message ) returns ( Message ) {} 8 | } 9 | 10 | message Message { 11 | string message = 1; 12 | } 13 | -------------------------------------------------------------------------------- /infinite-ping-pong/ping/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | security.basic.enabled=false 2 | management.security.enabled=false -------------------------------------------------------------------------------- /infinite-ping-pong/pong/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jfloff/thrike:8.5 2 | 3 | LABEL maintainer="jfloff@inesc-id.pt" 4 | 5 | ################### 6 | # Build pong 7 | # 8 | WORKDIR /home/pong 9 | # cache gradle build dependencies - is less often changed than code 10 | ADD build.gradle /home/pong 11 | RUN gradle getDependencies 12 | # add all code and build 13 | ADD . /home/pong 14 | RUN gradle build && \ 15 | cp build/libs/pong.war /usr/local/tomcat/webapps/ -------------------------------------------------------------------------------- /infinite-ping-pong/pong/build.gradle: -------------------------------------------------------------------------------- 1 | //////////////////////// 2 | // VARIABLES 3 | // 4 | def gradleVersion = "$System.env.GRADLE_VERSION" 5 | def grpcVersion = "$System.env.GRPC_JAVA_VERSION" 6 | def protobufVersion = "$System.env.PROTOBUF_VERSION" 7 | def protocPath = "$System.env.PROTOC_HOME" 8 | def grpcPluginPath = "$System.env.GRPC_JAVA_PLUGIN_HOME" 9 | 10 | apply plugin: 'java' 11 | apply plugin: 'war' 12 | apply plugin: 'application' 13 | apply plugin: 'org.springframework.boot' 14 | apply plugin: 'com.google.protobuf' 15 | 16 | buildscript { 17 | repositories { 18 | mavenCentral() 19 | jcenter() 20 | maven { url "https://plugins.gradle.org/m2/" } 21 | } 22 | dependencies { 23 | classpath "org.springframework.boot:spring-boot-gradle-plugin:1.5.10.RELEASE" 24 | classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.5" 25 | } 26 | } 27 | 28 | repositories { 29 | maven { url "http://repo.springsource.org/libs-snapshot" } 30 | maven { url "http://repo.springsource.org/plugins-release" } 31 | } 32 | 33 | sourceCompatibility = 1.8 34 | targetCompatibility = 1.8 35 | 36 | 37 | dependencies { 38 | // spring 39 | compile "org.springframework.boot:spring-boot-starter-web" 40 | compile "org.springframework.boot:spring-boot-starter-actuator" 41 | 42 | // grpc 43 | compile group: 'io.grpc', name: 'grpc-netty', version: "$grpcVersion" 44 | compile group: 'io.grpc', name: 'grpc-protobuf', version: "$grpcVersion" 45 | compile group: 'io.grpc', name: 'grpc-stub', version: "$grpcVersion" 46 | compile group: 'com.google.api.grpc', name: 'proto-google-common-protos', version: '1.5.0' 47 | compile 'org.lognet:grpc-spring-boot-starter:2.2.0' 48 | 49 | // for application itself 50 | compile group: 'org.projectlombok', name: 'lombok', version: '1.16.20' 51 | 52 | providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' 53 | } 54 | 55 | sourceSets { 56 | main { 57 | proto { 58 | srcDir 'src/main/proto' 59 | } 60 | } 61 | } 62 | 63 | protobuf { 64 | protoc { 65 | path = "${protocPath}" 66 | } 67 | plugins { 68 | grpc { 69 | path = "${grpcPluginPath}" 70 | } 71 | } 72 | 73 | generateProtoTasks { 74 | all().each { task -> 75 | task.builtins { 76 | java { 77 | outputSubDir = 'generated' 78 | } 79 | } 80 | task.plugins { 81 | grpc { 82 | outputSubDir = 'generated' 83 | } 84 | } 85 | } 86 | } 87 | generatedFilesBaseDir = "$projectDir/src/" 88 | } 89 | 90 | task cleanGenerated{ 91 | doFirst{ 92 | delete("$projectDir/src/main/generated") 93 | } 94 | } 95 | clean.dependsOn cleanGenerated 96 | 97 | task getDependencies(type: Exec) { 98 | configurations.testRuntime.files 99 | commandLine 'echo', 'Downloaded all dependencies' 100 | } 101 | 102 | task wrapper(type: Wrapper) { 103 | description = 'Generates gradlew[.bat] scripts' 104 | gradleVersion = "$gradleVersion" 105 | } 106 | 107 | jar { 108 | baseName = 'pong-service' 109 | version = '0.1.0' 110 | } 111 | 112 | mainClassName = 'pong.Application' 113 | 114 | defaultTasks 'build' -------------------------------------------------------------------------------- /infinite-ping-pong/pong/src/main/java/pong/Application.java: -------------------------------------------------------------------------------- 1 | package pong; 2 | 3 | 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.boot.builder.SpringApplicationBuilder; 8 | import org.springframework.boot.web.support.SpringBootServletInitializer; 9 | 10 | 11 | @SpringBootApplication 12 | public class Application extends SpringBootServletInitializer { 13 | 14 | @Override 15 | protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { 16 | return application.sources(Application.class); 17 | } 18 | 19 | public static void main(String[] args) throws Exception { 20 | SpringApplication.run(Application.class,args); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /infinite-ping-pong/pong/src/main/java/pong/Pong.java: -------------------------------------------------------------------------------- 1 | package pong; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.lognet.springboot.grpc.GRpcService; 5 | import org.springframework.boot.SpringApplication; 6 | import org.springframework.boot.autoconfigure.SpringBootApplication; 7 | import org.springframework.context.event.EventListener; 8 | import org.springframework.boot.context.event.ApplicationReadyEvent; 9 | 10 | import echo.grpc.EchoGrpc; 11 | import echo.grpc.EchoOuterClass; 12 | import io.grpc.stub.StreamObserver; 13 | import io.grpc.ManagedChannel; 14 | import io.grpc.ManagedChannelBuilder; 15 | import io.grpc.StatusRuntimeException; 16 | 17 | import java.util.concurrent.locks.ReentrantLock; 18 | 19 | 20 | @Slf4j 21 | @GRpcService 22 | public class Pong extends EchoGrpc.EchoImplBase { 23 | 24 | private final ManagedChannel pingChannel; 25 | private final EchoGrpc.EchoBlockingStub stub; 26 | private final ReentrantLock lock = new ReentrantLock(); 27 | 28 | public Pong() { 29 | super(); 30 | // we should get this info from a service like eureka 31 | this.pingChannel = ManagedChannelBuilder.forAddress("ping", 6565) 32 | // Channels are secure by default (via SSL/TLS). 33 | // For the example we disable TLS to avoid needing certificates. 34 | .usePlaintext(true) 35 | .build(); 36 | this.stub = EchoGrpc.newBlockingStub(pingChannel); 37 | } 38 | 39 | @Override 40 | public void echo(EchoOuterClass.Message request, StreamObserver responseObserver){ 41 | // receives message and prints 42 | log.info(request.getMessage()); 43 | responseObserver.onNext(pongMessage()); 44 | responseObserver.onCompleted(); 45 | // and then makes a new request 46 | pongEcho(); 47 | } 48 | 49 | // builds pong message used for both answers to GRPC and new communications 50 | private EchoOuterClass.Message pongMessage() { 51 | return EchoOuterClass.Message.newBuilder().setMessage("PONG").build(); 52 | } 53 | 54 | private void pongEcho() { 55 | lock.lock(); 56 | try { 57 | // this should be either replaced by a health-checking or 58 | // even better a eureka/zookeeper service discovery system 59 | while(true){ 60 | try { 61 | EchoOuterClass.Message echo = stub.echo(pongMessage()); 62 | log.info(echo.getMessage()); 63 | return; 64 | } catch (StatusRuntimeException e) { 65 | log.info("ERROR ON ECHO: " + e.getMessage()); 66 | coolOff(5); 67 | } finally { 68 | coolOff(2); 69 | } 70 | } 71 | } finally { 72 | lock.unlock(); 73 | } 74 | } 75 | 76 | private void coolOff(int s) { 77 | // always wait 2 seconds for next message 78 | log.info("Just hold on " + s + " seconds ..."); 79 | try { 80 | Thread.sleep(s * 1000); 81 | } catch (InterruptedException ie) { } 82 | } 83 | } -------------------------------------------------------------------------------- /infinite-ping-pong/pong/src/main/proto/echo.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "echo.grpc"; 4 | 5 | // The echo service definition. 6 | service Echo { 7 | rpc echo ( Message ) returns ( Message ) {} 8 | } 9 | 10 | message Message { 11 | string message = 1; 12 | } 13 | -------------------------------------------------------------------------------- /infinite-ping-pong/pong/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | security.basic.enabled=false 2 | management.security.enabled=false --------------------------------------------------------------------------------