├── .doc └── grpc-java-spring.png ├── .gitignore ├── 01-grpc-playground ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── vinsguru │ │ │ ├── common │ │ │ ├── Demo.java │ │ │ └── GrpcServer.java │ │ │ ├── sec01 │ │ │ └── SimpleProtoDemo.java │ │ │ ├── sec02 │ │ │ └── ProtoDemo.java │ │ │ ├── sec03 │ │ │ ├── JsonPerson.java │ │ │ ├── Lec01Scalar.java │ │ │ ├── Lec02Serialization.java │ │ │ ├── Lec03PerformanceTest.java │ │ │ ├── Lec04Composition.java │ │ │ ├── Lec05Collection.java │ │ │ ├── Lec06Map.java │ │ │ ├── Lec07DefaultValues.java │ │ │ └── Lec08OneOf.java │ │ │ ├── sec04 │ │ │ ├── Lec01Import.java │ │ │ └── Lec02WellKnownTypes.java │ │ │ ├── sec05 │ │ │ ├── V1VersionCompatibility.java │ │ │ ├── V2VersionCompatibility.java │ │ │ ├── V3VersionCompatibility.java │ │ │ └── parser │ │ │ │ ├── V1Parser.java │ │ │ │ ├── V2Parser.java │ │ │ │ └── V3Parser.java │ │ │ ├── sec06 │ │ │ ├── BankService.java │ │ │ ├── TransferService.java │ │ │ ├── repository │ │ │ │ └── AccountRepository.java │ │ │ └── requesthandlers │ │ │ │ ├── DepositRequestHandler.java │ │ │ │ └── TransferRequestHandler.java │ │ │ ├── sec07 │ │ │ └── FlowControlService.java │ │ │ ├── sec08 │ │ │ └── GuessNumberService.java │ │ │ ├── sec09 │ │ │ ├── BankService.java │ │ │ ├── repository │ │ │ │ └── AccountRepository.java │ │ │ └── validator │ │ │ │ └── RequestValidator.java │ │ │ ├── sec10 │ │ │ ├── BankService.java │ │ │ ├── repository │ │ │ │ └── AccountRepository.java │ │ │ └── validator │ │ │ │ └── RequestValidator.java │ │ │ ├── sec11 │ │ │ ├── DeadlineBankService.java │ │ │ └── repository │ │ │ │ └── AccountRepository.java │ │ │ ├── sec12 │ │ │ ├── BankService.java │ │ │ ├── Constants.java │ │ │ ├── UserRole.java │ │ │ ├── UserRoleBankService.java │ │ │ ├── interceptors │ │ │ │ ├── ApiKeyValidationInterceptor.java │ │ │ │ ├── GzipResponseInterceptor.java │ │ │ │ ├── UserRoleInterceptor.java │ │ │ │ └── UserTokenInterceptor.java │ │ │ └── repository │ │ │ │ └── AccountRepository.java │ │ │ └── sec13 │ │ │ ├── BankService.java │ │ │ └── repository │ │ │ └── AccountRepository.java │ ├── proto │ │ ├── sec01 │ │ │ └── person.proto │ │ ├── sec02 │ │ │ └── person.proto │ │ ├── sec03 │ │ │ ├── collection.proto │ │ │ ├── composition.proto │ │ │ ├── map.proto │ │ │ ├── one-of.proto │ │ │ └── person.proto │ │ ├── sec04 │ │ │ ├── common │ │ │ │ ├── address.proto │ │ │ │ └── car.proto │ │ │ ├── person.proto │ │ │ └── well-known.proto │ │ ├── sec05 │ │ │ ├── v1 │ │ │ │ └── television.proto │ │ │ ├── v2 │ │ │ │ └── television.proto │ │ │ ├── v3 │ │ │ │ └── television.proto │ │ │ └── v4 │ │ │ │ └── television.proto │ │ ├── sec06 │ │ │ └── bank-service.proto │ │ ├── sec07 │ │ │ └── flow-control.proto │ │ ├── sec08 │ │ │ └── game.proto │ │ ├── sec09 │ │ │ └── input-validation.proto │ │ ├── sec10 │ │ │ └── input-validation.proto │ │ ├── sec11 │ │ │ └── bank-service.proto │ │ ├── sec12 │ │ │ └── bank-service.proto │ │ └── sec13 │ │ │ └── bank-service.proto │ └── resources │ │ └── logback.xml │ └── test │ ├── java │ └── com │ │ └── vinsguru │ │ └── test │ │ ├── common │ │ ├── AbstractChannelTest.java │ │ └── ResponseObserver.java │ │ ├── sec06 │ │ ├── AbstractTest.java │ │ ├── Lec01UnaryBlockingClientTest.java │ │ ├── Lec02UnaryAsyncClientTest.java │ │ ├── Lec03ServerStreamingClientTest.java │ │ ├── Lec04ClientStreamingTest.java │ │ └── Lec05BiDirectionalStreamingTest.java │ │ ├── sec07 │ │ ├── FlowControlTest.java │ │ └── ResponseHandler.java │ │ ├── sec08 │ │ ├── GuessANumberTest.java │ │ └── GuessResponseHandler.java │ │ ├── sec09 │ │ ├── AbstractTest.java │ │ ├── Lec01UnaryInputValidationTest.java │ │ └── Lec02ServerStreamingInputValidationTest.java │ │ ├── sec10 │ │ ├── AbstractTest.java │ │ ├── Lec01UnaryInputValidationTest.java │ │ └── Lec02ServerStreamingInputValidationTest.java │ │ ├── sec11 │ │ ├── AbstractTest.java │ │ ├── Lec01UnaryDeadlineTest.java │ │ ├── Lec02ServerStreamingDeadlineTest.java │ │ ├── Lec03WaitForReadyTest.java │ │ ├── Lec04LazyChannelDemoTest.java │ │ ├── Lec05EagerChannelDemoTest.java │ │ ├── Lec06KeepAliveDemoTest.java │ │ └── Lec07LoadBalancingDemoTest.java │ │ ├── sec12 │ │ ├── AbstractInterceptorTest.java │ │ ├── AbstractTest.java │ │ ├── Lec01GzipCallOptionsTest.java │ │ ├── Lec02ExecutorCallOptionsTest.java │ │ ├── Lec03DeadlineInterceptorTest.java │ │ ├── Lec04GzipInterceptorTest.java │ │ ├── Lec05ClientApiKeyInterceptorTest.java │ │ ├── Lec06UserSessionTokenInterceptorTest.java │ │ ├── Lec07UserRoleContextTest.java │ │ └── interceptors │ │ │ ├── DeadlineInterceptor.java │ │ │ └── GzipRequestInterceptor.java │ │ └── sec13 │ │ ├── AbstractTest.java │ │ └── GrpcSSLTest.java │ └── resources │ ├── certs │ ├── generate-certs.sh │ ├── grpc.keystore.jks │ └── grpc.truststore.jks │ └── nginx-load-balancing │ ├── config │ └── nginx.conf │ └── docker-compose.yaml ├── 02-project-template ├── aggregator-service │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── vinsguru │ │ │ │ └── aggregator │ │ │ │ └── AggregatorServiceApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── vinsguru │ │ └── aggregator │ │ └── tests │ │ └── UserTradeTest.java ├── pom.xml ├── proto │ ├── pom.xml │ └── src │ │ └── main │ │ └── proto │ │ ├── common │ │ └── common.proto │ │ ├── stock-service.proto │ │ └── user-service.proto └── user-service │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── vinsguru │ │ │ └── user │ │ │ └── UserServiceApplication.java │ └── resources │ │ ├── application.properties │ │ └── data.sql │ └── test │ └── java │ └── com │ └── vinsguru │ └── user │ └── tests │ └── UserServiceTest.java ├── 03-grpc-trading-platform ├── aggregator-service │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── vinsguru │ │ │ │ └── aggregator │ │ │ │ ├── AggregatorServiceApplication.java │ │ │ │ ├── config │ │ │ │ └── ApplicationConfiguration.java │ │ │ │ ├── controller │ │ │ │ ├── StockController.java │ │ │ │ ├── TradeController.java │ │ │ │ ├── UserController.java │ │ │ │ └── advice │ │ │ │ │ └── ApplicationExceptionHandler.java │ │ │ │ ├── dto │ │ │ │ └── PriceUpdateDto.java │ │ │ │ └── service │ │ │ │ ├── PriceUpdateListener.java │ │ │ │ ├── PriceUpdateSubscriptionInitializer.java │ │ │ │ ├── TradeService.java │ │ │ │ └── UserService.java │ │ └── resources │ │ │ ├── application.properties │ │ │ └── static │ │ │ └── index.html │ │ └── test │ │ └── java │ │ └── com │ │ └── vinsguru │ │ └── aggregator │ │ └── tests │ │ ├── StockUpdatesTest.java │ │ ├── UserTradeTest.java │ │ └── mockservice │ │ ├── StockMockService.java │ │ └── UserMockService.java ├── pom.xml ├── proto │ ├── pom.xml │ └── src │ │ └── main │ │ └── proto │ │ ├── common │ │ └── common.proto │ │ ├── stock-service.proto │ │ └── user-service.proto └── user-service │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── vinsguru │ │ │ └── user │ │ │ ├── UserServiceApplication.java │ │ │ ├── config │ │ │ └── ServerConfiguration.java │ │ │ ├── entity │ │ │ ├── PortfolioItem.java │ │ │ └── User.java │ │ │ ├── exceptions │ │ │ ├── InsufficientBalanceException.java │ │ │ ├── InsufficientSharesException.java │ │ │ ├── UnknownTickerException.java │ │ │ └── UnknownUserException.java │ │ │ ├── repository │ │ │ ├── PortfolioItemRepository.java │ │ │ └── UserRepository.java │ │ │ ├── service │ │ │ ├── UserService.java │ │ │ ├── advice │ │ │ │ └── ServiceExceptionHandler.java │ │ │ └── handler │ │ │ │ ├── StockTradeRequestHandler.java │ │ │ │ └── UserInformationRequestHandler.java │ │ │ └── util │ │ │ └── EntityMessageMapper.java │ └── resources │ │ ├── application.properties │ │ └── data.sql │ └── test │ └── java │ └── com │ └── vinsguru │ └── user │ └── tests │ └── UserServiceTest.java ├── 04-stock-service ├── README.md └── stock-service.jar ├── 99-old-projects ├── grpc-flix │ ├── aggregator-service │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ └── grpcflix │ │ │ │ └── aggregator │ │ │ │ ├── AggregatorApplication.java │ │ │ │ ├── controller │ │ │ │ └── AggregatorController.java │ │ │ │ ├── dto │ │ │ │ ├── RecommendedMovie.java │ │ │ │ └── UserGenre.java │ │ │ │ └── service │ │ │ │ └── UserMovieService.java │ │ │ └── resources │ │ │ └── application.yaml │ ├── movie-service │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ ├── java │ │ │ └── com │ │ │ │ └── grpcflix │ │ │ │ └── movie │ │ │ │ ├── MovieApplication.java │ │ │ │ ├── entity │ │ │ │ └── Movie.java │ │ │ │ ├── repository │ │ │ │ └── MovieRepository.java │ │ │ │ └── service │ │ │ │ └── MovieService.java │ │ │ └── resources │ │ │ ├── application.properties │ │ │ ├── data.sql │ │ │ └── movie.csv │ ├── pom.xml │ ├── proto │ │ ├── pom.xml │ │ └── src │ │ │ └── main │ │ │ └── proto │ │ │ ├── common │ │ │ └── common.proto │ │ │ ├── movie-service.proto │ │ │ └── user-service.proto │ └── user-service │ │ ├── pom.xml │ │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── grpcflix │ │ │ └── user │ │ │ ├── UserApplication.java │ │ │ ├── entity │ │ │ └── User.java │ │ │ ├── repository │ │ │ └── UserRepository.java │ │ │ └── service │ │ │ └── UserService.java │ │ └── resources │ │ ├── application.properties │ │ ├── data.sql │ │ └── user.csv ├── grpc-intro │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── vinsguru │ │ │ │ └── server │ │ │ │ ├── deadline │ │ │ │ ├── DeadlineService.java │ │ │ │ └── GrpcServer.java │ │ │ │ ├── loadbalancing │ │ │ │ ├── BankService.java │ │ │ │ ├── CashStreamingRequest.java │ │ │ │ ├── GrpcServer1.java │ │ │ │ └── GrpcServer2.java │ │ │ │ ├── metadata │ │ │ │ ├── AuthInterceptor.java │ │ │ │ ├── GrpcServer.java │ │ │ │ ├── MetadataService.java │ │ │ │ ├── ServerConstants.java │ │ │ │ └── UserRole.java │ │ │ │ ├── rpctypes │ │ │ │ ├── AccountDatabase.java │ │ │ │ ├── BankService.java │ │ │ │ ├── CashStreamingRequest.java │ │ │ │ ├── GrpcServer.java │ │ │ │ ├── TransferService.java │ │ │ │ └── TransferStreamingRequest.java │ │ │ │ └── ssl │ │ │ │ ├── BankService.java │ │ │ │ └── GrpcServer.java │ │ └── proto │ │ │ ├── bank-service.proto │ │ │ └── transfer-service.proto │ │ └── test │ │ └── java │ │ └── com │ │ └── vinsguru │ │ └── client │ │ ├── deadline │ │ ├── DeadlineClientTest.java │ │ └── DeadlineInterceptor.java │ │ ├── loadbalancing │ │ ├── ClientSideLoadBalancingTest.java │ │ ├── NginxTestClient.java │ │ ├── ServiceRegistry.java │ │ ├── TempNameResolver.java │ │ └── TempNameResolverProvider.java │ │ ├── metadata │ │ ├── ClientConstants.java │ │ ├── MetadataClientTest.java │ │ └── UserSessionToken.java │ │ └── rpctypes │ │ ├── BalanceStreamObserver.java │ │ ├── BankClientTest.java │ │ ├── MoneyStreamingResponse.java │ │ ├── TransferClientTest.java │ │ └── TransferStreamingResponse.java ├── node-client │ ├── bank-client.js │ ├── package-lock.json │ ├── package.json │ └── proto │ │ └── bank-service.proto ├── protobuf │ ├── pom.xml │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── vinsguru │ │ │ ├── json │ │ │ └── JPerson.java │ │ │ └── protobuf │ │ │ ├── CompositionDemo.java │ │ │ ├── DefaultValueDemo.java │ │ │ ├── MapDemo.java │ │ │ ├── OneOfDemo.java │ │ │ ├── PerformanceTest.java │ │ │ ├── PersonDemo.java │ │ │ └── VersionCompatibilityTest.java │ │ └── proto │ │ ├── common │ │ ├── address.proto │ │ └── car.proto │ │ ├── credentials.proto │ │ ├── dealer.proto │ │ ├── person.proto │ │ └── television.proto └── snakes-ladders │ ├── pom.xml │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── vinsguru │ │ │ └── game │ │ │ └── server │ │ │ ├── DieStreamingRequest.java │ │ │ ├── GameService.java │ │ │ ├── GrpcServer.java │ │ │ └── SnakesAndLaddersMap.java │ └── proto │ │ └── game-service.proto │ └── test │ └── java │ └── com │ └── vinsguru │ └── game │ └── client │ ├── GameClientTest.java │ └── GameStateStreamingResponse.java └── README.md /.doc/grpc-java-spring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinsguru/grpc-java-course/05c32a6a89a9fa0de16f838c6abf4f21c4a68655/.doc/grpc-java-spring.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Java template 2 | # Compiled class file 3 | **/*.class 4 | 5 | # Log file 6 | **/*.log 7 | 8 | # BlueJ files 9 | **/*.ctxt 10 | 11 | # Mobile Tools for Java (J2ME) 12 | **/.mtj.tmp/ 13 | 14 | # Package Files # 15 | **/*.jar 16 | !04-stock-service/stock-service.jar 17 | **/*.war 18 | **/*.nar 19 | **/*.ear 20 | **/*.zip 21 | **/*.tar.gz 22 | **/*.rar 23 | 24 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 25 | **/hs_err_pid* 26 | 27 | ### Maven template 28 | **/target/ 29 | **/pom.xml.tag 30 | **/pom.xml.releaseBackup 31 | **/pom.xml.versionsBackup 32 | **/pom.xml.next 33 | **/release.properties 34 | **/dependency-reduced-pom.xml 35 | **/buildNumber.properties 36 | **/.mvn/timing.properties 37 | **/.mvn/wrapper/maven-wrapper.jar 38 | 39 | **/*.iml 40 | 41 | **/.idea/ 42 | 43 | 44 | **/HELP.md 45 | **/.mvn/ 46 | **/mvnw 47 | **/mvnw.cmd 48 | **/node_modules/ 49 | 50 | 51 | **/.DS_Store -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/common/Demo.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.common; 2 | 3 | import com.vinsguru.sec12.BankService; 4 | import com.vinsguru.sec12.interceptors.ApiKeyValidationInterceptor; 5 | 6 | /* 7 | a simple class to start the server with specific services for demo purposes 8 | */ 9 | public class Demo { 10 | 11 | public static void main(String[] args) { 12 | 13 | GrpcServer.create(6565, builder -> { 14 | builder.addService(new BankService()) 15 | .intercept(new ApiKeyValidationInterceptor()); 16 | }) 17 | .start() 18 | .await(); 19 | 20 | } 21 | 22 | 23 | /* Created for load balancing demo 24 | private static class BankInstance1 { 25 | public static void main(String[] args) { 26 | GrpcServer.create(6565, new BankService()) 27 | .start() 28 | .await(); 29 | } 30 | } 31 | 32 | private static class BankInstance2 { 33 | public static void main(String[] args) { 34 | GrpcServer.create(7575, new BankService()) 35 | .start() 36 | .await(); 37 | } 38 | } 39 | */ 40 | } 41 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec01/SimpleProtoDemo.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec01; 2 | 3 | import com.vinsguru.models.sec01.PersonOuterClass; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | public class SimpleProtoDemo { 8 | 9 | private static final Logger log = LoggerFactory.getLogger(SimpleProtoDemo.class); 10 | 11 | public static void main(String[] args) { 12 | var person = PersonOuterClass.Person.newBuilder() 13 | .setName("sam") 14 | .setAge(12) 15 | .build(); 16 | log.info("{}", person); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec02/ProtoDemo.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02; 2 | 3 | import com.vinsguru.models.sec02.Person; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | public class ProtoDemo { 8 | 9 | private static final Logger log = LoggerFactory.getLogger(ProtoDemo.class); 10 | 11 | public static void main(String[] args) { 12 | 13 | // create person1 14 | var person1 = createPerson(); 15 | 16 | // create another instance with same values 17 | var person2 = createPerson(); 18 | 19 | // compare 20 | log.info("equals {}", person1.equals(person2)); 21 | log.info("== {}", (person1 == person2)); 22 | 23 | // mutable? No 24 | 25 | // create another instance with diff values 26 | var person3 = person1.toBuilder().setName("mike").build(); 27 | log.info("person3: {}", person3); 28 | 29 | // compare 30 | log.info("equals {}", person1.equals(person3)); 31 | log.info("== {}", (person1 == person3)); 32 | 33 | //null? 34 | var person4 = person1.toBuilder().clearName().build(); 35 | log.info("person4: {}", person4); 36 | 37 | } 38 | 39 | private static Person createPerson() { 40 | return Person.newBuilder() 41 | .setName("sam") 42 | .setAge(12) 43 | .build(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec03/JsonPerson.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | public record JsonPerson(String lastName, 4 | int age, 5 | String email, 6 | boolean employed, 7 | double salary, 8 | long bankAccountNumber, 9 | int balance) { 10 | } 11 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec03/Lec01Scalar.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.models.sec03.Person; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | public class Lec01Scalar { 8 | 9 | private static final Logger log = LoggerFactory.getLogger(Lec01Scalar.class); 10 | 11 | public static void main(String[] args) { 12 | 13 | var person = Person.newBuilder() 14 | .setLastName("sam") 15 | .setAge(12) 16 | .setEmail("sam@gmail.com") 17 | .setEmployed(true) 18 | .setSalary(1000.2345) 19 | .setBankAccountNumber(123456789012L) 20 | .setBalance(-10000) 21 | .build(); 22 | 23 | log.info("{}", person); 24 | 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec03/Lec02Serialization.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.models.sec03.Person; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.IOException; 8 | import java.nio.file.Files; 9 | import java.nio.file.Path; 10 | 11 | public class Lec02Serialization { 12 | 13 | private static final Logger log = LoggerFactory.getLogger(Lec02Serialization.class); 14 | private static final Path PATH = Path.of("person.out"); 15 | 16 | public static void main(String[] args) throws IOException { 17 | 18 | var person = Person.newBuilder() 19 | .setLastName("sam") 20 | .setAge(12) 21 | .setEmail("sam@gmail.com") 22 | .setEmployed(false) 23 | .setSalary(1000.2345) 24 | .setBankAccountNumber(123456789012L) 25 | .setBalance(-10000) 26 | .build(); 27 | 28 | serialize(person); 29 | log.info("{}", deserialize()); 30 | log.info("equals: {}", person.equals(deserialize())); 31 | log.info("bytes length: {}", person.toByteArray().length); 32 | } 33 | 34 | public static void serialize(Person person) throws IOException { 35 | try(var stream = Files.newOutputStream(PATH)) { 36 | person.writeTo(stream); 37 | } 38 | //person.writeTo(Files.newOutputStream(PATH)); 39 | } 40 | 41 | public static Person deserialize() throws IOException { 42 | try(var stream = Files.newInputStream(PATH)){ 43 | return Person.parseFrom(stream); 44 | } 45 | //return Person.parseFrom(Files.newInputStream(PATH)); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec03/Lec04Composition.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.models.sec03.Address; 4 | import com.vinsguru.models.sec03.School; 5 | import com.vinsguru.models.sec03.Student; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class Lec04Composition { 10 | 11 | private static final Logger log = LoggerFactory.getLogger(Lec04Composition.class); 12 | 13 | public static void main(String[] args) { 14 | 15 | // create student 16 | var address = Address.newBuilder() 17 | .setStreet("123 main st") 18 | .setCity("atlanta") 19 | .setState("GA") 20 | .build(); 21 | var student = Student.newBuilder() 22 | .setName("sam") 23 | .setAddress(address) 24 | .build(); 25 | // create school 26 | var school = School.newBuilder() 27 | .setId(1) 28 | .setName("high school") 29 | .setAddress(address.toBuilder().setStreet("234 main st").build()) 30 | .build(); 31 | 32 | log.info("school: {}", school); 33 | log.info("student: {}", student); 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec03/Lec05Collection.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.models.sec03.Book; 4 | import com.vinsguru.models.sec03.Library; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | import java.util.List; 9 | import java.util.Set; 10 | 11 | public class Lec05Collection { 12 | 13 | private static final Logger log = LoggerFactory.getLogger(Lec05Collection.class); 14 | 15 | public static void main(String[] args) { 16 | 17 | // create books 18 | var book1 = Book.newBuilder() 19 | .setTitle("harry potter - part 1") 20 | .setAuthor("j k rowling") 21 | .setPublicationYear(1997) 22 | .build(); 23 | var book2 = book1.toBuilder().setTitle("harry potter - part 2").setPublicationYear(1998).build(); 24 | var book3 = book1.toBuilder().setTitle("harry potter - part 3").setPublicationYear(1999).build(); 25 | 26 | var library = Library.newBuilder() 27 | .setName("fantasy library") 28 | // .addBooks(book1) 29 | // .addBooks(book2) 30 | // .addBooks(book3) 31 | .addAllBooks(List.of(book1, book2, book3)) 32 | .build(); 33 | 34 | log.info("{}", library); 35 | 36 | 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec03/Lec06Map.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.models.sec03.BodyStyle; 4 | import com.vinsguru.models.sec03.Car; 5 | import com.vinsguru.models.sec03.Dealer; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class Lec06Map { 10 | 11 | private static final Logger log = LoggerFactory.getLogger(Lec06Map.class); 12 | 13 | public static void main(String[] args) { 14 | 15 | var car1 = Car.newBuilder() 16 | .setMake("honda") 17 | .setModel("civic") 18 | .setYear(2000) 19 | .setBodyStyle(BodyStyle.COUPE) 20 | .build(); 21 | var car2 = Car.newBuilder() 22 | .setMake("honda") 23 | .setModel("accord") 24 | .setYear(2002) 25 | .setBodyStyle(BodyStyle.SEDAN) 26 | .build(); 27 | 28 | var dealer = Dealer.newBuilder() 29 | .putInventory(car1.getYear(), car1) 30 | .putInventory(car2.getYear(), car2) 31 | .build(); 32 | 33 | log.info("{}", dealer); 34 | 35 | log.info("2002 ? : {}", dealer.containsInventory(2002)); 36 | log.info("2003 ? : {}", dealer.containsInventory(2003)); 37 | 38 | log.info("2002 model: {}", dealer.getInventoryOrThrow(2002).getBodyStyle()); 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec03/Lec07DefaultValues.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.models.sec03.*; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | public class Lec07DefaultValues { 8 | 9 | private static final Logger log = LoggerFactory.getLogger(Lec07DefaultValues.class); 10 | 11 | public static void main(String[] args) { 12 | 13 | var school = School.newBuilder().build(); 14 | 15 | log.info("{}", school.getId()); 16 | log.info("{}", school.getName()); 17 | log.info("{}", school.getAddress().getCity()); 18 | 19 | 20 | log.info("is default? : {}", school.getAddress().equals(Address.getDefaultInstance())); 21 | 22 | // has 23 | log.info("has address? {}", school.hasAddress()); 24 | 25 | // collection 26 | var lib = Library.newBuilder().build(); 27 | log.info("{}", lib.getBooksList()); 28 | 29 | // map 30 | var dealer = Dealer.newBuilder().build(); 31 | log.info("{}", dealer.getInventoryMap()); 32 | 33 | // enum 34 | var car = Car.newBuilder().build(); 35 | log.info("{}", car.getBodyStyle()); 36 | 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec03/Lec08OneOf.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.models.sec03.Credentials; 4 | import com.vinsguru.models.sec03.Email; 5 | import com.vinsguru.models.sec03.Phone; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | public class Lec08OneOf { 10 | 11 | private static final Logger log = LoggerFactory.getLogger(Lec08OneOf.class); 12 | 13 | public static void main(String[] args) { 14 | 15 | var email = Email.newBuilder().setAddress("sam@gmail.com").setPassword("admin").build(); 16 | var phone = Phone.newBuilder().setNumber(123456789).setCode(123).build(); 17 | 18 | login(Credentials.newBuilder().setEmail(email).build()); 19 | login(Credentials.newBuilder().setPhone(phone).build()); 20 | 21 | // what will happen if we set both? 22 | // last one wins! 23 | login(Credentials.newBuilder().setEmail(email).setPhone(phone).build()); 24 | 25 | } 26 | 27 | private static void login(Credentials credentials){ 28 | switch (credentials.getLoginTypeCase()){ 29 | case EMAIL -> log.info("email -> {}", credentials.getEmail()); 30 | case PHONE -> log.info("phone -> {}", credentials.getPhone()); 31 | } 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec04/Lec01Import.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec04; 2 | 3 | import com.vinsguru.models.common.Address; 4 | import com.vinsguru.models.common.BodyStyle; 5 | import com.vinsguru.models.common.Car; 6 | import com.vinsguru.models.sec04.Person; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | public class Lec01Import { 11 | 12 | private static final Logger log = LoggerFactory.getLogger(Lec01Import.class); 13 | 14 | public static void main(String[] args) { 15 | 16 | var address = Address.newBuilder().setCity("atlanta").build(); 17 | var car = Car.newBuilder().setBodyStyle(BodyStyle.COUPE).build(); 18 | var person = Person.newBuilder() 19 | .setName("sam") 20 | .setAge(12) 21 | .setCar(car) 22 | .setAddress(address) 23 | .build(); 24 | 25 | log.info("{}", person); 26 | 27 | 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec04/Lec02WellKnownTypes.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec04; 2 | 3 | import com.google.protobuf.Int32Value; 4 | import com.google.protobuf.Timestamp; 5 | import com.vinsguru.models.sec04.Sample; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.time.Instant; 10 | 11 | public class Lec02WellKnownTypes { 12 | 13 | private static final Logger log = LoggerFactory.getLogger(Lec02WellKnownTypes.class); 14 | 15 | public static void main(String[] args) { 16 | 17 | var sample = Sample.newBuilder() 18 | .setAge(Int32Value.of(12)) 19 | .setLoginTime(Timestamp.newBuilder().setSeconds(Instant.now().getEpochSecond()).build()) 20 | .build(); 21 | 22 | log.info("{}", Instant.ofEpochSecond(sample.getLoginTime().getSeconds())); 23 | 24 | 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec05/V1VersionCompatibility.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05; 2 | 3 | import com.google.protobuf.InvalidProtocolBufferException; 4 | import com.vinsguru.models.sec05.v1.Television; 5 | import com.vinsguru.sec05.parser.V1Parser; 6 | import com.vinsguru.sec05.parser.V2Parser; 7 | import com.vinsguru.sec05.parser.V3Parser; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | public class V1VersionCompatibility { 12 | 13 | private static final Logger log = LoggerFactory.getLogger(V1VersionCompatibility.class); 14 | 15 | public static void main(String[] args) throws InvalidProtocolBufferException { 16 | 17 | var tv = Television.newBuilder() 18 | .setBrand("samsung") 19 | .setYear(2019) 20 | .build(); 21 | 22 | V1Parser.parse(tv.toByteArray()); 23 | V2Parser.parse(tv.toByteArray()); 24 | V3Parser.parse(tv.toByteArray()); 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec05/V2VersionCompatibility.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05; 2 | 3 | import com.google.protobuf.InvalidProtocolBufferException; 4 | import com.vinsguru.models.sec05.v2.Television; 5 | import com.vinsguru.models.sec05.v2.Type; 6 | import com.vinsguru.sec05.parser.V1Parser; 7 | import com.vinsguru.sec05.parser.V2Parser; 8 | import com.vinsguru.sec05.parser.V3Parser; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | public class V2VersionCompatibility { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(V2VersionCompatibility.class); 15 | 16 | public static void main(String[] args) throws InvalidProtocolBufferException { 17 | 18 | var tv = Television.newBuilder() 19 | .setBrand("samsung") 20 | .setModel(2019) 21 | .setType(Type.UHD) 22 | .build(); 23 | 24 | V1Parser.parse(tv.toByteArray()); 25 | V2Parser.parse(tv.toByteArray()); 26 | V3Parser.parse(tv.toByteArray()); 27 | 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec05/V3VersionCompatibility.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05; 2 | 3 | import com.google.protobuf.InvalidProtocolBufferException; 4 | import com.vinsguru.models.sec05.v3.Television; 5 | import com.vinsguru.models.sec05.v3.Type; 6 | import com.vinsguru.sec05.parser.V1Parser; 7 | import com.vinsguru.sec05.parser.V2Parser; 8 | import com.vinsguru.sec05.parser.V3Parser; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | public class V3VersionCompatibility { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(V3VersionCompatibility.class); 15 | 16 | public static void main(String[] args) throws InvalidProtocolBufferException { 17 | 18 | var tv = Television.newBuilder() 19 | .setBrand("samsung") 20 | .setType(Type.UHD) 21 | .build(); 22 | 23 | V1Parser.parse(tv.toByteArray()); 24 | V2Parser.parse(tv.toByteArray()); 25 | V3Parser.parse(tv.toByteArray()); 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec05/parser/V1Parser.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05.parser; 2 | 3 | import com.google.protobuf.InvalidProtocolBufferException; 4 | import com.vinsguru.models.sec05.v1.Television; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | public class V1Parser { 9 | 10 | private static final Logger log = LoggerFactory.getLogger(V1Parser.class); 11 | 12 | public static void parse(byte[] bytes) throws InvalidProtocolBufferException { 13 | var tv = Television.parseFrom(bytes); 14 | log.info("brand: {}", tv.getBrand()); 15 | log.info("year: {}", tv.getYear()); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec05/parser/V2Parser.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05.parser; 2 | 3 | import com.google.protobuf.InvalidProtocolBufferException; 4 | import com.vinsguru.models.sec05.v2.Television; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | public class V2Parser { 9 | 10 | private static final Logger log = LoggerFactory.getLogger(V2Parser.class); 11 | 12 | public static void parse(byte[] bytes) throws InvalidProtocolBufferException { 13 | var tv = Television.parseFrom(bytes); 14 | log.info("brand: {}", tv.getBrand()); 15 | log.info("model: {}", tv.getModel()); 16 | log.info("type: {}", tv.getType()); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec05/parser/V3Parser.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05.parser; 2 | 3 | import com.google.protobuf.InvalidProtocolBufferException; 4 | import com.vinsguru.models.sec05.v3.Television; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | public class V3Parser { 9 | 10 | private static final Logger log = LoggerFactory.getLogger(V3Parser.class); 11 | 12 | public static void parse(byte[] bytes) throws InvalidProtocolBufferException { 13 | var tv = Television.parseFrom(bytes); 14 | log.info("brand: {}", tv.getBrand()); 15 | log.info("type: {}", tv.getType()); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec06/TransferService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec06; 2 | 3 | import com.vinsguru.models.sec06.TransferRequest; 4 | import com.vinsguru.models.sec06.TransferResponse; 5 | import com.vinsguru.models.sec06.TransferServiceGrpc; 6 | import com.vinsguru.sec06.requesthandlers.TransferRequestHandler; 7 | import io.grpc.stub.StreamObserver; 8 | 9 | public class TransferService extends TransferServiceGrpc.TransferServiceImplBase { 10 | 11 | @Override 12 | public StreamObserver transfer(StreamObserver responseObserver) { 13 | return new TransferRequestHandler(responseObserver); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec06/repository/AccountRepository.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec06.repository; 2 | 3 | import java.util.Collections; 4 | import java.util.Map; 5 | import java.util.function.Function; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.IntStream; 8 | 9 | public class AccountRepository { 10 | 11 | private static final Map db = IntStream.rangeClosed(1, 10) 12 | .boxed() 13 | .collect(Collectors.toConcurrentMap( 14 | Function.identity(), 15 | v -> 100 16 | )); 17 | 18 | public static Integer getBalance(int accountNumber){ 19 | return db.get(accountNumber); 20 | } 21 | 22 | public static void addAmount(int accountNumber, int amount){ 23 | db.computeIfPresent(accountNumber, (k, v) -> v + amount); 24 | } 25 | 26 | public static void deductAmount(int accountNumber, int amount){ 27 | db.computeIfPresent(accountNumber, (k, v) -> v - amount); 28 | } 29 | 30 | public static Map getAllAccounts(){ 31 | return Collections.unmodifiableMap(db); 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec06/requesthandlers/DepositRequestHandler.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec06.requesthandlers; 2 | 3 | import com.vinsguru.models.sec06.AccountBalance; 4 | import com.vinsguru.models.sec06.DepositRequest; 5 | import com.vinsguru.sec06.repository.AccountRepository; 6 | import io.grpc.stub.StreamObserver; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | public class DepositRequestHandler implements StreamObserver { 11 | 12 | private static final Logger log = LoggerFactory.getLogger(DepositRequestHandler.class); 13 | private final StreamObserver responseObserver; 14 | private int accountNumber; 15 | 16 | public DepositRequestHandler(StreamObserver responseObserver) { 17 | this.responseObserver = responseObserver; 18 | } 19 | 20 | @Override 21 | public void onNext(DepositRequest depositRequest) { 22 | log.info("received deposit {}", depositRequest); 23 | switch (depositRequest.getRequestCase()) { 24 | case ACCOUNT_NUMBER -> this.accountNumber = depositRequest.getAccountNumber(); 25 | case MONEY -> AccountRepository.addAmount(this.accountNumber, depositRequest.getMoney().getAmount()); 26 | } 27 | } 28 | 29 | @Override 30 | public void onError(Throwable throwable) { 31 | log.info("client error {}", throwable.getMessage()); 32 | } 33 | 34 | @Override 35 | public void onCompleted() { 36 | var accountBalance = AccountBalance.newBuilder() 37 | .setAccountNumber(this.accountNumber) 38 | .setBalance(AccountRepository.getBalance(this.accountNumber)) 39 | .build(); 40 | this.responseObserver.onNext(accountBalance); 41 | this.responseObserver.onCompleted(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec07/FlowControlService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec07; 2 | 3 | import com.vinsguru.models.sec07.FlowControlServiceGrpc; 4 | import com.vinsguru.models.sec07.Output; 5 | import com.vinsguru.models.sec07.RequestSize; 6 | import io.grpc.stub.StreamObserver; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.util.stream.IntStream; 11 | 12 | public class FlowControlService extends FlowControlServiceGrpc.FlowControlServiceImplBase { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(FlowControlService.class); 15 | 16 | @Override 17 | public StreamObserver getMessages(StreamObserver responseObserver) { 18 | return new RequestHandler(responseObserver); 19 | } 20 | 21 | private static class RequestHandler implements StreamObserver { 22 | 23 | private final StreamObserver responseObserver; 24 | private Integer emitted; // to keep track the number of messages emitted so far! 25 | 26 | public RequestHandler(StreamObserver responseObserver) { 27 | this.responseObserver = responseObserver; 28 | this.emitted = 0; 29 | } 30 | 31 | @Override 32 | public void onNext(RequestSize requestSize) { 33 | IntStream.rangeClosed((emitted + 1), 100) 34 | .limit(requestSize.getSize()) 35 | .forEach(i -> { 36 | log.info("emitting {}", i); 37 | responseObserver.onNext(Output.newBuilder().setValue(i).build()); 38 | }); 39 | emitted = emitted + requestSize.getSize(); 40 | if(emitted >= 100) { 41 | responseObserver.onCompleted(); 42 | } 43 | } 44 | 45 | @Override 46 | public void onError(Throwable throwable) { 47 | 48 | } 49 | 50 | @Override 51 | public void onCompleted() { 52 | this.responseObserver.onCompleted(); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec09/repository/AccountRepository.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.repository; 2 | 3 | import java.util.Collections; 4 | import java.util.Map; 5 | import java.util.function.Function; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.IntStream; 8 | 9 | public class AccountRepository { 10 | 11 | private static final Map db = IntStream.rangeClosed(1, 10) 12 | .boxed() 13 | .collect(Collectors.toConcurrentMap( 14 | Function.identity(), 15 | v -> 100 16 | )); 17 | 18 | public static Integer getBalance(int accountNumber){ 19 | return db.get(accountNumber); 20 | } 21 | 22 | public static void addAmount(int accountNumber, int amount){ 23 | db.computeIfPresent(accountNumber, (k, v) -> v + amount); 24 | } 25 | 26 | public static void deductAmount(int accountNumber, int amount){ 27 | db.computeIfPresent(accountNumber, (k, v) -> v - amount); 28 | } 29 | 30 | public static Map getAllAccounts(){ 31 | return Collections.unmodifiableMap(db); 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec09/validator/RequestValidator.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.validator; 2 | 3 | import io.grpc.Status; 4 | 5 | import java.util.Optional; 6 | 7 | public class RequestValidator { 8 | 9 | public static Optional validateAccount(int accountNumber){ 10 | if(accountNumber > 0 && accountNumber < 11){ 11 | return Optional.empty(); 12 | } 13 | return Optional.of(Status.INVALID_ARGUMENT.withDescription("account number should be between 1 and 10")); 14 | } 15 | 16 | public static Optional isAmountDivisibleBy10(int amount){ 17 | if(amount > 0 && amount % 10 == 0){ 18 | return Optional.empty(); 19 | } 20 | return Optional.of(Status.INVALID_ARGUMENT.withDescription("requested amount should be 10 multiples")); 21 | } 22 | 23 | public static Optional hasSufficientBalance(int amount, int balance){ 24 | if(amount <= balance){ 25 | return Optional.empty(); 26 | } 27 | return Optional.of(Status.FAILED_PRECONDITION.withDescription("insufficient balance")); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec10/repository/AccountRepository.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec10.repository; 2 | 3 | import java.util.Collections; 4 | import java.util.Map; 5 | import java.util.function.Function; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.IntStream; 8 | 9 | public class AccountRepository { 10 | 11 | private static final Map db = IntStream.rangeClosed(1, 10) 12 | .boxed() 13 | .collect(Collectors.toConcurrentMap( 14 | Function.identity(), 15 | v -> 100 16 | )); 17 | 18 | public static Integer getBalance(int accountNumber){ 19 | return db.get(accountNumber); 20 | } 21 | 22 | public static void addAmount(int accountNumber, int amount){ 23 | db.computeIfPresent(accountNumber, (k, v) -> v + amount); 24 | } 25 | 26 | public static void deductAmount(int accountNumber, int amount){ 27 | db.computeIfPresent(accountNumber, (k, v) -> v - amount); 28 | } 29 | 30 | public static Map getAllAccounts(){ 31 | return Collections.unmodifiableMap(db); 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec10/validator/RequestValidator.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec10.validator; 2 | 3 | import com.vinsguru.models.sec10.ErrorMessage; 4 | import com.vinsguru.models.sec10.ValidationCode; 5 | import io.grpc.Metadata; 6 | import io.grpc.Status; 7 | import io.grpc.StatusRuntimeException; 8 | import io.grpc.protobuf.ProtoUtils; 9 | 10 | import java.util.Optional; 11 | 12 | public class RequestValidator { 13 | 14 | private static final Metadata.Key ERROR_MESSAGE_KEY = ProtoUtils.keyForProto(ErrorMessage.getDefaultInstance()); 15 | 16 | public static Optional validateAccount(int accountNumber) { 17 | if (accountNumber > 0 && accountNumber < 11) { 18 | return Optional.empty(); 19 | } 20 | var metadata = toMetadata(ValidationCode.INVALID_ACCOUNT); 21 | return Optional.of(Status.INVALID_ARGUMENT.asRuntimeException(metadata)); 22 | } 23 | 24 | public static Optional isAmountDivisibleBy10(int amount) { 25 | if (amount > 0 && amount % 10 == 0) { 26 | return Optional.empty(); 27 | } 28 | var metadata = toMetadata(ValidationCode.INVALID_AMOUNT); 29 | return Optional.of(Status.INVALID_ARGUMENT.asRuntimeException(metadata)); 30 | } 31 | 32 | public static Optional hasSufficientBalance(int amount, int balance) { 33 | if (amount <= balance) { 34 | return Optional.empty(); 35 | } 36 | var metadata = toMetadata(ValidationCode.INSUFFICIENT_BALANCE); 37 | return Optional.of(Status.FAILED_PRECONDITION.asRuntimeException(metadata)); 38 | } 39 | 40 | private static Metadata toMetadata(ValidationCode code) { 41 | var metadata = new Metadata(); 42 | var errorMessage = ErrorMessage.newBuilder() 43 | .setValidationCode(code) 44 | .build(); 45 | metadata.put(ERROR_MESSAGE_KEY, errorMessage); 46 | return metadata; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec11/repository/AccountRepository.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec11.repository; 2 | 3 | import java.util.Collections; 4 | import java.util.Map; 5 | import java.util.function.Function; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.IntStream; 8 | 9 | public class AccountRepository { 10 | 11 | private static final Map db = IntStream.rangeClosed(1, 10) 12 | .boxed() 13 | .collect(Collectors.toConcurrentMap( 14 | Function.identity(), 15 | v -> 100 16 | )); 17 | 18 | public static Integer getBalance(int accountNumber){ 19 | return db.get(accountNumber); 20 | } 21 | 22 | public static void addAmount(int accountNumber, int amount){ 23 | db.computeIfPresent(accountNumber, (k, v) -> v + amount); 24 | } 25 | 26 | public static void deductAmount(int accountNumber, int amount){ 27 | db.computeIfPresent(accountNumber, (k, v) -> v - amount); 28 | } 29 | 30 | public static Map getAllAccounts(){ 31 | return Collections.unmodifiableMap(db); 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec12/Constants.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec12; 2 | 3 | import io.grpc.Context; 4 | import io.grpc.Metadata; 5 | 6 | public class Constants { 7 | 8 | public static final Metadata.Key API_KEY = Metadata.Key.of("api-key", Metadata.ASCII_STRING_MARSHALLER); 9 | 10 | public static final Metadata.Key USER_TOKEN_KEY = Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER); 11 | public static final String BEARER = "Bearer"; 12 | 13 | // Authorization: Bearer eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ1234567890 14 | 15 | public static final Context.Key USER_ROLE_KEY = Context.key("user-role"); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec12/UserRole.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec12; 2 | 3 | public enum UserRole { 4 | 5 | STANDARD, 6 | PRIME; 7 | 8 | } 9 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec12/UserRoleBankService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec12; 2 | 3 | import com.vinsguru.models.sec12.AccountBalance; 4 | import com.vinsguru.models.sec12.BalanceCheckRequest; 5 | import com.vinsguru.models.sec12.BankServiceGrpc; 6 | import com.vinsguru.sec12.repository.AccountRepository; 7 | import io.grpc.stub.StreamObserver; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | public class UserRoleBankService extends BankServiceGrpc.BankServiceImplBase { 12 | 13 | private static final Logger log = LoggerFactory.getLogger(UserRoleBankService.class); 14 | 15 | @Override 16 | public void getAccountBalance(BalanceCheckRequest request, StreamObserver responseObserver) { 17 | var accountNumber = request.getAccountNumber(); 18 | var balance = AccountRepository.getBalance(accountNumber); 19 | if(UserRole.STANDARD.equals(Constants.USER_ROLE_KEY.get())){ 20 | var fee = balance > 0 ? 1 : 0; 21 | AccountRepository.deductAmount(accountNumber, fee); 22 | balance = balance - fee; 23 | } 24 | var accountBalance = AccountBalance.newBuilder() 25 | .setAccountNumber(accountNumber) 26 | .setBalance(balance) 27 | .build(); 28 | responseObserver.onNext(accountBalance); 29 | responseObserver.onCompleted(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec12/interceptors/ApiKeyValidationInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec12.interceptors; 2 | 3 | import com.vinsguru.sec12.Constants; 4 | import io.grpc.*; 5 | 6 | import java.util.Objects; 7 | 8 | public class ApiKeyValidationInterceptor implements ServerInterceptor { 9 | 10 | @Override 11 | public ServerCall.Listener interceptCall(ServerCall serverCall, 12 | Metadata metadata, 13 | ServerCallHandler serverCallHandler) { 14 | var apiKey = metadata.get(Constants.API_KEY); 15 | if(isValid(apiKey)){ 16 | return serverCallHandler.startCall(serverCall, metadata); 17 | } 18 | serverCall.close( 19 | Status.UNAUTHENTICATED.withDescription("client must provide valid api key"), 20 | metadata 21 | ); 22 | return new ServerCall.Listener() { 23 | }; 24 | } 25 | 26 | private boolean isValid(String apiKey){ 27 | return Objects.nonNull(apiKey) && apiKey.equals("bank-client-secret"); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec12/interceptors/GzipResponseInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec12.interceptors; 2 | 3 | import io.grpc.Metadata; 4 | import io.grpc.ServerCall; 5 | import io.grpc.ServerCallHandler; 6 | import io.grpc.ServerInterceptor; 7 | 8 | public class GzipResponseInterceptor implements ServerInterceptor { 9 | 10 | @Override 11 | public ServerCall.Listener interceptCall(ServerCall serverCall, 12 | Metadata metadata, 13 | ServerCallHandler serverCallHandler) { 14 | serverCall.setCompression("gzip"); 15 | return serverCallHandler.startCall(serverCall, metadata); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec12/repository/AccountRepository.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec12.repository; 2 | 3 | import java.util.Collections; 4 | import java.util.Map; 5 | import java.util.function.Function; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.IntStream; 8 | 9 | public class AccountRepository { 10 | 11 | private static final Map db = IntStream.rangeClosed(1, 10) 12 | .boxed() 13 | .collect(Collectors.toConcurrentMap( 14 | Function.identity(), 15 | v -> 100 16 | )); 17 | 18 | public static Integer getBalance(int accountNumber){ 19 | return db.get(accountNumber); 20 | } 21 | 22 | public static void addAmount(int accountNumber, int amount){ 23 | db.computeIfPresent(accountNumber, (k, v) -> v + amount); 24 | } 25 | 26 | public static void deductAmount(int accountNumber, int amount){ 27 | db.computeIfPresent(accountNumber, (k, v) -> v - amount); 28 | } 29 | 30 | public static Map getAllAccounts(){ 31 | return Collections.unmodifiableMap(db); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/java/com/vinsguru/sec13/repository/AccountRepository.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec13.repository; 2 | 3 | import java.util.Collections; 4 | import java.util.Map; 5 | import java.util.function.Function; 6 | import java.util.stream.Collectors; 7 | import java.util.stream.IntStream; 8 | 9 | public class AccountRepository { 10 | 11 | private static final Map db = IntStream.rangeClosed(1, 10) 12 | .boxed() 13 | .collect(Collectors.toConcurrentMap( 14 | Function.identity(), 15 | v -> 100 16 | )); 17 | 18 | public static Integer getBalance(int accountNumber){ 19 | return db.get(accountNumber); 20 | } 21 | 22 | public static void addAmount(int accountNumber, int amount){ 23 | db.computeIfPresent(accountNumber, (k, v) -> v + amount); 24 | } 25 | 26 | public static void deductAmount(int accountNumber, int amount){ 27 | db.computeIfPresent(accountNumber, (k, v) -> v - amount); 28 | } 29 | 30 | public static Map getAllAccounts(){ 31 | return Collections.unmodifiableMap(db); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec01/person.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec01; 4 | 5 | option java_package = "com.vinsguru.models.sec01"; 6 | 7 | /* 8 | multi line comment 9 | This is my proto 10 | */ 11 | message Person { 12 | // single line comment 13 | string name = 1; // i can comment here as well 14 | int32 age = 2; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec02/person.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec02; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec02"; 7 | 8 | message Person { 9 | string name = 1; 10 | int32 age = 2; 11 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec03/collection.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec03; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec03"; 7 | 8 | message Book { 9 | string title = 1; 10 | string author = 2; 11 | int32 publication_year = 3; 12 | } 13 | 14 | message Library { 15 | string name = 1; 16 | repeated Book books = 2; 17 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec03/composition.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec03; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec03"; 7 | 8 | message Address { 9 | string street = 1; 10 | string city = 2; 11 | string state = 3; 12 | } 13 | 14 | message Student { 15 | string name = 1; 16 | Address address = 2; 17 | } 18 | 19 | message School { 20 | int32 id = 1; 21 | string name = 2; 22 | Address address = 3; 23 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec03/map.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec03; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec03"; 7 | 8 | enum BodyStyle { 9 | UNKNOWN = 0; 10 | SEDAN = 1; 11 | COUPE = 2; 12 | SUV = 3; 13 | } 14 | 15 | message Car { 16 | string make = 1; 17 | string model = 2; 18 | int32 year = 3; 19 | BodyStyle body_style = 4; 20 | } 21 | 22 | message Dealer { 23 | map inventory = 1; 24 | } 25 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec03/one-of.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec03; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec03"; 7 | 8 | message Email { 9 | string address = 1; 10 | string password = 2; 11 | } 12 | 13 | message Phone { 14 | int32 number = 1; 15 | int32 code = 2; 16 | } 17 | 18 | message Credentials{ 19 | oneof login_type { 20 | Email email = 1; 21 | Phone phone = 2; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec03/person.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec03; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec03"; 7 | 8 | message Person { 9 | 10 | string last_name = 1; 11 | int32 age = 2; 12 | string email = 3; 13 | bool employed = 4; 14 | double salary = 5; 15 | int64 bank_account_number = 6; 16 | sint32 balance = 7; 17 | 18 | } 19 | 20 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec04/common/address.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec04.common; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.common"; 7 | 8 | message Address { 9 | string street = 1; 10 | string city = 2; 11 | string state = 3; 12 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec04/common/car.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec04.common; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.common"; 7 | 8 | enum BodyStyle { 9 | UNKNOWN = 0; 10 | SEDAN = 1; 11 | COUPE = 2; 12 | SUV = 3; 13 | } 14 | 15 | message Car { 16 | string make = 1; 17 | string model = 2; 18 | int32 year = 3; 19 | BodyStyle body_style = 4; 20 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec04/person.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec04; 4 | 5 | import "sec04/common/address.proto"; 6 | import "sec04/common/car.proto"; 7 | 8 | option java_multiple_files = true; 9 | option java_package = "com.vinsguru.models.sec04"; 10 | 11 | message Person { 12 | 13 | string name = 1; 14 | optional int32 age = 2; 15 | sec04.common.Address address = 3; 16 | sec04.common.Car car = 4; 17 | 18 | } 19 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec04/well-known.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec04; 4 | 5 | import "google/protobuf/wrappers.proto"; 6 | import "google/protobuf/timestamp.proto"; 7 | 8 | option java_multiple_files = true; 9 | option java_package = "com.vinsguru.models.sec04"; 10 | 11 | 12 | message Sample { 13 | google.protobuf.Int32Value age = 1; 14 | google.protobuf.Timestamp login_time = 2; 15 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec05/v1/television.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec05.v1; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec05.v1"; 7 | 8 | message Television { 9 | string brand = 1; 10 | int32 year = 2; 11 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec05/v2/television.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec05.v2; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec05.v2"; 7 | 8 | message Television { 9 | string brand = 1; 10 | // changed year to model 11 | int32 model = 2; 12 | Type type = 3; 13 | } 14 | 15 | enum Type { 16 | HD = 0; 17 | UHD = 1; 18 | OLED = 2; 19 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec05/v3/television.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec05.v3; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec05.v3"; 7 | 8 | /* 9 | Requirement: 10 | - We NO longer need model/year! remove that! 11 | */ 12 | message Television { 13 | string brand = 1; 14 | 15 | reserved 2; 16 | reserved "year", "model"; 17 | 18 | Type type = 3; 19 | } 20 | 21 | enum Type { 22 | HD = 0; 23 | UHD = 1; 24 | OLED = 2; 25 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec05/v4/television.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec05.v4; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec05.v4"; 7 | 8 | /* 9 | Requirement: 10 | - Add price info 11 | */ 12 | message Television { 13 | string brand = 1; 14 | 15 | reserved 2; 16 | reserved "year", "model"; 17 | 18 | Type type = 3; 19 | int32 price = 4; 20 | 21 | } 22 | 23 | enum Type { 24 | HD = 0; 25 | UHD = 1; 26 | OLED = 2; 27 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec06/bank-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec06; 4 | 5 | import "google/protobuf/empty.proto"; 6 | 7 | option java_multiple_files = true; 8 | option java_package = "com.vinsguru.models.sec06"; 9 | 10 | message BalanceCheckRequest { 11 | int32 account_number = 1; 12 | } 13 | 14 | message AccountBalance { 15 | int32 account_number = 1; 16 | int32 balance = 2; 17 | } 18 | 19 | message AllAccountsResponse { 20 | repeated AccountBalance accounts = 1; 21 | } 22 | 23 | message WithdrawRequest { 24 | int32 account_number = 1; 25 | int32 amount = 2; 26 | } 27 | 28 | message Money { 29 | int32 amount = 1; 30 | } 31 | 32 | message DepositRequest { 33 | oneof request { 34 | int32 account_number = 1; 35 | Money money = 2; 36 | } 37 | } 38 | 39 | message TransferRequest { 40 | int32 from_account = 1; 41 | int32 to_account = 2; 42 | int32 amount = 3; 43 | } 44 | 45 | enum TransferStatus { 46 | REJECTED = 0; 47 | COMPLETED = 1; 48 | } 49 | 50 | message TransferResponse { 51 | TransferStatus status = 1; 52 | AccountBalance from_account = 2; 53 | AccountBalance to_account = 3; 54 | } 55 | 56 | service BankService { 57 | // unary 58 | rpc GetAccountBalance(BalanceCheckRequest) returns (AccountBalance); 59 | rpc GetAllAccounts(google.protobuf.Empty) returns (AllAccountsResponse); 60 | 61 | // server streaming 62 | rpc Withdraw(WithdrawRequest) returns (stream Money); 63 | 64 | // client streaming 65 | rpc Deposit(stream DepositRequest) returns (AccountBalance); 66 | 67 | } 68 | 69 | service TransferService { 70 | // bidirectional streaming 71 | rpc Transfer(stream TransferRequest) returns (stream TransferResponse); 72 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec07/flow-control.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec07; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec07"; 7 | 8 | /* 9 | Server emits 1-100 very fast. 10 | We want to control the rate in which server emits based on the client's processing speed (vice versa). 11 | This process is called back-pressure handling / flow control 12 | */ 13 | 14 | message Output { 15 | int32 value = 1; 16 | } 17 | 18 | message RequestSize { 19 | int32 size = 1; 20 | } 21 | 22 | service FlowControlService { 23 | rpc GetMessages(stream RequestSize) returns (stream Output); 24 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec08/game.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec08; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec08"; 7 | 8 | message GuessRequest { 9 | int32 guess = 1; 10 | } 11 | 12 | enum Result { 13 | CORRECT = 0; 14 | TOO_LOW = 1; 15 | TOO_HIGH = 2; 16 | } 17 | 18 | message GuessResponse { 19 | int32 attempt = 1; 20 | Result result = 2; 21 | } 22 | 23 | service GuessNumber { 24 | rpc MakeGuess(stream GuessRequest) returns (stream GuessResponse); 25 | } 26 | -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec09/input-validation.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec09; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec09"; 7 | 8 | message BalanceCheckRequest { 9 | int32 account_number = 1; 10 | } 11 | 12 | message AccountBalance { 13 | int32 account_number = 1; 14 | int32 balance = 2; 15 | } 16 | 17 | message WithdrawRequest { 18 | int32 account_number = 1; 19 | int32 amount = 2; 20 | } 21 | 22 | message Money { 23 | int32 amount = 1; 24 | } 25 | 26 | service BankService { 27 | /* 28 | Unary 29 | - account number should be between 1 and 10 30 | */ 31 | rpc GetAccountBalance(BalanceCheckRequest) returns (AccountBalance); 32 | 33 | /* 34 | Server streaming 35 | - account number should be between 1 and 10 36 | - amount should be 10 multiples 37 | - account should have enough balance 38 | */ 39 | rpc Withdraw(WithdrawRequest) returns (stream Money); 40 | 41 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec10/input-validation.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec10; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec10"; 7 | 8 | message BalanceCheckRequest { 9 | int32 account_number = 1; 10 | } 11 | 12 | message AccountBalance { 13 | int32 account_number = 1; 14 | int32 balance = 2; 15 | } 16 | 17 | message WithdrawRequest { 18 | int32 account_number = 1; 19 | int32 amount = 2; 20 | } 21 | 22 | message Money { 23 | int32 amount = 1; 24 | } 25 | 26 | enum ValidationCode { 27 | INVALID_ACCOUNT = 0; 28 | INVALID_AMOUNT = 1; 29 | INSUFFICIENT_BALANCE = 2; 30 | } 31 | 32 | message ErrorMessage { 33 | ValidationCode validation_code = 1; 34 | } 35 | 36 | service BankService { 37 | /* 38 | Unary 39 | - account number should be between 1 and 10 40 | */ 41 | rpc GetAccountBalance(BalanceCheckRequest) returns (AccountBalance); 42 | 43 | /* 44 | Server streaming 45 | - account number should be between 1 and 10 46 | - amount should be 10 multiples 47 | - account should have enough balance 48 | */ 49 | rpc Withdraw(WithdrawRequest) returns (stream Money); 50 | 51 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec11/bank-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec11; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec11"; 7 | 8 | message BalanceCheckRequest { 9 | int32 account_number = 1; 10 | } 11 | 12 | message AccountBalance { 13 | int32 account_number = 1; 14 | int32 balance = 2; 15 | } 16 | 17 | message WithdrawRequest { 18 | int32 account_number = 1; 19 | int32 amount = 2; 20 | } 21 | 22 | message Money { 23 | int32 amount = 1; 24 | } 25 | 26 | service BankService { 27 | 28 | // unary 29 | rpc GetAccountBalance(BalanceCheckRequest) returns (AccountBalance); 30 | 31 | // server streaming 32 | rpc Withdraw(WithdrawRequest) returns (stream Money); 33 | 34 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec12/bank-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec12; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec12"; 7 | 8 | message BalanceCheckRequest { 9 | int32 account_number = 1; 10 | } 11 | 12 | message AccountBalance { 13 | int32 account_number = 1; 14 | int32 balance = 2; 15 | } 16 | 17 | message WithdrawRequest { 18 | int32 account_number = 1; 19 | int32 amount = 2; 20 | } 21 | 22 | message Money { 23 | int32 amount = 1; 24 | } 25 | 26 | service BankService { 27 | 28 | // unary 29 | rpc GetAccountBalance(BalanceCheckRequest) returns (AccountBalance); 30 | 31 | // server streaming 32 | rpc Withdraw(WithdrawRequest) returns (stream Money); 33 | 34 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/proto/sec13/bank-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package sec13; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models.sec13"; 7 | 8 | message BalanceCheckRequest { 9 | int32 account_number = 1; 10 | } 11 | 12 | message AccountBalance { 13 | int32 account_number = 1; 14 | int32 balance = 2; 15 | } 16 | 17 | message WithdrawRequest { 18 | int32 account_number = 1; 19 | int32 amount = 2; 20 | } 21 | 22 | message Money { 23 | int32 amount = 1; 24 | } 25 | 26 | service BankService { 27 | 28 | // unary 29 | rpc GetAccountBalance(BalanceCheckRequest) returns (AccountBalance); 30 | 31 | // server streaming 32 | rpc Withdraw(WithdrawRequest) returns (stream Money); 33 | 34 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{HH:mm:ss.SSS} %-5level [%15.15t] %cyan(%-30.30logger{30}) : %m%n 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/common/AbstractChannelTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.common; 2 | 3 | import io.grpc.ManagedChannel; 4 | import io.grpc.ManagedChannelBuilder; 5 | import org.junit.jupiter.api.AfterAll; 6 | import org.junit.jupiter.api.BeforeAll; 7 | import org.junit.jupiter.api.TestInstance; 8 | 9 | import java.util.concurrent.TimeUnit; 10 | 11 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 12 | public abstract class AbstractChannelTest { 13 | 14 | protected ManagedChannel channel; 15 | 16 | @BeforeAll 17 | public void setupChannel() { 18 | this.channel = ManagedChannelBuilder.forAddress("localhost", 6565) 19 | .usePlaintext() 20 | .build(); 21 | } 22 | 23 | @AfterAll 24 | public void stopChannel() throws InterruptedException { 25 | this.channel.shutdownNow() 26 | .awaitTermination(5, TimeUnit.SECONDS); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/common/ResponseObserver.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.common; 2 | 3 | import io.grpc.stub.StreamObserver; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.util.ArrayList; 8 | import java.util.Collections; 9 | import java.util.List; 10 | import java.util.concurrent.CountDownLatch; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | /* 14 | Test utility 15 | */ 16 | public class ResponseObserver implements StreamObserver { 17 | 18 | private static final Logger log = LoggerFactory.getLogger(ResponseObserver.class); 19 | private final List list = Collections.synchronizedList(new ArrayList<>()); 20 | private final CountDownLatch latch; 21 | private Throwable throwable; 22 | 23 | private ResponseObserver(int countDown){ 24 | this.latch = new CountDownLatch(countDown); 25 | } 26 | 27 | public static ResponseObserver create(){ 28 | return new ResponseObserver<>(1); 29 | } 30 | 31 | public static ResponseObserver create(int countDown){ 32 | return new ResponseObserver<>(countDown); 33 | } 34 | 35 | @Override 36 | public void onNext(T t) { 37 | log.info("received item: {}", t); 38 | this.list.add(t); 39 | } 40 | 41 | @Override 42 | public void onError(Throwable throwable) { 43 | log.info("received error: {}", throwable.getMessage()); 44 | this.throwable = throwable; 45 | this.latch.countDown(); 46 | } 47 | 48 | @Override 49 | public void onCompleted() { 50 | log.info("completed"); 51 | this.latch.countDown(); 52 | } 53 | 54 | public void await(){ 55 | try{ 56 | this.latch.await(5, TimeUnit.SECONDS); 57 | }catch (Exception e){ 58 | throw new RuntimeException(e); 59 | } 60 | } 61 | 62 | public List getItems(){ 63 | return this.list; 64 | } 65 | 66 | public Throwable getThrowable() { 67 | return throwable; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec06/AbstractTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec06; 2 | 3 | import com.vinsguru.common.GrpcServer; 4 | import com.vinsguru.models.sec06.BankServiceGrpc; 5 | import com.vinsguru.models.sec06.TransferServiceGrpc; 6 | import com.vinsguru.sec06.BankService; 7 | import com.vinsguru.sec06.TransferService; 8 | import com.vinsguru.test.common.AbstractChannelTest; 9 | import org.junit.jupiter.api.AfterAll; 10 | import org.junit.jupiter.api.BeforeAll; 11 | 12 | public abstract class AbstractTest extends AbstractChannelTest { 13 | 14 | private final GrpcServer grpcServer = GrpcServer.create(new BankService(), new TransferService()); 15 | protected BankServiceGrpc.BankServiceStub bankStub; 16 | protected BankServiceGrpc.BankServiceBlockingStub bankBlockingStub; 17 | protected TransferServiceGrpc.TransferServiceStub transferStub; 18 | 19 | @BeforeAll 20 | public void setup(){ 21 | this.grpcServer.start(); 22 | this.bankStub = BankServiceGrpc.newStub(channel); 23 | this.bankBlockingStub = BankServiceGrpc.newBlockingStub(channel); 24 | this.transferStub = TransferServiceGrpc.newStub(channel); 25 | } 26 | 27 | @AfterAll 28 | public void stop(){ 29 | this.grpcServer.stop(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec06/Lec01UnaryBlockingClientTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec06; 2 | 3 | import com.google.protobuf.Empty; 4 | import com.vinsguru.models.sec06.BalanceCheckRequest; 5 | import org.junit.jupiter.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | public class Lec01UnaryBlockingClientTest extends AbstractTest { 11 | 12 | private static final Logger log = LoggerFactory.getLogger(Lec01UnaryBlockingClientTest.class); 13 | 14 | @Test 15 | public void getBalanceTest(){ 16 | var request = BalanceCheckRequest.newBuilder() 17 | .setAccountNumber(1) 18 | .build(); 19 | var balance = this.bankBlockingStub.getAccountBalance(request); 20 | log.info("unary balance received: {}", balance); 21 | Assertions.assertEquals(100, balance.getBalance()); 22 | } 23 | 24 | @Test 25 | public void allAccountsTest(){ 26 | var allAccounts = this.bankBlockingStub.getAllAccounts(Empty.getDefaultInstance()); 27 | log.info("all accounts size: {}", allAccounts.getAccountsCount()); 28 | Assertions.assertEquals(10, allAccounts.getAccountsCount()); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec06/Lec02UnaryAsyncClientTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec06; 2 | 3 | import com.google.protobuf.Empty; 4 | import com.vinsguru.models.sec06.AccountBalance; 5 | import com.vinsguru.models.sec06.AllAccountsResponse; 6 | import com.vinsguru.models.sec06.BalanceCheckRequest; 7 | import com.vinsguru.test.common.ResponseObserver; 8 | import org.junit.jupiter.api.Assertions; 9 | import org.junit.jupiter.api.Test; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | public class Lec02UnaryAsyncClientTest extends AbstractTest { 14 | 15 | private static final Logger log = LoggerFactory.getLogger(Lec02UnaryAsyncClientTest.class); 16 | 17 | @Test 18 | public void getBalanceTest() { 19 | var request = BalanceCheckRequest.newBuilder().setAccountNumber(1).build(); 20 | var observer = ResponseObserver.create(); 21 | this.bankStub.getAccountBalance(request, observer); 22 | observer.await(); 23 | Assertions.assertEquals(1, observer.getItems().size()); 24 | Assertions.assertEquals(100, observer.getItems().getFirst().getBalance()); 25 | Assertions.assertNull(observer.getThrowable()); 26 | } 27 | 28 | @Test 29 | public void allAccountsTest(){ 30 | var observer = ResponseObserver.create(); 31 | this.bankStub.getAllAccounts(Empty.getDefaultInstance(), observer); 32 | observer.await(); 33 | Assertions.assertEquals(1, observer.getItems().size()); 34 | Assertions.assertEquals(10, observer.getItems().getFirst().getAccountsCount()); 35 | Assertions.assertNull(observer.getThrowable()); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec06/Lec03ServerStreamingClientTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec06; 2 | 3 | import com.vinsguru.models.sec06.Money; 4 | import com.vinsguru.models.sec06.WithdrawRequest; 5 | import com.vinsguru.test.common.ResponseObserver; 6 | import org.junit.jupiter.api.Assertions; 7 | import org.junit.jupiter.api.Test; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | public class Lec03ServerStreamingClientTest extends AbstractTest { 12 | 13 | private static final Logger log = LoggerFactory.getLogger(Lec03ServerStreamingClientTest.class); 14 | 15 | @Test 16 | public void blockingClientWithdrawTest() { 17 | var request = WithdrawRequest.newBuilder() 18 | .setAccountNumber(2) 19 | .setAmount(20) 20 | .build(); 21 | var iterator = this.bankBlockingStub.withdraw(request); 22 | int count = 0; 23 | while (iterator.hasNext()){ 24 | log.info("received money: {}", iterator.next()); 25 | count++; 26 | } 27 | Assertions.assertEquals(2, count); 28 | } 29 | 30 | @Test 31 | public void asyncClientWithdrawTest() { 32 | var request = WithdrawRequest.newBuilder() 33 | .setAccountNumber(2) 34 | .setAmount(20) 35 | .build(); 36 | var observer = ResponseObserver.create(); 37 | this.bankStub.withdraw(request, observer); 38 | observer.await(); 39 | Assertions.assertEquals(2, observer.getItems().size()); 40 | Assertions.assertEquals(10, observer.getItems().getFirst().getAmount()); 41 | Assertions.assertNull(observer.getThrowable()); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec06/Lec04ClientStreamingTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec06; 2 | 3 | import com.vinsguru.models.sec06.AccountBalance; 4 | import com.vinsguru.models.sec06.DepositRequest; 5 | import com.vinsguru.models.sec06.Money; 6 | import com.vinsguru.test.common.ResponseObserver; 7 | import org.junit.jupiter.api.Assertions; 8 | import org.junit.jupiter.api.Test; 9 | 10 | import java.util.stream.IntStream; 11 | 12 | public class Lec04ClientStreamingTest extends AbstractTest { 13 | 14 | @Test 15 | public void depositTest() { 16 | var responseObserver = ResponseObserver.create(); 17 | var requestObserver = this.bankStub.deposit(responseObserver); 18 | 19 | // initial message - account number 20 | requestObserver.onNext(DepositRequest.newBuilder().setAccountNumber(5).build()); 21 | 22 | // sending stream of money 23 | IntStream.rangeClosed(1, 10) 24 | .mapToObj(i -> Money.newBuilder().setAmount(10).build()) 25 | .map(m -> DepositRequest.newBuilder().setMoney(m).build()) 26 | .forEach(requestObserver::onNext); 27 | 28 | // notifying the server that we are done 29 | requestObserver.onCompleted(); 30 | 31 | // at this point out response observer should receive a response 32 | responseObserver.await(); 33 | 34 | // assert 35 | Assertions.assertEquals(1, responseObserver.getItems().size()); 36 | Assertions.assertEquals(200, responseObserver.getItems().getFirst().getBalance()); 37 | Assertions.assertNull(responseObserver.getThrowable()); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec07/FlowControlTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec07; 2 | 3 | import com.vinsguru.common.GrpcServer; 4 | import com.vinsguru.models.sec07.FlowControlServiceGrpc; 5 | import com.vinsguru.sec07.FlowControlService; 6 | import com.vinsguru.test.common.AbstractChannelTest; 7 | import org.junit.jupiter.api.AfterAll; 8 | import org.junit.jupiter.api.BeforeAll; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.jupiter.api.TestInstance; 11 | 12 | /* 13 | It is simply a demo class 14 | */ 15 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 16 | public class FlowControlTest extends AbstractChannelTest { 17 | 18 | private final GrpcServer server = GrpcServer.create(new FlowControlService()); 19 | private FlowControlServiceGrpc.FlowControlServiceStub stub; 20 | 21 | @BeforeAll 22 | public void setup(){ 23 | this.server.start(); 24 | this.stub = FlowControlServiceGrpc.newStub(channel); 25 | } 26 | 27 | @Test 28 | public void flowControlDemo(){ 29 | var responseObserver = new ResponseHandler(); 30 | var requestObserver = this.stub.getMessages(responseObserver); 31 | responseObserver.setRequestObserver(requestObserver); 32 | responseObserver.start(); 33 | responseObserver.await(); 34 | } 35 | 36 | @AfterAll 37 | public void stop(){ 38 | this.server.stop(); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec08/GuessANumberTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec08; 2 | 3 | import com.vinsguru.common.GrpcServer; 4 | import com.vinsguru.models.sec08.GuessNumberGrpc; 5 | import com.vinsguru.sec08.GuessNumberService; 6 | import com.vinsguru.test.common.AbstractChannelTest; 7 | import io.grpc.Status; 8 | import org.junit.jupiter.api.*; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.util.List; 13 | import java.util.stream.IntStream; 14 | 15 | /* 16 | It is simply a demo class 17 | */ 18 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 19 | public class GuessANumberTest extends AbstractChannelTest { 20 | 21 | private static final Logger log = LoggerFactory.getLogger(GuessANumberTest.class); 22 | private final GrpcServer server = GrpcServer.create(new GuessNumberService()); 23 | private GuessNumberGrpc.GuessNumberStub stub; 24 | 25 | @BeforeAll 26 | public void setup(){ 27 | this.server.start(); 28 | this.stub = GuessNumberGrpc.newStub(channel); 29 | } 30 | 31 | @RepeatedTest(5) 32 | public void guessANumberGame(){ 33 | var responseObserver = new GuessResponseHandler(); 34 | var requestObserver = this.stub.makeGuess(responseObserver); 35 | responseObserver.setRequestObserver(requestObserver); 36 | responseObserver.start(); 37 | responseObserver.await(); 38 | log.info("--------------"); 39 | } 40 | 41 | @AfterAll 42 | public void stop(){ 43 | this.server.stop(); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec09/AbstractTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec09; 2 | 3 | import com.vinsguru.common.GrpcServer; 4 | import com.vinsguru.models.sec09.BankServiceGrpc; 5 | import com.vinsguru.sec09.BankService; 6 | import com.vinsguru.test.common.AbstractChannelTest; 7 | import org.junit.jupiter.api.AfterAll; 8 | import org.junit.jupiter.api.BeforeAll; 9 | 10 | public abstract class AbstractTest extends AbstractChannelTest { 11 | 12 | private final GrpcServer grpcServer = GrpcServer.create(new BankService()); 13 | protected BankServiceGrpc.BankServiceStub bankStub; 14 | protected BankServiceGrpc.BankServiceBlockingStub bankBlockingStub; 15 | 16 | @BeforeAll 17 | public void setup(){ 18 | this.grpcServer.start(); 19 | this.bankStub = BankServiceGrpc.newStub(channel); 20 | this.bankBlockingStub = BankServiceGrpc.newBlockingStub(channel); 21 | } 22 | 23 | @AfterAll 24 | public void stop(){ 25 | this.grpcServer.stop(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec09/Lec01UnaryInputValidationTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec09; 2 | 3 | import com.vinsguru.models.sec09.AccountBalance; 4 | import com.vinsguru.models.sec09.BalanceCheckRequest; 5 | import com.vinsguru.test.common.ResponseObserver; 6 | import io.grpc.Status; 7 | import io.grpc.StatusRuntimeException; 8 | import org.junit.jupiter.api.Assertions; 9 | import org.junit.jupiter.api.Test; 10 | 11 | public class Lec01UnaryInputValidationTest extends AbstractTest { 12 | 13 | @Test 14 | public void blockingInputValidationTest(){ 15 | var ex = Assertions.assertThrows(StatusRuntimeException.class, () -> { 16 | var request = BalanceCheckRequest.newBuilder() 17 | .setAccountNumber(11) 18 | .build(); 19 | var response = this.bankBlockingStub.getAccountBalance(request); 20 | }); 21 | Assertions.assertEquals(Status.Code.INVALID_ARGUMENT, ex.getStatus().getCode()); 22 | } 23 | 24 | @Test 25 | public void asyncInputValidationTest(){ 26 | var request = BalanceCheckRequest.newBuilder() 27 | .setAccountNumber(11) 28 | .build(); 29 | var observer = ResponseObserver.create(); 30 | this.bankStub.getAccountBalance(request, observer); 31 | observer.await(); 32 | 33 | Assertions.assertTrue(observer.getItems().isEmpty()); 34 | Assertions.assertNotNull(observer.getThrowable()); 35 | Assertions.assertEquals(Status.Code.INVALID_ARGUMENT, ((StatusRuntimeException) observer.getThrowable()).getStatus().getCode()); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec10/AbstractTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec10; 2 | 3 | import com.vinsguru.common.GrpcServer; 4 | import com.vinsguru.models.sec10.BankServiceGrpc; 5 | import com.vinsguru.models.sec10.ErrorMessage; 6 | import com.vinsguru.models.sec10.ValidationCode; 7 | import com.vinsguru.sec10.BankService; 8 | import com.vinsguru.test.common.AbstractChannelTest; 9 | import io.grpc.Metadata; 10 | import io.grpc.Status; 11 | import io.grpc.protobuf.ProtoUtils; 12 | import org.junit.jupiter.api.AfterAll; 13 | import org.junit.jupiter.api.BeforeAll; 14 | 15 | import java.util.Optional; 16 | 17 | public abstract class AbstractTest extends AbstractChannelTest { 18 | 19 | private static final Metadata.Key ERROR_MESSAGE_KEY = ProtoUtils.keyForProto(ErrorMessage.getDefaultInstance()); 20 | private final GrpcServer grpcServer = GrpcServer.create(new BankService()); 21 | protected BankServiceGrpc.BankServiceStub bankStub; 22 | protected BankServiceGrpc.BankServiceBlockingStub bankBlockingStub; 23 | 24 | @BeforeAll 25 | public void setup() { 26 | this.grpcServer.start(); 27 | this.bankStub = BankServiceGrpc.newStub(channel); 28 | this.bankBlockingStub = BankServiceGrpc.newBlockingStub(channel); 29 | } 30 | 31 | @AfterAll 32 | public void stop() { 33 | this.grpcServer.stop(); 34 | } 35 | 36 | protected ValidationCode getValidationCode(Throwable throwable) { 37 | return Optional.ofNullable(Status.trailersFromThrowable(throwable)) 38 | .map(m -> m.get(ERROR_MESSAGE_KEY)) 39 | .map(ErrorMessage::getValidationCode) 40 | .orElseThrow(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec10/Lec01UnaryInputValidationTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec10; 2 | 3 | import com.vinsguru.models.sec10.AccountBalance; 4 | import com.vinsguru.models.sec10.BalanceCheckRequest; 5 | import com.vinsguru.models.sec10.ValidationCode; 6 | import com.vinsguru.test.common.ResponseObserver; 7 | import io.grpc.StatusRuntimeException; 8 | import org.junit.jupiter.api.Assertions; 9 | import org.junit.jupiter.api.Test; 10 | 11 | public class Lec01UnaryInputValidationTest extends AbstractTest { 12 | 13 | @Test 14 | public void blockingInputValidationTest(){ 15 | var ex = Assertions.assertThrows(StatusRuntimeException.class, () -> { 16 | var request = BalanceCheckRequest.newBuilder() 17 | .setAccountNumber(11) 18 | .build(); 19 | var response = this.bankBlockingStub.getAccountBalance(request); 20 | }); 21 | Assertions.assertEquals(ValidationCode.INVALID_ACCOUNT, getValidationCode(ex)); 22 | } 23 | 24 | @Test 25 | public void asyncInputValidationTest(){ 26 | var request = BalanceCheckRequest.newBuilder() 27 | .setAccountNumber(11) 28 | .build(); 29 | var observer = ResponseObserver.create(); 30 | this.bankStub.getAccountBalance(request, observer); 31 | observer.await(); 32 | 33 | Assertions.assertTrue(observer.getItems().isEmpty()); 34 | Assertions.assertNotNull(observer.getThrowable()); 35 | Assertions.assertEquals(ValidationCode.INVALID_ACCOUNT, getValidationCode(observer.getThrowable())); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec11/AbstractTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec11; 2 | 3 | import com.vinsguru.common.GrpcServer; 4 | import com.vinsguru.models.sec11.BankServiceGrpc; 5 | import com.vinsguru.sec11.DeadlineBankService; 6 | import com.vinsguru.test.common.AbstractChannelTest; 7 | import org.junit.jupiter.api.AfterAll; 8 | import org.junit.jupiter.api.BeforeAll; 9 | 10 | public abstract class AbstractTest extends AbstractChannelTest { 11 | 12 | private final GrpcServer grpcServer = GrpcServer.create(new DeadlineBankService()); 13 | protected BankServiceGrpc.BankServiceStub bankStub; 14 | protected BankServiceGrpc.BankServiceBlockingStub bankBlockingStub; 15 | 16 | @BeforeAll 17 | public void setup() { 18 | this.grpcServer.start(); 19 | this.bankStub = BankServiceGrpc.newStub(channel); 20 | this.bankBlockingStub = BankServiceGrpc.newBlockingStub(channel); 21 | } 22 | 23 | @AfterAll 24 | public void stop() { 25 | this.grpcServer.stop(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec11/Lec01UnaryDeadlineTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec11; 2 | 3 | import com.vinsguru.models.sec11.AccountBalance; 4 | import com.vinsguru.models.sec11.BalanceCheckRequest; 5 | import com.vinsguru.test.common.ResponseObserver; 6 | import io.grpc.Deadline; 7 | import io.grpc.Status; 8 | import io.grpc.StatusRuntimeException; 9 | import org.junit.jupiter.api.Assertions; 10 | import org.junit.jupiter.api.Test; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.util.concurrent.TimeUnit; 15 | 16 | public class Lec01UnaryDeadlineTest extends AbstractTest { 17 | 18 | private static final Logger log = LoggerFactory.getLogger(Lec01UnaryDeadlineTest.class); 19 | 20 | @Test 21 | public void blockingDeadlineTest(){ 22 | var ex = Assertions.assertThrows(StatusRuntimeException.class, () -> { 23 | var request = BalanceCheckRequest.newBuilder() 24 | .setAccountNumber(1) 25 | .build(); 26 | var response = this.bankBlockingStub 27 | .withDeadline(Deadline.after(2, TimeUnit.SECONDS)) 28 | .getAccountBalance(request); 29 | }); 30 | Assertions.assertEquals(Status.Code.DEADLINE_EXCEEDED, ex.getStatus().getCode()); 31 | } 32 | 33 | @Test 34 | public void asyncDeadlineTest(){ 35 | var observer = ResponseObserver.create(); 36 | var request = BalanceCheckRequest.newBuilder() 37 | .setAccountNumber(1) 38 | .build(); 39 | this.bankStub 40 | .withDeadline(Deadline.after(2, TimeUnit.SECONDS)) 41 | .getAccountBalance(request, observer); 42 | observer.await(); 43 | Assertions.assertTrue(observer.getItems().isEmpty()); 44 | Assertions.assertEquals(Status.Code.DEADLINE_EXCEEDED, Status.fromThrowable(observer.getThrowable()).getCode()); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec11/Lec04LazyChannelDemoTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec11; 2 | 3 | import com.vinsguru.common.GrpcServer; 4 | import com.vinsguru.models.sec11.BalanceCheckRequest; 5 | import com.vinsguru.models.sec11.BankServiceGrpc; 6 | import com.vinsguru.sec11.DeadlineBankService; 7 | import com.vinsguru.test.common.AbstractChannelTest; 8 | import io.grpc.Status; 9 | import io.grpc.StatusRuntimeException; 10 | import org.junit.jupiter.api.AfterAll; 11 | import org.junit.jupiter.api.Assertions; 12 | import org.junit.jupiter.api.BeforeAll; 13 | import org.junit.jupiter.api.Test; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | 17 | /* 18 | It is a class to demo the lazy channel creation behavior 19 | */ 20 | public class Lec04LazyChannelDemoTest extends AbstractChannelTest { 21 | 22 | private static final Logger log = LoggerFactory.getLogger(Lec04LazyChannelDemoTest.class); 23 | private final GrpcServer grpcServer = GrpcServer.create(new DeadlineBankService()); 24 | private BankServiceGrpc.BankServiceBlockingStub bankBlockingStub; 25 | 26 | @BeforeAll 27 | public void setup() { 28 | // this.grpcServer.start(); 29 | this.bankBlockingStub = BankServiceGrpc.newBlockingStub(channel); 30 | } 31 | 32 | @Test 33 | public void lazyChannelDemo() { 34 | var ex = Assertions.assertThrows(StatusRuntimeException.class, () -> { 35 | var request = BalanceCheckRequest.newBuilder() 36 | .setAccountNumber(1) 37 | .build(); 38 | var response = this.bankBlockingStub.getAccountBalance(request); 39 | log.info("{}", response); 40 | }); 41 | Assertions.assertEquals(Status.Code.UNAVAILABLE, ex.getStatus().getCode()); 42 | } 43 | 44 | @AfterAll 45 | public void stop() { 46 | this.grpcServer.stop(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec11/Lec05EagerChannelDemoTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec11; 2 | 3 | import com.vinsguru.test.common.AbstractChannelTest; 4 | import org.junit.jupiter.api.Test; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | /* 9 | It is a class to demo the eager channel creation behavior. 10 | There is a bug: https://github.com/grpc/grpc-java/issues/10517 11 | */ 12 | public class Lec05EagerChannelDemoTest extends AbstractChannelTest { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(Lec05EagerChannelDemoTest.class); 15 | 16 | @Test 17 | public void eagerChannelDemo() { 18 | log.info("{}", channel.getState(true)); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec11/Lec06KeepAliveDemoTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec11; 2 | 3 | import com.google.common.util.concurrent.Uninterruptibles; 4 | import com.vinsguru.common.GrpcServer; 5 | import com.vinsguru.models.sec11.BalanceCheckRequest; 6 | import com.vinsguru.models.sec11.BankServiceGrpc; 7 | import com.vinsguru.sec11.DeadlineBankService; 8 | import com.vinsguru.test.common.AbstractChannelTest; 9 | import io.grpc.Status; 10 | import io.grpc.StatusRuntimeException; 11 | import org.junit.jupiter.api.AfterAll; 12 | import org.junit.jupiter.api.Assertions; 13 | import org.junit.jupiter.api.BeforeAll; 14 | import org.junit.jupiter.api.Test; 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | import java.util.concurrent.TimeUnit; 19 | 20 | /* 21 | It is a class to demo the keep alive PING & GO AWAY 22 | */ 23 | public class Lec06KeepAliveDemoTest extends AbstractChannelTest { 24 | 25 | private static final Logger log = LoggerFactory.getLogger(Lec06KeepAliveDemoTest.class); 26 | private final GrpcServer grpcServer = GrpcServer.create(new DeadlineBankService()); 27 | private BankServiceGrpc.BankServiceBlockingStub bankBlockingStub; 28 | 29 | @BeforeAll 30 | public void setup() { 31 | this.grpcServer.start(); 32 | this.bankBlockingStub = BankServiceGrpc.newBlockingStub(channel); 33 | } 34 | 35 | /* 36 | Configure the server with keep alive 37 | */ 38 | // @Test 39 | public void keepAliveDemo() { 40 | var request = BalanceCheckRequest.newBuilder() 41 | .setAccountNumber(1) 42 | .build(); 43 | var response = this.bankBlockingStub.getAccountBalance(request); 44 | log.info("{}", response); 45 | 46 | // just blocking the thread for 30 seconds 47 | Uninterruptibles.sleepUninterruptibly(30, TimeUnit.SECONDS); 48 | } 49 | 50 | @AfterAll 51 | public void stop() { 52 | this.grpcServer.stop(); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec12/AbstractInterceptorTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec12; 2 | 3 | import com.vinsguru.common.GrpcServer; 4 | import com.vinsguru.models.sec12.BankServiceGrpc; 5 | import com.vinsguru.sec12.BankService; 6 | import com.vinsguru.sec12.interceptors.GzipResponseInterceptor; 7 | import io.grpc.ClientInterceptor; 8 | import io.grpc.ManagedChannel; 9 | import io.grpc.ManagedChannelBuilder; 10 | import org.junit.jupiter.api.AfterAll; 11 | import org.junit.jupiter.api.BeforeAll; 12 | import org.junit.jupiter.api.TestInstance; 13 | 14 | import java.util.List; 15 | 16 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 17 | public abstract class AbstractInterceptorTest { 18 | 19 | private GrpcServer grpcServer; 20 | protected ManagedChannel channel; 21 | protected BankServiceGrpc.BankServiceStub bankStub; 22 | protected BankServiceGrpc.BankServiceBlockingStub bankBlockingStub; 23 | 24 | protected abstract List getClientInterceptors(); 25 | 26 | protected GrpcServer createServer() { 27 | return GrpcServer.create(6565, builder -> { 28 | builder.addService(new BankService()) 29 | .intercept(new GzipResponseInterceptor()); 30 | }); 31 | } 32 | 33 | @BeforeAll 34 | public void setup() { 35 | this.grpcServer = createServer(); 36 | this.grpcServer.start(); 37 | this.channel = ManagedChannelBuilder.forAddress("localhost", 6565) 38 | .usePlaintext() 39 | .intercept(getClientInterceptors()) 40 | .build(); 41 | this.bankStub = BankServiceGrpc.newStub(channel); 42 | this.bankBlockingStub = BankServiceGrpc.newBlockingStub(channel); 43 | } 44 | 45 | @AfterAll 46 | public void stop() { 47 | this.grpcServer.stop(); 48 | this.channel.shutdownNow(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec12/AbstractTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec12; 2 | 3 | import com.vinsguru.common.GrpcServer; 4 | import com.vinsguru.models.sec12.BankServiceGrpc; 5 | import com.vinsguru.sec12.BankService; 6 | import com.vinsguru.test.common.AbstractChannelTest; 7 | import org.junit.jupiter.api.AfterAll; 8 | import org.junit.jupiter.api.BeforeAll; 9 | 10 | public abstract class AbstractTest extends AbstractChannelTest { 11 | 12 | private final GrpcServer grpcServer = GrpcServer.create(new BankService()); 13 | protected BankServiceGrpc.BankServiceStub bankStub; 14 | protected BankServiceGrpc.BankServiceBlockingStub bankBlockingStub; 15 | 16 | @BeforeAll 17 | public void setup() { 18 | this.grpcServer.start(); 19 | this.bankStub = BankServiceGrpc.newStub(channel); 20 | this.bankBlockingStub = BankServiceGrpc.newBlockingStub(channel); 21 | } 22 | 23 | @AfterAll 24 | public void stop() { 25 | this.grpcServer.stop(); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec12/Lec01GzipCallOptionsTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec12; 2 | 3 | import com.vinsguru.models.sec12.BalanceCheckRequest; 4 | import org.junit.jupiter.api.Test; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | /* 9 | It is a class to demo enabling gzip compression 10 | Update logback xml with DEBUG mode 11 | */ 12 | public class Lec01GzipCallOptionsTest extends AbstractTest { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(Lec01GzipCallOptionsTest.class); 15 | 16 | @Test 17 | public void gzipDemo() { 18 | var request = BalanceCheckRequest.newBuilder() 19 | .setAccountNumber(1) 20 | .build(); 21 | var response = this.bankBlockingStub.withCompression("gzip") 22 | .getAccountBalance(request); 23 | log.info("{}", response); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec12/Lec02ExecutorCallOptionsTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec12; 2 | 3 | import com.vinsguru.models.sec12.Money; 4 | import com.vinsguru.models.sec12.WithdrawRequest; 5 | import com.vinsguru.test.common.ResponseObserver; 6 | import org.junit.jupiter.api.Test; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | 10 | import java.util.concurrent.Executors; 11 | 12 | /* 13 | It is a class to demo changing executor 14 | */ 15 | public class Lec02ExecutorCallOptionsTest extends AbstractTest { 16 | 17 | private static final Logger log = LoggerFactory.getLogger(Lec02ExecutorCallOptionsTest.class); 18 | 19 | @Test 20 | public void executorDemo() { 21 | var observer = ResponseObserver.create(); 22 | var request = WithdrawRequest.newBuilder() 23 | .setAccountNumber(1) 24 | .setAmount(30) 25 | .build(); 26 | this.bankStub 27 | .withExecutor(Executors.newVirtualThreadPerTaskExecutor()) 28 | .withdraw(request, observer); 29 | observer.await(); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec12/Lec03DeadlineInterceptorTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec12; 2 | 3 | import com.vinsguru.models.sec12.Money; 4 | import com.vinsguru.models.sec12.WithdrawRequest; 5 | import com.vinsguru.models.sec12.BalanceCheckRequest; 6 | import com.vinsguru.test.common.ResponseObserver; 7 | import com.vinsguru.test.sec12.interceptors.DeadlineInterceptor; 8 | import io.grpc.ClientInterceptor; 9 | import io.grpc.Deadline; 10 | import org.junit.jupiter.api.Test; 11 | 12 | import java.time.Duration; 13 | import java.util.List; 14 | import java.util.concurrent.TimeUnit; 15 | 16 | /* 17 | It is a class to demo interceptor 18 | */ 19 | public class Lec03DeadlineInterceptorTest extends AbstractInterceptorTest { 20 | 21 | @Override 22 | protected List getClientInterceptors() { 23 | return List.of(new DeadlineInterceptor(Duration.ofSeconds(2))); 24 | } 25 | 26 | @Test 27 | public void defaultDeadlineDemo(){ 28 | var request = BalanceCheckRequest.newBuilder() 29 | .setAccountNumber(1) 30 | .build(); 31 | var response = this.bankBlockingStub.getAccountBalance(request); 32 | } 33 | 34 | @Test 35 | public void overrideInterceptorDemo(){ 36 | var observer = ResponseObserver.create(); 37 | var request = WithdrawRequest.newBuilder() 38 | .setAccountNumber(1) 39 | .setAmount(50) 40 | .build(); 41 | this.bankStub 42 | .withDeadline(Deadline.after(6, TimeUnit.SECONDS)) 43 | .withdraw(request, observer); 44 | observer.await(); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec12/Lec04GzipInterceptorTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec12; 2 | 3 | import com.vinsguru.models.sec12.BalanceCheckRequest; 4 | import com.vinsguru.test.sec12.interceptors.GzipRequestInterceptor; 5 | import io.grpc.ClientInterceptor; 6 | import org.junit.jupiter.api.Test; 7 | 8 | import java.util.List; 9 | 10 | /* 11 | It is a class to demo enabling gzip compression via interceptor 12 | Update logback xml with DEBUG mode 13 | */ 14 | public class Lec04GzipInterceptorTest extends AbstractInterceptorTest { 15 | 16 | @Override 17 | protected List getClientInterceptors() { 18 | return List.of(new GzipRequestInterceptor()); 19 | } 20 | 21 | @Test 22 | public void gzipDemo() { 23 | var request = BalanceCheckRequest.newBuilder() 24 | .setAccountNumber(1) 25 | .build(); 26 | var response = this.bankBlockingStub.getAccountBalance(request); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec12/Lec05ClientApiKeyInterceptorTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec12; 2 | 3 | import com.vinsguru.common.GrpcServer; 4 | import com.vinsguru.models.sec12.BalanceCheckRequest; 5 | import com.vinsguru.sec12.BankService; 6 | import com.vinsguru.sec12.Constants; 7 | import com.vinsguru.sec12.interceptors.ApiKeyValidationInterceptor; 8 | import com.vinsguru.sec12.interceptors.GzipResponseInterceptor; 9 | import io.grpc.ClientInterceptor; 10 | import io.grpc.Metadata; 11 | import io.grpc.stub.MetadataUtils; 12 | import org.junit.jupiter.api.Test; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import java.util.List; 17 | 18 | /* 19 | It is a class to demo how to attach metadata for every request via interceptor 20 | */ 21 | public class Lec05ClientApiKeyInterceptorTest extends AbstractInterceptorTest { 22 | 23 | private static final Logger log = LoggerFactory.getLogger(Lec05ClientApiKeyInterceptorTest.class); 24 | 25 | @Override 26 | protected List getClientInterceptors() { 27 | return List.of( 28 | MetadataUtils.newAttachHeadersInterceptor(getApiKey()) 29 | ); 30 | } 31 | 32 | @Override 33 | protected GrpcServer createServer() { 34 | return GrpcServer.create(6565, builder -> { 35 | builder.addService(new BankService()) 36 | .intercept(new ApiKeyValidationInterceptor()); 37 | }); 38 | } 39 | 40 | @Test 41 | public void clientApiKeyDemo(){ 42 | var request = BalanceCheckRequest.newBuilder() 43 | .setAccountNumber(1) 44 | .build(); 45 | var response = this.bankBlockingStub.getAccountBalance(request); 46 | log.info("{}", response); 47 | } 48 | 49 | private Metadata getApiKey(){ 50 | var metadata = new Metadata(); 51 | metadata.put(Constants.API_KEY, "bank-client-secret"); 52 | return metadata; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec12/interceptors/DeadlineInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec12.interceptors; 2 | 3 | import io.grpc.*; 4 | 5 | import java.time.Duration; 6 | import java.util.Objects; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | public class DeadlineInterceptor implements ClientInterceptor { 10 | 11 | private final Duration duration; 12 | 13 | public DeadlineInterceptor(Duration duration) { 14 | this.duration = duration; 15 | } 16 | 17 | @Override 18 | public ClientCall interceptCall(MethodDescriptor methodDescriptor, 19 | CallOptions callOptions, 20 | Channel channel) { 21 | callOptions = Objects.nonNull(callOptions.getDeadline()) ? 22 | callOptions : 23 | callOptions.withDeadline(Deadline.after(duration.toMillis(), TimeUnit.MILLISECONDS)); 24 | return channel.newCall(methodDescriptor, callOptions); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec12/interceptors/GzipRequestInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec12.interceptors; 2 | 3 | import io.grpc.*; 4 | 5 | public class GzipRequestInterceptor implements ClientInterceptor { 6 | 7 | @Override 8 | public ClientCall interceptCall(MethodDescriptor methodDescriptor, 9 | CallOptions callOptions, 10 | Channel channel) { 11 | return channel.newCall(methodDescriptor, callOptions.withCompression("gzip")); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/java/com/vinsguru/test/sec13/GrpcSSLTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.test.sec13; 2 | 3 | import com.vinsguru.models.sec13.BalanceCheckRequest; 4 | import com.vinsguru.models.sec13.BankServiceGrpc; 5 | import com.vinsguru.models.sec13.Money; 6 | import com.vinsguru.models.sec13.WithdrawRequest; 7 | import com.vinsguru.test.common.ResponseObserver; 8 | import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; 9 | import org.junit.jupiter.api.Test; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | public class GrpcSSLTest extends AbstractTest { 14 | 15 | private static final Logger log = LoggerFactory.getLogger(GrpcSSLTest.class); 16 | 17 | @Test 18 | public void clientWithSSLTest() { 19 | var channel = NettyChannelBuilder.forAddress("localhost", 6565) 20 | .sslContext(clientSslContext()) 21 | .build(); 22 | var stub = BankServiceGrpc.newBlockingStub(channel); 23 | var request = BalanceCheckRequest.newBuilder() 24 | .setAccountNumber(1) 25 | .build(); 26 | var response = stub.getAccountBalance(request); 27 | log.info("{}", response); 28 | channel.shutdownNow(); 29 | } 30 | 31 | @Test 32 | public void streaming() { 33 | var channel = NettyChannelBuilder.forAddress("localhost", 6565) 34 | .sslContext(clientSslContext()) 35 | .build(); 36 | var stub = BankServiceGrpc.newStub(channel); 37 | var request = WithdrawRequest.newBuilder() 38 | .setAccountNumber(1) 39 | .setAmount(30) 40 | .build(); 41 | var observer = ResponseObserver.create(); 42 | stub.withdraw(request, observer); 43 | observer.await(); 44 | 45 | channel.shutdownNow(); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /01-grpc-playground/src/test/resources/certs/generate-certs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # CA creates private key and root CA certificate 4 | openssl genrsa -out root.key 5 | openssl req -new -x509 -key root.key -out root.crt -subj "/CN=localhost" -nodes 6 | 7 | # keystore 8 | keytool -keystore grpc.keystore.jks -storepass changeit -alias localhost -validity 3650 -genkey -keyalg RSA -dname "CN=localhost" 9 | 10 | # create CSR (certificate signing request) 11 | keytool -keystore grpc.keystore.jks -storepass changeit -alias localhost -certreq -file grpc-signing-request.crt 12 | 13 | # CA signs the certificate 14 | openssl x509 -req -CA root.crt -CAkey root.key -in grpc-signing-request.crt -out grpc-signed.crt -days 3650 -CAcreateserial 15 | 16 | # We can import root CA cert & our signed certificate 17 | # This should be private and owned by the server 18 | keytool -keystore grpc.keystore.jks -storepass changeit -alias CARoot -import -file root.crt -noprompt 19 | keytool -keystore grpc.keystore.jks -storepass changeit -alias localhost -import -file grpc-signed.crt -noprompt 20 | 21 | # This is for clients 22 | keytool -keystore grpc.truststore.jks -storepass changeit -noprompt -alias CARoot -import -file root.crt -------------------------------------------------------------------------------- /01-grpc-playground/src/test/resources/certs/grpc.keystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinsguru/grpc-java-course/05c32a6a89a9fa0de16f838c6abf4f21c4a68655/01-grpc-playground/src/test/resources/certs/grpc.keystore.jks -------------------------------------------------------------------------------- /01-grpc-playground/src/test/resources/certs/grpc.truststore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinsguru/grpc-java-course/05c32a6a89a9fa0de16f838c6abf4f21c4a68655/01-grpc-playground/src/test/resources/certs/grpc.truststore.jks -------------------------------------------------------------------------------- /01-grpc-playground/src/test/resources/nginx-load-balancing/config/nginx.conf: -------------------------------------------------------------------------------- 1 | # https://www.nginx.com/resources/wiki/start/topics/examples/full/ 2 | # list all the upstream service instances 3 | # do not use localhost. It runs inside the docker container. localhost is the container itself. 4 | # we expect the container to route the requests to our machine. So provide your machine IP 5 | upstream bank-service { 6 | server 192.168.1.118:6565; 7 | server 192.168.1.118:7575; 8 | } 9 | 10 | server { 11 | 12 | # nginx listens on port 8585. 13 | listen 8585 http2; 14 | 15 | # any requests we receive, it gets routed to the bank server instances above 16 | location / { 17 | grpc_pass grpc://bank-service; 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /01-grpc-playground/src/test/resources/nginx-load-balancing/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3" 2 | services: 3 | nginx: 4 | image: nginx:1.25-alpine 5 | volumes: 6 | - ./config:/etc/nginx/conf.d 7 | ports: 8 | - "8585:8585" -------------------------------------------------------------------------------- /02-project-template/aggregator-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 4.0.0 7 | 8 | com.vinsguru 9 | grpc-trading-platform 10 | 0.0.1-SNAPSHOT 11 | 12 | 13 | aggregator-service 14 | 15 | 16 | 17 | com.vinsguru 18 | proto 19 | ${project.version} 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-web 24 | 25 | 26 | net.devh 27 | grpc-client-spring-boot-starter 28 | 29 | 30 | 31 | com.google.protobuf 32 | protobuf-java-util 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-test 37 | test 38 | 39 | 40 | net.devh 41 | grpc-server-spring-boot-starter 42 | test 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /02-project-template/aggregator-service/src/main/java/com/vinsguru/aggregator/AggregatorServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class AggregatorServiceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(AggregatorServiceApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /02-project-template/aggregator-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # user-service 2 | # grpc.client.user-service.address=static://localhost:6565 3 | # grpc.client.user-service.negotiationType=PLAINTEXT 4 | 5 | # stock-service 6 | # grpc.client.stock-service.address=static://localhost:7575 7 | # grpc.client.stock-service.negotiationType=PLAINTEXT -------------------------------------------------------------------------------- /02-project-template/aggregator-service/src/test/java/com/vinsguru/aggregator/tests/UserTradeTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator.tests; 2 | 3 | public class UserTradeTest { 4 | 5 | 6 | } 7 | -------------------------------------------------------------------------------- /02-project-template/proto/src/main/proto/common/common.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package common; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.common"; 7 | 8 | enum Ticker { 9 | UNKNOWN = 0; 10 | APPLE = 1; 11 | GOOGLE = 2; 12 | AMAZON = 3; 13 | MICROSOFT = 4; 14 | } 15 | -------------------------------------------------------------------------------- /02-project-template/proto/src/main/proto/stock-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package stock; 4 | 5 | import "google/protobuf/empty.proto"; 6 | import "common/common.proto"; 7 | 8 | option java_multiple_files = true; 9 | option java_package = "com.vinsguru.stock"; 10 | 11 | message PriceUpdate { 12 | common.Ticker ticker = 1; 13 | int32 price = 2; 14 | } 15 | 16 | message StockPriceRequest { 17 | common.Ticker ticker = 1; 18 | } 19 | 20 | message StockPriceResponse { 21 | common.Ticker ticker = 1; 22 | int32 price = 2; 23 | } 24 | 25 | // Service for providing stock prices. 26 | service StockService { 27 | 28 | // Unary API to get the current price for a specific ticker. 29 | rpc GetStockPrice(StockPriceRequest) returns (StockPriceResponse); 30 | 31 | // Server streaming API to subscribe to real-time price updates. 32 | rpc GetPriceUpdates(google.protobuf.Empty) returns (stream PriceUpdate); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /02-project-template/proto/src/main/proto/user-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package user; 4 | 5 | import "common/common.proto"; 6 | 7 | option java_multiple_files = true; 8 | option java_package = "com.vinsguru.user"; 9 | 10 | message UserInformationRequest{ 11 | int32 user_id = 1; 12 | } 13 | 14 | message UserInformation { 15 | int32 user_id = 1; 16 | string name = 2; 17 | int32 balance = 3; 18 | repeated Holding holdings = 4; 19 | } 20 | 21 | message Holding { 22 | common.Ticker ticker = 1; 23 | int32 quantity = 2; 24 | } 25 | 26 | enum TradeAction { 27 | BUY = 0; 28 | SELL = 1; 29 | } 30 | 31 | message StockTradeRequest { 32 | int32 user_id = 1; 33 | common.Ticker ticker = 2; 34 | int32 price = 3; 35 | int32 quantity = 4; 36 | TradeAction action = 5; 37 | } 38 | 39 | message StockTradeResponse { 40 | int32 user_id = 1; 41 | common.Ticker ticker = 2; 42 | int32 price = 3; 43 | int32 quantity = 4; 44 | TradeAction action = 5; 45 | int32 total_price = 6; 46 | int32 balance = 7; 47 | } 48 | 49 | service UserService { 50 | 51 | rpc GetUserInformation(UserInformationRequest) returns (UserInformation); 52 | 53 | rpc TradeStock(StockTradeRequest) returns (StockTradeResponse); 54 | 55 | } -------------------------------------------------------------------------------- /02-project-template/user-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.vinsguru 8 | grpc-trading-platform 9 | 0.0.1-SNAPSHOT 10 | 11 | 12 | user-service 13 | 14 | 15 | 16 | com.vinsguru 17 | proto 18 | ${project.version} 19 | 20 | 21 | net.devh 22 | grpc-server-spring-boot-starter 23 | 24 | 25 | org.springframework.boot 26 | spring-boot-starter-data-jpa 27 | 28 | 29 | com.h2database 30 | h2 31 | runtime 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 38 | 39 | net.devh 40 | grpc-client-spring-boot-starter 41 | test 42 | 43 | 44 | io.grpc 45 | grpc-testing 46 | test 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /02-project-template/user-service/src/main/java/com/vinsguru/user/UserServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class UserServiceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(UserServiceApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /02-project-template/user-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #grpc.server.port=6565 2 | #spring.jpa.defer-datasource-initialization=true -------------------------------------------------------------------------------- /02-project-template/user-service/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS customer; 2 | DROP TABLE IF EXISTS portfolio_item; 3 | 4 | -- intentionally naming this table as customer as "user" has some issues 5 | CREATE TABLE customer ( 6 | id int AUTO_INCREMENT primary key, 7 | name VARCHAR(50), 8 | balance int 9 | ); 10 | 11 | CREATE TABLE portfolio_item ( 12 | id int AUTO_INCREMENT primary key, 13 | customer_id int, 14 | ticker VARCHAR(10), 15 | quantity int, 16 | foreign key (customer_id) references customer(id) 17 | ); 18 | 19 | insert into customer(name, balance) 20 | values 21 | ('Sam', 10000), 22 | ('Mike', 10000), 23 | ('John', 10000); -------------------------------------------------------------------------------- /02-project-template/user-service/src/test/java/com/vinsguru/user/tests/UserServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user.tests; 2 | 3 | public class UserServiceTest { 4 | 5 | 6 | 7 | } 8 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 4.0.0 7 | 8 | com.vinsguru 9 | grpc-trading-platform 10 | 0.0.1-SNAPSHOT 11 | 12 | 13 | aggregator-service 14 | 15 | 16 | 17 | com.vinsguru 18 | proto 19 | ${project.version} 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter-web 24 | 25 | 26 | net.devh 27 | grpc-client-spring-boot-starter 28 | 29 | 30 | 31 | com.google.protobuf 32 | protobuf-java-util 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-test 37 | test 38 | 39 | 40 | net.devh 41 | grpc-server-spring-boot-starter 42 | test 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/src/main/java/com/vinsguru/aggregator/AggregatorServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class AggregatorServiceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(AggregatorServiceApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/src/main/java/com/vinsguru/aggregator/config/ApplicationConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator.config; 2 | 3 | import com.google.protobuf.util.JsonFormat; 4 | import net.devh.boot.grpc.client.channelfactory.GrpcChannelConfigurer; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.http.converter.protobuf.ProtobufJsonFormatHttpMessageConverter; 10 | 11 | import java.util.concurrent.Executors; 12 | 13 | @Configuration 14 | public class ApplicationConfiguration { 15 | 16 | private static final Logger log = LoggerFactory.getLogger(ApplicationConfiguration.class); 17 | 18 | @Bean 19 | public GrpcChannelConfigurer channelConfigurer(){ 20 | return (channelBuilder, name) -> { 21 | log.info("channel builder {}", name); 22 | channelBuilder.executor(Executors.newVirtualThreadPerTaskExecutor()); // just for demo 23 | }; 24 | } 25 | 26 | @Bean 27 | public ProtobufJsonFormatHttpMessageConverter protobufJsonFormatHttpMessageConverter(){ 28 | return new ProtobufJsonFormatHttpMessageConverter( 29 | JsonFormat.parser().ignoringUnknownFields(), 30 | JsonFormat.printer().omittingInsignificantWhitespace().includingDefaultValueFields() 31 | ); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/src/main/java/com/vinsguru/aggregator/controller/StockController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator.controller; 2 | 3 | import com.vinsguru.aggregator.service.PriceUpdateListener; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.http.MediaType; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RestController; 9 | import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; 10 | 11 | @RestController 12 | @RequestMapping("stock") 13 | public class StockController { 14 | 15 | @Autowired 16 | private PriceUpdateListener listener; 17 | 18 | @GetMapping(value = "updates", produces = MediaType.TEXT_EVENT_STREAM_VALUE) 19 | public SseEmitter priceUpdates(){ 20 | return listener.createEmitter(); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/src/main/java/com/vinsguru/aggregator/controller/TradeController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator.controller; 2 | 3 | import com.vinsguru.aggregator.service.TradeService; 4 | import com.vinsguru.user.StockTradeRequest; 5 | import com.vinsguru.user.StockTradeResponse; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.http.MediaType; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | @RestController 14 | @RequestMapping("trade") 15 | public class TradeController { 16 | 17 | @Autowired 18 | private TradeService tradeService; 19 | 20 | @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE) 21 | public StockTradeResponse trade(@RequestBody StockTradeRequest request){ 22 | return this.tradeService.trade(request); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/src/main/java/com/vinsguru/aggregator/controller/UserController.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator.controller; 2 | 3 | import com.vinsguru.aggregator.service.UserService; 4 | import com.vinsguru.user.UserInformation; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.http.MediaType; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PathVariable; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | @RestController 13 | @RequestMapping("user") 14 | public class UserController { 15 | 16 | @Autowired 17 | private UserService userService; 18 | 19 | @GetMapping(value = "{userId}", produces = MediaType.APPLICATION_JSON_VALUE) 20 | public UserInformation getUserInformation(@PathVariable Integer userId){ 21 | return this.userService.getUserInformation(userId); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/src/main/java/com/vinsguru/aggregator/controller/advice/ApplicationExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator.controller.advice; 2 | 3 | import io.grpc.StatusRuntimeException; 4 | import org.springframework.http.ResponseEntity; 5 | import org.springframework.web.bind.annotation.ControllerAdvice; 6 | import org.springframework.web.bind.annotation.ExceptionHandler; 7 | 8 | @ControllerAdvice 9 | public class ApplicationExceptionHandler { 10 | 11 | @ExceptionHandler(StatusRuntimeException.class) 12 | public ResponseEntity handleStatusRuntimeException(StatusRuntimeException e){ 13 | return switch (e.getStatus().getCode()){ 14 | case INVALID_ARGUMENT, FAILED_PRECONDITION -> ResponseEntity.badRequest().body(e.getStatus().getDescription()); 15 | case NOT_FOUND -> ResponseEntity.notFound().build(); 16 | case null, default -> ResponseEntity.internalServerError().body(e.getMessage()); 17 | }; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/src/main/java/com/vinsguru/aggregator/dto/PriceUpdateDto.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator.dto; 2 | 3 | public record PriceUpdateDto(String ticker, 4 | Integer price) { 5 | } 6 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/src/main/java/com/vinsguru/aggregator/service/PriceUpdateSubscriptionInitializer.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator.service; 2 | 3 | import com.google.protobuf.Empty; 4 | import com.vinsguru.stock.StockServiceGrpc; 5 | import net.devh.boot.grpc.client.inject.GrpcClient; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.CommandLineRunner; 8 | import org.springframework.stereotype.Service; 9 | 10 | @Service 11 | public class PriceUpdateSubscriptionInitializer implements CommandLineRunner { 12 | 13 | @GrpcClient("stock-service") 14 | private StockServiceGrpc.StockServiceStub stockClient; 15 | 16 | @Autowired 17 | private PriceUpdateListener listener; 18 | 19 | @Override 20 | public void run(String... args) throws Exception { 21 | this.stockClient 22 | .withWaitForReady() 23 | .getPriceUpdates(Empty.getDefaultInstance(), listener); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/src/main/java/com/vinsguru/aggregator/service/TradeService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator.service; 2 | 3 | import com.vinsguru.stock.StockPriceRequest; 4 | import com.vinsguru.stock.StockServiceGrpc; 5 | import com.vinsguru.user.StockTradeRequest; 6 | import com.vinsguru.user.StockTradeResponse; 7 | import com.vinsguru.user.UserServiceGrpc; 8 | import net.devh.boot.grpc.client.inject.GrpcClient; 9 | import org.springframework.stereotype.Service; 10 | 11 | @Service 12 | public class TradeService { 13 | 14 | @GrpcClient("user-service") 15 | private UserServiceGrpc.UserServiceBlockingStub userClient; 16 | 17 | @GrpcClient("stock-service") 18 | private StockServiceGrpc.StockServiceBlockingStub stockClient; 19 | 20 | public StockTradeResponse trade(StockTradeRequest request){ 21 | var priceRequest = StockPriceRequest.newBuilder().setTicker(request.getTicker()).build(); 22 | var priceResponse = this.stockClient.getStockPrice(priceRequest); 23 | var tradeRequest = request.toBuilder().setPrice(priceResponse.getPrice()).build(); 24 | return this.userClient.tradeStock(tradeRequest); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/src/main/java/com/vinsguru/aggregator/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator.service; 2 | 3 | import com.vinsguru.user.UserInformation; 4 | import com.vinsguru.user.UserInformationRequest; 5 | import com.vinsguru.user.UserServiceGrpc; 6 | import net.devh.boot.grpc.client.inject.GrpcClient; 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | public class UserService { 11 | 12 | @GrpcClient("user-service") 13 | private UserServiceGrpc.UserServiceBlockingStub userClient; 14 | 15 | public UserInformation getUserInformation(int userId) { 16 | var request = UserInformationRequest.newBuilder() 17 | .setUserId(userId) 18 | .build(); 19 | return this.userClient.getUserInformation(request); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # user-service 2 | grpc.client.user-service.address=static://localhost:6565 3 | grpc.client.user-service.negotiationType=PLAINTEXT 4 | 5 | # stock-service 6 | grpc.client.stock-service.address=static://localhost:7575 7 | grpc.client.stock-service.negotiationType=PLAINTEXT -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/src/test/java/com/vinsguru/aggregator/tests/mockservice/StockMockService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator.tests.mockservice; 2 | 3 | import com.google.common.util.concurrent.Uninterruptibles; 4 | import com.google.protobuf.Empty; 5 | import com.vinsguru.common.Ticker; 6 | import com.vinsguru.stock.PriceUpdate; 7 | import com.vinsguru.stock.StockPriceRequest; 8 | import com.vinsguru.stock.StockPriceResponse; 9 | import com.vinsguru.stock.StockServiceGrpc; 10 | import io.grpc.stub.StreamObserver; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.util.concurrent.TimeUnit; 15 | 16 | public class StockMockService extends StockServiceGrpc.StockServiceImplBase { 17 | 18 | private static final Logger log = LoggerFactory.getLogger(StockMockService.class); 19 | 20 | @Override 21 | public void getStockPrice(StockPriceRequest request, StreamObserver responseObserver) { 22 | var response = StockPriceResponse.newBuilder().setPrice(15).build(); 23 | responseObserver.onNext(response); 24 | responseObserver.onCompleted(); 25 | } 26 | 27 | @Override 28 | public void getPriceUpdates(Empty request, StreamObserver responseObserver) { 29 | Uninterruptibles.sleepUninterruptibly(3, TimeUnit.SECONDS); 30 | for (int i = 1; i <= 5; i++) { 31 | var priceUpdate = PriceUpdate.newBuilder().setPrice(i).setTicker(Ticker.AMAZON).build(); 32 | log.info("{}", priceUpdate); 33 | responseObserver.onNext(priceUpdate); 34 | } 35 | responseObserver.onCompleted(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/aggregator-service/src/test/java/com/vinsguru/aggregator/tests/mockservice/UserMockService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.aggregator.tests.mockservice; 2 | 3 | import com.vinsguru.user.*; 4 | import io.grpc.Status; 5 | import io.grpc.stub.StreamObserver; 6 | 7 | public class UserMockService extends UserServiceGrpc.UserServiceImplBase { 8 | 9 | @Override 10 | public void getUserInformation(UserInformationRequest request, StreamObserver responseObserver) { 11 | if (request.getUserId() == 1) { 12 | var user = UserInformation.newBuilder() 13 | .setUserId(1) 14 | .setBalance(100) 15 | .setName("integration-test") 16 | .build(); 17 | responseObserver.onNext(user); 18 | responseObserver.onCompleted(); 19 | } else { 20 | responseObserver.onError(Status.NOT_FOUND.asRuntimeException()); 21 | } 22 | } 23 | 24 | @Override 25 | public void tradeStock(StockTradeRequest request, StreamObserver responseObserver) { 26 | var response = StockTradeResponse.newBuilder() 27 | .setUserId(request.getUserId()) 28 | .setTicker(request.getTicker()) 29 | .setAction(request.getAction()) 30 | .setPrice(request.getPrice()) 31 | .setQuantity(request.getQuantity()) 32 | .setTotalPrice(1000) 33 | .setBalance(0) 34 | .build(); 35 | responseObserver.onNext(response); 36 | responseObserver.onCompleted(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/proto/src/main/proto/common/common.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package common; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.common"; 7 | 8 | enum Ticker { 9 | UNKNOWN = 0; 10 | APPLE = 1; 11 | GOOGLE = 2; 12 | AMAZON = 3; 13 | MICROSOFT = 4; 14 | } 15 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/proto/src/main/proto/stock-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package stock; 4 | 5 | import "google/protobuf/empty.proto"; 6 | import "common/common.proto"; 7 | 8 | option java_multiple_files = true; 9 | option java_package = "com.vinsguru.stock"; 10 | 11 | message PriceUpdate { 12 | common.Ticker ticker = 1; 13 | int32 price = 2; 14 | } 15 | 16 | message StockPriceRequest { 17 | common.Ticker ticker = 1; 18 | } 19 | 20 | message StockPriceResponse { 21 | common.Ticker ticker = 1; 22 | int32 price = 2; 23 | } 24 | 25 | // Service for providing stock prices. 26 | service StockService { 27 | 28 | // Unary API to get the current price for a specific ticker. 29 | rpc GetStockPrice(StockPriceRequest) returns (StockPriceResponse); 30 | 31 | // Server streaming API to subscribe to real-time price updates. 32 | rpc GetPriceUpdates(google.protobuf.Empty) returns (stream PriceUpdate); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/proto/src/main/proto/user-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package user; 4 | 5 | import "common/common.proto"; 6 | 7 | option java_multiple_files = true; 8 | option java_package = "com.vinsguru.user"; 9 | 10 | message UserInformationRequest{ 11 | int32 user_id = 1; 12 | } 13 | 14 | message UserInformation { 15 | int32 user_id = 1; 16 | string name = 2; 17 | int32 balance = 3; 18 | repeated Holding holdings = 4; 19 | } 20 | 21 | message Holding { 22 | common.Ticker ticker = 1; 23 | int32 quantity = 2; 24 | } 25 | 26 | enum TradeAction { 27 | BUY = 0; 28 | SELL = 1; 29 | } 30 | 31 | message StockTradeRequest { 32 | int32 user_id = 1; 33 | common.Ticker ticker = 2; 34 | int32 price = 3; 35 | int32 quantity = 4; 36 | TradeAction action = 5; 37 | } 38 | 39 | message StockTradeResponse { 40 | int32 user_id = 1; 41 | common.Ticker ticker = 2; 42 | int32 price = 3; 43 | int32 quantity = 4; 44 | TradeAction action = 5; 45 | int32 total_price = 6; 46 | int32 balance = 7; 47 | } 48 | 49 | service UserService { 50 | 51 | rpc GetUserInformation(UserInformationRequest) returns (UserInformation); 52 | 53 | rpc TradeStock(StockTradeRequest) returns (StockTradeResponse); 54 | 55 | } -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 4.0.0 7 | 8 | com.vinsguru 9 | grpc-trading-platform 10 | 0.0.1-SNAPSHOT 11 | 12 | 13 | user-service 14 | 15 | 16 | 17 | com.vinsguru 18 | proto 19 | ${project.version} 20 | 21 | 22 | net.devh 23 | grpc-server-spring-boot-starter 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-data-jpa 28 | 29 | 30 | com.h2database 31 | h2 32 | runtime 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-test 37 | test 38 | 39 | 40 | net.devh 41 | grpc-client-spring-boot-starter 42 | test 43 | 44 | 45 | io.grpc 46 | grpc-testing 47 | test 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/java/com/vinsguru/user/UserServiceApplication.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class UserServiceApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(UserServiceApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/java/com/vinsguru/user/config/ServerConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user.config; 2 | 3 | import net.devh.boot.grpc.server.serverfactory.GrpcServerConfigurer; 4 | import org.springframework.context.annotation.Bean; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | import java.util.concurrent.Executors; 8 | 9 | /* 10 | This is optional 11 | */ 12 | @Configuration 13 | public class ServerConfiguration { 14 | 15 | @Bean 16 | public GrpcServerConfigurer serverConfigurer(){ 17 | return serverBuilder -> serverBuilder.executor(Executors.newVirtualThreadPerTaskExecutor()); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/java/com/vinsguru/user/entity/PortfolioItem.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user.entity; 2 | 3 | import com.vinsguru.common.Ticker; 4 | import jakarta.persistence.Column; 5 | import jakarta.persistence.Entity; 6 | import jakarta.persistence.GeneratedValue; 7 | import jakarta.persistence.Id; 8 | 9 | @Entity 10 | public class PortfolioItem { 11 | 12 | @Id 13 | @GeneratedValue 14 | private Integer id; 15 | 16 | @Column(name = "customer_id") 17 | private Integer userId; 18 | private Ticker ticker; 19 | private Integer quantity; 20 | 21 | public Integer getId() { 22 | return id; 23 | } 24 | 25 | public void setId(Integer id) { 26 | this.id = id; 27 | } 28 | 29 | public Integer getUserId() { 30 | return userId; 31 | } 32 | 33 | public void setUserId(Integer userId) { 34 | this.userId = userId; 35 | } 36 | 37 | public Ticker getTicker() { 38 | return ticker; 39 | } 40 | 41 | public void setTicker(Ticker ticker) { 42 | this.ticker = ticker; 43 | } 44 | 45 | public Integer getQuantity() { 46 | return quantity; 47 | } 48 | 49 | public void setQuantity(Integer quantity) { 50 | this.quantity = quantity; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/java/com/vinsguru/user/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user.entity; 2 | 3 | import jakarta.persistence.Entity; 4 | import jakarta.persistence.Id; 5 | import jakarta.persistence.Table; 6 | 7 | @Entity 8 | @Table(name = "customer") 9 | public class User { 10 | 11 | @Id 12 | private Integer id; 13 | private String name; 14 | private Integer balance; 15 | 16 | public Integer getId() { 17 | return id; 18 | } 19 | 20 | public void setId(Integer id) { 21 | this.id = id; 22 | } 23 | 24 | public String getName() { 25 | return name; 26 | } 27 | 28 | public void setName(String name) { 29 | this.name = name; 30 | } 31 | 32 | public Integer getBalance() { 33 | return balance; 34 | } 35 | 36 | public void setBalance(Integer balance) { 37 | this.balance = balance; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/java/com/vinsguru/user/exceptions/InsufficientBalanceException.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user.exceptions; 2 | 3 | public class InsufficientBalanceException extends RuntimeException { 4 | 5 | private static final String MESSAGE = "User [id=%d] does not have enough fund to complete the transaction"; 6 | 7 | public InsufficientBalanceException(Integer userId) { 8 | super(MESSAGE.formatted(userId)); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/java/com/vinsguru/user/exceptions/InsufficientSharesException.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user.exceptions; 2 | 3 | public class InsufficientSharesException extends RuntimeException { 4 | 5 | private static final String MESSAGE = "User [id=%d] does not have enough shares to complete the transaction"; 6 | 7 | public InsufficientSharesException(Integer userId) { 8 | super(MESSAGE.formatted(userId)); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/java/com/vinsguru/user/exceptions/UnknownTickerException.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user.exceptions; 2 | 3 | public class UnknownTickerException extends RuntimeException { 4 | 5 | private static final String MESSAGE = "Ticker is not found"; 6 | 7 | public UnknownTickerException() { 8 | super(MESSAGE); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/java/com/vinsguru/user/exceptions/UnknownUserException.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user.exceptions; 2 | 3 | public class UnknownUserException extends RuntimeException { 4 | 5 | private static final String MESSAGE = "User [id=%d] is not found"; 6 | 7 | public UnknownUserException(Integer userId) { 8 | super(MESSAGE.formatted(userId)); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/java/com/vinsguru/user/repository/PortfolioItemRepository.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user.repository; 2 | 3 | import com.vinsguru.common.Ticker; 4 | import com.vinsguru.user.entity.PortfolioItem; 5 | import org.springframework.data.repository.CrudRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | @Repository 12 | public interface PortfolioItemRepository extends CrudRepository { 13 | 14 | List findAllByUserId(Integer userId); 15 | 16 | Optional findByUserIdAndTicker(Integer userId, Ticker ticker); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/java/com/vinsguru/user/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user.repository; 2 | 3 | import com.vinsguru.user.entity.User; 4 | import org.springframework.data.repository.CrudRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface UserRepository extends CrudRepository { 9 | } 10 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/java/com/vinsguru/user/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user.service; 2 | 3 | import com.vinsguru.user.*; 4 | import com.vinsguru.user.service.handler.StockTradeRequestHandler; 5 | import com.vinsguru.user.service.handler.UserInformationRequestHandler; 6 | import io.grpc.stub.StreamObserver; 7 | import net.devh.boot.grpc.server.service.GrpcService; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | 11 | @GrpcService 12 | public class UserService extends UserServiceGrpc.UserServiceImplBase { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(UserService.class); 15 | private final UserInformationRequestHandler userRequestHandler; 16 | private final StockTradeRequestHandler tradeRequestHandler; 17 | 18 | public UserService(UserInformationRequestHandler userRequestHandler, 19 | StockTradeRequestHandler tradeRequestHandler) { 20 | this.userRequestHandler = userRequestHandler; 21 | this.tradeRequestHandler = tradeRequestHandler; 22 | } 23 | 24 | @Override 25 | public void getUserInformation(UserInformationRequest request, StreamObserver responseObserver) { 26 | log.info("user information for id {}", request.getUserId()); 27 | var userInformation = this.userRequestHandler.getUserInformation(request); 28 | responseObserver.onNext(userInformation); 29 | responseObserver.onCompleted(); 30 | } 31 | 32 | @Override 33 | public void tradeStock(StockTradeRequest request, StreamObserver responseObserver) { 34 | log.info("{}", request); 35 | var response = TradeAction.SELL.equals(request.getAction()) ? 36 | this.tradeRequestHandler.sellStock(request) : 37 | this.tradeRequestHandler.buyStock(request); 38 | responseObserver.onNext(response); 39 | responseObserver.onCompleted(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/java/com/vinsguru/user/service/advice/ServiceExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user.service.advice; 2 | 3 | import com.vinsguru.user.exceptions.InsufficientBalanceException; 4 | import com.vinsguru.user.exceptions.InsufficientSharesException; 5 | import com.vinsguru.user.exceptions.UnknownTickerException; 6 | import com.vinsguru.user.exceptions.UnknownUserException; 7 | import io.grpc.Status; 8 | import net.devh.boot.grpc.server.advice.GrpcAdvice; 9 | import net.devh.boot.grpc.server.advice.GrpcExceptionHandler; 10 | 11 | @GrpcAdvice 12 | public class ServiceExceptionHandler { 13 | 14 | @GrpcExceptionHandler(UnknownTickerException.class) 15 | public Status handleInvalidArguments(UnknownTickerException e){ 16 | return Status.INVALID_ARGUMENT.withDescription(e.getMessage()); 17 | } 18 | 19 | @GrpcExceptionHandler(UnknownUserException.class) 20 | public Status handleUnknownEntities(UnknownUserException e){ 21 | return Status.NOT_FOUND.withDescription(e.getMessage()); 22 | } 23 | 24 | @GrpcExceptionHandler({InsufficientBalanceException.class, InsufficientSharesException.class}) 25 | public Status handlePreconditionFailures(Exception e){ 26 | return Status.FAILED_PRECONDITION.withDescription(e.getMessage()); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/java/com/vinsguru/user/service/handler/UserInformationRequestHandler.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.user.service.handler; 2 | 3 | import com.vinsguru.user.UserInformation; 4 | import com.vinsguru.user.UserInformationRequest; 5 | import com.vinsguru.user.exceptions.UnknownUserException; 6 | import com.vinsguru.user.repository.PortfolioItemRepository; 7 | import com.vinsguru.user.repository.UserRepository; 8 | import com.vinsguru.user.util.EntityMessageMapper; 9 | import org.springframework.stereotype.Service; 10 | 11 | @Service 12 | public class UserInformationRequestHandler { 13 | 14 | private final UserRepository userRepository; 15 | private final PortfolioItemRepository portfolioItemRepository; 16 | 17 | public UserInformationRequestHandler(UserRepository userRepository, PortfolioItemRepository portfolioItemRepository) { 18 | this.userRepository = userRepository; 19 | this.portfolioItemRepository = portfolioItemRepository; 20 | } 21 | 22 | public UserInformation getUserInformation(UserInformationRequest request) { 23 | var user = this.userRepository.findById(request.getUserId()) 24 | .orElseThrow(() -> new UnknownUserException(request.getUserId())); 25 | var portfolioItems = this.portfolioItemRepository.findAllByUserId(request.getUserId()); 26 | return EntityMessageMapper.toUserInformation(user, portfolioItems); 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | grpc.server.port=6565 2 | spring.jpa.defer-datasource-initialization=true -------------------------------------------------------------------------------- /03-grpc-trading-platform/user-service/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS customer; 2 | DROP TABLE IF EXISTS portfolio_item; 3 | 4 | -- intentionally naming this table as customer as "user" has some issues 5 | CREATE TABLE customer ( 6 | id int AUTO_INCREMENT primary key, 7 | name VARCHAR(50), 8 | balance int 9 | ); 10 | 11 | CREATE TABLE portfolio_item ( 12 | id int AUTO_INCREMENT primary key, 13 | customer_id int, 14 | ticker VARCHAR(10), 15 | quantity int, 16 | foreign key (customer_id) references customer(id) 17 | ); 18 | 19 | insert into customer(name, balance) 20 | values 21 | ('Sam', 10000), 22 | ('Mike', 10000), 23 | ('John', 10000); -------------------------------------------------------------------------------- /04-stock-service/README.md: -------------------------------------------------------------------------------- 1 | # Running Stock Service 2 | 3 | ```bash 4 | java -jar stock-service.jar 5 | ``` 6 | 7 | ## Changing the port 8 | ```bash 9 | java -jar stock-service.jar --grpc.server.port=7576 10 | ``` -------------------------------------------------------------------------------- /04-stock-service/stock-service.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinsguru/grpc-java-course/05c32a6a89a9fa0de16f838c6abf4f21c4a68655/04-stock-service/stock-service.jar -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/aggregator-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | grpc-flix 7 | com.vinsguru 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | aggregator-service 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-web 17 | 18 | 19 | net.devh 20 | grpc-client-spring-boot-starter 21 | 2.15.0.RELEASE 22 | 23 | 24 | org.projectlombok 25 | lombok 26 | true 27 | 28 | 29 | com.vinsguru 30 | proto 31 | 0.0.1-SNAPSHOT 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/aggregator-service/src/main/java/com/grpcflix/aggregator/AggregatorApplication.java: -------------------------------------------------------------------------------- 1 | package com.grpcflix.aggregator; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class AggregatorApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(AggregatorApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/aggregator-service/src/main/java/com/grpcflix/aggregator/controller/AggregatorController.java: -------------------------------------------------------------------------------- 1 | package com.grpcflix.aggregator.controller; 2 | 3 | import com.grpcflix.aggregator.dto.RecommendedMovie; 4 | import com.grpcflix.aggregator.dto.UserGenre; 5 | import com.grpcflix.aggregator.service.UserMovieService; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.web.bind.annotation.*; 8 | 9 | import java.util.List; 10 | 11 | @RestController 12 | public class AggregatorController { 13 | 14 | @Autowired 15 | private UserMovieService userMovieService; 16 | 17 | @GetMapping("/user/{loginId}") 18 | public List getMovies(@PathVariable String loginId){ 19 | return this.userMovieService.getUserMovieSuggestions(loginId); 20 | } 21 | 22 | @PutMapping("/user") 23 | public void setUserGenre(@RequestBody UserGenre userGenre){ 24 | this.userMovieService.setUserGenre(userGenre); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/aggregator-service/src/main/java/com/grpcflix/aggregator/dto/RecommendedMovie.java: -------------------------------------------------------------------------------- 1 | package com.grpcflix.aggregator.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Data 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class RecommendedMovie { 11 | 12 | private String title; 13 | private int year; 14 | private double rating; 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/aggregator-service/src/main/java/com/grpcflix/aggregator/dto/UserGenre.java: -------------------------------------------------------------------------------- 1 | package com.grpcflix.aggregator.dto; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class UserGenre { 7 | 8 | private String loginId; 9 | private String genre; 10 | 11 | } 12 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/aggregator-service/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | grpc: 2 | client: 3 | user-service: 4 | address: static://localhost:6565 5 | negotiationType: plaintext 6 | movie-service: 7 | address: static://localhost:7575 8 | negotiationType: plaintext -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/movie-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | grpc-flix 7 | com.vinsguru 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | movie-service 13 | 14 | 15 | net.devh 16 | grpc-server-spring-boot-starter 17 | 2.15.0.RELEASE 18 | 19 | 20 | org.springframework.boot 21 | spring-boot-starter-data-jpa 22 | 23 | 24 | com.h2database 25 | h2 26 | runtime 27 | 28 | 29 | org.projectlombok 30 | lombok 31 | true 32 | 33 | 34 | com.vinsguru 35 | proto 36 | 0.0.1-SNAPSHOT 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/movie-service/src/main/java/com/grpcflix/movie/MovieApplication.java: -------------------------------------------------------------------------------- 1 | package com.grpcflix.movie; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class MovieApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(MovieApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/movie-service/src/main/java/com/grpcflix/movie/entity/Movie.java: -------------------------------------------------------------------------------- 1 | package com.grpcflix.movie.entity; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | //import javax.persistence.Column; 7 | //import javax.persistence.Entity; 8 | //import javax.persistence.Id; 9 | 10 | import jakarta.persistence.Column; 11 | import jakarta.persistence.Entity; 12 | import jakarta.persistence.Id; 13 | 14 | @Data 15 | @Entity 16 | @ToString 17 | public class Movie { 18 | 19 | @Id 20 | private int id; 21 | private String title; 22 | 23 | @Column(name="release_year") 24 | private int year; 25 | 26 | private double rating; 27 | private String genre; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/movie-service/src/main/java/com/grpcflix/movie/repository/MovieRepository.java: -------------------------------------------------------------------------------- 1 | package com.grpcflix.movie.repository; 2 | 3 | import com.grpcflix.movie.entity.Movie; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | import java.util.List; 8 | 9 | @Repository 10 | public interface MovieRepository extends JpaRepository { 11 | List getMovieByGenreOrderByYearDesc(String genre); 12 | } 13 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/movie-service/src/main/java/com/grpcflix/movie/service/MovieService.java: -------------------------------------------------------------------------------- 1 | package com.grpcflix.movie.service; 2 | 3 | import com.grpcflix.movie.repository.MovieRepository; 4 | import com.vinsguru.grpcflix.movie.MovieDto; 5 | import com.vinsguru.grpcflix.movie.MovieSearchRequest; 6 | import com.vinsguru.grpcflix.movie.MovieSearchResponse; 7 | import com.vinsguru.grpcflix.movie.MovieServiceGrpc; 8 | import io.grpc.stub.StreamObserver; 9 | import net.devh.boot.grpc.server.service.GrpcService; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | 12 | import java.util.List; 13 | import java.util.stream.Collectors; 14 | 15 | @GrpcService 16 | public class MovieService extends MovieServiceGrpc.MovieServiceImplBase { 17 | 18 | @Autowired 19 | private MovieRepository repository; 20 | 21 | @Override 22 | public void getMovies(MovieSearchRequest request, StreamObserver responseObserver) { 23 | List movieDtoList = this.repository.getMovieByGenreOrderByYearDesc(request.getGenre().toString()) 24 | .stream() 25 | .map(movie -> MovieDto.newBuilder() 26 | .setTitle(movie.getTitle()) 27 | .setYear(movie.getYear()) 28 | .setRating(movie.getRating()) 29 | .build()) 30 | .collect(Collectors.toList()); 31 | responseObserver.onNext(MovieSearchResponse.newBuilder().addAllMovie(movieDtoList).build()); 32 | responseObserver.onCompleted(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/movie-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | grpc.server.port=7575 2 | spring.jpa.defer-datasource-initialization=true -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/movie-service/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS movie; 2 | CREATE TABLE movie AS SELECT * FROM CSVREAD('classpath:movie.csv'); -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/movie-service/src/main/resources/movie.csv: -------------------------------------------------------------------------------- 1 | id, title, release_year,rating,genre 2 | 1, The Shawshank Redemption, 1994,9.3,DRAMA 3 | 2, The godfather, 1972, 9.2,DRAMA 4 | 3, Pulp Fiction, 1994, 8.9,CRIME, 5 | 4, The good the bad and the ugly, 1966, 8.8,WESTERN 6 | 5, Inception, 2010, 8.8,ACTION 7 | 6, Se7en, 1995, 8.6,CRIME 8 | 7, City of god, 2002, 8.06,CRIME 9 | 8, Django unchained, 2012, 8.4,WESTERN 10 | 9, Oldboy, 2003, 8.4,ACTION 11 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | pom 6 | 7 | proto 8 | user-service 9 | movie-service 10 | aggregator-service 11 | 12 | 13 | org.springframework.boot 14 | spring-boot-starter-parent 15 | 3.2.0 16 | 17 | 18 | com.vinsguru 19 | grpc-flix 20 | 0.0.1-SNAPSHOT 21 | grpc-flix 22 | Demo project for Spring Boot 23 | 24 | 25 | 21 26 | 27 | 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-test 32 | test 33 | 34 | 35 | 36 | 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-maven-plugin 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/proto/src/main/proto/common/common.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package common; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.grpcflix.common"; 7 | 8 | enum Genre { 9 | DRAMA = 0; 10 | ACTION = 1; 11 | CRIME = 2; 12 | WESTERN = 3; 13 | } -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/proto/src/main/proto/movie-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "common/common.proto"; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.grpcflix.movie"; 7 | 8 | message MovieDto{ 9 | string title = 1; 10 | int32 year = 2; 11 | double rating = 3; 12 | } 13 | 14 | message MovieSearchRequest{ 15 | common.Genre genre = 1; 16 | } 17 | 18 | message MovieSearchResponse { 19 | repeated MovieDto movie = 1; 20 | } 21 | 22 | service MovieService{ 23 | rpc getMovies(MovieSearchRequest) returns (MovieSearchResponse); 24 | } 25 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/proto/src/main/proto/user-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "common/common.proto"; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.grpcflix.user"; 7 | 8 | message UserSearchRequest{ 9 | string login_id = 1; 10 | } 11 | 12 | message UserResponse { 13 | string login_id = 1; 14 | string name = 2; 15 | common.Genre genre = 3; 16 | } 17 | 18 | message UserGenreUpdateRequest{ 19 | string login_id = 1; 20 | common.Genre genre = 2; 21 | } 22 | 23 | service UserService { 24 | rpc getUserGenre(UserSearchRequest) returns (UserResponse); 25 | rpc updateUserGenre(UserGenreUpdateRequest) returns (UserResponse); 26 | } -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/user-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | grpc-flix 7 | com.vinsguru 8 | 0.0.1-SNAPSHOT 9 | 10 | 4.0.0 11 | 12 | user-service 13 | 14 | 15 | 16 | net.devh 17 | grpc-server-spring-boot-starter 18 | 2.15.0.RELEASE 19 | 20 | 21 | org.springframework.boot 22 | spring-boot-starter-data-jpa 23 | 24 | 25 | com.h2database 26 | h2 27 | runtime 28 | 29 | 30 | org.projectlombok 31 | lombok 32 | true 33 | 34 | 35 | com.vinsguru 36 | proto 37 | 0.0.1-SNAPSHOT 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/user-service/src/main/java/com/grpcflix/user/UserApplication.java: -------------------------------------------------------------------------------- 1 | package com.grpcflix.user; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class UserApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(UserApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/user-service/src/main/java/com/grpcflix/user/entity/User.java: -------------------------------------------------------------------------------- 1 | package com.grpcflix.user.entity; 2 | 3 | import lombok.Data; 4 | import lombok.ToString; 5 | 6 | //import javax.persistence.Entity; 7 | //import javax.persistence.Id; 8 | //import javax.persistence.Table; 9 | 10 | import jakarta.persistence.Entity; 11 | import jakarta.persistence.Id; 12 | import jakarta.persistence.Table; 13 | 14 | @Data 15 | @Entity 16 | @ToString 17 | @Table(name = "\"user\"") 18 | public class User { 19 | 20 | @Id 21 | private String login; 22 | private String name; 23 | private String genre; 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/user-service/src/main/java/com/grpcflix/user/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.grpcflix.user.repository; 2 | 3 | import com.grpcflix.user.entity.User; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface UserRepository extends JpaRepository { 9 | } 10 | -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/user-service/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | grpc.server.port=6565 2 | spring.jpa.defer-datasource-initialization=true -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/user-service/src/main/resources/data.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS "user"; 2 | CREATE TABLE "user" AS SELECT * FROM CSVREAD('classpath:user.csv'); -------------------------------------------------------------------------------- /99-old-projects/grpc-flix/user-service/src/main/resources/user.csv: -------------------------------------------------------------------------------- 1 | login,name,genre 2 | vinsguru,vinoth,WESTERN 3 | sam123,sam,ACTION -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/deadline/GrpcServer.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.deadline; 2 | 3 | import io.grpc.Server; 4 | import io.grpc.ServerBuilder; 5 | 6 | import java.io.IOException; 7 | 8 | public class GrpcServer { 9 | 10 | public static void main(String[] args) throws IOException, InterruptedException { 11 | 12 | Server server = ServerBuilder.forPort(6565) 13 | .addService(new DeadlineService()) 14 | .build(); 15 | 16 | server.start(); 17 | 18 | server.awaitTermination(); 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/loadbalancing/BankService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.loadbalancing; 2 | 3 | import com.vinsguru.models.*; 4 | import com.vinsguru.server.rpctypes.AccountDatabase; 5 | import io.grpc.Status; 6 | import io.grpc.stub.StreamObserver; 7 | 8 | public class BankService extends BankServiceGrpc.BankServiceImplBase { 9 | 10 | @Override 11 | public void getBalance(BalanceCheckRequest request, StreamObserver responseObserver) { 12 | int accountNumber = request.getAccountNumber(); 13 | System.out.println( 14 | "Received the request for " + accountNumber 15 | ); 16 | Balance balance = Balance.newBuilder() 17 | .setAmount(AccountDatabase.getBalance(accountNumber)) 18 | .build(); 19 | responseObserver.onNext(balance); 20 | responseObserver.onCompleted(); 21 | } 22 | 23 | @Override 24 | public void withdraw(WithdrawRequest request, StreamObserver responseObserver) { 25 | int accountNumber = request.getAccountNumber(); 26 | int amount = request.getAmount(); //10, 20, 30.. 27 | int balance = AccountDatabase.getBalance(accountNumber); 28 | 29 | if(balance < amount){ 30 | Status status = Status.FAILED_PRECONDITION.withDescription("No enough money. You have only " + balance); 31 | responseObserver.onError(status.asRuntimeException()); 32 | return; 33 | } 34 | // all the validations passed 35 | for (int i = 0; i < (amount/10); i++) { 36 | Money money = Money.newBuilder().setValue(10).build(); 37 | responseObserver.onNext(money); 38 | AccountDatabase.deductBalance(accountNumber, 10); 39 | } 40 | responseObserver.onCompleted(); 41 | } 42 | 43 | @Override 44 | public StreamObserver cashDeposit(StreamObserver responseObserver) { 45 | return new CashStreamingRequest(responseObserver); 46 | } 47 | 48 | 49 | 50 | } 51 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/loadbalancing/CashStreamingRequest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.loadbalancing; 2 | 3 | import com.vinsguru.models.Balance; 4 | import com.vinsguru.models.DepositRequest; 5 | import com.vinsguru.server.rpctypes.AccountDatabase; 6 | import io.grpc.stub.StreamObserver; 7 | 8 | public class CashStreamingRequest implements StreamObserver { 9 | 10 | private StreamObserver balanceStreamObserver; 11 | private int accountBalance; 12 | 13 | public CashStreamingRequest(StreamObserver balanceStreamObserver) { 14 | this.balanceStreamObserver = balanceStreamObserver; 15 | } 16 | 17 | @Override 18 | public void onNext(DepositRequest depositRequest) { 19 | int accountNumber = depositRequest.getAccountNumber(); 20 | System.out.println( 21 | "Received cash deposit for " + accountNumber 22 | ); 23 | int amount = depositRequest.getAmount(); 24 | this.accountBalance = AccountDatabase.addBalance(accountNumber, amount); 25 | } 26 | 27 | @Override 28 | public void onError(Throwable throwable) { 29 | 30 | } 31 | 32 | @Override 33 | public void onCompleted() { 34 | Balance balance = Balance.newBuilder().setAmount(this.accountBalance).build(); 35 | this.balanceStreamObserver.onNext(balance); 36 | this.balanceStreamObserver.onCompleted(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/loadbalancing/GrpcServer1.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.loadbalancing; 2 | 3 | import io.grpc.Server; 4 | import io.grpc.ServerBuilder; 5 | 6 | import java.io.IOException; 7 | 8 | public class GrpcServer1 { 9 | 10 | public static void main(String[] args) throws IOException, InterruptedException { 11 | 12 | Server server = ServerBuilder.forPort(6565) 13 | .addService(new BankService()) 14 | .build(); 15 | 16 | server.start(); 17 | 18 | server.awaitTermination(); 19 | 20 | } 21 | 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/loadbalancing/GrpcServer2.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.loadbalancing; 2 | 3 | import io.grpc.Server; 4 | import io.grpc.ServerBuilder; 5 | 6 | import java.io.IOException; 7 | 8 | public class GrpcServer2 { 9 | 10 | public static void main(String[] args) throws IOException, InterruptedException { 11 | 12 | Server server = ServerBuilder.forPort(7575) 13 | .addService(new BankService()) 14 | .build(); 15 | 16 | server.start(); 17 | 18 | server.awaitTermination(); 19 | 20 | } 21 | 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/metadata/AuthInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.metadata; 2 | 3 | import io.grpc.*; 4 | 5 | import java.util.Objects; 6 | 7 | /* 8 | user-secret-3:prime 9 | user-secret-2:regular 10 | */ 11 | 12 | public class AuthInterceptor implements ServerInterceptor { 13 | @Override 14 | public ServerCall.Listener interceptCall(ServerCall serverCall, Metadata metadata, ServerCallHandler serverCallHandler) { 15 | String clientToken = metadata.get(ServerConstants.USER_TOKEN); 16 | if(this.validate(clientToken)){ 17 | UserRole userRole = this.extractUserRole(clientToken); 18 | Context context = Context.current().withValue( 19 | ServerConstants.CTX_USER_ROLE, 20 | userRole 21 | ); 22 | return Contexts.interceptCall(context, serverCall, metadata, serverCallHandler); 23 | //return serverCallHandler.startCall(serverCall, metadata); 24 | }else{ 25 | Status status = Status.UNAUTHENTICATED.withDescription("invalid token/expired token"); 26 | serverCall.close(status, metadata); 27 | } 28 | return new ServerCall.Listener() { 29 | }; 30 | } 31 | 32 | private boolean validate(String token){ 33 | return Objects.nonNull(token) && 34 | (token.startsWith("user-secret-3") || token.startsWith("user-secret-2")); 35 | } 36 | 37 | private UserRole extractUserRole(String jwt){ 38 | return jwt.endsWith("prime") ? UserRole.PRIME : UserRole.STANDARD; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/metadata/GrpcServer.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.metadata; 2 | 3 | import io.grpc.Server; 4 | import io.grpc.ServerBuilder; 5 | 6 | import java.io.IOException; 7 | 8 | public class GrpcServer { 9 | 10 | public static void main(String[] args) throws IOException, InterruptedException { 11 | 12 | Server server = ServerBuilder.forPort(6565) 13 | // .intercept(new AuthInterceptor()) 14 | .addService(new MetadataService()) 15 | .build(); 16 | 17 | server.start(); 18 | 19 | server.awaitTermination(); 20 | 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/metadata/ServerConstants.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.metadata; 2 | 3 | 4 | import io.grpc.Context; 5 | import io.grpc.Metadata; 6 | 7 | public class ServerConstants { 8 | public static final Metadata.Key TOKEN = Metadata.Key.of("client-token", 9 | Metadata.ASCII_STRING_MARSHALLER); 10 | 11 | public static final Metadata.Key USER_TOKEN = Metadata.Key.of("user-token", 12 | Metadata.ASCII_STRING_MARSHALLER); 13 | 14 | public static final Context.Key CTX_USER_ROLE = Context.key("user-role"); 15 | public static final Context.Key CTX_USER_ROLE1 = Context.key("user-role"); 16 | } 17 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/metadata/UserRole.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.metadata; 2 | 3 | public enum UserRole { 4 | PRIME, 5 | STANDARD; 6 | } 7 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/rpctypes/AccountDatabase.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.rpctypes; 2 | 3 | import java.util.Map; 4 | import java.util.function.Function; 5 | import java.util.stream.Collectors; 6 | import java.util.stream.IntStream; 7 | 8 | public class AccountDatabase { 9 | /* 10 | This is a DB 11 | 1 => 10 12 | 2 => 20 13 | ... 14 | 10 => 100 15 | */ 16 | 17 | private static final Map MAP = IntStream.rangeClosed(1, 10) 18 | .boxed() 19 | .collect(Collectors.toMap( 20 | Function.identity(), 21 | v -> 100) 22 | ); 23 | 24 | public static int getBalance(int accountId){ 25 | return MAP.get(accountId); 26 | } 27 | 28 | public static Integer addBalance(int accountId, int amount){ 29 | return MAP.computeIfPresent(accountId, (k, v) -> v + amount); 30 | } 31 | 32 | public static Integer deductBalance(int accountId, int amount){ 33 | return MAP.computeIfPresent(accountId, (k, v) -> v - amount); 34 | } 35 | 36 | public static void printAccountDetails(){ 37 | System.out.println( 38 | MAP 39 | ); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/rpctypes/BankService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.rpctypes; 2 | 3 | import com.vinsguru.models.*; 4 | import io.grpc.Status; 5 | import io.grpc.stub.StreamObserver; 6 | 7 | public class BankService extends BankServiceGrpc.BankServiceImplBase { 8 | 9 | @Override 10 | public void getBalance(BalanceCheckRequest request, StreamObserver responseObserver) { 11 | 12 | int accountNumber = request.getAccountNumber(); 13 | Balance balance = Balance.newBuilder() 14 | .setAmount(AccountDatabase.getBalance(accountNumber)) 15 | .build(); 16 | responseObserver.onNext(balance); 17 | responseObserver.onCompleted(); 18 | } 19 | 20 | @Override 21 | public void withdraw(WithdrawRequest request, StreamObserver responseObserver) { 22 | int accountNumber = request.getAccountNumber(); 23 | int amount = request.getAmount(); //10, 20, 30.. 24 | int balance = AccountDatabase.getBalance(accountNumber); 25 | 26 | if(balance < amount){ 27 | Status status = Status.FAILED_PRECONDITION.withDescription("No enough money. You have only " + balance); 28 | responseObserver.onError(status.asRuntimeException()); 29 | return; 30 | } 31 | // all the validations passed 32 | for (int i = 0; i < (amount/10); i++) { 33 | Money money = Money.newBuilder().setValue(10).build(); 34 | responseObserver.onNext(money); 35 | AccountDatabase.deductBalance(accountNumber, 10); 36 | } 37 | responseObserver.onCompleted(); 38 | } 39 | 40 | @Override 41 | public StreamObserver cashDeposit(StreamObserver responseObserver) { 42 | return new CashStreamingRequest(responseObserver); 43 | } 44 | 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/rpctypes/CashStreamingRequest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.rpctypes; 2 | 3 | import com.vinsguru.models.Balance; 4 | import com.vinsguru.models.DepositRequest; 5 | import io.grpc.stub.StreamObserver; 6 | 7 | public class CashStreamingRequest implements StreamObserver { 8 | 9 | private StreamObserver balanceStreamObserver; 10 | private int accountBalance; 11 | 12 | public CashStreamingRequest(StreamObserver balanceStreamObserver) { 13 | this.balanceStreamObserver = balanceStreamObserver; 14 | } 15 | 16 | @Override 17 | public void onNext(DepositRequest depositRequest) { 18 | int accountNumber = depositRequest.getAccountNumber(); 19 | int amount = depositRequest.getAmount(); 20 | this.accountBalance = AccountDatabase.addBalance(accountNumber, amount); 21 | } 22 | 23 | @Override 24 | public void onError(Throwable throwable) { 25 | 26 | } 27 | 28 | @Override 29 | public void onCompleted() { 30 | Balance balance = Balance.newBuilder().setAmount(this.accountBalance).build(); 31 | this.balanceStreamObserver.onNext(balance); 32 | this.balanceStreamObserver.onCompleted(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/rpctypes/GrpcServer.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.rpctypes; 2 | 3 | import io.grpc.Server; 4 | import io.grpc.ServerBuilder; 5 | 6 | import java.io.IOException; 7 | 8 | public class GrpcServer { 9 | 10 | public static void main(String[] args) throws IOException, InterruptedException { 11 | 12 | Server server = ServerBuilder.forPort(6565) 13 | .addService(new BankService()) 14 | .addService(new TransferService()) 15 | .build(); 16 | 17 | server.start(); 18 | 19 | server.awaitTermination(); 20 | 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/rpctypes/TransferService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.rpctypes; 2 | 3 | import com.vinsguru.models.TransferRequest; 4 | import com.vinsguru.models.TransferResponse; 5 | import com.vinsguru.models.TransferServiceGrpc; 6 | import io.grpc.stub.StreamObserver; 7 | 8 | public class TransferService extends TransferServiceGrpc.TransferServiceImplBase { 9 | 10 | @Override 11 | public StreamObserver transfer(StreamObserver responseObserver) { 12 | return new TransferStreamingRequest(responseObserver); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/ssl/BankService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.ssl; 2 | 3 | import com.vinsguru.models.*; 4 | import com.vinsguru.server.rpctypes.AccountDatabase; 5 | import com.vinsguru.server.rpctypes.CashStreamingRequest; 6 | import io.grpc.Status; 7 | import io.grpc.stub.StreamObserver; 8 | 9 | public class BankService extends BankServiceGrpc.BankServiceImplBase { 10 | 11 | @Override 12 | public void getBalance(BalanceCheckRequest request, StreamObserver responseObserver) { 13 | 14 | int accountNumber = request.getAccountNumber(); 15 | Balance balance = Balance.newBuilder() 16 | .setAmount(AccountDatabase.getBalance(accountNumber)) 17 | .build(); 18 | responseObserver.onNext(balance); 19 | responseObserver.onCompleted(); 20 | } 21 | 22 | @Override 23 | public void withdraw(WithdrawRequest request, StreamObserver responseObserver) { 24 | int accountNumber = request.getAccountNumber(); 25 | int amount = request.getAmount(); //10, 20, 30.. 26 | int balance = AccountDatabase.getBalance(accountNumber); 27 | 28 | if(balance < amount){ 29 | Status status = Status.FAILED_PRECONDITION.withDescription("No enough money. You have only " + balance); 30 | responseObserver.onError(status.asRuntimeException()); 31 | return; 32 | } 33 | // all the validations passed 34 | for (int i = 0; i < (amount/10); i++) { 35 | Money money = Money.newBuilder().setValue(10).build(); 36 | responseObserver.onNext(money); 37 | AccountDatabase.deductBalance(accountNumber, 10); 38 | } 39 | responseObserver.onCompleted(); 40 | } 41 | 42 | @Override 43 | public StreamObserver cashDeposit(StreamObserver responseObserver) { 44 | return new CashStreamingRequest(responseObserver); 45 | } 46 | 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/java/com/vinsguru/server/ssl/GrpcServer.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.server.ssl; 2 | 3 | import io.grpc.Server; 4 | import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; 5 | import io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder; 6 | import io.grpc.netty.shaded.io.netty.handler.ssl.SslContext; 7 | import io.grpc.netty.shaded.io.netty.handler.ssl.SslContextBuilder; 8 | 9 | import java.io.File; 10 | import java.io.IOException; 11 | 12 | public class GrpcServer { 13 | 14 | public static void main(String[] args) throws IOException, InterruptedException { 15 | 16 | SslContext sslContext = GrpcSslContexts.configure( 17 | SslContextBuilder.forServer( 18 | new File("path/localhost.crt"), 19 | new File("path/localhost.pem") 20 | ) 21 | ).build(); 22 | 23 | Server server = NettyServerBuilder.forPort(6565) 24 | .sslContext(sslContext) 25 | .addService(new BankService()) 26 | .build(); 27 | 28 | server.start(); 29 | 30 | server.awaitTermination(); 31 | 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/proto/bank-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "com.vinsguru.models"; 5 | 6 | message BalanceCheckRequest { 7 | int32 account_number = 1; 8 | } 9 | 10 | // USD 11 | message Balance { 12 | int32 amount = 1; 13 | } 14 | 15 | message WithdrawRequest { 16 | int32 account_number = 1; 17 | int32 amount = 2; 18 | } 19 | 20 | message Money { 21 | int32 value = 1; 22 | } 23 | 24 | message DepositRequest { 25 | int32 account_number = 1; 26 | int32 amount = 2; 27 | } 28 | 29 | enum ErrorMessage { 30 | ONLY_TEN_MULTIPLES = 0; 31 | INSUFFICIENT_BALANCE = 1; 32 | } 33 | 34 | message WithdrawalError { 35 | ErrorMessage error_message = 1; 36 | int32 amount = 2; 37 | } 38 | 39 | service BankService { 40 | 41 | //unary 42 | rpc getBalance(BalanceCheckRequest) returns (Balance); 43 | 44 | // server-side streaming 45 | rpc withdraw(WithdrawRequest) returns(stream Money); 46 | 47 | // client-side streaming 48 | rpc cashDeposit(stream DepositRequest) returns (Balance); 49 | } 50 | 51 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/main/proto/transfer-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "com.vinsguru.models"; 5 | 6 | message TransferRequest { 7 | int32 from_account = 1; 8 | int32 to_account = 2; 9 | int32 amount = 3; 10 | } 11 | 12 | message Account { 13 | int32 account_number = 1; 14 | int32 amount = 2; 15 | } 16 | 17 | enum TransferStatus { 18 | FAILED = 0; 19 | SUCCESS = 1; 20 | } 21 | 22 | message TransferResponse { 23 | TransferStatus status = 1; 24 | repeated Account accounts = 2; 25 | } 26 | 27 | service TransferService { 28 | rpc transfer(stream TransferRequest) returns (stream TransferResponse); 29 | } -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/test/java/com/vinsguru/client/deadline/DeadlineInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.client.deadline; 2 | 3 | import io.grpc.*; 4 | 5 | import java.util.Objects; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | public class DeadlineInterceptor implements ClientInterceptor { 9 | @Override 10 | public ClientCall interceptCall(MethodDescriptor methodDescriptor, CallOptions callOptions, Channel channel) { 11 | Deadline deadline = callOptions.getDeadline(); 12 | if(Objects.isNull(deadline)){ 13 | callOptions = callOptions.withDeadline(Deadline.after(4, TimeUnit.SECONDS)); 14 | } 15 | return channel.newCall(methodDescriptor, callOptions); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/test/java/com/vinsguru/client/loadbalancing/ServiceRegistry.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.client.loadbalancing; 2 | 3 | import io.grpc.EquivalentAddressGroup; 4 | 5 | import java.net.InetSocketAddress; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.stream.Collectors; 10 | 11 | public class ServiceRegistry { 12 | 13 | private static final Map> MAP = new HashMap<>(); 14 | 15 | //payment-service 127.0.0.1:8080,128.0.0.1:8080 16 | public static void register(String service, List instances){ 17 | List addressGroupList = instances.stream() 18 | .map(i -> i.split(":")) 19 | .map(a -> new InetSocketAddress(a[0], Integer.parseInt(a[1]))) 20 | .map(EquivalentAddressGroup::new) 21 | .collect(Collectors.toList()); 22 | MAP.put(service, addressGroupList); 23 | } 24 | 25 | public static List getInstances(String service){ 26 | return MAP.get(service); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/test/java/com/vinsguru/client/loadbalancing/TempNameResolver.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.client.loadbalancing; 2 | 3 | import io.grpc.EquivalentAddressGroup; 4 | import io.grpc.NameResolver; 5 | 6 | import java.util.List; 7 | 8 | public class TempNameResolver extends NameResolver { 9 | 10 | private final String service; 11 | 12 | public TempNameResolver(String service) { 13 | this.service = service; 14 | } 15 | 16 | @Override 17 | public String getServiceAuthority() { 18 | return "temp"; 19 | } 20 | 21 | @Override 22 | public void shutdown() { 23 | 24 | } 25 | 26 | @Override 27 | public void refresh() { 28 | super.refresh(); 29 | } 30 | 31 | @Override 32 | public void start(Listener2 listener) { 33 | List addressGroups = ServiceRegistry.getInstances(this.service); 34 | ResolutionResult resolutionResult = ResolutionResult.newBuilder().setAddresses(addressGroups).build(); 35 | listener.onResult(resolutionResult); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/test/java/com/vinsguru/client/loadbalancing/TempNameResolverProvider.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.client.loadbalancing; 2 | 3 | import io.grpc.NameResolver; 4 | import io.grpc.NameResolverProvider; 5 | 6 | import java.net.URI; 7 | 8 | public class TempNameResolverProvider extends NameResolverProvider { 9 | 10 | @Override 11 | protected boolean isAvailable() { 12 | return true; 13 | } 14 | 15 | @Override 16 | protected int priority() { 17 | return 5; 18 | } 19 | 20 | @Override 21 | public String getDefaultScheme() { 22 | return "dns"; 23 | } 24 | 25 | @Override 26 | public NameResolver newNameResolver(URI targetUri, NameResolver.Args args) { 27 | System.out.println( 28 | "Looking for service : " + targetUri.toString() 29 | ); 30 | return new TempNameResolver(targetUri.toString()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/test/java/com/vinsguru/client/metadata/ClientConstants.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.client.metadata; 2 | 3 | import com.vinsguru.models.WithdrawalError; 4 | import io.grpc.Metadata; 5 | import io.grpc.protobuf.ProtoUtils; 6 | 7 | public class ClientConstants { 8 | 9 | public static final Metadata.Key WITHDRAWAL_ERROR_KEY = ProtoUtils.keyForProto(WithdrawalError.getDefaultInstance()); 10 | public static final Metadata.Key USER_TOKEN = Metadata.Key.of("user-token", Metadata.ASCII_STRING_MARSHALLER); 11 | private static final Metadata METADATA = new Metadata(); 12 | 13 | static { 14 | METADATA.put( 15 | Metadata.Key.of("client-token", Metadata.ASCII_STRING_MARSHALLER), 16 | "bank-client-secre" 17 | ); 18 | } 19 | 20 | 21 | public static Metadata getClientToken(){ 22 | return METADATA; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/test/java/com/vinsguru/client/metadata/UserSessionToken.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.client.metadata; 2 | 3 | import io.grpc.CallCredentials; 4 | import io.grpc.Metadata; 5 | 6 | import java.util.concurrent.Executor; 7 | 8 | public class UserSessionToken extends CallCredentials { 9 | 10 | private String jwt; 11 | 12 | public UserSessionToken(String jwt){ 13 | this.jwt = jwt; 14 | } 15 | 16 | @Override 17 | public void applyRequestMetadata(RequestInfo requestInfo, Executor executor, MetadataApplier metadataApplier) { 18 | executor.execute(() -> { 19 | Metadata metadata = new Metadata(); 20 | metadata.put(ClientConstants.USER_TOKEN, this.jwt); 21 | metadataApplier.apply(metadata); 22 | //metadataApplier.fail(); 23 | }); 24 | } 25 | 26 | @Override 27 | public void thisUsesUnstableApi() { 28 | //may change in future 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/test/java/com/vinsguru/client/rpctypes/BalanceStreamObserver.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.client.rpctypes; 2 | 3 | import com.vinsguru.models.Balance; 4 | import io.grpc.stub.StreamObserver; 5 | 6 | import java.util.concurrent.CountDownLatch; 7 | 8 | public class BalanceStreamObserver implements StreamObserver { 9 | 10 | private CountDownLatch latch; 11 | 12 | public BalanceStreamObserver(CountDownLatch latch) { 13 | this.latch = latch; 14 | } 15 | 16 | @Override 17 | public void onNext(Balance balance) { 18 | System.out.println( 19 | "Final Balance : " + balance.getAmount() 20 | ); 21 | } 22 | 23 | @Override 24 | public void onError(Throwable throwable) { 25 | this.latch.countDown(); 26 | } 27 | 28 | @Override 29 | public void onCompleted() { 30 | System.out.println( 31 | "Server is done!" 32 | ); 33 | this.latch.countDown(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/test/java/com/vinsguru/client/rpctypes/MoneyStreamingResponse.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.client.rpctypes; 2 | 3 | import com.vinsguru.client.metadata.ClientConstants; 4 | import com.vinsguru.models.Money; 5 | import com.vinsguru.models.WithdrawalError; 6 | import io.grpc.Metadata; 7 | import io.grpc.Status; 8 | import io.grpc.stub.StreamObserver; 9 | 10 | import java.util.concurrent.CountDownLatch; 11 | 12 | public class MoneyStreamingResponse implements StreamObserver { 13 | 14 | private CountDownLatch latch; 15 | 16 | public MoneyStreamingResponse(CountDownLatch latch) { 17 | this.latch = latch; 18 | } 19 | 20 | @Override 21 | public void onNext(Money money) { 22 | System.out.println( 23 | "Received async : " + money.getValue() 24 | ); 25 | } 26 | 27 | @Override 28 | public void onError(Throwable throwable) { 29 | Metadata metadata = Status.trailersFromThrowable(throwable); 30 | WithdrawalError withdrawalError = metadata.get(ClientConstants.WITHDRAWAL_ERROR_KEY); 31 | System.out.println( 32 | withdrawalError.getAmount() + ":" + withdrawalError.getErrorMessage() 33 | ); 34 | latch.countDown(); 35 | } 36 | 37 | @Override 38 | public void onCompleted() { 39 | System.out.println( 40 | "Server is done!!" 41 | ); 42 | latch.countDown(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/test/java/com/vinsguru/client/rpctypes/TransferClientTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.client.rpctypes; 2 | 3 | import com.vinsguru.models.TransferRequest; 4 | import com.vinsguru.models.TransferServiceGrpc; 5 | import io.grpc.ManagedChannel; 6 | import io.grpc.ManagedChannelBuilder; 7 | import io.grpc.stub.StreamObserver; 8 | import org.junit.jupiter.api.BeforeAll; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.jupiter.api.TestInstance; 11 | 12 | import java.util.concurrent.CountDownLatch; 13 | import java.util.concurrent.ThreadLocalRandom; 14 | 15 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 16 | public class TransferClientTest { 17 | 18 | private TransferServiceGrpc.TransferServiceStub stub; 19 | 20 | @BeforeAll 21 | public void setup(){ 22 | ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 6565) 23 | .usePlaintext() 24 | .build(); 25 | this.stub = TransferServiceGrpc.newStub(managedChannel); 26 | } 27 | 28 | @Test 29 | public void transfer() throws InterruptedException { 30 | CountDownLatch latch = new CountDownLatch(1); 31 | TransferStreamingResponse response = new TransferStreamingResponse(latch); 32 | StreamObserver requestStreamObserver = this.stub.transfer(response); 33 | 34 | for (int i = 0; i < 100; i++) { 35 | TransferRequest request = TransferRequest.newBuilder() 36 | .setFromAccount(ThreadLocalRandom.current().nextInt(1, 11)) 37 | .setToAccount(ThreadLocalRandom.current().nextInt(1, 11)) 38 | .setAmount(ThreadLocalRandom.current().nextInt(1, 21)) 39 | .build(); 40 | requestStreamObserver.onNext(request); 41 | } 42 | requestStreamObserver.onCompleted(); 43 | latch.await(); 44 | } 45 | 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /99-old-projects/grpc-intro/src/test/java/com/vinsguru/client/rpctypes/TransferStreamingResponse.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.client.rpctypes; 2 | 3 | import com.vinsguru.models.TransferResponse; 4 | import io.grpc.stub.StreamObserver; 5 | 6 | import java.util.concurrent.CountDownLatch; 7 | 8 | public class TransferStreamingResponse implements StreamObserver { 9 | 10 | private CountDownLatch latch; 11 | 12 | public TransferStreamingResponse(CountDownLatch latch) { 13 | this.latch = latch; 14 | } 15 | 16 | @Override 17 | public void onNext(TransferResponse transferResponse) { 18 | System.out.println("Status : " + transferResponse.getStatus()); 19 | transferResponse.getAccountsList() 20 | .stream() 21 | .map(account -> account.getAccountNumber() + " : " + account.getAmount()) 22 | .forEach(System.out::println); 23 | System.out.println("-------------------------------"); 24 | } 25 | 26 | @Override 27 | public void onError(Throwable throwable) { 28 | this.latch.countDown(); 29 | } 30 | 31 | @Override 32 | public void onCompleted() { 33 | System.out.println( 34 | "All transfers done!" 35 | ); 36 | this.latch.countDown(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /99-old-projects/node-client/bank-client.js: -------------------------------------------------------------------------------- 1 | const grpc = require('grpc') 2 | const protoloader = require('@grpc/proto-loader') 3 | 4 | const packageDef = protoloader.loadSync('proto/bank-service.proto') 5 | const protoDesc = grpc.loadPackageDefinition(packageDef) 6 | 7 | const client = new protoDesc.BankService('localhost:6565', grpc.credentials.createInsecure()) 8 | 9 | client.getBalance({accountNumber: 4}, (err, balance) => { 10 | if(err){ 11 | console.error('something bad happened') 12 | }else{ 13 | console.log('Received : ' + balance.amount) 14 | } 15 | }) -------------------------------------------------------------------------------- /99-old-projects/node-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-client", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@grpc/proto-loader": "^0.5.5", 14 | "grpc": "^1.24.3" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /99-old-projects/node-client/proto/bank-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "com.vinsguru.models"; 5 | 6 | message BalanceCheckRequest { 7 | int32 account_number = 1; 8 | } 9 | 10 | // USD 11 | message Balance { 12 | int32 amount = 1; 13 | } 14 | 15 | service BankService { 16 | rpc getBalance(BalanceCheckRequest) returns (Balance); 17 | } -------------------------------------------------------------------------------- /99-old-projects/protobuf/src/main/java/com/vinsguru/json/JPerson.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.json; 2 | 3 | public class JPerson { 4 | 5 | private String name; 6 | private int age; 7 | 8 | public String getName() { 9 | return name; 10 | } 11 | 12 | public void setName(String name) { 13 | this.name = name; 14 | } 15 | 16 | public int getAge() { 17 | return age; 18 | } 19 | 20 | public void setAge(int age) { 21 | this.age = age; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /99-old-projects/protobuf/src/main/java/com/vinsguru/protobuf/CompositionDemo.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.protobuf; 2 | 3 | import com.vinsguru.models.Address; 4 | import com.vinsguru.models.Car; 5 | import com.vinsguru.models.Person; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | public class CompositionDemo { 11 | 12 | public static void main(String[] args) { 13 | 14 | Address address = Address.newBuilder() 15 | .setPostbox(123) 16 | .setStreet("main street") 17 | .setCity("Atlanta") 18 | .build(); 19 | 20 | Car accord = Car.newBuilder() 21 | .setMake("Honda") 22 | .setModel("Accord") 23 | .setYear(2020) 24 | .build(); 25 | 26 | Car civic = Car.newBuilder() 27 | .setMake("Honda") 28 | .setModel("Civic") 29 | .setYear(2005) 30 | .build(); 31 | 32 | List cars = new ArrayList(); 33 | cars.add(accord); 34 | cars.add(civic); 35 | Person sam = Person.newBuilder() 36 | .setName("sam") 37 | .setAge(25) 38 | .addAllCar(cars) 39 | .setAddress(address) 40 | .build(); 41 | 42 | System.out.println( 43 | sam 44 | ); 45 | 46 | 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /99-old-projects/protobuf/src/main/java/com/vinsguru/protobuf/DefaultValueDemo.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.protobuf; 2 | 3 | import com.vinsguru.models.Person; 4 | 5 | public class DefaultValueDemo { 6 | 7 | public static void main(String[] args) { 8 | 9 | Person person = Person.newBuilder().build(); 10 | 11 | System.out.println( 12 | "City : " + person.getAddress().getCity() 13 | ); 14 | 15 | System.out.println( 16 | person.hasAddress() 17 | ); 18 | 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /99-old-projects/protobuf/src/main/java/com/vinsguru/protobuf/MapDemo.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.protobuf; 2 | 3 | import com.vinsguru.models.BodyStyle; 4 | import com.vinsguru.models.Car; 5 | import com.vinsguru.models.Dealer; 6 | 7 | public class MapDemo { 8 | 9 | public static void main(String[] args) { 10 | 11 | Car accord = Car.newBuilder() 12 | .setMake("Honda") 13 | .setModel("Accord") 14 | .setBodyStyle(BodyStyle.COUPE) 15 | .setYear(2020) 16 | .build(); 17 | 18 | Car civic = Car.newBuilder() 19 | .setMake("Honda") 20 | .setModel("Civic") 21 | .setBodyStyle(BodyStyle.SEDAN) 22 | .setYear(2005) 23 | .build(); 24 | 25 | Dealer dealer = Dealer.newBuilder() 26 | .putModel(2005, civic) 27 | .putModel(2020, accord) 28 | .build(); 29 | 30 | System.out.println( 31 | dealer.getModelOrThrow(2020).getBodyStyle() 32 | ); 33 | 34 | 35 | 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /99-old-projects/protobuf/src/main/java/com/vinsguru/protobuf/OneOfDemo.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.protobuf; 2 | 3 | import com.vinsguru.models.Credentials; 4 | import com.vinsguru.models.EmailCredentials; 5 | import com.vinsguru.models.PhoneOTP; 6 | 7 | public class OneOfDemo { 8 | 9 | public static void main(String[] args) { 10 | 11 | EmailCredentials emailCredentials = EmailCredentials.newBuilder() 12 | .setEmail("nobody@gmail.com") 13 | .setPassword("admin123") 14 | .build(); 15 | 16 | PhoneOTP phoneOTP = PhoneOTP.newBuilder() 17 | .setNumber(1231231234) 18 | .setCode(456) 19 | .build(); 20 | 21 | Credentials credentials = Credentials.newBuilder() 22 | .setEmailMode(emailCredentials) 23 | .setPhoneMode(phoneOTP) 24 | 25 | .build(); 26 | 27 | login(credentials); 28 | } 29 | 30 | private static void login(Credentials credentials){ 31 | switch (credentials.getModeCase()){ 32 | case EMAILMODE -> System.out.println(credentials.getEmailMode()); 33 | case PHONEMODE -> System.out.println(credentials.getPhoneMode()); 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /99-old-projects/protobuf/src/main/java/com/vinsguru/protobuf/PersonDemo.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.protobuf; 2 | 3 | import com.vinsguru.models.Person; 4 | 5 | import java.io.IOException; 6 | import java.nio.file.Files; 7 | import java.nio.file.Path; 8 | import java.nio.file.Paths; 9 | 10 | public class PersonDemo { 11 | 12 | public static void main(String[] args) throws IOException { 13 | 14 | /* Person sam = Person.newBuilder() 15 | .setName("sam") 16 | .setAge(10) 17 | .build(); 18 | */ 19 | Path path = Paths.get("sam.ser"); 20 | // Files.write(path, sam.toByteArray()); 21 | 22 | byte[] bytes = Files.readAllBytes(path); 23 | Person newSam = Person.parseFrom(bytes); 24 | 25 | System.out.println( 26 | newSam 27 | ); 28 | 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /99-old-projects/protobuf/src/main/java/com/vinsguru/protobuf/VersionCompatibilityTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.protobuf; 2 | 3 | import com.vinsguru.models.Television; 4 | //import com.vinsguru.models.Type; 5 | 6 | import java.io.IOException; 7 | import java.nio.file.Files; 8 | import java.nio.file.Path; 9 | import java.nio.file.Paths; 10 | 11 | public class VersionCompatibilityTest { 12 | 13 | public static void main(String[] args) throws IOException { 14 | 15 | Path pathV1 = Paths.get("tv-v1"); 16 | Path pathV2 = Paths.get("tv-v2"); 17 | 18 | /* Television television = Television.newBuilder() 19 | .setBrand("sony") 20 | .setModel(2016) 21 | .setType(Type.OLED) 22 | .build(); 23 | 24 | Files.write(pathV2, television.toByteArray());*/ 25 | 26 | // 27 | byte[] bytes = Files.readAllBytes(pathV1); 28 | System.out.println( 29 | Television.parseFrom(bytes).getPrice() 30 | ); 31 | 32 | 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /99-old-projects/protobuf/src/main/proto/common/address.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package common; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models"; 7 | 8 | message Address { 9 | int32 postbox = 1; 10 | string street = 2; 11 | string city = 3; 12 | } -------------------------------------------------------------------------------- /99-old-projects/protobuf/src/main/proto/common/car.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package common; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models"; 7 | 8 | message Car { 9 | string make = 1; 10 | string model = 2; 11 | int32 year = 3; 12 | BodyStyle body_style = 4; 13 | } 14 | 15 | enum BodyStyle { 16 | UNKNOWN = 0; 17 | SEDAN = 1; 18 | COUPE = 2; 19 | SUV = 3; 20 | } -------------------------------------------------------------------------------- /99-old-projects/protobuf/src/main/proto/credentials.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_multiple_files = true; 4 | option java_package = "com.vinsguru.models"; 5 | 6 | message EmailCredentials { 7 | string email = 1; 8 | string password = 2; 9 | } 10 | 11 | message PhoneOTP { 12 | int32 number = 1; 13 | int32 code = 2; 14 | } 15 | 16 | message Credentials { 17 | oneof mode { 18 | EmailCredentials emailMode = 1; 19 | PhoneOTP phoneMode = 2; 20 | } 21 | } -------------------------------------------------------------------------------- /99-old-projects/protobuf/src/main/proto/dealer.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "common/car.proto"; 4 | 5 | option java_multiple_files = true; 6 | option java_package = "com.vinsguru.models"; 7 | 8 | message Dealer { 9 | map model = 1; 10 | } -------------------------------------------------------------------------------- /99-old-projects/protobuf/src/main/proto/person.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "common/address.proto"; 4 | import "common/car.proto"; 5 | 6 | option java_multiple_files = true; 7 | option java_package = "com.vinsguru.models"; 8 | 9 | message Person { 10 | string name = 1; 11 | int32 age = 2; 12 | common.Address address = 3; 13 | repeated common.Car car = 4; 14 | } -------------------------------------------------------------------------------- /99-old-projects/protobuf/src/main/proto/television.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | import "common/address.proto"; 4 | import "common/car.proto"; 5 | 6 | option java_multiple_files = true; 7 | option java_package = "com.vinsguru.models"; 8 | 9 | // v1 10 | /*message Television { 11 | string brand = 1; 12 | int32 year = 2; 13 | }*/ 14 | 15 | // v2 16 | /* 17 | message Television { 18 | string brand = 1; 19 | int32 model = 2; 20 | Type type = 3; 21 | }*/ 22 | 23 | // v4 24 | message Television { 25 | string brand = 1; 26 | 27 | reserved 2; 28 | reserved "year", "model"; 29 | 30 | int32 price = 4; 31 | Type type = 3; 32 | } 33 | 34 | enum Type { 35 | HD = 0; 36 | UHD = 1; 37 | OLED = 2; 38 | } -------------------------------------------------------------------------------- /99-old-projects/snakes-ladders/src/main/java/com/vinsguru/game/server/GameService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.game.server; 2 | 3 | import com.vinsguru.game.Die; 4 | import com.vinsguru.game.GameServiceGrpc; 5 | import com.vinsguru.game.GameState; 6 | import com.vinsguru.game.Player; 7 | import io.grpc.stub.StreamObserver; 8 | 9 | public class GameService extends GameServiceGrpc.GameServiceImplBase { 10 | 11 | @Override 12 | public StreamObserver roll(StreamObserver responseObserver) { 13 | Player client = Player.newBuilder().setName("client").setPosition(0).build(); 14 | Player server = Player.newBuilder().setName("server").setPosition(0).build(); 15 | return new DieStreamingRequest(client, server, responseObserver); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /99-old-projects/snakes-ladders/src/main/java/com/vinsguru/game/server/GrpcServer.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.game.server; 2 | 3 | import io.grpc.Server; 4 | import io.grpc.ServerBuilder; 5 | 6 | import java.io.IOException; 7 | import java.util.concurrent.Executors; 8 | 9 | public class GrpcServer { 10 | 11 | public static void main(String[] args) throws IOException, InterruptedException { 12 | 13 | Server server = ServerBuilder.forPort(6565) 14 | .executor(Executors.newFixedThreadPool(20)) 15 | .addService(new GameService()) 16 | .build(); 17 | 18 | server.start(); 19 | 20 | server.awaitTermination(); 21 | 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /99-old-projects/snakes-ladders/src/main/java/com/vinsguru/game/server/SnakesAndLaddersMap.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.game.server; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class SnakesAndLaddersMap { 7 | private static final Map MAP = new HashMap<>(); 8 | 9 | static{ 10 | // ladders 11 | MAP.put(1, 38); 12 | MAP.put(4, 14); 13 | MAP.put(8, 30); 14 | MAP.put(21, 42); 15 | MAP.put(28, 76); 16 | MAP.put(50, 67); 17 | MAP.put(71, 92); 18 | MAP.put(80, 99); 19 | //snakes 20 | MAP.put(32, 10); 21 | MAP.put(36, 6); 22 | MAP.put(48, 26); 23 | MAP.put(62, 18); 24 | MAP.put(88, 24); 25 | MAP.put(95, 56); 26 | MAP.put(97, 78); 27 | } 28 | 29 | public static int getPosition(int position){ 30 | return MAP.getOrDefault(position, position); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /99-old-projects/snakes-ladders/src/main/proto/game-service.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | option java_package = "com.vinsguru.game"; 4 | option java_multiple_files = true; 5 | 6 | message Die { 7 | int32 value = 1; 8 | } 9 | 10 | message Player { 11 | string name = 1; 12 | int32 position = 2; 13 | } 14 | 15 | message GameState{ 16 | repeated Player player = 1; 17 | } 18 | 19 | service GameService{ 20 | rpc roll(stream Die) returns (stream GameState); 21 | } -------------------------------------------------------------------------------- /99-old-projects/snakes-ladders/src/test/java/com/vinsguru/game/client/GameClientTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.game.client; 2 | 3 | import com.vinsguru.game.Die; 4 | import com.vinsguru.game.GameServiceGrpc; 5 | import io.grpc.ManagedChannel; 6 | import io.grpc.ManagedChannelBuilder; 7 | import io.grpc.stub.StreamObserver; 8 | import org.junit.jupiter.api.BeforeAll; 9 | import org.junit.jupiter.api.Test; 10 | import org.junit.jupiter.api.TestInstance; 11 | 12 | import java.util.concurrent.CountDownLatch; 13 | 14 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 15 | public class GameClientTest { 16 | 17 | private GameServiceGrpc.GameServiceStub stub; 18 | 19 | @BeforeAll 20 | public void setup(){ 21 | ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 6565) 22 | .usePlaintext() 23 | .build(); 24 | this.stub = GameServiceGrpc.newStub(channel); 25 | } 26 | 27 | @Test 28 | public void clientGame() throws InterruptedException { 29 | CountDownLatch latch = new CountDownLatch(1); 30 | GameStateStreamingResponse gameStateStreamingResponse = new GameStateStreamingResponse(latch); 31 | StreamObserver dieStreamObserver = this.stub.roll(gameStateStreamingResponse); 32 | gameStateStreamingResponse.setDieStreamObserver(dieStreamObserver); 33 | gameStateStreamingResponse.roll(); 34 | latch.await(); 35 | } 36 | 37 | 38 | 39 | } 40 | --------------------------------------------------------------------------------