├── .editorconfig ├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ └── 01-compatible-certification-request.md ├── .gitignore ├── CONTRIBUTING.adoc ├── LICENSE ├── NOTICE ├── README.adoc ├── api ├── .gitignore ├── bnd.bnd ├── package-lock.json ├── package.json ├── pom.xml └── src │ ├── docs │ └── js │ │ ├── SourceCodePro-Regular.ttf │ │ ├── generate-marble-diagrams.js │ │ ├── index.html │ │ ├── marble-diagram-hashes.json │ │ ├── mp-rs-ops-marbles.js │ │ ├── puppeteer.html │ │ ├── svg-marbles.js │ │ └── verify-marble-diagrams.js │ └── main │ ├── java │ └── org │ │ └── eclipse │ │ └── microprofile │ │ └── reactive │ │ └── streams │ │ └── operators │ │ ├── CompletionRunner.java │ │ ├── CompletionSubscriber.java │ │ ├── ConnectingOperators.java │ │ ├── ConsumingOperators.java │ │ ├── ErrorHandlingOperators.java │ │ ├── FilteringOperators.java │ │ ├── PeekingOperators.java │ │ ├── ProcessorBuilder.java │ │ ├── ProducesResult.java │ │ ├── PublisherBuilder.java │ │ ├── ReactiveStreams.java │ │ ├── ReactiveStreamsFactory.java │ │ ├── SubscriberBuilder.java │ │ ├── TransformingOperators.java │ │ ├── doc-files │ │ ├── collect.png │ │ ├── concat.png │ │ ├── coupled.png │ │ ├── distinct.png │ │ ├── dropWhile.png │ │ ├── empty.png │ │ ├── example.png │ │ ├── failed.png │ │ ├── filter.png │ │ ├── findFirst.png │ │ ├── flatMap.png │ │ ├── flatMapCompletionStage.png │ │ ├── flatMapIterable.png │ │ ├── flatMapRsPublisher.png │ │ ├── forEach.png │ │ ├── fromCompletionStage.png │ │ ├── fromCompletionStageNullable.png │ │ ├── fromIterable.png │ │ ├── generate.png │ │ ├── identity.png │ │ ├── ignore.png │ │ ├── iterate.png │ │ ├── limit.png │ │ ├── map.png │ │ ├── of-many.png │ │ ├── of-single.png │ │ ├── ofNullable.png │ │ ├── onComplete.png │ │ ├── onError.png │ │ ├── onErrorResume.png │ │ ├── onErrorResumeWith.png │ │ ├── onErrorResumeWithRsPublisher.png │ │ ├── onTerminate.png │ │ ├── peek.png │ │ ├── reduce-identity.png │ │ ├── reduce.png │ │ ├── skip.png │ │ ├── takeWhile.png │ │ └── toList.png │ │ ├── package-info.java │ │ └── spi │ │ ├── Graph.java │ │ ├── ReactiveStreamsEngine.java │ │ ├── ReactiveStreamsFactoryResolver.java │ │ ├── Stage.java │ │ ├── SubscriberWithCompletionStage.java │ │ ├── ToGraphable.java │ │ ├── UnsupportedStageException.java │ │ └── package-info.java │ └── resources │ └── META-INF │ ├── LICENSE │ └── NOTICE ├── approach.asciidoc ├── core ├── bnd.bnd ├── pom.xml └── src │ └── main │ ├── java │ └── org │ │ └── eclipse │ │ └── microprofile │ │ └── reactive │ │ └── streams │ │ └── operators │ │ └── core │ │ ├── CompletionRunnerImpl.java │ │ ├── GraphImpl.java │ │ ├── InternalStages.java │ │ ├── ProcessorBuilderImpl.java │ │ ├── PublisherBuilderImpl.java │ │ ├── ReactiveStreamsEngineResolver.java │ │ ├── ReactiveStreamsFactoryImpl.java │ │ ├── ReactiveStreamsGraphBuilder.java │ │ ├── Reductions.java │ │ ├── Stages.java │ │ ├── SubscriberBuilderImpl.java │ │ └── package-info.java │ └── resources │ └── META-INF │ ├── LICENSE │ ├── NOTICE │ └── services │ └── org.eclipse.microprofile.reactive.streams.operators.ReactiveStreamsFactory ├── pom.xml ├── site.yaml ├── spec ├── pom.xml └── src │ └── main │ ├── asciidoc │ ├── architecture.asciidoc │ ├── cdi.asciidoc │ ├── design.asciidoc │ ├── examples.asciidoc │ ├── images │ │ ├── change-shape.svg │ │ ├── closed-graph-builder.svg │ │ ├── picture-sources.odg │ │ ├── processor-builder.svg │ │ ├── processor-stage.svg │ │ ├── publisher-builder.svg │ │ ├── publisher-stage.svg │ │ ├── subscriber-builder.svg │ │ └── subscriber-stage.svg │ ├── implementation.asciidoc │ ├── java-streams.asciidoc │ ├── license-alv2.asciidoc │ ├── license-efsl.adoc │ ├── microprofile-reactive-streams-operators-spec.asciidoc │ ├── release_notes.asciidoc │ └── spi.asciidoc │ └── resources │ └── META-INF │ ├── LICENSE │ └── NOTICE └── tck ├── README.adoc ├── pom.xml └── src ├── main ├── java │ └── org │ │ └── eclipse │ │ └── microprofile │ │ └── reactive │ │ └── streams │ │ └── operators │ │ └── tck │ │ ├── DefaultReactiveStreamsFactory.java │ │ ├── ReactiveStreamsTck.java │ │ ├── api │ │ ├── AbstractReactiveStreamsApiVerification.java │ │ ├── CompletionRunnerVerification.java │ │ ├── CompletionSubscriberVerification.java │ │ ├── Mocks.java │ │ ├── ProcessorBuilderVerification.java │ │ ├── PublisherBuilderVerification.java │ │ ├── ReactiveStreamsApiVerification.java │ │ ├── ReactiveStreamsVerification.java │ │ └── SubscriberBuilderVerification.java │ │ ├── arquillian │ │ ├── ReactiveStreamsArquillianTck.java │ │ └── ReactiveStreamsCdiTck.java │ │ └── spi │ │ ├── AbstractStageVerification.java │ │ ├── CancelStageVerification.java │ │ ├── CollectStageVerification.java │ │ ├── ConcatStageVerification.java │ │ ├── CoupledStageVerification.java │ │ ├── DistinctStageVerification.java │ │ ├── DropWhileStageVerification.java │ │ ├── EmptyProcessorVerification.java │ │ ├── FilterStageVerification.java │ │ ├── FindFirstStageVerification.java │ │ ├── FlatMapCompletionStageVerification.java │ │ ├── FlatMapIterableStageVerification.java │ │ ├── FlatMapStageVerification.java │ │ ├── FromCompletionStageNullableVerification.java │ │ ├── FromCompletionStageVerification.java │ │ ├── LimitStageVerification.java │ │ ├── MapStageVerification.java │ │ ├── OfStageVerification.java │ │ ├── OnErrorResumeStageVerification.java │ │ ├── OnStagesVerification.java │ │ ├── PeekStageVerification.java │ │ ├── QuietRuntimeException.java │ │ ├── ReactiveStreamsSpiVerification.java │ │ ├── ScheduledPublisher.java │ │ ├── SkipStageVerification.java │ │ ├── SubscriberStageVerification.java │ │ └── TakeWhileStageVerification.java └── resources │ └── META-INF │ ├── LICENSE │ ├── NOTICE │ └── tck └── test ├── java └── org │ └── eclipse │ └── microprofile │ └── reactive │ └── streams │ └── operators │ └── tck │ └── TckTest.java └── resources ├── META-INF ├── LICENSE └── NOTICE └── README.adoc /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # http://editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | indent_style = space 9 | indent_size = 4 10 | end_of_line = lf 11 | charset = utf-8 12 | trim_trailing_whitespace = true 13 | insert_final_newline = true 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | 18 | [*.adoc] 19 | trim_trailing_whitespace = false 20 | 21 | [*.js] 22 | indent_size = 2 23 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Handle line endings automatically for files detected as text 2 | # and leave all files detected as binary untouched. 3 | * text=auto 4 | 5 | # 6 | # The above will handle all files NOT found below 7 | # 8 | # These files are text and should be normalized (Convert crlf => lf) 9 | *.adoc text 10 | *.conf text 11 | *.config text 12 | *.css text 13 | *.df text 14 | *.extension text 15 | *.groovy text 16 | *.htm text 17 | *.html text 18 | *.java text 19 | *.js text 20 | *.json text 21 | *.jsp text 22 | *.jspf text 23 | *.md text 24 | *.properties text 25 | *.sbt text 26 | *.scala text 27 | *.sh text 28 | *.sql text 29 | *.svg text 30 | *.template text 31 | *.tld text 32 | *.txt text 33 | *.vm text 34 | *.wadl text 35 | *.wsdl text 36 | *.xhtml text 37 | *.xml text 38 | *.xsd text 39 | *.yml text 40 | 41 | cipher text 42 | jaas text 43 | LICENSE text 44 | NOTICE text 45 | 46 | # These files are binary and should be left untouched 47 | # (binary is a macro for -text -diff) 48 | *.class binary 49 | *.dll binary 50 | *.ear binary 51 | *.gif binary 52 | *.ico binary 53 | *.jar binary 54 | *.jpg binary 55 | *.jpeg binary 56 | *.png binary 57 | *.ser binary 58 | *.so binary 59 | *.war binary 60 | *.zip binary 61 | *.exe binary 62 | *.gz binary 63 | 64 | #Windows 65 | *.bat text eol=crlf 66 | *.cmd text eol=crlf 67 | 68 | #Unix/Linux 69 | *.sh text eol=lf -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/01-compatible-certification-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Compatible Certification Request 3 | about: Start a request for a compatible certification 4 | title: 'MicroProfile Reactive Streams Operator [Version] Compatible Certification Request' 5 | labels: 'Certification :trophy:' 6 | assignees: '' 7 | 8 | --- 9 | 10 | - [ ] Organization Name ("Organization") and, if applicable, URL:
11 | // Add here 12 | - [ ] Product Name, Version and download URL (if applicable):
13 | // Add here 14 | - [ ] Specification Name, Version and download URL:
15 | // Add here 16 | - [ ] (Optional) TCK Version, digital SHA-256 fingerprint and download URL:
17 | // Add here 18 | - [ ] Public URL of TCK Results Summary:
19 | // Add here 20 | - [ ] Any Additional Specification Certification Requirements:
21 | // Add here 22 | - [ ] Java runtime used to run the implementation:
23 | // Add here 24 | - [ ] Summary of the information for the certification environment, operating system, cloud, ...:
25 | // Add here 26 | - [ ] By checking this box I acknowledge that the Organization I represent accepts the terms of the [EFTL](https://www.eclipse.org/legal/tck.php). 27 | - [ ] By checking this box I attest that all TCK requirements have been met, including any compatibility rules. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | .settings/ 3 | .checkstyle 4 | target/ 5 | tck/bin/ 6 | .project 7 | build/ 8 | .classpath 9 | .factorypath 10 | test-output 11 | /*.log 12 | .idea 13 | *.iml 14 | *.iwl 15 | *.ipr 16 | # Ignore a release.conf for perform_release/* script usage 17 | release.conf 18 | /bin/ 19 | .~lock.*.odg# 20 | **.DS_Store 21 | .vscode 22 | 23 | -------------------------------------------------------------------------------- /CONTRIBUTING.adoc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | // 4 | // See the NOTICE file(s) distributed with this work for additional 5 | // information regarding copyright ownership. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // You may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | 20 | == How to contribute 21 | 22 | Do you want to contribute to this project? Here is what you can do: 23 | 24 | * Fork the repository, make changes, then do a pull request. 25 | ** Remember to https://help.github.com/articles/signing-commits/[sign your commits] 26 | ** Make sure you have signed the https://www.eclipse.org/legal/ECA.php[Eclipse Contributor Agreement] 27 | * https://github.com/eclipse/microprofile-reactive-streams-operators/issues[Create or fix an issue]. 28 | * https://gitter.im/eclipse/microprofile-reactive[Join us on Gitter to discuss this project]. 29 | * Join our https://calendar.google.com/calendar/embed?src=gbnbc373ga40n0tvbl88nkc3r4%40group.calendar.google.com[weekly meeting] on Tuesday at https://www.timeanddate.com/time/map/[10h00 GMT]. 30 | ** https://docs.google.com/document/d/1UKBBNFn-CeMih3lNUGvpShcL2aTpnvmJs9LQ8qT9OI0/edit?usp=sharing[Minutes and Agenda]. 31 | ** https://zoom.us/j/509807821[Meeting room]. 32 | * Join the discussions on the https://groups.google.com/forum/#!forum/microprofile[MicroProfile Google Group] 33 | * https://microprofile.io/blog/[Contribute a blog post]. 34 | 35 | Also see the https://wiki.eclipse.org/MicroProfile/ContributingGuidelines[MicroProfile Contributing Guidelines] on the https://wiki.eclipse.org/MicroProfile[Eclipse MicroProfile wiki page] 36 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | ========================================================================= 2 | == NOTICE file corresponding to section 4(d) of the Apache License, == 3 | == Version 3.0, MicroProfile Reactive Streams Operators == 4 | ========================================================================= 5 | 6 | This product includes software developed at 7 | The Apache Software Foundation (http://www.apache.org/). 8 | 9 | 10 | SPDXVersion: SPDX-2.1 11 | PackageName: MicroProfile 12 | PackageHomePage: http://www.eclipse.org/microprofile 13 | PackageLicenseDeclared: Apache-2.0 14 | 15 | PackageCopyrightText: 16 | James Roper james@lightbend.com 17 | Clement Escoffier clement.escoffier@redhat.com 18 | Gordon Hutchison gordon_hutchison@uk.ibm.com 19 | -------------------------------------------------------------------------------- /api/.gitignore: -------------------------------------------------------------------------------- 1 | node/ 2 | node_modules/ 3 | *.log 4 | -------------------------------------------------------------------------------- /api/bnd.bnd: -------------------------------------------------------------------------------- 1 | -exportcontents: \ 2 | org.eclipse.microprofile.* 3 | 4 | Import-Package: \ 5 | org.reactivestreams;version="[1.0.0,2)", \ 6 | * 7 | 8 | Bundle-SymbolicName: org.eclipse.microprofile.reactive.streams.operators 9 | Bundle-Name: Eclipse MicroProfile Reactive Streams Operators API Bundle 10 | Bundle-License: Apache License, Version 2.0 11 | -------------------------------------------------------------------------------- /api/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svg-marbles", 3 | "version": "1.0.0", 4 | "description": "Marble diagram generator", 5 | "repository": { 6 | "type": "git", 7 | "url": "https://github.com/eclipse/microprofile-reactive-streams-operators.git" 8 | }, 9 | "license": "Apache-2.0", 10 | "dependencies": { 11 | "svg.js": "2.6.5" 12 | }, 13 | "devDependencies": { 14 | "puppeteer": "1.13.0", 15 | "shelljs": "0.8.5" 16 | }, 17 | "scripts": { 18 | "generate-marble-diagrams": "node src/docs/js/generate-marble-diagrams.js", 19 | "verify-marble-diagrams": "node src/docs/js/verify-marble-diagrams.js" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /api/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 4.0.0 22 | 23 | 24 | 25 | org.eclipse.microprofile.reactive-streams-operators 26 | microprofile-reactive-streams-operators-parent 27 | 3.1-SNAPSHOT 28 | 29 | 30 | 31 | 1.11.0 32 | false 33 | 34 | 35 | microprofile-reactive-streams-operators-api 36 | Eclipse MicroProfile Reactive Streams Operators API 37 | Eclipse MicroProfile Reactive Streams Operators :: API 38 | 39 | 40 | 41 | org.reactivestreams 42 | reactive-streams 43 | 44 | 45 | org.osgi 46 | org.osgi.annotation.versioning 47 | 48 | 49 | 50 | 51 | 52 | 53 | com.github.eirslett 54 | frontend-maven-plugin 55 | ${frontend-maven-plugin.version} 56 | 57 | v8.11.3 58 | 59 | 60 | 61 | install-node-and-run-npm-install 62 | 63 | install-node-and-npm 64 | npm 65 | 66 | 67 | install 68 | 69 | 70 | 71 | verify-marble-diagrams 72 | 73 | npm 74 | 75 | verify 76 | 77 | run-script verify-marble-diagrams 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | marble-diagrams 88 | 89 | 90 | 91 | com.github.eirslett 92 | frontend-maven-plugin 93 | ${frontend-maven-plugin.version} 94 | 95 | 96 | generate-marble-diagrams 97 | 98 | npm 99 | 100 | prepare-package 101 | 102 | run-script generate-marble-diagrams 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /api/src/docs/js/SourceCodePro-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/docs/js/SourceCodePro-Regular.ttf -------------------------------------------------------------------------------- /api/src/docs/js/generate-marble-diagrams.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | /** 21 | * Run this script in Puppeteer (ie, headless Chrome) to actually render each diagram. 22 | */ 23 | const path = require("path"); 24 | const projectBaseDir = path.normalize(__dirname + "/../../.."); 25 | const htmlPage = "file://" + projectBaseDir + "/src/docs/js/puppeteer.html"; 26 | const outputDir = projectBaseDir + "/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files"; 27 | 28 | const shell = require("shelljs"); 29 | shell.mkdir("-p", outputDir); 30 | 31 | const crypto = require("crypto"); 32 | const fs = require("fs"); 33 | const puppeteer = require("puppeteer"); 34 | 35 | (async () => { 36 | const browser = await puppeteer.launch(); 37 | const page = await browser.newPage(); 38 | // Important to wait until networkidle0, otherwise fonts won't be loaded. 39 | await page.goto(htmlPage, {waitUntil: "networkidle0"}); 40 | 41 | const keys = await page.evaluate(() => { 42 | window.marbles = createMarbles(); 43 | return Object.keys(marbles.graphs); 44 | }); 45 | 46 | const renderDiagrams = async (keys) => { 47 | if (keys.length > 0) { 48 | const key = keys[0]; 49 | console.log("Rendering marble diagram for " + key); 50 | const dimensions = await page.evaluate((key) => { 51 | const diagram = window.document.getElementById("diagram"); 52 | diagram.innerHTML = ""; 53 | return window.marbles.drawSingle(diagram, window.marbles.graphs[key]); 54 | }, key); 55 | await page.screenshot({path: outputDir + "/" + key + ".png", clip: { 56 | x: 0, 57 | y: 0, 58 | width: dimensions.width, 59 | height: dimensions.height 60 | }}); 61 | keys.shift(); 62 | await renderDiagrams(keys); 63 | } 64 | }; 65 | 66 | await renderDiagrams(keys); 67 | await browser.close(); 68 | 69 | // Now update MD5 hashes of everything 70 | console.log("Generating marble-diagram-hashes.json"); 71 | const files = {}; 72 | function md5File(file) { 73 | const md5sum = crypto.createHash('md5'); 74 | const data = fs.readFileSync(file); 75 | md5sum.update(data); 76 | files[path.relative(projectBaseDir, file)] = md5sum.digest("hex"); 77 | } 78 | 79 | shell.ls(__dirname + "/*.js", __dirname + "/*.html", __dirname + "/*.ttf").forEach(md5File); 80 | shell.ls(outputDir + "/*.png").forEach(md5File); 81 | 82 | fs.writeFileSync(__dirname + "/marble-diagram-hashes.json", JSON.stringify({ 83 | description1: "This file contains hashes of all the input and output files from the marble diagram generation ", 84 | description2: "process. Unfortunately due to limitations in the MicroProfile CI build and release environment, we can't ", 85 | description3: "generate diagrams as part of the build, so instead we have to check them into the build. This hash file is ", 86 | description4: "used to ensure the output files are up to date with the input files, and is verifyied by the Maven verify ", 87 | description5: "phase, so if they aren't, the build will fail.", 88 | files: files 89 | }, null, 2)); 90 | 91 | })().catch(error => { 92 | console.log(error); 93 | process.exit(1); 94 | }); 95 | -------------------------------------------------------------------------------- /api/src/docs/js/index.html: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 43 | 44 | 45 |
46 |
This div exists so that the browser will load the Source Code Pro font before we render the marbles, 47 | ensuring it gets the leading and sizes right.
48 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /api/src/docs/js/puppeteer.html: -------------------------------------------------------------------------------- 1 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 42 | 43 | 44 |
This div exists to force the browser to load the Source Code Pro font 45 | before we start rendering images.
46 | 47 | 48 | -------------------------------------------------------------------------------- /api/src/docs/js/verify-marble-diagrams.js: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | const path = require("path"); 21 | const projectBaseDir = path.normalize(__dirname + "/../../.."); 22 | const hashesFile = projectBaseDir + "/src/docs/js/marble-diagram-hashes.json"; 23 | 24 | const crypto = require("crypto"); 25 | const fs = require("fs"); 26 | 27 | if (!fs.existsSync(hashesFile)) { 28 | console.log(hashesFile + " not found! Cannot verify that marble diagrams are up to date."); 29 | process.exit(-1); 30 | } 31 | 32 | const files = JSON.parse(fs.readFileSync(hashesFile)).files; 33 | let conflicts = []; 34 | Object.keys(files).forEach(file => { 35 | const path = projectBaseDir + "/" + file; 36 | if (!fs.existsSync(path)) { 37 | conflicts.push(file); 38 | } else { 39 | const md5sum = crypto.createHash('md5'); 40 | const data = fs.readFileSync(file); 41 | md5sum.update(data); 42 | const md5 = md5sum.digest("hex"); 43 | if (files[file] !== md5) { 44 | conflicts.push(file); 45 | } 46 | } 47 | }); 48 | 49 | if (conflicts.length !== 0) { 50 | console.log("Marble diagram input or output files have changed since diagrams were last generated:"); 51 | conflicts.forEach(file => { 52 | console.log(" " + file); 53 | }); 54 | console.log("To fix this, run:"); 55 | console.log(" mvn -Pmarble-diagrams verify"); 56 | console.log("If you are getting this error from a CI build, the reason is that the MicroProfile CI and release"); 57 | console.log("environment does not have the necessary dependencies installed to run the diagram generation process,"); 58 | console.log("hence the diagrams are checked into revision control, and this script ensures they are up to date."); 59 | console.log("After running the above maven command, add the modified diagrams and marble-diagram-hashes.json file"); 60 | console.log("to git and commit."); 61 | process.exit(-1); 62 | } 63 | -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/CompletionRunner.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators; 21 | 22 | import java.util.concurrent.CompletionStage; 23 | 24 | import org.eclipse.microprofile.reactive.streams.operators.spi.ReactiveStreamsEngine; 25 | 26 | /** 27 | * A builder for a closed reactive streams graph. 28 | *

29 | * When built, this builder returns a {@link CompletionStage} that will be redeemed with the result produced by the 30 | * subscriber of the stream when the stream completes normally, or will be redeemed with an error if the stream 31 | * encounters an error. 32 | * 33 | * @param 34 | * The result of the stream. 35 | * @see ReactiveStreams 36 | */ 37 | public interface CompletionRunner extends ProducesResult { 38 | /** 39 | * Run this stream, using the first {@code ReactiveStreamsEngine} found by the {@link java.util.ServiceLoader}. 40 | * 41 | * @return A completion stage that will be redeemed with the result of the stream, or an error if the stream fails. 42 | */ 43 | CompletionStage run(); 44 | 45 | /** 46 | * Run this stream, using the supplied {@code ReactiveStreamsEngine}. 47 | * 48 | * @param engine 49 | * The engine to run the stream with. 50 | * @return A completion stage that will be redeemed with the result of the stream, or an error if the stream fails. 51 | */ 52 | CompletionStage run(ReactiveStreamsEngine engine); 53 | } 54 | -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/ConnectingOperators.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators; 21 | 22 | import org.reactivestreams.Processor; 23 | import org.reactivestreams.Publisher; 24 | import org.reactivestreams.Subscriber; 25 | 26 | /** 27 | * Operators for connecting different graphs together. 28 | * 29 | * @param 30 | * The type of the elements that the stream emits. 31 | */ 32 | public interface ConnectingOperators { 33 | 34 | /** 35 | * Connect the outlet of the {@link Publisher} built by this builder to the given {@link Subscriber}. The Reactive 36 | * Streams specification states that a subscriber should cancel any new stream subscription it receives if it 37 | * already has an active subscription. The returned result of this method is a stream that creates a subscription 38 | * for the subscriber passed in, so the resulting stream should only be run once. For the same reason, the 39 | * subscriber passed in should not have any active subscriptions and should not be used in more than one call to 40 | * this method. 41 | * 42 | * @param subscriber 43 | * The subscriber to connect. 44 | * @return A completion builder that completes when the stream completes. 45 | */ 46 | ProducesResult to(Subscriber subscriber); 47 | 48 | /** 49 | * Connect the outlet of this stream to the given {@link SubscriberBuilder} graph. The Reactive Streams 50 | * specification states that a subscriber should cancel any new stream subscription it receives if it already has an 51 | * active subscription. For this reason, a subscriber builder, particularly any that represents a graph that 52 | * includes a user supplied {@link Subscriber} or {@link Processor} stage, should not be used in the creation of 53 | * more than one stream instance. 54 | * 55 | * @param subscriberBuilder 56 | * The subscriber builder to connect. 57 | * @return A completion builder that completes when the stream completes. 58 | */ 59 | ProducesResult to(SubscriberBuilder subscriberBuilder); 60 | 61 | /** 62 | * Connect the outlet of the {@link Publisher} built by this builder to the given {@link ProcessorBuilder}. The 63 | * Reactive Streams specification states that a subscribing processor should cancel any new stream subscription it 64 | * receives if it already has an active subscription. For this reason, a processor builder, particularly any that 65 | * represents a graph that includes a user supplied {@link Processor} stage, should not be used in the creation of 66 | * more than one stream instance. 67 | * 68 | * @param processorBuilder 69 | * The processor builder to connect. 70 | * @return A stream builder that represents the passed in processor's outlet. 71 | */ 72 | ConnectingOperators via(ProcessorBuilder processorBuilder); 73 | 74 | /** 75 | * Connect the outlet of this stream to the given {@link Processor}. The Reactive Streams specification states that 76 | * a subscribing processor should cancel any new stream subscription it receives if it already has an active 77 | * subscription. The returned result of this method is a stream that creates a subscription for the processor passed 78 | * in, so the resulting stream should only be run once. For the same reason, the processor passed in should not have 79 | * any active subscriptions and should not be used in more than one call to this method. 80 | * 81 | * 82 | * @param processor 83 | * The processor builder to connect. 84 | * @return A stream builder that represents the passed in processor builder's outlet. 85 | */ 86 | ConnectingOperators via(Processor processor); 87 | } 88 | -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/PeekingOperators.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators; 21 | 22 | import java.util.function.Consumer; 23 | 24 | /** 25 | * Operations for peeking at elements and signals in the stream, without impacting the stream itself. 26 | *

27 | * The documentation for each operator uses marble diagrams to visualize how the operator functions. Each element 28 | * flowing in and out of the stream is represented as a coloured marble that has a value, with the operator applying 29 | * some transformation or some side effect, termination and error signals potentially being passed, and for operators 30 | * that subscribe to the stream, an output value being redeemed at the end. 31 | *

32 | * Below is an example diagram labelling all the parts of the stream. 33 | *

34 | * Example marble diagram 35 | * 36 | * @param 37 | * The type of the elements that the stream emits. 38 | */ 39 | public interface PeekingOperators { 40 | 41 | /** 42 | * Returns a stream containing all the elements from this stream, additionally performing the provided action on 43 | * each element. 44 | *

45 | * peek marbles diagram 46 | * 47 | * @param consumer 48 | * The function called for every element. 49 | * @return A new stream builder that consumes elements of type T and emits the same elements. In 50 | * between, the given function is called for each element. 51 | */ 52 | PeekingOperators peek(Consumer consumer); 53 | 54 | /** 55 | * Returns a stream containing all the elements from this stream, additionally performing the provided action if 56 | * this stream conveys an error. The given consumer is called with the failure. 57 | *

58 | * onError marble diagram 59 | * 60 | * @param errorHandler 61 | * The function called with the failure. 62 | * @return A new stream builder that consumes elements of type T and emits the same elements. If the 63 | * stream conveys a failure, the given error handler is called. 64 | */ 65 | PeekingOperators onError(Consumer errorHandler); 66 | 67 | /** 68 | * Returns a stream containing all the elements from this stream, additionally performing the provided action when 69 | * this stream completes or failed. The given action does not know if the stream failed or completed. If you need to 70 | * distinguish use {@link #onError(Consumer)} and {@link #onComplete(Runnable)}. In addition, the action is called 71 | * if the stream is cancelled downstream. 72 | *

73 | * onTerminate marble diagram 74 | * 75 | * @param action 76 | * The function called when the stream completes or failed. 77 | * @return A new stream builder that consumes elements of type T and emits the same elements. The given 78 | * action is called when the stream completes or fails. 79 | */ 80 | PeekingOperators onTerminate(Runnable action); 81 | 82 | /** 83 | * Returns a stream containing all the elements from this stream, additionally performing the provided action when 84 | * this stream completes. 85 | *

86 | * onComplete marble diagram 87 | * 88 | * @param action 89 | * The function called when the stream completes. 90 | * @return A new stream builder that consumes elements of type T and emits the same elements. The given 91 | * action is called when the stream completes. 92 | */ 93 | PeekingOperators onComplete(Runnable action); 94 | } 95 | -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/ProducesResult.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators; 21 | 22 | /** 23 | * A stream that completes with a single result. 24 | *

25 | * This will either be a {@link SubscriberBuilder}, representing a stream with an inlet that can be plumbed to a 26 | * publisher in order to run it, or a {@link CompletionRunner}, representing a closed graph that can be run as is. 27 | * 28 | * @param 29 | * The result of the stream. 30 | * @see SubscriberBuilder 31 | * @see CompletionRunner 32 | */ 33 | public interface ProducesResult { 34 | } 35 | -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/SubscriberBuilder.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators; 21 | 22 | import org.eclipse.microprofile.reactive.streams.operators.spi.ReactiveStreamsEngine; 23 | 24 | /** 25 | * A builder for a {@link org.reactivestreams.Subscriber} and its result. 26 | *

27 | * When built, this builder returns a {@link CompletionSubscriber}, which encapsulates both a 28 | * {@link org.reactivestreams.Subscriber} and a {@link java.util.concurrent.CompletionStage} that will be redeemed with 29 | * the result produced by the subscriber when the stream completes normally, or will be redeemed with an error if the 30 | * subscriber receives an error. A {@link SubscriberBuilder} may represent a compound set of stream stages and may 31 | * complete exceptionally without receiving an error externally. Similarly, {@link SubscriberBuilder}s may encapsulate 32 | * error handling such as the onErrorResume operator and recover from an externally received errors. 33 | * 34 | * @param 35 | * The type of the elements that this subscriber consumes. 36 | * @param 37 | * The type of the result that this subscriber emits. 38 | * @see ReactiveStreams 39 | */ 40 | public interface SubscriberBuilder extends ProducesResult { 41 | /** 42 | * Build this stream, using the first {@link ReactiveStreamsEngine} found by the {@link java.util.ServiceLoader}. 43 | * 44 | * @return A {@link CompletionSubscriber} that will run this stream. 45 | */ 46 | CompletionSubscriber build(); 47 | 48 | /** 49 | * Build this stream, using the supplied {@link ReactiveStreamsEngine}. 50 | * 51 | * @param engine 52 | * The engine to run the stream with. 53 | * @return A {@link CompletionSubscriber} that will run this stream. 54 | */ 55 | CompletionSubscriber build(ReactiveStreamsEngine engine); 56 | } 57 | -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/collect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/collect.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/concat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/concat.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/coupled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/coupled.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/distinct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/distinct.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/dropWhile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/dropWhile.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/empty.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/example.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/failed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/failed.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/filter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/filter.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/findFirst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/findFirst.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/flatMap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/flatMap.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/flatMapCompletionStage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/flatMapCompletionStage.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/flatMapIterable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/flatMapIterable.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/flatMapRsPublisher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/flatMapRsPublisher.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/forEach.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/forEach.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/fromCompletionStage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/fromCompletionStage.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/fromCompletionStageNullable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/fromCompletionStageNullable.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/fromIterable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/fromIterable.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/generate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/generate.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/identity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/identity.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/ignore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/ignore.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/iterate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/iterate.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/limit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/limit.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/map.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/map.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/of-many.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/of-many.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/of-single.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/of-single.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/ofNullable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/ofNullable.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/onComplete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/onComplete.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/onError.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/onError.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/onErrorResume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/onErrorResume.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/onErrorResumeWith.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/onErrorResumeWith.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/onErrorResumeWithRsPublisher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/onErrorResumeWithRsPublisher.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/onTerminate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/onTerminate.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/peek.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/peek.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/reduce-identity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/reduce-identity.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/reduce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/reduce.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/skip.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/skip.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/takeWhile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/takeWhile.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/toList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/doc-files/toList.png -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/spi/Graph.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.spi; 21 | 22 | import java.util.Collection; 23 | 24 | /** 25 | * A graph. 26 | *

27 | * Reactive Streams engines are required to convert the stages of this graph into a stream with interfaces according to 28 | * the shape, which is determined by which method is invoked on the {@link ReactiveStreamsEngine}. 29 | */ 30 | public interface Graph { 31 | /** 32 | * Get the stages of this graph. 33 | */ 34 | Collection getStages(); 35 | } 36 | -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/spi/ReactiveStreamsEngine.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.spi; 21 | 22 | import java.util.concurrent.CompletionStage; 23 | 24 | import org.reactivestreams.Processor; 25 | import org.reactivestreams.Publisher; 26 | 27 | /** 28 | * An engine for turning reactive streams graphs into Reactive Streams publishers/subscribers. 29 | *

30 | * The zero argument {@code build} and {@code run} methods on subclasses of this will use the 31 | * {@link java.util.ServiceLoader} to load an engine for the current context classloader. It does not cache engines 32 | * between invocations. If instantiating an engine is expensive (eg, it creates threads), then it is recommended that 33 | * the implementation does its own caching by providing the engine using a static provider method. 34 | */ 35 | public interface ReactiveStreamsEngine { 36 | 37 | /** 38 | * Build a {@link Publisher} from the given stages. 39 | *

40 | * The passed in graph will have an outlet and no inlet. 41 | * 42 | * @param graph 43 | * The stages to build the publisher from. Will not be empty. 44 | * @param 45 | * The type of elements that the publisher publishes. 46 | * @return A publisher that implements the passed in graph of stages. 47 | * @throws UnsupportedStageException 48 | * If a stage in the stages is not supported by this Reactive Streams engine. 49 | */ 50 | Publisher buildPublisher(Graph graph) throws UnsupportedStageException; 51 | 52 | /** 53 | * Build a {@link org.reactivestreams.Subscriber} from the given stages. 54 | *

55 | * The passed in graph will have an inlet and no outlet. 56 | * 57 | * @param graph 58 | * The graph to build the subscriber from. Will not be empty. 59 | * @param 60 | * The type of elements that the subscriber subscribes to. 61 | * @param 62 | * The result of subscribing to the stages. 63 | * @return A subscriber that implements the passed in graph of stages. 64 | * @throws UnsupportedStageException 65 | * If a stage in the stages is not supported by this Reactive Streams engine. 66 | */ 67 | SubscriberWithCompletionStage buildSubscriber(Graph graph) throws UnsupportedStageException; 68 | 69 | /** 70 | * Build a {@link Processor} from the given stages. 71 | *

72 | * The passed in graph will have an inlet and an outlet. 73 | * 74 | * @param graph 75 | * The graph to build the processor from. If empty, then the processor should be an identity processor. 76 | * @param 77 | * The type of elements that the processor subscribes to. 78 | * @param 79 | * The type of elements that the processor publishes. 80 | * @return A processor that implements the passed in graph of stages. 81 | * @throws UnsupportedStageException 82 | * If a stage in the stages is not supported by this Reactive Streams engine. 83 | */ 84 | Processor buildProcessor(Graph graph) throws UnsupportedStageException; 85 | 86 | /** 87 | * Build a closed graph from the given stages. 88 | *

89 | * The passed in graph will have no inlet and no outlet. 90 | * 91 | * @param graph 92 | * The graph to build the closed graph from. Will not be empty. 93 | * @param 94 | * The type of the result of running the closed graph. 95 | * @return A CompletionStage of the result of running the graph. 96 | * @throws UnsupportedStageException 97 | * If a stage in the stages is not supported by this reactive streams engine. 98 | */ 99 | CompletionStage buildCompletion(Graph graph) throws UnsupportedStageException; 100 | 101 | } 102 | -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/spi/ReactiveStreamsFactoryResolver.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | package org.eclipse.microprofile.reactive.streams.operators.spi; 20 | 21 | import java.security.AccessController; 22 | import java.security.PrivilegedAction; 23 | import java.security.PrivilegedActionException; 24 | import java.security.PrivilegedExceptionAction; 25 | import java.util.ServiceLoader; 26 | 27 | import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreams; 28 | import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreamsFactory; 29 | 30 | /** 31 | * This class is not intended to be used by end-users but for portable container integration purpose only. 32 | *

33 | * Service provider for ReactiveStreamsFactory. The implementation registers itself via the 34 | * {@link java.util.ServiceLoader} mechanism. 35 | */ 36 | public class ReactiveStreamsFactoryResolver { 37 | 38 | protected ReactiveStreamsFactoryResolver() { 39 | // Avoid direct instantiation. 40 | } 41 | 42 | private static volatile ReactiveStreamsFactory instance = null; 43 | 44 | /** 45 | * Creates a ReactiveStreamsFactory object Only used internally from within {@link ReactiveStreams} 46 | * 47 | * @return ReactiveStreamsFactory an instance of ReactiveStreamsFactory 48 | */ 49 | public static ReactiveStreamsFactory instance() { 50 | if (instance == null) { 51 | synchronized (ReactiveStreamsFactoryResolver.class) { 52 | if (instance != null) { 53 | return instance; 54 | } 55 | 56 | ClassLoader cl = AccessController.doPrivileged( 57 | (PrivilegedAction) () -> Thread.currentThread().getContextClassLoader()); 58 | if (cl == null) { 59 | cl = ReactiveStreamsFactory.class.getClassLoader(); 60 | } 61 | 62 | ReactiveStreamsFactory newInstance = loadFromSpi(cl); 63 | 64 | if (newInstance == null) { 65 | throw new IllegalStateException( 66 | "No ReactiveStreamsFactory implementation found!"); 67 | } 68 | 69 | instance = newInstance; 70 | } 71 | } 72 | 73 | return instance; 74 | } 75 | 76 | private static ReactiveStreamsFactory loadFromSpi(ClassLoader cl) { 77 | if (cl == null) { 78 | return null; 79 | } 80 | 81 | if (instance == null) { 82 | try { 83 | AccessController.doPrivileged((PrivilegedExceptionAction) () -> { 84 | ServiceLoader sl = ServiceLoader.load( 85 | ReactiveStreamsFactory.class, cl); 86 | for (ReactiveStreamsFactory spi : sl) { 87 | if (instance != null) { 88 | throw new IllegalStateException( 89 | "Multiple ReactiveStreamsFactory implementations found: " 90 | + spi.getClass().getName() + " and " 91 | + instance.getClass().getName()); 92 | } else { 93 | instance = spi; 94 | } 95 | } 96 | return null; 97 | }); 98 | } catch (PrivilegedActionException e) { 99 | Throwable t = e.getCause(); 100 | if (t instanceof RuntimeException) { 101 | throw (RuntimeException) t; 102 | } 103 | if (t instanceof Error) { 104 | throw (Error) t; 105 | } 106 | throw new RuntimeException(t); 107 | } 108 | } 109 | return instance; 110 | } 111 | 112 | /** 113 | * Set the instance. It is used by OSGi environment while service loader pattern is not supported. 114 | * 115 | * @param factory 116 | * set the instance. 117 | */ 118 | public static void setInstance(ReactiveStreamsFactory factory) { 119 | instance = factory; 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/spi/SubscriberWithCompletionStage.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.spi; 21 | 22 | import java.util.concurrent.CompletionStage; 23 | 24 | import org.reactivestreams.Subscriber; 25 | 26 | /** 27 | * A subscriber and completion stage pair. 28 | * 29 | * @param 30 | * The type of the elements that the subscriber consumes. 31 | * @param 32 | * The type of the result that the subscriber emits. 33 | */ 34 | public interface SubscriberWithCompletionStage { 35 | 36 | /** 37 | * Get the completion stage. 38 | *

39 | * This should be redeemed by the subscriber either when it cancels, or when it receives an 40 | * {@link Subscriber#onComplete} signal or an {@link Subscriber#onError(Throwable)} signal. Generally, the redeemed 41 | * value or error should be the result of consuming the stream. 42 | * 43 | * @return The completion stage. 44 | */ 45 | CompletionStage getCompletion(); 46 | 47 | /** 48 | * Get the subscriber. 49 | * 50 | * @return The subscriber. 51 | */ 52 | Subscriber getSubscriber(); 53 | } 54 | -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/spi/ToGraphable.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.spi; 21 | 22 | /** 23 | * All instances of {@code PublisherBuilder}, {@code ProcessorBuilder}, {@code SubscriberBuilder} and 24 | * {@code CompletionRunner} must implement this, to ensure that the builder can be turned into a graph by other 25 | * implementations of the API. 26 | */ 27 | public interface ToGraphable { 28 | 29 | /** 30 | * Convert this builder to a {@link Graph}. 31 | * 32 | * @return The graph. 33 | */ 34 | Graph toGraph(); 35 | } 36 | -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/spi/UnsupportedStageException.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.spi; 21 | 22 | /** 23 | * Exception thrown when a reactive streams engine doesn't support a stage that is passed to it. 24 | *

25 | * All reactive streams engines should support all stages, but this allows for a graceful mechanism to report issues, 26 | * for example if in a future version a new stage is added that is not recognised by an existing implementation. 27 | */ 28 | public class UnsupportedStageException extends RuntimeException { 29 | public UnsupportedStageException(Stage stage) { 30 | super("The " + stage.getClass().getSimpleName() + " stage is not supported by this Reactive Streams engine."); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /api/src/main/java/org/eclipse/microprofile/reactive/streams/operators/spi/package-info.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | /** 21 | * The Reactive Streams utils SPI. 22 | * 23 | * Implementors are expected to implement the {@code ReactiveStreamsEngine} interface, and use this SPI to inspect the 24 | * graph of stages. 25 | * 26 | * A TCK is also provided that validates that an implementation is both correct according to this specification, and the 27 | * Reactive Streams specification. 28 | */ 29 | @org.osgi.annotation.versioning.Version("1.0") 30 | package org.eclipse.microprofile.reactive.streams.operators.spi; 31 | -------------------------------------------------------------------------------- /api/src/main/resources/META-INF/NOTICE: -------------------------------------------------------------------------------- 1 | ========================================================================= 2 | == NOTICE file corresponding to section 4(d) of the Apache License, == 3 | == Version 3.0, MicroProfile Reactive Streams Operators == 4 | ========================================================================= 5 | 6 | This product includes software developed at 7 | The Apache Software Foundation (http://www.apache.org/). 8 | 9 | 10 | SPDXVersion: SPDX-2.1 11 | PackageName: MicroProfile 12 | PackageHomePage: http://www.eclipse.org/microprofile 13 | PackageLicenseDeclared: Apache-2.0 14 | 15 | PackageCopyrightText: 16 | James Roper james@lightbend.com 17 | Clement Escoffier clement.escoffier@redhat.com 18 | Gordon Hutchison gordon_hutchison@uk.ibm.com 19 | -------------------------------------------------------------------------------- /core/bnd.bnd: -------------------------------------------------------------------------------- 1 | -exportcontents: \ 2 | org.eclipse.microprofile.reactive.streams.operators.core.* 3 | 4 | Import-Package: \ 5 | org.reactivestreams;version="[1.0.0,2)", \ 6 | * 7 | 8 | Bundle-SymbolicName: org.eclipse.microprofile.reactive.streams.operators.core 9 | Bundle-Name: Eclipse MicroProfile Reactive Streams Operators Core Bundle 10 | Bundle-License: Apache License, Version 2.0 11 | -------------------------------------------------------------------------------- /core/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 4.0.0 22 | 23 | 24 | 25 | org.eclipse.microprofile.reactive-streams-operators 26 | microprofile-reactive-streams-operators-parent 27 | 3.1-SNAPSHOT 28 | 29 | 30 | 31 | false 32 | 33 | microprofile-reactive-streams-operators-core 34 | MicroProfile Reactive Streams Operators Core 35 | MicroProfile Reactive Streams Operators :: Core Implementation 36 | 37 | 38 | ${project.groupId} 39 | microprofile-reactive-streams-operators-api 40 | ${project.version} 41 | 42 | 43 | org.reactivestreams 44 | reactive-streams 45 | 46 | 47 | org.osgi 48 | org.osgi.annotation.versioning 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /core/src/main/java/org/eclipse/microprofile/reactive/streams/operators/core/CompletionRunnerImpl.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.core; 21 | 22 | import java.util.Objects; 23 | import java.util.concurrent.CompletionStage; 24 | 25 | import org.eclipse.microprofile.reactive.streams.operators.CompletionRunner; 26 | import org.eclipse.microprofile.reactive.streams.operators.spi.ReactiveStreamsEngine; 27 | import org.eclipse.microprofile.reactive.streams.operators.spi.Stage; 28 | 29 | final class CompletionRunnerImpl extends ReactiveStreamsGraphBuilder implements CompletionRunner { 30 | 31 | CompletionRunnerImpl(Stage stage, ReactiveStreamsGraphBuilder previous) { 32 | super(stage, previous); 33 | } 34 | 35 | @Override 36 | public CompletionStage run() { 37 | return run(ReactiveStreamsEngineResolver.instance()); 38 | } 39 | 40 | @Override 41 | public CompletionStage run(ReactiveStreamsEngine engine) { 42 | Objects.requireNonNull(engine, "Engine must not be null"); 43 | return engine.buildCompletion(toGraph()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /core/src/main/java/org/eclipse/microprofile/reactive/streams/operators/core/GraphImpl.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.core; 21 | 22 | import java.util.Collection; 23 | 24 | import org.eclipse.microprofile.reactive.streams.operators.spi.Graph; 25 | import org.eclipse.microprofile.reactive.streams.operators.spi.Stage; 26 | 27 | final class GraphImpl implements Graph { 28 | private final Collection stages; 29 | 30 | /** 31 | * Create a graph from the given stages. 32 | *

33 | * If the first stage has an inlet, then this graph has an inlet, and can therefore be represented as a 34 | * {@link org.reactivestreams.Subscriber}. If the last stage has an outlet, then this graph has an outlet, and 35 | * therefore can be represented as a {@link org.reactivestreams.Publisher}. 36 | * 37 | * @param stages 38 | * The stages. 39 | */ 40 | GraphImpl(Collection stages) { 41 | this.stages = stages; 42 | } 43 | 44 | @Override 45 | public Collection getStages() { 46 | return stages; 47 | } 48 | 49 | @Override 50 | public String toString() { 51 | return "Graph{" + 52 | "stages=" + stages + 53 | '}'; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /core/src/main/java/org/eclipse/microprofile/reactive/streams/operators/core/InternalStages.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.core; 21 | 22 | import java.util.Objects; 23 | 24 | import org.eclipse.microprofile.reactive.streams.operators.spi.Graph; 25 | import org.eclipse.microprofile.reactive.streams.operators.spi.Stage; 26 | import org.eclipse.microprofile.reactive.streams.operators.spi.ToGraphable; 27 | 28 | /** 29 | * Internal stages, used to capture the graph while being built, but never passed to a 30 | * {@link org.eclipse.microprofile.reactive.streams.operators.spi.ReactiveStreamsEngine}. These exist for performance 31 | * reasons, allowing the builder to hold the graph as an immutable linked tree where multiple stages can be appended in 32 | * constant time, rather than needing to copy an array each time. However, when it comes to building the graph, it is 33 | * first flattened out to an array, removing any of the internal stages that held nested stages, etc. 34 | */ 35 | class InternalStages { 36 | 37 | private InternalStages() { 38 | } 39 | 40 | interface InternalStage extends Stage { 41 | } 42 | 43 | /** 44 | * An identity stage - this stage simply passes is input to its output unchanged. It's used to represent processor 45 | * builders that have had no stages defined. 46 | *

47 | * It gets ignored by the {@link ReactiveStreamsGraphBuilder} when encountered. 48 | */ 49 | static final class Identity implements InternalStage { 50 | static final Identity INSTANCE = new Identity(); 51 | 52 | private Identity() { 53 | } 54 | } 55 | 56 | /** 57 | * A nested stage. This is used to avoid having to rebuild the entire graph (which is represented as an immutable 58 | * cons) whenever two graphs are joined, or a stage is prepended into the graph. 59 | *

60 | * It gets flattened out by the {@link ReactiveStreamsGraphBuilder} when building the graph. 61 | */ 62 | static final class Nested implements InternalStage { 63 | private final ReactiveStreamsGraphBuilder graphBuilder; 64 | 65 | Nested(ReactiveStreamsGraphBuilder graphBuilder) { 66 | this.graphBuilder = graphBuilder; 67 | } 68 | 69 | ReactiveStreamsGraphBuilder getBuilder() { 70 | return graphBuilder; 71 | } 72 | } 73 | 74 | /** 75 | * A nested stage, holding a graph. This is used when nesting a builder that has come from another implementation. 76 | */ 77 | static final class NestedGraph implements InternalStage { 78 | private final Graph graph; 79 | 80 | NestedGraph(Graph graph) { 81 | this.graph = graph; 82 | } 83 | 84 | public Graph getGraph() { 85 | return graph; 86 | } 87 | } 88 | 89 | static InternalStage nested(Object object) { 90 | Objects.requireNonNull(object); 91 | if (object instanceof ReactiveStreamsGraphBuilder) { 92 | return new Nested((ReactiveStreamsGraphBuilder) object); 93 | } else if (object instanceof ToGraphable) { 94 | return new NestedGraph(((ToGraphable) object).toGraph()); 95 | } else { 96 | throw new IllegalArgumentException("The passed in builder does not implement " + ToGraphable.class + 97 | " and so can't be added to this graph"); 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /core/src/main/java/org/eclipse/microprofile/reactive/streams/operators/core/ReactiveStreamsEngineResolver.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | package org.eclipse.microprofile.reactive.streams.operators.core; 20 | 21 | import java.security.AccessController; 22 | import java.security.PrivilegedAction; 23 | import java.security.PrivilegedActionException; 24 | import java.security.PrivilegedExceptionAction; 25 | import java.util.ServiceLoader; 26 | 27 | import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreams; 28 | import org.eclipse.microprofile.reactive.streams.operators.spi.ReactiveStreamsEngine; 29 | 30 | /** 31 | * This class is not intended to be used by end-users but for portable container integration purpose only. 32 | *

33 | * Service provider for ReactiveStreamsEngine. The implementation registers itself via the {@link ServiceLoader} 34 | * mechanism. 35 | */ 36 | public class ReactiveStreamsEngineResolver { 37 | 38 | protected ReactiveStreamsEngineResolver() { 39 | // Avoid direct instantiation. 40 | } 41 | 42 | private static volatile ReactiveStreamsEngine instance = null; 43 | 44 | /** 45 | * Creates a ReactiveStreamsFactory object Only used internally from within {@link ReactiveStreams} 46 | * 47 | * @return ReactiveStreamsFactory an instance of ReactiveStreamsFactory 48 | */ 49 | public static ReactiveStreamsEngine instance() { 50 | if (instance == null) { 51 | synchronized (ReactiveStreamsEngineResolver.class) { 52 | if (instance != null) { 53 | return instance; 54 | } 55 | 56 | ClassLoader cl = AccessController.doPrivileged( 57 | (PrivilegedAction) () -> Thread.currentThread().getContextClassLoader()); 58 | if (cl == null) { 59 | cl = ReactiveStreamsEngine.class.getClassLoader(); 60 | } 61 | 62 | ReactiveStreamsEngine newInstance = loadFromSpi(cl); 63 | 64 | if (newInstance == null) { 65 | throw new IllegalStateException( 66 | "No ReactiveStreamsEngine implementation found!"); 67 | } 68 | 69 | instance = newInstance; 70 | } 71 | } 72 | 73 | return instance; 74 | } 75 | 76 | private static ReactiveStreamsEngine loadFromSpi(ClassLoader cl) { 77 | if (cl == null) { 78 | return null; 79 | } 80 | if (instance == null) { 81 | try { 82 | AccessController.doPrivileged((PrivilegedExceptionAction) () -> { 83 | ServiceLoader sl = ServiceLoader.load( 84 | ReactiveStreamsEngine.class, cl); 85 | for (ReactiveStreamsEngine spi : sl) { 86 | if (instance != null) { 87 | throw new IllegalStateException( 88 | "Multiple ReactiveStreamsEngine implementations found: " 89 | + spi.getClass().getName() + " and " 90 | + instance.getClass().getName()); 91 | } else { 92 | instance = spi; 93 | } 94 | } 95 | return null; 96 | }); 97 | } catch (PrivilegedActionException e) { 98 | Throwable t = e.getCause(); 99 | if (t instanceof RuntimeException) { 100 | throw (RuntimeException) t; 101 | } 102 | if (t instanceof Error) { 103 | throw (Error) t; 104 | } 105 | throw new RuntimeException(t); 106 | } 107 | } 108 | return instance; 109 | } 110 | 111 | /** 112 | * Set the instance. It is used by OSGi environment while service loader pattern is not supported. 113 | * 114 | * @param factory 115 | * set the instance. 116 | */ 117 | public static void setInstance(ReactiveStreamsEngine factory) { 118 | instance = factory; 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /core/src/main/java/org/eclipse/microprofile/reactive/streams/operators/core/ReactiveStreamsGraphBuilder.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.core; 21 | 22 | import java.util.*; 23 | 24 | import org.eclipse.microprofile.reactive.streams.operators.spi.Graph; 25 | import org.eclipse.microprofile.reactive.streams.operators.spi.Stage; 26 | import org.eclipse.microprofile.reactive.streams.operators.spi.ToGraphable; 27 | import org.reactivestreams.Publisher; 28 | 29 | /** 30 | * Builds graphs of reactive streams. 31 | */ 32 | abstract class ReactiveStreamsGraphBuilder implements ToGraphable { 33 | 34 | private final Stage stage; 35 | private final ReactiveStreamsGraphBuilder previous; 36 | 37 | ReactiveStreamsGraphBuilder(Stage stage, ReactiveStreamsGraphBuilder previous) { 38 | this.stage = stage; 39 | this.previous = previous; 40 | } 41 | 42 | @Override 43 | public Graph toGraph() { 44 | ArrayDeque deque = new ArrayDeque<>(); 45 | flatten(deque); 46 | return new GraphImpl(Collections.unmodifiableCollection(deque)); 47 | } 48 | 49 | private void flatten(Deque stages) { 50 | ReactiveStreamsGraphBuilder thisStage = this; 51 | while (thisStage != null) { 52 | if (thisStage.stage == InternalStages.Identity.INSTANCE) { 53 | // Ignore, no need to add an identity stage 54 | } else if (thisStage.stage instanceof InternalStages.Nested) { 55 | ((InternalStages.Nested) thisStage.stage).getBuilder().flatten(stages); 56 | } else if (thisStage.stage instanceof InternalStages.NestedGraph) { 57 | // need to prepend to front in reverse order 58 | Collection nestedStages = ((InternalStages.NestedGraph) thisStage.stage).getGraph().getStages(); 59 | ListIterator iter; 60 | if (nestedStages instanceof List) { 61 | iter = ((List) nestedStages).listIterator(nestedStages.size()); 62 | } else { 63 | iter = new ArrayList<>(nestedStages).listIterator(nestedStages.size()); 64 | } 65 | while (iter.hasPrevious()) { 66 | stages.addFirst(iter.previous()); 67 | } 68 | } else { 69 | stages.addFirst(thisStage.stage); 70 | } 71 | thisStage = thisStage.previous; 72 | } 73 | } 74 | 75 | static Graph rsBuilderToGraph(Object obj) { 76 | Objects.requireNonNull(obj); 77 | if (obj instanceof ToGraphable) { 78 | return (((ToGraphable) obj).toGraph()); 79 | } else { 80 | throw new IllegalArgumentException(obj + " is not an instance of ToGraphable and so can't participate " + 81 | "in this graph"); 82 | } 83 | } 84 | 85 | static Graph publisherToGraph(Publisher publisher) { 86 | return new GraphImpl(Collections.singleton(new Stages.PublisherStage(publisher))); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /core/src/main/java/org/eclipse/microprofile/reactive/streams/operators/core/Reductions.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.core; 21 | 22 | import java.util.Objects; 23 | import java.util.Optional; 24 | import java.util.function.BinaryOperator; 25 | import java.util.stream.Collector; 26 | 27 | /** 28 | * Reduction utilities that convert arguments supplied to reduce methods on the builders to Collectors. 29 | */ 30 | final class Reductions { 31 | 32 | private Reductions() { 33 | } 34 | 35 | static Collector> reduce(BinaryOperator reducer) { 36 | Objects.requireNonNull(reducer, "Reduction function must not be null"); 37 | return Collector.of(Reduction::new, 38 | (r, t) -> { 39 | if (r.value == null) { 40 | r.value = t; 41 | } else { 42 | r.value = reducer.apply(r.value, t); 43 | } 44 | }, 45 | (r, s) -> { 46 | if (r.value == null) { 47 | return r.replace(s.value); 48 | } else if (s.value != null) { 49 | return r.replace(reducer.apply(r.value, s.value)); 50 | } else { 51 | return r; 52 | } 53 | }, 54 | r -> Optional.ofNullable(r.value)); 55 | } 56 | 57 | static Collector reduce(T identity, BinaryOperator reducer) { 58 | Objects.requireNonNull(reducer, "Reduction function must not be null"); 59 | return Collector.of(() -> new Reduction<>(identity), 60 | (r, t) -> r.value = reducer.apply(r.value, t), 61 | (r, s) -> r.replace(reducer.apply(r.value, s.value)), 62 | r -> r.value); 63 | } 64 | 65 | private static class Reduction { 66 | private T value; 67 | 68 | Reduction() { 69 | } 70 | 71 | Reduction(T value) { 72 | this.value = value; 73 | } 74 | 75 | Reduction replace(T newValue) { 76 | this.value = newValue; 77 | return this; 78 | } 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /core/src/main/java/org/eclipse/microprofile/reactive/streams/operators/core/SubscriberBuilderImpl.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.core; 21 | 22 | import java.util.Objects; 23 | 24 | import org.eclipse.microprofile.reactive.streams.operators.CompletionSubscriber; 25 | import org.eclipse.microprofile.reactive.streams.operators.SubscriberBuilder; 26 | import org.eclipse.microprofile.reactive.streams.operators.spi.ReactiveStreamsEngine; 27 | import org.eclipse.microprofile.reactive.streams.operators.spi.Stage; 28 | import org.eclipse.microprofile.reactive.streams.operators.spi.SubscriberWithCompletionStage; 29 | 30 | public final class SubscriberBuilderImpl extends ReactiveStreamsGraphBuilder implements SubscriberBuilder { 31 | 32 | SubscriberBuilderImpl(Stage stage, ReactiveStreamsGraphBuilder previous) { 33 | super(stage, previous); 34 | } 35 | 36 | @Override 37 | public CompletionSubscriber build() { 38 | return build(ReactiveStreamsEngineResolver.instance()); 39 | } 40 | 41 | @Override 42 | public CompletionSubscriber build(ReactiveStreamsEngine engine) { 43 | Objects.requireNonNull(engine, "Engine must not be null"); 44 | SubscriberWithCompletionStage subscriberWithCompletionStage = engine.buildSubscriber(toGraph()); 45 | return CompletionSubscriber.of(subscriberWithCompletionStage.getSubscriber(), 46 | subscriberWithCompletionStage.getCompletion()); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/main/java/org/eclipse/microprofile/reactive/streams/operators/core/package-info.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2020, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional information regarding copyright ownership. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); You may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on 12 | * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the 13 | * specific language governing permissions and limitations under the License. 14 | ******************************************************************************/ 15 | 16 | @org.osgi.annotation.versioning.Version("1.0") 17 | package org.eclipse.microprofile.reactive.streams.operators.core; 18 | -------------------------------------------------------------------------------- /core/src/main/resources/META-INF/NOTICE: -------------------------------------------------------------------------------- 1 | ========================================================================= 2 | == NOTICE file corresponding to section 4(d) of the Apache License, == 3 | == Version 3.0, MicroProfile Reactive Streams Operators == 4 | ========================================================================= 5 | 6 | This product includes software developed at 7 | The Apache Software Foundation (http://www.apache.org/). 8 | 9 | 10 | SPDXVersion: SPDX-2.1 11 | PackageName: MicroProfile 12 | PackageHomePage: http://www.eclipse.org/microprofile 13 | PackageLicenseDeclared: Apache-2.0 14 | 15 | PackageCopyrightText: 16 | James Roper james@lightbend.com 17 | Clement Escoffier clement.escoffier@redhat.com 18 | Gordon Hutchison gordon_hutchison@uk.ibm.com 19 | -------------------------------------------------------------------------------- /core/src/main/resources/META-INF/services/org.eclipse.microprofile.reactive.streams.operators.ReactiveStreamsFactory: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | # 4 | # See the NOTICE file(s) distributed with this work for additional 5 | # information regarding copyright ownership. 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # You may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | ################################################################################ 19 | 20 | org.eclipse.microprofile.reactive.streams.operators.core.ReactiveStreamsFactoryImpl 21 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 4.0.0 22 | 23 | 24 | org.eclipse.microprofile 25 | microprofile-parent 26 | 2.11 27 | 28 | 29 | org.eclipse.microprofile.reactive-streams-operators 30 | microprofile-reactive-streams-operators-parent 31 | 3.1-SNAPSHOT 32 | pom 33 | 34 | 35 | 2018 36 | 2.11 37 | 38 | 39 | Eclipse MicroProfile Reactive Streams Operators 40 | Eclipse MicroProfile Reactive Streams Operators :: Parent POM 41 | 42 | 43 | 44 | 45 | 46 | James Roper 47 | https://jazzy.id.au 48 | Lightbend 49 | https://www.lightbend.com 50 | 51 | 52 | Clement Escoffier 53 | Red Hat 54 | https://redhat.com 55 | 56 | 57 | 58 | 59 | scm:git:https://github.com/eclipse/microprofile-reactive-streams-operators.git 60 | scm:git:git@github.com:eclipse/microprofile-reactive-streams-operators.git 61 | https://github.com/eclipse/microprofile-reactive-streams-operators 62 | HEAD 63 | 64 | 65 | 66 | api 67 | core 68 | tck 69 | spec 70 | 71 | 72 | 73 | 74 | 75 | org.reactivestreams 76 | reactive-streams 77 | 1.0.3 78 | 79 | 80 | org.reactivestreams 81 | reactive-streams-tck 82 | 1.0.3 83 | 84 | 85 | org.osgi 86 | org.osgi.annotation.versioning 87 | 1.0.0 88 | provided 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /site.yaml: -------------------------------------------------------------------------------- 1 | ####################################################################### 2 | ## Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | ## 4 | ## See the NOTICE file(s) distributed with this work for additional 5 | ## information regarding copyright ownership. 6 | ## 7 | ## Licensed under the Apache License, Version 2.0 (the "License"); 8 | ## you may not use this file except in compliance with the License. 9 | ## You may obtain a copy of the License at 10 | ## 11 | ## http://www.apache.org/licenses/LICENSE-2.0 12 | ## 13 | ## Unless required by applicable law or agreed to in writing, software 14 | ## distributed under the License is distributed on an "AS IS" BASIS, 15 | ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | ## See the License for the specific language governing permissions and 17 | ## limitations under the License. 18 | ####################################################################### 19 | %YAML 1.2 20 | --- 21 | documentation: 22 | - title: Reactive Streams Operators for Microprofile 23 | file: spec/src/main/asciidoc/microprofile-reactive-streams-operators-spec.asciidoc 24 | 25 | - title: Architecture 26 | file: spec/src/main/asciidoc/architecture.asciidoc 27 | 28 | - title: Usage Examples 29 | file: spec/src/main/asciidoc/examples.asciidoc 30 | 31 | - title: License 32 | file: spec/src/main/asciidoc/license-alv2.asciidoc 33 | -------------------------------------------------------------------------------- /spec/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 4.0.0 22 | 23 | 24 | org.eclipse.microprofile.reactive-streams-operators 25 | microprofile-reactive-streams-operators-parent 26 | 3.1-SNAPSHOT 27 | 28 | 29 | microprofile-reactive-streams-operators-spec 30 | pom 31 | Eclipse MicroProfile Reactive Streams Operators Specification 32 | Eclipse MicroProfile Reactive Streams Operators :: Specification 33 | 34 | 35 | -------------------------------------------------------------------------------- /spec/src/main/asciidoc/cdi.asciidoc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | [[reactivestreamscdi]] 18 | == CDI Integration 19 | 20 | MicroProfile Reactive Streams Operators implementations may be used independently of a CDI container. 21 | Consequently, implementations are not required to provide any integration with CDI. 22 | 23 | This section of the specification is intended to provide advice for how other specifications may integrate CDI with MicroProfile Reactive Streams Operators. 24 | 25 | === Injection of engines 26 | 27 | If a MicroProfile container provides an implementation of MicroProfile Reactive Streams Operators, then it must make an application scoped `ReactiveStreamsEngine` available for injection. 28 | 29 | === Contexts 30 | 31 | This specification places no requirements on the propagation of CDI context, or what context(s) should be active when user supplied callbacks are executed during the running of a stream. 32 | 33 | Other specifications that use this specification may require that implementations make certain context's to be active when user callbacks are executed. 34 | In this case, it is expected that such specifications will have the responsibility of running the streams. 35 | 36 | For example, a hypothetical WebSocket specification may allow user code to return a `ProcessorBuilder` to handle messages: 37 | 38 | [source, java] 39 | ---- 40 | @WebSocket("/echo") 41 | public ProcessorBuilder echoWebsocket() { 42 | return ReactiveStreams.builder().map(message -> 43 | new Message("Echoing " + message.getText()) 44 | ); 45 | } 46 | ---- 47 | 48 | In this case, the implementation of that hypothetical WebSocket specification is responsible for running the `ProcessorBuilder` returned by the user, and that specification may require that the engine it uses to run it makes the request context active in callbacks, such as the `map` callback above. 49 | Since the implementation of that specification is in control of which engine is used to run the processor, this requirement can be made by that specification. 50 | It is the responsibility of that implementation (and the MicroProfile container that pulls these implementations together) to ensure that the MicroProfile Reactive Streams Operators implementation used is able to support CDI context propagation. 51 | 52 | In contrast, if a user is responsible for executing a stream, like in the following hypothetical example: 53 | 54 | [source, java] 55 | ---- 56 | @WebSocket("/echo") 57 | public void echoWebsocket(PublisherBuilder incoming, 58 | SubscriberBuilder outgoing) { 59 | 60 | incoming.map(message -> 61 | new Message("Echoing " + message.getText() 62 | ).to(outgoing).run(); 63 | } 64 | ---- 65 | 66 | Then there is no clear way for the container to control how the engine used there, which in this case would be loaded through the Java `ServiceLoader` API, would propagate context. 67 | For this reason, any cases where users are running their own streams are not expected to require any CDI context propagation, and it is recommended that specifications favour APIs where the container runs the stream, not the user, to facilitate context propagation. 68 | -------------------------------------------------------------------------------- /spec/src/main/asciidoc/images/picture-sources.odg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/spec/src/main/asciidoc/images/picture-sources.odg -------------------------------------------------------------------------------- /spec/src/main/asciidoc/implementation.asciidoc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | [[reactivestreamsimplementation]] 18 | == Implementation 19 | 20 | The behavior of each stage is specified in the javadocs for stages in the SPI, and tested by the TCK. 21 | 22 | Generally, across all stages, the following requirements exist: 23 | 24 | === Memory visibility 25 | 26 | Within a single stage in a single stream, implementations must guarantee a _happens-before_ relationship between any invocation of all callbacks supplied to that stage. 27 | 28 | Between different stages of a single stream, it is recommended that a _happens-before_ relationship exists between callbacks of different stages, however this is not required, and end users of the API must not depend on this. 29 | Implementations are expected to implement this for performance reasons, this is also known as operator fusing. 30 | Implementations may decide, for whatever reason, not to fuse stages in certain circumstances, when this is done, it is said that there is an asynchronous boundary between the two stages. 31 | 32 | When Reactive Streams interfaces, that is, `Publisher`, `Subscriber` or `Processor`, are wrapped in a stage, implementations may place an asynchronous boundary between that stage and its neighbors if they choose. 33 | Whether implementations do or don't place an asynchronous boundary there, they must conform to the Reactive Streams specification with regards to memory visibility. 34 | 35 | === User exceptions 36 | 37 | Exceptions thrown by user supplied callbacks must be caught and propagated downstream, unless otherwise handled by an error handling stage. 38 | 39 | User exceptions must not be thrown by the `build` or `run` methods of the builders. 40 | For example, if a user supplies an `Iterable` as a source for a `PublisherBuilder`, and the `iterator()` method is invoked synchronously from the `build` method on the publisher, and it throws an exception, this exception must be caught, and propagated through the stream, not thrown from the `build` method. 41 | 42 | An exception to this is the callbacks provided in user supplied Reactive Streams, ie `Publisher`, `Subscriber` and `Processor`. 43 | Since these interfaces are specified not to throw any exceptions when the consumer is adhering to the spec, implementations may assume that these interfaces won't throw exceptions, and the behavior of an implementation should these interfaces throw exceptions is unspecified. 44 | 45 | In some cases, exceptions may be wrapped, for example, `CompletableFuture` wraps exceptions in a `CompletionException`. 46 | It is recommended that implementations do not wrap exceptions if they don't need to, but rather that they propagate them downstream as is. 47 | 48 | === Error propagation 49 | 50 | Errors may be eagerly propagated by stages if an implementation chooses to do this. 51 | Such propagation can aid with fast failure of stages, to ensure things like connection failures do not wait excessively to discover that they have failed. 52 | 53 | A consequence of this is that errors can in certain circumstances overtake elements. 54 | For example, the `flatMapCompletionStage` stage may receive an error while an element is being asynchronously processed. 55 | This error may immediately be propagated downstream, which will mean the eventual redemption of the `CompletionStage` returned by the mapper function for the stage will be ignored, and the element it is redeemed with will be dropped. 56 | 57 | When a user does not desire this behavior, and wants to guarantee that stages don't drop elements when upstream errors arrive, they may insert an error recovery stage, such as `onErrorResume`, before the stage that they don't want to drop elements from. 58 | They will then need to implement an out of band mechanism to propagate the error, such as wrapping it in an element, should they wish to handle it downstream. 59 | 60 | === Cleanup 61 | 62 | Implementations must assume that any `PublisherBuilder`, `SubscriberBuilder` or `ProcessorBuilder` supplied to them, or any stages within, potentially hold resources, and must be cleaned up when the stream shuts down. 63 | For example, a `concat` stage accepts two `PublisherBuilder`'s. 64 | If the stream is cancelled before the first is finished, the second must still be built, and then cancelled too. 65 | 66 | === null elements 67 | 68 | Reactive Streams does not allow `null` elements. Hence, any user callbacks that return `null` as an element to be emitted by a stage must cause the stage to fail with a `NullPointerException`. 69 | -------------------------------------------------------------------------------- /spec/src/main/asciidoc/java-streams.asciidoc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | [[reactivestreams-java-streams]] 18 | == Similarities and differences with the Java Stream API 19 | 20 | The API shares a lot of similarities with the https://docs.oracle.com/javase/9/docs/api/java/util/stream/Stream.html[Java 21 | Stream API]. This similarity has been done on purpose to ease the adoption of the API. However, there are some 22 | differences and this section highlights them. 23 | 24 | === Asynchronous processing 25 | 26 | The goal of the Reactive Stream Operators specification is to define building blocks to enable the 27 | implementation of asynchronous processing of stream of data. On the other hand, the Java Stream API provides a synchronous 28 | approach to compute a result by analyzing data conveyed in a stream. Because of this asynchronous vs. synchronous 29 | processing, the terminal stages (such as `collect`, `findFirst`...) define by this API return `CompletableStage` and 30 | not `T`. Indeed, only when the result has been computed the returned `CompletableStage` is completed. As an example, 31 | here is the two versions of the same processing: 32 | 33 | [source, java] 34 | ---- 35 | List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 36 | 37 | // Java Stream version 38 | int sum = list.stream() 39 | .map(i -> i + 1) 40 | .mapToInt(i -> i) 41 | .sum(); 42 | // At the point the sum is computed 43 | System.out.println("sum: " + sum); 44 | 45 | // Reactive Streams Operators version 46 | CompletionStage future = ReactiveStreams.fromIterable(list) 47 | .map(i -> i + 1) 48 | .collect(Collectors.summingInt(i -> i)) 49 | .run(); 50 | future.whenComplete((res, err) -> System.out.println("async sum: " + res)); 51 | ---- 52 | 53 | The asynchronous vs. synchronous difference also means that the error propagation works differently. In the Java Streams 54 | API, the processing can be wrapped in a `try/catch` construct. In the asynchronous case, the error is propagated into the 55 | returned future. In the example above, the function passed to the `whenComplete` stage receives the result as well as the 56 | failure (if any). If the processing throws an exception, the function can react by looking at the `err` parameter. 57 | 58 | === No parallel processing 59 | 60 | The Reactive Streams specification is intrinsically sequential. So none of the parallel processing ability from the Java 61 | Stream API are supported. As a consequence, the API does not provide a `parallel​()` method. Also, operations like 62 | `findAny` are not provided as the behavior would be equivalent to the provided `findFirst` method. 63 | 64 | === Other differences 65 | 66 | * `allMatch`, `anyMatch` and `nonMatch` can be achieved by combining `filter` and `findFirst` 67 | * `collect(Collector collector)` - the combiner part of the collector is not used because of the sequential 68 | nature of Reactive Streams. 69 | * `collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner)` is provided as `collect 70 | (Supplier supplier, BiConsumer accumulator)`. Indeed, the combiner is not used because of the sequential 71 | nature of Reactive Streams. 72 | * `count` is not provided but can be implemented using `.collect(Collectors.counting())` instead. 73 | * `findAny` is not supported, use `findFirst` instead. Because of the sequential nature of Reactive Streams, the method 74 | has the same semantic. 75 | * `flatMapTo` and `mapTo` are not provided. These can easily be replaced using regular `flatMap` and `map` methods, or 76 | methods from `Collectors`. 77 | * `forEachOrdered` is not provided as Reactive Streams mandates ordering. So `forEach` should be used instead. 78 | * `max` and `min` can be achieved using `.collect(Collectors.maxBy(...))` and `.collect(Collectors.minBy(...))` 79 | * `sorted` is not supported 80 | * `toArray` is not supported, `toList` can be used instead 81 | * `onClose` is replaced by `onComplete`. Notice that the API also provides the `onError` and `onTerminate` methods. 82 | 83 | -------------------------------------------------------------------------------- /spec/src/main/asciidoc/license-alv2.asciidoc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | [subs="normal"] 18 | .... 19 | 20 | Specification: {doctitle} 21 | 22 | Version: {revnumber} 23 | 24 | Status: {revremark} 25 | 26 | Release: {revdate} 27 | 28 | Copyright (c) 2018 Contributors to the Eclipse Foundation 29 | 30 | Licensed under the Apache License, Version 2.0 (the "License"); 31 | you may not use this file except in compliance with the License. 32 | You may obtain a copy of the License at 33 | 34 | http://www.apache.org/licenses/LICENSE-2.0 35 | 36 | Unless required by applicable law or agreed to in writing, software 37 | distributed under the License is distributed on an "AS IS" BASIS, 38 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 39 | See the License for the specific language governing permissions and 40 | limitations under the License. 41 | 42 | .... -------------------------------------------------------------------------------- /spec/src/main/asciidoc/license-efsl.adoc: -------------------------------------------------------------------------------- 1 | [subs="normal"] 2 | .... 3 | Specification: {doctitle} 4 | 5 | Version: {revnumber} 6 | 7 | Status: {revremark} 8 | 9 | Release: {revdate} 10 | .... 11 | 12 | == Copyright 13 | 14 | Copyright (c) {inceptionYear} , {currentYear} Eclipse Foundation. 15 | 16 | === Eclipse Foundation Specification License 17 | 18 | By using and/or copying this document, or the Eclipse Foundation 19 | document from which this statement is linked, you (the licensee) agree 20 | that you have read, understood, and will comply with the following 21 | terms and conditions: 22 | 23 | Permission to copy, and distribute the contents of this document, or 24 | the Eclipse Foundation document from which this statement is linked, in 25 | any medium for any purpose and without fee or royalty is hereby 26 | granted, provided that you include the following on ALL copies of the 27 | document, or portions thereof, that you use: 28 | 29 | * link or URL to the original Eclipse Foundation document. 30 | * All existing copyright notices, or if one does not exist, a notice 31 | (hypertext is preferred, but a textual representation is permitted) 32 | of the form: "Copyright (c) [$date-of-document] 33 | Eclipse Foundation, Inc. \<>" 34 | 35 | Inclusion of the full text of this NOTICE must be provided. We 36 | request that authorship attribution be provided in any software, 37 | documents, or other items or products that you create pursuant to the 38 | implementation of the contents of this document, or any portion 39 | thereof. 40 | 41 | No right to create modifications or derivatives of Eclipse Foundation 42 | documents is granted pursuant to this license, except anyone may 43 | prepare and distribute derivative works and portions of this document 44 | in software that implements the specification, in supporting materials 45 | accompanying such software, and in documentation of such software, 46 | PROVIDED that all such works include the notice below. HOWEVER, the 47 | publication of derivative works of this document for use as a technical 48 | specification is expressly prohibited. 49 | 50 | The notice is: 51 | 52 | "Copyright (c) [$date-of-document] Eclipse Foundation. This software or 53 | document includes material copied from or derived from [title and URI 54 | of the Eclipse Foundation specification document]." 55 | 56 | ==== Disclaimers 57 | 58 | THIS DOCUMENT IS PROVIDED "AS IS," AND THE COPYRIGHT 59 | HOLDERS AND THE ECLIPSE FOUNDATION MAKE NO REPRESENTATIONS OR 60 | WARRANTIES, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 61 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, 62 | NON-INFRINGEMENT, OR TITLE; THAT THE CONTENTS OF THE DOCUMENT ARE 63 | SUITABLE FOR ANY PURPOSE; NOR THAT THE IMPLEMENTATION OF SUCH CONTENTS 64 | WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, TRADEMARKS OR 65 | OTHER RIGHTS. 66 | 67 | THE COPYRIGHT HOLDERS AND THE ECLIPSE FOUNDATION WILL NOT BE LIABLE 68 | FOR ANY DIRECT, INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT 69 | OF ANY USE OF THE DOCUMENT OR THE PERFORMANCE OR IMPLEMENTATION OF THE 70 | CONTENTS THEREOF. 71 | 72 | The name and trademarks of the copyright holders or the Eclipse 73 | Foundation may NOT be used in advertising or publicity pertaining to 74 | this document or its contents without specific, written prior 75 | permission. Title to copyright in this document will at all times 76 | remain with copyright holders. 77 | -------------------------------------------------------------------------------- /spec/src/main/asciidoc/microprofile-reactive-streams-operators-spec.asciidoc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | = MicroProfile Reactive Streams Operators Specification 18 | :authors: James Roper, Clement Escoffier, Gordon Hutchison 19 | :email: james@lightbend.com, clement.escoffier@redhat.com, gordon_hutchison@uk.ibm.com 20 | :version-label!: 21 | :sectanchors: 22 | :doctype: book 23 | :license: Apache License v2.0 24 | :source-highlighter: coderay 25 | :toc: left 26 | :toclevels: 4 27 | :sectnumlevels: 4 28 | ifdef::backend-pdf[] 29 | :pagenums: 30 | endif::[] 31 | 32 | 33 | // == License 34 | :sectnums!: 35 | include::license-efsl.adoc[] 36 | 37 | == MicroProfile Reactive Streams Operators 38 | 39 | include::architecture.asciidoc[] 40 | include::design.asciidoc[] 41 | include::implementation.asciidoc[] 42 | include::cdi.asciidoc[] 43 | 44 | include::examples.asciidoc[] 45 | 46 | include::java-streams.asciidoc[] 47 | 48 | include::spi.asciidoc[] 49 | 50 | include::release_notes.asciidoc[] 51 | -------------------------------------------------------------------------------- /spec/src/main/asciidoc/release_notes.asciidoc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2021, 2022 Contributors to the Eclipse Foundation 3 | // 4 | // See the NOTICE file(s) distributed with this work for additional 5 | // information regarding copyright ownership. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // You may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | [[release_notes_30]] 20 | == Release Notes for MicroProfile Reactive Streams Operator 3.0 21 | A full list of changes delivered in the 3.0 release can be found at link:https://github.com/eclipse/microprofile-reactive-streams-operators/milestone/8[MicroProfile Reactive Streams Operators 3.0 Milestone]. 22 | 23 | === Other Changes 24 | - Loading ReactiveStreamsEngine and ReactiveStreamsFactory should also work running with a security manager (link:https://github.com/eclipse/microprofile-reactive-streams-operators/pull/170[#170]) 25 | 26 | ==== Incompatible Changes 27 | This release aligns with Jakarta EE 9.1, so it won't work with earlier versions of Jakarta or Java EE. 28 | 29 | ==== API/SPI Changes 30 | There are no functional changes introduced in this release, except updating the dependencies from javax to jakarta. 31 | 32 | [[release_notes_20]] 33 | == Release Notes for MicroProfile Reactive Streams Operator 2.0 34 | 35 | A full list of changes delivered in the 2.0 release can be found at link:https://github.com/eclipse/microprofile-reactive-streams-operators/milestone/3?closed=1[MicroProfile Reactive Streams Operators 2.0 Milestone]. 36 | 37 | === Incompatible Changes 38 | 39 | - OSGi dependencies marked as "provided" (link:https://github.com/eclipse/microprofile-reactive-streams-operators/issues/132[#132]) 40 | 41 | === API/SPI Changes 42 | - ReactiveStreamsFactory.fromSubscriber parameter type change (link:https://github.com/eclipse/microprofile-reactive-streams-operators/issues/134[#134]) 43 | 44 | === Other Changes 45 | - Update to Jakarta EE8 APIs for MP 4.0 (link:https://github.com/eclipse/microprofile-reactive-streams-operators/issues/128[#128]) 46 | - Javadoc clarification: (link:https://github.com/eclipse/microprofile-reactive-streams-operators/issues/135[#135]) (link:https://github.com/eclipse/microprofile-reactive-streams-operators/issues/137[#137])(link:https://github.com/eclipse/microprofile-reactive-streams-operators/issues/142[#142]) (link:https://github.com/eclipse/microprofile-reactive-streams-operators/issues/129[#129]) 47 | - TCK clarification: (link:https://github.com/eclipse/microprofile-reactive-streams-operators/issues/141[#141]) 48 | 49 | -------------------------------------------------------------------------------- /spec/src/main/asciidoc/spi.asciidoc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | == SPI 18 | 19 | The API is responsible for building graphs of stages based on the operators the user invoked. 20 | This is done using builder classes that implement the fluent API that is used to compose the 21 | graph. These builders are obtained using the `ReactiveStreamsFactory` interface, a default 22 | implementation of which exists in the core package. 23 | The static methods of the `ReactiveStreams` class delegate to a service loaded implementation of `ReactiveStreamsFactory`, enabling the core implementation to be replaced. 24 | 25 | The stages form an SPI for `ReactiveStreamsEngine` implementations to build into a running stream. 26 | Examples of stages include: 27 | 28 | * Map 29 | * Filter 30 | * Elements to publish 31 | * Collect 32 | * Instances of Reactive Streams `Publisher`, `Subscriber` and `Processor` 33 | 34 | Each stage has either an inlet, an outlet, or both. 35 | A graph is a sequence of stages, consecutive stages will have an outlet and and inlet so that they can join - a graph that has a stage with no outlet followed by a stage that has an inlet is impossible, for example. 36 | Only the stages at the ends of the graph may have no inlet or outlet, whether these end stages have an inlet or outlet determines the shape of the overall graph. 37 | The API is responsible for ensuring that as graphs are constructed, only graphs that are logically possible are passed to the `ReactiveStreamsEngine` to construct. 38 | 39 | The implementation discovery relies on the Java `ServiceLoader` mechanism. 40 | However, for environments not supporting this mechanism, the user can pass custom implementations using the following methods: 41 | 42 | * `org.eclipse.microprofile.reactive.streams.operators.core.ReactiveStreamsEngineResolver#setInstance` - to configure the `ReactiveStreamEngine` 43 | * `org.eclipse.microprofile.reactive.streams.operators.spi.ReactiveStreamsFactoryResolver#setInstance` - to configure the `ReactiveStreamsFactory` 44 | 45 | These methods must be called before the access to the API and should only be used for integration purpose. 46 | -------------------------------------------------------------------------------- /spec/src/main/resources/META-INF/NOTICE: -------------------------------------------------------------------------------- 1 | ========================================================================= 2 | == NOTICE file corresponding to section 4(d) of the Apache License, == 3 | == Version 2.0, MicroProfile Reactive Streams Operators == 4 | ========================================================================= 5 | 6 | This product includes software developed at 7 | The Apache Software Foundation (http://www.apache.org/). 8 | 9 | 10 | SPDXVersion: SPDX-2.1 11 | PackageName: Eclipse Microprofile 12 | PackageHomePage: http://www.eclipse.org/microprofile 13 | PackageLicenseDeclared: Apache-2.0 14 | 15 | PackageCopyrightText: 16 | James Roper james@lightbend.com 17 | Clement Escoffier clement.escoffier@redhat.com 18 | Gordon Hutchison gordon_hutchison@uk.ibm.com 19 | -------------------------------------------------------------------------------- /tck/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 35 | 36 | 4.0.0 37 | 38 | 39 | org.eclipse.microprofile.reactive-streams-operators 40 | microprofile-reactive-streams-operators-parent 41 | 3.1-SNAPSHOT 42 | 43 | 44 | microprofile-reactive-streams-operators-tck 45 | Eclipse MicroProfile Reactive Streams Operators TCK 46 | Eclipse MicroProfile Reactive Streams Operators :: TCK 47 | 48 | 49 | 50 | 51 | org.eclipse.microprofile 52 | microprofile-tck-bom 53 | ${version.microprofile.tck.bom} 54 | pom 55 | import 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.eclipse.microprofile.reactive-streams-operators 63 | microprofile-reactive-streams-operators-api 64 | ${project.version} 65 | provided 66 | 67 | 68 | org.eclipse.microprofile.reactive-streams-operators 69 | microprofile-reactive-streams-operators-core 70 | ${project.version} 71 | test 72 | 73 | 74 | org.reactivestreams 75 | reactive-streams-tck 76 | 77 | 78 | 79 | org.jboss.arquillian.test 80 | arquillian-test-spi 81 | 82 | 83 | org.jboss.arquillian.testng 84 | arquillian-testng-container 85 | 86 | 87 | jakarta.enterprise 88 | jakarta.enterprise.cdi-api 89 | provided 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/DefaultReactiveStreamsFactory.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck; 21 | 22 | import java.util.concurrent.CompletionStage; 23 | import java.util.function.Supplier; 24 | import java.util.function.UnaryOperator; 25 | 26 | import org.eclipse.microprofile.reactive.streams.operators.ProcessorBuilder; 27 | import org.eclipse.microprofile.reactive.streams.operators.PublisherBuilder; 28 | import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreams; 29 | import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreamsFactory; 30 | import org.eclipse.microprofile.reactive.streams.operators.SubscriberBuilder; 31 | import org.reactivestreams.Processor; 32 | import org.reactivestreams.Publisher; 33 | import org.reactivestreams.Subscriber; 34 | 35 | /** 36 | * Implementation of the {@link ReactiveStreamsFactory} that delegates to {@link ReactiveStreams} static factory 37 | * methods. 38 | */ 39 | public class DefaultReactiveStreamsFactory implements ReactiveStreamsFactory { 40 | 41 | @Override 42 | public PublisherBuilder fromPublisher(Publisher publisher) { 43 | return ReactiveStreams.fromPublisher(publisher); 44 | } 45 | 46 | @Override 47 | public PublisherBuilder of(T t) { 48 | return ReactiveStreams.of(t); 49 | } 50 | 51 | @Override 52 | public PublisherBuilder of(T... ts) { 53 | return ReactiveStreams.of(ts); 54 | } 55 | 56 | @Override 57 | public PublisherBuilder empty() { 58 | return ReactiveStreams.empty(); 59 | } 60 | 61 | @Override 62 | public PublisherBuilder ofNullable(T t) { 63 | return ReactiveStreams.ofNullable(t); 64 | } 65 | 66 | @Override 67 | public PublisherBuilder fromIterable(Iterable ts) { 68 | return ReactiveStreams.fromIterable(ts); 69 | } 70 | 71 | @Override 72 | public PublisherBuilder failed(Throwable t) { 73 | return ReactiveStreams.failed(t); 74 | } 75 | 76 | @Override 77 | public ProcessorBuilder builder() { 78 | return ReactiveStreams.builder(); 79 | } 80 | 81 | @Override 82 | public ProcessorBuilder fromProcessor(Processor processor) { 83 | return ReactiveStreams.fromProcessor(processor); 84 | } 85 | 86 | @Override 87 | public SubscriberBuilder fromSubscriber(Subscriber subscriber) { 88 | return ReactiveStreams.fromSubscriber(subscriber); 89 | } 90 | 91 | @Override 92 | public PublisherBuilder iterate(T seed, UnaryOperator f) { 93 | return ReactiveStreams.iterate(seed, f); 94 | } 95 | 96 | @Override 97 | public PublisherBuilder generate(Supplier s) { 98 | return ReactiveStreams.generate(s); 99 | } 100 | 101 | @Override 102 | public PublisherBuilder concat(PublisherBuilder a, PublisherBuilder b) { 103 | return ReactiveStreams.concat(a, b); 104 | } 105 | 106 | @Override 107 | public PublisherBuilder fromCompletionStage(CompletionStage completionStage) { 108 | return ReactiveStreams.fromCompletionStage(completionStage); 109 | } 110 | 111 | @Override 112 | public PublisherBuilder fromCompletionStageNullable(CompletionStage completionStage) { 113 | return ReactiveStreams.fromCompletionStageNullable(completionStage); 114 | } 115 | 116 | @Override 117 | public ProcessorBuilder coupled(SubscriberBuilder subscriber, 118 | PublisherBuilder publisher) { 119 | return ReactiveStreams.coupled(subscriber, publisher); 120 | } 121 | 122 | @Override 123 | public ProcessorBuilder coupled(Subscriber subscriber, Publisher publisher) { 124 | return ReactiveStreams.coupled(subscriber, publisher); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/ReactiveStreamsTck.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2023 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck; 21 | 22 | import java.util.ArrayList; 23 | import java.util.List; 24 | import java.util.concurrent.Executors; 25 | import java.util.concurrent.ScheduledExecutorService; 26 | 27 | import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreamsFactory; 28 | import org.eclipse.microprofile.reactive.streams.operators.spi.ReactiveStreamsEngine; 29 | import org.eclipse.microprofile.reactive.streams.operators.tck.api.ReactiveStreamsApiVerification; 30 | import org.eclipse.microprofile.reactive.streams.operators.tck.spi.ReactiveStreamsSpiVerification; 31 | import org.reactivestreams.tck.TestEnvironment; 32 | import org.testng.annotations.AfterSuite; 33 | import org.testng.annotations.Factory; 34 | 35 | /** 36 | * The Reactive Streams TCK. 37 | *

38 | * A concrete class that extends this class is all that is needed to verify a {@link ReactiveStreamsEngine} against this 39 | * TCK. 40 | *

41 | * It produces a number of TestNG test classes via the TestNG {@link Factory} annotated {@link #allTests()} method. 42 | * 43 | * @param 44 | * The type of the Reactive Streams engine. 45 | */ 46 | public abstract class ReactiveStreamsTck { 47 | 48 | private final TestEnvironment testEnvironment; 49 | private E engine; 50 | private ReactiveStreamsFactory rs; 51 | private ScheduledExecutorService executorService; 52 | 53 | public ReactiveStreamsTck(TestEnvironment testEnvironment) { 54 | this.testEnvironment = testEnvironment; 55 | } 56 | 57 | /** 58 | * Override to provide the reactive streams engine. 59 | */ 60 | protected abstract E createEngine(); 61 | 62 | /** 63 | * Create the reactive streams factory to use. By default, will use one backed by the ReactiveStreams static factory 64 | * methods, that is, using the ServiceLoader to locate one. 65 | */ 66 | protected ReactiveStreamsFactory createFactory() { 67 | return new DefaultReactiveStreamsFactory(); 68 | } 69 | 70 | /** 71 | * Override to implement custom shutdown logic for the Reactive Streams engine. 72 | */ 73 | protected void shutdownEngine(E engine) { 74 | // By default, do nothing. 75 | } 76 | 77 | /** 78 | * Override this to disable/enable tests, useful for debugging one test at a time. 79 | */ 80 | protected boolean isEnabled(Object test) { 81 | return true; 82 | } 83 | 84 | @AfterSuite(alwaysRun = true) 85 | public void shutdownEngine() { 86 | if (engine != null) { 87 | shutdownEngine(engine); 88 | } 89 | if (executorService != null) { 90 | shutdownExecutorService(executorService); 91 | } 92 | } 93 | 94 | /** 95 | * Override this to provide a different ScheduledExecutorService 96 | */ 97 | protected ScheduledExecutorService createExecutorService() { 98 | return Executors.newScheduledThreadPool(4); 99 | } 100 | 101 | /** 102 | * Override this to customize the shutdown of a ScheduledExecutorService 103 | */ 104 | protected void shutdownExecutorService(ScheduledExecutorService executorService) { 105 | executorService.shutdown(); 106 | } 107 | 108 | @Factory 109 | public Object[] allTests() { 110 | engine = createEngine(); 111 | rs = createFactory(); 112 | executorService = createExecutorService(); 113 | 114 | ReactiveStreamsApiVerification apiVerification = new ReactiveStreamsApiVerification(rs); 115 | ReactiveStreamsSpiVerification spiVerification = 116 | new ReactiveStreamsSpiVerification(testEnvironment, rs, engine, executorService); 117 | 118 | // Add tests that aren't dependent on the dependencies. 119 | List allTests = new ArrayList<>(); 120 | 121 | allTests.addAll(apiVerification.allTests()); 122 | allTests.addAll(spiVerification.allTests()); 123 | 124 | return allTests.stream().filter(this::isEnabled).toArray(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/api/AbstractReactiveStreamsApiVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.api; 21 | 22 | import static org.testng.Assert.assertEquals; 23 | import static org.testng.Assert.assertTrue; 24 | 25 | import java.util.Collections; 26 | 27 | import org.eclipse.microprofile.reactive.streams.operators.CompletionRunner; 28 | import org.eclipse.microprofile.reactive.streams.operators.ProcessorBuilder; 29 | import org.eclipse.microprofile.reactive.streams.operators.PublisherBuilder; 30 | import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreamsFactory; 31 | import org.eclipse.microprofile.reactive.streams.operators.SubscriberBuilder; 32 | import org.eclipse.microprofile.reactive.streams.operators.spi.Graph; 33 | import org.eclipse.microprofile.reactive.streams.operators.spi.Stage; 34 | import org.eclipse.microprofile.reactive.streams.operators.spi.ToGraphable; 35 | 36 | public abstract class AbstractReactiveStreamsApiVerification { 37 | 38 | protected final ReactiveStreamsFactory rs; 39 | 40 | public AbstractReactiveStreamsApiVerification(ReactiveStreamsFactory rs) { 41 | this.rs = rs; 42 | } 43 | 44 | protected Graph graphFor(PublisherBuilder pb) { 45 | return objGraphFor(pb); 46 | } 47 | 48 | protected Graph graphFor(SubscriberBuilder sb) { 49 | return objGraphFor(sb); 50 | } 51 | 52 | protected Graph graphFor(ProcessorBuilder pb) { 53 | return objGraphFor(pb); 54 | } 55 | 56 | protected Graph graphFor(CompletionRunner cr) { 57 | return objGraphFor(cr); 58 | } 59 | 60 | private Graph objGraphFor(Object o) { 61 | return ((ToGraphable) o).toGraph(); 62 | } 63 | 64 | protected void assertEmptyStage(Stage stage) { 65 | assertTrue(stage instanceof Stage.Of); 66 | assertEquals(((Stage.Of) stage).getElements(), Collections.emptyList()); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/api/CompletionRunnerVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.api; 21 | 22 | import static org.testng.Assert.assertEquals; 23 | import static org.testng.Assert.assertSame; 24 | import static org.testng.Assert.assertTrue; 25 | 26 | import java.util.Iterator; 27 | import java.util.concurrent.CompletableFuture; 28 | import java.util.concurrent.CompletionStage; 29 | import java.util.concurrent.atomic.AtomicReference; 30 | 31 | import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreamsFactory; 32 | import org.eclipse.microprofile.reactive.streams.operators.spi.Graph; 33 | import org.eclipse.microprofile.reactive.streams.operators.spi.ReactiveStreamsEngine; 34 | import org.eclipse.microprofile.reactive.streams.operators.spi.Stage; 35 | import org.eclipse.microprofile.reactive.streams.operators.spi.SubscriberWithCompletionStage; 36 | import org.eclipse.microprofile.reactive.streams.operators.spi.UnsupportedStageException; 37 | import org.reactivestreams.Processor; 38 | import org.reactivestreams.Publisher; 39 | import org.testng.annotations.Test; 40 | 41 | /** 42 | * Verification for the {@link org.eclipse.microprofile.reactive.streams.operators.CompletionRunner} class. 43 | */ 44 | public class CompletionRunnerVerification extends AbstractReactiveStreamsApiVerification { 45 | 46 | public CompletionRunnerVerification(ReactiveStreamsFactory rs) { 47 | super(rs); 48 | } 49 | 50 | @Test 51 | public void run() { 52 | AtomicReference builtGraph = new AtomicReference<>(); 53 | CompletableFuture expected = new CompletableFuture(); 54 | CompletionStage returned = rs.empty().cancel().run(new ReactiveStreamsEngine() { 55 | @Override 56 | public Publisher buildPublisher(Graph graph) throws UnsupportedStageException { 57 | throw new RuntimeException("Wrong method invoked"); 58 | } 59 | 60 | @Override 61 | public SubscriberWithCompletionStage buildSubscriber(Graph graph) 62 | throws UnsupportedStageException { 63 | throw new RuntimeException("Wrong method invoked"); 64 | } 65 | 66 | @Override 67 | public Processor buildProcessor(Graph graph) throws UnsupportedStageException { 68 | throw new RuntimeException("Wrong method invoked"); 69 | } 70 | 71 | @Override 72 | public CompletionStage buildCompletion(Graph graph) throws UnsupportedStageException { 73 | builtGraph.set(graph); 74 | return expected; 75 | } 76 | }); 77 | 78 | assertSame(returned, expected); 79 | assertEquals(builtGraph.get().getStages().size(), 2); 80 | Iterator stages = builtGraph.get().getStages().iterator(); 81 | assertEmptyStage(stages.next()); 82 | assertTrue(stages.next() instanceof Stage.Cancel); 83 | } 84 | 85 | @Test(expectedExceptions = NullPointerException.class) 86 | public void runNull() { 87 | rs.empty().cancel().run(null); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/api/CompletionSubscriberVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.api; 21 | 22 | import static org.testng.Assert.assertEquals; 23 | import static org.testng.Assert.assertSame; 24 | import static org.testng.Assert.assertTrue; 25 | 26 | import java.util.ArrayDeque; 27 | import java.util.Deque; 28 | import java.util.concurrent.CompletableFuture; 29 | 30 | import org.eclipse.microprofile.reactive.streams.operators.CompletionSubscriber; 31 | import org.reactivestreams.Subscriber; 32 | import org.reactivestreams.Subscription; 33 | import org.testng.annotations.Test; 34 | 35 | /** 36 | * Verification for {@link org.eclipse.microprofile.reactive.streams.operators.CompletionSubscriber}. 37 | */ 38 | public class CompletionSubscriberVerification { 39 | 40 | @Test 41 | public void completionSubscriberShouldReturnSameCompletionStage() { 42 | CompletableFuture future = new CompletableFuture(); 43 | assertSame(CompletionSubscriber.of(Mocks.SUBSCRIBER, future).getCompletion(), future); 44 | } 45 | 46 | @Test 47 | public void completionSubscriberShouldDelegateToSubscriber() { 48 | Deque calls = new ArrayDeque<>(); 49 | CompletionSubscriber subscriber = CompletionSubscriber.of(new Subscriber() { 50 | @Override 51 | public void onSubscribe(Subscription s) { 52 | calls.add(s); 53 | } 54 | 55 | @Override 56 | public void onNext(Object o) { 57 | calls.add(o); 58 | } 59 | 60 | @Override 61 | public void onError(Throwable t) { 62 | calls.add(t); 63 | } 64 | 65 | @Override 66 | public void onComplete() { 67 | calls.add("onComplete"); 68 | } 69 | }, new CompletableFuture<>()); 70 | 71 | subscriber.onSubscribe(Mocks.SUBSCRIPTION); 72 | assertSame(calls.removeFirst(), Mocks.SUBSCRIPTION); 73 | subscriber.onNext("element"); 74 | assertEquals(calls.removeFirst(), "element"); 75 | Exception e = new Exception(); 76 | subscriber.onError(e); 77 | assertSame(calls.removeFirst(), e); 78 | subscriber.onComplete(); 79 | assertEquals(calls.removeFirst(), "onComplete"); 80 | assertTrue(calls.isEmpty()); 81 | } 82 | 83 | @Test(expectedExceptions = NullPointerException.class) 84 | public void completionSubscriberShouldNotAcceptNullSubscriber() { 85 | CompletionSubscriber.of(null, new CompletableFuture<>()); 86 | } 87 | 88 | @Test(expectedExceptions = NullPointerException.class) 89 | public void completionSubscriberShouldNotAcceptNullCompletionStage() { 90 | CompletionSubscriber.of(Mocks.SUBSCRIBER, null); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/api/ReactiveStreamsApiVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.api; 21 | 22 | import java.util.Arrays; 23 | import java.util.List; 24 | 25 | import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreamsFactory; 26 | 27 | /** 28 | * Factory for tests that verify the API itself without dependence on an SPI implementation. 29 | *

30 | * These tests serve not only to test the API provided by the MicroProfile API project, but also to test clean room 31 | * implementations of the API, that is, implementations that don't depend on the MicroProfile API artifact. 32 | */ 33 | public class ReactiveStreamsApiVerification { 34 | 35 | private final ReactiveStreamsFactory rs; 36 | 37 | public ReactiveStreamsApiVerification(ReactiveStreamsFactory rs) { 38 | this.rs = rs; 39 | } 40 | 41 | public List allTests() { 42 | return Arrays.asList( 43 | new ReactiveStreamsVerification(rs), 44 | new PublisherBuilderVerification(rs), 45 | new ProcessorBuilderVerification(rs), 46 | new SubscriberBuilderVerification(rs), 47 | new CompletionRunnerVerification(rs), 48 | new CompletionSubscriberVerification()); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/api/SubscriberBuilderVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.api; 21 | 22 | import static org.testng.Assert.assertEquals; 23 | import static org.testng.Assert.assertTrue; 24 | 25 | import java.util.concurrent.CompletableFuture; 26 | import java.util.concurrent.CompletionStage; 27 | import java.util.concurrent.atomic.AtomicReference; 28 | 29 | import org.eclipse.microprofile.reactive.streams.operators.CompletionSubscriber; 30 | import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreamsFactory; 31 | import org.eclipse.microprofile.reactive.streams.operators.spi.Graph; 32 | import org.eclipse.microprofile.reactive.streams.operators.spi.ReactiveStreamsEngine; 33 | import org.eclipse.microprofile.reactive.streams.operators.spi.Stage; 34 | import org.eclipse.microprofile.reactive.streams.operators.spi.SubscriberWithCompletionStage; 35 | import org.eclipse.microprofile.reactive.streams.operators.spi.UnsupportedStageException; 36 | import org.reactivestreams.Processor; 37 | import org.reactivestreams.Publisher; 38 | import org.reactivestreams.Subscriber; 39 | import org.testng.annotations.Test; 40 | 41 | /** 42 | * Verification for the {@link org.eclipse.microprofile.reactive.streams.operators.SubscriberBuilder} class. 43 | */ 44 | public class SubscriberBuilderVerification extends AbstractReactiveStreamsApiVerification { 45 | 46 | public SubscriberBuilderVerification(ReactiveStreamsFactory rs) { 47 | super(rs); 48 | } 49 | 50 | @Test 51 | public void build() { 52 | AtomicReference builtGraph = new AtomicReference<>(); 53 | CompletionStage expectedCs = new CompletableFuture(); 54 | CompletionSubscriber returned = rs.builder().cancel().build(new ReactiveStreamsEngine() { 55 | @Override 56 | public Publisher buildPublisher(Graph graph) throws UnsupportedStageException { 57 | throw new RuntimeException("Wrong method invoked"); 58 | } 59 | 60 | @Override 61 | public SubscriberWithCompletionStage buildSubscriber(Graph graph) 62 | throws UnsupportedStageException { 63 | builtGraph.set(graph); 64 | return new SubscriberWithCompletionStage() { 65 | @Override 66 | public CompletionStage getCompletion() { 67 | return expectedCs; 68 | } 69 | 70 | @Override 71 | public Subscriber getSubscriber() { 72 | return Mocks.SUBSCRIBER; 73 | } 74 | }; 75 | } 76 | 77 | @Override 78 | public Processor buildProcessor(Graph graph) throws UnsupportedStageException { 79 | throw new RuntimeException("Wrong method invoked"); 80 | } 81 | 82 | @Override 83 | public CompletionStage buildCompletion(Graph graph) throws UnsupportedStageException { 84 | throw new RuntimeException("Wrong method invoked"); 85 | } 86 | }); 87 | 88 | assertEquals(returned.getCompletion(), expectedCs); 89 | assertEquals(builtGraph.get().getStages().size(), 1); 90 | assertTrue(builtGraph.get().getStages().iterator().next() instanceof Stage.Cancel); 91 | } 92 | 93 | @Test(expectedExceptions = NullPointerException.class) 94 | public void buildNull() { 95 | rs.builder().cancel().build(null); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/arquillian/ReactiveStreamsCdiTck.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.arquillian; 21 | 22 | import org.eclipse.microprofile.reactive.streams.operators.spi.ReactiveStreamsEngine; 23 | import org.eclipse.microprofile.reactive.streams.operators.tck.ReactiveStreamsTck; 24 | import org.reactivestreams.tck.TestEnvironment; 25 | 26 | import jakarta.enterprise.context.ApplicationScoped; 27 | import jakarta.inject.Inject; 28 | 29 | @ApplicationScoped 30 | public class ReactiveStreamsCdiTck extends ReactiveStreamsTck { 31 | 32 | public ReactiveStreamsCdiTck() { 33 | super(new TestEnvironment()); 34 | } 35 | 36 | @Inject 37 | private ReactiveStreamsEngine engine; 38 | 39 | @Override 40 | protected ReactiveStreamsEngine createEngine() { 41 | return engine; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/spi/CancelStageVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.spi; 21 | 22 | import java.util.Collections; 23 | import java.util.List; 24 | import java.util.concurrent.CompletableFuture; 25 | import java.util.concurrent.CompletionStage; 26 | 27 | import org.eclipse.microprofile.reactive.streams.operators.SubscriberBuilder; 28 | import org.reactivestreams.Subscriber; 29 | import org.reactivestreams.Subscription; 30 | import org.testng.SkipException; 31 | import org.testng.annotations.Test; 32 | 33 | /** 34 | * Verification for the cancel stage. 35 | */ 36 | public class CancelStageVerification extends AbstractStageVerification { 37 | 38 | CancelStageVerification(ReactiveStreamsSpiVerification.VerificationDeps deps) { 39 | super(deps); 40 | } 41 | 42 | @Test 43 | public void cancelStageShouldCancelTheStage() { 44 | CompletableFuture cancelled = new CompletableFuture<>(); 45 | CompletionStage result = rs.fromPublisher(s -> s.onSubscribe(new Subscription() { 46 | @Override 47 | public void request(long n) { 48 | } 49 | 50 | @Override 51 | public void cancel() { 52 | cancelled.complete(null); 53 | } 54 | })).cancel().run(getEngine()); 55 | await(cancelled); 56 | await(result); 57 | } 58 | 59 | @Test 60 | public void cancelStageShouldIgnoreAnyUpstreamFailures() { 61 | await(rs.failed(new QuietRuntimeException()) 62 | .cancel().run(getEngine())); 63 | } 64 | 65 | @Test 66 | public void cancelSubscriberBuilderShouldBeReusable() { 67 | SubscriberBuilder cancel = rs.builder().cancel(); 68 | await(rs.of("a").to(cancel).run(getEngine())); 69 | await(rs.of("b").to(cancel).run(getEngine())); 70 | } 71 | 72 | @Override 73 | List reactiveStreamsTckVerifiers() { 74 | return Collections.singletonList(new SubscriberVerification()); 75 | } 76 | 77 | public class SubscriberVerification extends StageSubscriberBlackboxVerification { 78 | @Override 79 | public Subscriber createSubscriber() { 80 | return rs.builder().cancel().build(getEngine()); 81 | } 82 | 83 | @Override 84 | public Object createElement(int element) { 85 | return element; 86 | } 87 | 88 | @Override 89 | public void required_spec201_blackbox_mustSignalDemandViaSubscriptionRequest() throws Throwable { 90 | throw new SkipException("Cancel subscriber does not need to signal demand."); 91 | } 92 | 93 | @Override 94 | public void required_spec209_blackbox_mustBePreparedToReceiveAnOnCompleteSignalWithPrecedingRequestCall() 95 | throws Throwable { 96 | throw new SkipException("Cancel subscriber does not need to signal demand."); 97 | } 98 | 99 | @Override 100 | public void required_spec210_blackbox_mustBePreparedToReceiveAnOnErrorSignalWithPrecedingRequestCall() 101 | throws Throwable { 102 | throw new SkipException("Cancel subscriber does not need to signal demand."); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/spi/EmptyProcessorVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.spi; 21 | 22 | import java.util.Collections; 23 | import java.util.List; 24 | 25 | import org.reactivestreams.Processor; 26 | 27 | /** 28 | * Verification for an empty processor, ie, the processor returned from rs.builder().buildRs(). 29 | */ 30 | public class EmptyProcessorVerification extends AbstractStageVerification { 31 | 32 | public EmptyProcessorVerification(ReactiveStreamsSpiVerification.VerificationDeps deps) { 33 | super(deps); 34 | } 35 | 36 | @Override 37 | List reactiveStreamsTckVerifiers() { 38 | return Collections.singletonList(new ProcessorVerification()); 39 | } 40 | 41 | public class ProcessorVerification extends StageProcessorVerification { 42 | @Override 43 | public Processor createIdentityProcessor(int bufferSize) { 44 | return rs.builder().buildRs(getEngine()); 45 | } 46 | 47 | @Override 48 | public Integer createElement(int element) { 49 | return element; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/spi/FilterStageVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.spi; 21 | 22 | import static org.testng.Assert.assertEquals; 23 | 24 | import java.util.Arrays; 25 | import java.util.Collections; 26 | import java.util.List; 27 | import java.util.concurrent.CompletableFuture; 28 | import java.util.concurrent.CompletionStage; 29 | 30 | import org.eclipse.microprofile.reactive.streams.operators.ProcessorBuilder; 31 | import org.reactivestreams.Processor; 32 | import org.reactivestreams.Publisher; 33 | import org.testng.annotations.Test; 34 | 35 | /** 36 | * Verification for the filter stage. 37 | */ 38 | public class FilterStageVerification extends AbstractStageVerification { 39 | 40 | FilterStageVerification(ReactiveStreamsSpiVerification.VerificationDeps deps) { 41 | super(deps); 42 | } 43 | 44 | @Test 45 | public void filterStageShouldFilterElements() { 46 | assertEquals(await(rs.of(1, 2, 3, 4, 5, 6) 47 | .filter(i -> (i & 1) == 1) 48 | .toList() 49 | .run(getEngine())), Arrays.asList(1, 3, 5)); 50 | } 51 | 52 | @Test(expectedExceptions = QuietRuntimeException.class, expectedExceptionsMessageRegExp = "failed") 53 | public void filterStageShouldPropagateExceptions() { 54 | CompletableFuture cancelled = new CompletableFuture<>(); 55 | CompletionStage> result = infiniteStream() 56 | .onTerminate(() -> cancelled.complete(null)) 57 | .filter(foo -> { 58 | throw new QuietRuntimeException("failed"); 59 | }) 60 | .toList() 61 | .run(getEngine()); 62 | await(cancelled); 63 | await(result); 64 | } 65 | 66 | @Test(expectedExceptions = QuietRuntimeException.class, expectedExceptionsMessageRegExp = "failed") 67 | public void filterStageShouldPropagateUpstreamExceptions() { 68 | await(rs.failed(new QuietRuntimeException("failed")) 69 | .filter(foo -> true) 70 | .toList() 71 | .run(getEngine())); 72 | } 73 | 74 | @Test 75 | public void filterStageShouldPropagateCancel() { 76 | CompletableFuture cancelled = new CompletableFuture<>(); 77 | await(infiniteStream().onTerminate(() -> cancelled.complete(null)).filter(i -> i < 3).cancel() 78 | .run(getEngine())); 79 | await(cancelled); 80 | } 81 | 82 | @Test 83 | public void filterStageBuilderShouldBeReusable() { 84 | ProcessorBuilder filter = rs.builder().filter(i -> i < 3); 85 | assertEquals(await(rs.of(1, 2, 3).via(filter).toList().run(getEngine())), Arrays.asList(1, 2)); 86 | assertEquals(await(rs.of(1, 2, 3).via(filter).toList().run(getEngine())), Arrays.asList(1, 2)); 87 | } 88 | 89 | @Override 90 | List reactiveStreamsTckVerifiers() { 91 | return Collections.singletonList( 92 | new ProcessorVerification()); 93 | } 94 | 95 | class ProcessorVerification extends StageProcessorVerification { 96 | 97 | @Override 98 | public Processor createIdentityProcessor(int bufferSize) { 99 | return rs.builder().filter(i -> true).buildRs(getEngine()); 100 | } 101 | 102 | @Override 103 | public Publisher createFailedPublisher() { 104 | return rs.failed(new RuntimeException("failed")) 105 | .filter(i -> true).buildRs(getEngine()); 106 | } 107 | 108 | @Override 109 | public Integer createElement(int element) { 110 | return element; 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/spi/FindFirstStageVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.spi; 21 | 22 | import static org.testng.Assert.assertEquals; 23 | 24 | import java.util.Collections; 25 | import java.util.List; 26 | import java.util.Optional; 27 | import java.util.concurrent.CompletableFuture; 28 | 29 | import org.reactivestreams.Subscriber; 30 | import org.testng.annotations.Test; 31 | 32 | /** 33 | * Verification for find first stage. 34 | */ 35 | public class FindFirstStageVerification extends AbstractStageVerification { 36 | 37 | FindFirstStageVerification(ReactiveStreamsSpiVerification.VerificationDeps deps) { 38 | super(deps); 39 | } 40 | 41 | @Test 42 | public void findFirstStageShouldFindTheFirstElement() { 43 | assertEquals(await(rs.of(1, 2, 3) 44 | .findFirst().run(getEngine())), Optional.of(1)); 45 | } 46 | 47 | @Test 48 | public void findFirstStageShouldFindTheFirstElementInSingleElementStream() { 49 | assertEquals(await(rs.of(1) 50 | .findFirst().run(getEngine())), Optional.of(1)); 51 | } 52 | 53 | @Test 54 | public void findFirstStageShouldReturnEmptyForEmptyStream() { 55 | assertEquals(await(rs.of() 56 | .findFirst().run(getEngine())), Optional.empty()); 57 | } 58 | 59 | @Test 60 | public void findFirstStageShouldCancelUpstream() { 61 | CompletableFuture cancelled = new CompletableFuture<>(); 62 | assertEquals(await(infiniteStream().onTerminate(() -> cancelled.complete(null)) 63 | .findFirst().run(getEngine())), Optional.of(1)); 64 | await(cancelled); 65 | } 66 | 67 | @Test(expectedExceptions = QuietRuntimeException.class, expectedExceptionsMessageRegExp = "failed") 68 | public void findFirstStageShouldPropagateErrors() { 69 | await(rs.failed(new QuietRuntimeException("failed")) 70 | .findFirst().run(getEngine())); 71 | } 72 | 73 | @Test 74 | public void findFirstStageShouldBeReusable() { 75 | assertEquals(await(rs.of(1, 2, 3) 76 | .findFirst().run(getEngine())), Optional.of(1)); 77 | } 78 | 79 | @Override 80 | List reactiveStreamsTckVerifiers() { 81 | return Collections.singletonList(new SubscriberVerification()); 82 | } 83 | 84 | class SubscriberVerification extends StageSubscriberBlackboxVerification { 85 | @Override 86 | public Subscriber createSubscriber() { 87 | return rs.builder().findFirst().build(getEngine()); 88 | } 89 | 90 | @Override 91 | public Integer createElement(int element) { 92 | return element; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/spi/MapStageVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.spi; 21 | 22 | import static org.testng.Assert.assertEquals; 23 | 24 | import java.util.Arrays; 25 | import java.util.Collections; 26 | import java.util.List; 27 | import java.util.concurrent.CompletableFuture; 28 | import java.util.concurrent.CompletionStage; 29 | import java.util.function.Function; 30 | 31 | import org.eclipse.microprofile.reactive.streams.operators.ProcessorBuilder; 32 | import org.reactivestreams.Processor; 33 | import org.reactivestreams.Publisher; 34 | import org.testng.annotations.Test; 35 | 36 | public class MapStageVerification extends AbstractStageVerification { 37 | 38 | MapStageVerification(ReactiveStreamsSpiVerification.VerificationDeps deps) { 39 | super(deps); 40 | } 41 | 42 | @Test 43 | public void mapStageShouldMapElements() { 44 | assertEquals(await(rs.of(1, 2, 3) 45 | .map(Object::toString) 46 | .toList() 47 | .run(getEngine())), Arrays.asList("1", "2", "3")); 48 | } 49 | 50 | @Test(expectedExceptions = QuietRuntimeException.class, expectedExceptionsMessageRegExp = "failed") 51 | public void mapStageShouldHandleExceptions() { 52 | CompletableFuture cancelled = new CompletableFuture<>(); 53 | CompletionStage> result = infiniteStream() 54 | .onTerminate(() -> cancelled.complete(null)) 55 | .map(foo -> { 56 | throw new QuietRuntimeException("failed"); 57 | }) 58 | .toList() 59 | .run(getEngine()); 60 | await(cancelled); 61 | await(result); 62 | } 63 | 64 | @Test(expectedExceptions = QuietRuntimeException.class, expectedExceptionsMessageRegExp = "failed") 65 | public void mapStageShouldPropagateUpstreamExceptions() { 66 | await(rs.failed(new QuietRuntimeException("failed")) 67 | .map(Function.identity()) 68 | .toList() 69 | .run(getEngine())); 70 | } 71 | 72 | @Test(expectedExceptions = NullPointerException.class) 73 | public void mapStageShouldFailIfNullReturned() { 74 | CompletableFuture cancelled = new CompletableFuture<>(); 75 | CompletionStage> result = infiniteStream().onTerminate(() -> cancelled.complete(null)) 76 | .map(t -> null) 77 | .toList().run(getEngine()); 78 | await(cancelled); 79 | await(result); 80 | } 81 | 82 | @Test 83 | public void mapStageBuilderShouldBeReusable() { 84 | ProcessorBuilder map = rs.builder().map(i -> i + 1); 85 | assertEquals(await(rs.of(1, 2, 3).via(map).toList().run(getEngine())), Arrays.asList(2, 3, 4)); 86 | assertEquals(await(rs.of(4, 5, 6).via(map).toList().run(getEngine())), Arrays.asList(5, 6, 7)); 87 | } 88 | 89 | @Override 90 | List reactiveStreamsTckVerifiers() { 91 | return Collections.singletonList( 92 | new ProcessorVerification()); 93 | } 94 | 95 | public class ProcessorVerification extends StageProcessorVerification { 96 | 97 | @Override 98 | public Processor createIdentityProcessor(int bufferSize) { 99 | return rs.builder().map(Function.identity()).buildRs(getEngine()); 100 | } 101 | 102 | @Override 103 | public Publisher createFailedPublisher() { 104 | return rs.failed(new RuntimeException("failed")) 105 | .map(Function.identity()).buildRs(getEngine()); 106 | } 107 | 108 | @Override 109 | public Integer createElement(int element) { 110 | return element; 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/spi/PeekStageVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.spi; 21 | 22 | import static org.testng.Assert.assertEquals; 23 | import static org.testng.Assert.assertFalse; 24 | 25 | import java.util.Arrays; 26 | import java.util.Collections; 27 | import java.util.List; 28 | import java.util.concurrent.CompletableFuture; 29 | import java.util.concurrent.CompletionStage; 30 | import java.util.concurrent.atomic.AtomicBoolean; 31 | import java.util.concurrent.atomic.AtomicInteger; 32 | import java.util.function.Consumer; 33 | 34 | import org.eclipse.microprofile.reactive.streams.operators.ProcessorBuilder; 35 | import org.reactivestreams.Processor; 36 | import org.reactivestreams.Publisher; 37 | import org.testng.annotations.Test; 38 | 39 | public class PeekStageVerification extends AbstractStageVerification { 40 | 41 | PeekStageVerification(ReactiveStreamsSpiVerification.VerificationDeps deps) { 42 | super(deps); 43 | } 44 | 45 | @Test 46 | public void peekStageShouldNotModifyElements() { 47 | AtomicInteger count = new AtomicInteger(); 48 | assertEquals(await(rs.of(1, 2, 3) 49 | .peek(i -> count.incrementAndGet()) 50 | .toList() 51 | .run(getEngine())), Arrays.asList(1, 2, 3)); 52 | assertEquals(count.get(), 3); 53 | } 54 | 55 | @Test(expectedExceptions = QuietRuntimeException.class, expectedExceptionsMessageRegExp = "failed") 56 | public void peekStageShouldHandleExceptions() { 57 | CompletableFuture cancelled = new CompletableFuture<>(); 58 | CompletionStage> result = infiniteStream() 59 | .onTerminate(() -> cancelled.complete(null)) 60 | .peek(x -> { 61 | throw new QuietRuntimeException("failed"); 62 | }) 63 | .toList() 64 | .run(getEngine()); 65 | await(cancelled); 66 | await(result); 67 | } 68 | 69 | @Test(expectedExceptions = QuietRuntimeException.class, expectedExceptionsMessageRegExp = "failed") 70 | public void peekStageShouldPropagateUpstreamExceptions() { 71 | await(rs.failed(new QuietRuntimeException("failed")) 72 | .peek(x -> { 73 | }) 74 | .toList() 75 | .run(getEngine())); 76 | } 77 | 78 | public void peekStageShouldNotBeExecutedForEmptyStreams() { 79 | AtomicBoolean invoked = new AtomicBoolean(); 80 | await(rs.empty() 81 | .peek(x -> invoked.set(true)) 82 | .toList() 83 | .run(getEngine())); 84 | assertFalse(invoked.get()); 85 | } 86 | 87 | @Test 88 | public void peekStageShouldBeReusable() { 89 | ProcessorBuilder peek = rs.builder().peek(t -> { 90 | }); 91 | 92 | assertEquals(await(rs.of(1, 2, 3).via(peek).toList().run(getEngine())), Arrays.asList(1, 2, 3)); 93 | assertEquals(await(rs.of(4, 5, 6).via(peek).toList().run(getEngine())), Arrays.asList(4, 5, 6)); 94 | } 95 | 96 | @Override 97 | List reactiveStreamsTckVerifiers() { 98 | return Collections.singletonList( 99 | new ProcessorVerification()); 100 | } 101 | 102 | public class ProcessorVerification extends StageProcessorVerification { 103 | 104 | private Consumer noop = x -> { 105 | }; 106 | 107 | @Override 108 | public Processor createIdentityProcessor(int bufferSize) { 109 | return rs.builder().peek(noop).buildRs(getEngine()); 110 | } 111 | 112 | @Override 113 | public Publisher createFailedPublisher() { 114 | return rs.failed(new RuntimeException("failed")) 115 | .peek(noop).buildRs(getEngine()); 116 | } 117 | 118 | @Override 119 | public Integer createElement(int element) { 120 | return element; 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/spi/QuietRuntimeException.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.spi; 21 | 22 | /** 23 | * RuntimeException with no stack trace for expected failures, to make logging not so noisy. 24 | */ 25 | public class QuietRuntimeException extends RuntimeException { 26 | public QuietRuntimeException() { 27 | this(null, null); 28 | } 29 | 30 | public QuietRuntimeException(String message) { 31 | this(message, null); 32 | } 33 | 34 | public QuietRuntimeException(String message, Throwable cause) { 35 | super(message, cause, true, false); 36 | } 37 | 38 | public QuietRuntimeException(Throwable cause) { 39 | this(null, cause); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/spi/ReactiveStreamsSpiVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.spi; 21 | 22 | import java.util.ArrayList; 23 | import java.util.Arrays; 24 | import java.util.List; 25 | import java.util.concurrent.ScheduledExecutorService; 26 | import java.util.function.Function; 27 | 28 | import org.eclipse.microprofile.reactive.streams.operators.ReactiveStreamsFactory; 29 | import org.eclipse.microprofile.reactive.streams.operators.spi.ReactiveStreamsEngine; 30 | import org.reactivestreams.tck.TestEnvironment; 31 | 32 | /** 33 | * This test is a factory for all the tests for verifying implementations of the SPI. 34 | */ 35 | public class ReactiveStreamsSpiVerification { 36 | 37 | private final TestEnvironment testEnvironment; 38 | private final ReactiveStreamsFactory rs; 39 | private final ReactiveStreamsEngine engine; 40 | private final ScheduledExecutorService executorService; 41 | 42 | public ReactiveStreamsSpiVerification(TestEnvironment testEnvironment, ReactiveStreamsFactory rs, 43 | ReactiveStreamsEngine engine, ScheduledExecutorService executorService) { 44 | this.testEnvironment = testEnvironment; 45 | this.rs = rs; 46 | this.engine = engine; 47 | this.executorService = executorService; 48 | } 49 | 50 | public class VerificationDeps { 51 | ReactiveStreamsFactory rs() { 52 | return rs; 53 | } 54 | 55 | ReactiveStreamsEngine engine() { 56 | return engine; 57 | } 58 | 59 | TestEnvironment testEnvironment() { 60 | return testEnvironment; 61 | } 62 | 63 | ScheduledExecutorService executorService() { 64 | return executorService; 65 | } 66 | } 67 | 68 | public List allTests() { 69 | List> stageVerifications = Arrays.asList( 70 | OfStageVerification::new, 71 | MapStageVerification::new, 72 | FlatMapStageVerification::new, 73 | FilterStageVerification::new, 74 | FindFirstStageVerification::new, 75 | CollectStageVerification::new, 76 | TakeWhileStageVerification::new, 77 | FlatMapCompletionStageVerification::new, 78 | FlatMapIterableStageVerification::new, 79 | ConcatStageVerification::new, 80 | EmptyProcessorVerification::new, 81 | CancelStageVerification::new, 82 | SubscriberStageVerification::new, 83 | PeekStageVerification::new, 84 | DistinctStageVerification::new, 85 | OnStagesVerification::new, 86 | LimitStageVerification::new, 87 | SkipStageVerification::new, 88 | DropWhileStageVerification::new, 89 | OnErrorResumeStageVerification::new, 90 | FromCompletionStageVerification::new, 91 | FromCompletionStageNullableVerification::new, 92 | CoupledStageVerification::new); 93 | 94 | List allTests = new ArrayList<>(); 95 | VerificationDeps deps = new VerificationDeps(); 96 | for (Function creator : stageVerifications) { 97 | AbstractStageVerification stageVerification = creator.apply(deps); 98 | allTests.add(stageVerification); 99 | allTests.addAll(stageVerification.reactiveStreamsTckVerifiers()); 100 | } 101 | 102 | return allTests; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/spi/ScheduledPublisher.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.spi; 21 | 22 | import static org.testng.Assert.assertEquals; 23 | 24 | import java.util.concurrent.ScheduledExecutorService; 25 | import java.util.concurrent.TimeUnit; 26 | import java.util.concurrent.atomic.AtomicBoolean; 27 | import java.util.concurrent.atomic.AtomicInteger; 28 | import java.util.function.Supplier; 29 | 30 | import org.reactivestreams.Publisher; 31 | import org.reactivestreams.Subscriber; 32 | import org.reactivestreams.Subscription; 33 | 34 | /** 35 | * A publisher that publishes one element 100ms after being requested, and then completes 100ms later. It also uses 36 | * activePublishers to ensure that it is the only publisher that is subscribed to at any one time. 37 | */ 38 | class ScheduledPublisher implements Publisher { 39 | private final int id; 40 | private AtomicBoolean published = new AtomicBoolean(false); 41 | private final AtomicInteger activePublishers; 42 | private final Supplier supplier; 43 | 44 | ScheduledPublisher(int id, AtomicInteger activePublishers, Supplier supplier) { 45 | this.id = id; 46 | this.activePublishers = activePublishers; 47 | this.supplier = supplier; 48 | } 49 | 50 | @Override 51 | public void subscribe(Subscriber subscriber) { 52 | assertEquals(activePublishers.incrementAndGet(), 1); 53 | subscriber.onSubscribe(new Subscription() { 54 | @Override 55 | public void request(long n) { 56 | if (published.compareAndSet(false, true)) { 57 | getExecutorService().schedule(() -> { 58 | subscriber.onNext(id); 59 | getExecutorService().schedule(() -> { 60 | activePublishers.decrementAndGet(); 61 | subscriber.onComplete(); 62 | }, 100, TimeUnit.MILLISECONDS); 63 | }, 100, TimeUnit.MILLISECONDS); 64 | } 65 | } 66 | 67 | @Override 68 | public void cancel() { 69 | } 70 | }); 71 | } 72 | 73 | private ScheduledExecutorService getExecutorService() { 74 | return supplier.get(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/spi/SkipStageVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.spi; 21 | 22 | import static org.testng.Assert.assertEquals; 23 | 24 | import java.util.Arrays; 25 | import java.util.Collections; 26 | import java.util.List; 27 | 28 | import org.eclipse.microprofile.reactive.streams.operators.ProcessorBuilder; 29 | import org.reactivestreams.Processor; 30 | import org.reactivestreams.Publisher; 31 | import org.testng.annotations.Test; 32 | 33 | public class SkipStageVerification extends AbstractStageVerification { 34 | 35 | SkipStageVerification(ReactiveStreamsSpiVerification.VerificationDeps deps) { 36 | super(deps); 37 | } 38 | 39 | @Test 40 | public void skipStageShouldSkipElements() { 41 | assertEquals(await(rs.of(1, 2, 3, 4) 42 | .skip(2) 43 | .toList() 44 | .run(getEngine())), Arrays.asList(3, 4)); 45 | } 46 | 47 | @Test 48 | public void skipStageShouldSupportSkippingNoElements() { 49 | assertEquals(await(rs.of(1, 2, 3, 4) 50 | .skip(0) 51 | .toList() 52 | .run(getEngine())), Arrays.asList(1, 2, 3, 4)); 53 | } 54 | 55 | @Test 56 | public void skipStageShouldBeReusable() { 57 | ProcessorBuilder skip = rs.builder().skip(2); 58 | 59 | assertEquals(await(rs.of(1, 2, 3, 4).via(skip).toList().run(getEngine())), Arrays.asList(3, 4)); 60 | assertEquals(await(rs.of(5, 6, 7, 8).via(skip).toList().run(getEngine())), Arrays.asList(7, 8)); 61 | } 62 | 63 | @Override 64 | List reactiveStreamsTckVerifiers() { 65 | return Collections.singletonList( 66 | new ProcessorVerification()); 67 | } 68 | 69 | class ProcessorVerification extends StageProcessorVerification { 70 | 71 | @Override 72 | public Processor createIdentityProcessor(int bufferSize) { 73 | return rs.builder().skip(0).buildRs(getEngine()); 74 | } 75 | 76 | @Override 77 | public Publisher createFailedPublisher() { 78 | return rs.failed(new RuntimeException("failed")) 79 | .skip(1).buildRs(getEngine()); 80 | } 81 | 82 | @Override 83 | public Integer createElement(int element) { 84 | return element; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /tck/src/main/java/org/eclipse/microprofile/reactive/streams/operators/tck/spi/SubscriberStageVerification.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018, 2022 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck.spi; 21 | 22 | import java.util.Collections; 23 | import java.util.List; 24 | import java.util.concurrent.CancellationException; 25 | import java.util.concurrent.CompletionStage; 26 | 27 | import org.reactivestreams.Subscription; 28 | import org.testng.annotations.Test; 29 | 30 | public class SubscriberStageVerification extends AbstractStageVerification { 31 | SubscriberStageVerification(ReactiveStreamsSpiVerification.VerificationDeps deps) { 32 | super(deps); 33 | } 34 | 35 | @Test 36 | public void subscriberStageShouldRedeemCompletionStageWhenCompleted() { 37 | CompletionStage result = rs.of().to( 38 | rs.builder().ignore().build(getEngine())).run(getEngine()); 39 | await(result); 40 | } 41 | 42 | @Test(expectedExceptions = RuntimeException.class, expectedExceptionsMessageRegExp = "failed") 43 | public void subscriberStageShouldRedeemCompletionStageWhenFailed() { 44 | CompletionStage result = rs.failed(new RuntimeException("failed")).to( 45 | rs.builder().ignore().build(getEngine())).run(getEngine()); 46 | await(result); 47 | } 48 | 49 | @Test(expectedExceptions = CancellationException.class) 50 | public void subscriberStageShouldRedeemCompletionStageWithCancellationExceptionWhenCancelled() { 51 | CompletionStage result = rs.fromPublisher(subscriber -> subscriber.onSubscribe(new Subscription() { 52 | @Override 53 | public void request(long n) { 54 | } 55 | 56 | @Override 57 | public void cancel() { 58 | } 59 | })).to( 60 | rs.builder().cancel().build(getEngine())).run(getEngine()); 61 | await(result); 62 | } 63 | 64 | @Override 65 | List reactiveStreamsTckVerifiers() { 66 | return Collections.emptyList(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /tck/src/main/resources/META-INF/NOTICE: -------------------------------------------------------------------------------- 1 | ========================================================================= 2 | == NOTICE file corresponding to section 4(d) of the Apache License, == 3 | == Version 3.0, MicroProfile Reactive Streams Operators == 4 | ========================================================================= 5 | 6 | This product includes software developed at 7 | The Apache Software Foundation (http://www.apache.org/). 8 | 9 | 10 | SPDXVersion: SPDX-2.1 11 | PackageName: MicroProfile 12 | PackageHomePage: http://www.eclipse.org/microprofile 13 | PackageLicenseDeclared: Apache-2.0 14 | 15 | PackageCopyrightText: 16 | James Roper james@lightbend.com 17 | Clement Escoffier clement.escoffier@redhat.com 18 | Gordon Hutchison gordon_hutchison@uk.ibm.com 19 | -------------------------------------------------------------------------------- /tck/src/main/resources/META-INF/tck: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microprofile/microprofile-reactive-streams-operators/0872462adb5c6c100cb5e529cc0feead1c95740e/tck/src/main/resources/META-INF/tck -------------------------------------------------------------------------------- /tck/src/test/java/org/eclipse/microprofile/reactive/streams/operators/tck/TckTest.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | * 4 | * See the NOTICE file(s) distributed with this work for additional 5 | * information regarding copyright ownership. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * You may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | ******************************************************************************/ 19 | 20 | package org.eclipse.microprofile.reactive.streams.operators.tck; 21 | 22 | import org.eclipse.microprofile.reactive.streams.operators.tck.api.ReactiveStreamsApiVerification; 23 | import org.testng.annotations.Factory; 24 | 25 | /** 26 | * This runs any tests that don't require an implementation to run, that is, the API verification. 27 | */ 28 | public class TckTest { 29 | 30 | @Factory 31 | public Object[] allTests() { 32 | return new ReactiveStreamsApiVerification(new DefaultReactiveStreamsFactory()).allTests().toArray(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tck/src/test/resources/META-INF/NOTICE: -------------------------------------------------------------------------------- 1 | ========================================================================= 2 | == NOTICE file corresponding to section 4(d) of the Apache License, == 3 | == Version 3.0, MicroProfile Reactive Streams Operators == 4 | ========================================================================= 5 | 6 | This product includes software developed at 7 | The Apache Software Foundation (http://www.apache.org/). 8 | 9 | 10 | SPDXVersion: SPDX-2.1 11 | PackageName: MicroProfile 12 | PackageHomePage: http://www.eclipse.org/microprofile 13 | PackageLicenseDeclared: Apache-2.0 14 | 15 | PackageCopyrightText: 16 | James Roper james@lightbend.com 17 | Clement Escoffier clement.escoffier@redhat.com 18 | Gordon Hutchison gordon_hutchison@uk.ibm.com 19 | -------------------------------------------------------------------------------- /tck/src/test/resources/README.adoc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2018 Contributors to the Eclipse Foundation 3 | // 4 | // See the NOTICE file(s) distributed with this work for additional 5 | // information regarding copyright ownership. 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | // 19 | image:https://badges.gitter.im/eclipse/microprofile-reactive.svg[link="https://gitter.im/eclipse/microprofile-reactive"] 20 | 21 | = Unit Test for MicroProfile Reactive Streams Operators 22 | 23 | This test is a unit test and it runs when building MicroProfile Reactive Stream Operators. --------------------------------------------------------------------------------