From b4bbc940ada517bf68bf787318569dfac83a31da Mon Sep 17 00:00:00 2001 From: Ralf Ueberfuhr <40685729+ueberfuhr@users.noreply.github.com> Date: Fri, 5 Jan 2024 10:37:23 +0100 Subject: [PATCH] BAEL-7141: Create project structure with API stubs, service provider and service consumer. (#15478) --- spring-boot-modules/pom.xml | 1 + .../helloworld-grpc-consumer/pom.xml | 35 ++++++++ .../helloworld/consumer/HelloWorldClient.java | 61 +++++++++++++ .../HelloWorldConsumerApplication.java | 13 +++ .../src/main/resources/application.yml | 11 +++ .../helloworld-grpc-java/pom.xml | 89 +++++++++++++++++++ .../helloworld/stubs/package-info.java | 5 ++ .../src/main/proto/helloworld.proto | 19 ++++ .../helloworld-grpc-provider/pom.xml | 35 ++++++++ .../provider/HelloWorldController.java | 42 +++++++++ .../HelloWorldProviderApplication.java | 13 +++ .../provider/StreamObserverUtility.java | 35 ++++++++ .../src/main/resources/application.yml | 9 ++ .../spring-boot-3-grpc/pom.xml | 25 ++++++ 14 files changed, 393 insertions(+) create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/pom.xml create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldClient.java create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldConsumerApplication.java create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/resources/application.yml create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/pom.xml create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/java/com/baeldung/helloworld/stubs/package-info.java create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/proto/helloworld.proto create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/pom.xml create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldController.java create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldProviderApplication.java create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/StreamObserverUtility.java create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/resources/application.yml create mode 100644 spring-boot-modules/spring-boot-3-grpc/pom.xml diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml index 890edd6cc5..4c8102f1c8 100644 --- a/spring-boot-modules/pom.xml +++ b/spring-boot-modules/pom.xml @@ -91,6 +91,7 @@ spring-boot-cassandre spring-boot-react + spring-boot-3-grpc spring-boot-3-native spring-boot-3-observation spring-boot-3-test-pitfalls diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/pom.xml b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/pom.xml new file mode 100644 index 0000000000..cebedf64f2 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + helloworld-grpc-consumer + 0.0.1-SNAPSHOT + helloworld-grpc-consumer + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../../parent-boot-3 + + + + + net.devh + grpc-client-spring-boot-starter + ${grpc-spring-boot-starter.version} + + + com.baeldung.spring-boot-modules + helloworld-grpc-java + 1.0.0-SNAPSHOT + + + + + 3.2.0 + 2.15.0.RELEASE + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldClient.java b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldClient.java new file mode 100644 index 0000000000..166759544f --- /dev/null +++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldClient.java @@ -0,0 +1,61 @@ +package com.baeldung.helloworld.consumer; + +import com.baeldung.helloworld.stubs.HelloWorldRequest; +import com.baeldung.helloworld.stubs.HelloWorldResponse; +import com.baeldung.helloworld.stubs.HelloWorldServiceGrpc; +import io.grpc.stub.StreamObserver; +import net.devh.boot.grpc.client.inject.GrpcClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import java.util.stream.Stream; + +@Component +public class HelloWorldClient { + + private static final Logger log = LoggerFactory.getLogger(HelloWorldClient.class); + + // constructor injection not possible + // "Do not use in conjunction with @Autowired or @Inject" + // (see https://github.com/grpc-ecosystem/grpc-spring) + @GrpcClient("hello") + HelloWorldServiceGrpc.HelloWorldServiceStub stub; + + @EventListener(ContextRefreshedEvent.class) + void sendRequests() { + // prepare the response callback + final StreamObserver responseObserver = new StreamObserver() { + @Override + public void onNext(HelloWorldResponse helloWorldResponse) { + log.info("Hello World Response: {}", helloWorldResponse.getGreeting()); + } + + @Override + public void onError(Throwable throwable) { + log.error("Error occured", throwable); + } + + @Override + public void onCompleted() { + log.info("Hello World request finished"); + } + }; + // connect to the server + final StreamObserver request = stub.sayHello(responseObserver); + // send multiple requests (streaming) + Stream.of("Tom", "Julia", "Baeldung", "", "Ralf") + .map(HelloWorldRequest.newBuilder()::setName) + .map(HelloWorldRequest.Builder::build) + .forEach(request::onNext); + request.onCompleted(); + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldConsumerApplication.java b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldConsumerApplication.java new file mode 100644 index 0000000000..3df4667b77 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldConsumerApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.helloworld.consumer; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class HelloWorldConsumerApplication { + + public static void main(String[] args) { + SpringApplication.run(HelloWorldConsumerApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/resources/application.yml b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/resources/application.yml new file mode 100644 index 0000000000..9b0ed68375 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/resources/application.yml @@ -0,0 +1,11 @@ +grpc: + client: + hello: + address: localhost:9090 + negotiation-type: plaintext +logging: + pattern: + console: "[%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5level [%t] [%logger - %line]: %m%n" + level: + com.baeldung.helloworld.consumer: info + include-application-name: false diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/pom.xml b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/pom.xml new file mode 100644 index 0000000000..0a5bea3e0b --- /dev/null +++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + + com.baeldung.spring-boot-modules + spring-boot-3-grpc + 1.0.0-SNAPSHOT + + + helloworld-grpc-java + + + + io.grpc + grpc-protobuf + ${io.grpc.version} + + + io.grpc + grpc-stub + ${io.grpc.version} + + + io.grpc + grpc-testing + ${io.grpc.version} + test + + + + javax.annotation + javax.annotation-api + ${annotation-api.version} + provided + true + + + + + + + kr.motd.maven + os-maven-plugin + ${os-maven-plugin.version} + + + + + org.xolstice.maven.plugins + protobuf-maven-plugin + ${protobuf-maven-plugin.version} + + com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier} + + grpc-java + io.grpc:protoc-gen-grpc-java:${io.grpc.version}:exe:${os.detected.classifier} + + + + + protobuf-compile + + compile + test-compile + + + + protobuf-compile-custom + + compile-custom + test-compile-custom + + + + + + + + + 1.58.0 + 3.25.1 + 1.7.1 + 0.6.1 + 1.3.2 + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/java/com/baeldung/helloworld/stubs/package-info.java b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/java/com/baeldung/helloworld/stubs/package-info.java new file mode 100644 index 0000000000..a7d7190612 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/java/com/baeldung/helloworld/stubs/package-info.java @@ -0,0 +1,5 @@ +/** + * This package contains the gRPC stubs + * generated by the protoc compiler. + */ +package com.baeldung.helloworld.stubs; diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/proto/helloworld.proto b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/proto/helloworld.proto new file mode 100644 index 0000000000..19461bae0a --- /dev/null +++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/proto/helloworld.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +option java_package = "com.baeldung.helloworld.stubs"; +option java_multiple_files = true; + +message HelloWorldRequest { + // a name to greet, default is "World" + optional string name = 1; +} + +message HelloWorldResponse { + string greeting = 1; +} + +service HelloWorldService { + + rpc SayHello(stream HelloWorldRequest) returns (stream HelloWorldResponse); + +} \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/pom.xml b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/pom.xml new file mode 100644 index 0000000000..f13d65203d --- /dev/null +++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + helloworld-grpc-provider + 0.0.1-SNAPSHOT + helloworld-grpc-provider + + + com.baeldung + parent-boot-3 + 0.0.1-SNAPSHOT + ../../../parent-boot-3 + + + + + net.devh + grpc-server-spring-boot-starter + ${grpc-spring-boot-starter.version} + + + com.baeldung.spring-boot-modules + helloworld-grpc-java + 1.0.0-SNAPSHOT + + + + + 3.2.0 + 2.15.0.RELEASE + + + \ No newline at end of file diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldController.java b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldController.java new file mode 100644 index 0000000000..2d9426a46e --- /dev/null +++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldController.java @@ -0,0 +1,42 @@ +package com.baeldung.helloworld.provider; + +import com.baeldung.helloworld.stubs.HelloWorldRequest; +import com.baeldung.helloworld.stubs.HelloWorldResponse; +import com.baeldung.helloworld.stubs.HelloWorldServiceGrpc; +import io.grpc.stub.StreamObserver; +import net.devh.boot.grpc.server.service.GrpcService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Optional; + +@GrpcService +public class HelloWorldController extends HelloWorldServiceGrpc.HelloWorldServiceImplBase { + + private static final Logger log = LoggerFactory.getLogger(HelloWorldController.class); + + private HelloWorldResponse sayHello(HelloWorldRequest request) { + log.info("Received request: {}", request); + return HelloWorldResponse + .newBuilder() + .setGreeting("Hello " + + Optional + .of(request.getName()) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .orElse("World") + + "!" + ) + .build(); + } + + @Override + public StreamObserver sayHello( + StreamObserver responseObserver + ) { + return StreamObserverUtility.proxyStream( + responseObserver, + this::sayHello + ); + } +} diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldProviderApplication.java b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldProviderApplication.java new file mode 100644 index 0000000000..fa69ed8d57 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldProviderApplication.java @@ -0,0 +1,13 @@ +package com.baeldung.helloworld.provider; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class HelloWorldProviderApplication { + + public static void main(String[] args) { + SpringApplication.run(HelloWorldProviderApplication.class, args); + } + +} diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/StreamObserverUtility.java b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/StreamObserverUtility.java new file mode 100644 index 0000000000..394f3a999c --- /dev/null +++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/StreamObserverUtility.java @@ -0,0 +1,35 @@ +package com.baeldung.helloworld.provider; + +import io.grpc.stub.StreamObserver; + +import java.util.function.Function; + +final class StreamObserverUtility { + + private StreamObserverUtility() { + } + + static StreamObserver proxyStream( + StreamObserver target, + Function handler + ) { + return new StreamObserver() { + @Override + public void onNext(Source value) { + final Target targetValue = handler.apply(value); + target.onNext(targetValue); + } + + @Override + public void onError(Throwable t) { + target.onError(t); + } + + @Override + public void onCompleted() { + target.onCompleted(); + } + }; + } + +} diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/resources/application.yml b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/resources/application.yml new file mode 100644 index 0000000000..2ccf6ad95f --- /dev/null +++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/resources/application.yml @@ -0,0 +1,9 @@ +grpc: + server: + port: 9090 +logging: + pattern: + console: "[%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5level [%t] [%logger - %line]: %m%n" + level: + com.baeldung.helloworld.provider: info + include-application-name: false diff --git a/spring-boot-modules/spring-boot-3-grpc/pom.xml b/spring-boot-modules/spring-boot-3-grpc/pom.xml new file mode 100644 index 0000000000..3b5ef15048 --- /dev/null +++ b/spring-boot-modules/spring-boot-3-grpc/pom.xml @@ -0,0 +1,25 @@ + + + 4.0.0 + com.baeldung.spring-boot-modules + spring-boot-3-grpc + 1.0.0-SNAPSHOT + spring-boot-3-grpc + pom + + + com.baeldung + parent-modules + 1.0.0-SNAPSHOT + ../../pom.xml + + + + helloworld-grpc-java + helloworld-grpc-provider + helloworld-grpc-consumer + + +