├── .doc └── java-reactive-programming.png ├── .gitignore ├── 01-reactive-programming-playground ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── vinsguru │ │ │ ├── common │ │ │ ├── AbstractHttpClient.java │ │ │ ├── DefaultSubscriber.java │ │ │ └── Util.java │ │ │ ├── sec01 │ │ │ ├── Demo.java │ │ │ ├── publisher │ │ │ │ ├── PublisherImpl.java │ │ │ │ └── SubscriptionImpl.java │ │ │ └── subscriber │ │ │ │ └── SubscriberImpl.java │ │ │ ├── sec02 │ │ │ ├── Lec01LazyStream.java │ │ │ ├── Lec02MonoJust.java │ │ │ ├── Lec03MonoSubscribe.java │ │ │ ├── Lec04MonoEmptyError.java │ │ │ ├── Lec05MonoFromSupplier.java │ │ │ ├── Lec06MonoFromCallable.java │ │ │ ├── Lec07MonoFromRunnable.java │ │ │ ├── Lec08MonoFromFuture.java │ │ │ ├── Lec09PublisherCreateVsExecution.java │ │ │ ├── Lec10MonoDefer.java │ │ │ ├── Lec11NonBlockingIO.java │ │ │ ├── Lec12Assignment.java │ │ │ ├── assignment │ │ │ │ ├── FileService.java │ │ │ │ └── FileServiceImpl.java │ │ │ └── client │ │ │ │ └── ExternalServiceClient.java │ │ │ ├── sec03 │ │ │ ├── Lec01FluxJust.java │ │ │ ├── Lec02MultipleSubscribers.java │ │ │ ├── Lec03FluxFromIterableOrArray.java │ │ │ ├── Lec04FluxFromStream.java │ │ │ ├── Lec05FluxRange.java │ │ │ ├── Lec06Log.java │ │ │ ├── Lec07FluxVsList.java │ │ │ ├── Lec08NonBlockingStreamingMessages.java │ │ │ ├── Lec09FluxInterval.java │ │ │ ├── Lec10FluxEmptyError.java │ │ │ ├── Lec11FluxMono.java │ │ │ ├── Lec12Assignment.java │ │ │ ├── assignment │ │ │ │ └── StockPriceObserver.java │ │ │ ├── client │ │ │ │ └── ExternalServiceClient.java │ │ │ └── helper │ │ │ │ └── NameGenerator.java │ │ │ ├── sec04 │ │ │ ├── Lec01FluxCreate.java │ │ │ ├── Lec02FluxCreateRefactor.java │ │ │ ├── Lec03FluxSinkThreadSafety.java │ │ │ ├── Lec04FluxCreateDownstreamDemand.java │ │ │ ├── Lec05TakeOperator.java │ │ │ ├── Lec06FluxGenerate.java │ │ │ ├── Lec07FluxGenerateUntil.java │ │ │ ├── Lec08GenerateWithState.java │ │ │ ├── Lec09Assignment.java │ │ │ ├── assignment │ │ │ │ ├── FileReaderService.java │ │ │ │ └── FileReaderServiceImpl.java │ │ │ └── helper │ │ │ │ └── NameGenerator.java │ │ │ ├── sec05 │ │ │ ├── Lec01Handle.java │ │ │ ├── Lec02HandleUntilAssignment.java │ │ │ ├── Lec03DoCallbacks.java │ │ │ ├── Lec04Delay.java │ │ │ ├── Lec05Subscribe.java │ │ │ ├── Lec06ErrorHandling.java │ │ │ ├── Lec07DefaultIfEmpty.java │ │ │ ├── Lec08SwitchIfEmpty.java │ │ │ ├── Lec09Timeout.java │ │ │ ├── Lec10Transform.java │ │ │ ├── Lec11Assignment.java │ │ │ └── assignment │ │ │ │ └── ExternalServiceClient.java │ │ │ ├── sec06 │ │ │ ├── Lec01ColdPublisher.java │ │ │ ├── Lec02HotPublisher.java │ │ │ ├── Lec03HotPublisherAutoConnect.java │ │ │ ├── Lec04HotPublisherCache.java │ │ │ ├── Lec05FluxCreateIssueFix.java │ │ │ ├── Lec06Assignment.java │ │ │ └── assignment │ │ │ │ ├── ExternalServiceClient.java │ │ │ │ ├── InventoryService.java │ │ │ │ ├── Order.java │ │ │ │ ├── OrderProcessor.java │ │ │ │ └── RevenueService.java │ │ │ ├── sec07 │ │ │ ├── Lec01DefaultBehaviorDemo.java │ │ │ ├── Lec02SubscribeOn.java │ │ │ ├── Lec03MultipleSubscribeOn.java │ │ │ ├── Lec04VirtualThreads.java │ │ │ ├── Lec05BackPressureStrategies.java │ │ │ ├── Lec05PublishOn.java │ │ │ ├── Lec06EventLoopIssueFix.java │ │ │ ├── Lec07PublishOnSubscribeOn.java │ │ │ ├── Lec08Parallel.java │ │ │ └── client │ │ │ │ └── ExternalServiceClient.java │ │ │ ├── sec08 │ │ │ ├── Lec01BackPressureHandling.java │ │ │ ├── Lec02LimitRate.java │ │ │ ├── Lec03MultipleSubscribers.java │ │ │ ├── Lec04FluxCreate.java │ │ │ └── Lec05BackPressureStrategies.java │ │ │ ├── sec09 │ │ │ ├── Lec01StartWith.java │ │ │ ├── Lec02StartWithUseCase.java │ │ │ ├── Lec03ConcatWith.java │ │ │ ├── Lec04ConcatError.java │ │ │ ├── Lec05Merge.java │ │ │ ├── Lec06MergeUseCase.java │ │ │ ├── Lec07Zip.java │ │ │ ├── Lec08ZipAssignment.java │ │ │ ├── Lec09MonoFlatMap.java │ │ │ ├── Lec10MonoFlatMapMany.java │ │ │ ├── Lec11FluxFlatMap.java │ │ │ ├── Lec12FluxFlatMapAssignment.java │ │ │ ├── Lec13ConcatMap.java │ │ │ ├── Lec14CollectList.java │ │ │ ├── Lec15Then.java │ │ │ ├── Lec16Assignment.java │ │ │ ├── applications │ │ │ │ ├── Order.java │ │ │ │ ├── OrderService.java │ │ │ │ ├── PaymentService.java │ │ │ │ ├── User.java │ │ │ │ └── UserService.java │ │ │ ├── assignment │ │ │ │ ├── ExternalServiceClient.java │ │ │ │ └── Product.java │ │ │ └── helper │ │ │ │ ├── AmericanAirlines.java │ │ │ │ ├── Emirates.java │ │ │ │ ├── Flight.java │ │ │ │ ├── Kayak.java │ │ │ │ ├── NameGenerator.java │ │ │ │ └── Qatar.java │ │ │ ├── sec10 │ │ │ ├── Lec01Buffer.java │ │ │ ├── Lec02BufferAssignment.java │ │ │ ├── Lec03Window.java │ │ │ ├── Lec04WindowAssignment.java │ │ │ ├── Lec05GroupedFlux.java │ │ │ ├── Lec06GroupByAssignment.java │ │ │ └── assignment │ │ │ │ ├── buffer │ │ │ │ ├── BookOrder.java │ │ │ │ └── RevenueReport.java │ │ │ │ ├── groupby │ │ │ │ ├── OrderProcessingService.java │ │ │ │ └── PurchaseOrder.java │ │ │ │ └── window │ │ │ │ └── FileWriter.java │ │ │ ├── sec11 │ │ │ ├── Lec01Repeat.java │ │ │ ├── Lec02Retry.java │ │ │ ├── Lec03ExternalServiceDemo.java │ │ │ └── client │ │ │ │ ├── ClientError.java │ │ │ │ ├── ExternalServiceClient.java │ │ │ │ └── ServerError.java │ │ │ ├── sec12 │ │ │ ├── Lec01SinkOne.java │ │ │ ├── Lec02SinkUnicast.java │ │ │ ├── Lec03SinkThreadSafety.java │ │ │ ├── Lec04Multicast.java │ │ │ ├── Lec05MulticastDirectBestEffort.java │ │ │ ├── Lec06MulticastDirectAllOrNothing.java │ │ │ ├── Lec07Replay.java │ │ │ ├── Lec08SlackAssignment.java │ │ │ └── assignment │ │ │ │ ├── SlackMember.java │ │ │ │ ├── SlackMessage.java │ │ │ │ └── SlackRoom.java │ │ │ └── sec13 │ │ │ ├── Lec01Context.java │ │ │ ├── Lec02ContextAppendUpdate.java │ │ │ ├── Lec03ContextPropagation.java │ │ │ ├── Lec04ContextRateLimiterDemo.java │ │ │ └── client │ │ │ ├── ExternalServiceClient.java │ │ │ ├── RateLimiter.java │ │ │ └── UserService.java │ └── resources │ │ ├── logback.xml │ │ └── sec04 │ │ └── file.txt │ └── test │ └── java │ └── com │ └── vinsguru │ └── tests │ ├── Lec01MonoTest.java │ ├── Lec02EmptyErrorTest.java │ ├── Lec03FluxTest.java │ ├── Lec04RangeTest.java │ ├── Lec05AssertNextTest.java │ ├── Lec06VirtualTimeTest.java │ ├── Lec07ScenarioNameTest.java │ ├── Lec08ContextTest.java │ ├── Lec09PublisherTest.java │ └── Lec10TimeoutTest.java ├── 02-external-services ├── external-services-instructions.md └── external-services.jar ├── 03-old-content ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── rp │ │ │ ├── courseutil │ │ │ ├── DefaultSubscriber.java │ │ │ └── Util.java │ │ │ ├── sec01 │ │ │ ├── Lec01Stream.java │ │ │ ├── Lec02MonoJust.java │ │ │ ├── Lec03MonoSubscribe.java │ │ │ ├── Lec04MonoEmptyOrError.java │ │ │ ├── Lec05MonoFromSupplier.java │ │ │ ├── Lec06SupplierRefactoring.java │ │ │ ├── Lec07MonoFromFuture.java │ │ │ ├── Lec08MonoFromRunnable.java │ │ │ ├── Lec09AssignmentDemo.java │ │ │ └── assignment │ │ │ │ └── FileService.java │ │ │ ├── sec02 │ │ │ ├── Lec01FluxIntro.java │ │ │ ├── Lec02MultipleSubscribers.java │ │ │ ├── Lec03FluxFromArrayOrList.java │ │ │ ├── Lec04FluxFromStream.java │ │ │ ├── Lec05FluxRange.java │ │ │ ├── Lec06Subscription.java │ │ │ ├── Lec07FluxVsList.java │ │ │ ├── Lec08FluxInterval.java │ │ │ ├── Lec09FluxFromMono.java │ │ │ ├── Lec10StockPriceAssignment.java │ │ │ ├── assignment │ │ │ │ └── StockPricePublisher.java │ │ │ └── helper │ │ │ │ └── NameGenerator.java │ │ │ ├── sec03 │ │ │ ├── Lec01FluxCreate.java │ │ │ ├── Lec02FluxCreateRefactoring.java │ │ │ ├── Lec03FluxTake.java │ │ │ ├── Lec04FluxCreateIssueFix.java │ │ │ ├── Lec05FluxGenerate.java │ │ │ ├── Lec06FluxGenerateAssignment.java │ │ │ ├── Lec07FluxGenerateCounter.java │ │ │ ├── Lec08FluxPush.java │ │ │ ├── Lec09FileReaderServiceAssignment.java │ │ │ ├── assignment │ │ │ │ └── FileReaderService.java │ │ │ └── helper │ │ │ │ └── NameProducer.java │ │ │ ├── sec04 │ │ │ ├── Lec01Handle.java │ │ │ ├── Lec02HandleAssignment.java │ │ │ ├── Lec03DoCallbacks.java │ │ │ ├── Lec04LimitRate.java │ │ │ ├── Lec05Delay.java │ │ │ ├── Lec06OnError.java │ │ │ ├── Lec07Timeout.java │ │ │ ├── Lec08DefaultIfEmpty.java │ │ │ ├── Lec09SwitchIfEmpty.java │ │ │ ├── Lec10Transform.java │ │ │ ├── Lec11SwitchOnFirst.java │ │ │ ├── Lec12FlatMap.java │ │ │ └── helper │ │ │ │ ├── OrderService.java │ │ │ │ ├── Person.java │ │ │ │ ├── PurchaseOrder.java │ │ │ │ ├── User.java │ │ │ │ └── UserService.java │ │ │ ├── sec05 │ │ │ ├── Lec01ColdPublisher.java │ │ │ ├── Lec02HotShare.java │ │ │ ├── Lec03HotPublish.java │ │ │ ├── Lec04HotPublishAutoConnect.java │ │ │ ├── Lec05HotPublishCache.java │ │ │ ├── Lec06Assignment.java │ │ │ └── assignment │ │ │ │ ├── InventoryService.java │ │ │ │ ├── OrderService.java │ │ │ │ ├── PurchaseOrder.java │ │ │ │ └── RevenueService.java │ │ │ ├── sec06 │ │ │ ├── Lec01ThreadDemo.java │ │ │ ├── Lec02SubscribeOnDemo.java │ │ │ ├── Lec03SubscribeOnMultipleItems.java │ │ │ ├── Lec04PublishOn.java │ │ │ ├── Lec05PubSubOn.java │ │ │ ├── Lec06Parallel.java │ │ │ └── Lec07FluxInterval.java │ │ │ ├── sec07 │ │ │ ├── Lec01Demo.java │ │ │ ├── Lec02Drop.java │ │ │ ├── Lec03Latest.java │ │ │ ├── Lec04Error.java │ │ │ └── Lec05BufferWithSize.java │ │ │ ├── sec08 │ │ │ ├── Lec01StartWith.java │ │ │ ├── Lec02Concat.java │ │ │ ├── Lec03Merge.java │ │ │ ├── Lec04Zip.java │ │ │ ├── Lec05CombineLatest.java │ │ │ ├── Lec06Assignment.java │ │ │ └── helper │ │ │ │ ├── AmericanAirlines.java │ │ │ │ ├── Emirates.java │ │ │ │ ├── NameGenerator.java │ │ │ │ └── Qatar.java │ │ │ ├── sec09 │ │ │ ├── Lec01Buffer.java │ │ │ ├── Lec02OverlapAndDrop.java │ │ │ ├── Lec03Assignment.java │ │ │ ├── Lec04Window.java │ │ │ ├── Lec05Group.java │ │ │ ├── Lec06Assignment.java │ │ │ ├── assignment │ │ │ │ ├── OrderProcessor.java │ │ │ │ ├── OrderService.java │ │ │ │ └── PurchaseOrder.java │ │ │ └── helper │ │ │ │ ├── BookOrder.java │ │ │ │ └── RevenueReport.java │ │ │ ├── sec10 │ │ │ ├── Lec01Repeat.java │ │ │ ├── Lec02Retry.java │ │ │ ├── Lec03RetryWhen.java │ │ │ └── Lec04RetryWhenAdvanced.java │ │ │ ├── sec11 │ │ │ ├── Lec01SinkOne.java │ │ │ ├── Lec02SinkUnicast.java │ │ │ ├── Lec03SinkThreadSafety.java │ │ │ ├── Lec04SinkMulti.java │ │ │ ├── Lec05SinkMultiDirectAll.java │ │ │ ├── Lec06SinkReplay.java │ │ │ ├── Lec07SlackDemo.java │ │ │ └── assignment │ │ │ │ ├── SlackMember.java │ │ │ │ ├── SlackMessage.java │ │ │ │ └── SlackRoom.java │ │ │ ├── sec12 │ │ │ ├── Lec01Ctx.java │ │ │ ├── Lec02CtxRateLimiterDemo.java │ │ │ └── helper │ │ │ │ ├── BookService.java │ │ │ │ └── UserService.java │ │ │ └── sec13 │ │ │ └── Lec01Checkpoint.java │ └── resources │ │ └── assignment │ │ ├── sec01 │ │ ├── file01.txt │ │ └── file02.txt │ │ └── sec03 │ │ └── file01.txt │ └── test │ └── java │ └── com │ └── rp │ └── test │ ├── Lec01SVDemoTest.java │ ├── Lec02SVErrorTest.java │ ├── Lec03SVRangeTest.java │ ├── Lec04AssertTest.java │ ├── Lec05VirtualTimeTest.java │ ├── Lec06ScenarioNameTest.java │ ├── Lec07CtxTest.java │ └── PublisherTest.java └── README.md /.doc/java-reactive-programming.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinsguru/java-reactive-programming-course/054d932072a2982c72f26045a6539b84660cb270/.doc/java-reactive-programming.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 | !02-external-services/external-services.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 | **/.DS_STORE 43 | 44 | **/HELP.md 45 | **/.mvn/ 46 | **/mvnw 47 | **/mvnw.cmd 48 | **/node_modules/ 49 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/common/AbstractHttpClient.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.common; 2 | 3 | import reactor.netty.http.client.HttpClient; 4 | import reactor.netty.resources.LoopResources; 5 | 6 | public abstract class AbstractHttpClient { 7 | 8 | private static final String BASE_URL = "http://localhost:7070"; 9 | protected final HttpClient httpClient; 10 | 11 | public AbstractHttpClient() { 12 | var loopResources = LoopResources.create("vins", 1, true); 13 | this.httpClient = HttpClient.create().runOn(loopResources).baseUrl(BASE_URL); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/common/DefaultSubscriber.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.common; 2 | 3 | import org.reactivestreams.Subscriber; 4 | import org.reactivestreams.Subscription; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | public class DefaultSubscriber implements Subscriber { 9 | 10 | private static final Logger log = LoggerFactory.getLogger(DefaultSubscriber.class); 11 | private final String name; 12 | 13 | public DefaultSubscriber(String name) { 14 | this.name = name; 15 | } 16 | 17 | @Override 18 | public void onSubscribe(Subscription subscription) { 19 | subscription.request(Long.MAX_VALUE); 20 | } 21 | 22 | @Override 23 | public void onNext(T item) { 24 | log.info("{} received: {}", this.name, item); 25 | } 26 | 27 | @Override 28 | public void onError(Throwable throwable) { 29 | log.error("{} error", this.name, throwable); 30 | } 31 | 32 | @Override 33 | public void onComplete() { 34 | log.info("{} received complete!", this.name); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec01/publisher/PublisherImpl.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec01.publisher; 2 | 3 | import org.reactivestreams.Publisher; 4 | import org.reactivestreams.Subscriber; 5 | 6 | public class PublisherImpl implements Publisher { 7 | 8 | @Override 9 | public void subscribe(Subscriber subscriber) { 10 | var subscription = new SubscriptionImpl(subscriber); 11 | subscriber.onSubscribe(subscription); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec01/subscriber/SubscriberImpl.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec01.subscriber; 2 | 3 | import org.reactivestreams.Subscriber; 4 | import org.reactivestreams.Subscription; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | public class SubscriberImpl implements Subscriber { 9 | 10 | private static final Logger log = LoggerFactory.getLogger(SubscriberImpl.class); 11 | private Subscription subscription; 12 | 13 | public Subscription getSubscription() { 14 | return subscription; 15 | } 16 | 17 | @Override 18 | public void onSubscribe(Subscription subscription) { 19 | this.subscription = subscription; 20 | } 21 | 22 | @Override 23 | public void onNext(String email) { 24 | log.info("received: {}", email); 25 | } 26 | 27 | @Override 28 | public void onError(Throwable throwable) { 29 | log.error("error", throwable); 30 | } 31 | 32 | @Override 33 | public void onComplete() { 34 | log.info("completed!"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/Lec01LazyStream.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.util.stream.Stream; 7 | 8 | /* 9 | If we do not have the terminal operator, then stream operators will not execute 10 | */ 11 | public class Lec01LazyStream { 12 | 13 | private static final Logger log = LoggerFactory.getLogger(Lec01LazyStream.class); 14 | 15 | public static void main(String[] args) { 16 | 17 | Stream.of(1) 18 | .peek(i -> log.info("received : {}", i)) 19 | .toList(); 20 | 21 | 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/Lec02MonoJust.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02; 2 | 3 | import com.vinsguru.sec01.subscriber.SubscriberImpl; 4 | import reactor.core.publisher.Mono; 5 | 6 | /* 7 | Use just when the value to be emitted is already in the memory 8 | */ 9 | 10 | public class Lec02MonoJust { 11 | 12 | public static void main(String[] args) { 13 | 14 | var mono = Mono.just("vins"); 15 | var subscriber = new SubscriberImpl(); 16 | mono.subscribe(subscriber); 17 | 18 | subscriber.getSubscription().request(10); 19 | 20 | // adding these will have no effect as producer already sent complete 21 | subscriber.getSubscription().request(10); 22 | subscriber.getSubscription().cancel(); 23 | 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/Lec03MonoSubscribe.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import reactor.core.publisher.Mono; 6 | 7 | /* 8 | To discuss some of the subscribe overloaded methods 9 | */ 10 | public class Lec03MonoSubscribe { 11 | 12 | private static final Logger log = LoggerFactory.getLogger(Lec03MonoSubscribe.class); 13 | 14 | public static void main(String[] args) { 15 | 16 | var mono = Mono.just(1); 17 | 18 | mono.subscribe( 19 | i -> log.info("received: {}", i), 20 | err -> log.error("error", err), 21 | () -> log.info("completed"), 22 | subscription -> subscription.request(1) 23 | ); 24 | 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/Lec04MonoEmptyError.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02; 2 | 3 | /* 4 | Emitting empty / error 5 | */ 6 | 7 | import com.vinsguru.common.Util; 8 | import reactor.core.publisher.Mono; 9 | 10 | public class Lec04MonoEmptyError { 11 | 12 | public static void main(String[] args) { 13 | 14 | getUsername(3) 15 | .subscribe(Util.subscriber()); 16 | 17 | } 18 | 19 | private static Mono getUsername(int userId){ 20 | return switch (userId){ 21 | case 1 -> Mono.just("sam"); 22 | case 2 -> Mono.empty(); // null 23 | default -> Mono.error(new RuntimeException("invalid input")); 24 | }; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/Lec05MonoFromSupplier.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Mono; 7 | 8 | import java.util.List; 9 | 10 | /* 11 | To delay the execution using supplier / callable 12 | */ 13 | public class Lec05MonoFromSupplier { 14 | 15 | private static final Logger log = LoggerFactory.getLogger(Lec05MonoFromSupplier.class); 16 | 17 | public static void main(String[] args) { 18 | 19 | var list = List.of(1, 2, 3); 20 | Mono.fromSupplier(() -> sum(list)) 21 | .subscribe(Util.subscriber()); 22 | 23 | } 24 | 25 | private static int sum(List list) { 26 | log.info("finding the sum of {}", list); 27 | return list.stream().mapToInt(a -> a).sum(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/Lec06MonoFromCallable.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Mono; 7 | 8 | import java.util.List; 9 | 10 | /* 11 | To delay the execution using supplier / callable 12 | */ 13 | public class Lec06MonoFromCallable { 14 | 15 | private static final Logger log = LoggerFactory.getLogger(Lec06MonoFromCallable.class); 16 | 17 | public static void main(String[] args) { 18 | 19 | var list = List.of(1, 2, 3); 20 | Mono.fromCallable(() -> sum(list)) 21 | .subscribe(Util.subscriber()); 22 | 23 | } 24 | 25 | private static int sum(List list) throws Exception { 26 | log.info("finding the sum of {}", list); 27 | return list.stream().mapToInt(a -> a).sum(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/Lec07MonoFromRunnable.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Mono; 7 | 8 | /* 9 | Emitting empty after some method invocation 10 | */ 11 | public class Lec07MonoFromRunnable { 12 | 13 | private static final Logger log = LoggerFactory.getLogger(Lec07MonoFromRunnable.class); 14 | 15 | public static void main(String[] args) { 16 | 17 | getProductName(2) 18 | .subscribe(Util.subscriber()); 19 | 20 | } 21 | 22 | private static Mono getProductName(int productId){ 23 | if(productId == 1){ 24 | return Mono.fromSupplier(() -> Util.faker().commerce().productName()); 25 | } 26 | return Mono.fromRunnable(() -> notifyBusiness(productId)); 27 | } 28 | 29 | private static void notifyBusiness(int productId){ 30 | log.info("notifying business on unavailable product {}", productId); 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/Lec08MonoFromFuture.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Mono; 7 | 8 | import java.util.concurrent.CompletableFuture; 9 | 10 | /* 11 | If you have a CompletableFuture already, then we can convert that into a Mono 12 | */ 13 | public class Lec08MonoFromFuture { 14 | 15 | private static final Logger log = LoggerFactory.getLogger(Lec08MonoFromFuture.class); 16 | 17 | public static void main(String[] args) { 18 | 19 | Mono.fromFuture(Lec08MonoFromFuture::getName) 20 | .subscribe(Util.subscriber()); 21 | 22 | Util.sleepSeconds(1); 23 | } 24 | 25 | private static CompletableFuture getName(){ 26 | return CompletableFuture.supplyAsync(() -> { 27 | log.info("generating name"); 28 | return Util.faker().name().firstName(); 29 | }); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/Lec09PublisherCreateVsExecution.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Mono; 7 | 8 | /* 9 | Creating publisher is a lightweight operation. 10 | Executing time-consuming business logic can be delayed 11 | */ 12 | 13 | public class Lec09PublisherCreateVsExecution { 14 | 15 | private static final Logger log = LoggerFactory.getLogger(Lec09PublisherCreateVsExecution.class); 16 | 17 | public static void main(String[] args) { 18 | 19 | getName() 20 | .subscribe(Util.subscriber()); 21 | 22 | } 23 | 24 | private static Mono getName(){ 25 | log.info("entered the method"); 26 | return Mono.fromSupplier(() -> { 27 | log.info("generating name"); 28 | Util.sleepSeconds(3); 29 | return Util.faker().name().firstName(); 30 | }); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/Lec10MonoDefer.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02; 2 | 3 | /* 4 | To delay the publisher creation 5 | */ 6 | 7 | import com.vinsguru.common.Util; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import reactor.core.publisher.Mono; 11 | 12 | import java.util.List; 13 | 14 | public class Lec10MonoDefer { 15 | 16 | private static final Logger log = LoggerFactory.getLogger(Lec10MonoDefer.class); 17 | 18 | public static void main(String[] args) { 19 | 20 | Mono.defer(Lec10MonoDefer::createPublisher) 21 | .subscribe(Util.subscriber()); 22 | 23 | } 24 | 25 | // time-consuming publisher creation 26 | private static Mono createPublisher(){ 27 | log.info("creating publisher"); 28 | var list = List.of(1, 2, 3); 29 | Util.sleepSeconds(1); 30 | return Mono.fromSupplier(() -> sum(list)); 31 | } 32 | 33 | // time-consuming business logic 34 | private static int sum(List list) { 35 | log.info("finding the sum of {}", list); 36 | Util.sleepSeconds(3); 37 | return list.stream().mapToInt(a -> a).sum(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/Lec11NonBlockingIO.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec02.client.ExternalServiceClient; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | 8 | /* 9 | To demo non-blocking IO 10 | Ensure that the external service is up and running! 11 | */ 12 | public class Lec11NonBlockingIO { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(Lec11NonBlockingIO.class); 15 | 16 | public static void main(String[] args) { 17 | 18 | var client = new ExternalServiceClient(); 19 | 20 | log.info("starting"); 21 | 22 | for (int i = 1; i <= 100; i++) { 23 | client.getProductName(i) 24 | .subscribe(Util.subscriber()); 25 | } 26 | 27 | Util.sleepSeconds(2); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/Lec12Assignment.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec02.assignment.FileServiceImpl; 5 | 6 | public class Lec12Assignment { 7 | 8 | public static void main(String[] args) { 9 | 10 | var fileService = new FileServiceImpl(); 11 | 12 | fileService.write("file.txt", "This is a test file") 13 | .subscribe(Util.subscriber()); 14 | 15 | fileService.read("file.txt") 16 | .subscribe(Util.subscriber()); 17 | 18 | fileService.delete("file.txt") 19 | .subscribe(Util.subscriber()); 20 | 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/assignment/FileService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02.assignment; 2 | 3 | import reactor.core.publisher.Mono; 4 | 5 | public interface FileService { 6 | 7 | Mono read(String fileName); 8 | 9 | Mono write(String fileName, String content); 10 | 11 | Mono delete(String fileName); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec02/client/ExternalServiceClient.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec02.client; 2 | 3 | import com.vinsguru.common.AbstractHttpClient; 4 | import reactor.core.publisher.Mono; 5 | 6 | public class ExternalServiceClient extends AbstractHttpClient { 7 | 8 | public Mono getProductName(int productId) { 9 | return this.httpClient.get() 10 | .uri("/demo01/product/" + productId) 11 | .responseContent() 12 | .asString() 13 | .next(); 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/Lec01FluxJust.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | /* 7 | To create a Flux with arbitrary items in memory 8 | */ 9 | public class Lec01FluxJust { 10 | 11 | 12 | public static void main(String[] args) { 13 | 14 | Flux.just(1, 2, 3, "sam") 15 | .subscribe(Util.subscriber()); 16 | 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/Lec02MultipleSubscribers.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | /* 7 | To demo filter / map operators 8 | */ 9 | public class Lec02MultipleSubscribers { 10 | 11 | 12 | public static void main(String[] args) { 13 | 14 | var flux = Flux.just(1,2,3,4,5,6); 15 | 16 | flux.subscribe(Util.subscriber("sub1")); 17 | flux.filter(i -> i > 7) 18 | .subscribe(Util.subscriber("sub2")); 19 | flux 20 | .filter(i -> i % 2 == 0) 21 | .map(i -> i + "a") 22 | .subscribe(Util.subscriber("sub3")); 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/Lec03FluxFromIterableOrArray.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.util.List; 7 | 8 | /* 9 | To create flux from iterable or array 10 | */ 11 | public class Lec03FluxFromIterableOrArray { 12 | 13 | public static void main(String[] args) { 14 | 15 | var list = List.of("a", "b", "c"); 16 | Flux.fromIterable(list) 17 | .subscribe(Util.subscriber()); 18 | 19 | Integer[] arr = {1,2,3,4,5,6}; 20 | Flux.fromArray(arr) 21 | .subscribe(Util.subscriber()); 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/Lec04FluxFromStream.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.util.List; 7 | 8 | /* 9 | To create flux from stream 10 | */ 11 | public class Lec04FluxFromStream { 12 | 13 | public static void main(String[] args) { 14 | 15 | var list = List.of(1,2,3,4); 16 | var stream = list.stream(); 17 | 18 | // stream.forEach(System.out::println); 19 | // stream.forEach(System.out::println); 20 | 21 | var flux = Flux.fromStream(list::stream); 22 | 23 | flux.subscribe(Util.subscriber("sub1")); 24 | flux.subscribe(Util.subscriber("sub2")); 25 | 26 | 27 | 28 | 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/Lec05FluxRange.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | /* 7 | To create a range of items based on the given start and count 8 | */ 9 | public class Lec05FluxRange { 10 | 11 | public static void main(String[] args) { 12 | 13 | Flux.range(3, 10) 14 | .subscribe(Util.subscriber()); 15 | 16 | // assignment - generate 10 random first names 17 | Flux.range(1, 10) 18 | .map(i -> Util.faker().name().firstName()) 19 | .subscribe(Util.subscriber()); 20 | 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/Lec06Log.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec06Log { 7 | 8 | public static void main(String[] args) { 9 | 10 | 11 | Flux.range(1, 5) 12 | .log() 13 | .map(i -> Util.faker().name().firstName()) 14 | .log() 15 | .subscribe(Util.subscriber()); 16 | 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/Lec07FluxVsList.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.sec01.subscriber.SubscriberImpl; 4 | import com.vinsguru.sec03.helper.NameGenerator; 5 | 6 | public class Lec07FluxVsList { 7 | 8 | public static void main(String[] args) { 9 | 10 | // var list = NameGenerator.getNamesList(10); 11 | // System.out.println(list); 12 | 13 | var subscriber = new SubscriberImpl(); 14 | NameGenerator.getNamesFlux(10) 15 | .subscribe(subscriber); 16 | 17 | subscriber.getSubscription().request(3); 18 | subscriber.getSubscription().cancel(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/Lec08NonBlockingStreamingMessages.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec03.client.ExternalServiceClient; 5 | 6 | /* 7 | To demo non-blocking IO with streaming messages 8 | Ensure that the external service is up and running! 9 | */ 10 | public class Lec08NonBlockingStreamingMessages { 11 | 12 | public static void main(String[] args) { 13 | 14 | var client = new ExternalServiceClient(); 15 | 16 | client.getNames() 17 | .subscribe(Util.subscriber("sub1")); 18 | 19 | client.getNames() 20 | .subscribe(Util.subscriber("sub2")); 21 | 22 | Util.sleepSeconds(6); 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/Lec09FluxInterval.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | /* 9 | To emit a message based on the given interval 10 | */ 11 | public class Lec09FluxInterval { 12 | 13 | public static void main(String[] args) { 14 | 15 | Flux.interval(Duration.ofMillis(500)) 16 | .map(i -> Util.faker().name().firstName()) 17 | .subscribe(Util.subscriber()); 18 | 19 | Util.sleepSeconds(5); 20 | 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/Lec10FluxEmptyError.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | /* 7 | To create empty/error flux 8 | */ 9 | public class Lec10FluxEmptyError { 10 | 11 | public static void main(String[] args) { 12 | 13 | Flux.empty() 14 | .subscribe(Util.subscriber()); 15 | 16 | Flux.error(new RuntimeException("oops")) 17 | .subscribe(Util.subscriber()); 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/Lec11FluxMono.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.publisher.Mono; 6 | 7 | /* 8 | To covert a Flux <--> Mono 9 | */ 10 | public class Lec11FluxMono { 11 | 12 | public static void main(String[] args) { 13 | 14 | monoToFlux(); 15 | fluxToMono(); 16 | 17 | } 18 | 19 | private static void fluxToMono(){ 20 | var flux = Flux.range(1, 10); 21 | Mono.from(flux) 22 | .subscribe(Util.subscriber()); 23 | } 24 | 25 | private static void monoToFlux(){ 26 | var mono = getUsername(1); 27 | save(Flux.from(mono)); 28 | } 29 | 30 | private static Mono getUsername(int userId){ 31 | return switch (userId){ 32 | case 1 -> Mono.just("sam"); 33 | case 2 -> Mono.empty(); // null 34 | default -> Mono.error(new RuntimeException("invalid input")); 35 | }; 36 | } 37 | 38 | private static void save(Flux flux){ 39 | flux.subscribe(Util.subscriber()); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/Lec12Assignment.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03; 2 | 3 | 4 | import com.vinsguru.common.Util; 5 | import com.vinsguru.sec03.assignment.StockPriceObserver; 6 | import com.vinsguru.sec03.client.ExternalServiceClient; 7 | 8 | /* 9 | Ensure that the external service is up and running! 10 | */ 11 | public class Lec12Assignment { 12 | 13 | public static void main(String[] args) { 14 | 15 | var client = new ExternalServiceClient(); 16 | var subscriber = new StockPriceObserver(); 17 | client.getPriceChanges() 18 | .subscribe(subscriber); 19 | 20 | 21 | Util.sleepSeconds(20); 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/client/ExternalServiceClient.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03.client; 2 | 3 | import com.vinsguru.common.AbstractHttpClient; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class ExternalServiceClient extends AbstractHttpClient { 7 | 8 | public Flux getNames() { 9 | return this.httpClient.get() 10 | .uri("/demo02/name/stream") 11 | .responseContent() 12 | .asString(); 13 | } 14 | 15 | public Flux getPriceChanges() { 16 | return this.httpClient.get() 17 | .uri("/demo02/stock/stream") 18 | .responseContent() 19 | .asString() 20 | .map(Integer::parseInt); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec03/helper/NameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec03.helper; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.util.List; 7 | import java.util.stream.IntStream; 8 | 9 | public class NameGenerator { 10 | 11 | public static List getNamesList(int count){ 12 | return IntStream.rangeClosed(1, count) 13 | .mapToObj(i -> generateName()) 14 | .toList(); 15 | } 16 | 17 | public static Flux getNamesFlux(int count){ 18 | return Flux.range(1, count) 19 | .map(i -> generateName()); 20 | } 21 | 22 | private static String generateName(){ 23 | Util.sleepSeconds(1); 24 | return Util.faker().name().firstName(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec04/Lec01FluxCreate.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec04; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | /* 7 | To create a flux & emit items programmatically 8 | */ 9 | public class Lec01FluxCreate { 10 | 11 | public static void main(String[] args) { 12 | 13 | Flux.create(fluxSink -> { 14 | String country; 15 | do { 16 | country = Util.faker().country().name(); 17 | fluxSink.next(country); 18 | } while (!country.equalsIgnoreCase("canada")); 19 | fluxSink.complete(); 20 | }) 21 | .subscribe(Util.subscriber()); 22 | 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec04/Lec02FluxCreateRefactor.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec04; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec04.helper.NameGenerator; 5 | import reactor.core.publisher.Flux; 6 | 7 | public class Lec02FluxCreateRefactor { 8 | 9 | public static void main(String[] args) { 10 | 11 | var generator = new NameGenerator(); 12 | var flux = Flux.create(generator); 13 | flux.subscribe(Util.subscriber()); 14 | 15 | // somewhere else! 16 | for (int i = 0; i < 10; i++) { 17 | generator.generate(); 18 | } 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec04/Lec05TakeOperator.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec04; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | /* 7 | Take is similar to java stream's limit 8 | */ 9 | public class Lec05TakeOperator { 10 | 11 | public static void main(String[] args) { 12 | 13 | 14 | takeUntil(); 15 | 16 | 17 | } 18 | 19 | private static void take(){ 20 | Flux.range(1, 10) 21 | .log("take") 22 | .take(3) 23 | .log("sub") 24 | .subscribe(Util.subscriber()); 25 | } 26 | 27 | private static void takeWhile() { 28 | Flux.range(1, 10) 29 | .log("take") 30 | .takeWhile(i -> i < 5) // stop when the condition is not met 31 | .log("sub") 32 | .subscribe(Util.subscriber()); 33 | } 34 | 35 | private static void takeUntil() { 36 | Flux.range(1, 10) 37 | .log("take") 38 | .takeUntil(i -> i < 5) // stop when the condition is met + allow the last item 39 | .log("sub") 40 | .subscribe(Util.subscriber()); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec04/Lec06FluxGenerate.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec04; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Flux; 7 | 8 | /* 9 | Flux generate 10 | - invokes the given lambda expression again and again based on downstream demand. 11 | - We can emit only one value at a time 12 | - will stop when complete method is invoked 13 | - will stop when error method is invoked 14 | - will stop downstream cancels 15 | */ 16 | public class Lec06FluxGenerate { 17 | 18 | private static final Logger log = LoggerFactory.getLogger(Lec06FluxGenerate.class); 19 | 20 | public static void main(String[] args) { 21 | 22 | 23 | Flux.generate(synchronousSink -> { 24 | log.info("invoked"); 25 | synchronousSink.next(1); 26 | // synchronousSink.next(2); 27 | //synchronousSink.complete(); 28 | synchronousSink.error(new RuntimeException("oops")); 29 | }) 30 | .take(4) 31 | .subscribe(Util.subscriber()); 32 | 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec04/Lec07FluxGenerateUntil.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec04; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec07FluxGenerateUntil { 7 | 8 | public static void main(String[] args) { 9 | 10 | demo2(); 11 | 12 | } 13 | 14 | private static void demo1() { 15 | Flux.generate(synchronousSink -> { 16 | var country = Util.faker().country().name(); 17 | synchronousSink.next(country); 18 | if (country.equalsIgnoreCase("canada")) { 19 | synchronousSink.complete(); 20 | } 21 | }) 22 | .subscribe(Util.subscriber()); 23 | } 24 | 25 | private static void demo2() { 26 | Flux.generate(synchronousSink -> { 27 | var country = Util.faker().country().name(); 28 | synchronousSink.next(country); 29 | }) 30 | .takeUntil(c -> c.equalsIgnoreCase("canada")) 31 | .subscribe(Util.subscriber()); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec04/Lec08GenerateWithState.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec04; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec08GenerateWithState { 7 | 8 | public static void main(String[] args) { 9 | 10 | Flux.generate( 11 | () -> 0, 12 | (counter, sink) -> { 13 | var country = Util.faker().country().name(); 14 | sink.next(country); 15 | counter++; 16 | if (counter == 10 || country.equalsIgnoreCase("canada")) { 17 | sink.complete(); 18 | } 19 | return counter; 20 | } 21 | ) 22 | .subscribe(Util.subscriber()); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec04/Lec09Assignment.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec04; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec04.assignment.FileReaderServiceImpl; 5 | 6 | import java.nio.file.Path; 7 | 8 | public class Lec09Assignment { 9 | 10 | public static void main(String[] args) { 11 | 12 | var path = Path.of("src/main/resources/sec04/file.txt"); 13 | var fileReaderService = new FileReaderServiceImpl(); 14 | fileReaderService.read(path) 15 | .takeUntil(s -> s.equalsIgnoreCase("line17")) 16 | .subscribe(Util.subscriber()); 17 | 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec04/assignment/FileReaderService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec04.assignment; 2 | 3 | import reactor.core.publisher.Flux; 4 | 5 | import java.nio.file.Path; 6 | 7 | /* 8 | - do the work only when it is subscribed 9 | - do the work based on the demand 10 | - stop producing when subscriber cancels 11 | - produce only the requested items 12 | - file should be closed once done 13 | */ 14 | public interface FileReaderService { 15 | 16 | Flux read(Path path); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec04/helper/NameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec04.helper; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.FluxSink; 5 | 6 | import java.util.function.Consumer; 7 | 8 | public class NameGenerator implements Consumer> { 9 | 10 | private FluxSink sink; 11 | 12 | @Override 13 | public void accept(FluxSink stringFluxSink) { 14 | this.sink = stringFluxSink; 15 | } 16 | 17 | public void generate(){ 18 | this.sink.next(Util.faker().name().firstName()); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec05/Lec01Handle.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | /* 7 | Handle behaves like filter + map 8 | 9 | 1 => -2 10 | 4 => do not send 11 | 7 => error 12 | everything else => send as it is 13 | */ 14 | public class Lec01Handle { 15 | 16 | public static void main(String[] args) { 17 | 18 | Flux.range(1, 10) 19 | .handle((item, sink) -> { 20 | switch (item){ 21 | case 1 -> sink.next(-2); 22 | case 4 -> {} 23 | case 7 -> sink.error(new RuntimeException("oops")); 24 | default -> sink.next(item); 25 | } 26 | }) 27 | .cast(Integer.class) 28 | .subscribe(Util.subscriber()); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec05/Lec02HandleUntilAssignment.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec02HandleUntilAssignment { 7 | 8 | public static void main(String[] args) { 9 | 10 | Flux.generate(sink -> sink.next(Util.faker().country().name())) 11 | .handle((item, sink) -> { 12 | sink.next(item); 13 | if(item.equalsIgnoreCase("canada")){ 14 | sink.complete(); 15 | } 16 | }) 17 | .subscribe(Util.subscriber()); 18 | 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec05/Lec04Delay.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | public class Lec04Delay { 9 | 10 | public static void main(String[] args) { 11 | 12 | 13 | Flux.range(1, 10) 14 | .log() 15 | .delayElements(Duration.ofSeconds(1)) 16 | .subscribe(Util.subscriber()); 17 | 18 | Util.sleepSeconds(12); 19 | 20 | 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec05/Lec05Subscribe.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | import reactor.core.publisher.Flux; 6 | 7 | public class Lec05Subscribe { 8 | 9 | private static final Logger log = LoggerFactory.getLogger(Lec05Subscribe.class); 10 | 11 | public static void main(String[] args) { 12 | 13 | Flux.range(1, 10) 14 | .doOnNext(i -> log.info("received: {}", i)) 15 | .doOnComplete(() -> log.info("completed")) 16 | .doOnError(err -> log.error("error", err)) 17 | .subscribe(); 18 | 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec05/Lec07DefaultIfEmpty.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | /* 7 | Similar to error handling. 8 | Handling empty! 9 | */ 10 | public class Lec07DefaultIfEmpty { 11 | 12 | public static void main(String[] args) { 13 | 14 | Flux.range(1, 10) 15 | .filter(i -> i > 11) 16 | .defaultIfEmpty(50) 17 | .subscribe(Util.subscriber()); 18 | 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec05/Lec08SwitchIfEmpty.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | /* 7 | Similar to error handling. 8 | Handling empty! 9 | */ 10 | public class Lec08SwitchIfEmpty { 11 | 12 | public static void main(String[] args) { 13 | 14 | /* 15 | postgres + redis 16 | */ 17 | 18 | Flux.range(1, 10) 19 | .filter(i -> i > 10) 20 | .switchIfEmpty(fallback()) 21 | .subscribe(Util.subscriber()); 22 | 23 | 24 | } 25 | 26 | private static Flux fallback(){ 27 | return Flux.range(100, 3); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec05/Lec09Timeout.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Mono; 7 | 8 | import java.time.Duration; 9 | 10 | /* 11 | timeout - will produce timeout error. 12 | - We can handle as part of onError methods 13 | there is also an overloaded method to accept a publisher 14 | we can have multiple timeouts. the closest one to the subscriber will take effect for the subscriber. 15 | */ 16 | public class Lec09Timeout { 17 | 18 | private static final Logger log = LoggerFactory.getLogger(Lec09Timeout.class); 19 | 20 | public static void main(String[] args) { 21 | 22 | getProductName() 23 | .timeout(Duration.ofSeconds(1), fallback()) 24 | .subscribe(Util.subscriber()); 25 | 26 | Util.sleepSeconds(5); 27 | 28 | } 29 | 30 | private static Mono getProductName() { 31 | return Mono.fromSupplier(() -> "service-" + Util.faker().commerce().productName()) 32 | .delayElement(Duration.ofMillis(1900)); 33 | } 34 | 35 | private static Mono fallback() { 36 | return Mono.fromSupplier(() -> "fallback-" + Util.faker().commerce().productName()) 37 | .delayElement(Duration.ofMillis(300)) 38 | .doFirst(() -> log.info("do first")); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec05/Lec11Assignment.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec05.assignment.ExternalServiceClient; 5 | 6 | /* 7 | Ensure that the external service is up and running! 8 | */ 9 | public class Lec11Assignment { 10 | 11 | public static void main(String[] args) { 12 | 13 | 14 | var client = new ExternalServiceClient(); 15 | 16 | for (int i = 1; i < 5; i++) { 17 | client.getProductName(i) 18 | .subscribe(Util.subscriber()); 19 | } 20 | 21 | Util.sleepSeconds(3); 22 | 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec05/assignment/ExternalServiceClient.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec05.assignment; 2 | 3 | import com.vinsguru.common.AbstractHttpClient; 4 | import reactor.core.publisher.Mono; 5 | 6 | import java.time.Duration; 7 | 8 | public class ExternalServiceClient extends AbstractHttpClient { 9 | 10 | public Mono getProductName(int productId) { 11 | var defaultPath = "/demo03/product/" + productId; 12 | var timeoutPath = "/demo03/timeout-fallback/product/" + productId; 13 | var emptyPath = "/demo03/empty-fallback/product/" + productId; 14 | return getProductName(defaultPath) 15 | .timeout(Duration.ofSeconds(2), getProductName(timeoutPath)) 16 | .switchIfEmpty(getProductName(emptyPath)); 17 | } 18 | 19 | private Mono getProductName(String path) { 20 | return this.httpClient.get() 21 | .uri(path) 22 | .responseContent() 23 | .asString() 24 | .next(); 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec06/Lec01ColdPublisher.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec06; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Flux; 7 | 8 | public class Lec01ColdPublisher { 9 | 10 | private static final Logger log = LoggerFactory.getLogger(Lec01ColdPublisher.class); 11 | 12 | public static void main(String[] args) { 13 | 14 | var flux = Flux.create(fluxSink -> { 15 | log.info("invoked"); 16 | for (int i = 0; i < 3; i++) { 17 | fluxSink.next(i); 18 | } 19 | fluxSink.complete(); 20 | }); 21 | 22 | 23 | flux.subscribe(Util.subscriber("sub1")); 24 | flux.subscribe(Util.subscriber("sub2")); 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec06/Lec04HotPublisherCache.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec06; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Flux; 7 | 8 | import java.time.Duration; 9 | 10 | /* 11 | - publish().autoConnect(0) will provide new values to the subscribers. 12 | - replay allows us to cache 13 | */ 14 | public class Lec04HotPublisherCache { 15 | 16 | private static final Logger log = LoggerFactory.getLogger(Lec04HotPublisherCache.class); 17 | 18 | public static void main(String[] args) { 19 | 20 | var stockFlux = stockStream().replay(1).autoConnect(0); 21 | 22 | Util.sleepSeconds(4); 23 | 24 | log.info("sam joining"); 25 | stockFlux 26 | .subscribe(Util.subscriber("sam")); 27 | 28 | Util.sleepSeconds(4); 29 | 30 | log.info("mike joining"); 31 | stockFlux 32 | .subscribe(Util.subscriber("mike")); 33 | 34 | Util.sleepSeconds(15); 35 | 36 | } 37 | 38 | private static Flux stockStream() { 39 | return Flux.generate(sink -> sink.next(Util.faker().random().nextInt(10, 100))) 40 | .delayElements(Duration.ofSeconds(3)) 41 | .doOnNext(price -> log.info("emitting price: {}", price)) 42 | .cast(Integer.class); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec06/Lec05FluxCreateIssueFix.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec06; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec04.helper.NameGenerator; 5 | import reactor.core.publisher.Flux; 6 | 7 | /* 8 | To fix the issue we faced in sec04/Lec02FluxCreateRefactor 9 | */ 10 | public class Lec05FluxCreateIssueFix { 11 | 12 | public static void main(String[] args) { 13 | 14 | var generator = new NameGenerator(); 15 | var flux = Flux.create(generator).share(); 16 | flux.subscribe(Util.subscriber("sub1")); 17 | flux.subscribe(Util.subscriber("sub2")); 18 | 19 | // somewhere else! 20 | for (int i = 0; i < 10; i++) { 21 | generator.generate(); 22 | } 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec06/Lec06Assignment.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec06; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec06.assignment.ExternalServiceClient; 5 | import com.vinsguru.sec06.assignment.InventoryService; 6 | import com.vinsguru.sec06.assignment.RevenueService; 7 | 8 | /* 9 | Ensure that the external service is up and running! 10 | */ 11 | public class Lec06Assignment { 12 | 13 | public static void main(String[] args) { 14 | 15 | var client = new ExternalServiceClient(); 16 | var inventoryService = new InventoryService(); 17 | var revenueService = new RevenueService(); 18 | 19 | client.orderStream().subscribe(inventoryService::consume); 20 | client.orderStream().subscribe(revenueService::consume); 21 | 22 | inventoryService.stream() 23 | .subscribe(Util.subscriber("inventory")); 24 | 25 | revenueService.stream() 26 | .subscribe(Util.subscriber("revenue")); 27 | 28 | 29 | Util.sleepSeconds(30); 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec06/assignment/InventoryService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec06.assignment; 2 | 3 | import reactor.core.publisher.Flux; 4 | 5 | import java.time.Duration; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | public class InventoryService implements OrderProcessor { 10 | 11 | private final Map db = new HashMap<>(); 12 | 13 | @Override 14 | public void consume(Order order) { 15 | var currentInventory = db.getOrDefault(order.category(), 500); 16 | var updatedInventory = currentInventory - order.quantity(); 17 | db.put(order.category(), updatedInventory); 18 | } 19 | 20 | @Override 21 | public Flux stream() { 22 | return Flux.interval(Duration.ofSeconds(2)) 23 | .map(i -> this.db.toString()); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec06/assignment/Order.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec06.assignment; 2 | 3 | public record Order(String category, Integer price, Integer quantity) { 4 | } 5 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec06/assignment/OrderProcessor.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec06.assignment; 2 | 3 | import reactor.core.publisher.Flux; 4 | 5 | public interface OrderProcessor { 6 | 7 | void consume(Order order); 8 | 9 | Flux stream(); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec06/assignment/RevenueService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec06.assignment; 2 | 3 | import reactor.core.publisher.Flux; 4 | 5 | import java.time.Duration; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | public class RevenueService implements OrderProcessor { 10 | 11 | private final Map db = new HashMap<>(); 12 | 13 | @Override 14 | public void consume(Order order) { 15 | var currentRevenue = db.getOrDefault(order.category(), 0); 16 | var updatedRevenue = currentRevenue + order.price(); 17 | db.put(order.category(), updatedRevenue); 18 | } 19 | 20 | @Override 21 | public Flux stream() { 22 | return Flux.interval(Duration.ofSeconds(2)) 23 | .map(i -> this.db.toString()); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec07/Lec01DefaultBehaviorDemo.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec07; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Flux; 7 | 8 | /* 9 | By default, the current thread is doing all the work 10 | */ 11 | public class Lec01DefaultBehaviorDemo { 12 | 13 | private static final Logger log = LoggerFactory.getLogger(Lec01DefaultBehaviorDemo.class); 14 | 15 | public static void main(String[] args) { 16 | 17 | var flux = Flux.create(sink -> { 18 | for (int i = 1; i < 3; i++) { 19 | log.info("generating: {}", i); 20 | sink.next(i); 21 | } 22 | sink.complete(); 23 | }) 24 | .doOnNext(v -> log.info("value: {}", v)); 25 | 26 | Runnable runnable = () -> flux.subscribe(Util.subscriber("sub1")); 27 | 28 | Thread.ofPlatform().start(runnable); 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec07/Lec02SubscribeOn.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec07; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Flux; 7 | import reactor.core.scheduler.Schedulers; 8 | 9 | public class Lec02SubscribeOn { 10 | 11 | private static final Logger log = LoggerFactory.getLogger(Lec02SubscribeOn.class); 12 | 13 | public static void main(String[] args) { 14 | 15 | var flux = Flux.create(sink -> { 16 | for (int i = 1; i < 3; i++) { 17 | log.info("generating: {}", i); 18 | sink.next(i); 19 | } 20 | sink.complete(); 21 | }) 22 | .doOnNext(v -> log.info("value: {}", v)) 23 | .doFirst(() -> log.info("first1")) 24 | .subscribeOn(Schedulers.boundedElastic()) 25 | .doFirst(() -> log.info("first2")); 26 | 27 | 28 | Runnable runnable1 = () -> flux.subscribe(Util.subscriber("sub1")); 29 | Runnable runnable2 = () -> flux.subscribe(Util.subscriber("sub2")); 30 | 31 | Thread.ofPlatform().start(runnable1); 32 | Thread.ofPlatform().start(runnable2); 33 | 34 | Util.sleepSeconds(2); 35 | 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec07/Lec05BackPressureStrategies.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec07; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | /* 7 | Reactor provides various strategies to handle the backpressure 8 | */ 9 | public class Lec05BackPressureStrategies { 10 | 11 | private static final Logger log = LoggerFactory.getLogger(Lec05BackPressureStrategies.class); 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec07/Lec05PublishOn.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec07; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Flux; 7 | import reactor.core.scheduler.Schedulers; 8 | 9 | /* 10 | publish on for downstream! 11 | */ 12 | public class Lec05PublishOn { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(Lec05PublishOn.class); 15 | 16 | public static void main(String[] args) { 17 | 18 | var flux = Flux.create(sink -> { 19 | for (int i = 1; i < 3; i++) { 20 | log.info("generating: {}", i); 21 | sink.next(i); 22 | } 23 | sink.complete(); 24 | }) 25 | .publishOn(Schedulers.parallel()) 26 | .doOnNext(v -> log.info("value: {}", v)) 27 | .doFirst(() -> log.info("first1")) 28 | .publishOn(Schedulers.boundedElastic()) 29 | .doFirst(() -> log.info("first2")); 30 | 31 | 32 | Runnable runnable1 = () -> flux.subscribe(Util.subscriber("sub1")); 33 | 34 | Thread.ofPlatform().start(runnable1); 35 | 36 | Util.sleepSeconds(2); 37 | 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec07/Lec06EventLoopIssueFix.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec07; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec07.client.ExternalServiceClient; 5 | 6 | /* 7 | Ensure that the external service is up and running! 8 | */ 9 | public class Lec06EventLoopIssueFix { 10 | 11 | public static void main(String[] args) { 12 | 13 | var client = new ExternalServiceClient(); 14 | 15 | for (int i = 1; i <= 5; i++) { 16 | client.getProductName(i) 17 | .map(Lec06EventLoopIssueFix::process) 18 | .subscribe(Util.subscriber()); 19 | } 20 | 21 | Util.sleepSeconds(20); 22 | 23 | } 24 | 25 | private static String process(String input){ 26 | Util.sleepSeconds(1); 27 | return input + "-processed"; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec07/Lec07PublishOnSubscribeOn.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec07; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Flux; 7 | import reactor.core.scheduler.Schedulers; 8 | 9 | /* 10 | publish on for downstream! 11 | subscribeOn for upstream 12 | */ 13 | public class Lec07PublishOnSubscribeOn { 14 | 15 | private static final Logger log = LoggerFactory.getLogger(Lec07PublishOnSubscribeOn.class); 16 | 17 | public static void main(String[] args) { 18 | 19 | var flux = Flux.create(sink -> { 20 | for (int i = 1; i < 3; i++) { 21 | log.info("generating: {}", i); 22 | sink.next(i); 23 | } 24 | sink.complete(); 25 | }) 26 | .publishOn(Schedulers.parallel()) 27 | .doOnNext(v -> log.info("value: {}", v)) 28 | .doFirst(() -> log.info("first1")) 29 | .subscribeOn(Schedulers.boundedElastic()) 30 | .doFirst(() -> log.info("first2")); 31 | 32 | 33 | Runnable runnable1 = () -> flux.subscribe(Util.subscriber("sub1")); 34 | 35 | Thread.ofPlatform().start(runnable1); 36 | 37 | Util.sleepSeconds(2); 38 | 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec07/Lec08Parallel.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec07; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Flux; 7 | import reactor.core.scheduler.Schedulers; 8 | 9 | /* 10 | Often times you really do not need this! 11 | - prefer non-blocking IO for network calls 12 | */ 13 | public class Lec08Parallel { 14 | 15 | private static final Logger log = LoggerFactory.getLogger(Lec08Parallel.class); 16 | 17 | public static void main(String[] args) { 18 | 19 | Flux.range(1, 10) 20 | .parallel(3) 21 | .runOn(Schedulers.parallel()) 22 | .map(Lec08Parallel::process) 23 | // .sequential() 24 | .map(i -> i + "a") 25 | .subscribe(Util.subscriber()); 26 | 27 | Util.sleepSeconds(30); 28 | } 29 | 30 | private static int process(int i){ 31 | log.info("time consuming task {}", i); 32 | Util.sleepSeconds(1); 33 | return i * 2; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec07/client/ExternalServiceClient.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec07.client; 2 | 3 | import com.vinsguru.common.AbstractHttpClient; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Mono; 7 | import reactor.core.scheduler.Schedulers; 8 | 9 | public class ExternalServiceClient extends AbstractHttpClient { 10 | 11 | private static final Logger log = LoggerFactory.getLogger(ExternalServiceClient.class); 12 | 13 | public Mono getProductName(int productId) { 14 | return this.httpClient.get() 15 | .uri("/demo01/product/" + productId) 16 | .responseContent() 17 | .asString() 18 | .doOnNext(m -> log.info("next: {}", m)) 19 | .next() 20 | .publishOn(Schedulers.boundedElastic()); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/Lec02StartWithUseCase.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec09.helper.NameGenerator; 5 | 6 | public class Lec02StartWithUseCase { 7 | 8 | public static void main(String[] args) { 9 | 10 | 11 | var nameGenerator = new NameGenerator(); 12 | 13 | nameGenerator.generateNames() 14 | .take(2) 15 | .subscribe(Util.subscriber("sam")); 16 | 17 | 18 | nameGenerator.generateNames() 19 | .take(2) 20 | .subscribe(Util.subscriber("mike")); 21 | 22 | nameGenerator.generateNames() 23 | .take(3) 24 | .subscribe(Util.subscriber("jake")); 25 | 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/Lec06MergeUseCase.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec09.helper.Kayak; 5 | 6 | public class Lec06MergeUseCase { 7 | 8 | public static void main(String[] args) { 9 | 10 | Kayak.getFlights() 11 | .subscribe(Util.subscriber()); 12 | 13 | 14 | Util.sleepSeconds(3); 15 | 16 | 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/Lec07Zip.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | /* 9 | Zip 10 | - we will subscribe to all the producers at the same time 11 | - all or nothing 12 | - all producers will have to emit an item 13 | */ 14 | public class Lec07Zip { 15 | 16 | record Car(String body, String engine, String tires){} 17 | 18 | public static void main(String[] args) { 19 | 20 | Flux.zip(getBody(), getEngine(), getTires()) 21 | .map(t -> new Car(t.getT1(), t.getT2(), t.getT3())) 22 | .subscribe(Util.subscriber()); 23 | 24 | Util.sleepSeconds(5); 25 | } 26 | 27 | private static Flux getBody(){ 28 | return Flux.range(1, 5) 29 | .map(i -> "body-" + i) 30 | .delayElements(Duration.ofMillis(100)); 31 | } 32 | 33 | private static Flux getEngine(){ 34 | return Flux.range(1, 3) 35 | .map(i -> "engine-" + i) 36 | .delayElements(Duration.ofMillis(200)); 37 | } 38 | 39 | private static Flux getTires(){ 40 | return Flux.range(1, 10) 41 | .map(i -> "tires-" + i) 42 | .delayElements(Duration.ofMillis(75)); 43 | } 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/Lec08ZipAssignment.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec09.assignment.ExternalServiceClient; 5 | 6 | /* 7 | Ensure that the external service is up and running! 8 | */ 9 | public class Lec08ZipAssignment { 10 | 11 | public static void main(String[] args) { 12 | 13 | var client = new ExternalServiceClient(); 14 | 15 | for (int i = 1; i < 10; i++) { 16 | client.getProduct(i) 17 | .subscribe(Util.subscriber()); 18 | } 19 | 20 | Util.sleepSeconds(2); 21 | 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/Lec09MonoFlatMap.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec09.applications.PaymentService; 5 | import com.vinsguru.sec09.applications.UserService; 6 | 7 | /* 8 | Sequential non-blocking IO calls! 9 | flatMap is used to flatten the inner publisher / to subscribe to the inner publisher 10 | */ 11 | public class Lec09MonoFlatMap { 12 | 13 | public static void main(String[] args) { 14 | 15 | /* 16 | We have username. 17 | Get user account balance 18 | */ 19 | 20 | UserService.getUserId("mike") 21 | .flatMap(PaymentService::getUserBalance) 22 | .subscribe(Util.subscriber()); 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/Lec10MonoFlatMapMany.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec09.applications.OrderService; 5 | import com.vinsguru.sec09.applications.UserService; 6 | 7 | /* 8 | Sequential non-blocking IO calls! 9 | flatMap is used to flatten the inner publisher / to subscribe to the inner publisher 10 | Mono is supposed to be 1 item - what if the flatMap returns multiple items!? 11 | */ 12 | public class Lec10MonoFlatMapMany { 13 | 14 | public static void main(String[] args) { 15 | 16 | /* 17 | We have username 18 | get all user orders! 19 | */ 20 | 21 | UserService.getUserId("jake") 22 | .flatMapMany(OrderService::getUserOrders) 23 | .subscribe(Util.subscriber()); 24 | 25 | 26 | Util.sleepSeconds(3); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/Lec11FluxFlatMap.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec09.applications.OrderService; 5 | import com.vinsguru.sec09.applications.User; 6 | import com.vinsguru.sec09.applications.UserService; 7 | 8 | /* 9 | Sequential non-blocking IO calls! 10 | flatMap is used to flatten the inner publisher / to subscribe to the inner publisher 11 | */ 12 | public class Lec11FluxFlatMap { 13 | 14 | public static void main(String[] args) { 15 | 16 | /* 17 | Get all the orders from order service! 18 | */ 19 | 20 | UserService.getAllUsers() 21 | .map(User::id) 22 | .flatMap(OrderService::getUserOrders) 23 | .subscribe(Util.subscriber()); 24 | 25 | Util.sleepSeconds(5); 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/Lec12FluxFlatMapAssignment.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec09.assignment.ExternalServiceClient; 5 | import reactor.core.publisher.Flux; 6 | 7 | /* 8 | Ensure that the external service is up and running! 9 | */ 10 | public class Lec12FluxFlatMapAssignment { 11 | 12 | public static void main(String[] args) { 13 | 14 | var client = new ExternalServiceClient(); 15 | 16 | Flux.range(1, 10) 17 | .flatMap(client::getProduct, 3) 18 | .subscribe(Util.subscriber()); 19 | 20 | Util.sleepSeconds(20); 21 | 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/Lec13ConcatMap.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec09.assignment.ExternalServiceClient; 5 | import reactor.core.publisher.Flux; 6 | 7 | /* 8 | Ensure that the external service is up and running! 9 | */ 10 | public class Lec13ConcatMap { 11 | 12 | public static void main(String[] args) { 13 | 14 | var client = new ExternalServiceClient(); 15 | 16 | Flux.range(1, 10) 17 | .concatMap(client::getProduct) 18 | .subscribe(Util.subscriber()); 19 | 20 | Util.sleepSeconds(20); 21 | 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/Lec14CollectList.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | /* 7 | To collect the items received via Flux. Assuming we will have finite items! 8 | */ 9 | public class Lec14CollectList { 10 | 11 | public static void main(String[] args) { 12 | 13 | Flux.range(1, 10) 14 | .collectList() 15 | .subscribe(Util.subscriber()); 16 | 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/Lec15Then.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Flux; 7 | import reactor.core.publisher.Mono; 8 | 9 | import java.time.Duration; 10 | import java.util.List; 11 | 12 | /* 13 | "then" could be helpful when we are not interested in the result of a publisher / 14 | we need to have sequential execution of asynchronous tasks. 15 | */ 16 | public class Lec15Then { 17 | 18 | private static final Logger log = LoggerFactory.getLogger(Lec15Then.class); 19 | 20 | public static void main(String[] args) { 21 | 22 | var records = List.of("a", "b", "c"); 23 | 24 | saveRecords(records) 25 | .then(sendNotification(records)) // only in case of success 26 | .subscribe(Util.subscriber()); 27 | 28 | 29 | Util.sleepSeconds(5); 30 | 31 | } 32 | 33 | private static Flux saveRecords(List records) { 34 | return Flux.fromIterable(records) 35 | .map(r -> "saved " + r) 36 | .delayElements(Duration.ofMillis(500)); 37 | } 38 | 39 | private static Mono sendNotification(List records) { 40 | return Mono.fromRunnable(() -> log.info("all these {} records saved successfully", records)); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/Lec16Assignment.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec09.applications.*; 5 | import reactor.core.publisher.Mono; 6 | 7 | import java.util.List; 8 | 9 | /* 10 | Get all users and build 1 object as shown here. 11 | record UserInformation(Integer userId, String username, Integer balance, List orders) {} 12 | */ 13 | public class Lec16Assignment { 14 | 15 | record UserInformation(Integer userId, String username, Integer balance, List orders) { 16 | } 17 | 18 | public static void main(String[] args) { 19 | 20 | UserService.getAllUsers() 21 | .flatMap(Lec16Assignment::getUserInformation) 22 | .subscribe(Util.subscriber()); 23 | 24 | Util.sleepSeconds(2); 25 | 26 | } 27 | 28 | private static Mono getUserInformation(User user) { 29 | return Mono.zip( 30 | PaymentService.getUserBalance(user.id()), 31 | OrderService.getUserOrders(user.id()).collectList() 32 | ) 33 | .map(t -> new UserInformation(user.id(), user.username(), t.getT1(), t.getT2())); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/applications/Order.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.applications; 2 | 3 | // just for demo 4 | // we have user id in the order to show that it belongs to the user 5 | public record Order(Integer userId, 6 | String productName, 7 | Integer price) { 8 | } 9 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/applications/PaymentService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.applications; 2 | 3 | import reactor.core.publisher.Mono; 4 | 5 | import java.util.Map; 6 | 7 | /* 8 | Just for demo. 9 | Imagine payment-service, as an application, has an endpoint. 10 | This is a client class to make a call to the endpoint (IO request). 11 | */ 12 | public class PaymentService { 13 | 14 | private static final Map userBalanceTable = Map.of( 15 | 1, 100, 16 | 2, 200, 17 | 3, 300 18 | ); 19 | 20 | public static Mono getUserBalance(Integer userId) { 21 | return Mono.fromSupplier(() -> userBalanceTable.get(userId)); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/applications/User.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.applications; 2 | 3 | public record User(Integer id, String username) { 4 | } 5 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/applications/UserService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.applications; 2 | 3 | import reactor.core.publisher.Flux; 4 | import reactor.core.publisher.Mono; 5 | 6 | import java.util.Map; 7 | 8 | /* 9 | Just for demo. 10 | Imagine user-service, as an application, has 2 endpoints. 11 | This is a client class to make a call to those 2 endpoints (IO requests). 12 | */ 13 | public class UserService { 14 | 15 | private static final Map userTable = Map.of( 16 | "sam", 1, 17 | "mike", 2, 18 | "jake", 3 19 | ); 20 | 21 | public static Flux getAllUsers() { 22 | return Flux.fromIterable(userTable.entrySet()) 23 | .map(entry -> new User(entry.getValue(), entry.getKey())); 24 | } 25 | 26 | public static Mono getUserId(String username){ 27 | return Mono.fromSupplier(() -> userTable.get(username)); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/assignment/ExternalServiceClient.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.assignment; 2 | 3 | import com.vinsguru.common.AbstractHttpClient; 4 | import reactor.core.publisher.Mono; 5 | 6 | // just for demo 7 | public class ExternalServiceClient extends AbstractHttpClient { 8 | 9 | public Mono getProduct(int productId) { 10 | return Mono.zip( 11 | getProductName(productId), 12 | getReview(productId), 13 | getPrice(productId) 14 | ) 15 | .map(t -> new Product(t.getT1(), t.getT2(), t.getT3())); 16 | } 17 | 18 | private Mono getProductName(int productId) { 19 | return get("/demo05/product/" + productId); 20 | } 21 | 22 | private Mono getReview(int productId) { 23 | return get("/demo05/review/" + productId); 24 | } 25 | 26 | private Mono getPrice(int productId) { 27 | return get("/demo05/price/" + productId); 28 | } 29 | 30 | private Mono get(String path) { 31 | return this.httpClient.get() 32 | .uri(path) 33 | .responseContent() 34 | .asString() 35 | .next(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/assignment/Product.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.assignment; 2 | 3 | public record Product(String name, 4 | String review, 5 | String price) { 6 | } 7 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/helper/AmericanAirlines.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.helper; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | // to represent the client class to call remote service 9 | public class AmericanAirlines { 10 | 11 | private static final String AIRLINE = "American Airlines"; 12 | 13 | public static Flux getFlights(){ 14 | return Flux.range(1, Util.faker().random().nextInt(5, 10)) 15 | .delayElements(Duration.ofMillis(Util.faker().random().nextInt(200, 1200))) 16 | .map(i -> new Flight(AIRLINE, Util.faker().random().nextInt(300, 1200))) 17 | .transform(Util.fluxLogger(AIRLINE)); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/helper/Emirates.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.helper; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | // to represent the client class to call remote service 9 | public class Emirates { 10 | 11 | private static final String AIRLINE = "Emirates"; 12 | 13 | public static Flux getFlights(){ 14 | return Flux.range(1, Util.faker().random().nextInt(2, 10)) 15 | .delayElements(Duration.ofMillis(Util.faker().random().nextInt(200, 1000))) 16 | .map(i -> new Flight(AIRLINE, Util.faker().random().nextInt(300, 1000))) 17 | .transform(Util.fluxLogger(AIRLINE)); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/helper/Flight.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.helper; 2 | 3 | public record Flight(String airline, 4 | Integer price) { 5 | } 6 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/helper/Kayak.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.helper; 2 | 3 | import reactor.core.publisher.Flux; 4 | 5 | import java.time.Duration; 6 | 7 | public class Kayak { 8 | 9 | public static Flux getFlights() { 10 | return Flux.merge( 11 | AmericanAirlines.getFlights(), 12 | Emirates.getFlights(), 13 | Qatar.getFlights() 14 | ) 15 | .take(Duration.ofSeconds(2)); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/helper/NameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.helper; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Flux; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class NameGenerator { 12 | 13 | private static final Logger log = LoggerFactory.getLogger(NameGenerator.class); 14 | private final List redis = new ArrayList<>(); // intentional for demo 15 | 16 | public Flux generateNames() { 17 | return Flux.generate(sink -> { 18 | log.info("generating name"); 19 | Util.sleepSeconds(1); 20 | var name = Util.faker().name().firstName(); 21 | redis.add(name); // intentional for demo 22 | sink.next(name); 23 | }) 24 | .startWith(redis) 25 | .cast(String.class); 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec09/helper/Qatar.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec09.helper; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | // to represent the client class to call remote service 9 | public class Qatar { 10 | 11 | private static final String AIRLINE = "Qatar"; 12 | 13 | public static Flux getFlights(){ 14 | return Flux.range(1, Util.faker().random().nextInt(3, 5)) 15 | .delayElements(Duration.ofMillis(Util.faker().random().nextInt(300, 800))) 16 | .map(i -> new Flight(AIRLINE, Util.faker().random().nextInt(400, 900))) 17 | .transform(Util.fluxLogger(AIRLINE)); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec10/Lec03Window.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec10; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.publisher.Mono; 6 | 7 | import java.time.Duration; 8 | 9 | public class Lec03Window { 10 | 11 | 12 | public static void main(String[] args) { 13 | 14 | eventStream() 15 | .window(Duration.ofMillis(1800)) 16 | .flatMap(Lec03Window::processEvents) 17 | .subscribe(); 18 | 19 | 20 | Util.sleepSeconds(60); 21 | 22 | } 23 | 24 | private static Flux eventStream() { 25 | return Flux.interval(Duration.ofMillis(500)) 26 | .map(i -> "event-" + (i + 1)); 27 | } 28 | 29 | private static Mono processEvents(Flux flux) { 30 | return flux.doOnNext(e -> System.out.print("*")) 31 | .doOnComplete(System.out::println) 32 | .then(); 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec10/Lec04WindowAssignment.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec10; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec10.assignment.window.FileWriter; 5 | import reactor.core.publisher.Flux; 6 | 7 | import java.nio.file.Path; 8 | import java.time.Duration; 9 | import java.util.concurrent.atomic.AtomicInteger; 10 | 11 | public class Lec04WindowAssignment { 12 | 13 | public static void main(String[] args) { 14 | 15 | var counter = new AtomicInteger(0); 16 | var fileNameFormat = "src/main/resources/sec10/file%d.txt"; 17 | 18 | eventStream() 19 | .window(Duration.ofMillis(1800)) // just for demo 20 | .flatMap(flux -> FileWriter.create(flux, Path.of(fileNameFormat.formatted(counter.incrementAndGet())))) 21 | .subscribe(); 22 | 23 | 24 | Util.sleepSeconds(60); 25 | 26 | } 27 | 28 | private static Flux eventStream() { 29 | return Flux.interval(Duration.ofMillis(500)) 30 | .map(i -> "event-" + (i + 1)); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec10/Lec05GroupedFlux.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec10; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Flux; 7 | import reactor.core.publisher.GroupedFlux; 8 | import reactor.core.publisher.Mono; 9 | 10 | import java.time.Duration; 11 | 12 | public class Lec05GroupedFlux { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(Lec05GroupedFlux.class); 15 | 16 | public static void main(String[] args) { 17 | 18 | Flux.range(1, 30) 19 | .delayElements(Duration.ofSeconds(1)) 20 | .groupBy(i -> i % 2) // 0, 1 21 | .flatMap(Lec05GroupedFlux::processEvents) 22 | .subscribe(); 23 | 24 | Util.sleepSeconds(60); 25 | 26 | } 27 | 28 | private static Mono processEvents(GroupedFlux groupedFlux) { 29 | log.info("received flux for {}", groupedFlux.key()); 30 | return groupedFlux.doOnNext(i -> log.info("key: {}, item: {}", groupedFlux.key(), i)) 31 | .then(); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec10/Lec06GroupByAssignment.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec10; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec10.assignment.groupby.OrderProcessingService; 5 | import com.vinsguru.sec10.assignment.groupby.PurchaseOrder; 6 | import reactor.core.publisher.Flux; 7 | 8 | import java.time.Duration; 9 | 10 | public class Lec06GroupByAssignment { 11 | 12 | public static void main(String[] args) { 13 | 14 | orderStream() 15 | .filter(OrderProcessingService.canProcess()) 16 | .groupBy(PurchaseOrder::category) 17 | .flatMap(gf -> gf.transform(OrderProcessingService.getProcessor(gf.key()))) 18 | .subscribe(Util.subscriber()); 19 | 20 | Util.sleepSeconds(60); 21 | 22 | } 23 | 24 | private static Flux orderStream(){ 25 | return Flux.interval(Duration.ofMillis(200)) 26 | .map(i -> PurchaseOrder.create()); 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec10/assignment/buffer/BookOrder.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec10.assignment.buffer; 2 | 3 | import com.vinsguru.common.Util; 4 | 5 | public record BookOrder(String genre, 6 | String title, 7 | Integer price) { 8 | 9 | public static BookOrder create(){ 10 | var book = Util.faker().book(); 11 | return new BookOrder( 12 | book.genre(), 13 | book.title(), 14 | Util.faker().random().nextInt(10, 100) 15 | ); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec10/assignment/buffer/RevenueReport.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec10.assignment.buffer; 2 | 3 | import java.time.LocalTime; 4 | import java.util.Map; 5 | 6 | public record RevenueReport(LocalTime time, 7 | Map revenue) { 8 | } 9 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec10/assignment/groupby/PurchaseOrder.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec10.assignment.groupby; 2 | 3 | import com.vinsguru.common.Util; 4 | 5 | public record PurchaseOrder(String item, 6 | String category, 7 | Integer price) { 8 | 9 | public static PurchaseOrder create() { 10 | var commerce = Util.faker().commerce(); 11 | return new PurchaseOrder( 12 | commerce.productName(), 13 | commerce.department(), 14 | Util.faker().random().nextInt(10, 100) 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec11/client/ClientError.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec11.client; 2 | 3 | // just for demo 4 | public class ClientError extends RuntimeException { 5 | 6 | public ClientError() { 7 | super("bad request"); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec11/client/ExternalServiceClient.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec11.client; 2 | 3 | import com.vinsguru.common.AbstractHttpClient; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.publisher.Mono; 6 | import reactor.netty.ByteBufFlux; 7 | import reactor.netty.http.client.HttpClientResponse; 8 | 9 | // just for demo 10 | public class ExternalServiceClient extends AbstractHttpClient { 11 | 12 | public Mono getProductName(int productId) { 13 | return get("/demo06/product/" + productId); 14 | } 15 | 16 | public Mono getCountry() { 17 | return get("/demo06/country"); 18 | } 19 | 20 | private Mono get(String path) { 21 | return this.httpClient.get() 22 | .uri(path) 23 | .response(this::toResponse) 24 | .next(); 25 | } 26 | 27 | private Flux toResponse(HttpClientResponse httpClientResponse, ByteBufFlux byteBufFlux) { 28 | return switch (httpClientResponse.status().code()) { 29 | case 200 -> byteBufFlux.asString(); 30 | case 400 -> Flux.error(new ClientError()); 31 | default -> Flux.error(new ServerError()); 32 | }; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec11/client/ServerError.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec11.client; 2 | 3 | // just for demo 4 | public class ServerError extends RuntimeException { 5 | 6 | public ServerError() { 7 | super("server error"); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec12/Lec06MulticastDirectAllOrNothing.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec12; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Sinks; 7 | 8 | import java.time.Duration; 9 | 10 | public class Lec06MulticastDirectAllOrNothing { 11 | 12 | private static final Logger log = LoggerFactory.getLogger(Lec06MulticastDirectAllOrNothing.class); 13 | 14 | public static void main(String[] args) { 15 | 16 | demo1(); 17 | 18 | Util.sleepSeconds(10); 19 | 20 | } 21 | 22 | /* 23 | directAllOrNothing - all or nothing - either deliver to all the subscribers or no one! 24 | */ 25 | private static void demo1(){ 26 | 27 | System.setProperty("reactor.bufferSize.small", "16"); 28 | 29 | // handle through which we would push items 30 | // onBackPressureBuffer - bounded queue 31 | var sink = Sinks.many().multicast().directAllOrNothing(); 32 | 33 | // handle through which subscribers will receive items 34 | var flux = sink.asFlux(); 35 | 36 | flux.subscribe(Util.subscriber("sam")); 37 | flux.delayElements(Duration.ofMillis(200)).subscribe(Util.subscriber("mike")); 38 | 39 | for (int i = 1; i <= 100 ; i++) { 40 | var result = sink.tryEmitNext(i); 41 | log.info("item: {}, result: {}", i, result); 42 | } 43 | 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec12/Lec07Replay.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec12; 2 | 3 | import com.vinsguru.common.Util; 4 | import reactor.core.publisher.Sinks; 5 | 6 | public class Lec07Replay { 7 | 8 | public static void main(String[] args) { 9 | 10 | demo1(); 11 | 12 | } 13 | 14 | 15 | private static void demo1(){ 16 | 17 | // handle through which we would push items 18 | var sink = Sinks.many().replay().all(1); 19 | 20 | // handle through which subscribers will receive items 21 | var flux = sink.asFlux(); 22 | 23 | flux.subscribe(Util.subscriber("sam")); 24 | flux.subscribe(Util.subscriber("mike")); 25 | 26 | sink.tryEmitNext("hi"); 27 | sink.tryEmitNext("how are you"); 28 | sink.tryEmitNext("?"); 29 | 30 | Util.sleepSeconds(2); 31 | 32 | flux.subscribe(Util.subscriber("jake")); 33 | sink.tryEmitNext("new message"); 34 | 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec12/Lec08SlackAssignment.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec12; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec12.assignment.SlackMember; 5 | import com.vinsguru.sec12.assignment.SlackRoom; 6 | 7 | public class Lec08SlackAssignment { 8 | 9 | public static void main(String[] args) { 10 | 11 | var room = new SlackRoom("reactor"); 12 | var sam = new SlackMember("sam"); 13 | var jake = new SlackMember("jake"); 14 | var mike = new SlackMember("mike"); 15 | 16 | // add 2 members 17 | room.addMember(sam); 18 | room.addMember(jake); 19 | 20 | sam.says("Hi all.."); 21 | Util.sleepSeconds(4); 22 | 23 | jake.says("Hey!"); 24 | sam.says("I simply wanted to say hi.."); 25 | Util.sleepSeconds(4); 26 | 27 | room.addMember(mike); 28 | mike.says("Hey guys..glad to be here..."); 29 | 30 | 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec12/assignment/SlackMember.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec12.assignment; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import java.util.function.Consumer; 7 | 8 | public class SlackMember { 9 | 10 | private static final Logger log = LoggerFactory.getLogger(SlackMember.class); 11 | 12 | private final String name; 13 | private Consumer messageConsumer; 14 | 15 | public SlackMember(String name) { 16 | this.name = name; 17 | } 18 | 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | public void says(String message){ 24 | this.messageConsumer.accept(message); 25 | } 26 | 27 | void setMessageConsumer(Consumer messageConsumer) { 28 | this.messageConsumer = messageConsumer; 29 | } 30 | 31 | void receives(String message){ 32 | log.info(message); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec12/assignment/SlackMessage.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec12.assignment; 2 | 3 | public record SlackMessage(String sender, 4 | String message) { 5 | 6 | private static final String MESSAGE_FORMAT = "[%s -> %s] : %s"; 7 | 8 | public String formatForDelivery(String receiver){ 9 | return MESSAGE_FORMAT.formatted(sender, receiver, message); 10 | } 11 | 12 | } 13 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec13/Lec01Context.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec13; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Mono; 7 | import reactor.util.context.Context; 8 | 9 | /* 10 | Context is for providing metadata about the request (similar to HTTP headers) 11 | */ 12 | public class Lec01Context { 13 | 14 | private static final Logger log = LoggerFactory.getLogger(Lec01Context.class); 15 | 16 | public static void main(String[] args) { 17 | 18 | getWelcomeMessage() 19 | .contextWrite(Context.of("user", "sam")) 20 | .subscribe(Util.subscriber()); 21 | 22 | } 23 | 24 | private static Mono getWelcomeMessage(){ 25 | return Mono.deferContextual(ctx -> { 26 | if(ctx.hasKey("user")){ 27 | return Mono.just("Welcome %s".formatted(ctx.get("user").toString())); 28 | } 29 | return Mono.error(new RuntimeException("unauthenticated")); 30 | }); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec13/Lec04ContextRateLimiterDemo.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec13; 2 | 3 | import com.vinsguru.common.Util; 4 | import com.vinsguru.sec13.client.ExternalServiceClient; 5 | import reactor.util.context.Context; 6 | 7 | /* 8 | Ensure that the external service is up and running! 9 | */ 10 | public class Lec04ContextRateLimiterDemo { 11 | 12 | public static void main(String[] args) { 13 | 14 | var client = new ExternalServiceClient(); 15 | for (int i = 0; i < 20; i++) { 16 | client.getBook() 17 | .contextWrite(Context.of("user", "mike")) 18 | .subscribe(Util.subscriber()); 19 | Util.sleepSeconds(1); 20 | } 21 | 22 | Util.sleepSeconds(5); 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec13/client/ExternalServiceClient.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec13.client; 2 | 3 | import com.vinsguru.common.AbstractHttpClient; 4 | import reactor.core.publisher.Mono; 5 | 6 | // just for demo 7 | public class ExternalServiceClient extends AbstractHttpClient { 8 | 9 | public Mono getBook() { 10 | return this.httpClient.get() 11 | .uri("/demo07/book") 12 | .responseContent() 13 | .asString() 14 | .startWith(RateLimiter.limitCalls()) 15 | .contextWrite(UserService.userCategoryContext()) 16 | .next(); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/main/java/com/vinsguru/sec13/client/UserService.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.sec13.client; 2 | 3 | import reactor.util.context.Context; 4 | 5 | import java.util.Map; 6 | import java.util.function.Function; 7 | 8 | // just for demo - could be a bean in real life 9 | public class UserService { 10 | 11 | private static final Map USER_CATEGORY = Map.of( 12 | "sam", "standard", 13 | "mike", "prime" 14 | ); 15 | 16 | static Function userCategoryContext() { 17 | return ctx -> ctx.getOrEmpty("user") 18 | .filter(USER_CATEGORY::containsKey) 19 | .map(USER_CATEGORY::get) 20 | .map(category -> ctx.put("category", category)) 21 | .orElse(Context.empty()); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /01-reactive-programming-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 | 12 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/test/java/com/vinsguru/tests/Lec01MonoTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tests; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | import reactor.core.publisher.Mono; 7 | import reactor.test.StepVerifier; 8 | 9 | /* 10 | To write a simple test using StepVerifier. 11 | StepVerifier acts like a subscriber. 12 | */ 13 | public class Lec01MonoTest { 14 | 15 | private static final Logger log = LoggerFactory.getLogger(Lec01MonoTest.class); 16 | 17 | // assume this a method from your service class 18 | private Mono getProduct(int id) { 19 | return Mono.fromSupplier(() -> "product-" + id) 20 | .doFirst(() -> log.info("invoked")); 21 | } 22 | 23 | @Test 24 | public void productTest(){ 25 | StepVerifier.create(getProduct(1)) 26 | .expectNext("product-1") 27 | .expectComplete() 28 | .verify(); // subscribe 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/test/java/com/vinsguru/tests/Lec03FluxTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tests; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import reactor.core.publisher.Flux; 5 | import reactor.test.StepVerifier; 6 | 7 | public class Lec03FluxTest { 8 | 9 | private Flux getItems() { 10 | return Flux.just(1, 2, 3) 11 | .log(); 12 | } 13 | 14 | @Test 15 | public void fluxTest1() { 16 | StepVerifier.create(getItems(), 1) 17 | .expectNext(1) 18 | .thenCancel() 19 | .verify(); 20 | } 21 | 22 | @Test 23 | public void fluxTest2() { 24 | StepVerifier.create(getItems()) 25 | .expectNext(1) 26 | .expectNext(2) 27 | .expectNext(3) 28 | .expectComplete() 29 | .verify(); 30 | } 31 | 32 | @Test 33 | public void fluxTest3() { 34 | StepVerifier.create(getItems()) 35 | .expectNext(1, 2, 3) 36 | .expectComplete() 37 | .verify(); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/test/java/com/vinsguru/tests/Lec05AssertNextTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tests; 2 | 3 | import com.vinsguru.common.Util; 4 | import org.junit.jupiter.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | import reactor.core.publisher.Flux; 7 | import reactor.test.StepVerifier; 8 | 9 | import java.util.Objects; 10 | 11 | /* 12 | "assertNext" is a method in StepVerifier 13 | assertNext = consumeNextWith 14 | We can also collect all the items and test. 15 | */ 16 | public class Lec05AssertNextTest { 17 | 18 | record Book(int id, String author, String title) { 19 | } 20 | 21 | private Flux getBooks() { 22 | return Flux.range(1, 3) 23 | .map(i -> new Book(i, Util.faker().book().author(), Util.faker().book().title())); 24 | } 25 | 26 | @Test 27 | public void assertNextTest() { 28 | StepVerifier.create(getBooks()) 29 | .assertNext(b -> Assertions.assertEquals(1, b.id())) 30 | .thenConsumeWhile(b -> Objects.nonNull(b.title())) 31 | .expectComplete() 32 | .verify(); 33 | } 34 | 35 | @Test 36 | public void collectAllAndTest() { 37 | StepVerifier.create(getBooks().collectList()) 38 | .assertNext(list -> Assertions.assertEquals(3, list.size())) 39 | .expectComplete() 40 | .verify(); 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/test/java/com/vinsguru/tests/Lec07ScenarioNameTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tests; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import reactor.core.publisher.Flux; 5 | import reactor.test.StepVerifier; 6 | import reactor.test.StepVerifierOptions; 7 | 8 | public class Lec07ScenarioNameTest { 9 | 10 | private Flux getItems() { 11 | return Flux.range(1, 3); 12 | } 13 | 14 | @Test 15 | public void scenarioNameTest() { 16 | var options = StepVerifierOptions.create().scenarioName("1 to 3 items test"); 17 | StepVerifier.create(getItems(), options) 18 | .expectNext(1) 19 | .as("first item should be 1") 20 | .expectNext(2, 3) 21 | .as("then 2 and 3") 22 | .expectComplete() 23 | .verify(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/test/java/com/vinsguru/tests/Lec08ContextTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tests; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import reactor.core.publisher.Mono; 5 | import reactor.test.StepVerifier; 6 | import reactor.test.StepVerifierOptions; 7 | import reactor.util.context.Context; 8 | 9 | public class Lec08ContextTest { 10 | 11 | Mono getWelcomeMessage() { 12 | return Mono.deferContextual(ctx -> { 13 | if (ctx.hasKey("user")) { 14 | return Mono.just("Welcome %s".formatted(ctx.get("user").toString())); 15 | } 16 | return Mono.error(new RuntimeException("unauthenticated")); 17 | }); 18 | } 19 | 20 | @Test 21 | public void welcomeMessageTest() { 22 | var options = StepVerifierOptions.create().withInitialContext(Context.of("user", "sam")); 23 | StepVerifier.create(getWelcomeMessage(), options) 24 | .expectNext("Welcome sam") 25 | .expectComplete() 26 | .verify(); 27 | } 28 | 29 | @Test 30 | public void unauthenticatedTest() { 31 | var options = StepVerifierOptions.create().withInitialContext(Context.empty()); 32 | StepVerifier.create(getWelcomeMessage(), options) 33 | .expectErrorMessage("unauthenticated") 34 | .verify(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/test/java/com/vinsguru/tests/Lec09PublisherTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tests; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import reactor.core.publisher.Flux; 5 | import reactor.test.StepVerifier; 6 | import reactor.test.publisher.TestPublisher; 7 | 8 | import java.util.function.UnaryOperator; 9 | 10 | public class Lec09PublisherTest { 11 | 12 | private UnaryOperator> processor() { 13 | return flux -> flux 14 | .filter(s -> s.length() > 1) 15 | .map(String::toUpperCase) 16 | .map(s -> s + ":" + s.length()); 17 | } 18 | 19 | @Test 20 | public void publisherTest1() { 21 | var publisher = TestPublisher.create(); 22 | var flux = publisher.flux(); 23 | 24 | StepVerifier.create(flux.transform(processor())) 25 | .then(() -> publisher.emit("hi", "hello")) 26 | .expectNext("HI:2") 27 | .expectNext("HELLO:5") 28 | .expectComplete() 29 | .verify(); 30 | } 31 | 32 | @Test 33 | public void publisherTest2() { 34 | var publisher = TestPublisher.create(); 35 | var flux = publisher.flux(); 36 | 37 | StepVerifier.create(flux.transform(processor())) 38 | .then(() -> publisher.emit("a", "b", "c")) 39 | .expectComplete() 40 | .verify(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /01-reactive-programming-playground/src/test/java/com/vinsguru/tests/Lec10TimeoutTest.java: -------------------------------------------------------------------------------- 1 | package com.vinsguru.tests; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import reactor.core.publisher.Flux; 5 | import reactor.test.StepVerifier; 6 | 7 | import java.time.Duration; 8 | 9 | public class Lec10TimeoutTest { 10 | 11 | private Flux getItems() { 12 | return Flux.range(1, 5) 13 | .delayElements(Duration.ofMillis(200)); 14 | } 15 | 16 | @Test 17 | public void timeoutTest() { 18 | StepVerifier.create(getItems()) 19 | .expectNext(1, 2, 3, 4, 5) 20 | .expectComplete() 21 | .verify(Duration.ofMillis(1500)); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /02-external-services/external-services-instructions.md: -------------------------------------------------------------------------------- 1 | # External Services 2 | 3 | We will be using below jar file to demonstrate non-blocking HTTP. 4 | 5 | ## How To Run 6 | 7 | - Ensure that you have Java 17 or anything above installed 8 | - Please download [this jar](https://github.com/vinsguru/java-reactive-programming-course/raw/master/02-external-services/external-services.jar) 9 | - Keep the downloaded jar somewhere in your machine 10 | - Open terminal/command line and navigate to the path where you have the jar. 11 | - Run this below command. 12 | 13 | ```bash 14 | java -jar external-services.jar 15 | ``` 16 | - It uses port `7070` by default. 17 | 18 | ## Docker 19 | 20 | If you do not want to run the jar directly on your machine, You can use docker. Build your image and run by doing the port mapping. 21 | ```Dockerfile 22 | FROM bellsoft/liberica-openjdk-alpine:21 23 | WORKDIR app 24 | ADD https://github.com/vinsguru/java-reactive-programming-course/raw/master/02-external-services/external-services.jar external-services.jar 25 | CMD java -jar external-services.jar 26 | ``` 27 | 28 | ## To change the port 29 | 30 | ```bash 31 | java -jar external-services.jar --server.port=8080 32 | ``` 33 | 34 | -------------------------------------------------------------------------------- /02-external-services/external-services.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinsguru/java-reactive-programming-course/054d932072a2982c72f26045a6539b84660cb270/02-external-services/external-services.jar -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/courseutil/DefaultSubscriber.java: -------------------------------------------------------------------------------- 1 | package com.rp.courseutil; 2 | 3 | import org.reactivestreams.Subscriber; 4 | import org.reactivestreams.Subscription; 5 | 6 | public class DefaultSubscriber implements Subscriber { 7 | 8 | private String name = ""; 9 | 10 | public DefaultSubscriber(String name) { 11 | this.name = name + " - "; 12 | } 13 | 14 | public DefaultSubscriber() { 15 | } 16 | 17 | @Override 18 | public void onSubscribe(Subscription subscription) { 19 | subscription.request(Long.MAX_VALUE); 20 | } 21 | 22 | @Override 23 | public void onNext(Object o) { 24 | System.out.println(name + "Received : " + o); 25 | } 26 | 27 | @Override 28 | public void onError(Throwable throwable) { 29 | System.out.println(name + "ERROR : " + throwable.getMessage()); 30 | } 31 | 32 | @Override 33 | public void onComplete() { 34 | System.out.println(name + "Completed"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/courseutil/Util.java: -------------------------------------------------------------------------------- 1 | package com.rp.courseutil; 2 | 3 | import com.github.javafaker.Faker; 4 | import org.reactivestreams.Subscriber; 5 | 6 | import java.util.function.Consumer; 7 | 8 | public class Util { 9 | 10 | private static final Faker FAKER = Faker.instance(); 11 | 12 | public static Consumer onNext(){ 13 | return o -> System.out.println("Received : " + o); 14 | } 15 | 16 | public static Consumer onError(){ 17 | return e -> System.out.println("ERROR : " + e.getMessage()); 18 | } 19 | 20 | public static Runnable onComplete(){ 21 | return () -> System.out.println("Completed"); 22 | } 23 | 24 | public static Faker faker(){ 25 | return FAKER; 26 | } 27 | 28 | public static void sleepSeconds(int seconds){ 29 | sleepMillis(seconds * 1000); 30 | } 31 | 32 | public static void sleepMillis(int millis){ 33 | try { 34 | Thread.sleep(millis); 35 | } catch (InterruptedException e) { 36 | e.printStackTrace(); 37 | } 38 | } 39 | 40 | public static Subscriber subscriber(){ 41 | return new DefaultSubscriber(); 42 | } 43 | 44 | public static Subscriber subscriber(String name){ 45 | return new DefaultSubscriber(name); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec01/Lec01Stream.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec01; 2 | 3 | import java.util.stream.Stream; 4 | 5 | public class Lec01Stream { 6 | 7 | public static void main(String[] args) { 8 | 9 | Stream stream = Stream.of(1) 10 | .map(i -> { 11 | try { 12 | Thread.sleep(1000); 13 | } catch (InterruptedException e) { 14 | e.printStackTrace(); 15 | } 16 | return i * 2; 17 | }); 18 | 19 | //System.out.println(stream); 20 | stream.forEach(System.out::println); 21 | 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec01/Lec02MonoJust.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec01; 2 | 3 | import reactor.core.publisher.Mono; 4 | 5 | public class Lec02MonoJust { 6 | 7 | public static void main(String[] args) { 8 | 9 | // publisher 10 | Mono mono = Mono.just(1); 11 | 12 | System.out.println(mono); 13 | 14 | mono.subscribe(i -> System.out.println("Received : " + i)); 15 | 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec01/Lec03MonoSubscribe.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec01; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Mono; 5 | 6 | public class Lec03MonoSubscribe { 7 | 8 | public static void main(String[] args) { 9 | 10 | // publisher 11 | Mono mono = Mono.just("ball") 12 | .map(String::length) 13 | .map(l -> l / 1); 14 | 15 | // 1 16 | // mono.subscribe(); 17 | 18 | // 2 19 | mono.subscribe( 20 | Util.onNext(), 21 | Util.onError(), 22 | Util.onComplete() 23 | ); 24 | 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec01/Lec04MonoEmptyOrError.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec01; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Mono; 5 | 6 | public class Lec04MonoEmptyOrError { 7 | 8 | public static void main(String[] args) { 9 | 10 | userRepository(20) 11 | .subscribe( 12 | Util.onNext(), 13 | Util.onError(), 14 | Util.onComplete() 15 | ); 16 | 17 | } 18 | 19 | 20 | private static Mono userRepository(int userId){ 21 | // 1 22 | if(userId == 1){ 23 | return Mono.just(Util.faker().name().firstName()); 24 | }else if(userId == 2){ 25 | return Mono.empty(); // null 26 | }else 27 | return Mono.error(new RuntimeException("Not in the allowed range")); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec01/Lec05MonoFromSupplier.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec01; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Mono; 5 | 6 | import java.util.concurrent.Callable; 7 | import java.util.function.Supplier; 8 | 9 | public class Lec05MonoFromSupplier { 10 | 11 | public static void main(String[] args) { 12 | 13 | // use just only when you have data already 14 | // Mono mono = Mono.just(getName()); 15 | 16 | Supplier stringSupplier = () -> getName(); 17 | Mono mono = Mono.fromSupplier(stringSupplier); 18 | mono.subscribe( 19 | Util.onNext() 20 | ); 21 | 22 | Callable stringCallable = () -> getName(); 23 | Mono.fromCallable(stringCallable) 24 | .subscribe( 25 | Util.onNext() 26 | ); 27 | 28 | 29 | } 30 | 31 | private static String getName(){ 32 | System.out.println("Generating name.."); 33 | return Util.faker().name().fullName(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec01/Lec06SupplierRefactoring.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec01; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Mono; 5 | import reactor.core.scheduler.Schedulers; 6 | 7 | public class Lec06SupplierRefactoring { 8 | 9 | public static void main(String[] args) { 10 | 11 | getName(); 12 | String name = getName() 13 | .subscribeOn(Schedulers.boundedElastic()) 14 | .block(); 15 | System.out.println(name); 16 | getName(); 17 | 18 | Util.sleepSeconds(4); 19 | } 20 | 21 | private static Mono getName(){ 22 | System.out.println("entered getName method"); 23 | return Mono.fromSupplier(() -> { 24 | System.out.println("Generating name.."); 25 | Util.sleepSeconds(3); 26 | return Util.faker().name().fullName(); 27 | }).map(String::toUpperCase); 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec01/Lec07MonoFromFuture.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec01; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Mono; 5 | 6 | import java.util.concurrent.CompletableFuture; 7 | 8 | public class Lec07MonoFromFuture { 9 | 10 | public static void main(String[] args) { 11 | 12 | Mono.fromFuture(getName()) 13 | .subscribe(Util.onNext()); 14 | 15 | Util.sleepSeconds(1); 16 | 17 | } 18 | 19 | private static CompletableFuture getName(){ 20 | return CompletableFuture.supplyAsync(() -> Util.faker().name().fullName()); 21 | } 22 | 23 | 24 | } 25 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec01/Lec08MonoFromRunnable.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec01; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Mono; 5 | 6 | public class Lec08MonoFromRunnable { 7 | 8 | public static void main(String[] args) { 9 | 10 | 11 | Mono.fromRunnable(timeConsumingProcess()) 12 | .subscribe(Util.onNext(), 13 | Util.onError(), 14 | () -> { 15 | System.out.println("process is done. Sending emails..."); 16 | }); 17 | 18 | 19 | } 20 | 21 | private static Runnable timeConsumingProcess(){ 22 | return () -> { 23 | Util.sleepSeconds(3); 24 | System.out.println("Operation completed"); 25 | }; 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec01/Lec09AssignmentDemo.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec01; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec01.assignment.FileService; 5 | 6 | public class Lec09AssignmentDemo { 7 | 8 | public static void main(String[] args) { 9 | 10 | FileService.write("file03.txt", "This is file3") 11 | .subscribe(Util.onNext(), Util.onError(), Util.onComplete()); 12 | 13 | FileService.read("file03.txt") 14 | .subscribe(Util.onNext(), Util.onError(), Util.onComplete()); 15 | 16 | FileService.delete("file03.txt") 17 | .subscribe(Util.onNext(), Util.onError(), Util.onComplete()); 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec02/Lec01FluxIntro.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec02; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec01FluxIntro { 7 | 8 | public static void main(String[] args) { 9 | 10 | Flux flux = Flux.just(1,2, 3, "a", Util.faker().name().fullName()); 11 | 12 | flux.subscribe( 13 | Util.onNext(), 14 | Util.onError(), 15 | Util.onComplete()); 16 | 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec02/Lec02MultipleSubscribers.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec02; 2 | 3 | import reactor.core.publisher.Flux; 4 | 5 | public class Lec02MultipleSubscribers { 6 | 7 | public static void main(String[] args) { 8 | 9 | 10 | Flux integerFlux = Flux.just(1, 2, 3, 4); 11 | 12 | Flux evenFlux = integerFlux.filter(i -> i % 2 == 0); 13 | 14 | integerFlux 15 | .subscribe(i -> System.out.println("Sub 1 : " + i)); 16 | 17 | evenFlux 18 | .subscribe(i -> System.out.println("Sub 2 : " + i)); 19 | 20 | 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec02/Lec03FluxFromArrayOrList.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec02; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec03FluxFromArrayOrList { 7 | 8 | public static void main(String[] args) { 9 | 10 | // List strings = Arrays.asList("a", "b", "c"); 11 | /* Flux.fromIterable(strings) 12 | .subscribe(Util.onNext());*/ 13 | 14 | Integer[] arr = { 2, 5, 7, 8}; 15 | Flux.fromArray(arr) 16 | .subscribe(Util.onNext()); 17 | 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec02/Lec04FluxFromStream.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec02; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.util.List; 7 | import java.util.stream.Stream; 8 | 9 | public class Lec04FluxFromStream { 10 | 11 | public static void main(String[] args) { 12 | 13 | List list = List.of(1, 2, 3, 4, 5); 14 | Stream stream = list.stream(); 15 | 16 | // stream.forEach(System.out::println); // closed 17 | // stream.forEach(System.out::println); 18 | 19 | Flux integerFlux = Flux.fromStream(() -> list.stream()); 20 | 21 | integerFlux 22 | .subscribe( 23 | Util.onNext(), 24 | Util.onError(), 25 | Util.onComplete() 26 | ); 27 | 28 | integerFlux 29 | .subscribe( 30 | Util.onNext(), 31 | Util.onError(), 32 | Util.onComplete() 33 | ); 34 | 35 | 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec02/Lec05FluxRange.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec02; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec05FluxRange { 7 | 8 | public static void main(String[] args) { 9 | 10 | Flux.range(3, 10) 11 | .log() 12 | .map(i -> Util.faker().name().fullName()) 13 | .log() 14 | .subscribe( 15 | Util.onNext() 16 | ); 17 | 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec02/Lec07FluxVsList.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec02; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec02.helper.NameGenerator; 5 | 6 | public class Lec07FluxVsList { 7 | 8 | public static void main(String[] args) { 9 | 10 | // List names = NameGenerator.getNames(5); 11 | //System.out.println(names); 12 | 13 | NameGenerator.getNames(5) 14 | .subscribe(Util.onNext()); 15 | 16 | 17 | 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec02/Lec08FluxInterval.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec02; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | public class Lec08FluxInterval { 9 | 10 | public static void main(String[] args) { 11 | 12 | Flux.interval(Duration.ofSeconds(1)) 13 | .subscribe(Util.onNext()); 14 | 15 | Util.sleepSeconds(5); 16 | 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec02/Lec09FluxFromMono.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec02; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec09FluxFromMono { 7 | 8 | public static void main(String[] args) { 9 | 10 | /* Mono mono = Mono.just("a"); 11 | 12 | Flux flux = Flux.from(mono); 13 | 14 | flux.subscribe(Util.onNext());*/ 15 | 16 | Flux.range(1, 10) 17 | .next() // 1 18 | .filter(i -> i > 3) 19 | .subscribe(Util.onNext(), Util.onError(), Util.onComplete()); 20 | 21 | 22 | } 23 | 24 | private static void doSomething(Flux flux){ 25 | 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec02/assignment/StockPricePublisher.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec02.assignment; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | import java.util.concurrent.atomic.AtomicInteger; 8 | 9 | public class StockPricePublisher { 10 | 11 | public static Flux getPrice(){ 12 | AtomicInteger atomicInteger = new AtomicInteger(100); 13 | return Flux.interval(Duration.ofSeconds(1)) 14 | .map(i -> atomicInteger.getAndAccumulate( 15 | Util.faker().random().nextInt(-5, 5), 16 | Integer::sum 17 | )); 18 | } 19 | 20 | 21 | } 22 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec02/helper/NameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec02.helper; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class NameGenerator { 7 | 8 | /* public static List getNames(int count){ 9 | List list = new ArrayList<>(count); 10 | for (int i = 0; i < count; i++) { 11 | list.add(getName()); 12 | } 13 | return list; 14 | }*/ 15 | 16 | public static Flux getNames(int count){ 17 | return Flux.range(0, count) 18 | .map(i -> getName()); 19 | } 20 | 21 | private static String getName(){ 22 | Util.sleepSeconds(1); 23 | return Util.faker().name().fullName(); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec03/Lec01FluxCreate.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec03; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec01FluxCreate { 7 | 8 | public static void main(String[] args) { 9 | 10 | Flux.create(fluxSink -> { 11 | String country; 12 | do{ 13 | country = Util.faker().country().name(); 14 | fluxSink.next(country); 15 | }while (!country.toLowerCase().equals("canada")); 16 | fluxSink.complete(); 17 | }) 18 | .subscribe(Util.subscriber()); 19 | 20 | 21 | 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec03/Lec02FluxCreateRefactoring.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec03; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec03.helper.NameProducer; 5 | import reactor.core.publisher.Flux; 6 | 7 | public class Lec02FluxCreateRefactoring { 8 | 9 | public static void main(String[] args) { 10 | 11 | NameProducer nameProducer = new NameProducer(); 12 | 13 | Flux.create(nameProducer) 14 | .subscribe(Util.subscriber()); 15 | 16 | Runnable runnable = nameProducer::produce; 17 | 18 | for (int i = 0; i < 10; i++) { 19 | new Thread(runnable).start(); 20 | } 21 | 22 | Util.sleepSeconds(2); 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec03/Lec03FluxTake.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec03; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec03FluxTake { 7 | 8 | public static void main(String[] args) { 9 | 10 | // map 11 | // filter 12 | Flux.range(1, 10) 13 | .log() 14 | .take(3) // cancels 15 | .log() 16 | .subscribe(Util.subscriber()); 17 | 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec03/Lec04FluxCreateIssueFix.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec03; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec04FluxCreateIssueFix { 7 | 8 | public static void main(String[] args) { 9 | 10 | // only one instance of fluxsink 11 | Flux.create(fluxSink -> { 12 | String country; 13 | int counter = 0; 14 | do{ 15 | country = Util.faker().country().name(); 16 | System.out.println("emitting : " + country); 17 | fluxSink.next(country); 18 | counter++; 19 | }while (!country.toLowerCase().equals("canada") && !fluxSink.isCancelled() && counter < 10); 20 | fluxSink.complete(); 21 | }) 22 | .take(3) 23 | .subscribe(Util.subscriber()); 24 | 25 | 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec03/Lec05FluxGenerate.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec03; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec05FluxGenerate { 7 | 8 | public static void main(String[] args) { 9 | 10 | Flux.generate(synchronousSink -> { 11 | System.out.println("emitting"); 12 | synchronousSink.next(Util.faker().country().name()); // 1 13 | //synchronousSink.error(new RuntimeException("oops")); 14 | }) 15 | .take(2) 16 | .subscribe(Util.subscriber()); 17 | 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec03/Lec06FluxGenerateAssignment.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec03; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec06FluxGenerateAssignment { 7 | 8 | public static void main(String[] args) { 9 | 10 | // canada 11 | // max = 10 12 | // subscriber cancels - exit 13 | 14 | Flux.generate(synchronousSink -> { 15 | String country = Util.faker().country().name(); 16 | System.out.println("emitting " + country); 17 | synchronousSink.next(country); 18 | if(country.toLowerCase().equals("canada")) 19 | synchronousSink.complete(); 20 | }) 21 | .subscribe(Util.subscriber()); 22 | 23 | 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec03/Lec07FluxGenerateCounter.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec03; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec07FluxGenerateCounter { 7 | 8 | public static void main(String[] args) { 9 | 10 | Flux.generate( 11 | () -> 1, 12 | (counter, sink) -> { 13 | String country = Util.faker().country().name(); 14 | sink.next(country); 15 | if(counter >= 10 || country.toLowerCase().equals("canada") ) 16 | sink.complete(); 17 | return counter + 1; 18 | } 19 | ) 20 | .take(4) 21 | .subscribe(Util.subscriber()); 22 | 23 | 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec03/Lec08FluxPush.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec03; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec03.helper.NameProducer; 5 | import reactor.core.publisher.Flux; 6 | 7 | public class Lec08FluxPush { 8 | 9 | public static void main(String[] args) { 10 | 11 | 12 | NameProducer nameProducer = new NameProducer(); 13 | 14 | Flux.create(nameProducer) 15 | .subscribe(Util.subscriber()); 16 | 17 | Runnable runnable = nameProducer::produce; 18 | 19 | for (int i = 0; i < 10; i++) { 20 | new Thread(runnable).start(); 21 | } 22 | 23 | Util.sleepSeconds(2); 24 | 25 | 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec03/Lec09FileReaderServiceAssignment.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec03; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec03.assignment.FileReaderService; 5 | 6 | import java.nio.file.Path; 7 | import java.nio.file.Paths; 8 | 9 | public class Lec09FileReaderServiceAssignment { 10 | 11 | public static void main(String[] args) { 12 | 13 | FileReaderService readerService = new FileReaderService(); 14 | 15 | Path path = Paths.get("src/main/resources/assignment/sec03/file01.txt"); 16 | readerService.read(path) 17 | .map(s -> { 18 | Integer integer = Util.faker().random().nextInt(0, 10); 19 | if(integer > 8) 20 | throw new RuntimeException("oops"); 21 | return s; 22 | }) 23 | .take(20) 24 | .subscribe(Util.subscriber()); 25 | 26 | 27 | 28 | 29 | 30 | 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec03/helper/NameProducer.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec03.helper; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.FluxSink; 5 | 6 | import java.util.function.Consumer; 7 | 8 | public class NameProducer implements Consumer> { 9 | 10 | private FluxSink fluxSink; 11 | 12 | @Override 13 | public void accept(FluxSink stringFluxSink) { 14 | this.fluxSink = stringFluxSink; 15 | } 16 | 17 | public void produce(){ 18 | String name = Util.faker().name().fullName(); 19 | String thread = Thread.currentThread().getName(); 20 | this.fluxSink.next(thread + " : " + name); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/Lec01Handle.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec01Handle { 7 | 8 | public static void main(String[] args) { 9 | 10 | // handle = filter + map 11 | Flux.range(1, 20) 12 | .handle((integer, synchronousSink) -> { 13 | if(integer == 7) 14 | synchronousSink.complete(); 15 | else 16 | synchronousSink.next(integer); 17 | }) 18 | .subscribe(Util.subscriber()); 19 | 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/Lec02HandleAssignment.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec02HandleAssignment { 7 | 8 | public static void main(String[] args) { 9 | 10 | Flux.generate(synchronousSink -> synchronousSink.next(Util.faker().country().name())) 11 | .map(Object::toString) 12 | .handle((s, synchronousSink) -> { 13 | synchronousSink.next(s); 14 | if(s.toLowerCase().equals("canada")) 15 | synchronousSink.complete(); 16 | }) 17 | .subscribe(Util.subscriber()); 18 | 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/Lec04LimitRate.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec04LimitRate { 7 | 8 | public static void main(String[] args) { 9 | 10 | Flux.range(1, 1000) // 175 11 | .log() 12 | .limitRate(100, 0) // 75% 13 | .subscribe(Util.subscriber()); 14 | 15 | 16 | 17 | } 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/Lec05Delay.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | public class Lec05Delay { 9 | 10 | public static void main(String[] args) { 11 | 12 | System.setProperty("reactor.bufferSize.x", "9"); 13 | 14 | Flux.range(1, 100) // 32 15 | .log() 16 | .delayElements(Duration.ofSeconds(1)) 17 | .subscribe(Util.subscriber()); 18 | 19 | 20 | 21 | Util.sleepSeconds(60); 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/Lec06OnError.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.publisher.Mono; 6 | 7 | public class Lec06OnError { 8 | 9 | public static void main(String[] args) { 10 | 11 | Flux.range(1, 10) 12 | .log() 13 | .map(i -> 10 / (5 - i)) 14 | // .onErrorReturn(-1) 15 | // .onErrorResume(e -> fallback()) 16 | .onErrorContinue((err, obj) -> { 17 | 18 | }) 19 | .subscribe(Util.subscriber()); 20 | 21 | 22 | } 23 | 24 | private static Mono fallback(){ 25 | return Mono.fromSupplier(() -> Util.faker().random().nextInt(100, 200)); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/Lec07Timeout.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | public class Lec07Timeout { 9 | 10 | public static void main(String[] args) { 11 | 12 | getOrderNumbers() 13 | .timeout(Duration.ofSeconds(2), fallback()) 14 | .subscribe(Util.subscriber()); 15 | 16 | 17 | Util.sleepSeconds(60); 18 | 19 | } 20 | 21 | private static Flux getOrderNumbers(){ 22 | return Flux.range(1, 10) 23 | .delayElements(Duration.ofSeconds(5)); 24 | } 25 | 26 | private static Flux fallback(){ 27 | return Flux.range(100, 10) 28 | .delayElements(Duration.ofSeconds(5)); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/Lec08DefaultIfEmpty.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec08DefaultIfEmpty { 7 | 8 | public static void main(String[] args) { 9 | 10 | getOrderNumbers() 11 | .filter(i -> i > 10) 12 | .defaultIfEmpty(-100) 13 | .subscribe(Util.subscriber()); 14 | 15 | } 16 | 17 | private static Flux getOrderNumbers(){ 18 | return Flux.range(1, 12); 19 | } 20 | 21 | 22 | } 23 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/Lec09SwitchIfEmpty.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec09SwitchIfEmpty { 7 | 8 | public static void main(String[] args) { 9 | 10 | getOrderNumbers() 11 | .filter(i -> i > 10) 12 | .switchIfEmpty(fallback()) 13 | .subscribe(Util.subscriber()); 14 | 15 | } 16 | 17 | // redis cache / db 18 | private static Flux getOrderNumbers(){ 19 | return Flux.range(1, 10); 20 | } 21 | 22 | // db // cache 23 | private static Flux fallback(){ 24 | return Flux.range(20, 5); 25 | } 26 | 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/Lec10Transform.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec04.helper.Person; 5 | import reactor.core.publisher.Flux; 6 | 7 | import java.util.function.Function; 8 | 9 | public class Lec10Transform { 10 | 11 | public static void main(String[] args) { 12 | 13 | getPerson() 14 | .transform(applyFilterMap()) 15 | .subscribe(Util.subscriber()); 16 | } 17 | 18 | public static Flux getPerson(){ 19 | return Flux.range(1, 10) 20 | .map(i -> new Person()); 21 | } 22 | 23 | public static Function, Flux> applyFilterMap(){ 24 | return flux -> flux 25 | .filter(p -> p.getAge() > 10) 26 | .doOnNext(p -> p.setName(p.getName().toUpperCase())) 27 | .doOnDiscard(Person.class, p -> System.out.println("Not allowing : " + p)); 28 | } 29 | 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/Lec11SwitchOnFirst.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec04.helper.Person; 5 | import reactor.core.publisher.Flux; 6 | 7 | import java.util.function.Function; 8 | 9 | public class Lec11SwitchOnFirst { 10 | 11 | public static void main(String[] args) { 12 | 13 | getPerson() 14 | .switchOnFirst((signal, personFlux) -> { 15 | System.out.println("inside switch-on-first"); 16 | return signal.isOnNext() && signal.get().getAge() > 10 ? personFlux : applyFilterMap().apply(personFlux); 17 | }) 18 | .subscribe(Util.subscriber()); 19 | } 20 | 21 | public static Flux getPerson(){ 22 | return Flux.range(1, 10) 23 | .map(i -> new Person()); 24 | } 25 | 26 | public static Function, Flux> applyFilterMap(){ 27 | return flux -> flux 28 | .filter(p -> p.getAge() > 10) 29 | .doOnNext(p -> p.setName(p.getName().toUpperCase())) 30 | .doOnDiscard(Person.class, p -> System.out.println("Not allowing : " + p)); 31 | } 32 | 33 | 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/Lec12FlatMap.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec04.helper.OrderService; 5 | import com.rp.sec04.helper.UserService; 6 | 7 | import java.io.BufferedReader; 8 | 9 | public class Lec12FlatMap { 10 | 11 | public static void main(String[] args) { 12 | 13 | BufferedReader reader; 14 | 15 | 16 | UserService.getUsers() 17 | .flatMap(user -> OrderService.getOrders(user.getUserId())) // mono / flux 18 | // .filter(p -> p > 10) 19 | .subscribe(Util.subscriber()); 20 | 21 | 22 | Util.sleepSeconds(60); 23 | 24 | 25 | } 26 | 27 | 28 | } 29 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/helper/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04.helper; 2 | 3 | import reactor.core.publisher.Flux; 4 | import reactor.core.publisher.FluxSink; 5 | 6 | import java.time.Duration; 7 | import java.util.Arrays; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | public class OrderService { 13 | 14 | private static Map> db = new HashMap<>(); 15 | 16 | static { 17 | List list1 = Arrays.asList( 18 | new PurchaseOrder(1), 19 | new PurchaseOrder(1), 20 | new PurchaseOrder(1) 21 | ); 22 | List list2 = Arrays.asList( 23 | new PurchaseOrder(2), 24 | new PurchaseOrder(2) 25 | ); 26 | db.put(1, list1); 27 | db.put(2, list2); 28 | } 29 | 30 | public static Flux getOrders(int userId){ 31 | return Flux.create((FluxSink purchaseOrderFluxSink) -> { 32 | db.get(userId).forEach(purchaseOrderFluxSink::next); 33 | purchaseOrderFluxSink.complete(); 34 | }) 35 | .delayElements(Duration.ofSeconds(1)); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/helper/Person.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04.helper; 2 | 3 | import com.rp.courseutil.Util; 4 | import lombok.Data; 5 | import lombok.ToString; 6 | 7 | @Data 8 | @ToString 9 | public class Person { 10 | 11 | private String name; 12 | private int age; 13 | 14 | public Person(){ 15 | this.name = Util.faker().name().firstName(); 16 | this.age = Util.faker().random().nextInt(1, 30); 17 | } 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/helper/PurchaseOrder.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04.helper; 2 | 3 | import com.rp.courseutil.Util; 4 | import lombok.Data; 5 | import lombok.ToString; 6 | 7 | @Data 8 | @ToString 9 | public class PurchaseOrder { 10 | 11 | private String item; 12 | private String price; 13 | private int userId; 14 | 15 | public PurchaseOrder(int userId) { 16 | this.userId = userId; 17 | this.item = Util.faker().commerce().productName(); 18 | this.price = Util.faker().commerce().price(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/helper/User.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04.helper; 2 | 3 | import com.rp.courseutil.Util; 4 | import lombok.Data; 5 | import lombok.ToString; 6 | 7 | @Data 8 | @ToString 9 | public class User { 10 | 11 | private int userId; 12 | private String name; 13 | 14 | public User(int userId) { 15 | this.userId = userId; 16 | this.name = Util.faker().name().fullName(); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec04/helper/UserService.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec04.helper; 2 | 3 | import reactor.core.publisher.Flux; 4 | 5 | public class UserService { 6 | 7 | public static Flux getUsers(){ 8 | return Flux.range(1, 2) 9 | .map(i -> new User(i)); 10 | } 11 | 12 | 13 | } 14 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec05/Lec01ColdPublisher.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec05; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | import java.util.stream.Stream; 8 | 9 | public class Lec01ColdPublisher { 10 | 11 | public static void main(String[] args) { 12 | 13 | Flux movieStream = Flux.fromStream(() -> getMovie()) 14 | .delayElements(Duration.ofSeconds(2)); 15 | 16 | movieStream 17 | .subscribe(Util.subscriber("sam")); 18 | 19 | Util.sleepSeconds(5); 20 | 21 | movieStream 22 | .subscribe(Util.subscriber("mike")); 23 | 24 | 25 | Util.sleepSeconds(60); 26 | 27 | 28 | } 29 | 30 | // netflix 31 | private static Stream getMovie(){ 32 | System.out.println("Got the movie streaming req"); 33 | return Stream.of( 34 | "Scene 1", 35 | "Scene 2", 36 | "Scene 3", 37 | "Scene 4", 38 | "Scene 5", 39 | "Scene 6", 40 | "Scene 7" 41 | ); 42 | } 43 | 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec05/Lec02HotShare.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec05; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | import java.util.stream.Stream; 8 | 9 | public class Lec02HotShare { 10 | 11 | public static void main(String[] args) { 12 | 13 | Flux movieStream = Flux.fromStream(() -> getMovie()) 14 | .delayElements(Duration.ofSeconds(2)) 15 | .share(); 16 | 17 | movieStream 18 | .subscribe(Util.subscriber("sam")); 19 | 20 | Util.sleepSeconds(5); 21 | 22 | movieStream 23 | .subscribe(Util.subscriber("mike")); 24 | 25 | 26 | Util.sleepSeconds(60); 27 | 28 | 29 | } 30 | 31 | // movie-theatre 32 | private static Stream getMovie(){ 33 | System.out.println("Got the movie streaming req"); 34 | return Stream.of( 35 | "Scene 1", 36 | "Scene 2", 37 | "Scene 3", 38 | "Scene 4", 39 | "Scene 5", 40 | "Scene 6", 41 | "Scene 7" 42 | ); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec05/Lec03HotPublish.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec05; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | import java.util.stream.Stream; 8 | 9 | public class Lec03HotPublish { 10 | 11 | public static void main(String[] args) { 12 | // share = publish().refCount(1) 13 | Flux movieStream = Flux.fromStream(() -> getMovie()) 14 | .delayElements(Duration.ofSeconds(1)) 15 | .publish() 16 | .refCount(1); 17 | 18 | movieStream 19 | .subscribe(Util.subscriber("sam")); 20 | 21 | Util.sleepSeconds(10); 22 | 23 | movieStream 24 | .subscribe(Util.subscriber("mike")); 25 | 26 | 27 | Util.sleepSeconds(60); 28 | 29 | 30 | } 31 | 32 | // movie-theatre 33 | private static Stream getMovie(){ 34 | System.out.println("Got the movie streaming req"); 35 | return Stream.of( 36 | "Scene 1", 37 | "Scene 2", 38 | "Scene 3", 39 | "Scene 4", 40 | "Scene 5", 41 | "Scene 6", 42 | "Scene 7" 43 | ); 44 | } 45 | 46 | 47 | } 48 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec05/Lec04HotPublishAutoConnect.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec05; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | import java.util.stream.Stream; 8 | 9 | public class Lec04HotPublishAutoConnect { 10 | 11 | public static void main(String[] args) { 12 | // share = publish().refCount(1) 13 | Flux movieStream = Flux.fromStream(() -> getMovie()) 14 | .delayElements(Duration.ofSeconds(1)) 15 | .publish() 16 | .autoConnect(0); 17 | 18 | Util.sleepSeconds(3); 19 | 20 | movieStream 21 | .subscribe(Util.subscriber("sam")); 22 | 23 | Util.sleepSeconds(10); 24 | 25 | System.out.println("Mike is about to join"); 26 | 27 | movieStream 28 | .subscribe(Util.subscriber("mike")); 29 | 30 | 31 | Util.sleepSeconds(60); 32 | 33 | 34 | } 35 | 36 | // movie-theatre 37 | private static Stream getMovie(){ 38 | System.out.println("Got the movie streaming req"); 39 | return Stream.of( 40 | "Scene 1", 41 | "Scene 2", 42 | "Scene 3", 43 | "Scene 4", 44 | "Scene 5", 45 | "Scene 6", 46 | "Scene 7" 47 | ); 48 | } 49 | 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec05/Lec05HotPublishCache.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec05; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | import java.util.stream.Stream; 8 | 9 | public class Lec05HotPublishCache { 10 | 11 | public static void main(String[] args) { 12 | // share = publish().refCount(1) 13 | // cache = publish().replay() int.max 14 | Flux movieStream = Flux.fromStream(() -> getMovie()) 15 | .delayElements(Duration.ofSeconds(1)) 16 | .cache(2); 17 | 18 | Util.sleepSeconds(2); 19 | 20 | movieStream 21 | .subscribe(Util.subscriber("sam")); 22 | 23 | Util.sleepSeconds(10); 24 | 25 | System.out.println("Mike is about to join"); 26 | 27 | movieStream 28 | .subscribe(Util.subscriber("mike")); 29 | 30 | 31 | Util.sleepSeconds(60); 32 | 33 | 34 | } 35 | 36 | // movie-theatre 37 | private static Stream getMovie(){ 38 | System.out.println("Got the movie streaming req"); 39 | return Stream.of( 40 | "Scene 1", 41 | "Scene 2", 42 | "Scene 3", 43 | "Scene 4", 44 | "Scene 5", 45 | "Scene 6", 46 | "Scene 7" 47 | ); 48 | } 49 | 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec05/Lec06Assignment.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec05; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec05.assignment.InventoryService; 5 | import com.rp.sec05.assignment.OrderService; 6 | import com.rp.sec05.assignment.RevenueService; 7 | 8 | public class Lec06Assignment { 9 | 10 | public static void main(String[] args) { 11 | 12 | OrderService orderService = new OrderService(); 13 | RevenueService revenueService = new RevenueService(); 14 | InventoryService inventoryService = new InventoryService(); 15 | 16 | // revenue and inv - observe the order stream 17 | orderService.orderStream().subscribe(revenueService.subscribeOrderStream()); 18 | orderService.orderStream().subscribe(inventoryService.subscribeOrderStream()); 19 | 20 | inventoryService.inventoryStream() 21 | 22 | .subscribe(Util.subscriber("inventory")); 23 | 24 | revenueService.revenueStream() 25 | .subscribe(Util.subscriber("revenue")); 26 | 27 | Util.sleepSeconds(60); 28 | 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec05/assignment/InventoryService.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec05.assignment; 2 | 3 | import reactor.core.publisher.Flux; 4 | 5 | import java.time.Duration; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.function.Consumer; 9 | 10 | public class InventoryService { 11 | 12 | private Map db = new HashMap<>(); 13 | 14 | public InventoryService(){ 15 | db.put("Kids", 100); 16 | db.put("Automotive", 100); 17 | } 18 | 19 | public Consumer subscribeOrderStream(){ 20 | return p -> db.computeIfPresent(p.getCategory(), (k, v) -> v - p.getQuantity()); 21 | } 22 | 23 | public Flux inventoryStream(){ 24 | return Flux.interval(Duration.ofSeconds(2)) 25 | .map(i -> db.toString()); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec05/assignment/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec05.assignment; 2 | 3 | import reactor.core.publisher.Flux; 4 | 5 | import java.time.Duration; 6 | import java.util.Objects; 7 | 8 | public class OrderService { 9 | 10 | private Flux flux; 11 | 12 | public Flux orderStream(){ 13 | if(Objects.isNull(flux)) 14 | flux=getOrderStream(); 15 | return flux; 16 | } 17 | 18 | private Flux getOrderStream(){ 19 | return Flux.interval(Duration.ofMillis(100)) 20 | .map(i -> new PurchaseOrder()) 21 | .publish() 22 | .refCount(2); 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec05/assignment/PurchaseOrder.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec05.assignment; 2 | 3 | import com.rp.courseutil.Util; 4 | import lombok.Data; 5 | import lombok.ToString; 6 | 7 | @Data 8 | @ToString 9 | public class PurchaseOrder { 10 | 11 | private String item; 12 | private double price; 13 | private String category; 14 | private int quantity; 15 | 16 | public PurchaseOrder() { 17 | this.item = Util.faker().commerce().productName(); 18 | this.price = Double.parseDouble(Util.faker().commerce().price()); 19 | this.category = Util.faker().commerce().department(); 20 | this.quantity = Util.faker().random().nextInt(1, 10); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec05/assignment/RevenueService.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec05.assignment; 2 | 3 | import reactor.core.publisher.Flux; 4 | 5 | import java.time.Duration; 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | import java.util.function.Consumer; 9 | 10 | public class RevenueService { 11 | 12 | private Map db = new HashMap<>(); 13 | 14 | public RevenueService(){ 15 | db.put("Kids", 0.0); 16 | db.put("Automotive", 0.0); 17 | } 18 | 19 | public Consumer subscribeOrderStream(){ 20 | return p -> db.computeIfPresent(p.getCategory(), (k, v) -> v + p.getPrice()); 21 | } 22 | 23 | public Flux revenueStream(){ 24 | return Flux.interval(Duration.ofSeconds(2)) 25 | .map(i -> db.toString()); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec06/Lec01ThreadDemo.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec06; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec01ThreadDemo { 7 | 8 | public static void main(String[] args) { 9 | 10 | Flux flux = Flux.create(fluxSink -> { 11 | printThreadName("create"); 12 | fluxSink.next(1); 13 | }) 14 | .doOnNext(i -> printThreadName("next " + i)); 15 | 16 | 17 | Runnable runnable = () -> flux.subscribe(v -> printThreadName("sub " + v)); 18 | 19 | for (int i = 0; i < 2; i++) { 20 | new Thread(runnable).start(); 21 | } 22 | 23 | Util.sleepSeconds(5); 24 | 25 | } 26 | 27 | private static void printThreadName(String msg){ 28 | System.out.println(msg + "\t\t: Thread : " + Thread.currentThread().getName()); 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec06/Lec02SubscribeOnDemo.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec06; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.scheduler.Schedulers; 6 | 7 | public class Lec02SubscribeOnDemo { 8 | 9 | public static void main(String[] args) { 10 | 11 | Flux flux = Flux.create(fluxSink -> { 12 | printThreadName("create"); 13 | fluxSink.next(1); 14 | }) 15 | .subscribeOn(Schedulers.newParallel("vins")) 16 | .doOnNext(i -> printThreadName("next " + i)); 17 | 18 | 19 | Runnable runnable = () -> flux 20 | .doFirst(() -> printThreadName("first2")) 21 | .subscribeOn(Schedulers.boundedElastic()) 22 | .doFirst(() -> printThreadName("first1")) 23 | .subscribe(v -> printThreadName("sub " + v)); 24 | 25 | for (int i = 0; i < 2; i++) { 26 | new Thread(runnable).start(); 27 | } 28 | 29 | Util.sleepSeconds(5); 30 | 31 | } 32 | 33 | private static void printThreadName(String msg){ 34 | System.out.println(msg + "\t\t: Thread : " + Thread.currentThread().getName()); 35 | } 36 | 37 | 38 | } 39 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec06/Lec03SubscribeOnMultipleItems.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec06; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.scheduler.Schedulers; 6 | 7 | public class Lec03SubscribeOnMultipleItems { 8 | 9 | public static void main(String[] args) { 10 | 11 | Flux flux = Flux.create(fluxSink -> { 12 | printThreadName("create"); 13 | for (int i = 0; i < 4; i++) { 14 | fluxSink.next(i); 15 | Util.sleepSeconds(1); 16 | } 17 | fluxSink.complete(); 18 | }) 19 | .doOnNext(i -> printThreadName("next " + i)); 20 | 21 | 22 | flux 23 | .subscribeOn(Schedulers.boundedElastic()) 24 | .subscribe(v -> printThreadName("sub " + v)); 25 | 26 | flux 27 | .subscribeOn(Schedulers.parallel()) 28 | .subscribe(v -> printThreadName("sub " + v)); 29 | 30 | Util.sleepSeconds(5); 31 | 32 | } 33 | 34 | private static void printThreadName(String msg){ 35 | System.out.println(msg + "\t\t: Thread : " + Thread.currentThread().getName()); 36 | } 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec06/Lec04PublishOn.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec06; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.scheduler.Schedulers; 6 | 7 | public class Lec04PublishOn { 8 | 9 | public static void main(String[] args) { 10 | 11 | Flux flux = Flux.create(fluxSink -> { 12 | printThreadName("create"); 13 | for (int i = 0; i < 4; i++) { 14 | fluxSink.next(i); 15 | } 16 | fluxSink.complete(); 17 | }) 18 | .doOnNext(i -> printThreadName("next " + i)); 19 | 20 | 21 | flux 22 | .publishOn(Schedulers.boundedElastic()) 23 | .doOnNext(i -> printThreadName("next " + i)) 24 | .publishOn(Schedulers.parallel()) 25 | .subscribe(v -> printThreadName("sub " + v)); 26 | 27 | 28 | Util.sleepSeconds(5); 29 | 30 | } 31 | 32 | private static void printThreadName(String msg){ 33 | System.out.println(msg + "\t\t: Thread : " + Thread.currentThread().getName()); 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec06/Lec05PubSubOn.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec06; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.scheduler.Schedulers; 6 | 7 | public class Lec05PubSubOn { 8 | 9 | public static void main(String[] args) { 10 | 11 | Flux flux = Flux.create(fluxSink -> { 12 | printThreadName("create"); 13 | for (int i = 0; i < 4; i++) { 14 | fluxSink.next(i); 15 | } 16 | fluxSink.complete(); 17 | }) 18 | .doOnNext(i -> printThreadName("next " + i)); 19 | 20 | 21 | flux 22 | .publishOn(Schedulers.parallel()) 23 | .doOnNext(i -> printThreadName("next " + i)) 24 | .subscribeOn(Schedulers.boundedElastic()) 25 | .subscribe(v -> printThreadName("sub " + v)); 26 | 27 | 28 | Util.sleepSeconds(5); 29 | 30 | } 31 | 32 | private static void printThreadName(String msg){ 33 | System.out.println(msg + "\t\t: Thread : " + Thread.currentThread().getName()); 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec06/Lec06Parallel.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec06; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.scheduler.Schedulers; 6 | 7 | public class Lec06Parallel { 8 | 9 | public static void main(String[] args) { 10 | 11 | 12 | Flux.range(1, 10) 13 | .parallel(10) 14 | .runOn(Schedulers.boundedElastic()) 15 | .doOnNext(i -> printThreadName("next " + i)) 16 | .sequential() 17 | .subscribe(v -> printThreadName("sub " + v)); 18 | 19 | 20 | Util.sleepSeconds(5); 21 | 22 | } 23 | 24 | private static void printThreadName(String msg){ 25 | System.out.println(msg + "\t\t: Thread : " + Thread.currentThread().getName()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec06/Lec07FluxInterval.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec06; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | public class Lec07FluxInterval { 9 | 10 | public static void main(String[] args) { 11 | 12 | Flux.range(1, 10) 13 | .delayElements(Duration.ofSeconds(1)) 14 | .log() 15 | .subscribe(Util.subscriber()); 16 | 17 | 18 | Util.sleepSeconds(60); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec07/Lec01Demo.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec07; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.scheduler.Schedulers; 6 | 7 | public class Lec01Demo { 8 | 9 | public static void main(String[] args) { 10 | 11 | 12 | Flux.create(fluxSink -> { 13 | for (int i = 1; i < 501; i++) { 14 | fluxSink.next(i); 15 | System.out.println("Pushed : " + i); 16 | } 17 | fluxSink.complete(); 18 | }) 19 | .publishOn(Schedulers.boundedElastic()) 20 | .doOnNext(i -> { 21 | Util.sleepMillis(10); 22 | }) 23 | .subscribe(Util.subscriber()); 24 | 25 | 26 | Util.sleepSeconds(60); 27 | 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec07/Lec02Drop.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec07; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.scheduler.Schedulers; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | 11 | public class Lec02Drop { 12 | 13 | public static void main(String[] args) { 14 | // 75% 12 15 | System.setProperty("reactor.bufferSize.small", "16"); 16 | 17 | List list = new ArrayList<>(); 18 | 19 | Flux.create(fluxSink -> { 20 | for (int i = 1; i < 201; i++) { 21 | fluxSink.next(i); 22 | System.out.println("Pushed : " + i); 23 | Util.sleepMillis(1); 24 | } 25 | fluxSink.complete(); 26 | }) 27 | .onBackpressureDrop(list::add) 28 | .publishOn(Schedulers.boundedElastic()) 29 | .doOnNext(i -> { 30 | Util.sleepMillis(10); 31 | }) 32 | .subscribe(Util.subscriber()); 33 | 34 | 35 | Util.sleepSeconds(10); 36 | System.out.println(list); 37 | 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec07/Lec03Latest.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec07; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.scheduler.Schedulers; 6 | 7 | public class Lec03Latest { 8 | 9 | public static void main(String[] args) { 10 | // 75% 12 11 | System.setProperty("reactor.bufferSize.small", "16"); 12 | 13 | Flux.create(fluxSink -> { 14 | for (int i = 1; i < 201; i++) { 15 | fluxSink.next(i); 16 | System.out.println("Pushed : " + i); 17 | Util.sleepMillis(1); 18 | } 19 | fluxSink.complete(); 20 | }) 21 | .onBackpressureLatest() 22 | .publishOn(Schedulers.boundedElastic()) 23 | .doOnNext(i -> { 24 | Util.sleepMillis(10); 25 | }) 26 | .subscribe(Util.subscriber()); 27 | 28 | 29 | Util.sleepSeconds(10); 30 | 31 | 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec07/Lec04Error.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec07; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.scheduler.Schedulers; 6 | 7 | public class Lec04Error { 8 | 9 | public static void main(String[] args) { 10 | // 75% 12 11 | System.setProperty("reactor.bufferSize.small", "16"); 12 | 13 | Flux.create(fluxSink -> { 14 | for (int i = 1; i < 201 && !fluxSink.isCancelled(); i++) { 15 | fluxSink.next(i); 16 | System.out.println("Pushed : " + i); 17 | Util.sleepMillis(1); 18 | } 19 | fluxSink.complete(); 20 | }) 21 | .onBackpressureError() 22 | .publishOn(Schedulers.boundedElastic()) 23 | 24 | .doOnNext(i -> { 25 | Util.sleepMillis(10); 26 | }) 27 | .subscribe(Util.subscriber()); 28 | 29 | 30 | Util.sleepSeconds(10); 31 | 32 | 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec07/Lec05BufferWithSize.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec07; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.scheduler.Schedulers; 6 | 7 | public class Lec05BufferWithSize { 8 | 9 | public static void main(String[] args) { 10 | // 75% 12 11 | System.setProperty("reactor.bufferSize.small", "16"); 12 | 13 | Flux.create(fluxSink -> { 14 | for (int i = 1; i < 201 && !fluxSink.isCancelled(); i++) { 15 | fluxSink.next(i); 16 | System.out.println("Pushed : " + i); 17 | Util.sleepMillis(1); 18 | } 19 | fluxSink.complete(); 20 | }) 21 | .onBackpressureBuffer(50, o -> System.out.println("Dropped : "+ o)) 22 | .publishOn(Schedulers.boundedElastic()) 23 | 24 | .doOnNext(i -> { 25 | Util.sleepMillis(10); 26 | }) 27 | .subscribe(Util.subscriber()); 28 | 29 | 30 | Util.sleepSeconds(10); 31 | 32 | 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec08/Lec01StartWith.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec08; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec08.helper.NameGenerator; 5 | 6 | public class Lec01StartWith { 7 | 8 | public static void main(String[] args) { 9 | 10 | 11 | NameGenerator generator = new NameGenerator(); 12 | generator.generateNames() 13 | .take(2) 14 | .subscribe(Util.subscriber("sam")); 15 | 16 | generator.generateNames() 17 | .take(2) 18 | .subscribe(Util.subscriber("mike")); 19 | 20 | generator.generateNames() 21 | .take(3) 22 | .subscribe(Util.subscriber("Jake")); 23 | 24 | generator.generateNames() 25 | .filter(n -> n.startsWith("A")) 26 | .take(2) 27 | .subscribe(Util.subscriber("Marshal")); 28 | 29 | 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec08/Lec02Concat.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec08; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec02Concat { 7 | 8 | public static void main(String[] args) { 9 | 10 | Flux flux1 = Flux.just("a", "b"); 11 | Flux flux2 = Flux.error(new RuntimeException("oops")); 12 | Flux flux3 = Flux.just("c", "d", "e"); 13 | 14 | 15 | Flux flux = Flux.concatDelayError(flux1, flux2, flux3); 16 | 17 | 18 | flux.subscribe(Util.subscriber()); 19 | 20 | 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec08/Lec03Merge.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec08; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec08.helper.AmericanAirlines; 5 | import com.rp.sec08.helper.Emirates; 6 | import com.rp.sec08.helper.Qatar; 7 | import reactor.core.publisher.Flux; 8 | 9 | public class Lec03Merge { 10 | 11 | public static void main(String[] args) { 12 | 13 | Flux merge = Flux.merge( 14 | Qatar.getFlights(), 15 | Emirates.getFlights(), 16 | AmericanAirlines.getFlights() 17 | ); 18 | 19 | merge.subscribe(Util.subscriber()); 20 | 21 | Util.sleepSeconds(10); 22 | 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec08/Lec04Zip.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec08; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | public class Lec04Zip { 7 | 8 | public static void main(String[] args) { 9 | Flux.zip(getBody(), getEngine(), getTires()) 10 | .subscribe(Util.subscriber()); 11 | 12 | } 13 | 14 | private static Flux getBody(){ 15 | return Flux.range(1, 5) 16 | .map(i -> "body"); 17 | } 18 | 19 | private static Flux getEngine(){ 20 | return Flux.range(1, 3) 21 | .map(i -> "engine"); 22 | } 23 | 24 | private static Flux getTires(){ 25 | return Flux.range(1, 6) 26 | .map(i -> "tires"); 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec08/Lec05CombineLatest.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec08; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | public class Lec05CombineLatest { 9 | 10 | public static void main(String[] args) { 11 | 12 | Flux.combineLatest(getString(), getNumber(), (s, i) -> s+i) 13 | .subscribe(Util.subscriber()); 14 | 15 | Util.sleepSeconds(10); 16 | 17 | } 18 | 19 | private static Flux getString(){ 20 | return Flux.just("A", "B", "C", "D") 21 | .delayElements(Duration.ofSeconds(1)); 22 | } 23 | 24 | private static Flux getNumber(){ 25 | return Flux.just(1, 2, 3) 26 | .delayElements(Duration.ofSeconds(3)); 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec08/Lec06Assignment.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec08; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | public class Lec06Assignment { 9 | 10 | public static void main(String[] args) { 11 | 12 | final int carPrice = 10000; 13 | Flux.combineLatest(monthStream(), demandStream(), (month, demand) -> { 14 | return (carPrice - (month * 100)) * demand; 15 | }) 16 | .subscribe(Util.subscriber()); 17 | 18 | 19 | Util.sleepSeconds(20); 20 | 21 | } 22 | 23 | 24 | private static Flux monthStream(){ 25 | return Flux.interval(Duration.ZERO, Duration.ofSeconds(1)); 26 | } 27 | 28 | private static Flux demandStream(){ 29 | return Flux.interval(Duration.ofSeconds(3)) 30 | .map(i -> Util.faker().random().nextInt(80, 120) / 100d) 31 | .startWith(1d); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec08/helper/AmericanAirlines.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec08.helper; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | public class AmericanAirlines { 9 | 10 | public static Flux getFlights(){ 11 | return Flux.range(1, Util.faker().random().nextInt(1, 10)) 12 | .delayElements(Duration.ofSeconds(1)) 13 | .map(i -> "AA " + Util.faker().random().nextInt(100, 999)) 14 | .filter(i -> Util.faker().random().nextBoolean()); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec08/helper/Emirates.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec08.helper; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | public class Emirates { 9 | 10 | public static Flux getFlights(){ 11 | return Flux.range(1, Util.faker().random().nextInt(1, 10)) 12 | .delayElements(Duration.ofSeconds(1)) 13 | .map(i -> "Emirates " + Util.faker().random().nextInt(100, 999)) 14 | .filter(i -> Util.faker().random().nextBoolean()); 15 | } 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec08/helper/NameGenerator.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec08.helper; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class NameGenerator { 10 | 11 | private List list = new ArrayList<>(); 12 | 13 | public Flux generateNames(){ 14 | return Flux.generate(stringSynchronousSink -> { 15 | System.out.println("generated fresh"); 16 | Util.sleepSeconds(1); 17 | String name = Util.faker().name().firstName(); 18 | list.add(name); 19 | stringSynchronousSink.next(name); 20 | }) 21 | .cast(String.class) 22 | .startWith(getFromCache()); 23 | } 24 | 25 | private Flux getFromCache(){ 26 | return Flux.fromIterable(list); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec08/helper/Qatar.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec08.helper; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | public class Qatar { 9 | 10 | public static Flux getFlights(){ 11 | return Flux.range(1, Util.faker().random().nextInt(1, 5)) 12 | .delayElements(Duration.ofSeconds(1)) 13 | .map(i -> "Qatar " + Util.faker().random().nextInt(100, 999)) 14 | .filter(i -> Util.faker().random().nextBoolean()); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec09/Lec01Buffer.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec09; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | public class Lec01Buffer { 9 | 10 | public static void main(String[] args) { 11 | 12 | eventStream() 13 | .bufferTimeout(5, Duration.ofSeconds(2)) 14 | .subscribe(Util.subscriber()); 15 | 16 | Util.sleepSeconds(60); 17 | 18 | } 19 | 20 | 21 | private static Flux eventStream(){ 22 | return Flux.interval(Duration.ofMillis(800)) 23 | .map(i -> "event"+i); 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec09/Lec02OverlapAndDrop.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec09; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | public class Lec02OverlapAndDrop { 9 | 10 | public static void main(String[] args) { 11 | 12 | eventStream() 13 | .buffer(3, 5) 14 | .subscribe(Util.subscriber()); 15 | 16 | Util.sleepSeconds(60); 17 | 18 | } 19 | 20 | 21 | private static Flux eventStream(){ 22 | return Flux.interval(Duration.ofMillis(300)) 23 | .map(i -> "event"+i); 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec09/Lec04Window.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec09; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.publisher.Mono; 6 | 7 | import java.time.Duration; 8 | import java.util.concurrent.atomic.AtomicInteger; 9 | 10 | public class Lec04Window { 11 | 12 | private static AtomicInteger atomicInteger = new AtomicInteger(1); 13 | 14 | public static void main(String[] args) { 15 | 16 | eventStream() 17 | .window(3) 18 | .flatMap(flux -> saveEvents(flux)) 19 | .subscribe(Util.subscriber()); 20 | 21 | Util.sleepSeconds(60); 22 | 23 | } 24 | 25 | private static Flux eventStream(){ 26 | return Flux.interval(Duration.ofMillis(500)) 27 | .map(i -> "event"+i); 28 | } 29 | 30 | private static Mono saveEvents(Flux flux){ 31 | return flux 32 | .doOnNext(e -> System.out.println("saving " + e)) 33 | .doOnComplete(() -> { 34 | System.out.println("saved this batch"); 35 | System.out.println("-------------------"); 36 | }) 37 | .then(Mono.just(atomicInteger.getAndIncrement())); 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec09/Lec05Group.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec09; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.time.Duration; 7 | 8 | public class Lec05Group { 9 | 10 | public static void main(String[] args) { 11 | 12 | 13 | Flux.range(1, 30) 14 | .delayElements(Duration.ofSeconds(1)) 15 | .groupBy(i -> i % 2) // key 0, 1 16 | .subscribe(gf -> process(gf, gf.key())); 17 | 18 | 19 | Util.sleepSeconds(60); 20 | 21 | } 22 | 23 | private static void process(Flux flux , int key){ 24 | System.out.println("Called"); 25 | flux.subscribe(i -> System.out.println("Key : " + key + ", Item : " + i)); 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec09/Lec06Assignment.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec09; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec09.assignment.OrderProcessor; 5 | import com.rp.sec09.assignment.OrderService; 6 | import com.rp.sec09.assignment.PurchaseOrder; 7 | import reactor.core.publisher.Flux; 8 | 9 | import java.util.Map; 10 | import java.util.Set; 11 | import java.util.function.Function; 12 | 13 | public class Lec06Assignment { 14 | 15 | public static void main(String[] args) { 16 | 17 | Map, Flux>> map = Map.of( 18 | "Kids", OrderProcessor.kidsProcessing(), 19 | "Automotive", OrderProcessor.automotiveProcessing() 20 | ); 21 | 22 | Set set = map.keySet(); 23 | 24 | OrderService.orderStream() 25 | .filter(p -> set.contains(p.getCategory())) 26 | .groupBy(PurchaseOrder::getCategory) // 2 keys 27 | .flatMap(gf -> map.get(gf.key()).apply(gf)) //flux 28 | .subscribe(Util.subscriber()); 29 | 30 | Util.sleepSeconds(60); 31 | 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec09/assignment/OrderProcessor.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec09.assignment; 2 | 3 | import reactor.core.publisher.Flux; 4 | import reactor.core.publisher.Mono; 5 | 6 | import java.util.function.Function; 7 | 8 | public class OrderProcessor { 9 | 10 | public static Function, Flux> automotiveProcessing() { 11 | return flux -> flux 12 | .doOnNext(p -> p.setPrice(1.1 * p.getPrice())) 13 | .doOnNext(p -> p.setItem("{{ " + p.getItem() + " }}")); 14 | } 15 | 16 | public static Function, Flux> kidsProcessing() { 17 | return flux -> flux 18 | .doOnNext(p -> p.setPrice(0.5 * p.getPrice())) 19 | .flatMap(p -> Flux.concat(Mono.just(p), getFreeKidsOrder())); 20 | } 21 | 22 | private static Mono getFreeKidsOrder(){ 23 | return Mono.fromSupplier(() -> { 24 | PurchaseOrder purchaseOrder = new PurchaseOrder(); 25 | purchaseOrder.setItem("FREE - " + purchaseOrder.getItem()); 26 | purchaseOrder.setPrice(0); 27 | purchaseOrder.setCategory("Kids"); 28 | return purchaseOrder; 29 | }); 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec09/assignment/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec09.assignment; 2 | 3 | import reactor.core.publisher.Flux; 4 | 5 | import java.time.Duration; 6 | 7 | public class OrderService { 8 | 9 | public static Flux orderStream(){ 10 | return Flux.interval(Duration.ofMillis(100)) 11 | .map(i -> new PurchaseOrder()); 12 | } 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec09/assignment/PurchaseOrder.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec09.assignment; 2 | 3 | import com.rp.courseutil.Util; 4 | import lombok.Data; 5 | import lombok.ToString; 6 | 7 | @Data 8 | @ToString 9 | public class PurchaseOrder { 10 | 11 | private String item; 12 | private double price; 13 | private String category; 14 | 15 | public PurchaseOrder() { 16 | this.item = Util.faker().commerce().productName(); 17 | this.price = Double.parseDouble(Util.faker().commerce().price()); 18 | this.category = Util.faker().commerce().department(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec09/helper/BookOrder.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec09.helper; 2 | 3 | import com.github.javafaker.Book; 4 | import com.rp.courseutil.Util; 5 | import lombok.Getter; 6 | import lombok.ToString; 7 | 8 | @Getter 9 | @ToString 10 | public class BookOrder { 11 | 12 | private String title; 13 | private String author; 14 | private String category; 15 | private double price; 16 | 17 | public BookOrder() { 18 | Book book = Util.faker().book(); 19 | this.title = book.title(); 20 | this.author = book.author(); 21 | this.category = book.genre(); 22 | this.price = Double.parseDouble(Util.faker().commerce().price()); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec09/helper/RevenueReport.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec09.helper; 2 | 3 | import lombok.ToString; 4 | 5 | import java.time.LocalDateTime; 6 | import java.util.Map; 7 | 8 | @ToString 9 | public class RevenueReport { 10 | 11 | private LocalDateTime localDateTime = LocalDateTime.now(); 12 | private Map revenue; 13 | 14 | public RevenueReport(Map revenue) { 15 | this.revenue = revenue; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec10/Lec01Repeat.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec10; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | public class Lec01Repeat { 9 | 10 | private static AtomicInteger atomicInteger = new AtomicInteger(1); 11 | 12 | public static void main(String[] args) { 13 | 14 | getIntegers() 15 | .repeat(() -> atomicInteger.get() < 14) 16 | .subscribe(Util.subscriber()); 17 | 18 | 19 | } 20 | 21 | 22 | private static Flux getIntegers(){ 23 | return Flux.range(1, 3) 24 | .doOnSubscribe(s -> System.out.println("Subscribed")) 25 | .doOnComplete(() -> System.out.println("--Completed")) 26 | .map(i -> atomicInteger.getAndIncrement()); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec10/Lec02Retry.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec10; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | public class Lec02Retry { 9 | 10 | private static AtomicInteger atomicInteger = new AtomicInteger(1); 11 | 12 | public static void main(String[] args) { 13 | 14 | getIntegers() 15 | .retry(2) 16 | .subscribe(Util.subscriber()); 17 | 18 | 19 | } 20 | 21 | private static Flux getIntegers(){ 22 | return Flux.range(1, 3) 23 | .doOnSubscribe(s -> System.out.println("Subscribed")) 24 | .doOnComplete(() -> System.out.println("--Completed")) 25 | .map(i -> i / (Util.faker().random().nextInt(1, 5) > 3 ? 0 : 1)) 26 | .doOnError(err -> System.out.println("--error")); 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec10/Lec03RetryWhen.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec10; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.util.retry.Retry; 6 | 7 | import java.time.Duration; 8 | 9 | public class Lec03RetryWhen { 10 | 11 | public static void main(String[] args) { 12 | 13 | getIntegers() 14 | .retryWhen(Retry.fixedDelay(2, Duration.ofSeconds(3))) 15 | .subscribe(Util.subscriber()); 16 | 17 | Util.sleepSeconds(60); 18 | } 19 | 20 | private static Flux getIntegers(){ 21 | return Flux.range(1, 3) 22 | .doOnSubscribe(s -> System.out.println("Subscribed")) 23 | .doOnComplete(() -> System.out.println("--Completed")) 24 | .map(i -> i / (Util.faker().random().nextInt(1, 5) > 3 ? 0 : 1)) 25 | .doOnError(err -> System.out.println("--error")); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec11/Lec01SinkOne.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec11; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Mono; 5 | import reactor.core.publisher.Sinks; 6 | 7 | public class Lec01SinkOne { 8 | 9 | public static void main(String[] args) { 10 | 11 | // mono 1 value / empty / error 12 | Sinks.One sink = Sinks.one(); 13 | 14 | Mono mono = sink.asMono(); 15 | 16 | mono.subscribe(Util.subscriber("sam")); 17 | mono.subscribe(Util.subscriber("mike")); 18 | 19 | /* sink.emitValue("hi", (signalType, emitResult) -> { 20 | System.out.println(signalType.name()); 21 | System.out.println(emitResult.name()); 22 | return false; 23 | }); 24 | 25 | sink.emitValue("hello", (signalType, emitResult) -> { 26 | System.out.println(signalType.name()); 27 | System.out.println(emitResult.name()); 28 | return false; 29 | });*/ 30 | 31 | sink.tryEmitValue("Hello"); 32 | 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec11/Lec02SinkUnicast.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec11; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.publisher.Sinks; 6 | 7 | public class Lec02SinkUnicast { 8 | 9 | public static void main(String[] args) { 10 | 11 | // handle through which we would push items 12 | Sinks.Many sink = Sinks.many().unicast().onBackpressureBuffer(); 13 | 14 | // handle through which subscribers will receive items 15 | Flux flux = sink.asFlux(); 16 | 17 | flux.subscribe(Util.subscriber("sam")); 18 | flux.subscribe(Util.subscriber("mike")); 19 | 20 | sink.tryEmitNext("hi"); 21 | sink.tryEmitNext("how are you"); 22 | sink.tryEmitNext("?"); 23 | 24 | 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec11/Lec03SinkThreadSafety.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec11; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.publisher.Sinks; 6 | 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | import java.util.concurrent.CompletableFuture; 10 | 11 | public class Lec03SinkThreadSafety { 12 | 13 | public static void main(String[] args) { 14 | 15 | 16 | // handle through which we would push items 17 | Sinks.Many sink = Sinks.many().unicast().onBackpressureBuffer(); 18 | 19 | // handle through which subscribers will receive items 20 | Flux flux = sink.asFlux(); 21 | List list = new ArrayList<>(); 22 | 23 | flux.subscribe(list::add); 24 | 25 | /* for (int i = 0; i < 1000; i++) { 26 | final int j = i; 27 | CompletableFuture.runAsync(() -> { 28 | sink.tryEmitNext(j); 29 | }); 30 | }*/ 31 | 32 | for (int i = 0; i < 1000; i++) { 33 | final int j = i; 34 | CompletableFuture.runAsync(() -> { 35 | sink.emitNext(j, (s, e) -> true); 36 | }); 37 | } 38 | 39 | Util.sleepSeconds(3); 40 | System.out.println(list.size()); 41 | 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec11/Lec04SinkMulti.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec11; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.publisher.Sinks; 6 | 7 | public class Lec04SinkMulti { 8 | 9 | public static void main(String[] args) { 10 | 11 | // handle through which we would push items 12 | Sinks.Many sink = Sinks.many().multicast().onBackpressureBuffer(); 13 | 14 | // handle through which subscribers will receive items 15 | Flux flux = sink.asFlux(); 16 | 17 | 18 | 19 | sink.tryEmitNext("hi"); 20 | sink.tryEmitNext("how are you"); 21 | 22 | flux.subscribe(Util.subscriber("sam")); 23 | flux.subscribe(Util.subscriber("mike")); 24 | sink.tryEmitNext("?"); 25 | flux.subscribe(Util.subscriber("jake")); 26 | 27 | sink.tryEmitNext("new msg"); 28 | 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec11/Lec05SinkMultiDirectAll.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec11; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.publisher.Sinks; 6 | 7 | import java.time.Duration; 8 | 9 | public class Lec05SinkMultiDirectAll { 10 | 11 | public static void main(String[] args) { 12 | 13 | System.setProperty("reactor.bufferSize.small", "16"); 14 | 15 | // handle through which we would push items 16 | Sinks.Many sink = Sinks.many().multicast().directBestEffort(); 17 | 18 | // handle through which subscribers will receive items 19 | Flux flux = sink.asFlux(); 20 | 21 | flux.subscribe(Util.subscriber("sam")); 22 | flux.delayElements(Duration.ofMillis(200)).subscribe(Util.subscriber("mike")); 23 | 24 | for (int i = 0; i < 100; i++) { 25 | sink.tryEmitNext(i); 26 | } 27 | 28 | Util.sleepSeconds(10); 29 | 30 | } 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec11/Lec06SinkReplay.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec11; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.publisher.Sinks; 6 | 7 | public class Lec06SinkReplay { 8 | 9 | public static void main(String[] args) { 10 | 11 | // handle through which we would push items 12 | Sinks.Many sink = Sinks.many().replay().all(); 13 | 14 | // handle through which subscribers will receive items 15 | Flux flux = sink.asFlux(); 16 | 17 | 18 | sink.tryEmitNext("hi"); 19 | sink.tryEmitNext("how are you"); 20 | 21 | flux.subscribe(Util.subscriber("sam")); 22 | flux.subscribe(Util.subscriber("mike")); 23 | sink.tryEmitNext("?"); 24 | flux.subscribe(Util.subscriber("jake")); 25 | 26 | sink.tryEmitNext("new msg"); 27 | 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec11/Lec07SlackDemo.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec11; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec11.assignment.SlackMember; 5 | import com.rp.sec11.assignment.SlackRoom; 6 | 7 | public class Lec07SlackDemo { 8 | 9 | public static void main(String[] args) { 10 | 11 | SlackRoom slackRoom = new SlackRoom("reactor"); 12 | 13 | SlackMember sam = new SlackMember("sam"); 14 | SlackMember jake = new SlackMember("jake"); 15 | SlackMember mike = new SlackMember("mike"); 16 | 17 | slackRoom.joinRoom(sam); 18 | slackRoom.joinRoom(jake); 19 | 20 | sam.says("Hi all.."); 21 | Util.sleepSeconds(4); 22 | 23 | jake.says("Hey!"); 24 | sam.says("I simply wanted to say hi.."); 25 | Util.sleepSeconds(4); 26 | 27 | slackRoom.joinRoom(mike); 28 | mike.says("Hey guys..glad to be here..."); 29 | 30 | 31 | 32 | 33 | } 34 | 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec11/assignment/SlackMember.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec11.assignment; 2 | 3 | import java.util.function.Consumer; 4 | 5 | public class SlackMember { 6 | 7 | private String name; 8 | private Consumer messageConsumer; 9 | 10 | public SlackMember(String name) { 11 | this.name = name; 12 | } 13 | 14 | String getName() { 15 | return name; 16 | } 17 | 18 | void receives(String message){ 19 | System.out.println(message); 20 | } 21 | 22 | public void says(String message){ 23 | this.messageConsumer.accept(message); 24 | } 25 | 26 | void setMessageConsumer(Consumer messageConsumer) { 27 | this.messageConsumer = messageConsumer; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec11/assignment/SlackMessage.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec11.assignment; 2 | 3 | import lombok.Data; 4 | 5 | @Data 6 | public class SlackMessage { 7 | 8 | private static final String FORMAT = "[%s -> %s] : %s"; 9 | 10 | private String sender; 11 | private String receiver; 12 | private String message; 13 | 14 | @Override 15 | public String toString(){ 16 | return String.format(FORMAT, this.sender, this.receiver, this.message); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec12/Lec01Ctx.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec12; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Mono; 5 | import reactor.util.context.Context; 6 | 7 | public class Lec01Ctx { 8 | 9 | public static void main(String[] args) { 10 | 11 | getWelcomeMessage() 12 | .contextWrite(ctx -> ctx.put("user", ctx.get("user").toString().toUpperCase())) 13 | .contextWrite(Context.of("user", "sam")) 14 | .subscribe(Util.subscriber()); 15 | 16 | } 17 | 18 | 19 | private static Mono getWelcomeMessage(){ 20 | return Mono.deferContextual(ctx -> { 21 | if(ctx.hasKey("user")){ 22 | return Mono.just("Welcome " + ctx.get("user")); 23 | }else{ 24 | return Mono.error(new RuntimeException("unauthenticated")); 25 | } 26 | }); 27 | } 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec12/Lec02CtxRateLimiterDemo.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec12; 2 | 3 | import com.rp.courseutil.Util; 4 | import com.rp.sec12.helper.BookService; 5 | import com.rp.sec12.helper.UserService; 6 | import reactor.util.context.Context; 7 | 8 | public class Lec02CtxRateLimiterDemo { 9 | 10 | public static void main(String[] args) { 11 | 12 | BookService.getBook() 13 | .repeat(3) 14 | .contextWrite(UserService.userCategoryContext()) 15 | .contextWrite(Context.of("user", "mike")) 16 | .subscribe(Util.subscriber()); 17 | 18 | 19 | 20 | 21 | 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec12/helper/BookService.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec12.helper; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Mono; 5 | import reactor.util.context.Context; 6 | 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import java.util.function.Function; 10 | 11 | public class BookService { 12 | 13 | private static Map map = new HashMap<>(); 14 | 15 | static { 16 | map.put("std", 2); 17 | map.put("prime", 3); 18 | } 19 | 20 | public static Mono getBook(){ 21 | return Mono.deferContextual(ctx -> { 22 | if(ctx.get("allow")){ 23 | return Mono.just(Util.faker().book().title()); 24 | }else{ 25 | return Mono.error(new RuntimeException("not-allowed")); 26 | } 27 | }) 28 | .contextWrite(rateLimiterContext()); 29 | } 30 | 31 | 32 | 33 | private static Function rateLimiterContext(){ 34 | return ctx -> { 35 | if(ctx.hasKey("category")){ 36 | String category = ctx.get("category").toString(); 37 | Integer attempts = map.get(category); 38 | if(attempts > 0){ 39 | map.put(category, attempts - 1); 40 | return ctx.put("allow", true); 41 | } 42 | } 43 | return ctx.put("allow", false); 44 | }; 45 | } 46 | 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec12/helper/UserService.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec12.helper; 2 | 3 | import reactor.util.context.Context; 4 | 5 | import java.util.Map; 6 | import java.util.function.Function; 7 | 8 | public class UserService { 9 | 10 | private static final Map MAP = Map.of( 11 | "sam", "std", 12 | "mike", "prime" 13 | ); 14 | 15 | public static Function userCategoryContext(){ 16 | return ctx -> { 17 | String user = ctx.get("user").toString(); 18 | String category = MAP.get(user); 19 | return ctx.put("category", category); 20 | }; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /03-old-content/src/main/java/com/rp/sec13/Lec01Checkpoint.java: -------------------------------------------------------------------------------- 1 | package com.rp.sec13; 2 | 3 | import com.rp.courseutil.Util; 4 | import reactor.core.publisher.Flux; 5 | import reactor.core.publisher.Mono; 6 | 7 | public class Lec01Checkpoint { 8 | 9 | public static void main(String[] args) { 10 | 11 | Flux.range(1, 10) 12 | .checkpoint("cp1") 13 | .map(i -> i + i) 14 | .checkpoint("cp2") 15 | .map(i -> i / 2) 16 | .checkpoint("cp3") 17 | .flatMap(i -> Mono.just(i < 3 ? i : i /(5-i))) 18 | .checkpoint("cp4") 19 | .map(i -> i + 2) 20 | .checkpoint("cp5") 21 | .filter(i -> i % 2 == 0) 22 | .checkpoint("cp6") 23 | .subscribe(Util.onNext()); 24 | 25 | 26 | 27 | 28 | 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /03-old-content/src/main/resources/assignment/sec01/file01.txt: -------------------------------------------------------------------------------- 1 | This is file1 -------------------------------------------------------------------------------- /03-old-content/src/main/resources/assignment/sec01/file02.txt: -------------------------------------------------------------------------------- 1 | This is file2 -------------------------------------------------------------------------------- /03-old-content/src/test/java/com/rp/test/Lec01SVDemoTest.java: -------------------------------------------------------------------------------- 1 | package com.rp.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import reactor.core.publisher.Flux; 5 | import reactor.test.StepVerifier; 6 | 7 | public class Lec01SVDemoTest { 8 | 9 | @Test 10 | public void test1(){ 11 | Flux just = Flux.just(1, 2, 3); 12 | 13 | StepVerifier.create(just) 14 | .expectNext(1) 15 | .expectNext(2) 16 | .expectNext(3) 17 | .verifyComplete(); 18 | } 19 | 20 | @Test 21 | public void test2(){ 22 | Flux just = Flux.just(1, 2, 3); 23 | StepVerifier.create(just) 24 | .expectNext(1, 2, 3) 25 | .verifyComplete(); 26 | } 27 | 28 | 29 | } 30 | -------------------------------------------------------------------------------- /03-old-content/src/test/java/com/rp/test/Lec02SVErrorTest.java: -------------------------------------------------------------------------------- 1 | package com.rp.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import reactor.core.publisher.Flux; 5 | import reactor.test.StepVerifier; 6 | 7 | public class Lec02SVErrorTest { 8 | 9 | @Test 10 | public void test1(){ 11 | Flux just = Flux.just(1, 2, 3); 12 | Flux error = Flux.error(new RuntimeException("oops")); 13 | Flux concat = Flux.concat(just, error); 14 | 15 | StepVerifier.create(concat) 16 | .expectNext(1, 2, 3) 17 | .verifyError(); 18 | } 19 | 20 | @Test 21 | public void test2(){ 22 | Flux just = Flux.just(1, 2, 3); 23 | Flux error = Flux.error(new RuntimeException("oops")); 24 | Flux concat = Flux.concat(just, error); 25 | 26 | StepVerifier.create(concat) 27 | .expectNext(1, 2, 3) 28 | .verifyError(RuntimeException.class); 29 | } 30 | 31 | @Test 32 | public void test3(){ 33 | Flux just = Flux.just(1, 2, 3); 34 | Flux error = Flux.error(new RuntimeException("oops")); 35 | Flux concat = Flux.concat(just, error); 36 | 37 | StepVerifier.create(concat) 38 | .expectNext(1, 2, 3) 39 | .verifyErrorMessage("oops"); 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /03-old-content/src/test/java/com/rp/test/Lec03SVRangeTest.java: -------------------------------------------------------------------------------- 1 | package com.rp.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import reactor.core.publisher.Flux; 5 | import reactor.test.StepVerifier; 6 | 7 | public class Lec03SVRangeTest { 8 | 9 | @Test 10 | public void test1(){ 11 | Flux range = Flux.range(1, 50); 12 | StepVerifier.create(range) 13 | .expectNextCount(50) 14 | .verifyComplete(); 15 | } 16 | 17 | @Test 18 | public void test2(){ 19 | Flux range = Flux.range(1, 50); 20 | StepVerifier.create(range) 21 | .thenConsumeWhile(i -> i < 100) 22 | .verifyComplete(); 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /03-old-content/src/test/java/com/rp/test/Lec04AssertTest.java: -------------------------------------------------------------------------------- 1 | package com.rp.test; 2 | 3 | import com.rp.sec09.helper.BookOrder; 4 | import org.junit.jupiter.api.Assertions; 5 | import org.junit.jupiter.api.Test; 6 | import reactor.core.publisher.Mono; 7 | import reactor.test.StepVerifier; 8 | 9 | import java.time.Duration; 10 | 11 | public class Lec04AssertTest { 12 | 13 | @Test 14 | public void test1(){ 15 | 16 | Mono mono = Mono.fromSupplier(() -> new BookOrder()); 17 | 18 | StepVerifier.create(mono) 19 | .assertNext(b -> Assertions.assertNotNull(b.getAuthor())) 20 | .verifyComplete(); 21 | } 22 | 23 | @Test 24 | public void test2(){ 25 | 26 | Mono mono = Mono.fromSupplier(() -> new BookOrder()) 27 | .delayElement(Duration.ofSeconds(3)); 28 | 29 | StepVerifier.create(mono) 30 | .assertNext(b -> Assertions.assertNotNull(b.getAuthor())) 31 | .expectComplete() 32 | .verify(Duration.ofSeconds(4)); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /03-old-content/src/test/java/com/rp/test/Lec05VirtualTimeTest.java: -------------------------------------------------------------------------------- 1 | package com.rp.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import reactor.core.publisher.Flux; 5 | import reactor.test.StepVerifier; 6 | 7 | import java.time.Duration; 8 | 9 | public class Lec05VirtualTimeTest { 10 | 11 | @Test 12 | public void test1(){ 13 | StepVerifier.withVirtualTime(() -> timeConsumingFlux()) 14 | .thenAwait(Duration.ofSeconds(30)) 15 | .expectNext("1a", "2a", "3a", "4a") 16 | .verifyComplete(); 17 | } 18 | 19 | @Test 20 | public void test2(){ 21 | StepVerifier.withVirtualTime(() -> timeConsumingFlux()) 22 | .expectSubscription() // sub is an event 23 | .expectNoEvent(Duration.ofSeconds(4)) 24 | .thenAwait(Duration.ofSeconds(20)) 25 | .expectNext("1a", "2a", "3a", "4a") 26 | .verifyComplete(); 27 | } 28 | 29 | 30 | private Flux timeConsumingFlux(){ 31 | return Flux.range(1, 4) 32 | .delayElements(Duration.ofSeconds(5)) 33 | .map((i -> i + "a")); 34 | } 35 | 36 | 37 | } 38 | -------------------------------------------------------------------------------- /03-old-content/src/test/java/com/rp/test/Lec06ScenarioNameTest.java: -------------------------------------------------------------------------------- 1 | package com.rp.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import reactor.core.publisher.Flux; 5 | import reactor.test.StepVerifier; 6 | import reactor.test.StepVerifierOptions; 7 | 8 | public class Lec06ScenarioNameTest { 9 | 10 | @Test 11 | public void test1(){ 12 | 13 | Flux flux = Flux.just("a", "b", "c"); 14 | 15 | StepVerifierOptions scenarioName = StepVerifierOptions.create().scenarioName("alphabets-test"); 16 | 17 | StepVerifier.create(flux, scenarioName) 18 | .expectNextCount(12) 19 | .verifyComplete(); 20 | 21 | 22 | } 23 | 24 | @Test 25 | public void test2(){ 26 | 27 | Flux flux = Flux.just("a", "b1", "c"); 28 | 29 | StepVerifier.create(flux) 30 | .expectNext("a") 31 | .as("a-test") 32 | .expectNext("b") 33 | .as("b-test") 34 | .expectNext("c") 35 | .as("c-test") 36 | .verifyComplete(); 37 | 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /03-old-content/src/test/java/com/rp/test/Lec07CtxTest.java: -------------------------------------------------------------------------------- 1 | package com.rp.test; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import reactor.core.publisher.Mono; 5 | import reactor.test.StepVerifier; 6 | import reactor.test.StepVerifierOptions; 7 | import reactor.util.context.Context; 8 | 9 | public class Lec07CtxTest { 10 | 11 | @Test 12 | public void test1(){ 13 | StepVerifier.create(getWelcomeMessage()) 14 | .verifyError(RuntimeException.class); 15 | 16 | } 17 | 18 | @Test 19 | public void test2(){ 20 | StepVerifierOptions options = StepVerifierOptions.create().withInitialContext(Context.of("user", "sam")); 21 | StepVerifier.create(getWelcomeMessage(), options) 22 | .expectNext("Welcome sam") 23 | .verifyComplete(); 24 | } 25 | 26 | 27 | 28 | 29 | private Mono getWelcomeMessage(){ 30 | return Mono.deferContextual(ctx -> { 31 | if(ctx.hasKey("user")){ 32 | return Mono.just("Welcome " + ctx.get("user")); 33 | }else{ 34 | return Mono.error(new RuntimeException("unauthenticated")); 35 | } 36 | }); 37 | } 38 | 39 | } 40 | --------------------------------------------------------------------------------