├── .gitignore ├── .settings ├── gradle │ ├── org.springsource.ide.eclipse.gradle.core.import.prefs │ ├── org.springsource.ide.eclipse.gradle.core.prefs │ └── org.springsource.ide.eclipse.gradle.refresh.prefs └── org.eclipse.jdt.core.prefs ├── README.md ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── src ├── main ├── java │ └── com │ │ └── packtpub │ │ └── reactive │ │ ├── chapter01 │ │ ├── ObservableVSIterator.java │ │ └── ReactiveSumV1.java │ │ ├── chapter02 │ │ ├── Java8LambdasSyntaxIntroduction.java │ │ ├── PureAndHigherOrderFunctions.java │ │ └── ReactiveSumV2.java │ │ ├── chapter03 │ │ ├── CreatingObservablesUsingJust.java │ │ ├── CreatingObservablesUsingVariousFactoryMethods.java │ │ ├── CreatingObservablesWithFrom.java │ │ ├── ObservableCreateExample.java │ │ ├── ReactiveSumV3.java │ │ ├── SubjectsDemonstration.java │ │ └── UsingConnectableObservables.java │ │ ├── chapter04 │ │ ├── FilteringExamples.java │ │ ├── FlatMapAndFiles.java │ │ ├── MappingExamples.java │ │ ├── ScanAndUsingMultipleOperators.java │ │ ├── UsingGroupBy.java │ │ └── VariousTransformationsDemonstration.java │ │ ├── chapter05 │ │ ├── CombiningObservables.java │ │ ├── Conditionals.java │ │ ├── HandlingErrors.java │ │ └── HttpRequestsExample.java │ │ ├── chapter06 │ │ ├── BackpressureExamples.java │ │ ├── IntervalAndSchedulers.java │ │ ├── ParallelRequestsExample.java │ │ ├── SchedulersTypes.java │ │ └── SubscribeOnAndObserveOn.java │ │ ├── chapter07 │ │ └── BlockingObservablesAndOperators.java │ │ ├── chapter08 │ │ ├── Compose.java │ │ ├── Lift.java │ │ └── ResourceManagement.java │ │ └── common │ │ ├── CreateObservable.java │ │ ├── Helpers.java │ │ ├── Program.java │ │ └── checked │ │ ├── CheckedAction1.java │ │ ├── CheckedFunc0.java │ │ └── Uncheck.java └── resources │ ├── letters.txt │ ├── lorem.txt │ ├── lorem_big.txt │ ├── operators.txt │ └── test.log └── test └── java └── com └── packtpub └── reactive ├── chapter07 ├── CreateObservableIntervalTest.java └── SortedObservableTest.java └── chapter08 ├── IndexedTest.java └── OddFilterTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | build 3 | .gradle/* 4 | .classpath 5 | .project 6 | cache 7 | *.iml 8 | .idea 9 | -------------------------------------------------------------------------------- /.settings/gradle/org.springsource.ide.eclipse.gradle.core.import.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleImportPreferences 2 | #Wed May 20 18:02:22 EEST 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | enableDependendencyManagement=true 10 | projects=; 11 | -------------------------------------------------------------------------------- /.settings/gradle/org.springsource.ide.eclipse.gradle.core.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.preferences.GradleProjectPreferences 2 | #Wed Jan 21 14:34:20 EET 2015 3 | build.family.org.gradle.tooling.model.eclipse.HierarchicalEclipseProject=; 4 | org.springsource.ide.eclipse.gradle.linkedresources= 5 | org.springsource.ide.eclipse.gradle.rootprojectloc= 6 | -------------------------------------------------------------------------------- /.settings/gradle/org.springsource.ide.eclipse.gradle.refresh.prefs: -------------------------------------------------------------------------------- 1 | #org.springsource.ide.eclipse.gradle.core.actions.GradleRefreshPreferences 2 | #Wed Jan 21 14:34:19 EET 2015 3 | addResourceFilters=true 4 | afterTasks=afterEclipseImport; 5 | beforeTasks=cleanEclipse;eclipse; 6 | enableAfterTasks=true 7 | enableBeforeTasks=true 8 | enableDSLD=false 9 | useHierarchicalNames=false 10 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | # 2 | #Wed May 20 18:02:25 EEST 2015 3 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 4 | org.eclipse.jdt.core.compiler.compliance=1.8 5 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 6 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 7 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 8 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 9 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 10 | eclipse.preferences.version=1 11 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 12 | org.eclipse.jdt.core.compiler.source=1.8 13 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learning Reactive Programming With Java 8 Example Runner 2 | This project contains the examples of the 'Learning Reactive Programming With Java 8' book. 3 | 4 | ## Installing and running this program. 5 | * Of course you'll need Git :). 6 | * To run these examples you need Java 8, if you don't have it, navigate to Oracle's site and download/install it. 7 | * Now you can clone this project by running : 8 | 9 | ``` 10 | git clone https://github.com/meddle0x53/learning-rxjava.git 11 | ``` 12 | 13 | * Navigate to the root of the project (`cd learning-rxjava`) and run : 14 | 15 | ``` 16 | ./gradlew build 17 | ``` 18 | 19 | * This will download and install all the dependencies needed by the project and will compile it. 20 | * You can open the project with Eclipse and run the examples. You'll need the Gradle plugin for Eclipse. 21 | 22 | ### Running example from console 23 | 24 | ```bashgra 25 | ./gradlew execute -Pchapter=1 -Pexample=ReactiveSumV1 26 | ``` 27 | 28 | ## Examples 29 | Here are the descriptions of all the examples in the book. 30 | 31 | #### 01. Iterator VS Observable 32 | This example is used in the book in the 'Comparing the Iterator pattern and the RxJava Observable' of the first chapter. 33 | It demonstrates the difference between RxJava's Observables and the Iterators, by iterating over a list of strings. 34 | The `Observable.from` method is introduced here for the first time, as well as subscribing. 35 | 36 | The example can be found here [ObservableVSIterator](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter01/ObservableVSIterator.java) 37 | 38 | #### 02. Reactive Sum, version 1 39 | This is example demonstrates a reactive sum, which is updated on change of any of its collectors. It is demonstrates 40 | many of the features of RxJava, like Observers, Schedulers Observable transformations, filtering and combining. 41 | 42 | The example can be found here [ReactiveSumV1](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter01/ReactiveSumV1.java) 43 | 44 | #### 03. Introduction to the new syntax and semantics 45 | Demonstrates creating and using lambdas, passing them to methods, that receive Functional Interfaces as parameters and references 46 | to existing methods. 47 | 48 | The example can be found here [Java8LambdasSyntaxIntroduction](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter02/Java8LambdasSyntaxIntroduction.java) 49 | 50 | #### 04. Reactive Sum, version 2 (with lambdas) 51 | Another implementation of the 'Reactive Sum', similar to the on of the first chapter, but it uses the new Java 8 syntax with lambdas. 52 | 53 | The example can be found here [ReactiveSumV2](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter02/ReactiveSumV2.java) 54 | 55 | #### 05. Pure and higher functions 56 | Demonstrates pure and higher order functions. Applies higher order functions to other functions. 57 | 58 | The example can be found here [PureAndHigherOrderFunctions](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter02/PureAndHigherOrderFunctions.java) 59 | 60 | #### 06. Introduction to monads 61 | Shows implementation and uses of a monad. The Optional monad. 62 | 63 | The example can be found here [Monads](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter02/Monads.java) 64 | 65 | #### 07. Observables and monads 66 | Shows that Observables are not true monads. They are monad-like structures though and benefit from that. 67 | 68 | The example can be found here [ObservablesAndMonads](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter02/ObservablesAndMonads.java) 69 | 70 | #### 08. Creating Observables with Observable.from 71 | A set of examples of using the Observable.from method for creating Observables from collections, arrays and Iterables. 72 | 73 | The example can be found here [CreatingObservablesWithFrom](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter03/CreatingObservablesWithFrom.java) 74 | 75 | #### 09. Using Observable.from with Future 76 | Demonstrates creating Observables using the Observable.from(Future) method. 77 | 78 | The example can be found here [CreatingObservablesWithFromFuture](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter03/CreatingObservablesWithFromFuture.java) 79 | 80 | #### 10. Using the Observable.just method to create Observables 81 | Demonstrates creating Observables using the Observable.just method. 82 | 83 | The example can be found here [CreatingObservablesUsingJust](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter03/CreatingObservablesUsingJust.java) 84 | 85 | #### 11. A few factory methods for creating Observables (Chapter 3, pages 43-46) 86 | Demonstrates using Observable.interval, Observable.timer, Observable.error, 87 | Observable.never, Observable.empty and Observable.range for Obsevable creation. 88 | 89 | The example can be found here [CreatingObservablesUsingVariousFactoryMethods](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter03/CreatingObservablesUsingVariousFactoryMethods.java) 90 | 91 | #### 12. Demonstration of the Observable.create method (Chapter 3, pages 46-50) 92 | Demonstrates using Observable.create for creating custom Observables. 93 | Contains unsubscribing and implementing unsubscribing logic in Observable.create. 94 | 95 | The example can be found here [ObservableCreateExample](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter03/ObservableCreateExample.java) 96 | 97 | #### 13. A ConnectableObservable demonstration (Chapter 3, pages 51-53) 98 | Demonstration of ConnectableObservables and the methods realted to them - publish, refCount, share. 99 | 100 | The example can be found here [UsingConnectableObservables](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter03/UsingConnectableObservables.java) 101 | 102 | #### 14. Subjects demonstration (Chapter 3, pages 53-54) 103 | Demonstrates using a Subject to subscribe to an Observables, propagating its notifications to multiple Subscribers. 104 | 105 | The example can be found here [SubjectsDemonstration](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter03/SubjectsDemonstration.java) 106 | 107 | #### 15. Reactive Sum, version 3 (with Subjects) (Chapter 3, pages 55-57) 108 | The 'Reactive Sum' is implemented through reactive properties, which are in fact BehaviorSubjects. 109 | 110 | The example can be found here [ReactiveSumV3](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter03/ReactiveSumV3.java) 111 | 112 | #### 16. Examples of using Observable transformations (Chapter 4, pages 59-66) 113 | Demonstration of using map, flatMap, flatMapIterable and switchMap. 114 | 115 | The example can be found here [MappingExamples](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter04/MappingExamples.java) 116 | 117 | #### 17. Working with files using flatMap (Chapter 4, pages 60-62) 118 | Demonstration of using flatMap with an Observable created by directory stream, 119 | reading all the files from it, using Observables. 120 | 121 | The example can be found here [FlatMapAndFiles](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter04/FlatMapAndFiles.java) 122 | 123 | #### 18. Demonstration of using the Observable#groupBy operator (Chapter 4, pages 67-69) 124 | Demonstrates how the groupBy operator can be used. 125 | 126 | The example can be found here [UsingGroupBy](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter04/UsingGroupBy.java) 127 | 128 | #### 19. Demonstration of various transforming operators (Chapter 4, pages 69-71) 129 | Demonstration of working with the cast, materialize, timestamp and timeInterval operators. 130 | 131 | The example can be found here [VariousTransformationsDemonstration](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter04/VariousTransformationsDemonstration.java) 132 | 133 | #### 20. Various examples of using filtering operators (Chapter 4, pages 71-75) 134 | Demonstrates the filter, takeLast, last, takeLastBuffer, lastOrDefault, 135 | skipLast, skip, first, elementAt, distinct, distinctUntilChanged and ofType operators. 136 | 137 | The example can be found here [FilteringExamples](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter04/FilteringExamples.java) 138 | 139 | #### 21. Demonstration of using Observable#scan and more (Chapter 4, pages 76-78) 140 | Demonstrates the scan operator and contains an example of working with data using the majority of the operators learned through the chapter. 141 | 142 | The example can be found here [ScanAndUsingMultipleOperators](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter04/ScanAndUsingMultipleOperators.java) 143 | 144 | #### 22. Examples of combining Observables (Chapter 5, pages 82-88) 145 | Demonstrates combining Observables using Observable.zip, Observable.merge and Observable.concat. 146 | 147 | The example can be found here [CombiningObservables](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter05/CombiningObservables.java) 148 | 149 | #### 23. Some examples of using conditionals (Chapter 5, pages 88-91) 150 | Demonstration of using the Observable.amb, Observable.takeWhile, Observable.takeUntil, 151 | Observable.skipUntil and Observable.defaultIfEmpty. 152 | 153 | The example can be found here [Conditionals](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter05/Conditionals.java) 154 | 155 | #### 24. Examples of handling errors (Chapter 5, pages 92-95) 156 | A demonstrates working with Observable.onErrorReturn, Observable.onErrorResumeNext and Observable.onExceptionResumeNext 157 | as well as retrying with Observable.retry and Observable.retryWhen. 158 | 159 | The example can be found here [HandlingErrors](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter05/HandlingErrors.java) 160 | 161 | #### 25. Example of doing HTTP requests and handling responses with Observables (Chapter 5, pages 95-99) 162 | Using multiple Observable operators in order to handle and augment an HTTP response from Github. 163 | 164 | The example can be found here [HttpRequestsExample](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter05/HttpRequestsExample.java) 165 | 166 | #### 26. Observable.interval and Schedulers (Chapter 6, pages 103-105) 167 | More information of Observable.interval and its default Scheduler. Contains an example of debugging information of the emitted items and the current Thread. 168 | 169 | The example can be found here [IntervalAndSchedulers](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter06/IntervalAndSchedulers.java) 170 | 171 | #### 27. Demonstration of the different Schedulers types (Chapter 6, pages 106-114) 172 | A collection of examples of using the different Schedulers. 173 | 174 | The example can be found here [SchedulersTypes](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter06/SchedulersTypes.java) 175 | 176 | #### 28. A few examples of observeOn and subscribeOn (Chapter 6, pages 115-119) 177 | Demonstrates using subscribeOn and observeOn with Schedulers and Observables. 178 | 179 | The example can be found here [SubscribeOnAndObserveOn](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter06/SubscribeOnAndObserveOn.java) 180 | 181 | #### 29. Demonstraton of parallelism (Chapter 6, pages 121-122) 182 | Demonstrates parallelism by executing a number of requests in parallel. 183 | 184 | The example can be found here [ParallelRequestsExample](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter06/ParallelRequestsExample.java) 185 | 186 | #### 30. Examples demonstrating backpressure and buffering operators (Chapter 6, pages 122-127) 187 | Demonstrates using the Observable#sample, Observable#buffer, Observable#window 188 | Observable#throttleLast, Observable#debounce, Observable#onBackpressureDrop and 189 | Observable#onBackpressureBuffer operators 190 | 191 | The example can be found here [BackpressureExamples](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter06/BackpressureExamples.java) 192 | 193 | #### 31. A demonstration of using Blocking Observables (Chapter 7, pages 133-136) 194 | Examples of using BlockingObservable and their operators - 195 | BlockingObservable#forEach, BlockingObservable#first, BlockingObservable#next, 196 | BlockingObservable#last and BlockingObservable#single. 197 | Includes examples of Observable#count and Observable#toList combined with the Observable#toBlocking operator. 198 | 199 | The example can be found here [BlockingObservablesAndOperators](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter07/BlockingObservablesAndOperators.java) 200 | 201 | #### 32. Unit test demonstrating different ways of testing Observables (Chapter 7, pages 131-133, 136-138) 202 | Includes simple subscription test, test with BlockingObservable and test with TestSubscriber. 203 | 204 | The example can be found here [SortedObservableTest](https://github.com/meddle0x53/learning-rxjava/blob/master/src/test/java/com/packtpub/reactive/chapter07/SortedObservableTest.java) 205 | 206 | #### 33. Example of testing asynchronous Observables (Chapter 7, pages 139-140) 207 | A unit test testing the custom reateObservable#interval method. 208 | 209 | The example can be found here [CreateObservableIntervalTest](https://github.com/meddle0x53/learning-rxjava/blob/master/src/test/java/com/packtpub/reactive/chapter07/CreateObservableIntervalTest.java) 210 | 211 | #### 34. Resource management demonstration (Chapter 8, pages 142-148) 212 | Demonstration of custom resource management with Observable#using. 213 | 214 | The example can be found here [ResourceManagement](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter08/ResourceManagement.java) 215 | 216 | #### 35. Example of using Observable#lift for executing custom operators (Chapter 8, pages 148-152) 217 | Demonstrates implementing values with indices using lift and the custom operator Indexed. 218 | 219 | The example can be found here [Lift](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter08/Lift.java) 220 | 221 | #### 36. Unit test for the Indexed operator (Chapter 8, pages 152-153) 222 | 223 | The example can be found here [IndexedTest](https://github.com/meddle0x53/learning-rxjava/blob/master/src/test/java/com/packtpub/reactive/chapter08/IndexedTest.java) 224 | 225 | #### 37. Demonstration of the Observable.compose operator (Chapter 8, pages 153) 226 | Example of implementing a Transformer and passing it to Observable#compose. 227 | 228 | The example can be found here [Compose](https://github.com/meddle0x53/learning-rxjava/blob/master/src/main/java/com/packtpub/reactive/chapter08/Compose.java) 229 | 230 | #### 38. Unit test for the OddFilter Transformer. (Chapter 8, pages 154) 231 | 232 | The example can be found here [OddFilterTest](https://github.com/meddle0x53/learning-rxjava/blob/master/src/test/java/com/packtpub/reactive/chapter08/OddFilterTest.java) 233 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'eclipse' 3 | apply plugin: 'application' 4 | 5 | mainClassName = 'com.packtpub.reactive.chapter01.ReactiveSumV1' 6 | 7 | sourceCompatibility = 1.8 8 | version = '1.1' 9 | 10 | jar { 11 | manifest { 12 | attributes 'Implementation-Title': 'Reactive Java Examples', 'Implementation-Version': version 13 | } 14 | } 15 | 16 | run { 17 | standardInput = System.in 18 | 19 | } 20 | 21 | repositories { 22 | mavenCentral() 23 | } 24 | 25 | dependencies { 26 | compile 'io.reactivex:rxjava:1.0.8' 27 | compile 'io.reactivex:rxapache-http:0.21.0' 28 | compile 'com.google.code.gson:gson:2.3.1' 29 | testCompile group: 'junit', name: 'junit', version: '4.+' 30 | } 31 | 32 | test { 33 | systemProperties 'property': 'value' 34 | } 35 | 36 | task wrapper(type: Wrapper) { 37 | gradleVersion = '2.0' 38 | } 39 | 40 | task (execute, dependsOn: 'classes') << { 41 | def cl = 'com.packtpub.reactive.chapter0' + chapter + '.' + example 42 | def classpath = sourceSets.main.runtimeClasspath 43 | 44 | def command = [ 45 | 'java', 46 | '-ea', 47 | '-cp', classpath.collect().join(System.getProperty('path.separator')), 48 | cl, 49 | '--color' 50 | ] 51 | 52 | def proc = new ProcessBuilder(command) 53 | .redirectOutput(ProcessBuilder.Redirect.INHERIT) 54 | .redirectInput(ProcessBuilder.Redirect.INHERIT) 55 | .redirectError(ProcessBuilder.Redirect.INHERIT) 56 | .start() 57 | 58 | proc.waitFor() 59 | 60 | if (0 != proc.exitValue()) { 61 | throw new RuntimeException("Program exited with status: ${proc.exitValue()}!") 62 | } 63 | } 64 | 65 | uploadArchives { 66 | repositories { 67 | flatDir { 68 | dirs 'repos' 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/meddle0x53/learning-rxjava/0182bbf8efabd7dd0315af7f803d1a6bcb4a3f25/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Mar 16 18:38:30 EET 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.0-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter01/ObservableVSIterator.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter01; 2 | 3 | import java.util.Arrays; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | 7 | import rx.Observable; 8 | import rx.functions.Action0; 9 | import rx.functions.Action1; 10 | 11 | import com.packtpub.reactive.common.Program; 12 | 13 | /** 14 | * Demonstrate the differences between Iterators and Observables. 15 | * 16 | * @author meddle 17 | */ 18 | public class ObservableVSIterator implements Program { 19 | 20 | private static void usingIteratorExample() { 21 | List list = Arrays 22 | .asList("One", "Two", "Three", "Four", "Five"); 23 | 24 | Iterator iterator = list.iterator(); 25 | 26 | // While there is a next element, PULL it from the source and print it. 27 | while (iterator.hasNext()) { 28 | System.out.println(iterator.next()); 29 | } 30 | } 31 | 32 | private static void usingObservableExample() { 33 | List list = Arrays 34 | .asList("One", "Two", "Three", "Four", "Five"); 35 | 36 | Observable observable = Observable.from(list); 37 | 38 | // Subscribe to the Observable. It will PUSH it's values to the Subscriber, and it will be printed. 39 | observable.subscribe(new Action1() { 40 | public void call(String element) { 41 | System.out.println(element); 42 | } 43 | }, new Action1() { 44 | public void call(Throwable t) { 45 | System.err.println(t); // (1) 46 | } 47 | }, new Action0() { 48 | public void call() { 49 | System.out.println("We've finnished!"); // (2) 50 | } 51 | }); 52 | } 53 | 54 | @Override 55 | public String name() { 56 | return "Iterator vs Observable"; 57 | } 58 | 59 | @Override 60 | public void run() { 61 | System.out.println("Running Iterator example:"); 62 | usingIteratorExample(); 63 | 64 | System.out.println("Running Observable example:"); 65 | usingObservableExample(); 66 | } 67 | 68 | @Override 69 | public int chapter() { 70 | return 1; 71 | } 72 | 73 | public static void main(String[] args) { 74 | new ObservableVSIterator().run(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter01/ReactiveSumV1.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter01; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | import java.util.regex.Matcher; 5 | import java.util.regex.Pattern; 6 | 7 | import rx.Observable; 8 | import rx.Observer; 9 | import rx.Subscription; 10 | import rx.functions.Func1; 11 | import rx.functions.Func2; 12 | import rx.observables.ConnectableObservable; 13 | import rx.schedulers.Schedulers; 14 | 15 | import com.packtpub.reactive.common.CreateObservable; 16 | import com.packtpub.reactive.common.Program; 17 | 18 | /** 19 | * A demonstration of how to implement a sum that updates automatically when any of its collectors changes. 20 | * 21 | * @author meddle 22 | */ 23 | public class ReactiveSumV1 implements Program { 24 | 25 | /** 26 | * The sum is just an Observer, which subscribes to a stream created by combining 'a' and 'b', via summing. 27 | * 28 | * @author meddle 29 | */ 30 | public static final class ReactiveSum implements Observer { 31 | 32 | private CountDownLatch latch = new CountDownLatch(1); 33 | 34 | private double sum; 35 | private Subscription subscription = null; 36 | 37 | public ReactiveSum(Observable a, Observable b) { 38 | this.sum = 0; 39 | 40 | subscribe(a, b); 41 | } 42 | 43 | private void subscribe(Observable a, Observable b) { 44 | // combineLatest creates an Observable, sending notifications on changes of either of its sources. 45 | // This notifications are formed using a Func2. 46 | this.subscription = Observable.combineLatest(a, b, new Func2() { 47 | public Double call(Double a, Double b) { 48 | return a + b; 49 | } 50 | }).subscribeOn(Schedulers.io()).subscribe(this); 51 | } 52 | 53 | public void unsubscribe() { 54 | this.subscription.unsubscribe(); 55 | this.latch.countDown(); 56 | } 57 | 58 | public void onCompleted() { 59 | System.out.println("Exiting last sum was : " + this.sum); 60 | this.latch.countDown(); 61 | } 62 | 63 | public void onError(Throwable e) { 64 | System.err.println("Got an error!"); 65 | e.printStackTrace(); 66 | } 67 | 68 | public void onNext(Double sum) { 69 | this.sum = sum; 70 | System.out.println("update : a + b = " + sum); 71 | } 72 | 73 | public CountDownLatch getLatch() { 74 | return latch; 75 | } 76 | } 77 | 78 | /** 79 | * The Observable returned by this method, only reacts to values in the form 80 | * = or : . 81 | * It emits the . 82 | */ 83 | public static Observable varStream(final String varName, 84 | Observable input) { 85 | final Pattern pattern = Pattern.compile("^\\s*" + varName 86 | + "\\s*[:|=]\\s*(-?\\d+\\.?\\d*)$"); 87 | 88 | return input.map(new Func1() { 89 | public Matcher call(String str) { 90 | return pattern.matcher(str); 91 | } 92 | }).filter(new Func1() { 93 | public Boolean call(Matcher matcher) { 94 | return matcher.matches() && matcher.group(1) != null; 95 | } 96 | }).map(new Func1() { 97 | public String call(Matcher matcher) { 98 | return matcher.group(1); 99 | } 100 | }).filter(new Func1() { 101 | public Boolean call(String str) { 102 | return str != null; 103 | } 104 | }).map(new Func1() { 105 | public Double call(String str) { 106 | return Double.parseDouble(str); 107 | } 108 | }); 109 | } 110 | 111 | public String name() { 112 | return "Reactive Sum, version 1"; 113 | } 114 | 115 | public void run() { 116 | ConnectableObservable input = CreateObservable.from(System.in); 117 | 118 | Observable a = varStream("a", input); 119 | Observable b = varStream("b", input); 120 | 121 | ReactiveSum sum = new ReactiveSum(a, b); 122 | 123 | input.connect(); 124 | 125 | try { 126 | sum.getLatch().await(); 127 | } catch (InterruptedException e) {} 128 | } 129 | 130 | @Override 131 | public int chapter() { 132 | return 1; 133 | } 134 | 135 | /** 136 | * Here the input is executed on a separate thread, so we block the current one until it sends 137 | * a `completed` notification. 138 | */ 139 | public static void main(String[] args) { 140 | System.out.println(); 141 | System.out.println("Reacitve Sum. Type 'a: ' and 'b: ' to try it."); 142 | 143 | new ReactiveSumV1().run(); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter02/Java8LambdasSyntaxIntroduction.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter02; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | import java.util.function.Consumer; 7 | import java.util.function.Function; 8 | import java.util.function.Predicate; 9 | 10 | import com.packtpub.reactive.common.Program; 11 | 12 | /** 13 | * Some of examples of using lambdas. 14 | * 15 | * @author meddle 16 | */ 17 | public class Java8LambdasSyntaxIntroduction implements Program { 18 | 19 | /** 20 | * Functional interface with method with one argument, that returns a value. 21 | * 22 | * @author meddle 23 | */ 24 | interface Mapper { 25 | M map(V value); 26 | } 27 | 28 | /** 29 | * Functional interface with method with one argument, that doesn't return anything - just executes actions. 30 | * 31 | * @author meddle 32 | */ 33 | interface Action { 34 | void act(V value); 35 | } 36 | 37 | public static List map(List list, Mapper mapper) { 38 | List mapped = new ArrayList(list.size()); 39 | for (V v : list) { 40 | mapped.add(mapper.map(v)); 41 | } 42 | 43 | return mapped; 44 | } 45 | 46 | public static void act(List list, Action action) { 47 | for (V v : list) { 48 | action.act(v); 49 | } 50 | } 51 | 52 | @Override 53 | public String name() { 54 | return "Introduction to the new syntax and semantics"; 55 | } 56 | 57 | @Override 58 | public int chapter() { 59 | return 2; 60 | } 61 | 62 | @Override 63 | public void run() { 64 | // A list of numbers. 65 | List numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 66 | 67 | // A list of numbers powered by 2, using the custom map function. 68 | List mapped = map(numbers, new Mapper() { 69 | @Override 70 | public Integer map(Integer value) { 71 | return value * value; 72 | } 73 | }); 74 | 75 | // Reference to the System.out's print method. 76 | Consumer print = System.out::println; 77 | print.andThen(print).accept("Here we go!"); // 2x Here we go! 78 | 79 | // Defining a new lambda that turns a value to string and concatenates '!' to it. 80 | Function map = (value) -> (value + "!"); 81 | print.accept(map.apply(5)); // 5! 82 | 83 | // Another map lambda 84 | Mapper toMessage = (value) -> "We are happy to present to you : " 85 | + (value) + "!"; 86 | 87 | // Passing a lambda to a function, receiving interface with only one method. 88 | List messages = map(mapped, toMessage); 89 | 90 | // Predicate that tests if a number is odd as a lambda. 91 | Predicate odd = (value) -> value % 2 != 0; 92 | print.accept(odd.test(5) + ""); 93 | 94 | // Passing reference to a function, to method that receives functional interface. 95 | act(messages, System.out::println); 96 | 97 | // Using map and act with lambdas. 98 | List lambdaMapped = map(numbers, v -> { 99 | return "The square of " + v + " is " + (v * v) + "!"; 100 | }); 101 | act(lambdaMapped, v -> System.out.println(v)); 102 | } 103 | 104 | public static void main(String[] args) { 105 | new Java8LambdasSyntaxIntroduction().run(); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter02/PureAndHigherOrderFunctions.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter02; 2 | 3 | import java.util.function.Function; 4 | import java.util.function.Predicate; 5 | 6 | import com.packtpub.reactive.common.Program; 7 | 8 | /** 9 | * Demonstrates pure and higher order functions. 10 | * 11 | * @author meddle 12 | */ 13 | public class PureAndHigherOrderFunctions implements Program { 14 | 15 | @Override 16 | public String name() { 17 | return "Pure and higher functions"; 18 | } 19 | 20 | @Override 21 | public int chapter() { 22 | return 2; 23 | } 24 | 25 | @Override 26 | public void run() { 27 | // A pure function - no side effects 28 | Predicate even = (number) -> number % 2 == 0; 29 | 30 | // Not a pure function - with a side effect - prints something and then returns. 31 | Predicate impureEven = (number) -> { 32 | System.out.println("Printing here is side effect!"); 33 | return number % 2 == 0; 34 | }; 35 | 36 | int i = 5; 37 | while ((i--) > 0) { 38 | System.out.println("Is five even? - " + even.test(5)); 39 | System.out.println("Is five even? - " + impureEven.test(5)); 40 | } 41 | 42 | // A pure function - converts string to integer 43 | Function strToInt = s -> Integer.parseInt(s); 44 | 45 | // Some examples of applying higher order functions. 46 | System.out.println(highSum(v -> v * v, v -> v * v * v, 3, 2)); 47 | System.out.println(highSum(strToInt, strToInt, "4", "5")); 48 | System.out.println(highSum(strToInt, "4", "5")); 49 | 50 | System.out.println(greet("Hello").apply("world")); 51 | System.out.println(greet("Goodbye").apply("cruel world")); 52 | 53 | Function howdy = greet("Howdy"); 54 | System.out.println(howdy.apply("Tanya")); 55 | System.out.println(howdy.apply("Dali")); 56 | } 57 | 58 | /** 59 | * A higher order function - sums the results of two other functions, passed to it as parameters. 60 | */ 61 | public static int highSum(Function f1, 62 | Function f2, T data1, R data2) { 63 | return f1.apply(data1) + f2.apply(data2); 64 | } 65 | 66 | public static int highSum(Function f, T data1, T data2) { 67 | return highSum(f, f, data1, data2); 68 | } 69 | 70 | /** 71 | * A higher order function - returns a function. 72 | */ 73 | public static Function greet(String greeting) { 74 | return (String name) -> greeting + " " + name + "!"; 75 | } 76 | 77 | public static void main(String[] args) { 78 | new PureAndHigherOrderFunctions().run(); 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter02/ReactiveSumV2.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter02; 2 | 3 | import java.util.concurrent.CountDownLatch; 4 | import java.util.regex.Pattern; 5 | 6 | import rx.Observable; 7 | import rx.observables.ConnectableObservable; 8 | import rx.schedulers.Schedulers; 9 | 10 | import com.packtpub.reactive.common.CreateObservable; 11 | import com.packtpub.reactive.common.Program; 12 | 13 | /** 14 | * Version 2 of the Reactive Sum, implemented using Java 8 lambdas. 15 | * 16 | * @author meddle 17 | */ 18 | public class ReactiveSumV2 implements Program { 19 | 20 | private CountDownLatch latch = new CountDownLatch(1); 21 | 22 | public static Observable varStream(final String varName, 23 | Observable input) { 24 | final Pattern pattern = Pattern.compile("\\s*" + varName 25 | + "\\s*[:|=]\\s*(-?\\d+\\.?\\d*)"); 26 | 27 | return input 28 | .map(pattern::matcher) 29 | .filter(matcher -> matcher.matches() 30 | && matcher.group(1) != null) 31 | .map(matcher -> matcher.group(1)) 32 | .map(Double::parseDouble); 33 | } 34 | 35 | public void reactiveSum(Observable a, Observable b) { 36 | 37 | Observable 38 | .combineLatest(a.startWith(0.0), b.startWith(0.0), (x, y) -> x + y) 39 | .subscribeOn(Schedulers.io()) 40 | .subscribe( 41 | sum -> System.out.println("update : a + b = " + sum), 42 | error -> { 43 | System.out.println("Got an error!"); 44 | error.printStackTrace(); 45 | }, () -> { 46 | System.out.println("Exiting..."); 47 | latch.countDown(); 48 | }); 49 | 50 | } 51 | 52 | public String name() { 53 | return "Reactive Sum, version 2 (with lambdas)"; 54 | } 55 | 56 | public void run() { 57 | ConnectableObservable input = CreateObservable.from(System.in); 58 | 59 | Observable a = varStream("a", input); 60 | Observable b = varStream("b", input); 61 | 62 | reactiveSum(a, b); 63 | 64 | input.connect(); 65 | 66 | try { 67 | latch.await(); 68 | } catch (InterruptedException e) {} 69 | } 70 | 71 | @Override 72 | public int chapter() { 73 | return 2; 74 | } 75 | 76 | public static void main(String[] args) { 77 | new ReactiveSumV2().run(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter03/CreatingObservablesUsingJust.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter03; 2 | 3 | import rx.Observable; 4 | 5 | import com.packtpub.reactive.common.Program; 6 | 7 | /** 8 | * Demonstrates using Observable.just for creating Observables. 9 | * 10 | * @author meddle 11 | */ 12 | public class CreatingObservablesUsingJust implements Program { 13 | 14 | @Override 15 | public String name() { 16 | return "Using the Observable.just method to create Observables"; 17 | } 18 | 19 | @Override 20 | public int chapter() { 21 | return 3; 22 | } 23 | 24 | public static class User { 25 | 26 | private final String forename; 27 | private final String lastname; 28 | 29 | public User(String forename, String lastname) { 30 | this.forename = forename; 31 | this.lastname = lastname; 32 | } 33 | 34 | public String getForename() { 35 | return this.forename; 36 | } 37 | 38 | public String getLastname() { 39 | return this.lastname; 40 | } 41 | 42 | } 43 | 44 | @Override 45 | public void run() { 46 | Observable.just('S').subscribe(System.out::println); 47 | 48 | Observable.just('R', 'x', 'J', 'a', 'v', 'a').subscribe( 49 | System.out::print, System.err::println, System.out::println); 50 | 51 | Observable.just(new User("Dali", "Bali")) 52 | .map(u -> u.getForename() + " " + u.getLastname()) 53 | .subscribe(System.out::println); 54 | } 55 | 56 | public static void main(String[] args) { 57 | new CreatingObservablesUsingJust().run(); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter03/CreatingObservablesUsingVariousFactoryMethods.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter03; 2 | 3 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import rx.Observable; 8 | 9 | import com.packtpub.reactive.common.Program; 10 | 11 | /** 12 | * Demonstrates using Observable.interval, Observable.timer, Observable.error, 13 | * Observable.never, Observable.empty and Observable.range for Obsevable creation. 14 | * 15 | * @author meddle 16 | */ 17 | public class CreatingObservablesUsingVariousFactoryMethods implements Program { 18 | 19 | @Override 20 | public String name() { 21 | return "A few factory methods for creating Observables"; 22 | } 23 | 24 | @Override 25 | public int chapter() { 26 | return 3; 27 | } 28 | 29 | @Override 30 | public void run() { 31 | subscribePrint(Observable.interval(500L, TimeUnit.MILLISECONDS), 32 | "Interval Observable"); 33 | 34 | subscribePrint(Observable.timer(0L, 1L, TimeUnit.SECONDS), 35 | "Timed Interval Observable"); 36 | 37 | subscribePrint(Observable.timer(1L, TimeUnit.SECONDS), 38 | "Timer Observable"); 39 | 40 | subscribePrint(Observable.error(new Exception("Test Error!")), 41 | "Error Observable"); 42 | 43 | subscribePrint(Observable.empty(), "Empty Observable"); 44 | subscribePrint(Observable.never(), "Never Observable"); 45 | 46 | subscribePrint(Observable.range(1, 10), "Range Observable"); 47 | 48 | try { 49 | Thread.sleep(2000L); 50 | } catch (InterruptedException e) { 51 | } 52 | 53 | } 54 | 55 | public static void main(String[] args) { 56 | new CreatingObservablesUsingVariousFactoryMethods().run(); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter03/CreatingObservablesWithFrom.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter03; 2 | 3 | import java.io.IOException; 4 | import java.nio.file.DirectoryStream; 5 | import java.nio.file.Files; 6 | import java.nio.file.Path; 7 | import java.nio.file.Paths; 8 | import java.util.Arrays; 9 | import java.util.List; 10 | 11 | import rx.Observable; 12 | import rx.functions.Action1; 13 | 14 | import com.packtpub.reactive.common.Program; 15 | 16 | /** 17 | * A set of examples of using Observable.from. 18 | * 19 | * @author meddle 20 | */ 21 | public class CreatingObservablesWithFrom implements Program { 22 | 23 | public static Action1 N = (v) -> { 24 | }; 25 | public static Action1 NE = (e) -> { 26 | }; 27 | 28 | @Override 29 | public String name() { 30 | return "Creating Observables with Observable.from"; 31 | } 32 | 33 | @Override 34 | public int chapter() { 35 | return 3; 36 | } 37 | 38 | @Override 39 | public void run() { 40 | // from(list) 41 | List list = Arrays.asList("blue", "red", "green", "yellow", 42 | "orange", "cyan", "purple"); 43 | 44 | Observable listObservable = Observable.from(list); 45 | listObservable.subscribe(System.out::println); 46 | listObservable.subscribe(color -> System.out.print(color + "|"), NE, 47 | System.out::println); 48 | listObservable.subscribe(color -> System.out.print(color + "/"), NE, 49 | System.out::println); 50 | 51 | // from(Iterable) 52 | Path resources = Paths.get("src", "main", "resources"); 53 | try (DirectoryStream dStream = Files.newDirectoryStream(resources)) { 54 | Observable dirObservable = Observable.from(dStream); 55 | dirObservable.subscribe(System.out::println); 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | } 59 | 60 | // from(array) 61 | Observable arrayObservable = Observable.from(new Integer[] { 62 | 3, 5, 8 }); 63 | arrayObservable.subscribe(System.out::println); 64 | } 65 | 66 | public static void main(String[] args) { 67 | new CreatingObservablesWithFrom().run(); 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter03/ObservableCreateExample.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter03; 2 | 3 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 4 | 5 | import java.nio.file.Files; 6 | import java.nio.file.Path; 7 | import java.nio.file.Paths; 8 | import java.util.Arrays; 9 | import java.util.Iterator; 10 | import java.util.List; 11 | 12 | import rx.Observable; 13 | import rx.Observable.OnSubscribe; 14 | import rx.Subscriber; 15 | import rx.Subscription; 16 | import rx.schedulers.Schedulers; 17 | 18 | import com.packtpub.reactive.common.Program; 19 | 20 | /** 21 | * Show case of the Observable.create method. 22 | * Contains a simple implementation of the Observable.from(Iterable) method, using Observable.create. 23 | * 24 | * @author meddle 25 | */ 26 | public class ObservableCreateExample implements Program { 27 | 28 | @Override 29 | public String name() { 30 | return "Demonstration of the Observable.create method"; 31 | } 32 | 33 | @Override 34 | public int chapter() { 35 | return 3; 36 | } 37 | 38 | public static Observable fromIterable(final Iterable iterable) { 39 | return Observable.create(new OnSubscribe() { 40 | @Override 41 | public void call(Subscriber subscriber) { 42 | try { 43 | Iterator iterator = iterable.iterator(); 44 | 45 | while (iterator.hasNext()) { 46 | if (subscriber.isUnsubscribed()) { 47 | return; 48 | } 49 | subscriber.onNext(iterator.next()); 50 | } 51 | 52 | if (!subscriber.isUnsubscribed()) { 53 | subscriber.onCompleted(); 54 | } 55 | } catch (Exception e) { 56 | if (!subscriber.isUnsubscribed()) { 57 | subscriber.onError(e); 58 | } 59 | } 60 | 61 | } 62 | }); 63 | } 64 | 65 | @Override 66 | public void run() { 67 | subscribePrint(fromIterable(Arrays.asList(1, 3, 5)), "List1"); 68 | subscribePrint(fromIterable(Arrays.asList(2, 4, 6)), "List2"); 69 | 70 | try { 71 | Path path = Paths.get("src", "main", "resources", "lorem_big.txt"); 72 | List data = Files.readAllLines(path); 73 | 74 | Observable observable = fromIterable(data).subscribeOn( 75 | Schedulers.computation()); 76 | 77 | Subscription subscription = subscribePrint(observable, "File"); 78 | System.out.println("Before unsubscribe!"); 79 | System.out.println("-------------------"); 80 | 81 | subscription.unsubscribe(); 82 | 83 | System.out.println("-------------------"); 84 | System.out.println("After unsubscribe!"); 85 | 86 | Thread.sleep(100L); 87 | } catch (Exception e) { 88 | e.printStackTrace(); 89 | } 90 | } 91 | 92 | public static void main(String[] args) { 93 | new ObservableCreateExample().run(); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter03/ReactiveSumV3.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter03; 2 | 3 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 4 | import rx.Observable; 5 | import rx.subjects.BehaviorSubject; 6 | 7 | import com.packtpub.reactive.common.Program; 8 | 9 | /** 10 | * Another version of the 'Reactive Sum', this time it is implemented, using {@link BehaviorSubject}s. 11 | * 12 | * @author meddle 13 | */ 14 | public class ReactiveSumV3 implements Program { 15 | 16 | public static class ReactiveSum { 17 | private BehaviorSubject a = BehaviorSubject.create(0.0); 18 | private BehaviorSubject b = BehaviorSubject.create(0.0); 19 | private BehaviorSubject c = BehaviorSubject.create(0.0); 20 | 21 | public ReactiveSum() { 22 | Observable.combineLatest(a, b, (x, y) -> x + y).subscribe(c); 23 | } 24 | 25 | public double getA() { 26 | return a.getValue(); 27 | } 28 | 29 | public void setA(double a) { 30 | this.a.onNext(a); 31 | } 32 | 33 | public Observable obsA() { 34 | return a.asObservable(); 35 | } 36 | 37 | public double getB() { 38 | return b.getValue(); 39 | } 40 | 41 | public void setB(double b) { 42 | this.b.onNext(b); 43 | } 44 | 45 | public Observable obsB() { 46 | return b.asObservable(); 47 | } 48 | 49 | public double getC() { 50 | return c.getValue(); 51 | } 52 | 53 | public Observable obsC() { 54 | return c.asObservable(); 55 | } 56 | 57 | } 58 | 59 | @Override 60 | public String name() { 61 | return "Reactive Sum, version 3 (with Subjects)"; 62 | } 63 | 64 | @Override 65 | public int chapter() { 66 | return 3; 67 | } 68 | 69 | @Override 70 | public void run() { 71 | ReactiveSum sum = new ReactiveSum(); 72 | 73 | subscribePrint(sum.obsC(), "Sum"); 74 | sum.setA(5); 75 | sum.setB(4); 76 | } 77 | 78 | public static void main(String[] args) { 79 | new ReactiveSumV3().run(); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter03/SubjectsDemonstration.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter03; 2 | 3 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import rx.Observable; 8 | import rx.Subscription; 9 | import rx.subjects.PublishSubject; 10 | import rx.subjects.Subject; 11 | 12 | import com.packtpub.reactive.common.Program; 13 | 14 | /** 15 | * Demonstration of using Subjects and what we could do with them. 16 | * Uses a {@link PublishSubject} to subscribe to an {@link Observable} and propagate its notifications. 17 | * 18 | * @author meddle 19 | */ 20 | public class SubjectsDemonstration implements Program { 21 | 22 | @Override 23 | public String name() { 24 | return "Subjects demonstration"; 25 | } 26 | 27 | @Override 28 | public int chapter() { 29 | return 3; 30 | } 31 | 32 | 33 | 34 | @Override 35 | public void run() { 36 | 37 | Observable interval = Observable.interval(100L, 38 | TimeUnit.MILLISECONDS); 39 | 40 | Subject publishSubject = PublishSubject.create(); 41 | interval.subscribe(publishSubject); 42 | 43 | Subscription sub1 = subscribePrint(publishSubject, "First"); 44 | Subscription sub2 = subscribePrint(publishSubject, "Second"); 45 | 46 | Subscription sub3 = null; 47 | try { 48 | Thread.sleep(300L); 49 | 50 | publishSubject.onNext(555L); 51 | sub3 = subscribePrint(publishSubject, "Third"); 52 | Thread.sleep(500L); 53 | } catch (InterruptedException e) { 54 | } 55 | 56 | sub1.unsubscribe(); 57 | sub2.unsubscribe(); 58 | sub3.unsubscribe(); 59 | 60 | try { 61 | Thread.sleep(500L); 62 | } catch (InterruptedException e) { 63 | } 64 | 65 | Subscription sub4 = subscribePrint(publishSubject, "Fourth"); 66 | 67 | try { 68 | Thread.sleep(500L); 69 | } catch (InterruptedException e) { 70 | } 71 | 72 | sub4.unsubscribe(); 73 | 74 | System.out.println("-----------------------------"); 75 | 76 | } 77 | 78 | public static void main(String[] args) { 79 | new SubjectsDemonstration().run(); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter03/UsingConnectableObservables.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter03; 2 | 3 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import rx.Observable; 8 | import rx.Subscription; 9 | import rx.observables.ConnectableObservable; 10 | 11 | import com.packtpub.reactive.common.Program; 12 | 13 | /** 14 | * Demonstrates how to create and use ConnectableObservables. 15 | * 16 | * @author meddle 17 | */ 18 | public class UsingConnectableObservables implements Program { 19 | 20 | @Override 21 | public String name() { 22 | return "A ConnectableObservable demonstration"; 23 | } 24 | 25 | @Override 26 | public int chapter() { 27 | return 3; 28 | } 29 | 30 | @Override 31 | public void run() { 32 | Observable interval = Observable.interval(100L, 33 | TimeUnit.MILLISECONDS); 34 | ConnectableObservable published = interval.publish(); 35 | 36 | Subscription sub1 = subscribePrint(published, "First"); 37 | Subscription sub2 = subscribePrint(published, "Second"); 38 | 39 | published.connect(); 40 | 41 | Subscription sub3 = null; 42 | try { 43 | Thread.sleep(300L); 44 | 45 | sub3 = subscribePrint(published, "Third"); 46 | Thread.sleep(500L); 47 | } catch (InterruptedException e) { 48 | } 49 | 50 | sub1.unsubscribe(); 51 | sub2.unsubscribe(); 52 | sub3.unsubscribe(); 53 | 54 | System.out.println("-----------------------------------"); 55 | 56 | Observable refCount = interval.share(); // publish().refCount(); 57 | 58 | sub1 = subscribePrint(refCount, "First"); 59 | sub2 = subscribePrint(refCount, "Second"); 60 | 61 | sub3 = null; 62 | try { 63 | Thread.sleep(300L); 64 | 65 | sub3 = subscribePrint(refCount, "Third"); 66 | Thread.sleep(500L); 67 | } catch (InterruptedException e) { 68 | } 69 | 70 | sub1.unsubscribe(); 71 | sub2.unsubscribe(); 72 | sub3.unsubscribe(); 73 | 74 | Subscription sub4 = subscribePrint(refCount, "Fourth"); 75 | 76 | try { 77 | Thread.sleep(300L); 78 | } catch (InterruptedException e) { 79 | } 80 | sub4.unsubscribe(); 81 | } 82 | 83 | public static void main(String[] args) { 84 | new UsingConnectableObservables().run(); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter04/FilteringExamples.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter04; 2 | 3 | import java.util.Arrays; 4 | 5 | import rx.Observable; 6 | 7 | import com.packtpub.reactive.common.Program; 8 | 9 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 10 | 11 | /** 12 | * Demonstrates the filter, takeLast, last, takeLastBuffer, lastOrDefault, 13 | * skipLast, skip, first, elementAt, distinct, distinctUntilChanged and ofType operators. 14 | * 15 | * @author meddle 16 | */ 17 | public class FilteringExamples implements Program { 18 | 19 | @Override 20 | public String name() { 21 | return "Various examples of using filtering operators"; 22 | } 23 | 24 | @Override 25 | public int chapter() { 26 | return 4; 27 | } 28 | 29 | @Override 30 | public void run() { 31 | Observable numbers = Observable.just(1, 13, 32, 45, 21, 8, 98, 32 | 103, 55); 33 | 34 | Observable filter = numbers.filter(n -> n % 2 == 0); 35 | subscribePrint(filter, "Filter"); 36 | 37 | subscribePrint(numbers.takeLast(4), "Last 4"); 38 | subscribePrint(numbers.last(), "Last"); 39 | subscribePrint(numbers.takeLastBuffer(4), "Last buffer"); 40 | 41 | subscribePrint(numbers.lastOrDefault(200), "Last or default"); 42 | subscribePrint(Observable.empty().lastOrDefault(200), "Last or default"); 43 | 44 | subscribePrint(numbers.skipLast(4), "Skip last 4"); 45 | subscribePrint(numbers.skip(4), "Skip 4"); 46 | 47 | subscribePrint(numbers.take(4), "First 4"); 48 | 49 | subscribePrint(numbers.first(), "First"); 50 | 51 | subscribePrint(numbers.elementAt(5), "At 5"); 52 | 53 | Observable words = Observable.just("One", "of", "the", "few", 54 | "of", "the", "crew", "crew"); 55 | subscribePrint(words.distinct(), "Distinct"); 56 | subscribePrint(words.distinctUntilChanged(), "Distinct until changed"); 57 | 58 | Observable various = Observable.from(Arrays.asList("1", 2, 3.0, 4, 59 | 5L)); 60 | 61 | subscribePrint(various.ofType(Integer.class), "Only integers"); 62 | } 63 | 64 | public static void main(String[] args) { 65 | new FilteringExamples().run(); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter04/FlatMapAndFiles.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter04; 2 | 3 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 4 | 5 | import java.nio.file.Paths; 6 | 7 | import rx.Observable; 8 | 9 | import com.packtpub.reactive.common.CreateObservable; 10 | import com.packtpub.reactive.common.Program; 11 | 12 | /** 13 | * Demonstration of using flatMap with an Observable created by directory stream, 14 | * reading all the files from it, using Observables. 15 | * 16 | * @author meddle 17 | */ 18 | public class FlatMapAndFiles implements Program { 19 | 20 | @Override 21 | public String name() { 22 | return "Working with files using flatMap"; 23 | } 24 | 25 | @Override 26 | public int chapter() { 27 | return 4; 28 | } 29 | 30 | @Override 31 | public void run() { 32 | Observable fsObs = CreateObservable.listFolder( 33 | Paths.get("src", "main", "resources"), 34 | "{lorem.txt,letters.txt}") 35 | .flatMap(path -> CreateObservable.from(path)); 36 | 37 | subscribePrint(fsObs, "FS"); 38 | } 39 | 40 | public static void main(String[] args) { 41 | new FlatMapAndFiles().run(); 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter04/MappingExamples.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter04; 2 | 3 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 4 | 5 | import java.nio.file.Paths; 6 | import java.util.Arrays; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import rx.Observable; 10 | import rx.Subscription; 11 | import rx.functions.Func0; 12 | import rx.functions.Func1; 13 | 14 | import com.packtpub.reactive.common.CreateObservable; 15 | import com.packtpub.reactive.common.Program; 16 | 17 | /** 18 | * Demonstration of using map, flatMap, flatMapIterable and switchMap. 19 | * 20 | * @author meddle 21 | */ 22 | public class MappingExamples implements Program { 23 | 24 | @Override 25 | public String name() { 26 | return "Examples of using Observable transformations"; 27 | } 28 | 29 | @Override 30 | public int chapter() { 31 | return 4; 32 | } 33 | 34 | @Override 35 | public void run() { 36 | Observable mapped = Observable.just(2, 3, 5, 8).map(v -> v * 3) 37 | .map(v -> (v % 2 == 0) ? "even" : "odd"); 38 | 39 | subscribePrint(mapped, "map"); 40 | 41 | System.out.println("-----------------"); 42 | 43 | Observable flatMapped = Observable.just(3, 5, 8).flatMap( 44 | v -> Observable.range(v, v)); 45 | 46 | subscribePrint(flatMapped, "flatMap"); 47 | 48 | System.out.println("-----------------"); 49 | 50 | flatMapped = Observable 51 | .just(-1, 0, 1) 52 | .map(v -> 2 / v) 53 | .flatMap( 54 | new Func1>() { 55 | @Override 56 | public Observable call(Integer v) { 57 | return Observable.just(v); 58 | } 59 | }, 60 | new Func1>() { 61 | @Override 62 | public Observable call(Throwable e) { 63 | return Observable.just(0); 64 | } 65 | }, 66 | new Func0>() { 67 | @Override 68 | public Observable call() { 69 | return Observable.just(42); 70 | } 71 | } 72 | ); 73 | 74 | subscribePrint(flatMapped, "flatMap"); 75 | System.out.println("-----------------"); 76 | 77 | flatMapped = Observable.just(5, 432).flatMap(v -> Observable.range(v, 2), 78 | (x, y) -> x + y); 79 | 80 | subscribePrint(flatMapped, "flatMap"); 81 | System.out.println("-----------------"); 82 | 83 | Observable fsObs = CreateObservable.listFolder( 84 | Paths.get("src", "main", "resources"), 85 | "{lorem.txt,letters.txt}") 86 | .flatMap(path -> CreateObservable.from(path), (path, line) -> path.getFileName() + " : " + line); 87 | 88 | subscribePrint(fsObs, "FS"); 89 | 90 | Observable fMapped = Observable.just(Arrays.asList(2, 4), 91 | Arrays.asList("two", "four"), Arrays.asList('t', 'f'), 92 | Arrays.asList(true, false)).flatMap(l -> Observable.from(l)); 93 | 94 | subscribePrint(fMapped, "flatMap"); 95 | Observable fIterableMapped = Observable.just(Arrays.asList(2, 4), 96 | Arrays.asList("two", "four"), Arrays.asList('t', 'f'), 97 | Arrays.asList(true, false)).flatMapIterable(l -> l); 98 | 99 | subscribePrint(fIterableMapped, "flatMapIterable"); 100 | System.out.println("-----------------"); 101 | 102 | Observable obs = Observable 103 | .interval(40L, TimeUnit.MILLISECONDS).switchMap( 104 | v -> Observable.timer(0L, 10L, TimeUnit.MILLISECONDS) 105 | .map(u -> "Observable <" + (v + 1) + "> : " + (v + u))); 106 | 107 | Subscription sub = subscribePrint(obs, "switchMap"); 108 | 109 | try { 110 | Thread.sleep(400L); 111 | } catch (InterruptedException e) { 112 | } 113 | sub.unsubscribe(); 114 | 115 | System.out.println("-----------------"); 116 | } 117 | 118 | public static void main(String[] args) { 119 | new MappingExamples().run(); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter04/ScanAndUsingMultipleOperators.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter04; 2 | 3 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 4 | 5 | import java.beans.Introspector; 6 | import java.nio.file.Paths; 7 | 8 | import rx.Observable; 9 | 10 | import com.packtpub.reactive.common.CreateObservable; 11 | import com.packtpub.reactive.common.Program; 12 | 13 | /** 14 | * Demonstrates how to use the `scan` operator. 15 | * Contains an example of working with data using the majority of the operators learned through the chapter. 16 | * 17 | * @author meddle 18 | */ 19 | public class ScanAndUsingMultipleOperators implements Program { 20 | 21 | @Override 22 | public String name() { 23 | return "Demonstration of using Observable#scan and more"; 24 | } 25 | 26 | @Override 27 | public int chapter() { 28 | return 4; 29 | } 30 | 31 | @Override 32 | public void run() { 33 | Observable scan = Observable.range(1, 10) 34 | .scan((p, v) -> p + v); 35 | 36 | subscribePrint(scan, "Sum"); 37 | 38 | subscribePrint(scan.last(), "Final sum"); 39 | 40 | Observable file = CreateObservable.fromViaUsing(Paths.get("src", 41 | "main", "resources", "letters.txt")); 42 | 43 | scan = file.scan(0, (p, v) -> p + 1); 44 | 45 | subscribePrint(scan.last(), "wc -l"); 46 | 47 | file = CreateObservable.fromViaUsing(Paths.get("src", "main", "resources", 48 | "operators.txt")); 49 | 50 | Observable multy = file 51 | .flatMap(line -> Observable.from(line.split("\\."))) 52 | .map(String::trim) 53 | .map(sentence -> sentence.split(" ")) 54 | .filter(array -> array.length > 0) 55 | .map(array -> array[0]) 56 | .distinct() 57 | .groupBy(word -> word.contains("'")) 58 | .flatMap( 59 | observable -> observable.getKey() ? observable 60 | : observable.map(Introspector::decapitalize)) 61 | .map(String::trim).filter(word -> !word.isEmpty()) 62 | .scan((current, word) -> current + " " + word).last() 63 | .map(sentence -> sentence + "."); 64 | subscribePrint(multy, "Multiple operators"); 65 | } 66 | 67 | public static void main(String[] args) { 68 | new ScanAndUsingMultipleOperators().run(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter04/UsingGroupBy.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter04; 2 | 3 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | import rx.Observable; 9 | 10 | import com.packtpub.reactive.common.Program; 11 | 12 | /** 13 | * Demonstrates how the groupBy operator can be used. 14 | * 15 | * @author meddle 16 | */ 17 | public class UsingGroupBy implements Program { 18 | 19 | 20 | @Override 21 | public String name() { 22 | return "Demonstration of using the Observable#groupBy operator"; 23 | } 24 | 25 | @Override 26 | public int chapter() { 27 | return 4; 28 | } 29 | 30 | @Override 31 | public void run() { 32 | List albums = Arrays.asList( 33 | "The Piper at the Gates of Dawn", "A Saucerful of Secrets", "More", 34 | "Ummagumma", "Atom Heart Mother", "Meddle", "Obscured by Clouds", 35 | "The Dark Side of the Moon", "Wish You Were Here", "Animals", 36 | "The Wall"); 37 | 38 | Observable.from(albums).groupBy(album -> album.split(" ").length) 39 | .subscribe(obs -> { 40 | subscribePrint(obs, obs.getKey() + " word(s)"); 41 | }); 42 | 43 | Observable 44 | .from(albums) 45 | .groupBy(album -> album.replaceAll("[^mM]", "").length(), 46 | album -> album.replaceAll("[mM]", "*")) 47 | .subscribe( 48 | obs -> subscribePrint(obs, obs.getKey() 49 | + " occurences of 'm'")); 50 | 51 | } 52 | 53 | public static void main(String[] args) { 54 | new UsingGroupBy().run(); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter04/VariousTransformationsDemonstration.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter04; 2 | 3 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import rx.Observable; 10 | import rx.Subscription; 11 | import rx.schedulers.TimeInterval; 12 | import rx.schedulers.Timestamped; 13 | 14 | import com.packtpub.reactive.common.Program; 15 | 16 | /** 17 | * Demonstrates various transforming operators : timestamp, materialize, timeInterval and cast. 18 | * 19 | * @author meddle 20 | */ 21 | public class VariousTransformationsDemonstration implements Program { 22 | 23 | @Override 24 | public String name() { 25 | return "Demonstration of working with the cast, materialize, timestamp and timeInterval operators"; 26 | } 27 | 28 | @Override 29 | public int chapter() { 30 | return 4; 31 | } 32 | 33 | @Override 34 | public void run() { 35 | List list = Arrays.asList(1, 2, 3); 36 | Observable iObs = Observable.from(list).cast(Integer.class); 37 | 38 | subscribePrint(iObs, "Integers"); 39 | 40 | Observable> timestamp = Observable.from(list) 41 | .timestamp(); 42 | 43 | subscribePrint(timestamp, "Timestamps"); 44 | 45 | Observable> timeInterval = Observable.timer(0L, 46 | 150L, TimeUnit.MILLISECONDS).timeInterval(); 47 | 48 | Subscription sub = subscribePrint(timeInterval, "Time intervals"); 49 | 50 | try { 51 | Thread.sleep(1000L); 52 | } catch (InterruptedException e) { 53 | } 54 | sub.unsubscribe(); 55 | } 56 | 57 | public static void main(String[] args) { 58 | new VariousTransformationsDemonstration().run(); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter05/CombiningObservables.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter05; 2 | 3 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 4 | import static com.packtpub.reactive.common.Helpers.blockingSubscribePrint; 5 | 6 | import java.util.Arrays; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import rx.Observable; 10 | 11 | import com.packtpub.reactive.common.Program; 12 | 13 | /** 14 | * Combining {@link Observable}s using {@link Observable#zip}, {@link Observable#merge} and {@link Observable#concat}. 15 | * 16 | * @author meddle 17 | */ 18 | public class CombiningObservables implements Program { 19 | 20 | @Override 21 | public String name() { 22 | return "Examples of combining Observables"; 23 | } 24 | 25 | @Override 26 | public int chapter() { 27 | return 5; 28 | } 29 | 30 | public T onlyFirstArg(T arg1, R arg2) { 31 | return arg1; 32 | } 33 | 34 | public Observable slowDown(Observable o, long ms) { 35 | return o.zipWith(Observable.interval(ms, TimeUnit.MILLISECONDS), (elem, i) -> elem); 36 | } 37 | 38 | @Override 39 | public void run() { 40 | Observable zip = Observable.zip( 41 | Observable.just(1, 3, 4), 42 | Observable.just(5, 2, 6), 43 | (a, b) -> a + b); 44 | subscribePrint(zip, "Simple zip"); 45 | 46 | Observable timedZip = 47 | slowDown(Observable.from(Arrays.asList("Z", "I", "P", "P")), 300); 48 | blockingSubscribePrint(timedZip, "Timed zip"); 49 | 50 | Observable greetings = 51 | slowDown(Observable.just("Hello", "Hi", "Howdy", "Zdravei", "Yo", "Good to see ya"), 1000); 52 | 53 | Observable names = 54 | slowDown(Observable.just("Meddle", "Tanya", "Dali", "Joshua"), 1500L); 55 | 56 | Observable punctuation = 57 | slowDown(Observable.just(".", "?", "!", "!!!", "..."), 1100L); 58 | 59 | Observable combined = Observable.combineLatest( 60 | greetings, names, punctuation, 61 | (greeting, name, puntuation) -> greeting + " " + name + puntuation); 62 | 63 | blockingSubscribePrint(combined, "Sentences"); 64 | 65 | Observable merged = Observable.merge(greetings, names, punctuation); 66 | blockingSubscribePrint(merged, "Words"); 67 | 68 | Observable concat = Observable.concat(greetings, names, punctuation); 69 | blockingSubscribePrint(concat, "Concat"); 70 | 71 | blockingSubscribePrint(punctuation.startWith(names).startWith(greetings), "SW"); 72 | } 73 | 74 | public static void main(String[] args) { 75 | new CombiningObservables().run(); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter05/Conditionals.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter05; 2 | 3 | import static com.packtpub.reactive.common.Helpers.blockingSubscribePrint; 4 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 5 | 6 | import java.util.Random; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import rx.Observable; 10 | 11 | import com.packtpub.reactive.common.Program; 12 | 13 | /** 14 | * Demonstration of using the {@link Observable#amb}, {@link Observable#takeWhile}, {@link Observable#takeUntil}, 15 | * {@link Observable#skipUntil} and {@link Observable#defaultIfEmpty}. 16 | * 17 | * @author meddle 18 | */ 19 | public class Conditionals implements Program { 20 | 21 | @Override 22 | public String name() { 23 | return "Some examples of using conditionals"; 24 | } 25 | 26 | @Override 27 | public int chapter() { 28 | return 5; 29 | } 30 | 31 | @Override 32 | public void run() { 33 | Observable words = Observable.just("Some", "Other"); 34 | Observable interval = Observable 35 | .interval(500L, TimeUnit.MILLISECONDS).take(2); 36 | 37 | Observable amb = Observable.amb(words, interval); 38 | blockingSubscribePrint(amb, "Amb 1"); 39 | 40 | Random r = new Random(); 41 | Observable source1 = Observable.just("data from source 1") 42 | .delay(r.nextInt(1000), TimeUnit.MILLISECONDS); 43 | Observable source2 = Observable.just("data from source 2") 44 | .delay(r.nextInt(1000), TimeUnit.MILLISECONDS); 45 | blockingSubscribePrint(Observable.amb(source1, source2), "Amb 2"); 46 | 47 | words = Observable.just("one", "way", "or", "another", "I'll", "learn", "RxJava") 48 | .zipWith(Observable.interval(200L, TimeUnit.MILLISECONDS), (x, y) -> x); 49 | 50 | blockingSubscribePrint(words.takeUntil(interval).delay(1L, TimeUnit.SECONDS), "takeUntil"); 51 | blockingSubscribePrint(words.delay(800L, TimeUnit.MILLISECONDS).takeWhile( 52 | word -> word.length() > 2), "takeWhile"); 53 | 54 | 55 | blockingSubscribePrint(words.skipUntil(interval), "skipUntil"); 56 | 57 | 58 | Observable test = Observable.empty().defaultIfEmpty(5); 59 | subscribePrint(test, "defaultIfEmpty"); 60 | } 61 | 62 | public static void main(String[] args) { 63 | new Conditionals().run(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter05/HandlingErrors.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter05; 2 | 3 | import static com.packtpub.reactive.common.Helpers.subscribePrint; 4 | 5 | import java.util.concurrent.TimeUnit; 6 | 7 | import rx.Observable; 8 | import rx.Observable.OnSubscribe; 9 | import rx.Subscriber; 10 | import rx.schedulers.Schedulers; 11 | 12 | import com.packtpub.reactive.common.Program; 13 | 14 | /** 15 | * Demonstrates working with {@link Observable#onErrorReturn}, {@link Observable#onErrorResumeNext} and {@link Observable#onExceptionResumeNext} 16 | * as well as retrying with {@link Observable#retry} and {@link Observable#retryWhen}. 17 | * 18 | * @author meddle 19 | */ 20 | public class HandlingErrors implements Program { 21 | 22 | class FooException extends RuntimeException { 23 | private static final long serialVersionUID = 1L; 24 | public FooException() { 25 | super("Foo!"); 26 | } 27 | } 28 | 29 | class BooException extends RuntimeException { 30 | private static final long serialVersionUID = 1L; 31 | public BooException() { 32 | super("Boo!"); 33 | } 34 | } 35 | 36 | class ErrorEmitter implements OnSubscribe { 37 | 38 | private int throwAnErrorCounter = 5; 39 | 40 | @Override 41 | public void call(Subscriber subscriber) { 42 | subscriber.onNext(1); 43 | subscriber.onNext(2); 44 | 45 | if (throwAnErrorCounter > 4) { 46 | throwAnErrorCounter--; 47 | subscriber.onError(new FooException()); 48 | return; 49 | } 50 | if (throwAnErrorCounter > 0) { 51 | throwAnErrorCounter--; 52 | subscriber.onError(new BooException()); 53 | return; 54 | } 55 | 56 | subscriber.onNext(3); 57 | subscriber.onNext(4); 58 | subscriber.onCompleted(); 59 | 60 | } 61 | } 62 | 63 | @Override 64 | public String name() { 65 | return "Examples of handling errors"; 66 | } 67 | 68 | @Override 69 | public int chapter() { 70 | return 5; 71 | } 72 | 73 | @Override 74 | public void run() { 75 | 76 | Observable numbers = Observable.just("1", "2", "three", "4", "5"); 77 | 78 | Observable n = numbers.map(Integer::parseInt).onErrorReturn(e -> -1); 79 | 80 | subscribePrint(n, "error returned"); 81 | 82 | Observable defaultOnError = Observable.just(5, 4, 3, 2, 1); 83 | 84 | n = numbers.map(Integer::parseInt).onErrorResumeNext(defaultOnError); 85 | 86 | subscribePrint(n, "on error resume next"); 87 | 88 | n = numbers.map(Integer::parseInt).onExceptionResumeNext(defaultOnError); 89 | 90 | subscribePrint(n, "on exception resume next"); 91 | 92 | n = numbers.doOnNext(number -> { 93 | assert !number.equals("three"); 94 | }).map(Integer::parseInt).onExceptionResumeNext(defaultOnError); 95 | 96 | 97 | subscribePrint(n, "on exception resume next 2"); 98 | 99 | n = numbers.doOnNext(number -> { 100 | assert !number.equals("three"); 101 | }).map(Integer::parseInt).onErrorResumeNext(defaultOnError); 102 | 103 | subscribePrint(n, "on error resume next 2"); 104 | 105 | subscribePrint(Observable.create(new ErrorEmitter()).retry(), "Retry"); 106 | 107 | Observable when = Observable.create(new ErrorEmitter()).retryWhen(attempts -> { 108 | return attempts.flatMap(error -> { 109 | if (error instanceof FooException) { 110 | System.err.println("Delaying..."); 111 | return Observable.timer(1L, TimeUnit.SECONDS, Schedulers.immediate()); 112 | } 113 | 114 | return Observable.error(error); 115 | }); 116 | }).retry((attempts, error) -> { 117 | return (error instanceof BooException) && attempts < 3; 118 | }); 119 | 120 | subscribePrint(when, "retryWhen"); 121 | 122 | } 123 | 124 | public static void main(String[] args) { 125 | new HandlingErrors().run(); 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter05/HttpRequestsExample.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter05; 2 | 3 | import static com.packtpub.reactive.common.Helpers.blockingSubscribePrint; 4 | 5 | import java.io.IOException; 6 | import java.util.HashSet; 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | import java.util.concurrent.ConcurrentHashMap; 11 | 12 | import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; 13 | import org.apache.http.impl.nio.client.HttpAsyncClients; 14 | import org.apache.http.nio.client.HttpAsyncClient; 15 | 16 | import rx.Observable; 17 | import rx.apache.http.ObservableHttp; 18 | 19 | import com.google.gson.Gson; 20 | import com.packtpub.reactive.common.Program; 21 | 22 | /** 23 | * Using multiple {@link Observable} operators in order to handle and augment an HTTP response 24 | * from Github. 25 | * 26 | * @author meddle 27 | */ 28 | public class HttpRequestsExample implements Program { 29 | 30 | @Override 31 | public String name() { 32 | return "Example of doing HTTP requests and handling responses with Observables"; 33 | } 34 | 35 | @Override 36 | public int chapter() { 37 | return 5; 38 | } 39 | 40 | private Map>> cache = new ConcurrentHashMap<>(); 41 | 42 | public Observable> fromCache(String url) { 43 | return Observable.from(getCache(url)).defaultIfEmpty(null) 44 | .flatMap(json -> (json == null) ? Observable.never() : Observable.just(json)) 45 | .doOnNext(json -> json.put("json_cached", true)); 46 | } 47 | 48 | public Set> getCache(String url) { 49 | if (!cache.containsKey(url)) { 50 | cache.put(url, new HashSet>()); 51 | } 52 | return cache.get(url); 53 | } 54 | 55 | @SuppressWarnings({ "rawtypes" }) 56 | @Override 57 | public void run() { 58 | try(CloseableHttpAsyncClient client = HttpAsyncClients.createDefault()) { 59 | 60 | client.start(); 61 | 62 | String username = "meddle0x53"; 63 | 64 | Observable resp = githubUserInfoRequest(client, username); 65 | 66 | blockingSubscribePrint(resp 67 | .map(json -> json.get("name") + "(" + json.get("language") + ")") 68 | , "Json"); 69 | 70 | } catch (IOException e1) { 71 | e1.printStackTrace(); 72 | } 73 | } 74 | 75 | @SuppressWarnings({ "rawtypes" }) 76 | private Observable githubUserInfoRequest( 77 | HttpAsyncClient client, String githubUser) { 78 | if (githubUser == null) { 79 | return Observable.error(new NullPointerException("Github user must not be null!")); 80 | } 81 | 82 | String url = "https://api.github.com/users/" + githubUser + "/repos"; 83 | 84 | Observable response = requestJson(client, url); 85 | return response 86 | .filter(json -> json.containsKey("git_url")) 87 | .filter(json -> json.get("fork").equals(false)); 88 | } 89 | 90 | @SuppressWarnings({ "rawtypes", "unchecked" }) 91 | private Observable requestJson(HttpAsyncClient client, 92 | String url) { 93 | Observable rawResponse = ObservableHttp 94 | .createGet(url, client) 95 | .toObservable() 96 | .flatMap(resp -> resp.getContent() 97 | .map(bytes -> new String(bytes, java.nio.charset.StandardCharsets.UTF_8))) 98 | .retry(5) 99 | .cast(String.class) 100 | .map(String::trim) 101 | .doOnNext(resp -> getCache(url).clear()); 102 | 103 | Observable objects = rawResponse 104 | .filter(data -> data.startsWith("{")) 105 | .map(data -> "[" + data + "]"); 106 | 107 | Observable arrays = rawResponse 108 | .filter(data -> data.startsWith("[")); 109 | 110 | Observable response = arrays.ambWith(objects) 111 | .map(data -> { 112 | return new Gson().fromJson(data, List.class); 113 | }).flatMapIterable(list -> list) 114 | .cast(Map.class) 115 | .doOnNext(json -> getCache(url).add((Map) json)); 116 | 117 | return Observable.amb(fromCache(url), response); 118 | } 119 | 120 | public static void main(String[] args) { 121 | new HttpRequestsExample().run(); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter06/BackpressureExamples.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter06; 2 | 3 | import java.nio.file.Files; 4 | import java.nio.file.Path; 5 | import java.nio.file.Paths; 6 | import java.util.concurrent.CountDownLatch; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import rx.Observable; 10 | import rx.schedulers.Schedulers; 11 | 12 | import com.packtpub.reactive.common.CreateObservable; 13 | import com.packtpub.reactive.common.Helpers; 14 | import com.packtpub.reactive.common.Program; 15 | 16 | /** 17 | * Demonstrates using the {@link Observable#sample}, {@link Observable#buffer}, {@link Observable#window} 18 | * {@link Observable#throttleLast}, {@link Observable#debounce}, {@link Observable#onBackpressureDrop} and 19 | * {@link Observable#onBackpressureBuffer} operators. 20 | * 21 | * @author meddle 22 | */ 23 | public class BackpressureExamples implements Program { 24 | 25 | @Override 26 | public String name() { 27 | return "Examples demonstrating backpressure and buffering operators"; 28 | } 29 | 30 | @Override 31 | public int chapter() { 32 | return 6; 33 | } 34 | 35 | @Override 36 | public void run() { 37 | 38 | CountDownLatch latch = new CountDownLatch(7); 39 | 40 | Path path = Paths.get("src", "main", "resources"); 41 | 42 | Observable data = CreateObservable.listFolderViaUsing(path, "*") 43 | .flatMap(file -> { 44 | if (!Files.isDirectory(file)) { 45 | return CreateObservable.fromViaUsing(file).subscribeOn(Schedulers.io()); 46 | } 47 | 48 | return Observable.empty(); 49 | }); 50 | 51 | Helpers.subscribePrint( 52 | data.sample(Observable.interval( 53 | 100L, TimeUnit.MILLISECONDS).take(10) 54 | .concatWith(Observable.interval( 55 | 200L, TimeUnit.MILLISECONDS))) 56 | .doOnCompleted(() -> latch.countDown()), 57 | "sample(Observable)"); 58 | 59 | Helpers.subscribePrint( 60 | data.throttleLast(100L, TimeUnit.MILLISECONDS) 61 | .doOnCompleted(() -> latch.countDown()), 62 | "throttleLast(long, TimeUnit)"); 63 | Observable sampler = Observable.create(subscriber -> { 64 | subscriber.onNext(0); 65 | 66 | try { 67 | Thread.sleep(100L); 68 | 69 | subscriber.onNext(10); 70 | 71 | Thread.sleep(200L); 72 | 73 | subscriber.onNext(200); 74 | 75 | Thread.sleep(150L); 76 | subscriber.onCompleted(); 77 | } catch (Exception e) { 78 | subscriber.onError(e); 79 | } 80 | }).repeat().subscribeOn(Schedulers.computation()); 81 | 82 | 83 | Helpers.subscribePrint( 84 | data.sample(sampler).debounce(150L, TimeUnit.MILLISECONDS) 85 | .doOnCompleted(() -> latch.countDown()), 86 | "sample(Observable).debounce(long, TimeUnit)"); 87 | 88 | 89 | Helpers.subscribePrint( 90 | data.buffer(2, 1500) 91 | .doOnCompleted(() -> latch.countDown()), 92 | "buffer(int, int)"); 93 | 94 | 95 | Helpers.subscribePrint( 96 | data.window(3L, 200L, TimeUnit.MILLISECONDS).flatMap(o -> o) 97 | .doOnCompleted(() -> latch.countDown()), 98 | "window(long, long, TimeUnit)"); 99 | 100 | 101 | Helpers.subscribePrint( 102 | data.onBackpressureBuffer(10000) 103 | .doOnCompleted(() -> latch.countDown()), 104 | "onBackpressureBuffer(int)"); 105 | 106 | Helpers.subscribePrint( 107 | data.onBackpressureDrop() 108 | .doOnCompleted(() -> latch.countDown()), 109 | "onBackpressureDrop"); 110 | 111 | try { 112 | latch.await(15L, TimeUnit.SECONDS); 113 | } catch (InterruptedException e) { 114 | } 115 | } 116 | 117 | public static void main(String[] args) { 118 | new BackpressureExamples().run(); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter06/IntervalAndSchedulers.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter06; 2 | 3 | import static com.packtpub.reactive.common.Helpers.debug; 4 | 5 | import java.util.concurrent.CountDownLatch; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import rx.Observable; 9 | import rx.Scheduler; 10 | import rx.schedulers.Schedulers; 11 | 12 | import com.packtpub.reactive.common.Program; 13 | 14 | /** 15 | * More information of {@link Observable#interval} and its default {@link Scheduler}. 16 | * 17 | * @author meddle 18 | */ 19 | public class IntervalAndSchedulers implements Program { 20 | 21 | @Override 22 | public String name() { 23 | return "Observable.interval and Schedulers"; 24 | } 25 | 26 | @Override 27 | public int chapter() { 28 | return 6; 29 | } 30 | 31 | @Override 32 | public void run() { 33 | CountDownLatch latch = new CountDownLatch(1); 34 | 35 | Observable.range(5, 5).doOnEach(debug("Test")).subscribe(); 36 | 37 | Observable 38 | .interval(500L, TimeUnit.MILLISECONDS) 39 | .take(5) 40 | .doOnEach(debug("Default interval")) 41 | .doOnCompleted(() -> latch.countDown()) 42 | .subscribe(); 43 | 44 | try { 45 | latch.await(); 46 | } catch (InterruptedException e) {} 47 | 48 | Observable 49 | .interval(500L, TimeUnit.MILLISECONDS, Schedulers.immediate()) 50 | .take(5) 51 | .doOnEach(debug("Imediate interval")) 52 | .subscribe(); 53 | } 54 | 55 | public static void main(String[] args) { 56 | new IntervalAndSchedulers().run(); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter06/ParallelRequestsExample.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter06; 2 | 3 | import java.io.IOException; 4 | import java.util.Map; 5 | import java.util.concurrent.CountDownLatch; 6 | 7 | import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; 8 | import org.apache.http.impl.nio.client.HttpAsyncClients; 9 | 10 | import rx.Observable; 11 | import rx.schedulers.Schedulers; 12 | 13 | import com.packtpub.reactive.common.CreateObservable; 14 | import com.packtpub.reactive.common.Program; 15 | 16 | 17 | /** 18 | * Demonstrates parallelism by executing a number of requests in parallel. 19 | * 20 | * @author meddle 21 | */ 22 | public class ParallelRequestsExample implements Program { 23 | 24 | @Override 25 | public String name() { 26 | return "Demonstraton of parallelism"; 27 | } 28 | 29 | @Override 30 | public int chapter() { 31 | return 6; 32 | } 33 | 34 | @SuppressWarnings("rawtypes") 35 | @Override 36 | public void run() { 37 | CloseableHttpAsyncClient client = HttpAsyncClients.createDefault(); 38 | CountDownLatch latch = new CountDownLatch(1); 39 | 40 | try { 41 | client.start(); 42 | 43 | Observable response = CreateObservable.requestJson(client, "https://api.github.com/users/meddle0x53/followers"); 44 | 45 | 46 | response 47 | .map(followerJson -> followerJson.get("url")) 48 | .cast(String.class) 49 | .flatMap(profileUrl -> CreateObservable 50 | .requestJson(client, profileUrl) 51 | .subscribeOn(Schedulers.io()) 52 | .filter(res -> res.containsKey("followers")) 53 | .map(json -> json.get("login") + " : " + json.get("followers")) 54 | ) 55 | .doOnNext(follower -> System.out.println(follower)) 56 | .count() 57 | .doOnCompleted(() -> latch.countDown()) 58 | .subscribe(sum -> System.out.println("meddle0x53 : " + sum)); 59 | 60 | try { 61 | latch.await(); 62 | } catch (InterruptedException e) {} 63 | 64 | } finally { 65 | try { 66 | client.close(); 67 | } catch (IOException e) {} 68 | } 69 | } 70 | 71 | public static void main(String[] args) { 72 | new ParallelRequestsExample().run(); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter06/SchedulersTypes.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter06; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Random; 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | import rx.Scheduler; 9 | import rx.Scheduler.Worker; 10 | import rx.functions.Action0; 11 | import rx.schedulers.Schedulers; 12 | 13 | import com.packtpub.reactive.common.Program; 14 | 15 | /** 16 | * A collection of examples of using the different {@link Scheduler}s. 17 | * 18 | * @author meddle 19 | */ 20 | public class SchedulersTypes implements Program { 21 | 22 | 23 | 24 | @Override 25 | public String name() { 26 | return "Demonstration of the different Schedulers types"; 27 | } 28 | 29 | @Override 30 | public int chapter() { 31 | return 6; 32 | } 33 | 34 | 35 | public void schedule(Scheduler scheduler, int numberOfSubTasks, boolean onTheSameWorker) { 36 | List list = new ArrayList<>(0); 37 | AtomicInteger current = new AtomicInteger(0); 38 | 39 | Random random = new Random(); 40 | Worker worker = scheduler.createWorker(); 41 | 42 | Action0 addWork = () -> { 43 | 44 | synchronized (list) { 45 | System.out.println(" Add : " + Thread.currentThread().getName() + " " + current.get()); 46 | list.add(random.nextInt(current.get())); 47 | System.out.println(" End add : " + Thread.currentThread().getName() + " " + current.get()); 48 | } 49 | 50 | 51 | }; 52 | 53 | Action0 removeWork = () -> { 54 | 55 | synchronized (list) { 56 | if (!list.isEmpty()) { 57 | System.out.println(" Remove : " + Thread.currentThread().getName()); 58 | list.remove(0); 59 | System.out.println(" End remove : " + Thread.currentThread().getName()); 60 | 61 | } 62 | } 63 | 64 | }; 65 | 66 | 67 | Action0 work = () -> { 68 | System.out.println(Thread.currentThread().getName()); 69 | 70 | for (int i = 1; i <= numberOfSubTasks; i++) { 71 | current.set(i); 72 | 73 | System.out.println("Begin add!"); 74 | if (onTheSameWorker) { 75 | worker.schedule(addWork); 76 | } else { 77 | scheduler.createWorker().schedule(addWork); 78 | } 79 | System.out.println("End add!"); 80 | } 81 | 82 | while (!list.isEmpty()) { 83 | System.out.println("Begin remove!"); 84 | 85 | if (onTheSameWorker) { 86 | worker.schedule(removeWork); 87 | } else { 88 | scheduler.createWorker().schedule(removeWork); 89 | } 90 | 91 | System.out.println("End remove!"); 92 | } 93 | }; 94 | 95 | worker.schedule(work); 96 | } 97 | 98 | @Override 99 | public void run() { 100 | 101 | System.out.println("Immediate"); 102 | schedule(Schedulers.immediate(), 2, true); 103 | System.out.println("Spawn!"); 104 | schedule(Schedulers.immediate(), 2, false); 105 | try { Thread.sleep(1000L); } catch (InterruptedException e) {} 106 | 107 | System.out.println("------"); 108 | 109 | System.out.println("Trampoline"); 110 | schedule(Schedulers.trampoline(), 2, true); 111 | System.out.println("Spawn!"); 112 | schedule(Schedulers.trampoline(), 2, false); 113 | try { Thread.sleep(1000L); } catch (InterruptedException e) {} 114 | 115 | System.out.println("------"); 116 | 117 | System.out.println("New thread"); 118 | schedule(Schedulers.newThread(), 2, true); 119 | try { Thread.sleep(500L); } catch (InterruptedException e) {} 120 | 121 | System.out.println("------"); 122 | 123 | System.out.println("Spawn!"); 124 | schedule(Schedulers.newThread(), 2, false); 125 | try { Thread.sleep(500L); } catch (InterruptedException e) {} 126 | 127 | System.out.println("------"); 128 | 129 | System.out.println("Computation thread"); 130 | schedule(Schedulers.computation(), 5, true); 131 | try { Thread.sleep(500L); } catch (InterruptedException e) {} 132 | 133 | System.out.println("------"); 134 | 135 | System.out.println("Spawn!"); 136 | schedule(Schedulers.computation(), 5, false); 137 | try { Thread.sleep(500L); } catch (InterruptedException e) {} 138 | 139 | System.out.println("------"); 140 | 141 | System.out.println("IO thread"); 142 | schedule(Schedulers.io(), 2, true); 143 | try { Thread.sleep(500L); } catch (InterruptedException e) {} 144 | 145 | System.out.println("------"); 146 | 147 | System.out.println("Spawn!"); 148 | schedule(Schedulers.io(), 2, false); 149 | try { Thread.sleep(500L); } catch (InterruptedException e) {} 150 | 151 | 152 | } 153 | 154 | public static void main(String[] args) { 155 | new SchedulersTypes().run(); 156 | } 157 | 158 | } 159 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter06/SubscribeOnAndObserveOn.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter06; 2 | 3 | import static com.packtpub.reactive.common.Helpers.debug; 4 | 5 | import java.util.concurrent.CountDownLatch; 6 | 7 | import rx.Observable; 8 | import rx.schedulers.Schedulers; 9 | 10 | import com.packtpub.reactive.common.Program; 11 | 12 | /** 13 | * Demonstrates using subscribeOn and observeOn with {@link Schedulers} and {@link Observable}s. 14 | * 15 | * @author meddle 16 | */ 17 | public class SubscribeOnAndObserveOn implements Program { 18 | 19 | @Override 20 | public String name() { 21 | return "A few examples of observeOn and subscribeOn"; 22 | } 23 | 24 | @Override 25 | public int chapter() { 26 | return 6; 27 | } 28 | 29 | @Override 30 | public void run() { 31 | CountDownLatch latch = new CountDownLatch(1); 32 | 33 | Observable range = Observable 34 | .range(20, 5) 35 | .flatMap(n -> Observable 36 | .range(n, 3) 37 | .subscribeOn(Schedulers.computation()) 38 | .doOnEach(debug("Source")) 39 | ); 40 | 41 | 42 | Observable chars = range 43 | .observeOn(Schedulers.newThread()) 44 | .map(n -> n + 48) 45 | .doOnEach(debug("+48 ", " ")) 46 | .observeOn(Schedulers.computation()) 47 | .map(n -> Character.toChars(n)) 48 | .map(c -> c[0]) 49 | .doOnEach(debug("Chars ", " ")) 50 | .finallyDo(() -> latch.countDown()); 51 | 52 | chars.subscribe(); 53 | 54 | System.out.println("Hey!"); 55 | 56 | try { 57 | latch.await(); 58 | } catch (InterruptedException e) {} 59 | } 60 | 61 | public static void main(String[] args) { 62 | new SubscribeOnAndObserveOn().run(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter07/BlockingObservablesAndOperators.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter07; 2 | 3 | import java.io.StringReader; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import rx.Observable; 9 | import rx.observables.BlockingObservable; 10 | 11 | import com.packtpub.reactive.common.CreateObservable; 12 | import com.packtpub.reactive.common.Program; 13 | 14 | /** 15 | * Examples of using {@link BlockingObservable} and their operators - 16 | * {@link BlockingObservable#forEach}, {@link BlockingObservable#first}, {@link BlockingObservable#next}, 17 | * {@link BlockingObservable#last} and {@link BlockingObservable#single}. 18 | * Includes examples of {@link Observable#count} and {@link Observable#toList} combined with the {@link Observable#toBlocking}. 19 | * 20 | * @author meddle 21 | */ 22 | public class BlockingObservablesAndOperators implements Program { 23 | 24 | @Override 25 | public String name() { 26 | return "A demonstration of using Blocking Observables"; 27 | } 28 | 29 | @Override 30 | public int chapter() { 31 | return 7; 32 | } 33 | 34 | @Override 35 | public void run() { 36 | 37 | 38 | Observable 39 | .interval(100L, TimeUnit.MILLISECONDS) 40 | .take(5) 41 | .toBlocking() 42 | .forEach(System.out::println); 43 | System.out.println("END"); 44 | 45 | Integer first = Observable.range(3, 13).toBlocking().first(); 46 | System.out.println(first); 47 | Integer last = Observable.range(3, 13).toBlocking().last(); 48 | System.out.println(last); 49 | 50 | Iterable next = Observable 51 | .interval(100L, TimeUnit.MILLISECONDS) 52 | .toBlocking() 53 | .next(); 54 | Iterator iterator = next.iterator(); 55 | System.out.println(iterator.next()); 56 | System.out.println(iterator.next()); 57 | System.out.println(iterator.next()); 58 | 59 | Iterable latest = Observable 60 | .interval(1000L, TimeUnit.MILLISECONDS) 61 | .toBlocking() 62 | .latest(); 63 | iterator = latest.iterator(); 64 | System.out.println(iterator.next()); 65 | 66 | try { 67 | Thread.sleep(5500L); 68 | } catch (InterruptedException e) {} 69 | System.out.println(iterator.next()); 70 | System.out.println(iterator.next()); 71 | 72 | 73 | List single = Observable 74 | .range(5, 15) 75 | .toList() 76 | .toBlocking().single(); 77 | System.out.println(single); 78 | 79 | Observable.range(10, 100).count().subscribe(System.out::println); 80 | 81 | 82 | StringReader reader = new StringReader("One\nTwo\nThree"); 83 | Observable observable = CreateObservable.from(reader); 84 | 85 | System.out.println(observable.count().toBlocking().first()); 86 | System.out.println(observable.toList().toBlocking().first()); 87 | } 88 | 89 | public static void main(String[] args) { 90 | new BlockingObservablesAndOperators().run(); 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter08/Compose.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter08; 2 | 3 | import java.nio.file.Path; 4 | import java.nio.file.Paths; 5 | 6 | import rx.Observable; 7 | import rx.Observable.Transformer; 8 | 9 | import com.packtpub.reactive.chapter08.Lift.Indexed; 10 | import com.packtpub.reactive.common.CreateObservable; 11 | import com.packtpub.reactive.common.Helpers; 12 | import com.packtpub.reactive.common.Program; 13 | 14 | /** 15 | * Example of implementing a {@link Transformer} and passing it to {@link Observable#compose}. 16 | * 17 | * @author meddle 18 | */ 19 | public class Compose implements Program { 20 | 21 | public static class OddFilter implements Transformer { 22 | 23 | @Override 24 | public Observable call(Observable observable) { 25 | return observable 26 | .lift(new Indexed(1L)) 27 | .filter(pair -> pair.getLeft() % 2 == 1) 28 | .map(pair -> pair.getRight()); 29 | } 30 | 31 | } 32 | 33 | @Override 34 | public String name() { 35 | return "Demonstration of the Observable.compose operator"; 36 | } 37 | 38 | @Override 39 | public int chapter() { 40 | return 8; 41 | } 42 | 43 | @Override 44 | public void run() { 45 | Path path = Paths.get("src", "main", "resources", "letters.txt"); 46 | Observable indexedStrings = CreateObservable 47 | .fromViaUsing(path).compose(new OddFilter()); 48 | 49 | Helpers.subscribePrint(indexedStrings, "Indexed strings"); 50 | } 51 | 52 | public static void main(String[] args) { 53 | new Compose().run(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter08/Lift.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter08; 2 | 3 | import java.nio.file.Path; 4 | import java.nio.file.Paths; 5 | 6 | import rx.Observable; 7 | import rx.Observable.Operator; 8 | import rx.Subscriber; 9 | 10 | import com.packtpub.reactive.common.CreateObservable; 11 | import com.packtpub.reactive.common.Helpers; 12 | import com.packtpub.reactive.common.Program; 13 | 14 | /** 15 | * Demonstrates implementing values with indices using lift and the custom operator {@link Indexed}. 16 | * 17 | * @author meddle 18 | */ 19 | public class Lift implements Program { 20 | 21 | public static class Pair { 22 | final L left; 23 | final R right; 24 | 25 | public Pair(L left, R right) { 26 | this.left = left; 27 | this.right = right; 28 | } 29 | 30 | public L getLeft() { 31 | return left; 32 | } 33 | 34 | public R getRight() { 35 | return right; 36 | } 37 | 38 | public Pair setLeft(L newLeft) { 39 | return new Pair(newLeft, this.right); 40 | } 41 | 42 | public Pair setRight(R newRight) { 43 | return new Pair(this.left, newRight); 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return String.format("%s : %s", this.left, this.right); 49 | } 50 | 51 | @Override 52 | public int hashCode() { 53 | final int prime = 31; 54 | int result = 1; 55 | result = prime * result + ((left == null) ? 0 : left.hashCode()); 56 | result = prime * result + ((right == null) ? 0 : right.hashCode()); 57 | return result; 58 | } 59 | 60 | @SuppressWarnings("rawtypes") 61 | @Override 62 | public boolean equals(Object obj) { 63 | if (this == obj) { 64 | return true; 65 | } 66 | if (obj == null) { 67 | return false; 68 | } 69 | if (!(obj instanceof Pair)) { 70 | return false; 71 | } 72 | Pair other = (Pair) obj; 73 | if (left == null) { 74 | if (other.left != null) { 75 | return false; 76 | } 77 | } else if (!left.equals(other.left)) { 78 | return false; 79 | } 80 | if (right == null) { 81 | if (other.right != null) { 82 | return false; 83 | } 84 | } else if (!right.equals(other.right)) { 85 | return false; 86 | } 87 | return true; 88 | } 89 | 90 | 91 | } 92 | 93 | public static class Indexed implements Operator, T> { 94 | final private long initialIndex; 95 | 96 | public Indexed() { 97 | this(0L); 98 | } 99 | 100 | public Indexed(long initial) { 101 | this.initialIndex = initial; 102 | } 103 | 104 | @Override 105 | public Subscriber call(Subscriber> s) { 106 | return new Subscriber(s) { 107 | private long index = initialIndex; 108 | 109 | @Override 110 | public void onCompleted() { 111 | s.onCompleted(); 112 | } 113 | 114 | @Override 115 | public void onError(Throwable e) { 116 | s.onError(e); 117 | } 118 | 119 | @Override 120 | public void onNext(T t) { 121 | s.onNext(new Pair(index++, t)); 122 | } 123 | }; 124 | } 125 | } 126 | 127 | @Override 128 | public String name() { 129 | return "Example of using Observable#lift for executing custom operators"; 130 | } 131 | 132 | @Override 133 | public int chapter() { 134 | return 8; 135 | } 136 | 137 | @Override 138 | public void run() { 139 | Path path = Paths.get("src", "main", "resources", "letters.txt"); 140 | Observable indexedStrings = CreateObservable 141 | .fromViaUsing(path) 142 | .lift(new Indexed(1L)); 143 | 144 | Helpers.subscribePrint(indexedStrings, "Indexed strings"); 145 | 146 | Observable> indexed = 147 | Observable.zip( 148 | Observable.just("a", "b", "c", "d", "e"), 149 | Observable.range(0, 100), 150 | (s, i) -> new Pair((long) i, s)); 151 | 152 | Helpers.subscribePrint(indexed, "Indexed, no lift"); 153 | } 154 | 155 | public static void main(String[] args) { 156 | new Lift().run(); 157 | } 158 | 159 | } 160 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/chapter08/ResourceManagement.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter08; 2 | 3 | import java.io.IOException; 4 | 5 | import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; 6 | import org.apache.http.impl.nio.client.HttpAsyncClients; 7 | import org.apache.http.nio.client.HttpAsyncClient; 8 | 9 | import rx.Observable; 10 | import rx.apache.http.ObservableHttp; 11 | import rx.apache.http.ObservableHttpResponse; 12 | import rx.functions.Action1; 13 | import rx.functions.Func0; 14 | import rx.functions.Func1; 15 | 16 | import com.packtpub.reactive.common.Program; 17 | 18 | /** 19 | * Demonstration of custom resource management with {@link Observable#using}. 20 | * 21 | * @author meddle 22 | */ 23 | public class ResourceManagement implements Program { 24 | 25 | @Override 26 | public String name() { 27 | return "Resource management demonstration"; 28 | } 29 | 30 | @Override 31 | public int chapter() { 32 | return 8; 33 | } 34 | 35 | public Observable request(String url) { 36 | Func0 resourceFactory = () -> { 37 | CloseableHttpAsyncClient client = HttpAsyncClients.createDefault(); 38 | client.start(); 39 | 40 | System.out.println(Thread.currentThread().getName() + " : Created and started the client."); 41 | return client; 42 | }; 43 | 44 | Func1> observableFactory = (client) -> { 45 | System.out.println(Thread.currentThread().getName() + " : About to create Observable."); 46 | return ObservableHttp.createGet(url, client).toObservable(); 47 | }; 48 | 49 | Action1 disposeAction = (client) -> { 50 | try { 51 | System.out.println(Thread.currentThread().getName() + " : Closing the client."); 52 | client.close(); 53 | } catch (IOException e) { 54 | } 55 | }; 56 | 57 | return Observable.using( 58 | resourceFactory, 59 | observableFactory, 60 | disposeAction); 61 | } 62 | 63 | @Override 64 | public void run() { 65 | 66 | String url = "https://api.github.com/orgs/ReactiveX/repos"; 67 | Observable response = request(url); 68 | 69 | System.out.println("Not yet subscribed."); 70 | Observable stringResponse = response 71 | .flatMap(resp -> resp.getContent() 72 | .map(bytes -> new String(bytes, java.nio.charset.StandardCharsets.UTF_8))) 73 | .retry(5) 74 | .map(String::trim) 75 | .cache(); 76 | 77 | System.out.println("Subscribe 1:"); 78 | System.out.println(stringResponse.toBlocking().first()); 79 | 80 | System.out.println("Subscribe 2:"); 81 | System.out.println(stringResponse.toBlocking().first()); 82 | 83 | } 84 | 85 | public static void main(String[] args) { 86 | new ResourceManagement().run(); 87 | } 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/common/CreateObservable.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.common; 2 | 3 | import static com.packtpub.reactive.common.checked.Uncheck.unchecked; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.InputStreamReader; 9 | import java.io.Reader; 10 | import java.nio.file.DirectoryIteratorException; 11 | import java.nio.file.DirectoryStream; 12 | import java.nio.file.Files; 13 | import java.nio.file.Path; 14 | import java.nio.file.Paths; 15 | import java.nio.file.StandardOpenOption; 16 | import java.nio.file.attribute.BasicFileAttributes; 17 | import java.nio.file.attribute.FileTime; 18 | import java.util.Arrays; 19 | import java.util.Comparator; 20 | import java.util.HashMap; 21 | import java.util.List; 22 | import java.util.Map; 23 | import java.util.concurrent.TimeUnit; 24 | 25 | import org.apache.commons.codec.binary.Base64; 26 | import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; 27 | import org.apache.http.impl.nio.client.HttpAsyncClients; 28 | import org.apache.http.nio.client.HttpAsyncClient; 29 | 30 | import rx.Observable; 31 | import rx.Scheduler; 32 | import rx.Scheduler.Worker; 33 | import rx.Subscriber; 34 | import rx.apache.http.ObservableHttp; 35 | import rx.apache.http.ObservableHttpResponse; 36 | import rx.functions.Action0; 37 | import rx.functions.Action1; 38 | import rx.functions.Func0; 39 | import rx.functions.Func1; 40 | import rx.observables.ConnectableObservable; 41 | import rx.schedulers.Schedulers; 42 | import rx.subscriptions.Subscriptions; 43 | 44 | import com.google.gson.Gson; 45 | import com.google.gson.GsonBuilder; 46 | 47 | /** 48 | * Contains a set of methods for creating custom {@link Observable}s. 49 | * 50 | * @author meddle 51 | */ 52 | public class CreateObservable { 53 | 54 | public static Observable fromViaUsing(final Path path) { 55 | return Observable. using( 56 | unchecked(() -> Files.newBufferedReader(path)), 57 | reader -> from(reader).refCount(), 58 | unchecked(reader -> reader.close())); 59 | } 60 | 61 | public static Observable from(final Path path) { 62 | return Observable.create(subscriber -> { 63 | try { 64 | BufferedReader reader = Files.newBufferedReader(path); 65 | subscriber.add(Subscriptions.create(() -> { 66 | try { 67 | reader.close(); 68 | } catch (IOException e) { 69 | e.printStackTrace(); 70 | } 71 | })); 72 | 73 | String line = null; 74 | while ((line = reader.readLine()) != null && !subscriber.isUnsubscribed()) { 75 | subscriber.onNext(line); 76 | } 77 | if (!subscriber.isUnsubscribed()) { 78 | subscriber.onCompleted(); 79 | } 80 | } catch (IOException ioe) { 81 | if (!subscriber.isUnsubscribed()) { 82 | subscriber.onError(ioe); 83 | } 84 | } 85 | }); 86 | } 87 | 88 | public static Observable from(final Path path, Scheduler scheduler) { 89 | return fromViaUsing(path).subscribeOn(scheduler); 90 | } 91 | 92 | public static ConnectableObservable from(final InputStream stream) { 93 | return from(new BufferedReader(new InputStreamReader(stream))); 94 | } 95 | 96 | public static Observable from(final Reader reader) { 97 | return Observable.defer(() -> { 98 | return from(new BufferedReader(reader)).refCount(); 99 | }).cache(); 100 | } 101 | 102 | public static ConnectableObservable from(final BufferedReader reader) { 103 | return Observable.create((Subscriber subscriber) -> { 104 | try { 105 | String line; 106 | 107 | if (subscriber.isUnsubscribed()) { 108 | return; 109 | } 110 | 111 | while (!subscriber.isUnsubscribed() && (line = reader.readLine()) != null) { 112 | if (line.equals("exit")) { 113 | break; 114 | } 115 | 116 | subscriber.onNext(line); 117 | } 118 | } catch (IOException e) { 119 | subscriber.onError(e); 120 | } 121 | 122 | if (!subscriber.isUnsubscribed()) { 123 | subscriber.onCompleted(); 124 | } 125 | }).publish(); 126 | } 127 | 128 | public static Observable listFolder(Path dir, String glob) { 129 | return Observable.create(subscriber -> { 130 | try { 131 | DirectoryStream stream = 132 | Files.newDirectoryStream(dir, glob); 133 | 134 | subscriber.add(Subscriptions.create(() -> { 135 | try { 136 | stream.close(); 137 | } catch (IOException e) { 138 | e.printStackTrace(); 139 | } 140 | })); 141 | Observable.from(stream).subscribe(subscriber); 142 | } catch (DirectoryIteratorException ex) { 143 | subscriber.onError(ex); 144 | } catch (IOException ioe) { 145 | subscriber.onError(ioe); 146 | } 147 | }); 148 | } 149 | 150 | public static Observable listFolderViaUsing(Path dir, String glob) { 151 | return Observable.> using( 152 | unchecked(() -> Files.newDirectoryStream(dir, glob)), 153 | dirStream -> Observable.from(dirStream), 154 | unchecked(dirStream -> dirStream.close())); 155 | } 156 | 157 | public static final Path CACHE_DIR = Paths.get("src", "main", "resources", "cache"); 158 | 159 | private static Map cache = new HashMap<>(); 160 | 161 | @SuppressWarnings("rawtypes") 162 | public static Observable fromCache(String url) { 163 | return getCache(url).get(); 164 | } 165 | 166 | public static Cache getCache(String url) { 167 | if (!cache.containsKey(url)) { 168 | cache.put(url, new Cache(url)); 169 | } 170 | 171 | return cache.get(url); 172 | } 173 | 174 | @SuppressWarnings("rawtypes") 175 | public static class Cache { 176 | private final Path filePath; 177 | 178 | public Cache(String url) { 179 | byte[] urlBytes = Base64.encodeBase64(url.getBytes()); 180 | Path file = Paths.get(new String(urlBytes)); 181 | this.filePath = CACHE_DIR.resolve(file); 182 | } 183 | 184 | public Observable get() { 185 | return read() 186 | .filter(line -> !line.equals("<><><><><>")) 187 | .map(line -> new Gson().fromJson(line, Map.class)) 188 | .cast(Map.class); 189 | } 190 | 191 | public Observable read() { 192 | return fromViaUsing(this.filePath) 193 | .onErrorResumeNext(Helpers::createFileOnNotFound); 194 | } 195 | 196 | public void clear() { 197 | try { 198 | BasicFileAttributes targetAttrs = Files.readAttributes(this.filePath, BasicFileAttributes.class); 199 | FileTime targetTime = targetAttrs.lastModifiedTime(); 200 | FileTime hour = FileTime.fromMillis(System.currentTimeMillis() - (60L * 60L * 1000L)); 201 | 202 | if (targetTime.compareTo(hour) < 0) { 203 | synchronized (this.filePath) { 204 | Files.delete(this.filePath); 205 | } 206 | } 207 | } catch (IOException e) { 208 | } 209 | } 210 | 211 | public Observable add(Map json) { 212 | return Observable.just(json) 213 | .map(jsonMap -> new GsonBuilder().create().toJson(jsonMap)) 214 | .map(jsonString -> ("<><><><><>\n" + jsonString + "\n")) 215 | .flatMap(jsonString -> { 216 | try { 217 | synchronized (this.filePath) { 218 | Files.write( 219 | this.filePath, 220 | jsonString.getBytes(), 221 | StandardOpenOption.APPEND, 222 | StandardOpenOption.CREATE); 223 | } 224 | return Observable.just(jsonString); 225 | } catch (Exception e) { 226 | return Observable.error(e); 227 | } 228 | }); 229 | } 230 | } 231 | 232 | @SuppressWarnings({ "rawtypes", "unchecked" }) 233 | public static Observable requestJson(HttpAsyncClient client, 234 | String url) { 235 | Observable rawResponse = ObservableHttp 236 | .createGet(url, client) 237 | .toObservable() 238 | .flatMap(resp -> resp.getContent() 239 | .map(bytes -> new String(bytes))) 240 | .retry(5) 241 | .cast(String.class) 242 | .map(String::trim) 243 | .doOnNext(resp -> getCache(url).clear()); 244 | 245 | Observable objects = rawResponse 246 | .filter(data -> data.startsWith("{")) 247 | .map(data -> "[" + data + "]"); 248 | 249 | Observable arrays = rawResponse 250 | .filter(data -> data.startsWith("[")); 251 | 252 | Observable response = arrays.concatWith(objects) 253 | .map(data -> { 254 | return new Gson().fromJson(data, List.class); 255 | }).flatMapIterable(list -> list) 256 | .cast(Map.class) 257 | .doOnNext(json -> getCache(url).add((Map) json).subscribe()); 258 | 259 | return Observable.amb(fromCache(url), response); 260 | } 261 | 262 | @SafeVarargs 263 | public static Observable sorted(Comparator comparator, T... data) { 264 | List listData = Arrays.asList(data); 265 | listData.sort(comparator); 266 | 267 | return Observable.from(listData); 268 | } 269 | 270 | public static Observable interval(Long... gaps) { 271 | return interval(Arrays.asList(gaps)); 272 | } 273 | 274 | public static Observable interval(List gaps) { 275 | return interval(gaps, TimeUnit.MILLISECONDS); 276 | } 277 | 278 | public static Observable interval(List gaps, TimeUnit unit) { 279 | return interval(gaps, unit, Schedulers.computation()); 280 | } 281 | 282 | public static Observable interval(List gaps, TimeUnit unit, Scheduler scheduler) { 283 | if (gaps == null || gaps.isEmpty()) { 284 | throw new IllegalArgumentException("Provide one or more interval gaps!"); 285 | } 286 | 287 | return Observable.create(subscriber -> { 288 | int size = gaps.size(); 289 | 290 | Worker worker = scheduler.createWorker(); 291 | subscriber.add(worker); 292 | 293 | final Action0 action = new Action0() { 294 | 295 | long current = 0; 296 | @Override 297 | public void call() { 298 | subscriber.onNext(current++); 299 | 300 | long currentGap = gaps.get((int) current % size); 301 | worker.schedule(this, currentGap, unit); 302 | } 303 | }; 304 | 305 | worker.schedule(action, gaps.get(0), unit); 306 | }); 307 | } 308 | 309 | public static Observable request(String url) { 310 | Func0 resourceFactory = () -> { 311 | CloseableHttpAsyncClient client = HttpAsyncClients.createDefault(); 312 | client.start(); 313 | 314 | System.out.println(Thread.currentThread().getName() + " : Created and started the client."); 315 | return client; 316 | }; 317 | 318 | Func1> observableFactory = (client) -> { 319 | System.out.println(Thread.currentThread().getName() + " : About to create Observable."); 320 | return ObservableHttp.createGet(url, client).toObservable(); 321 | }; 322 | 323 | Action1 disposeAction = (client) -> { 324 | try { 325 | System.out.println(Thread.currentThread().getName() + " : Closing the client."); 326 | client.close(); 327 | } catch (IOException e) { 328 | } 329 | }; 330 | 331 | return Observable.using( 332 | resourceFactory, 333 | observableFactory, 334 | disposeAction); 335 | } 336 | 337 | @SuppressWarnings({ "rawtypes", "unchecked" }) 338 | public static Observable requestJson(String url) { 339 | Observable rawResponse = request(url) 340 | .flatMap(resp -> resp.getContent() 341 | .map(bytes -> new String(bytes))) 342 | .retry(5) 343 | .cast(String.class) 344 | .map(String::trim) 345 | .doOnNext(resp -> getCache(url).clear()); 346 | 347 | Observable objects = rawResponse 348 | .filter(data -> data.startsWith("{")) 349 | .map(data -> "[" + data + "]"); 350 | 351 | Observable arrays = rawResponse 352 | .filter(data -> data.startsWith("[")); 353 | 354 | Observable response = arrays.concatWith(objects) 355 | .map(data -> { 356 | return new Gson().fromJson(data, List.class); 357 | }).flatMapIterable(list -> list) 358 | .cast(Map.class) 359 | .doOnNext(json -> getCache(url).add((Map) json).subscribe()); 360 | 361 | return Observable.amb(fromCache(url), response); 362 | } 363 | } 364 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/common/Helpers.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.common; 2 | 3 | import java.nio.file.Files; 4 | import java.nio.file.NoSuchFileException; 5 | import java.nio.file.Path; 6 | import java.nio.file.Paths; 7 | import java.util.Arrays; 8 | import java.util.concurrent.CountDownLatch; 9 | import java.util.concurrent.atomic.AtomicReference; 10 | import java.util.stream.Collectors; 11 | 12 | import rx.Notification; 13 | import rx.Observable; 14 | import rx.Subscription; 15 | import rx.exceptions.Exceptions; 16 | import rx.functions.Action1; 17 | 18 | /** 19 | * Contains a set of helper methods, used in the examples. 20 | * 21 | * @author meddle 22 | */ 23 | public final class Helpers { 24 | 25 | public static Subscription subscribePrint(Observable observable, 26 | String name) { 27 | return observable.subscribe( 28 | (v) -> System.out.println(Thread.currentThread().getName() 29 | + "|" + name + " : " + v), (e) -> { 30 | System.err.println("Error from " + name + ":"); 31 | System.err.println(e); 32 | System.err.println(Arrays 33 | .stream(e.getStackTrace()) 34 | .limit(5L) 35 | .map(stackEl -> " " + stackEl) 36 | .collect(Collectors.joining("\n")) 37 | ); 38 | }, () -> System.out.println(name + " ended!")); 39 | } 40 | 41 | /** 42 | * Subscribes to an observable, printing all its emissions. 43 | * Blocks until the observable calls onCompleted or onError. 44 | */ 45 | public static void blockingSubscribePrint(Observable observable, String name) { 46 | CountDownLatch latch = new CountDownLatch(1); 47 | subscribePrint(observable.finallyDo(() -> latch.countDown()), name); 48 | try { latch.await(); } catch (InterruptedException e) {} 49 | } 50 | 51 | public static Action1> debug(String description) { 52 | return debug(description, ""); 53 | } 54 | 55 | public static Action1> debug(String description, String offset) { 56 | AtomicReference nextOffset = new AtomicReference(">"); 57 | 58 | return (Notification notification) -> { 59 | switch (notification.getKind()) { 60 | case OnNext: 61 | 62 | System.out.println( 63 | Thread.currentThread().getName() + 64 | "|" + description + ": " + offset + 65 | nextOffset.get() + 66 | notification.getValue() 67 | ); 68 | break; 69 | case OnError: 70 | System.err.println(Thread.currentThread().getName() + 71 | "|" + description + ": " + offset + 72 | nextOffset.get() + " X " + notification.getThrowable()); 73 | break; 74 | case OnCompleted: 75 | System.out.println(Thread.currentThread().getName() + 76 | "|" + description + ": " + offset + 77 | nextOffset.get() + "|" 78 | ); 79 | break; 80 | default: 81 | break; 82 | } 83 | nextOffset.getAndUpdate(p -> "-" + p); 84 | }; 85 | } 86 | 87 | public static Observable createFileOnNotFound(Throwable t) { 88 | Throwable error = Exceptions.getFinalCause(t); 89 | if (error instanceof NoSuchFileException) { 90 | Path path = Paths.get(((NoSuchFileException) error).getFile()); 91 | try { 92 | Files.createDirectories(path.getParent()); 93 | Files.createFile(path); 94 | 95 | return Observable.never(); 96 | } catch (Exception e) { 97 | return Observable.error(e); 98 | } 99 | } 100 | return Observable.error(error); 101 | } 102 | } -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/common/Program.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.common; 2 | 3 | /** 4 | * All the examples of the book implement this. 5 | * It introduces a name and cahpter number for the example. 6 | * 7 | * @author meddle 8 | */ 9 | public interface Program { 10 | 11 | String name(); 12 | 13 | int chapter(); 14 | 15 | void run(); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/common/checked/CheckedAction1.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.common.checked; 2 | 3 | public interface CheckedAction1 { 4 | void call(T arg) throws Exception; 5 | } -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/common/checked/CheckedFunc0.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.common.checked; 2 | 3 | public interface CheckedFunc0 { 4 | R call() throws Exception; 5 | } -------------------------------------------------------------------------------- /src/main/java/com/packtpub/reactive/common/checked/Uncheck.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.common.checked; 2 | 3 | import rx.functions.Action1; 4 | import rx.functions.Func0; 5 | 6 | public class Uncheck { 7 | 8 | public static Func0 unchecked(CheckedFunc0 f) { 9 | return () -> { 10 | try { 11 | return f.call(); 12 | } catch (Exception e) { 13 | throw new RuntimeException(e); 14 | } 15 | }; 16 | } 17 | 18 | public static Action1 unchecked(CheckedAction1 a) { 19 | return arg -> { 20 | try { 21 | a.call(arg); 22 | } catch (Exception e) { 23 | throw new RuntimeException(e); 24 | } 25 | }; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/resources/letters.txt: -------------------------------------------------------------------------------- 1 | a 2 | b 3 | c 4 | d 5 | e 6 | f 7 | g 8 | h 9 | i 10 | j 11 | k 12 | l 13 | m 14 | n 15 | o 16 | p 17 | q 18 | r 19 | s 20 | t 21 | u 22 | v 23 | w 24 | x 25 | y 26 | z 27 | -------------------------------------------------------------------------------- /src/main/resources/lorem.txt: -------------------------------------------------------------------------------- 1 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. 2 | Phasellus odio magna, pretium nec viverra eget, sagittis eget lorem. 3 | Duis et tristique elit, at faucibus lectus. 4 | Nunc commodo massa nisl, a suscipit turpis pharetra et. 5 | Duis vel commodo elit. Nunc vel convallis odio. 6 | Nulla eros dui, aliquam et odio a, efficitur suscipit elit. 7 | Sed gravida elit in libero suscipit, a consequat ex commodo. 8 | Aliquam ornare erat non justo consectetur lacinia. 9 | Etiam porta dui urna, nec ultrices risus tempus nec. 10 | Nam tristique aliquet aliquet. 11 | Proin bibendum sed leo id consequat. 12 | Proin pharetra a mi nec lobortis. 13 | 14 | Nam bibendum metus id blandit ullamcorper. Donec eu metus nec ante posuere varius a sed elit. Aliquam fermentum vehicula nibh vel pharetra. Vestibulum eu laoreet diam. Maecenas interdum ultrices euismod. Sed vulputate tellus risus, laoreet auctor purus iaculis sed. Donec congue, lorem sed ultrices mollis, augue nibh bibendum neque, eu finibus tortor augue at ligula. Morbi aliquam pretium pellentesque. Donec sed pellentesque lacus, eu tempor mi. Proin in scelerisque diam. Morbi vel ultricies tortor, ut mollis libero. 15 | 16 | Phasellus eget nibh nisi. Morbi rhoncus euismod tellus non suscipit. Aliquam viverra nec justo a suscipit. Phasellus placerat lectus ex, sit amet volutpat tortor iaculis vel. Nunc volutpat sollicitudin odio, a aliquam velit rhoncus vitae. Phasellus cursus cursus ligula nec sollicitudin. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus iaculis tempor commodo. Sed interdum dui fermentum eros pretium, sed viverra nulla pretium. Vivamus laoreet nisi ut neque auctor, ut sodales risus accumsan. Ut quis nunc id dui ultricies consectetur fermentum eget nunc. Vivamus laoreet lacus elementum, cursus sapien sed, convallis est. Aenean ante elit, gravida vulputate vestibulum eleifend, lobortis at libero. Fusce venenatis elit gravida nibh placerat ultricies. 17 | 18 | Curabitur eget nunc ligula. Praesent metus sapien, ultricies a lacus porttitor, pellentesque lobortis libero. Suspendisse pretium nec urna sit amet laoreet. Sed pharetra ut est a aliquet. Duis at ex venenatis, finibus nunc in, pharetra lectus. Fusce vulputate ut arcu sit amet porta. Fusce egestas lectus ac auctor rhoncus. Quisque efficitur condimentum magna a posuere. Pellentesque lacinia mattis nulla, eu tempus risus ullamcorper vitae. Morbi quis diam quam. Nam bibendum nunc libero, sit amet pharetra purus blandit mollis. Nunc iaculis pulvinar laoreet. Curabitur non malesuada ex. Mauris consequat ex id faucibus vestibulum. Nullam rutrum, felis nec blandit vestibulum, metus magna tincidunt magna, eu ultricies erat lacus a mi. 19 | 20 | Donec rhoncus lectus nec urna vehicula gravida. Sed finibus augue elit, ac fringilla tellus dapibus a. Sed rutrum dolor at aliquet condimentum. Suspendisse fermentum ex at sollicitudin elementum. Donec a tempor nulla, vitae maximus justo. Quisque faucibus, dui in faucibus auctor, ex arcu lacinia ligula, eu lacinia justo urna nec sem. Mauris dictum hendrerit purus id malesuada. 21 | -------------------------------------------------------------------------------- /src/main/resources/operators.txt: -------------------------------------------------------------------------------- 1 | I'm smellin' like the rose that somebody gave me on my birthday deathbed, 2 | I'm smellin' like the rose that somebody gave me 'cause I'm dead & bloated. 3 | The more you cry your ashes turn to mud! 4 | One of these days i'm going to cut you into little pieces! And I've got this friend, you see. Who makes me feel and. 5 | Will you come with me? 6 | Become your own fear... 7 | RX damn your righteous hand -------------------------------------------------------------------------------- /src/test/java/com/packtpub/reactive/chapter07/CreateObservableIntervalTest.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter07; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import java.util.Arrays; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import org.junit.Test; 9 | 10 | import rx.Observable; 11 | import rx.observers.TestSubscriber; 12 | import rx.schedulers.Schedulers; 13 | import rx.schedulers.TestScheduler; 14 | 15 | import com.packtpub.reactive.common.CreateObservable; 16 | 17 | /** 18 | * A unit test testing the custom {@link CreateObservable#interval} method. 19 | * 20 | * @author meddle 21 | */ 22 | public class CreateObservableIntervalTest { 23 | 24 | @Test(expected = IllegalArgumentException.class) 25 | public void testExceptionWithNoGaps() { 26 | CreateObservable.interval(); 27 | } 28 | 29 | @Test 30 | public void testBehavesAsNormalIntervalWithOneGap() throws Exception { 31 | TestScheduler testScheduler = Schedulers.test(); 32 | Observable interval = CreateObservable.interval( 33 | Arrays.asList(100L), TimeUnit.MILLISECONDS, testScheduler 34 | ); 35 | 36 | TestSubscriber subscriber = new TestSubscriber(); 37 | interval.subscribe(subscriber); 38 | 39 | assertTrue(subscriber.getOnNextEvents().isEmpty()); 40 | 41 | testScheduler.advanceTimeBy(101L, TimeUnit.MILLISECONDS); 42 | assertEquals(Arrays.asList(0L), subscriber.getOnNextEvents()); 43 | 44 | testScheduler.advanceTimeBy(101L, TimeUnit.MILLISECONDS); 45 | assertEquals(Arrays.asList(0L, 1L), subscriber.getOnNextEvents()); 46 | 47 | testScheduler.advanceTimeTo(1L, TimeUnit.SECONDS); 48 | assertEquals(Arrays.asList(0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L), subscriber.getOnNextEvents()); 49 | } 50 | 51 | @Test 52 | public void testWithMabyGaps() throws Exception { 53 | TestScheduler testScheduler = Schedulers.test(); 54 | Observable interval = CreateObservable.interval( 55 | Arrays.asList(100L, 200L, 300L), TimeUnit.MILLISECONDS, testScheduler 56 | ); 57 | 58 | TestSubscriber subscriber = new TestSubscriber(); 59 | interval.subscribe(subscriber); 60 | 61 | assertTrue(subscriber.getOnNextEvents().isEmpty()); 62 | 63 | testScheduler.advanceTimeBy(100L, TimeUnit.MILLISECONDS); 64 | assertEquals(Arrays.asList(0L), subscriber.getOnNextEvents()); 65 | 66 | testScheduler.advanceTimeBy(100L, TimeUnit.MILLISECONDS); 67 | assertEquals(Arrays.asList(0L), subscriber.getOnNextEvents()); 68 | 69 | testScheduler.advanceTimeTo(1L, TimeUnit.SECONDS); 70 | assertEquals(Arrays.asList(0L, 1L, 2L, 3L, 4L), subscriber.getOnNextEvents()); 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/com/packtpub/reactive/chapter07/SortedObservableTest.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter07; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | import org.junit.After; 8 | import org.junit.Assert; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | 12 | import rx.Observable; 13 | import rx.observers.TestSubscriber; 14 | 15 | import com.packtpub.reactive.common.CreateObservable; 16 | 17 | /** 18 | * Demonstrates testing the same thing using different methods. 19 | * 20 | * @author meddle 21 | */ 22 | public class SortedObservableTest { 23 | 24 | private Observable tested; 25 | private List expected; 26 | 27 | @Before 28 | public void before() { 29 | tested = CreateObservable.sorted( 30 | (a, b) -> a.compareTo(b), 31 | "Star", "Bar", "Car", "War", "Far", "Jar"); 32 | expected = Arrays.asList("Bar", "Car", "Far", "Jar", "Star", "War"); 33 | } 34 | 35 | @After 36 | public void after() { 37 | tested = null; 38 | expected = null; 39 | } 40 | 41 | private class TestData { 42 | private Throwable error = null; 43 | private boolean completed = false; 44 | private List result = new ArrayList(); 45 | 46 | public void setError(Throwable error) { 47 | this.error = error; 48 | } 49 | 50 | public boolean isCompleted() { 51 | return completed; 52 | } 53 | 54 | public void setCompleted(boolean completed) { 55 | this.completed = completed; 56 | } 57 | 58 | public List getResult() { 59 | return result; 60 | } 61 | 62 | public Throwable getError() { 63 | return error; 64 | } 65 | } 66 | 67 | @Test 68 | public void testUsingNormalSubscription() { 69 | TestData data = new TestData(); 70 | 71 | tested.subscribe( 72 | (v) -> data.getResult().add(v), 73 | (e) -> data.setError(e), 74 | () -> data.setCompleted(true)); 75 | 76 | Assert.assertTrue(data.isCompleted()); 77 | Assert.assertNull(data.getError()); 78 | Assert.assertEquals(expected, data.getResult()); 79 | } 80 | 81 | @Test 82 | public void testUsingBlockingObservable() { 83 | List result = tested.toList().toBlocking().single(); 84 | 85 | Assert.assertEquals(expected, result); 86 | } 87 | 88 | @Test 89 | public void testUsingTestSubscriber() { 90 | TestSubscriber subscriber = new TestSubscriber(); 91 | tested.subscribe(subscriber); 92 | 93 | Assert.assertEquals(expected, subscriber.getOnNextEvents()); 94 | Assert.assertSame(1, subscriber.getOnCompletedEvents().size()); 95 | Assert.assertTrue(subscriber.getOnErrorEvents().isEmpty()); 96 | Assert.assertTrue(subscriber.isUnsubscribed()); 97 | } 98 | 99 | @Test 100 | public void testUsingTestSubscriberAssertions() { 101 | TestSubscriber subscriber = new TestSubscriber(); 102 | tested.subscribe(subscriber); 103 | 104 | subscriber.assertReceivedOnNext(expected); 105 | subscriber.assertTerminalEvent(); 106 | subscriber.assertNoErrors(); 107 | subscriber.assertUnsubscribed(); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/com/packtpub/reactive/chapter08/IndexedTest.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter08; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | import org.junit.Test; 9 | 10 | import rx.Observable; 11 | import rx.observers.TestSubscriber; 12 | 13 | import com.packtpub.reactive.chapter08.Lift.Indexed; 14 | import com.packtpub.reactive.chapter08.Lift.Pair; 15 | 16 | /** 17 | * Tests the {@link Indexed} operator. 18 | * 19 | * @author meddle 20 | */ 21 | public class IndexedTest { 22 | 23 | @Test 24 | public void testGeneratesSequentialIndexes() { 25 | Observable> observable = Observable 26 | .just("a", "b", "c", "d", "e") 27 | .lift(new Indexed()); 28 | 29 | List> expected = Arrays.asList( 30 | new Pair(0L, "a"), 31 | new Pair(1L, "b"), 32 | new Pair(2L, "c"), 33 | new Pair(3L, "d"), 34 | new Pair(4L, "e") 35 | ); 36 | 37 | List> actual = observable 38 | .toList() 39 | .toBlocking(). 40 | single(); 41 | 42 | assertEquals(expected, actual); 43 | 44 | // The same result the second time around 45 | TestSubscriber> testSubscriber = new TestSubscriber>(); 46 | observable.subscribe(testSubscriber); 47 | 48 | testSubscriber.assertReceivedOnNext(expected); 49 | 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/test/java/com/packtpub/reactive/chapter08/OddFilterTest.java: -------------------------------------------------------------------------------- 1 | package com.packtpub.reactive.chapter08; 2 | 3 | import static org.junit.Assert.assertEquals; 4 | 5 | import java.util.Arrays; 6 | import java.util.List; 7 | 8 | import org.junit.Test; 9 | 10 | import rx.Observable; 11 | import rx.Observable.Transformer; 12 | 13 | import com.packtpub.reactive.chapter08.Compose.OddFilter; 14 | 15 | /** 16 | * Test for the {@link OddFilter} {@link Transformer}. 17 | * 18 | * @author meddle 19 | */ 20 | public class OddFilterTest { 21 | 22 | @Test 23 | public void testFiltersOddOfTheSequence() { 24 | 25 | Observable tested = Observable 26 | .just("One", "Two", "Three", "Four", "Five", "June", "July") 27 | .compose(new OddFilter()); 28 | 29 | List expected = 30 | Arrays.asList("One", "Three", "Five", "July"); 31 | 32 | List actual = tested 33 | .toList() 34 | .toBlocking() 35 | .single(); 36 | 37 | assertEquals(expected, actual); 38 | } 39 | 40 | } 41 | --------------------------------------------------------------------------------