Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Reactive System. What and How?

Reactive System. What and How?

Oleh Dokuka

August 19, 2017
Tweet

More Decks by Oleh Dokuka

Other Decks in Programming

Transcript

  1. • JSE at Levi9 • JEEConf Speaker • Spring fan

    • Reactivity preacher About me 2
  2. • JSE at Levi9 • JEEConf Speaker • Spring fan

    • Reactivity preacher /oleh.dokuka /OlegDokuka /OlehDokuka About me 2
  3. 5

  4. 6

  5. 7

  6. 24

  7. 24

  8. 25

  9. 25

  10. 26

  11. 26

  12. anotherEventSource.setHandler( new EventHandler() { void onEvent(Event event) { eventSource.setHandler( new

    EventHandler() { void onEvent(Event event) { //do stuff } } ); } } ); 29
  13. public interface IObserver<in T> { // Notifies the observer that

    // the source has finished sending messages. void OnCompleted(); // Notifies the observer about any // exception or error. void OnError(Exception error); // Pushes the next data value from // the source to the observer. void OnNext(T value); } 45
  14. public interface IObserver<in T> { // Notifies the observer that

    // the source has finished sending messages. void OnCompleted(); // Notifies the observer about any // exception or error. void OnError(Exception error); // Pushes the next data value from // the source to the observer. void OnNext(T value); } 46
  15. public interface IObserver<in T> { // Notifies the observer that

    // the source has finished sending messages. void OnCompleted(); // Notifies the observer about any // exception or error. void OnError(Exception error); // Pushes the next data value from // the source to the observer. void OnNext(T value); } 47
  16. public interface IObserver<in T> { // Notifies the observer that

    // the source has finished sending messages. void OnCompleted(); // Notifies the observer about any // exception or error. void OnError(Exception error); // Pushes the next data value from // the source to the observer. void OnNext(T value); } 48
  17. class Observable<T> { ... static <T> Observable<T> from(T... items) static

    Observable<Integer> range(...) static <T> Observable<T> just(T value) ... } 57
  18. Observable .just("a") .subscribe( onNext(), onError(), onComplete() ) .just( ) a

    Observable .just("a") .subscribe( onNext(), onError(), onComplete() ) 68
  19. .just( ) a a onNext() onError() onComplete() Observable .just("a") .subscribe(

    onNext(), onError(), onComplete() ) Observable .just("a") .subscribe( onNext(), onError(), onComplete() ) 69
  20. .just( ) .just( ) onNext() onNext() onError() onComplete() Observable .just("a")

    .subscribe( onNext(), onError(), onComplete() ) Observable .just("a") .subscribe( onNext(), onError(), onComplete() ) a 70
  21. onNext() Observable .just("a") .subscribe( onNext(), onError(), onComplete() ) onNext() .just(

    ) onError() onComplete() Observable .just("a") .subscribe( onNext(), onError(), onComplete() ) onComplete() 71
  22. onComplete() onNext() .just( ) onError() onComplete() Observable .just("a") .subscribe( onNext(),

    onError(), onComplete() ) Observable .just("a") .subscribe( onNext(), onError(), onComplete() ) 72
  23. Observable .just("a") .subscribe( onNext(), onError(), onComplete() ) onNext() Observable .just("a")

    .subscribe( onNext(), onError(), onComplete() ) .just( ) onError() onComplete() onComplete() onComplete() 73
  24. 75 onNext() onError() onComplete() Observable .from(asList("a","b")) .subscribe( onNext(), onError(), onComplete()

    ) Observable .from(asList("a","b")) .subscribe( onNext(), onError(), onComplete() ) .from(asList( )) a b
  25. .from(asList( )) .from(asList( )) 76 onNext() onError() onComplete() onNext() a

    Observable .from(asList("a","b")) .subscribe( onNext(), onError(), onComplete() ) Observable .from(asList("a","b")) .subscribe( onNext(), onError(), onComplete() ) b
  26. onNext() onComplete() .from(asList( )) onError() .from(asList( )) 77 onError() Observable

    .from(asList("a","b")) .subscribe( onNext(), onError(), onComplete() ) a b
  27. onComplete() onNext() onComplete() onNext() .from(asList( )) onError() .from(asList( )) 77

    onError() Observable .from(asList("a","b")) .subscribe( onNext(), onError(), onComplete() ) Observable .from(asList("a","b")) .subscribe( onNext(), onError(), onComplete() )
  28. onNext() onComplete() onNext() .from(asList( )) onComplete() onError() .from(asList( )) 78

    onError() Observable .from(asList("a","b")) .subscribe( onNext(), onError(), onComplete() )
  29. onNext() onComplete() onNext() .from(asList( )) onComplete() onError() .from(asList( )) 78

    onError() onComplete() Observable .from(asList("a","b")) .subscribe( onNext(), onError(), onComplete() ) Observable .from(asList("a","b")) .subscribe( onNext(), onError(), onComplete() )
  30. 80 Observable .defer(() -> just("a", "b") ) .subscribe( onNext(), onError(),

    onComplete() ) .defer() Observable .defer(() -> just("a", "b") ) .subscribe( onNext(), onError(), onComplete() )
  31. Observable .defer(() -> just("a", "b") ) .subscribe( onNext(), onError(), onComplete()

    ) 81 Observable .defer(() -> just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) .defer() onNext() onError() onComplete()
  32. Observable .defer(() -> just("a", "b") ) .subscribe( onNext(), onError(), onComplete()

    ) Observable .defer(() -> just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) onNext() onError() onComplete() 82 .just( ) a b .defer() .defer()
  33. .just( ) onNext() onError() onComplete() 83 Observable .defer(() -> just("a",

    "b") ) .subscribe( onNext(), onError(), onComplete() ) a b .defer()
  34. .just( ) onNext() onNext() onError() onComplete() 83 Observable .defer(() ->

    just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) .just( ) a b .defer() Observable .defer(() -> just("a", "b") ) .subscribe( onNext(), onError(), onComplete() )
  35. onNext() onError() onComplete() 84 Observable .defer(() -> just("a", "b") )

    .subscribe( onNext(), onError(), onComplete() ) .just( ) .defer() a b
  36. onNext() onNext() onError() onComplete() onComplete() 84 Observable .defer(() -> just("a",

    "b") ) .subscribe( onNext(), onError(), onComplete() ) .just( ) .defer() Observable .defer(() -> just("a", "b") ) .subscribe( onNext(), onError(), onComplete() )
  37. onComplete() onNext() onError() 85 Observable .defer(() -> just("a", "b") )

    .subscribe( onNext(), onError(), onComplete() ) .just( ) .defer()
  38. onComplete() onNext() onError() onComplete() 85 Observable .defer(() -> just("a", "b")

    ) .subscribe( onNext(), onError(), onComplete() ) .just( ) .defer() Observable .defer(() -> just("a", "b") ) .subscribe( onNext(), onError(), onComplete() )
  39. onNext() onError() onComplete() onComplete() onComplete() 86 Observable .defer(() -> just("a",

    "b") ) .subscribe( onNext(), onError(), onComplete() ) .just( ) .defer()
  40. .from( ) 4 3 2 1 Observable .just(1, 2, 3,

    4) 1 2 3 4 .subscribe() 105
  41. .from( ) 4 3 2 1 Observable .just(1, 2, 3,

    4) 1 2 3 4 1 2 3 4 .subscribe() 106
  42. .from( ) 4 3 2 1 Observable .just(1, 2, 3,

    4) 1 2 3 4 1 2 3 4 .subscribe() .subscribe() 106
  43. .from( ) 4 3 2 1 Observable .just(1, 2, 3,

    4) 1 2 3 4 1 2 3 4 .subscribe() .subscribe() 107
  44. RxJava Cons • Not easy to understand • Unexpected behaviors

    • Complicated extensibility • No backpressure 117
  45. 118

  46. 128 public interface Subscriber<T> { public void onSubscribe(Subscription s); public

    void onNext(T t); public void onError(Throwable t); public void onComplete(); }
  47. 128 public interface Subscriber<T> { public void onSubscribe(Subscription s); public

    void onNext(T t); public void onError(Throwable t); public void onComplete(); } public interface Subscriber<T> { public void onSubscribe(Subscription s); public void onNext(T t); public void onError(Throwable t); public void onComplete(); }
  48. public interface Subscription { public void request(long n); public void

    cancel(); } 129 public interface Subscription { public void request(long n); public void cancel(); }
  49. Subscriber<String> { void onSubscribe(Subscription s){ s.request(1); } … } Subscriber<String>

    { void onSubscribe(Subscription s){ s.request(1); } … } 130 .publish( ) a .subscribe() Publisher<String>
  50. Publisher<String> Subscriber<String> { void onSubscribe(Subscription s){ s.request(1); } … }

    Subscriber<String> { void onSubscribe(Subscription s){ s.request(1); } … } 131 .publish( ) .subscribe() a
  51. Publisher<String> Subscriber<String> { void onSubscribe(Subscription s){ s.request(1); } … }

    Subscriber<String> { void onSubscribe(Subscription s){ s.request(1); } … } 131 .publish( ) .subscribe() Publisher<String> a
  52. Publisher<String> Subscriber<String> { void onSubscribe(Subscription s){ s.request(1); } … }

    Subscriber<String> { void onSubscribe(Subscription s){ s.request(1); } … } 131 .publish( ) .subscribe() Publisher<String> a
  53. Processor<String, String> Processor<String, String> { s.request(1); } Processor<String, String> {

    s.request(1); } .publish( ) 136 .subscribe() Publisher<String> a .process() Subscriber<String>
  54. Processor<String, String> Processor<String, String> { s.request(1); } .publish( ) b

    .process() 137 .subscribe() Publisher<String> a Subscriber<String>
  55. Processor<String, String> Processor<String, String> { s.request(1); } .publish( ) b

    .process() 137 .subscribe() Publisher<String> Subscriber<String> a
  56. Processor<String, String> { s.request(1); } .publish( ) b .process() 138

    .subscribe() Publisher<String> Subscriber<String> a
  57. Processor<String, String> { s.request(1); } Processor<String, String> { s.request(1); }

    Processor<String, String> { s.request(1); } .publish( ) b .process() 138 .subscribe() Publisher<String> Subscriber<String> a
  58. Subscriber<String> Subscriber<String> { s.request(2); } Processor<String, String> 140 .publish( )

    .subscribe() Publisher<String> .process() Processor<String, String> b a
  59. 149 abstract class Flux<T> implements Publisher<T> { ... static <T>

    Flux<T> from(...) static Flux<Integer> range(...) static <T> Flux<T> just(T data) ... }
  60. 150 abstract class Flux<T> implements Publisher<T> { ... <R> Flux<R>

    map(...) Flux<T> filter(...) <R> Flux<R> flatMap(...) ... }
  61. 152

  62. 157 Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() )

    .from( ____ ) .just( ) a b onNext() onError() onComplete() Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() )
  63. .from( ____ ) .just( ) a b Mono.from( Flux.just("a", "b")

    ) .subscribe( onNext(), onError(), onComplete() ) 158 onNext() onError() onComplete()
  64. .from( ____ ) .just( ) a b Mono.from( Flux.just("a", "b")

    ) .subscribe( onNext(), onError(), onComplete() ) 158 Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) .from( ____ ) .just( ) a b onNext() onError() onComplete()
  65. Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) .from(

    ____ ) .just( ) a b 159 .from( ____ ) .just( ) b onNext() onError() onComplete() a
  66. Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) .from(

    ____ ) .just( ) a b Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) 159 .from( ____ ) .just( ) b onNext() onError() onComplete() onNext() a
  67. Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) Mono.from(

    Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) .from( ____ ) .from( ____ ) .just( ) a b 160 .just( ) onNext() onError() onComplete() a b
  68. Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) Mono.from(

    Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) .from( ____ ) .from( ____ ) .from( ____ ) .just( ) a b 160 .just( ) onNext() onError() onComplete() a Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) .just( ) b
  69. Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) Mono.from(

    Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) .from( ____ ) .from( ____ ) .from( ____ ) .just( ) a b 160 .just( ) onNext() onError() onComplete() a Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) .just( )
  70. Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) Mono.from(

    Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) .from( ____ ) .from( ____ ) .just( ) a b 161 .just( ) onNext() onError() onComplete() a .just( )
  71. Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) Mono.from(

    Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() ) .from( ____ ) .from( ____ ) .just( ) a b 161 .just( ) onNext() onError() onComplete() a .just( ) onComplete() Mono.from( Flux.just("a", "b") ) .subscribe( onNext(), onError(), onComplete() )
  72. 168 Flux.zip( Flux.just("a"), Flux.just("b"), (a, b) -> a + b

    ) .zipWith(Flux.just("c"), (ab, c) -> ab + c);
  73. 184

  74. 196

  75. 196

  76. 197

  77. 197

  78. 198

  79. 198

  80. 199

  81. 199

  82. 202

  83. 202

  84. 206

  85. 206

  86. 207

  87. 209

  88. 209

  89. 210

  90. 210

  91. 211

  92. 213

  93. 213

  94. 214

  95. 214

  96. 215

  97. 217

  98. 217

  99. Reactive Stack (WebFlux) @Controller, @RequestMapping,… Spring MVC Servlet API Servlet

    Container Spring Web Reactive Reactive HTTP Servlet, Netty, Undertow 221
  100. @RestController @RequestMapping("/api/v1/statistics") public class StatisticResource { private final StatisticService statisticService;

    @Autowired public StatisticResource( StatisticService statisticService) { this.statisticService = statisticService; } @GetMapping("/users") public List<UsersStatisticVM> getUsersStatistic() { return statisticService.getUsersStatistic(); } } 222
  101. @RestController @RequestMapping("/api/v1/statistics") public class StatisticResource { private final StatisticService statisticService;

    @Autowired public StatisticResource( StatisticService statisticService) { this.statisticService = statisticService; } @GetMapping("/users") public List<UsersStatisticVM> getUsersStatistic() { return statisticService.getUsersStatistic(); } } 223
  102. @RestController @RequestMapping("/api/v1/statistics") public class StatisticResource { private final StatisticService statisticService;

    @Autowired public StatisticResource( StatisticService statisticService) { this.statisticService = statisticService; } @GetMapping("/users") public Flux<UsersStatisticVM> getUsersStatistic() { return Flux.fromIterable(statisticService .getUsersStatistic()); } 224
  103. @RestController @RequestMapping("/api/v1/statistics") public class StatisticResource { private final StatisticService statisticService;

    @Autowired public StatisticResource( StatisticService statisticService) { this.statisticService = statisticService; } @GetMapping("/users") public Flux<UsersStatisticVM> getUsersStatistic() { return Flux.fromIterable(statisticService .getUsersStatistic()); } 225
  104. 226

  105. 226

  106. 227

  107. interface ReactiveCrudRepository<T, ID> extends Repository<T, ID> <S extends T> Mono<S>

    save(S entity); <S extends T> Flux<S> saveAll(Iterable<S> entities); <S extends T> Flux<S> saveAll(Publisher<S> entityStream); Mono<T> findById(ID id); Mono<T> findById(Mono<ID> id); Mono<Boolean> existsById(ID id); Mono<Boolean> existsById(Mono<ID> id); Flux<T> findAll(); Flux<T> findAllById(Iterable<ID> ids); Flux<T> findAllById(Publisher<ID> idStream); Mono<Long> count(); Mono<Void> deleteById(ID id); Mono<Void> delete(T entity); Mono<Void> deleteAll(Iterable<? extends T> entities); Mono<Void> deleteAll(Publisher<? extends T> entityStream); Mono<Void> deleteAll(); } 239
  108. interface ReactiveCrudRepository<T, ID> extends Repository<T, ID> <S extends T> Mono<S>

    save(S entity); <S extends T> Flux<S> saveAll(Iterable<S> entities); <S extends T> Flux<S> saveAll(Publisher<S> entityStream); Mono<T> findById(ID id); Mono<T> findById(Mono<ID> id); Mono<Boolean> existsById(ID id); Mono<Boolean> existsById(Mono<ID> id); Flux<T> findAll(); Flux<T> findAllById(Iterable<ID> ids); Flux<T> findAllById(Publisher<ID> idStream); Mono<Long> count(); Mono<Void> deleteById(ID id); Mono<Void> delete(T entity); Mono<Void> deleteAll(Iterable<? extends T> entities); Mono<Void> deleteAll(Publisher<? extends T> entityStream); Mono<Void> deleteAll(); } 240
  109. public interface WebClient { UriSpec<RequestHeadersSpec<?>> get(); //omitted... static WebClient create()

    { return new DefaultWebClientBuilder().build(); } interface RequestHeadersSpec<S extends RequestHeadersSpec<S>> { //omitted... Mono<ClientResponse> exchange(); //omitted... } interface ResponseSpec { <T> Mono<T> bodyToMono(Class<T> bodyType); <T> Flux<T> bodyToFlux(Class<T> elementType); <T> Mono<ResponseEntity<T>> toEntity(Class<T> bodyType); <T> Mono<ResponseEntity<List<T>>> toEntityList(Class<T> element } } 245
  110. public interface WebClient { UriSpec<RequestHeadersSpec<?>> get(); //omitted... static WebClient create()

    { return new DefaultWebClientBuilder().build(); } interface RequestHeadersSpec<S extends RequestHeadersSpec<S>> { //omitted... Mono<ClientResponse> exchange(); //omitted... } interface ResponseSpec { <T> Mono<T> bodyToMono(Class<T> bodyType); <T> Flux<T> bodyToFlux(Class<T> elementType); <T> Mono<ResponseEntity<T>> toEntity(Class<T> bodyType); <T> Mono<ResponseEntity<List<T>>> toEntityList(Class<T> element } } 246
  111. 247

  112. 247

  113. @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge(

    getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } 249
  114. @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge(

    getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } 249 .getMS() .getLM() .retry() cache
  115. 250 @Autowired public GitterService( GitterClient gitterClient ) { gas =

    Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } .getMS() .getLM() .retry() cache
  116. 250 @Autowired public GitterService( GitterClient gitterClient ) { gas =

    Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } .getMS() .getLM() .retry() cache
  117. .getMS() .getLM() .retry() cache 251 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  118. .getMS() .getLM() .retry() cache 251 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  119. .getLM() .getMS() .retry() cache 252 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  120. .getLM() .getMS() .retry() cache 252 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  121. .getMS() .getLM() .retry() cache 253 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  122. .getMS() .getLM() .retry() cache 253 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } .getLM()
  123. .getMS() .getLM() .retry() cache 254 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  124. .getMS() .getLM() .retry() cache 254 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  125. .getMS() .getLM() .retry() cache 255 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  126. .getMS() .getLM() .retry() cache 255 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  127. .getMS() .getLM() .retry() cache 256 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  128. .getMS() .getLM() .retry() cache 256 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  129. .getMS() .getLM() .retry() cache 257 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  130. .getMS() .getLM() .retry() cache 257 @Autowired public GitterService( GitterClient gitterClient

    ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  131. 258 @Autowired public GitterService( GitterClient gitterClient ) { gas =

    Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } .getMS() .getLM() .retry() cache
  132. …subscribe(); 258 @Autowired public GitterService( GitterClient gitterClient ) { gas

    = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } .getMS() .getLM() .retry() cache @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  133. …subscribe(); 258 @Autowired public GitterService( GitterClient gitterClient ) { gas

    = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } .getMS() .getLM() .retry() cache @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); }
  134. …subscribe(); 259 @Autowired public GitterService( GitterClient gitterClient ) { gas

    = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } .getMS() .getLM() .retry() cache
  135. @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge(

    getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } …subscribe(); 260 .getMS() .getLM() .retry() cache
  136. @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge(

    getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } …subscribe(); 260 .getMS() .getLM() .retry() cache .getMS() .retry()
  137. @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge(

    getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } …subscribe(); 261 .getMS() .getLM() .retry() cache
  138. @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge(

    getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } …subscribe(); 261 .getMS() .getLM() .retry() cache …subscribe();
  139. @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge(

    getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } …subscribe(); 261 .getMS() .getLM() .retry() cache …subscribe();
  140. …subscribe(); 262 @Autowired public GitterService( GitterClient gitterClient ) { gas

    = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } .getMS() .getLM() .retry() cache @Autowired public GitterService( GitterClient gitterClient ) { gas = Flux.merge( getLatestMessages(), getMessagesStream(null) ) .retryWhen(...) .replay(30) .autoConnect(0); } …subscribe();
  141. 264

  142. 264

  143. @Autowired public DefaultMessageService( MessageRepository messageRepository, ChatService<MessageResponse> chatClient, ApplicationContext context )

    { this.chatClient = chatClient; chatClient.stream() .transform(MessageMapper::toDomainUnits) .transform(messageRepository::saveAll) .subscribe() messageBroker.createChannel( "statisticChanged", saved.materialize() ); } 266
  144. @Autowired public DefaultMessageService( MessageRepository messageRepository, ChatService<MessageResponse> chatClient, MessageBroker messageBroker )

    { this.chatClient = chatClient; chatClient.stream() .transform(MessageMapper::toDomainUnits) .transform(messageRepository::saveAll) .subscribe() messageBroker.createChannel( "statisticChanged", saved.materialize() ); } .transform() 267
  145. @Autowired public DefaultMessageService( MessageRepository messageRepository, ChatService<MessageResponse> chatClient, MessageBroker messageBroker )

    { this.chatClient = chatClient; chatClient.stream() .transform(MessageMapper::toDomainUnits) .transform(messageRepository::saveAll) .subscribe() messageBroker.createChannel( "statisticChanged", saved.materialize() ); } .transform() 268
  146. @Autowired public DefaultMessageService( MessageRepository messageRepository, ChatService<MessageResponse> chatClient, MessageBroker messageBroker )

    { this.chatClient = chatClient; chatClient.stream() .transform(MessageMapper::toDomainUnits) .transform(messageRepository::saveAll) .subscribe() messageBroker.createChannel( "statisticChanged", saved.materialize() ); } .transform() 268
  147. @Autowired public DefaultMessageService( MessageRepository messageRepository, ChatService<MessageResponse> chatClient, MessageBroker messageBroker )

    { this.chatClient = chatClient; chatClient.stream() .transform(MessageMapper::toDomainUnits) .transform(messageRepository::saveAll) .subscribe() messageBroker.createChannel( "statisticChanged", saved.materialize() ); } .transform() 269
  148. @Autowired public DefaultMessageService( MessageRepository messageRepository, ChatService<MessageResponse> chatClient, MessageBroker messageBroker )

    { this.chatClient = chatClient; chatClient.stream() .transform(MessageMapper::toDomainUnits) .transform(messageRepository::saveAll) .subscribe() messageBroker.createChannel( "statisticChanged", saved.materialize() ); } .transform() 269
  149. @Autowired public DefaultMessageService( MessageRepository messageRepository, ChatService<MessageResponse> chatClient, MessageBroker messageBroker )

    { this.chatClient = chatClient; chatClient.stream() .transform(MessageMapper::toDomainUnits) .transform(messageRepository::saveAll) .subscribe() messageBroker.createChannel( "statisticChanged", saved.materialize() ); } .transform() 270
  150. @Autowired public DefaultMessageService( MessageRepository messageRepository, ChatService<MessageResponse> chatClient, MessageBroker messageBroker )

    { this.chatClient = chatClient; chatClient.stream() .transform(MessageMapper::toDomainUnits) .transform(messageRepository::saveAll) .subscribe() messageBroker.createChannel( "statisticChanged", saved.materialize() ); } .transform() 271
  151. @Autowired public DefaultMessageService( MessageRepository messageRepository, ChatService<MessageResponse> chatClient, MessageBroker messageBroker )

    { this.chatClient = chatClient; chatClient.stream() .transform(MessageMapper::toDomainUnits) .transform(messageRepository::saveAll) .subscribe() messageBroker.createChannel( "statisticChanged", saved.materialize() ); } .transform() 271
  152. @Autowired public DefaultMessageService( MessageRepository messageRepository, ChatService<MessageResponse> chatClient, MessageBroker messageBroker )

    { this.chatClient = chatClient; chatClient.stream() .transform(MessageMapper::toDomainUnits) .transform(messageRepository::saveAll) .subscribe() messageBroker.createChannel( "statisticChanged", saved.materialize() ); } .transform() 272
  153. @Autowired public DefaultMessageService( MessageRepository messageRepository, ChatService<MessageResponse> chatClient, MessageBroker messageBroker )

    { this.chatClient = chatClient; chatClient.stream() .transform(MessageMapper::toDomainUnits) .transform(messageRepository::saveAll) .subscribe() messageBroker.createChannel( "statisticChanged", saved.materialize() ); } .transform() 272
  154. @Autowired public DefaultMessageService( MessageRepository messageRepository, ChatService<MessageResponse> chatClient, MessageBroker messageBroker )

    { this.chatClient = chatClient; chatClient.stream() .transform(MessageMapper::toDomainUnits) .transform(messageRepository::saveAll) .subscribe() messageBroker.createChannel( "statisticChanged", saved.materialize() ); } .transform() 273
  155. @Override public Flux<MessageVM> latest() { return chatClient.stream() .transform(MessageMapper ::toViewModelUnits );

    } @Override public Flux<MessageVM> latest() { return chatClient.stream() .transform(MessageMapper ::toViewModelUnits ); } @Override public Flux<MessageVM> latest() { return chatClient.stream() .transform(MessageMapper ::toViewModelUnits ); } .transform() 274
  156. 276

  157. 276

  158. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) 278
  159. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) 279
  160. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) 279
  161. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) 280
  162. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) 280
  163. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) 281
  164. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) 282
  165. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) 282
  166. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) 283
  167. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .defaultIfEmpty(…) .zip(…) .subscribe() 283
  168. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .defaultIfEmpty(…) .zip(…) .subscribe() 284
  169. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .defaultIfEmpty(…) .zip(…) .subscribe() 285
  170. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) 285
  171. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) 286
  172. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) null 286
  173. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) null 287
  174. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) null 287
  175. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) null 288
  176. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) null 289
  177. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) null 289
  178. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) null 290
  179. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) null 290
  180. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) null 291
  181. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) null 291
  182. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) null 292
  183. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) null 292
  184. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .map(…) .defaultIfEmpty(…) .zip(…) 293
  185. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .defaultIfEmpty(…) .zip(…) .subscribe() 293
  186. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .defaultIfEmpty(…) .zip(…) .subscribe() 294
  187. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .defaultIfEmpty(…) .zip(…) .subscribe() 295
  188. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .defaultIfEmpty(…) .zip(…) .subscribe() 295
  189. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM> topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .defaultIfEmpty(…) .zip(…) .subscribe() 296
  190. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM> topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .defaultIfEmpty(…) .zip(…) .subscribe() 296
  191. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .defaultIfEmpty(…) .zip(…) .subscribe() 297
  192. private Mono<UsersStatisticVM> doGetUserStatistic Mono<UserVM> topActiveUser = userRepository .findMostActive() .map(UserMapper::toViewModelUnits); Mono<UserVM>

    topMentionedUser = userRepository .findMostPopular() .map(UserMapper::toViewModelUnits); return Mono.zip( topActiveUser.defaultIfEmpty(EMPTY_USER), topMentionedUser.defaultIfEmpty(EMPTY_USER), UsersStatisticVM::new ); } .defaultIfEmpty(…) .zip(…) .subscribe() 297
  193. 299

  194. 299

  195. public interface WebSocketSession { String getId(); HandshakeInfo getHandshakeInfo(); DataBufferFactory bufferFactory();

    Flux<WebSocketMessage> receive(); Mono<Void> send(Publisher<WebSocketMessage> messages); default Mono<Void> close() { return close(CloseStatus.NORMAL); } Mono<Void> close(CloseStatus status); WebSocketMessage textMessage(String payload); WebSocketMessage binaryMessage( Function<DataBufferFactory, DataBuffer> payloadFactory); WebSocketMessage pingMessage( Function<DataBufferFactory, DataBuffer> payloadFactory); WebSocketMessage pongMessage( Function<DataBufferFactory, DataBuffer> payloadFactory); } 301
  196. public interface WebSocketSession { String getId(); HandshakeInfo getHandshakeInfo(); DataBufferFactory bufferFactory();

    Flux<WebSocketMessage> receive(); Mono<Void> send(Publisher<WebSocketMessage> messages); default Mono<Void> close() { return close(CloseStatus.NORMAL); } Mono<Void> close(CloseStatus status); WebSocketMessage textMessage(String payload); WebSocketMessage binaryMessage( Function<DataBufferFactory, DataBuffer> payloadFactory); WebSocketMessage pingMessage( Function<DataBufferFactory, DataBuffer> payloadFactory); WebSocketMessage pongMessage( Function<DataBufferFactory, DataBuffer> payloadFactory); } 302
  197. public interface WebSocketSession { String getId(); HandshakeInfo getHandshakeInfo(); DataBufferFactory bufferFactory();

    Flux<WebSocketMessage> receive(); Mono<Void> send(Publisher<WebSocketMessage> messages); default Mono<Void> close() { return close(CloseStatus.NORMAL); } Mono<Void> close(CloseStatus status); WebSocketMessage textMessage(String payload); WebSocketMessage binaryMessage( Function<DataBufferFactory, DataBuffer> payloadFactory); WebSocketMessage pingMessage( Function<DataBufferFactory, DataBuffer> payloadFactory); WebSocketMessage pongMessage( Function<DataBufferFactory, DataBuffer> payloadFactory); } 303
  198. @Override public Publisher<?> handle( Publisher<Object> in ) { return Flux.merge(

    messageService.latest(), statisticService .usersStatisticStream() ); } network .merge() 305
  199. @Override public Publisher<?> handle( Publisher<Object> in ) { return Flux.merge(

    messageService.latest(), statisticService .usersStatisticStream() ); } network .merge() 306
  200. @Override public Publisher<?> handle( Publisher<Object> in ) { return Flux.merge(

    messageService.latest(), statisticService .usersStatisticStream() ); } network .merge() 306
  201. @Override public Publisher<?> handle( Publisher<Object> in ) { return Flux.merge(

    messageService.latest(), statisticService .usersStatisticStream() ); } network .merge() 307
  202. @Override public Publisher<?> handle( Publisher<Object> in ) { return Flux.merge(

    messageService.latest(), statisticService .usersStatisticStream() ); } network .merge() 308
  203. @Override public Publisher<?> handle( Publisher<Object> in ) { return Flux.merge(

    messageService.latest(), statisticService .usersStatisticStream() ); } network .merge() 308
  204. .merge() @Override public Publisher<?> handle( Publisher<Object> in ) { return

    Flux.merge( messageService.latest(), statisticService .usersStatisticStream() ); } network 309
  205. .merge() @Override public Publisher<?> handle( Publisher<Object> in ) { return

    Flux.merge( messageService.latest(), statisticService .usersStatisticStream() ); } network 309
  206. @Override public Publisher<?> handle( Publisher<Object> in ) { return Flux.merge(

    messageService.latest(), statisticService .usersStatisticStream() ); } network .merge() 310
  207. @Override public Publisher<?> handle( Publisher<Object> in ) { return Flux.merge(

    messageService.latest(), statisticService .usersStatisticStream() ); } network .merge() 310
  208. @Override public Publisher<?> handle( Publisher<Object> in ) { return Flux.merge(

    messageService.latest(), statisticService .usersStatisticStream() ); } network .merge() 311
  209. @Override public Publisher<?> handle( Publisher<Object> in ) { return Flux.merge(

    messageService.latest(), statisticService .usersStatisticStream() ); } network .merge() 312
  210. @Override public Publisher<?> handle( Publisher<Object> in ) { return Flux.merge(

    messageService.latest(), statisticService .usersStatisticStream() ); } network .merge() 312
  211. 314

  212. 314

  213. Resources 1. Why Reactive? [http://www.oreilly.com/programming/ free/why-reactive.csp] 2. Operator Fusion Part

    1 [http://akarnokd.blogspot.com/ 2016/03/operator-fusion-part-1.html] 3. Reactive Streams Specification [http://www.reactive- streams.org/] 4. Learn Project Reactor [http://projectreactor.io/learn] 320