├── RxAndroidTest
├── app
│ ├── .gitignore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ ├── values
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ ├── dimens.xml
│ │ │ │ │ ├── styles.xml
│ │ │ │ │ └── strings.xml
│ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ ├── ic_launcher.xml
│ │ │ │ │ └── ic_launcher_round.xml
│ │ │ │ ├── drawable-v24
│ │ │ │ │ └── ic_launcher_foreground.xml
│ │ │ │ ├── layout
│ │ │ │ │ └── activity_login.xml
│ │ │ │ └── drawable
│ │ │ │ │ └── ic_launcher_background.xml
│ │ │ └── AndroidManifest.xml
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── adamldavis
│ │ │ │ └── rxadroidtest
│ │ │ │ └── ExampleUnitTest.java
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── adamldavis
│ │ │ └── rxadroidtest
│ │ │ └── ExampleInstrumentedTest.java
│ ├── proguard-rules.pro
│ └── build.gradle
├── settings.gradle
├── README.md
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── build.gradle
├── gradle.properties
├── .gitignore
├── gradlew.bat
├── gradlew
└── LICENSE
├── reactive-streams-in-java
├── gradle.properties
├── testfile.txt
├── compare_performance.ods
├── README.md
├── .gitignore
├── src
│ ├── main
│ │ └── java
│ │ │ └── com
│ │ │ └── github
│ │ │ └── adamldavis
│ │ │ ├── ReactiveStreamsDemo.java
│ │ │ ├── MessageConsumer.java
│ │ │ ├── MessageController.java
│ │ │ ├── Application.java
│ │ │ ├── Channel.java
│ │ │ ├── AkkaStreamsDemo.java
│ │ │ ├── ReactorDemo.java
│ │ │ └── RxJavaDemo.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── github
│ │ └── adamldavis
│ │ ├── DemoData.java
│ │ ├── RxJavaDemoTest.java
│ │ ├── ReactorDemo10Test.java
│ │ ├── AkkaStreamsDemoTest.java
│ │ ├── ReactorDemoTest.java
│ │ └── PerformanceTest.java
├── build.gradle
├── perf.csv
├── pom.xml
└── LICENSE
├── humblecode
├── settings.gradle
├── mongo.sh
├── src
│ ├── main
│ │ ├── resources
│ │ │ ├── static
│ │ │ │ ├── images
│ │ │ │ │ ├── Holly.gif
│ │ │ │ │ ├── Olive.gif
│ │ │ │ │ ├── Zamia.gif
│ │ │ │ │ ├── Eggplant.gif
│ │ │ │ │ ├── Pinkroot.gif
│ │ │ │ │ ├── Sugar_Cane.gif
│ │ │ │ │ └── Honeysuckle.gif
│ │ │ │ ├── error
│ │ │ │ │ └── 404.html
│ │ │ │ ├── css
│ │ │ │ │ ├── prettify.css
│ │ │ │ │ └── base.css
│ │ │ │ └── js
│ │ │ │ │ ├── html5shiv.min.js
│ │ │ │ │ └── main.js
│ │ │ └── templates
│ │ │ │ ├── pay.ftl
│ │ │ │ ├── login.ftl
│ │ │ │ ├── home.ftl
│ │ │ │ └── account.ftl
│ │ └── java
│ │ │ └── com
│ │ │ └── humblecode
│ │ │ └── humblecode
│ │ │ ├── model
│ │ │ ├── TestResult.java
│ │ │ ├── Payment.java
│ │ │ ├── Question.java
│ │ │ ├── Segment.java
│ │ │ ├── Test.java
│ │ │ ├── Course.java
│ │ │ └── User.java
│ │ │ ├── HumblecodeApplication.java
│ │ │ ├── WebFluxConfig.java
│ │ │ ├── rest
│ │ │ ├── PaymentControl.java
│ │ │ └── CourseControl.java
│ │ │ ├── SecurityConfig.java
│ │ │ └── web
│ │ │ └── WebControl.java
│ └── test
│ │ └── java
│ │ └── com
│ │ └── humblecode
│ │ └── humblecode
│ │ └── HumblecodeApplicationTests.java
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── README.md
├── humblecode
│ └── .gitignore
├── .gitignore
├── build.gradle
├── gradlew.bat
└── gradlew
├── .gitattributes
├── 9781484241752.jpg
├── akka-http-java
├── README.md
├── .gitignore
├── src
│ ├── main
│ │ ├── java
│ │ │ └── com
│ │ │ │ └── github
│ │ │ │ └── adamldavis
│ │ │ │ └── akkahttp
│ │ │ │ ├── MessageRepository.java
│ │ │ │ ├── ChatMessage.java
│ │ │ │ ├── WebApp.java
│ │ │ │ ├── JmsToWebSocket.java
│ │ │ │ ├── ChatServer.java
│ │ │ │ └── WebSocketExample.java
│ │ └── resources
│ │ │ └── akkahttp
│ │ │ └── index.html
│ └── test
│ │ └── java
│ │ └── com
│ │ └── github
│ │ └── adamldavis
│ │ └── akkhttp
│ │ ├── WebAppTest.java
│ │ ├── MessageRepositoryTest.java
│ │ └── ChatServerTest.java
└── build.gradle
├── errata.md
├── README.md
├── Contributing.md
└── LICENSE.txt
/RxAndroidTest/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/gradle.properties:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/RxAndroidTest/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/testfile.txt:
--------------------------------------------------------------------------------
1 | foo
2 | bar
3 |
--------------------------------------------------------------------------------
/humblecode/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'humblecode'
2 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/9781484241752.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/9781484241752.jpg
--------------------------------------------------------------------------------
/RxAndroidTest/README.md:
--------------------------------------------------------------------------------
1 | # RxAndroidTest
2 | Demo of RxJava, RxAndroid, RxLifecycle, and RxBinding
3 |
--------------------------------------------------------------------------------
/humblecode/mongo.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | mongod --dbpath data/ --fork --logpath ~/mongodb/logs/mongodb.log
4 |
5 |
--------------------------------------------------------------------------------
/RxAndroidTest/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/RxAndroidTest/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/reactive-streams-in-java/compare_performance.ods:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/reactive-streams-in-java/compare_performance.ods
--------------------------------------------------------------------------------
/humblecode/src/main/resources/static/images/Holly.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/humblecode/src/main/resources/static/images/Holly.gif
--------------------------------------------------------------------------------
/humblecode/src/main/resources/static/images/Olive.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/humblecode/src/main/resources/static/images/Olive.gif
--------------------------------------------------------------------------------
/humblecode/src/main/resources/static/images/Zamia.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/humblecode/src/main/resources/static/images/Zamia.gif
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/RxAndroidTest/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/RxAndroidTest/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/humblecode/src/main/resources/static/images/Eggplant.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/humblecode/src/main/resources/static/images/Eggplant.gif
--------------------------------------------------------------------------------
/humblecode/src/main/resources/static/images/Pinkroot.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/humblecode/src/main/resources/static/images/Pinkroot.gif
--------------------------------------------------------------------------------
/humblecode/src/main/resources/static/images/Sugar_Cane.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/humblecode/src/main/resources/static/images/Sugar_Cane.gif
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/RxAndroidTest/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/RxAndroidTest/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/humblecode/src/main/resources/static/images/Honeysuckle.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/humblecode/src/main/resources/static/images/Honeysuckle.gif
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/RxAndroidTest/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/RxAndroidTest/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/RxAndroidTest/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/RxAndroidTest/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/RxAndroidTest/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/reactive-streams-in-java/HEAD/RxAndroidTest/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/akka-http-java/README.md:
--------------------------------------------------------------------------------
1 | # akka-http-java
2 |
3 | ## Demo of Akka Http + Akka Streams in Java
4 |
5 | Built to accompany the book "Reactive Streams in Java"
6 |
7 | See [akka-http docs](https://doc.akka.io/docs/akka-http/10.1.3/introduction.html) for more.
8 |
9 |
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/errata.md:
--------------------------------------------------------------------------------
1 | # Errata for *Book Title*
2 |
3 | On **page xx** [Summary of error]:
4 |
5 | Details of error here. Highlight key pieces in **bold**.
6 |
7 | ***
8 |
9 | On **page xx** [Summary of error]:
10 |
11 | Details of error here. Highlight key pieces in **bold**.
12 |
13 | ***
--------------------------------------------------------------------------------
/RxAndroidTest/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Sep 21 21:45:59 EDT 2018
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-4.4-all.zip
7 |
--------------------------------------------------------------------------------
/humblecode/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Jun 26 14:24:36 EDT 2018
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-4.5.1-all.zip
7 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/README.md:
--------------------------------------------------------------------------------
1 | # reactive-streams-in-java
2 | Reactive Streams in Java
3 |
4 | Examples of three different implementations of reactive streams in Java.
5 | - Akka Stream
6 | - Project Reactor
7 | - RxJava2
8 |
9 | ## Building
10 |
11 | Can be built with either Gradle or Maven.
12 |
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/humblecode/src/main/resources/static/error/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 404 Not Found
6 |
7 |
8 |
9 | Can't find it. Sorry
10 | Please have this nice picture instead...
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/humblecode/README.md:
--------------------------------------------------------------------------------
1 | # Demo of Spring Boot + Reactor + MongoDB
2 |
3 | Welcome to HumbleCode, my demo code for Spring Boot, Reactor, and reactive-mongo.
4 |
5 | This code is part of the leanpub book, [Reactive Streams in Java](https://leanpub.com/reactivestreamsinjava).
6 |
7 | The example is built around an online Course catalog and includes security, WebFlux configuration,
8 | and even some payment logic.
9 |
--------------------------------------------------------------------------------
/humblecode/src/main/java/com/humblecode/humblecode/model/TestResult.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode.model;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 |
6 | import java.util.Date;
7 | import java.util.UUID;
8 |
9 | @Data
10 | @AllArgsConstructor
11 | public class TestResult {
12 |
13 | UUID testId;
14 | Date date;
15 | boolean passed;
16 | float percent;
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/humblecode/humblecode/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | /build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 |
5 | ### STS ###
6 | .apt_generated
7 | .classpath
8 | .factorypath
9 | .project
10 | .settings
11 | .springBeans
12 | .sts4-cache
13 |
14 | ### IntelliJ IDEA ###
15 | .idea
16 | *.iws
17 | *.iml
18 | *.ipr
19 | /out/
20 |
21 | ### NetBeans ###
22 | /nbproject/private/
23 | /build/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
--------------------------------------------------------------------------------
/humblecode/src/main/resources/templates/pay.ftl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
--------------------------------------------------------------------------------
/humblecode/src/main/java/com/humblecode/humblecode/model/Payment.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode.model;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import org.springframework.data.mongodb.core.mapping.Document;
6 |
7 | import java.util.Date;
8 | import java.util.UUID;
9 |
10 | @Document
11 | @Data
12 | @AllArgsConstructor
13 | public class Payment {
14 |
15 | Date date;
16 | UUID userId;
17 | int amount;
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/akka-http-java/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 | # IDEA
4 | bin/
5 | target/
6 | build/
7 | .idea
8 | *.iml
9 | *.ipr
10 | *.ipw
11 |
12 | #Gradle
13 | .gradle
14 |
15 | # Log file
16 | *.log
17 |
18 | # BlueJ files
19 | *.ctxt
20 |
21 | # Mobile Tools for Java (J2ME)
22 | .mtj.tmp/
23 |
24 | # Package Files #
25 | *.jar
26 | *.war
27 | *.nar
28 | *.ear
29 | *.zip
30 | *.tar.gz
31 | *.rar
32 |
33 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
34 | hs_err_pid*
35 |
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/test/java/com/adamldavis/rxadroidtest/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.adamldavis.rxadroidtest;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/humblecode/src/main/java/com/humblecode/humblecode/model/Question.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode.model;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | @Data
10 | @AllArgsConstructor
11 | public class Question {
12 |
13 | String text = "";
14 |
15 | String tip = "";
16 |
17 | String answer = "";
18 |
19 | List answers = new ArrayList<>();
20 |
21 | List correctAnswers = new ArrayList<>();
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/.gitignore:
--------------------------------------------------------------------------------
1 | #Gradle
2 | .gradle
3 | build/
4 | #Eclipse
5 | .settings
6 | .classpath
7 | .project
8 | #IDEA
9 | *.iws
10 | *.iml
11 | .idea
12 | *.ipr
13 |
14 | # Compiled class file
15 | *.class
16 |
17 | # Log file
18 | *.log
19 |
20 | # BlueJ files
21 | *.ctxt
22 |
23 | # Mobile Tools for Java (J2ME)
24 | .mtj.tmp/
25 |
26 | # Package Files #
27 | *.jar
28 | *.war
29 | *.nar
30 | *.ear
31 | *.zip
32 | *.tar.gz
33 | *.rar
34 |
35 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
36 | hs_err_pid*
37 | /bin/
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Apress Source Code
2 |
3 | This repository accompanies [*Reactive Streams in Java*](https://www.apress.com/9781484241752) by Adam L. Davis (Apress, 2019).
4 |
5 | [comment]: #cover
6 | 
7 |
8 | Download the files as a zip using the green button, or clone the repository to your machine using Git.
9 |
10 | ## Releases
11 |
12 | Release v1.0 corresponds to the code in the published book, without corrections or updates.
13 |
14 | ## Contributions
15 |
16 | See the file Contributing.md for more information on how you can contribute to this repository.
--------------------------------------------------------------------------------
/humblecode/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled class file
2 | *.class
3 |
4 | # Secret properties
5 | application.*
6 |
7 | # IDEA files
8 | .idea
9 | *.iml
10 | *.iws
11 | *.ipr
12 | out/
13 | build/
14 | #Gradle
15 | .gradle
16 |
17 | #mongo
18 | data/
19 |
20 | # Log file
21 | *.log
22 |
23 | # BlueJ files
24 | *.ctxt
25 |
26 | # Mobile Tools for Java (J2ME)
27 | .mtj.tmp/
28 |
29 | # Package Files #
30 | *.jar
31 | *.war
32 | *.nar
33 | *.ear
34 | *.zip
35 | *.tar.gz
36 | *.rar
37 |
38 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
39 | hs_err_pid*
40 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/src/main/java/com/github/adamldavis/ReactiveStreamsDemo.java:
--------------------------------------------------------------------------------
1 | package com.github.adamldavis;
2 |
3 | import java.util.List;
4 | import java.util.concurrent.Future;
5 |
6 | /** Interface to implement for each implementation of reactive streams in Java for performance testing. */
7 | public interface ReactiveStreamsDemo {
8 |
9 | Future> doSquaresAsync(int count);
10 |
11 | Future doStringConcatAsync(int count);
12 |
13 | Future> doParallelSquaresAsync(int count);
14 |
15 | Future doParallelStringConcatAsync(int count);
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/humblecode/src/main/resources/static/css/prettify.css:
--------------------------------------------------------------------------------
1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee}
2 |
--------------------------------------------------------------------------------
/RxAndroidTest/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 |
5 | repositories {
6 | google()
7 | jcenter()
8 | }
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:3.1.4'
11 |
12 |
13 | // NOTE: Do not place your application dependencies here; they belong
14 | // in the individual module build.gradle files
15 | }
16 | }
17 |
18 | allprojects {
19 | repositories {
20 | google()
21 | jcenter()
22 | }
23 | }
24 |
25 | task clean(type: Delete) {
26 | delete rootProject.buildDir
27 | }
28 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/src/test/java/com/github/adamldavis/DemoData.java:
--------------------------------------------------------------------------------
1 | package com.github.adamldavis;
2 |
3 | import java.util.List;
4 |
5 | import static java.util.Arrays.asList;
6 |
7 | public interface DemoData {
8 |
9 | List squares = asList(1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121,
10 | 144, 169, 196, 225, 256, 289, 324, 361, 400, 441, 484, 529, 576,
11 | 625, 676, 729, 784, 841, 900, 961, 1024, 1089, 1156, 1225, 1296,
12 | 1369, 1444, 1521, 1600, 1681, 1764, 1849, 1936, 2025, 2116, 2209,
13 | 2304, 2401, 2500, 2601, 2704, 2809, 2916, 3025, 3136, 3249, 3364,
14 | 3481, 3600, 3721, 3844, 3969, 4096);
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/Contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing to Apress Source Code
2 |
3 | Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers.
4 |
5 | ## How to Contribute
6 |
7 | 1. Make sure you have a GitHub account.
8 | 2. Fork the repository for the relevant book.
9 | 3. Create a new branch on which to make your change, e.g.
10 | `git checkout -b my_code_contribution`
11 | 4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted.
12 | 5. Submit a pull request.
13 |
14 | Thank you for your contribution!
--------------------------------------------------------------------------------
/akka-http-java/src/main/java/com/github/adamldavis/akkahttp/MessageRepository.java:
--------------------------------------------------------------------------------
1 | package com.github.adamldavis.akkahttp;
2 |
3 |
4 | import java.util.concurrent.CompletableFuture;
5 | import java.util.concurrent.CompletionStage;
6 |
7 | public class MessageRepository {
8 |
9 | public CompletionStage save(ChatMessage message) {
10 | return CompletableFuture.supplyAsync(() -> {
11 | try {
12 | Thread.sleep(500); // imitate long running operation
13 | } catch (InterruptedException e) {
14 | e.printStackTrace();
15 | }
16 | System.out.println("saving message: " + message);
17 | return message;
18 | });
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/humblecode/src/main/java/com/humblecode/humblecode/HumblecodeApplication.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
5 | import org.springframework.boot.autoconfigure.SpringBootApplication;
6 | import org.springframework.context.annotation.Bean;
7 | import reactor.core.publisher.Flux;
8 |
9 | @EnableAutoConfiguration
10 | @SpringBootApplication
11 | public class HumblecodeApplication {
12 |
13 | public static void main(String[] args) {
14 | SpringApplication.run(HumblecodeApplication.class, args);
15 | }
16 |
17 | @Bean
18 | public Flux exampleBean() {
19 | return Flux.just("example");
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/RxAndroidTest/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx1536m
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 |
--------------------------------------------------------------------------------
/humblecode/src/main/java/com/humblecode/humblecode/model/Segment.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode.model;
2 |
3 | import lombok.Data;
4 |
5 | import java.util.Objects;
6 | import java.util.UUID;
7 |
8 | @Data
9 | public class Segment {
10 |
11 | //String video;
12 |
13 | public UUID id = UUID.randomUUID();
14 |
15 | public String name;
16 |
17 | public String body; // body of the course as text
18 |
19 | public Test test;
20 |
21 | public int hashCode() {
22 | return id == null ? 0 : id.hashCode();
23 | }
24 |
25 | @Override
26 | public boolean equals(Object o) {
27 | if (this == o) return true;
28 | if (!(o instanceof Segment)) return false;
29 | Segment segment = (Segment) o;
30 | return Objects.equals(id, segment.id);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/RxAndroidTest/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/akka-http-java/src/test/java/com/github/adamldavis/akkhttp/WebAppTest.java:
--------------------------------------------------------------------------------
1 | package com.github.adamldavis.akkhttp;
2 |
3 | import akka.actor.ActorSystem;
4 | import akka.testkit.javadsl.TestKit;
5 | import com.github.adamldavis.akkahttp.WebApp;
6 | import org.junit.*;
7 | import static org.assertj.core.api.Assertions.assertThat;
8 |
9 | public class WebAppTest {
10 |
11 | WebApp webApp;
12 | ActorSystem actorSystem;
13 |
14 | @Before
15 | public void setup() {
16 | actorSystem = ActorSystem.create("test-system");
17 | webApp = new WebApp(actorSystem);
18 | }
19 | @After
20 | public void tearDown() {
21 | TestKit.shutdownActorSystem(actorSystem);
22 | }
23 |
24 | @Test
25 | public void createWebsocketRoute_should_exist(){
26 | assertThat(webApp.createWebsocketRoute()).isNotNull();
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | RxAdroidTest
3 |
4 |
5 | Email
6 | Password (optional)
7 | Sign in or register
8 | Sign in
9 | This email address is invalid
10 | This password is too short
11 | This password is incorrect
12 | This field is required
13 | "Contacts permissions are needed for providing email
14 | completions."
15 |
16 |
17 |
--------------------------------------------------------------------------------
/humblecode/src/main/java/com/humblecode/humblecode/WebFluxConfig.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode;
2 |
3 | import org.springframework.http.HttpStatus;
4 | import org.springframework.web.reactive.config.EnableWebFlux;
5 | import org.springframework.web.reactive.config.WebFluxConfigurationSupport;
6 | import org.springframework.web.server.WebExceptionHandler;
7 | import reactor.core.publisher.Mono;
8 |
9 | @EnableWebFlux
10 | public class WebFluxConfig extends WebFluxConfigurationSupport {
11 |
12 | @Override
13 | public WebExceptionHandler responseStatusExceptionHandler() {
14 | return (exchange, ex) -> Mono.create(callback -> {
15 | exchange.getResponse().setStatusCode(HttpStatus.I_AM_A_TEAPOT);
16 | System.err.println(ex.getMessage());
17 | callback.success(null);
18 | });
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/build.gradle:
--------------------------------------------------------------------------------
1 |
2 | plugins {
3 | id "java"
4 | id "application"
5 | id "idea"
6 | }
7 |
8 | mainClassName='com.github.adamldavis.Application'
9 |
10 | // REQUIRES Gradle 4.7+ and Java 10+
11 | sourceCompatibility = 1.10
12 | targetCompatibility = 1.10
13 |
14 | repositories {
15 | mavenLocal()
16 | jcenter()
17 | }
18 |
19 | dependencies {
20 |
21 | compile("org.springframework.boot:spring-boot-starter-web:2.0.2.RELEASE")
22 |
23 | compile 'io.reactivex.rxjava2:rxjava:2.1.9'
24 |
25 | compile 'io.projectreactor:reactor-core:3.1.7.RELEASE'
26 | testCompile 'io.projectreactor:reactor-test:3.1.7.RELEASE'
27 |
28 | compile group: 'com.typesafe.akka', name: 'akka-stream_2.12', version:'2.5.12'
29 | testCompile 'com.typesafe.akka:akka-stream-testkit_2.12:2.5.12'
30 |
31 | testCompile 'junit:junit:4.12'
32 | testCompile 'org.hamcrest:hamcrest-all:1.3'
33 | }
34 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/src/main/java/com/github/adamldavis/MessageConsumer.java:
--------------------------------------------------------------------------------
1 | package com.github.adamldavis;
2 |
3 | import io.reactivex.functions.Consumer;
4 |
5 | /**
6 | * Implements reactive-streams Consumer interface which could be done as a Java
7 | * 8 lambda, but sometimes you might want to pull the code out into its own
8 | * class.
9 | */
10 | public class MessageConsumer implements Consumer {
11 |
12 | final String type;
13 |
14 | public MessageConsumer(String type) {
15 | this.type = type;
16 | }
17 |
18 | @Override
19 | public void accept(String message) {
20 | // do something with the Data
21 | if (message.startsWith("Error:"))
22 | System.err.println("type=" + type + " message=" + message);
23 | else
24 | System.out.println("type=" + type + " message=" + message);
25 | }
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/androidTest/java/com/adamldavis/rxadroidtest/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.adamldavis.rxadroidtest;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumented test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.adamldavis.rxadroidtest", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/humblecode/src/main/java/com/humblecode/humblecode/model/Test.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode.model;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 | import java.util.UUID;
9 |
10 | /** Test user takes to complete the course. Questions are picked randomly out of given list of questions. */
11 | @Data
12 | @AllArgsConstructor
13 | public class Test {
14 |
15 | UUID id = UUID.randomUUID();
16 |
17 | /** List of quesions that make up the test. */
18 | final List questions = new ArrayList<>();
19 |
20 | /** Number of actual questions to use in the test, should be less than total number of questions. */
21 | public int numberOfQuestions;
22 |
23 | public Test() {}
24 |
25 | public void setQuestions(List questions) {
26 | this.questions.clear();
27 | this.questions.addAll(questions);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/perf.csv:
--------------------------------------------------------------------------------
1 | PSquares akka-st, 7279337
2 | PSquares reactor, 443791
3 | PSquares rxjava, 809336
4 | PStrCon akka-st, 116305
5 | PStrCon reactor, 212981
6 | PStrCon rxjava, 303566
7 | Squares akka-st, 730614
8 | Squares reactor, 18550
9 | Squares rxjava, 161371
10 | StrCon akka-st, 164492
11 | StrCon reactor, 49480
12 | StrCon rxjava, 98594
13 | PSquares akka-st, 3551354
14 | PSquares reactor, 270502
15 | PSquares rxjava, 373837
16 | PStrCon akka-st, 72037
17 | PStrCon reactor, 83421
18 | PStrCon rxjava, 85740
19 | Squares akka-st, 113160
20 | Squares reactor, 12973
21 | Squares rxjava, 25292
22 | StrCon akka-st, 89372
23 | StrCon reactor, 15333
24 | StrCon rxjava, 8317
25 | PSquares akka-st, 2383551
26 | PSquares reactor, 192171
27 | PSquares rxjava, 304251
28 | PStrCon akka-st, 57634
29 | PStrCon reactor, 56424
30 | PStrCon rxjava, 65377
31 | Squares akka-st, 58297
32 | Squares reactor, 4306
33 | Squares rxjava, 29972
34 | StrCon akka-st, 57856
35 | StrCon reactor, 6768
36 | StrCon rxjava, 6729
37 |
--------------------------------------------------------------------------------
/akka-http-java/build.gradle:
--------------------------------------------------------------------------------
1 |
2 | apply plugin: 'java'
3 | apply plugin: 'eclipse'
4 | apply plugin: 'idea'
5 | apply plugin: 'application'
6 |
7 | group = 'com.github.adamldavis'
8 | applicationName = 'akka-http-java'
9 | version = '0.0.1-SNAPSHOT'
10 | mainClassName = 'com.github.adamldavis.akkahttp.WebApp'
11 | // requires Gradle 4.7+
12 | sourceCompatibility = 1.10
13 | targetCompatibility = 1.10
14 |
15 | repositories {
16 | mavenCentral()
17 | }
18 | ext {
19 | akkaHttpVersion = '10.1.5'
20 | akkaVersion = '2.5.16'
21 | }
22 |
23 | dependencies {
24 | compile "com.typesafe.akka:akka-http_2.12:$akkaHttpVersion"
25 | compile "com.typesafe.akka:akka-http-jackson_2.12:$akkaHttpVersion"
26 | compile "com.typesafe.akka:akka-stream_2.12:$akkaVersion"
27 | compile group: 'com.typesafe.akka', name: 'akka-http-jackson_2.12', version: akkaHttpVersion
28 |
29 | testCompile "com.typesafe.akka:akka-http-testkit_2.12:$akkaHttpVersion"
30 | testCompile "com.typesafe.akka:akka-stream-testkit_2.12:$akkaVersion"
31 | testCompile 'junit:junit:4.12'
32 | testCompile "org.assertj:assertj-core:3.11.1"
33 | }
34 |
--------------------------------------------------------------------------------
/humblecode/src/main/java/com/humblecode/humblecode/model/Course.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode.model;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import org.springframework.data.annotation.Id;
6 | import org.springframework.data.mongodb.core.mapping.Document;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 | import java.util.UUID;
11 |
12 | @Data
13 | @AllArgsConstructor
14 | @Document
15 | public class Course {
16 |
17 | @Id UUID id = UUID.randomUUID();
18 |
19 | public String name;
20 | public long price = 2000; // $20.00 is default price
21 |
22 | public final List segments = new ArrayList<>();
23 |
24 | public Course(String name) {
25 | this.name = name;
26 | }
27 |
28 | public void setSegments(List segments) {
29 | this.segments.clear();
30 | this.segments.addAll(segments);
31 | }
32 |
33 | @Override
34 | public String toString() {
35 | return "Course{" +
36 | "name='" + name + '\'' +
37 | ", price=" + price +
38 | '}';
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/akka-http-java/src/test/java/com/github/adamldavis/akkhttp/MessageRepositoryTest.java:
--------------------------------------------------------------------------------
1 | package com.github.adamldavis.akkhttp;
2 |
3 | import com.github.adamldavis.akkahttp.ChatMessage;
4 | import com.github.adamldavis.akkahttp.MessageRepository;
5 | import org.junit.After;
6 | import org.junit.Before;
7 | import org.junit.Test;
8 |
9 | import java.util.concurrent.ExecutionException;
10 |
11 | import static org.assertj.core.api.Assertions.assertThat;
12 |
13 | public class MessageRepositoryTest {
14 |
15 | MessageRepository repository;
16 |
17 | @Before
18 | public void setup() {
19 | repository = new MessageRepository();
20 | }
21 | @After
22 | public void tearDown() {
23 | repository = null;
24 | }
25 |
26 | @Test(timeout = 2000)
27 | public void save_should_take_a_while() throws ExecutionException, InterruptedException {
28 | long start = System.currentTimeMillis();
29 |
30 | repository.save(new ChatMessage("foo", "testing 123")).toCompletableFuture().get();
31 |
32 | long took = System.currentTimeMillis() - start;
33 |
34 | assertThat(took).isGreaterThan(498);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/humblecode/src/main/resources/templates/login.ftl:
--------------------------------------------------------------------------------
1 |
2 |
3 | ${applicationName}: Login
4 |
5 |
6 |
7 |
8 |
9 |
10 |
${applicationName}
11 |
12 |
13 |
14 |
Login with Username and Password
15 |
16 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/RxAndroidTest/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | *.apk
3 | *.ap_
4 |
5 | # Files for the ART/Dalvik VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # Generated files
12 | bin/
13 | gen/
14 | out/
15 |
16 | # Gradle files
17 | .gradle/
18 | build/
19 |
20 | # Local configuration file (sdk path, etc)
21 | local.properties
22 |
23 | # Proguard folder generated by Eclipse
24 | proguard/
25 |
26 | # Log Files
27 | *.log
28 |
29 | # Android Studio Navigation editor temp files
30 | .navigation/
31 |
32 | # Android Studio captures folder
33 | captures/
34 |
35 | # IntelliJ
36 | *.iml
37 | .idea/workspace.xml
38 | .idea/tasks.xml
39 | .idea/gradle.xml
40 | .idea/assetWizardSettings.xml
41 | .idea/dictionaries
42 | .idea/libraries
43 | .idea/caches
44 |
45 | # Keystore files
46 | # Uncomment the following line if you do not want to check your keystore files in.
47 | #*.jks
48 |
49 | # External native build folder generated in Android Studio 2.2 and later
50 | .externalNativeBuild
51 |
52 | # Google Services (e.g. APIs or Firebase)
53 | google-services.json
54 |
55 | # Freeline
56 | freeline.py
57 | freeline/
58 | freeline_project_description.json
59 |
60 | # fastlane
61 | fastlane/report.xml
62 | fastlane/Preview.html
63 | fastlane/screenshots
64 | fastlane/test_output
65 | fastlane/readme.md
66 |
--------------------------------------------------------------------------------
/akka-http-java/src/main/resources/akkahttp/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hello Akka HTTP!
6 |
24 |
25 |
26 |
27 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/humblecode/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext {
3 | springBootVersion = '2.0.3.RELEASE'
4 | }
5 | repositories {
6 | mavenCentral()
7 | }
8 | dependencies {
9 | classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
10 | }
11 | }
12 |
13 | apply plugin: 'java'
14 | apply plugin: 'eclipse'
15 | apply plugin: 'org.springframework.boot'
16 | apply plugin: 'io.spring.dependency-management'
17 | apply plugin: 'idea'
18 |
19 |
20 | group = 'com.humblecode'
21 | version = '0.0.1-SNAPSHOT'
22 | sourceCompatibility = 1.8
23 |
24 | repositories {
25 | mavenCentral()
26 | }
27 |
28 | dependencies {
29 | compile 'com.stripe:stripe-java:5.38.0'
30 |
31 | compile('org.springframework.boot:spring-boot-starter-data-mongodb-reactive')
32 | compile('org.springframework.boot:spring-boot-starter-freemarker')
33 | compile('org.springframework.boot:spring-boot-starter-security')
34 | compile('org.springframework.boot:spring-boot-starter-webflux')
35 | compile 'io.projectreactor.ipc:reactor-netty'
36 | compileOnly('org.projectlombok:lombok')
37 |
38 | testCompile('org.springframework.boot:spring-boot-starter-test')
39 | testCompile('de.flapdoodle.embed:de.flapdoodle.embed.mongo')
40 | testCompile('io.projectreactor:reactor-test')
41 | testCompile('org.springframework.security:spring-security-test')
42 | }
43 |
--------------------------------------------------------------------------------
/humblecode/src/main/resources/static/css/base.css:
--------------------------------------------------------------------------------
1 | /* Sticky footer styles
2 | -------------------------------------------------- */
3 |
4 | html,
5 | body {
6 | height: 100%;
7 | /* The html and body elements cannot have any padding or margin. */
8 | }
9 |
10 | /* Wrapper for page content to push down footer */
11 | #wrap {
12 | min-height: 100%;
13 | height: auto !important;
14 | height: 100%;
15 | /* Negative indent footer by it's height */
16 | margin: 0 auto -60px;
17 | }
18 |
19 | /* Set the fixed height of the footer here */
20 | #push,
21 | #footer {
22 | height: 60px;
23 | }
24 | #footer {
25 | background-color: #f5f5f5;
26 | padding: 0;
27 | }
28 |
29 | /* Lastly, apply responsive CSS fixes as necessary */
30 | @media (max-width: 767px) {
31 | #footer {
32 | margin-left: -20px;
33 | margin-right: -20px;
34 | padding-left: 20px;
35 | padding-right: 20px;
36 | }
37 | }
38 |
39 | /* Custom page CSS
40 | -------------------------------------------------- */
41 | /* Not required for template or sticky footer method. */
42 |
43 | #wrap > .container {
44 | padding-top: 60px;
45 | }
46 | .container .credit {
47 | margin: 20px 0;
48 | }
49 |
50 | /*code {
51 | font-size: 80%;
52 | }*/
53 |
54 | .tags {
55 | display: flex;
56 | }
57 | .tags li {
58 | color: green;
59 | padding: 1em;
60 | list-style: none;
61 | }
62 | .tags li:hover { background: lightgray }
63 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Freeware License, some rights reserved
2 |
3 | Copyright (c) 2019 Adam L. Davis
4 |
5 | Permission is hereby granted, free of charge, to anyone obtaining a copy
6 | of this software and associated documentation files (the "Software"),
7 | to work with the Software within the limits of freeware distribution and fair use.
8 | This includes the rights to use, copy, and modify the Software for personal use.
9 | Users are also allowed and encouraged to submit corrections and modifications
10 | to the Software for the benefit of other users.
11 |
12 | It is not allowed to reuse, modify, or redistribute the Software for
13 | commercial use in any way, or for a user’s educational materials such as books
14 | or blog articles without prior permission from the copyright holder.
15 |
16 | The above copyright notice and this permission notice need to be included
17 | in all copies or substantial portions of the software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS OR APRESS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | SOFTWARE.
26 |
27 |
28 |
--------------------------------------------------------------------------------
/akka-http-java/src/main/java/com/github/adamldavis/akkahttp/ChatMessage.java:
--------------------------------------------------------------------------------
1 | package com.github.adamldavis.akkahttp;
2 |
3 | import com.fasterxml.jackson.annotation.JsonCreator;
4 | import com.fasterxml.jackson.annotation.JsonProperty;
5 |
6 | import java.util.Objects;
7 |
8 | public class ChatMessage {
9 |
10 | final String username;
11 | final String message;
12 |
13 | @JsonCreator
14 | public ChatMessage(@JsonProperty("username") String username,
15 | @JsonProperty("message") String message) {
16 | this.username = username;
17 | this.message = message;
18 | }
19 |
20 | @Override
21 | public String toString() {
22 | return "ChatMessage {username='" + username + '\'' +
23 | ", message='" + message + '\'' + '}';
24 | }
25 |
26 | @Override
27 | public boolean equals(Object o) {
28 | if (this == o) return true;
29 | if (!(o instanceof ChatMessage)) return false;
30 | ChatMessage that = (ChatMessage) o;
31 | return Objects.equals(username, that.username) &&
32 | Objects.equals(message, that.message);
33 | }
34 |
35 | @Override
36 | public int hashCode() {
37 | return Objects.hash(username, message);
38 | }
39 |
40 | public String getUsername() {
41 | return username;
42 | }
43 |
44 | public String getMessage() {
45 | return message;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/RxAndroidTest/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 28
5 | defaultConfig {
6 | applicationId "com.adamldavis.rxadroidtest"
7 | minSdkVersion 26
8 | targetSdkVersion 28
9 | versionCode 1
10 | versionName "1.0"
11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
12 | }
13 | buildTypes {
14 | release {
15 | minifyEnabled false
16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
17 | }
18 | }
19 | compileOptions {
20 | sourceCompatibility '1.8'
21 | targetCompatibility '1.8'
22 | }
23 | }
24 |
25 | dependencies {
26 | implementation fileTree(dir: 'libs', include: ['*.jar'])
27 | implementation 'com.android.support:appcompat-v7:28.0.0-rc02'
28 | implementation 'com.android.support:design:28.0.0-rc02'
29 | // begin changes
30 | implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
31 | implementation 'io.reactivex.rxjava2:rxjava:2.2.2'
32 | implementation 'com.jakewharton.rxbinding2:rxbinding:2.1.1'
33 | implementation 'com.trello.rxlifecycle2:rxlifecycle:2.2.2'
34 | implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.2'
35 | implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.2'
36 | // end changes
37 | testImplementation 'junit:junit:4.12'
38 | androidTestImplementation 'com.android.support.test:runner:1.0.2'
39 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
40 | }
41 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/src/main/java/com/github/adamldavis/MessageController.java:
--------------------------------------------------------------------------------
1 | package com.github.adamldavis;
2 |
3 | import java.util.Arrays;
4 | import java.util.List;
5 | import java.util.Random;
6 |
7 | import io.reactivex.Observable;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.http.ResponseEntity;
10 | import org.springframework.stereotype.Controller;
11 | import org.springframework.web.bind.annotation.GetMapping;
12 | import org.springframework.web.bind.annotation.PathVariable;
13 |
14 | @Controller
15 | public class MessageController {
16 |
17 | @Autowired
18 | private Channel channel;
19 |
20 | final List types = Arrays.asList("Error", "Warning", "Info");
21 |
22 | final String INFO = "Channel is running? %s, name: %s, pollCount: %d. (Use /messages/100 to add 100 messages)\n";
23 | final String POSTED = "Posted %d messages.\n";
24 |
25 | @GetMapping("/messages/{param}")
26 | public ResponseEntity createMessages(@PathVariable Integer param) {
27 | final Random rnd = new Random();
28 | // using RxJava to create the messages:
29 | Observable.range(0, param)
30 | .subscribeOn(io.reactivex.schedulers.Schedulers.computation())
31 | .map(i -> types.get(rnd.nextInt(3)) + ": message " + i)
32 | .doOnNext(msg -> channel.publish(msg))
33 | .forEach(msg -> System.out.println("Posted message : " + msg));
34 |
35 | return ResponseEntity.ok(String.format(POSTED, param) + getInfo());
36 | }
37 |
38 | @GetMapping("/")
39 | public ResponseEntity info() {
40 | return ResponseEntity.ok(getInfo());
41 | }
42 |
43 | private String getInfo() {
44 | return String.format(INFO, channel.isAlive(), channel.getName(), channel.pollCount.get());
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/humblecode/src/main/resources/templates/home.ftl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ${applicationName}: Learn how to code
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
24 |
25 |
26 |
27 |
28 |
29 | <#if name == "">
Sign up today!#if>
30 |
31 |
Hello ${name}!
32 |
33 |
36 |
37 |
38 |
39 |
42 |
43 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/humblecode/src/main/resources/templates/account.ftl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | ${applicationName}: Learn how to code
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
25 |
26 |
27 |
28 |
29 |
30 |
Hello ${username}!
31 |
32 |
35 |
36 |
37 |
38 |
39 | Upgrade now to get access to all courses.
40 | Includes: Courses, Tests, Certificates upon completion.
41 |
42 |
43 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/humblecode/src/main/java/com/humblecode/humblecode/model/User.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode.model;
2 |
3 | import lombok.Data;
4 | import org.springframework.data.annotation.Id;
5 | import org.springframework.data.mongodb.core.mapping.Document;
6 | import org.springframework.security.core.GrantedAuthority;
7 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
8 | import org.springframework.security.core.userdetails.UserDetails;
9 |
10 | import java.util.*;
11 |
12 | @Data
13 | @Document
14 | public class User implements UserDetails {
15 |
16 | static final String DEFAULT = "default";
17 | static final String MONTHLY = "monthly";
18 | static final String YEARLY = "yearly";
19 |
20 | @Id
21 | public UUID id = UUID.randomUUID();
22 |
23 | public String username;
24 |
25 | public String credentials;
26 |
27 | public String accountType = DEFAULT; //default/monthly/etc.
28 |
29 | public String loginType; // github/facebook/etc.
30 |
31 | public List courseIdsPaidFor = new LinkedList<>();
32 |
33 | public List testResults = new LinkedList<>();
34 |
35 | public User() {}
36 | public User(String username, String credentials) {
37 | this.username = username;
38 | this.credentials = credentials;
39 | }
40 |
41 | @Override
42 | public Collection extends GrantedAuthority> getAuthorities() {
43 | return Arrays.asList(new SimpleGrantedAuthority("user"));
44 | }
45 |
46 | @Override
47 | public String getPassword() {
48 | return credentials;
49 | }
50 |
51 | @Override
52 | public String getUsername() {
53 | return username;
54 | }
55 |
56 | @Override
57 | public boolean isAccountNonExpired() {
58 | return true;
59 | }
60 |
61 | @Override
62 | public boolean isAccountNonLocked() {
63 | return true;
64 | }
65 |
66 | @Override
67 | public boolean isCredentialsNonExpired() {
68 | return true;
69 | }
70 |
71 | @Override
72 | public boolean isEnabled() {
73 | return true;
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/humblecode/src/main/java/com/humblecode/humblecode/rest/PaymentControl.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode.rest;
2 |
3 | import com.stripe.Stripe;
4 | import com.stripe.model.Charge;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 | import org.springframework.beans.factory.annotation.Value;
8 | import org.springframework.web.bind.annotation.PostMapping;
9 | import org.springframework.web.bind.annotation.RequestBody;
10 | import org.springframework.web.bind.annotation.RestController;
11 | import reactor.core.publisher.Mono;
12 |
13 | import java.util.Map;
14 |
15 | @RestController
16 | public class PaymentControl {
17 |
18 | private static final Logger logger = LoggerFactory.getLogger(PaymentControl.class);
19 |
20 | @Value("${app.stripe.secret}")
21 | String secret;
22 |
23 | @PostMapping(value = "/pay", consumes = "application/x-www-form-urlencoded;charset=UTF-8")
24 | public Mono postCharge(@RequestBody final Map params) {
25 | // Set your secret key: remember to change this to your live secret key in production
26 | // See your keys here: https://dashboard.stripe.com/account/apikeys
27 | Stripe.apiKey = secret;
28 |
29 | // These parameters come from the request body and we should probably validate them.
30 | // params.put("amount", 999);
31 | // params.put("currency", "usd");
32 | // params.put("source", "tok_visa");
33 | // params.put("receipt_email", "jenny.rosen@example.com");
34 | return Mono. create(callback -> {
35 | try {
36 | Charge charge = Charge.create(params);
37 |
38 | logger.info("Charge:" + charge.getDescription() + " at " +
39 | System.currentTimeMillis() + " of amount: $" + charge.getAmount() / 100 + "."
40 | + (charge.getAmount() % 100) + " was " + charge.getStatus());
41 |
42 | callback.success(charge.getStatus());
43 | } catch (Throwable ex) {
44 | callback.error(ex);
45 | }
46 | }).doOnError(e -> logger.error(e.getMessage(), e));
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/humblecode/src/main/java/com/humblecode/humblecode/SecurityConfig.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode;
2 |
3 | import com.humblecode.humblecode.data.UserRepository;
4 | import com.humblecode.humblecode.model.User;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.context.annotation.Bean;
7 | import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
8 | import org.springframework.security.config.web.server.ServerHttpSecurity;
9 | import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
10 | import org.springframework.security.core.userdetails.UserDetails;
11 | import org.springframework.security.crypto.password.PasswordEncoder;
12 | import org.springframework.security.web.server.SecurityWebFilterChain;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | @EnableWebFluxSecurity
18 | public class SecurityConfig {
19 |
20 | @Bean
21 | public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
22 | http
23 | .authorizeExchange()
24 | .pathMatchers("/api/**", "/css/**", "/js/**", "/images/**", "/").permitAll()
25 | .pathMatchers("/user/**").hasAuthority("user")
26 | .and()
27 | .csrf()
28 | .and()
29 | .formLogin();
30 | return http.build();
31 | }
32 |
33 | @Bean
34 | public MapReactiveUserDetailsService userDetailsService(@Autowired UserRepository userRepository) {
35 | List userDetails = new ArrayList<>();
36 | userDetails.addAll(userRepository.findAll().collectList().block());
37 | if (userDetails.isEmpty()) { // here for tests to work
38 | userDetails.add(new User("user1", "password"));
39 | }
40 | return new MapReactiveUserDetailsService(userDetails);
41 | }
42 |
43 | @Bean
44 | public PasswordEncoder myPasswordEncoder() {
45 | // never do this in production of course
46 | return new PasswordEncoder() {
47 | @Override
48 | public String encode(CharSequence charSequence) {
49 | return charSequence.toString();
50 | }
51 | @Override
52 | public boolean matches(CharSequence charSequence, String s) {
53 | return charSequence.equals(s);
54 | }
55 | };
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/RxAndroidTest/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/humblecode/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 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
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 Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/humblecode/src/main/resources/static/js/html5shiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.2",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b)}(this,document);
--------------------------------------------------------------------------------
/reactive-streams-in-java/src/main/java/com/github/adamldavis/Application.java:
--------------------------------------------------------------------------------
1 | package com.github.adamldavis;
2 |
3 | import akka.actor.ActorSystem;
4 | import akka.stream.ActorMaterializer;
5 | import akka.stream.OverflowStrategy;
6 | import akka.stream.javadsl.Sink;
7 | import akka.stream.javadsl.Source;
8 | import org.springframework.boot.SpringApplication;
9 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
10 | import org.springframework.context.annotation.Bean;
11 | import org.springframework.context.annotation.ComponentScan;
12 | import org.springframework.context.annotation.Configuration;
13 | import org.springframework.context.annotation.Lazy;
14 |
15 | import reactor.core.publisher.Flux;
16 | import reactor.core.scheduler.Schedulers;
17 |
18 | @Configuration
19 | @EnableAutoConfiguration
20 | @ComponentScan
21 | public class Application {
22 |
23 | @Bean
24 | Flux createMessageFlux(final Channel channel) {
25 | // using Reactor to create a Flux linked to the Channel:
26 | Flux bridge = Flux.create(sink -> {
27 | sink.onRequest(n -> channel.poll(n)) // 1
28 | .onCancel(channel::cancel) // 2
29 | .onDispose(channel::close); // 3
30 |
31 | channel.register(sink::next); //4
32 | });
33 | return bridge;
34 | }
35 |
36 | @Lazy(false)
37 | @Bean
38 | MessageConsumer createMessageConsumer(Flux messageFlux) {
39 | MessageConsumer messageConsumer = new MessageConsumer("Reactor");
40 | // using Reactor to consume messages:
41 | messageFlux.publishOn(Schedulers.newSingle("message-pub"))
42 | .subscribeOn(Schedulers.elastic())
43 | .onBackpressureBuffer(100) // 100 max buffer
44 | .subscribe(s -> messageConsumer.accept(s));
45 |
46 | return messageConsumer;
47 | }
48 |
49 | @Lazy(false)
50 | @Bean
51 | MessageConsumer createAkkaMessageConsumer(Flux messageFlux, ActorSystem actorSystem) {
52 | MessageConsumer messageConsumer = new MessageConsumer("Akka");
53 | // using Akka Streams to consume messages:
54 | ActorMaterializer mat = ActorMaterializer.create(actorSystem);
55 |
56 | Source.fromPublisher(messageFlux)
57 | .buffer(100, OverflowStrategy.backpressure()) // 100 max buffer
58 | .to(Sink.foreach(msg -> messageConsumer.accept(msg)))
59 | .run(mat);
60 |
61 | return messageConsumer;
62 | }
63 |
64 | @Bean
65 | ActorSystem createActorSystem() {
66 | return ActorSystem.create();
67 | }
68 |
69 | public static void main(String[] args) {
70 | SpringApplication.run(Application.class, args);
71 | }
72 | }
--------------------------------------------------------------------------------
/humblecode/src/main/java/com/humblecode/humblecode/rest/CourseControl.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode.rest;
2 |
3 | import com.humblecode.humblecode.data.CourseRepository;
4 | import com.humblecode.humblecode.model.Course;
5 | import com.humblecode.humblecode.model.Segment;
6 | import org.springframework.http.MediaType;
7 | import org.springframework.web.bind.annotation.*;
8 | import reactor.core.publisher.Flux;
9 | import reactor.core.publisher.Mono;
10 |
11 | import java.util.Map;
12 | import java.util.UUID;
13 |
14 | @RestController
15 | public class CourseControl {
16 |
17 | final CourseRepository courseRepository;
18 |
19 | public CourseControl(CourseRepository courseRepository) {
20 | this.courseRepository = courseRepository;
21 | }
22 |
23 | @GetMapping("/api/courses")
24 | public Flux getCourses() {
25 | return courseRepository.findAll();
26 | }
27 |
28 | @GetMapping("/api/course/{id}")
29 | public Mono getCourse(@PathVariable("id") String id) {
30 | return courseRepository.findById(UUID.fromString(id));
31 | }
32 |
33 | @PostMapping(value = "/api/course", consumes = MediaType.APPLICATION_JSON_VALUE)
34 | public Mono saveCourse(@RequestBody Map body) {
35 | Course course = new Course((String) body.get("name"));
36 |
37 | course.price = Long.parseLong(body.get("price").toString());
38 |
39 | return courseRepository.insert(course);
40 | }
41 |
42 | @PutMapping(value = "/api/course/{id}", consumes = MediaType.APPLICATION_JSON_VALUE)
43 | public Mono updateCourse(@PathVariable("id") String id, @RequestBody Map body) {
44 |
45 | Mono courseMono = courseRepository.findById(UUID.fromString(id));
46 |
47 | return courseMono.flatMap(course -> {
48 | if (body.containsKey("price")) course.price = Long.parseLong(body.get("price").toString());
49 | if (body.containsKey("name")) course.name = (String) body.get("name");
50 | return courseRepository.save(course);
51 | });
52 | }
53 |
54 | @PostMapping(value = "/api/course/{id}/segment", consumes = MediaType.APPLICATION_JSON_VALUE)
55 | public Mono saveSegment(@PathVariable("id") String id, Segment segment) {
56 | Mono courseMono = courseRepository.findById(UUID.fromString(id));
57 |
58 | return courseMono.flatMap(course -> {
59 | int index = course.segments.indexOf(segment);
60 |
61 | course.segments.remove(segment); // remove it if already there
62 | if (index >= 0) {
63 | course.segments.add(index, segment);
64 | } else {
65 | course.segments.add(segment);
66 | }
67 | return courseRepository.save(course);
68 | });
69 | }
70 |
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/src/main/java/com/github/adamldavis/Channel.java:
--------------------------------------------------------------------------------
1 | package com.github.adamldavis;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Deque;
5 | import java.util.List;
6 | import java.util.concurrent.ConcurrentLinkedDeque;
7 | import java.util.concurrent.atomic.AtomicLong;
8 |
9 | import org.springframework.stereotype.Service;
10 |
11 | import io.reactivex.functions.Consumer;
12 |
13 | /**
14 | * Channel uses a Deque to act as a buffer of messages.
15 | * Merely here as a demo of integrating an outside system with Reactive Streams.
16 | * In practice this could probably be better replaced by PublishProcessor in RxJava or a Broadcast in Akka Streams
17 | * or UnicastProcessor in Reactor.
18 | *
19 | * This is definitely not the best implementation available for this concept.
20 | * For example, this Channel does not make any guarantee about ordering. Again, this is just for show.
21 | */
22 | @Service
23 | public class Channel extends Thread {
24 |
25 | final Deque deque = new ConcurrentLinkedDeque<>();
26 |
27 | final List> listeners = new ArrayList<>();
28 |
29 | AtomicLong pollCount = new AtomicLong(0);
30 |
31 | /** Non-Blocking and increments the pollCount by n. */
32 | public void poll(long n) {
33 | synchronized (deque) {
34 | pollCount.getAndAdd(n);
35 | System.out.println("--> poll (" + n + ") called");
36 | if (!isAlive()) start();
37 | }
38 | }
39 |
40 | /** Loops forever, gets up to pollCount messages and sends them to the Listeners. */
41 | @Override
42 | public void run() {
43 | while (true) {
44 | loop();
45 | }
46 | }
47 |
48 | private void loop() {
49 | int count = 0;
50 |
51 | for (String msg; count < pollCount.get() && !deque.isEmpty(); count++) {
52 | msg = deque.pop();
53 | final String message = msg;
54 | listeners.forEach(listener -> {
55 | try {
56 | listener.accept(message);
57 | } catch (Exception e) {
58 | e.printStackTrace();
59 | }
60 | });
61 | }
62 | pollCount.getAndAdd(0 - count); // decrement by number of messages accepted.
63 | try {
64 | Thread.sleep(25);
65 | } // sleep to allow other threads to go
66 | catch (Exception ignore) {}
67 | }
68 |
69 | public void cancel() {
70 | deque.clear();
71 | super.interrupt();
72 | }
73 |
74 | public void close() {
75 | deque.clear();
76 | super.interrupt();
77 | }
78 |
79 | public void publish(String message) {
80 | deque.add(message);
81 | }
82 |
83 | public void register(Consumer listener) {
84 | listeners.add(listener);
85 | }
86 | }
--------------------------------------------------------------------------------
/humblecode/src/main/java/com/humblecode/humblecode/web/WebControl.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode.web;
2 |
3 | import com.humblecode.humblecode.data.CourseRepository;
4 | import com.humblecode.humblecode.data.UserRepository;
5 | import com.humblecode.humblecode.model.Course;
6 | import com.humblecode.humblecode.model.User;
7 | import org.springframework.beans.factory.annotation.Autowired;
8 | import org.springframework.beans.factory.annotation.Value;
9 | import org.springframework.stereotype.Controller;
10 | import org.springframework.ui.Model;
11 | import org.springframework.web.bind.annotation.GetMapping;
12 | import org.springframework.web.bind.annotation.RequestMapping;
13 | import org.springframework.web.bind.annotation.RequestMethod;
14 | import org.springframework.web.bind.annotation.RequestParam;
15 | import reactor.core.publisher.Flux;
16 | import reactor.core.publisher.Mono;
17 | import reactor.core.scheduler.Schedulers;
18 |
19 | import javax.annotation.PostConstruct;
20 | import java.security.Principal;
21 |
22 | @Controller
23 | public class WebControl {
24 |
25 | @Value("${app.name}")
26 | String appName;
27 |
28 | @Autowired
29 | CourseRepository courseRepository;
30 | @Autowired
31 | UserRepository userRepository;
32 |
33 | @PostConstruct
34 | public void setup() {
35 | courseRepository.count().blockOptional().filter(count -> count == 0).ifPresent(it ->
36 | Flux.just(
37 | new Course("Beginning Java"),
38 | new Course("Advanced Java"),
39 | new Course("Reactive Streams in Java"))
40 | .doOnNext(c -> System.out.println(c.toString()))
41 | .flatMap(courseRepository::save).subscribeOn(Schedulers.single())
42 | .subscribe() // need to actually execute save*/
43 | );
44 | // just adding dummy user for demo purposes:
45 | userRepository.count().blockOptional().filter(count -> count == 0).ifPresent(it ->
46 | Flux.just(new User("user", "password"))
47 | .flatMap(userRepository::save).subscribeOn(Schedulers.single())
48 | .subscribe()
49 | );
50 | }
51 |
52 | @GetMapping("/")
53 | public Mono home(Model model, Principal principal) {
54 | model.addAttribute("name", principal == null ? "" : principal.getName());
55 | model.addAttribute("applicationName", appName);
56 | return Mono.just("home");
57 | }
58 |
59 | @GetMapping("/login-error")
60 | public String loginError(Model model) {
61 | model.addAttribute("applicationName", appName);
62 | model.addAttribute("error", "Login failed.");
63 | return "login";
64 | }
65 |
66 | @GetMapping("/user/account")
67 | public String userAccount(Model model, Principal principal) {
68 | model.addAttribute("applicationName", appName);
69 | model.addAttribute("username", principal.getName());
70 | return "account";
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/humblecode/src/test/java/com/humblecode/humblecode/HumblecodeApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.humblecode.humblecode;
2 |
3 | import org.junit.Test;
4 | import org.junit.runner.RunWith;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.boot.test.context.SpringBootTest;
7 | import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
8 | import org.springframework.boot.test.web.client.TestRestTemplate;
9 | import org.springframework.http.*;
10 | import org.springframework.test.context.junit4.SpringRunner;
11 |
12 | import java.util.Arrays;
13 |
14 | import static org.assertj.core.api.Assertions.assertThat;
15 |
16 | @RunWith(SpringRunner.class)
17 | @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
18 | public class HumblecodeApplicationTests {
19 |
20 | @Autowired
21 | private TestRestTemplate testRestTemplate;
22 |
23 | @Test
24 | public void testFreeMarkerTemplate() {
25 | ResponseEntity entity = this.testRestTemplate.getForEntity("/",
26 | String.class);
27 | assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
28 | assertThat(entity.getBody()).contains("Welcome to");
29 | }
30 |
31 | @Test
32 | public void testFreeMarkerErrorTemplate() {
33 | HttpHeaders headers = new HttpHeaders();
34 | headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
35 | HttpEntity requestEntity = new HttpEntity<>(headers);
36 |
37 | ResponseEntity responseEntity = this.testRestTemplate
38 | .exchange("/css/foobar", HttpMethod.GET, requestEntity, String.class);
39 |
40 | assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND);
41 | assertThat(responseEntity.getBody()).contains("404 Not Found");
42 | }
43 |
44 | @Test
45 | public void testCSSCanBeGotten() {
46 | HttpHeaders headers = new HttpHeaders();
47 | headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
48 | HttpEntity requestEntity = new HttpEntity<>(headers);
49 |
50 | ResponseEntity responseEntity = this.testRestTemplate
51 | .exchange("/css/base.css", HttpMethod.GET, requestEntity, String.class);
52 |
53 | assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
54 | }
55 |
56 | @Test
57 | public void testLoginPageCanBeGotten() {
58 | HttpHeaders headers = new HttpHeaders();
59 | headers.setAccept(Arrays.asList(MediaType.TEXT_HTML));
60 | HttpEntity requestEntity = new HttpEntity<>(headers);
61 |
62 | ResponseEntity responseEntity = this.testRestTemplate
63 | .exchange("/user/account", HttpMethod.GET, requestEntity, String.class);
64 |
65 | assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
66 | }
67 |
68 | @Test
69 | public void testGetCourses() {
70 | HttpHeaders headers = new HttpHeaders();
71 | headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
72 | HttpEntity requestEntity = new HttpEntity<>(headers);
73 |
74 | ResponseEntity response = this.testRestTemplate
75 | .exchange("/api/courses", HttpMethod.GET, requestEntity, String.class);
76 |
77 | assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
78 | assertThat(response.getBody()).contains("\"name\":\"Beginning Java\",\"price\":2000");
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/humblecode/src/main/resources/static/js/main.js:
--------------------------------------------------------------------------------
1 |
2 | var errorHandler = (err) => { alert("Sorry, there was a problem. " + err); console.log(err) }
3 |
4 | var HC = {
5 | loadCourses: function() {
6 | jQuery.ajax({method: 'get', url: '/api/courses'}).done(
7 | function(data) {
8 | var list = data;
9 | var ul = jQuery('');
10 | list.forEach((crs) => {
11 | ul.append(''
12 | + crs.name + ': ' + HC.toDollars(crs.price) + '')
13 | });
14 | jQuery('#content').html(ul);
15 | }
16 | ).fail( errorHandler );
17 | },
18 | toDollars: function(price) {
19 | return '$' + (price/ 100);
20 | },
21 | course: null,
22 | currentSegment: null,
23 | nextSegment: null,
24 | loadCourse: function(id) {
25 | jQuery.ajax({method: 'get', url: '/api/course/'+id}).done(
26 | function(course) {
27 | console.log("data=" + course);
28 | HC.course = course;
29 | var segments = course.segments;
30 | var ul = jQuery('');
31 | segments.forEach((segment) => {
32 | ul.append(''
33 | + segment.name + '')
34 | });
35 | jQuery('h1').text(course.name);
36 | jQuery('#content').html(ul);
37 | }
38 | ).fail( errorHandler );
39 | },
40 | loadSegment: function(id) {
41 | if (!HC.course) {
42 | console.log("ERROR: course not available");
43 | return;
44 | } else {
45 | var ids = HC.course.segments.map(it => it.id);
46 | var index = ids.indexOf(id);
47 | HC.currentSegment = HC.course.segments[index];
48 | if (HC.course.segments.length > index) HC.nextSegment = HC.course.segments[index + 1];
49 | else HC.nextSegment = null;
50 | //TODO: improve styling of text
51 | jQuery('h1').text(HC.currentSegment.name);
52 | jQuery('#content').text(HC.currentSegment.body);
53 | }
54 | },
55 | postCourse: function() {
56 | var name = jQuery('#name').val();
57 | var price = jQuery('#price').val();
58 | jQuery.ajax({method: 'post', url: '/api/course/', data: {name: name, price: price}}).done(
59 | function(course) {
60 | console.log("data=" + course);
61 | HC.course = course;
62 | var segments = course.segments;
63 | var ul = jQuery('');
64 | segments.forEach((segment) => {
65 | ul.append(''
66 | + segment.name + '')
67 | });
68 | jQuery('h1').text(course.name);
69 | jQuery('#content').html(ul);
70 | }
71 | ).fail( errorHandler );
72 | }
73 | }
74 |
75 |
--------------------------------------------------------------------------------
/RxAndroidTest/app/src/main/res/layout/activity_login.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 |
22 |
23 |
27 |
28 |
33 |
34 |
37 |
38 |
46 |
47 |
48 |
49 |
52 |
53 |
64 |
65 |
66 |
67 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/src/test/java/com/github/adamldavis/RxJavaDemoTest.java:
--------------------------------------------------------------------------------
1 | package com.github.adamldavis;
2 |
3 | import io.reactivex.BackpressureStrategy;
4 | import io.reactivex.Flowable;
5 | import io.reactivex.Observable;
6 | import io.reactivex.observers.TestObserver;
7 | import io.reactivex.schedulers.TestScheduler;
8 | import io.reactivex.subscribers.TestSubscriber;
9 | import org.junit.Test;
10 |
11 | import java.io.File;
12 | import java.util.List;
13 | import java.util.concurrent.TimeUnit;
14 | import java.util.stream.Collectors;
15 |
16 | import static com.github.adamldavis.DemoData.squares;
17 | import static org.junit.Assert.assertArrayEquals;
18 | import static org.junit.Assert.assertEquals;
19 |
20 | public class RxJavaDemoTest {
21 |
22 | RxJavaDemo demo = new RxJavaDemo();
23 |
24 | @Test
25 | public void testDoSquares() {
26 | assertArrayEquals(squares.toArray(), demo.doSquares().toArray());
27 | }
28 |
29 | @Test
30 | public void testDoParallelSquares() {
31 | List result = demo.doParallelSquares()
32 | .stream().sorted().collect(Collectors.toList());
33 |
34 | assertArrayEquals(squares.toArray(), result.toArray());
35 | }
36 |
37 | @Test
38 | public void testrunComputation() throws Exception {
39 | demo.runComputation();
40 | Thread.sleep(1100);
41 | }
42 |
43 | @Test
44 | public void testReadFile() {
45 | demo.readFile(new File("README.md"));
46 | }
47 |
48 | @Test
49 | public void testReadFile2() {
50 | demo.readFile2(new File("README.md"));
51 | }
52 |
53 | @Test
54 | public void testBackpressure() throws InterruptedException {
55 | assertEquals(10, demo.countUsingBackpressure(1050));
56 | }
57 |
58 | @Test
59 | public void testSubscriber() {
60 | TestSubscriber ts =
61 | Flowable.range(1, 5).test();
62 |
63 | assertEquals(5, ts.valueCount());
64 | }
65 |
66 | @Test
67 | public void testSubscriberWithException() {
68 | Flowable flowable = Flowable.create(source -> {
69 | source.onNext(1);
70 | source.onError(new RuntimeException());
71 | }, BackpressureStrategy.LATEST);
72 |
73 | TestSubscriber ts = flowable.test();
74 |
75 | ts.assertSubscribed();
76 | ts.assertError(RuntimeException.class);
77 | }
78 |
79 | @Test
80 | public void testObserver() {
81 | TestObserver ts =
82 | Observable.range(1, 5).test();
83 |
84 | assertEquals(5, ts.valueCount());
85 | }
86 |
87 | @Test
88 | public void testScheduler() {
89 | TestScheduler scheduler = new TestScheduler(); //1
90 | Observable tick = Observable
91 | .interval(1, TimeUnit.SECONDS, scheduler); //2
92 | Observable observable =
93 | Observable.just("foo", "bar", "biz", "baz") //3
94 | .zipWith(tick, (string, index) -> index + "-" + string);//4
95 | TestObserver testObserver = observable
96 | .subscribeOn(scheduler).test();//5
97 |
98 | scheduler.advanceTimeBy(2300, TimeUnit.MILLISECONDS);//6
99 |
100 | testObserver.assertNoErrors(); //7
101 | testObserver.assertValues("0-foo", "1-bar");
102 | testObserver.assertNotComplete();
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/src/test/java/com/github/adamldavis/ReactorDemo10Test.java:
--------------------------------------------------------------------------------
1 | package com.github.adamldavis;
2 |
3 | import org.junit.Test;
4 | import reactor.core.publisher.Flux;
5 | import reactor.core.publisher.Mono;
6 | import reactor.test.StepVerifier;
7 | import reactor.test.publisher.TestPublisher;
8 | import reactor.util.context.Context;
9 |
10 | import java.time.Duration;
11 | import java.util.ArrayList;
12 | import java.util.List;
13 | import java.util.stream.Collectors;
14 |
15 | import static com.github.adamldavis.DemoData.squares;
16 | import static org.junit.Assert.assertArrayEquals;
17 | import static org.junit.Assert.assertEquals;
18 |
19 | /** Identical to ReactorDemoTest but using Java 10+ var. */
20 | public class ReactorDemo10Test {
21 |
22 |
23 | ReactorDemo demo = new ReactorDemo();
24 |
25 | @Test
26 | public void testDoSquares() {
27 | assertArrayEquals(squares.toArray(), demo.doSquares().toArray());
28 | }
29 |
30 | @Test
31 | public void testDoParallelSquares() {
32 | var result = demo.doParallelSquares()
33 | .stream().sorted().collect(Collectors.toList());
34 |
35 | assertArrayEquals(squares.toArray(), result.toArray());
36 | }
37 |
38 | @Test
39 | public void testStepVerifier_Mono_error() {
40 | var monoError = Mono.error(new RuntimeException("error"));
41 |
42 | StepVerifier.create(monoError)
43 | .expectErrorMessage("error")
44 | .verify();
45 | }
46 |
47 | @Test
48 | public void testStepVerifier_Mono_foo() {
49 | var foo = Mono.just("foo");
50 | StepVerifier.create(foo)
51 | .expectNext("foo")
52 | .verifyComplete();
53 | }
54 |
55 | @Test
56 | public void testStepVerifier_Flux() {
57 | var flux = Flux.just(1, 4, 9);
58 |
59 | StepVerifier.create(flux)
60 | .expectNext(1)
61 | .expectNext(4)
62 | .expectNext(9)
63 | .expectComplete()
64 | .verify(Duration.ofSeconds(10));
65 | }
66 |
67 | @Test
68 | public void testStepVerifier_Context_Wrong() {
69 | var flux = Flux.just(1).subscriberContext(Context.of("pid", 123));
70 |
71 | var stringFlux = flux.flatMap(i ->
72 | Mono.subscriberContext().map(ctx -> i + " pid: " + ctx.getOrDefault("pid", 0)));
73 |
74 | StepVerifier.create(stringFlux)
75 | .expectNext("1 pid: 0")
76 | .verifyComplete();
77 | }
78 |
79 | @Test
80 | public void testStepVerifier_Context_Right() {
81 | var flux = Flux.just(1);
82 |
83 | var stringFlux = flux.flatMap(i ->
84 | Mono.subscriberContext().map(ctx -> i + " pid: " + ctx.getOrDefault("pid", 0)));
85 |
86 | StepVerifier.create(stringFlux.subscriberContext(Context.of("pid", 123)))
87 | .expectNext("1 pid: 123")
88 | .verifyComplete();
89 | }
90 |
91 | @Test
92 | public void test_TestPublisher() {
93 | var publisher = TestPublisher.create(); //1
94 | var stringFlux = publisher.flux(); //2
95 | var list = new ArrayList(); //3
96 |
97 | stringFlux.subscribe(next -> list.add(next), ex -> ex.printStackTrace()); //4
98 | publisher.emit("foo", "bar"); //5
99 |
100 | assertEquals(2, list.size()); //6
101 | assertEquals("foo", list.get(0));
102 | assertEquals("bar", list.get(1));
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 | 4.0.0
7 |
8 | com.packtpub.reactive
9 | reactive-streams-in-java
10 | 1.0.0-SNAPSHOT
11 |
12 |
13 | 11
14 | 11
15 |
16 |
17 |
18 |
19 | org.reactivestreams
20 | reactive-streams
21 | 1.0.0
22 |
23 |
24 |
25 | io.reactivex.rxjava2
26 | rxjava
27 | 2.1.9
28 |
29 |
30 |
31 | io.projectreactor
32 | reactor-core
33 | 3.1.7.RELEASE
34 |
35 |
36 |
37 | io.projectreactor
38 | reactor-test
39 | 3.1.7.RELEASE
40 | test
41 |
42 |
43 |
44 | com.typesafe.akka
45 | akka-stream_2.12
46 | 2.5.12
47 |
48 |
49 | com.typesafe.akka
50 | akka-stream-testkit_2.12
51 | 2.5.12
52 | test
53 |
54 |
55 |
56 | org.springframework.boot
57 | spring-boot-starter-web
58 | 2.0.2.RELEASE
59 |
60 |
61 |
62 | org.springframework
63 | spring-test
64 | 4.3.2.RELEASE
65 |
66 |
67 |
68 | junit
69 | junit
70 | 4.12
71 | test
72 |
73 |
74 |
75 | org.assertj
76 | assertj-core
77 | 3.5.1
78 | test
79 |
80 |
81 |
82 | org.mockito
83 | mockito-core
84 | 2.0.1-beta
85 | test
86 |
87 |
88 |
89 |
90 |
91 |
92 | maven-compiler-plugin
93 | 3.8.1
94 |
95 | 11
96 |
97 |
98 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/reactive-streams-in-java/src/test/java/com/github/adamldavis/AkkaStreamsDemoTest.java:
--------------------------------------------------------------------------------
1 | package com.github.adamldavis;
2 |
3 | import akka.NotUsed;
4 | import akka.actor.ActorSystem;
5 | import akka.japi.Pair;
6 | import akka.stream.ActorMaterializer;
7 | import akka.stream.javadsl.Keep;
8 | import akka.stream.javadsl.Sink;
9 | import akka.stream.javadsl.Source;
10 | import akka.stream.testkit.TestPublisher;
11 | import akka.stream.testkit.TestSubscriber;
12 | import akka.stream.testkit.javadsl.TestSink;
13 | import akka.stream.testkit.javadsl.TestSource;
14 | import org.junit.After;
15 | import org.junit.Before;
16 | import org.junit.Test;
17 |
18 | import java.util.Arrays;
19 | import java.util.List;
20 | import java.util.concurrent.CompletionStage;
21 | import java.util.concurrent.ExecutionException;
22 | import java.util.concurrent.TimeUnit;
23 | import java.util.concurrent.TimeoutException;
24 | import java.util.stream.Collectors;
25 |
26 | import static com.github.adamldavis.DemoData.squares;
27 | import static org.junit.Assert.*;
28 |
29 | public class AkkaStreamsDemoTest {
30 |
31 | AkkaStreamsDemo demo = new AkkaStreamsDemo();
32 |
33 | @Test
34 | public void testDoSquares() {
35 | assertArrayEquals(squares.toArray(), demo.doSquares().toArray());
36 | }
37 |
38 | @Test
39 | public void testDoParallelSquares() {
40 | List result = demo.doParallelSquares()
41 | .stream().sorted().collect(Collectors.toList());
42 |
43 | assertArrayEquals(squares.toArray(), result.toArray());
44 | }
45 |
46 | Channel channel = new Channel();
47 |
48 | @Test
49 | public void testPrintErrors() {
50 | // given
51 | demo.setChannel(channel);
52 | // when
53 | demo.printErrors();
54 |
55 | int count = 201;
56 |
57 | for (int i = 0; i < count; i++) {
58 | channel.publish("Error: " + i);
59 | }
60 | try { Thread.sleep(2000); } catch (Exception e) { throw new RuntimeException(e); }
61 | // then
62 | assertFalse(demo.messageList.isEmpty());
63 | assertEquals(count, demo.messageList.size());
64 | assertNotNull(demo.publisher);
65 | }
66 |
67 |
68 | ActorSystem system;
69 | ActorMaterializer materializer;
70 | @Before
71 | public void setup() {
72 | system = ActorSystem.create();
73 | materializer = ActorMaterializer.create(system);
74 | }
75 | @After
76 | public void tearDown() {
77 | akka.testkit.javadsl.TestKit.shutdownActorSystem(system);
78 | }
79 |
80 | @Test
81 | public void test_a_source() {
82 | Sink