{"id":21073931,"url":"https://github.com/const/asyncflows","last_synced_at":"2025-07-03T09:34:13.070Z","repository":{"id":37258043,"uuid":"147245650","full_name":"const/asyncflows","owner":"const","description":"The framework provides DSL for easy and modular construction of asynchronous processes from simpler constructs. The framework is mostly targeted to IO-bound processes and it is not intended for CPU-bound processes.","archived":false,"fork":false,"pushed_at":"2023-12-05T22:18:58.000Z","size":1313,"stargazers_count":5,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-16T06:35:15.008Z","etag":null,"topics":["asynchronous-api","asynchronous-io","asynchronous-programming","domain-specific-language","dsl","event-driven","groovy","java","kotlin"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/const.png","metadata":{"files":{"readme":"README.adoc","changelog":"CHANGES.adoc","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2018-09-03T19:32:50.000Z","updated_at":"2024-01-10T18:08:11.000Z","dependencies_parsed_at":"2023-12-15T20:09:44.404Z","dependency_job_id":"c408952b-3209-406b-b7e9-eac1decb3a05","html_url":"https://github.com/const/asyncflows","commit_stats":{"total_commits":84,"total_committers":2,"mean_commits":42.0,"dds":"0.41666666666666663","last_synced_commit":"02209793246acad19a17caa47a96e63ff419cecd"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/const/asyncflows","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/const%2Fasyncflows","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/const%2Fasyncflows/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/const%2Fasyncflows/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/const%2Fasyncflows/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/const","download_url":"https://codeload.github.com/const/asyncflows/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/const%2Fasyncflows/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263301298,"owners_count":23445344,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asynchronous-api","asynchronous-io","asynchronous-programming","domain-specific-language","dsl","event-driven","groovy","java","kotlin"],"created_at":"2024-11-19T19:13:46.012Z","updated_at":"2025-07-03T09:34:13.034Z","avatar_url":"https://github.com/const.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"= AsyncFlows Framework {current-version}\nKonstantin Plotnikov \u003cconstantine.plotnikov@gmail.com\u003e\n0.1.2-SNAPSHOT, 2019-??-??\n:source-highlighter: rouge\n:experimental:\n:toc:\n:toclevels: 5\n:toc-placement!:\n:stable-version: 0.1.1\n:current-version: 0.1.2-SNAPSHOT\n\nThe framework provides DSL for easy and modular construction of asynchronous processes from simpler constructs.\nThe framework is targeted to IO-bound processes, and it is not intended for CPU-bound processes.\n\ntoc::[]\n\n== Project information\n\n=== Licensing\n\nThe framework is licensed under copyleft link:LICENSE.txt[MIT license].\nThis could change if the project is migrated to other project groups (Apache, Eclipse, or something else).\nThere is currently no legal framework to accept project contributions in form of the code.\nHowever, bug reporting, experimental forking, and other feedback is welcome.\nThe project might migrate to some project groups to solve this problem.\n\nCAUTION: Currently, project is considered in the Alpha phase and there could be backward incompatible changes even for minor versions.\n\n=== Code Samples\n\nThe code samples in this guide are usually taken from unit tests of the framework.\nSo they are directly executable.\nIf copied in own code, one usually need to resolve some static imports that are used by DSL.\n\n=== Distribution\n\nThe project source repository is currently available on https://github.com/const/asyncflows[github].\n\nSnapshot releases are available at repository https://oss.sonatype.org/content/groups/public[OSS Sonatype repository].\n\nIMPORTANT: The framework currently requires Java 11.\n\nThe latest stable version is {stable-version} is available from maven central.The following project artifacts are released:\n\n[source,xml,subs=\"attributes,verbatim\"]\n----\n            \u003c!-- Core library --\u003e\n            \u003cdependency\u003e\n                \u003cgroupId\u003eorg.asyncflows\u003c/groupId\u003e\n                \u003cartifactId\u003easyncflows-core\u003c/artifactId\u003e\n                \u003cversion\u003e{stable-version}\u003c/version\u003e\n            \u003c/dependency\u003e\n            \u003c!-- IO library --\u003e\n            \u003cdependency\u003e\n                \u003cgroupId\u003eorg.asyncflows\u003c/groupId\u003e\n                \u003cartifactId\u003easyncflows-io\u003c/artifactId\u003e\n                \u003cversion\u003e{stable-version}\u003c/version\u003e\n            \u003c/dependency\u003e\n            \u003c!-- HTTP protocol support --\u003e\n            \u003cdependency\u003e\n                \u003cgroupId\u003eorg.asyncflows\u003c/groupId\u003e\n                \u003cartifactId\u003easyncflows-protocol-http\u003c/artifactId\u003e\n                \u003cversion\u003e{stable-version}\u003c/version\u003e\n            \u003c/dependency\u003e\n----\n\nThis document contains information about the current version {current-version}, and it might mention unreleased features.\nFor the document corresponding to the latest stable version refer to the following\nhttps://github.com/const/asyncflows/blob/release-{stable-version}/readme.adoc[link].\n\n=== History\n\nThe project has started at 2007 on Java under name http://asyncobjects.sourceforge.net/[AsyncObjects].\nThere were many iterations trying to find suitable DSL syntax for Java.\nThen there were experimental project branches https://sourceforge.net/p/asyncobjects/asyncgroovy/ci/master/tree/[AsyncGroovy] and\nhttps://sourceforge.net/p/asyncobjects/asyncscala/ci/master/tree/[AsyncScala] that were attempts to build DSL using closures, the experience gathered resulted in the current project restart firstly using inner classes, and then using the Java 8 syntax.\n\n== Framework Foundations\n\nThe concept described in this section are foundations of the framework.\nWhile they are foundation, the user of the framework rarely interacts\nwith them directly, so do not assume that code samples here are anything\nlike what you would see in application.Like with real building,\nfoundations are mostly stay hidden from the sight.\n\n=== Vats\n\nA Vat is Executor that has the following guarantees:\n\n1. It executes events in order that was sent\n2. It executes only one event at each time\n3. During execution, it is possible to get the current Vat\n\nThese guarantees allow avoiding a lot of concurrency issues and organize asynchronous processes a lot easier.\n\nThe concept of the vat is taken from http://www.e-elang.org[E programming language], from which many ideas were borrowed in this framework.\n\nWhile a vat is handling events, it specifies itself in thread context.\nSo it is available with `Vat.current()`.\nAsynchronous operations in the framework generally inherit `Vat` as execution context, unless the executor is specified explicitly.\n\nThere is a special cached thread pool with daemon threads that is used for daemon vats `Vats.daemonVat()`.\n\nThere are following vats in the core library (there are also some vats in additional libraries):\n\n* `Vat` - abstract class for all vats\n* `AWTVat` - vat over AWT event queue\n* `BatchedVat` - abstract vat that executes event in batches\n* `ExecutorVat` - a vat that runs over some executor.\nNote, that this vat occupies executor thread only when there are events to handle.\nIf there are no events, no threads are occupied.\nVat re-schedule itself after a batch of events are processed even if there are still events in the queue in order to give other vats of over the same executor a chance to process their events.\n* `SingleThreadVatWithIdle` - an abstract vat that occupies one thread and need to periodically poll events from an external source (for example NIO events).\n* `SingeThreadVat` - a vat that occupies the entire thread and can be stopped.\nThis vat is usually used in unit tests and to start application on the main thread.\n\nFor example, the vat could be used like the following, if more high-level constructs could not be used otherwise.\n\n[source,java]\n----\n        final Cell\u003cVat\u003e result = new Cell\u003c\u003e(); // create holder for value\n        final SingleThreadVat vat = new SingleThreadVat(null); // create vat\n        vat.execute(() -\u003e { // schedule event\n            result.setValue(Vat.current()); // save current vat value\n            vat.stop(null); // stop vat execution\n        });\n        assertNull(result.getValue()); // check that it is not executed yet\n        vat.runInCurrentThread(); // start vat and execute event\n        // vat is stopped\n        assertSame(vat, result.getValue()); // get vat value\n----\n\nIt is rarely needed to use vat directly.The typical cases are:\n\n* Application setup\n* Library or framework code\n\n=== Promise\n\n`Promise` is similar in a role to `CompletableFuture` that provides additional restrictions compared with\n`CompletableFuture`.\nIt does not support `get()` operation directly to discourage it, and it does not permit changing result in midway.\n\nA `Promise` could be wrapped into `CompletableFuture`, and it could be created from any `CompletableStage`\n(including `CompletableFuture`), when it is needed to integrate with external services.\nOperations on\n`Promise` are created to encourage correct usage of it.\n\nThe promise outcome is represented by `Outcome` class that has `Failure` and `Success` subclasses.\nIf promise is not resolved, its outcome is null.\n\nLinked with `Promise` is `AResolver` interface, that could act as a listener to a promise, and to specify an outcome for `Promise`.\nOnly other way to specify an outcome for a promise is to pass it to the constructor of promise.\n\nThere are three versions of method that adds listener to promise:\n\n* `listenSync(AResolver)` - adds the listener for `Promise` that is notified in the execution context where promise is resolved.\nThis method should be only used, if listener already has appropriate synchronizations or asynchronous event delivery implemented (for example, a resolver for other promise).\n* `listen(AResolver)` - adds the listener for `Promise` that is notified in the context of default executor where a listener is registered.\n\nThere are also some utility methods on the promise that help its usage and contain some optimizations.\n\n* `flatMap` - converts value when a promise is successful with `AFunction`\n* `flatMapOutcome` - converts outcome when promise is resolved with `AFunction`\n* `flatMapFailure` - maps failure with `AFunction` in case if promise failed (like try-catch in Java).\n* `finallyDo` - execute some code when promise finishes with any outcome (like try-finally in Java).\n* `map` - converts value when promise is successful with `Function`\n* `mapOutcome` - converts outcome when promise is resolved with `Function`\n\nThere are few more utility methods.\n\nThese functions are executed immediately, if result is already available.\nIf not, they will be executed after promise is resolved, using the vat associated with the current thread.\n\n== Structured Asynchronous Programming\n\nThe core concept of the framework is asynchronous operation.*Asynchronous operation* is a sequence of logically grouped execution of the events in some events loops that that finish with some outcome (or just finish for one-way operations).\n\nAsynchronous operators are static methods that usually return `Promise` and start with the prefix 'a' (for example `aValue`).The operations are supposed to be imported using static import to form a DSL in the programming language.\n\nThe structured programming constructs are inspired by combining ideas from two sources:\n\n* http://www.e-elang.org[E programming language]\n* https://en.wikipedia.org/wiki/Occam_(programming_language)[Occam programming language]\n\n=== Asynchronous Functions\n\nThe most of the operators expect lambdas are arguments.\nThese function interfaces are located at package\n`org.asyncflows.core.function`.\nThese functions return `Promise`.\n\n* `ASupplier` - the suppler interface (analog of `Supplier`)\n* `AFunction` - the single argument function interface (analog of `Function`)\n* `AFunction2` - the two argument function interface (analog of `BiFunction`)\n* `AFunction3` - the three argument function interface\n* `AFunction4` - the four argument function interface\n* `AOneWayAction` - the one-way action for which result is ignored ('Runnable', but with exception)\n\n=== Asynchronous Context\n\nWhile much of the framework functionality is able to work w/o current vat, it is best to provide a context vat.\nThe simplest way to do so is using AsyncContext class to create temporary local context to implement some operation.\n\n[source,java]\n----\nInteger i = doAsync(() -\u003e aValue(42));\nassertEquals(42, i);\n----\n\nThe operation above creates `SingeThreadedVat`, run it on the current thread, and then stops vat when `Promise`\nis done with success or failure.\nIf it is done with success, operation exits with value, otherwise it throws\n`AsyncExecutionException`.\n\n=== Trivial Operations\n\nTrivial operations are just different way to construct promise.\nGenerally, the code should not need to create promise directly, except for few DSL cases.\nUse promise construction operation instead.\nAll these trivial operations are implemented in `Promise` class as they are mostly factory methods for it.\n\n[source,java]\n----\naValue(42) // resolved promise that holds specified value\naFailure(new NullPointerException) // failed promise\naNull() // promise holding null\naVoid() // null promise with Void type.\naTrue() // promise holding true\naFalse() // promise holding false\naResolver(r -\u003e r.accept(null, new NullPointerException())) // return promise, and to some things with resolver in body\naNow(()-\u003eaValue(a * b)) // evaluate body and return promise (if body failed, return failed promise)\naLater(()-\u003eaValue(a * b)) // evaluate on later turn in default vat\naLater(vat, ()-\u003eaValue(a * b)) // evaluate on later turn in the specified vat\naNever() // the process that never ends\n----\n\nNote, `aNow` looks like useless operation, but it is actually used quite often.\nAn expression that returns a promise might result in the following:\n\n. Return unresolved promise\n. Return promise resolved with some outcome (failure or value)\n. Return `null`\n. Throw an exception\n\nIf we want to register listener on the result of operation, the fist two cases are not much different.\nThe listener will be called either immediately, or later when promise is resolved.\nThe last two cases are significantly different.\nThey will cause listener to be never called, and the listeners will be never be called.\nThis will case operation to hang up, if these two exceptional cases are not handled specially.\nThe operator `aNow` reduces these two cases to a promise with failure outcome.\nSo, there is no need to handle these cases specially.\nThis greatly simplifies the code.\nThere still could be problem in case of StackOverflowException or OutOfMemoryError, but most of the asynchronous frameworks will have problems with these failures as well.\n\n=== Sequential Processes\n\nAll sequential controls method now require that they should be running in the context of the vat.\n\n==== aNow and aSeq Operator\n\nThe sequential fow in AsyncFlows is organized using operations on `Promise`.\n\nThe operator `aSeq` is just alias for `aNow` operator.\nIt is used to indicate that there is some chain of the sequential operations on promise.\nIt also wraps the first expression that returns promise, so it is shown on the same block level as subsequent operations.\n\nThe following test demonstrate its usage:\n\n[source,java]\n----\n        final ArrayList\u003cInteger\u003e list = new ArrayList\u003c\u003e();\n        final int rc = doAsync(() -\u003e\n                aSeq(() -\u003e {\n                    list.add(1);\n                    return aValue(1);\n                }).flatMap(value -\u003e {\n                    list.add(value + 1);\n                    throw new IllegalStateException();\n                }).thenFlatGet(() -\u003e {\n                    // never called\n                    list.add(-1);\n                    return aValue(-1);\n                }).flatMapFailure(value -\u003e {\n                    assertEquals(IllegalStateException.class, value.getClass());\n                    list.add(3);\n                    return aValue(42);\n                }).finallyDo(() -\u003e {\n                    list.add(4);\n                    return aVoid();\n                }));\n        assertEquals(42, rc);\n        assertEquals(Arrays.asList(1, 2, 3, 4), list);\n----\n\n==== Simple Loops\n\nThe simplest loop is `aSeqWhile`.This loop is executed while its body returns true.\n\n[source,java]\n----\n        final int rc = doAsync(() -\u003e {\n            final int[] sum = new int[1];\n            final int[] current = new int[1];\n            return aSeqWhile(() -\u003e {\n                sum[0] += current[0];\n                current[0]++;\n                return aBoolean(current[0] \u003c= 4);\n            }).thenFlatGet(() -\u003e aValue(sum[0]));\n        });\n        assertEquals(10, rc);\n----\n\nThere is also the `Maybe` type in the framework that represent the optional value.Differently from Java `Optional`,\nthe `Maybe` type could hold any value including null value.It also could be serialized, passed as parameter etc.\n\nIt is possible to iterate until the value is available with this aSeqUntilValue loop.\n\n[source,java]\n----\n        final int rc = doAsync(() -\u003e {\n            final int[] sum = new int[1];\n            final int[] current = new int[1];\n            return aSeqUntilValue(() -\u003e {\n                sum[0] += current[0];\n                current[0]++;\n                return current[0] \u003c= 4 ? aMaybeEmpty() : aMaybeValue(sum[0]);\n            });\n        });\n        assertEquals(10, rc);\n----\n\n==== Collections Loops\n\nIt is possible to iterate over collections using iterator:\n\n[source,java]\n----\n        final int rc = doAsync(() -\u003e {\n            final int[] sum = new int[1];\n            return aSeqForUnit(Arrays.asList(0, 1, 2, 3, 4), value -\u003e {\n                sum[0] += value;\n                return aTrue();\n            }).thenFlatGet(() -\u003e aValue(sum[0]));\n        });\n        assertEquals(10, rc);\n----\n\nIt is also possible to supply iteration values to collector, but in that case it is not possible\nto abort the loop:\n\n[source,java]\n----\n        final int rc = doAsync(() -\u003e\n                aSeqForCollect(Stream.of(1, 2, 3, 4),\n                        e -\u003e aValue(e + 1),\n                        Collectors.summingInt((Integer e) -\u003e e))\n        );\n        assertEquals(14, rc);\n----\n\nThe more advanced collection processing could be done by the stream framework.\n\n=== Simultaneous Processes\n\nSequential execution is not that interesting in asynchronous context.\nMore intriguing is case when asynchronous operations overlap.\nIt could happen in the context of the same event loop.\nAsyncFlows provides a number of methods to organize simultaneous asynchronous activity.\n\n==== aAll Operator\n\nThe simplest form is aAll operator.\nThe operator starts all its branches on the current vat on the current turn and executes the operation\n`map(...)` when all branches are finished.\nIf some branch thrown exception, the operator throws an error, but it will still wait for all branches to complete.\n\n[source,java]\n----\n        final Tuple2\u003cString, Integer\u003e rc = doAsync(() -\u003e\n                aAll(\n                        () -\u003e aValue(\"The answer\")\n                ).and(\n                        () -\u003e aLater(() -\u003e aValue(42))\n                ).map((a, b) -\u003e aValue(Tuple2.of(a, b))));\n        assertEquals(Tuple2.of(\"The answer\", 42), rc);\n----\n\nIt is possible to return tuple from all arguments directly using `Last` suffix on the last branch.\n\n[source,java]\n----\n        final Tuple2\u003cString, Integer\u003e rc = doAsync(() -\u003e\n                aAll(\n                        () -\u003e aValue(\"The answer\")\n                ).andLast(\n                        () -\u003e aLater(() -\u003e aValue(42))\n                ));\n        assertEquals(Tuple2.of(\"The answer\", 42), rc);\n----\n\n==== Processing Collections\n\nBasic operation for iterating collection, streams, and iterators is `aAllForCollect` operators.\n\n[source,java]\n----\n        final int rc = doAsync(() -\u003e\n                aAllForCollect(Stream.of(1, 2, 3, 4),\n                        e -\u003e aValue(e + 1),\n                        Collectors.summingInt((Integer e) -\u003e e))\n        );\n        assertEquals(14, rc);\n----\n\nIt processes all branches in interleaving on the current event loop.\nThen summarize them using supplied collector.\n\nThe more advanced collection processing could be done by the stream framework.\n\n==== Parallel Processes\n\nIf `aAll` is replaced with `aPar` in the previous section, then we will get parallel operations provided by the framework.\nBy default, each branch is executed on the own new daemon vat.\nHowever, is possible to customize execution by providing an implementation of ARunner interface.\n\n[source,java]\n----\n        final Tuple2\u003cString, Integer\u003e rc = doAsync(() -\u003e\n                aPar(\n                        () -\u003e aValue(\"The answer\")\n                ).and(\n                        () -\u003e aLater(() -\u003e aValue(42))\n                ).map((a, b) -\u003e aValue(Tuple2.of(a, b))));\n        assertEquals(Tuple2.of(\"The answer\", 42), rc);\n----\n\nThis is applicable to all other `aAll` operators.\n\n=== Alternative Processing\n\nThe alternative processing is done using `aAny` operator.\nThis operator starts all branches on the current turn and waits for the first branch to complete with error or success.\nThe `aAny` operator is intended for error handling and querying alternative sources of information.\n\n[source,java]\n----\n        int value = doAsync(() -\u003e\n                aAny(\n                        () -\u003e aLater(() -\u003e aValue(1))\n                ).orLast(\n                        () -\u003e aValue(2)\n                )\n        );\n        assertEquals(2, value);\n        try {\n            doAsync(() -\u003e\n                    aAny(\n                            () -\u003e aLater(() -\u003e aValue(1))\n                    ).orLast(\n                            () -\u003e aFailure(new RuntimeException())\n                    )\n            );\n            fail(\"Unreachable\");\n        } catch (AsyncExecutionException ex) {\n            assertEquals(RuntimeException.class, ex.getCause().getClass());\n        }\n----\n\n\nThere is also execution mode that the `aAny` operator tries to wait for successful result if possible.\n\n[source,java]\n----\n        int value = doAsync(() -\u003e\n                aAny(true,\n                        () -\u003e aLater(() -\u003e aValue(1))\n                ).orLast(\n                        () -\u003e aFailure(new RuntimeException())\n                )\n        );\n        assertEquals(1, value);\n----\n\nThe other feature of `aAny` operator is handling of the branches that did not reach output of `aAny` operator.\nThis is important when the `aAny` operator opens resources that are required to be closed.Or when exceptions from failed branches need to be logged.\n\nThe sample below demonstrates usage of `suppressed(...)` and `suppressedFailure(...)` that could be used to receive the abandoned results.\nThis might be used for logging and cleaning up resources.\nNote, these operations will be called after `aAny` operator promise will be resolved.\nIn some cases vat might be already stopped at that points, so these operations might be never executed.\nUse these operations with care or on the vats which cannot be stopped (like daemon vat's).\n\n[source,java]\n----\n        Tuple3\u003cInteger, Throwable, Integer\u003e t = doAsync(\n                () -\u003e {\n                    Promise\u003cThrowable\u003e failure = new Promise\u003c\u003e();\n                    Promise\u003cInteger\u003e suppressed = new Promise\u003c\u003e();\n                    return aAll(\n                            () -\u003e aAny(true,\n                                    () -\u003e aLater(() -\u003e aValue(1))\n                            ).or(\n                                    () -\u003e aValue(2)\n                            ).or(\n                                    () -\u003e aFailure(new RuntimeException())\n                            ).suppressed(v -\u003e {\n                                notifySuccess(suppressed.resolver(), v);\n                            }).suppressedFailureLast(ex -\u003e {\n                                notifySuccess(failure.resolver(), ex);\n                            })\n                    ).and(\n                            () -\u003e failure\n                    ).andLast(\n                            () -\u003e suppressed\n                    );\n                }\n        );\n        assertEquals(2, t.getValue1().intValue());\n        assertEquals(RuntimeException.class, t.getValue2().getClass());\n        assertEquals(1, t.getValue3().intValue());\n\n----\n\n==== Cancellation\n\nThe `Cancellation` utility class is an application of the `aAny` operator.\n\nIn some cases it is needed to fail the entire process if some operation has failed.\nFor example, if one asynchronous operation has already failed, the related operations need also fail.\n\nFor that purpose, framework contains Cancellation utility class.\nThe class monitor results of operations.\n\nSometimes, an operation returns the resource that require cleanup (for example open connection).\nIn that case ignoring resource is not a valid option.\nFor that purpose there is cleanup operation.\n\nLet's consider a case when we have some consumer, and some provider of values.\nFor that purpose, we will use queue components, that will be explained later in that guide.\nWe will assume that provider fail, so consumer might fail to receive expected value that would terminate processing.\nIn that case, we would like to consumer to fail as well.\nFor example:\n\n[source,java]\n----\n        ArrayList\u003cInteger\u003e list = new ArrayList\u003c\u003e();\n        doAsync(() -\u003e {\n            SimpleQueue\u003cInteger\u003e queue = new SimpleQueue\u003c\u003e();\n            Cancellation cancellation = new Cancellation();\n            return aAll(\n                    // () -\u003e aSeqWhile(() -\u003e queue.take().map(t -\u003e {\n                    () -\u003e aSeqWhile(() -\u003e cancellation.run(queue::take).map(t -\u003e {\n                        if (t == null) {\n                            return false;\n                        } else {\n                            list.add(t);\n                            return true;\n                        }\n                    }))\n            ).andLast(\n                    () -\u003e aSeq(\n                            () -\u003e queue.put(1)\n                    ).thenFlatGet(\n                            () -\u003e queue.put(2)\n                    ).thenFlatGet(\n                            // pause\n                            () -\u003e aSeqForUnit(rangeIterator(1, 10), t -\u003e aLater(() -\u003e aTrue()))\n                    ).thenFlatGet(\n                            () -\u003e cancellation.run(() -\u003e aFailure(new RuntimeException()))\n                    )\n            ).mapOutcome(o -\u003e {\n                assertTrue(o.isFailure());\n                assertEquals(RuntimeException.class, o.failure().getClass());\n                return true;\n            });\n        });\n        assertEquals(Arrays.asList(1, 2), list);\n----\n\nIf we do queue reading like in commented out line, the test will hang up, because the consumer will never receive the value, because supplier failed.\nBut, in uncommented line, we wrap call to `queue.take()` into cancellation runner.\nThis allows us to fail all executions of cancellation that are active or will be active.\nInside the call of `cancellation.run(...)` there is any operator against common promise, if any of the\n`cancellation.run(...)` fails, that promise fails as well.\nOtherwise, it stays in unresolved state.\n\n=== Context Propagation\n\nSome API requires propagation of the context and setting the context for action execution.\nThe best option would be passing it via implicit or explicit arguments, but in some cases it is not practical, particularly in case of integration with different frameworks that rely on thread-local variables to keep contextual information.\n\nTo simplify handling of such cases AsyncFlows provides Context API. The context API allows is automatic propagation of context ot most actions.\n\nBasic operation `aLater(...)` and `aSend(...)` support such propagation, and most of control constructs are using them.\nSo it is recommended to rely on them when you are creating own DSL operations.\n\n==== Context Object\n\nThe class link:asyncflows-core/src/main/java/org/asyncflows/core/context/Context.java[Context] is the basic element of the context propagation functionality.\nThe context construction starts with `Context.empty()` then elements could be added with `context.with(...)`\nand `context.withPrivate(...)` entries, and removed with `context.without(...)` entries.\n\nThe context has two operators for establishing the context: `context.setContext()` that returns `Context.Cleanup`\nthat could be used in 'try with resources' Java statement.\n\n[source,java]\n----\nfinal Context test = ...;\ntry (Cleanup ignored = test.setContext()) {\n    action.doIt();\n}\n----\n\nThe method `context.run(...)` that set context runs runnable and then close context cleanup.\n\n[source,java]\n----\ntest.run(() -\u003e {\n    action.doIt();\n});\n----\n\nThere are private and public entries in the context.\nThe public entries are added using `context.with(...)` operator, and they could be later removed with `context.without(...)` operation.\n\nEach such entry is associated with key of the type `ContextKey`.\nThe context values could be added later with the method `context.getOrNull(...)` and other get methods.\n\nThe keys are created as the following:\n\n[source,java]\n----\n    private static final ContextKey\u003cString\u003e TEST_KEY = ContextKey.get(ContextTest.class, \"test\");\n----\n\nThe type parameter of key is the type of the value associated with context.\nThen the key could be used to access and add context values.\n\n[source,java]\n----\nfinal Context test = Context.empty().with(TEST_KEY, \"test\");\nassertNull(Context.current().getOrNull(TEST_KEY));\ntest.run(() -\u003e {\n    assertEquals(\"test\", Context.current().getOrNull(TEST_KEY));\n    test.without(TEST_KEY).run(() -\u003e {\n        assertNull(Context.current().getOrNull(TEST_KEY));\n    });\n    assertEquals(\"test\", Context.current().getOrNull(TEST_KEY));\n});\nassertNull(Context.current().getOrNull(TEST_KEY));\n----\n\nContext is an immutable object, and each modification of the context return a new instance of the context.\nHowever, context entries could contain mutable objects (for example logging MDC) When new instance of the context is established, the old instance is completely rolled back.\n\n==== Active Context Entries\n\nSome context entries require modification of the thread when context is established: setting thread local state, modifying security context, setting context class loader, joining or leaving transactions, etc.\n\nTo support such contextual entries an interface\nlink:asyncflows-core/src/main/java/org/asyncflows/core/context/spi/ActiveContextEntry.java[ActiveContextEntry]\nwas introduced.\nWhen context with such value is activated, the method `Cleanup setContextInTheCurrentThread()` is invoked.\nThe returned value is used to return to the previous state of the context.\nThe convention is that such state should be equal to the previous state, for example, the previous state of `ThreadLocal` should be set.\n\nSee the definition of\nlink:asyncflows-core/src/main/java/org/asyncflows/core/context/util/ContextClassLoaderEntry.java[ContextClassLoaderEntry]\nfor example of typical ActiveContextEntry.\nAs a convention, such entries should provide the static `with*(...)`\nmethods that return `UnaryOperator\u003cContext\u003e` that could be passed to `context.transform(...)` method, instead of requiring adding such entries explicitly.\nThis allows hiding implementation details like keys and initialization of initial values.\nFor example:\n\n[source,java]\n----\npublic static UnaryOperator\u003cContext\u003e withSavedContextClassloader() {\n    return withContextClassloader(Thread.currentThread().getContextClassLoader());\n}\n\npublic static UnaryOperator\u003cContext\u003e withContextClassloader(ClassLoader newClassLoader) {\n    return c -\u003e c.with(KEY, new ContextClassLoaderEntry(newClassLoader));\n}\n----\n\nSuch method could be used later as the following:\n\n[source,java]\n----\nfinal Context test1 = Context.empty().transform(withContextClassloader(classLoader));\n----\n\nSometimes it is not practical or possible to require creation of the separate key for context entries, as context entries could have own identity (for example, ThreadLocal).\nSuch entries exist only for establishing the thread context, and there is no meaningful textual names for such objects.\nTo support such entries, the interface\nlink:asyncflows-core/src/main/java/org/asyncflows/core/context/spi/PrivateContextEntry.java[PrivateContextEntry]\nwas introduced.\nIt is possible to add it context (or replace with in a new instance of context), but it is not possible to create a context with such entry removed.\n\nInstead of the explicit key, such entries should implement the method  `Object identity()` that returns identity object for context entry, this identity object will be used as a key (it will be compared by the operator `==`).\nFor thread local context entry, such entry will return a reference to thread local itself.\nSee\nlink:asyncflows-core/src/main/java/org/asyncflows/core/context/util/ThreadLocalEntry.java[ThreadLocalEntry]\nas an example of such context entry.\n\nThe package link:asyncflows-core/src/main/java/org/asyncflows/core/context/util[org.asyncflows.core.context.util]\ncontains a number of useful active context entries that could be used as examples.\n\n==== Asynchronous Operations\n\nWhile context framework does not depend on the rest of the AsyncFlows framework, and it could be used independently, the AsyncFlows framework integrates with it and provide some ready to use control constructs.\n\nThere are two versions of the contextual execution, one that gets ready to use context, and one that updates the context.\n\n[source,java]\n----\ndoAsync(() -\u003e {\n    assertNull(MDC.get(\"k\"));\n    return inContext(withMdcEntry(\"k\", \"v\"), () -\u003e { // updates current context using\n        assertEquals(\"v\", MDC.get(\"k\"));             // the function return from withMdcEntry\n        return inContext(Context.empty(), () -\u003e { // explicitly passed context\n            assertNull(MDC.get(\"k\")); // value is not set, because it is running in empty context\n            return aVoid();\n        });\n    }).thenGet(() -\u003e {\n        assertNull(MDC.get(\"k\"));\n        return null;\n    });\n});\n----\n\nIt is also possible to create contexts asynchronously, if establishing context requires contacting some external service.\nThe same sample in the asynchronous version:\n\n[source,java]\n----\ndoAsync(() -\u003e {\n    assertNull(MDC.get(\"k\"));\n    return inContext(c -\u003e aValue(c.transform(withMdcEntry(\"k\", \"v\")))).run(() -\u003e aLater(() -\u003e {\n        assertEquals(\"v\", MDC.get(\"k\"));\n        return inContext(() -\u003e aValue(Context.empty())).run(() -\u003e {\n            assertNull(MDC.get(\"k\"));\n            return aVoid();\n        }).thenGet(() -\u003e {\n            assertEquals(\"v\", MDC.get(\"k\"));\n            return aVoid();\n        });\n    })).thenGet(() -\u003e {\n        assertNull(MDC.get(\"k\"));\n        return null;\n    });\n});\n----\n\n=== Safety frames\n\nThe asynchronous operations generally do not own data, and many changes could happen to data when there is a simultaneous processing on it.\n\nGenerally, the code should be written that data invariant should be maintained while single closure is executed.\nOther closures represent code that might be executed after something has changed.\n\nIf there is no explicit fork like (aPar, aSed/aLater to other vat, calls to components), the mutable data could be assumed to be safe to use from vat as vat context would not switch while operation is in progress.\nThe thread might be different, but there will be write/read barriers for the new thread.\n\nIf callback is passed to other Vat, it usually need to be exported in order to be executed in this Vat context with the same safety guarantees using\nlink:asyncflows-core/src/main/java/org/asyncflows/core/function/FunctionExporter.java[FunctionExporter]\nor other way.\n\n== Object-Oriented Programming\n\nAs we have seen in the previous section, the framework support rich set of asynchronous operators that support functional and structured asynchronous programming.\nAnd, the framework also supports creation of asynchronous components, so normal object-oriented programming could be used as well.\n\n=== Classes and Interfaces\n\nThe asynchronous interface is normal Java interface that has methods that return Promise or void.\nThe other types of methods could present on the interface, but they will not be supported by the runtime, and they will throw an exception.\nLet's consider a simple Queue interface:\n\n[source,java]\n----\n@Asynchronous\npublic interface ATestQueue\u003cT\u003e {\n    Promise\u003cT\u003e take();\n    void put(T element);\n}\n----\n\nThe method `put(...)` is one way, the method is one-way is just for demonstration here.\nAQueue component in the library returns Promise\u003cVoid\u003e because there might be errors on put operations.\nThe method `take()` returns the `Promise` as it might need to wait until some value is available.\nBy convention, the interface names start with 'A' to indicate that is an asynchronous interface.\n\n[source,java]\n----\npublic class TestQueue\u003cT\u003e implements ATestQueue\u003cT\u003e, ExportableComponent\u003cATestQueue\u003cT\u003e\u003e {\n    private final Deque\u003cT\u003e elements = new LinkedList\u003c\u003e();\n    private final Deque\u003cAResolver\u003cT\u003e\u003e resolvers = new LinkedList\u003c\u003e();\n\n    private void invariantCheck() {\n        // checks that queue invariant holds\n        if(!elements.isEmpty() \u0026\u0026 !resolvers.isEmpty()) {\n            throw new RuntimeException(\"BUG: one of the collections should be empty\");\n        }\n    }\n\n    @Override\n    public Promise\u003cT\u003e take() {\n        invariantCheck();\n        if (elements.isEmpty()) {\n            return aResolver(r -\u003e {\n                resolvers.addLast(r);\n            });\n        } else {\n            return aValue(elements.removeFirst());\n        }\n    }\n\n    @Override\n    public void put(final T element) {\n        invariantCheck();\n        if (resolvers.isEmpty()) {\n            elements.addLast(element);\n        } else {\n            notifySuccess(resolvers.removeFirst(), element);\n        }\n    }\n\n    @Override\n    public ATestQueue\u003cT\u003e export(final Vat vat) {\n        return exportTestQueue(vat, this);\n    }\n}\n----\n\nThe basic idea of the implementation is that we have two queues, queue of values and queue of waiters for value.\nOnly one of the queues could contain values at the same time.\n\nThe method `take()` just returns the value if value is available, but if value is not available, it returns not resolved promise and saves resolver to queue of resolvers.\n\nThe method `put(...)` checks if there is some resolver and if there is, the waiter is notified and value is supplied to requester.\nOtherwise, the value is saved.\nIf invariant of put method fails, the error will be logged by AsyncFlows framework, but caller will not receive it.\nThis is why one-way methods should be generally avoided.\n\nThe class also implements interface `ExportableComponent`.\nThis interface indicates that class is not safe to use outside of the vat, and it should be generally exported.\nThe proxies could be written manually or APT code generator could be used to generate proxies.\n\nThe exporter could be written manually, and would look like this:\n\n[source,java]\n----\n    public static \u003cT\u003e ATestQueue\u003cT\u003e exportTestQueue(final ATestQueue\u003cT\u003e service, final Vat vat) {\n        return new ATestQueue\u003cT\u003e() {\n            @Override\n            public Promise\u003cT\u003e take() {\n                return aLater(vat, () -\u003e service.take());\n            }\n\n            @Override\n            public void put(T element) {\n                aOneWay(vat, () -\u003e put(element));\n            }\n        };\n    }\n----\n\nLet's test this method:\n\n[source,java]\n----\n        final int rc = doAsync(() -\u003e {\n            final ATestQueue\u003cInteger\u003e queue = new TestQueue\u003cInteger\u003e().export();\n            return aAll(() -\u003e aSeqForUnit(rangeIterator(0, 10), i -\u003e {\n                queue.put(i + 1);\n                return aTrue();\n            })).and(() -\u003e aSeqForCollect(rangeIterator(0, 10),\n                    i -\u003e queue.take(),\n                    Collectors.summingInt((Integer i) -\u003e i))\n            ).selectValue2();\n        });\n        assertEquals((11 * 10) / 2, rc);\n----\n\n==== Asynchronous Proxy Generator\n\nThe AsyncFlows framework includes annotation processor for generating proxies.\nThis annotation\nprocessor is used for generating proxies for all asynchronous interfaces in the framework.\n\nTo enable annotation processor, add it as optional dependency like the following:\n\n[source, xml, subs=\"attributes,verbatim\"]\n----\n        \u003cdependency\u003e\n            \u003cgroupId\u003eorg.asyncflows\u003c/groupId\u003e\n            \u003cartifactId\u003easyncflows-apt\u003c/artifactId\u003e\n            \u003cversion\u003e{stable-version}\u003c/version\u003e\n            \u003coptional\u003etrue\u003c/optional\u003e\n        \u003c/dependency\u003e\n----\n\nThe annotation processor will generate proxies for all interfaces with `@Asynchronous`\nannotation.The implementation will be generated only for non-default interface methods.\n\nThe generated proxy will look like the following:\n\n[source,java]\n----\n@javax.annotation.Generated(\"org.asyncflows.apt.AsynchronousProxyProcessor\")\npublic final class ATestQueueProxyFactory implements java.util.function.BiFunction\u003corg.asyncflows.core.vats.Vat, java.lang.Object, java.lang.Object\u003e, org.asyncflows.core.util.AsynchronousService {\n    public static final ATestQueueProxyFactory INSTANCE = new ATestQueueProxyFactory();\n\n    /**\n     * Create a proxy.\n     *\n     * @param vat     the vat\n     * @param service the service to export\n     * @param \u003cT\u003e a type parameter\n     * @return the exported service\n     */\n    public static \u003cT\u003e org.asyncflows.core.util.sample.ATestQueue\u003cT\u003e createProxy(org.asyncflows.core.vats.Vat vat, org.asyncflows.core.util.sample.ATestQueue\u003cT\u003e service) {\n        return new ATestQueueAsyncProxy\u003cT\u003e(vat, service);\n    }\n\n    /**\n     * Create a proxy.\n     *\n     * @param vat     the vat\n     * @param service the service to export\n     * @param \u003cT\u003e a type parameter\n     * @return the exported service\n     */\n    public \u003cT\u003e org.asyncflows.core.util.sample.ATestQueue\u003cT\u003e export(org.asyncflows.core.vats.Vat vat, org.asyncflows.core.util.sample.ATestQueue\u003cT\u003e service) {\n        return createProxy(vat, service);\n    }\n\n    @Override\n    @SuppressWarnings(\"unchecked\")\n    public java.lang.Object apply(org.asyncflows.core.vats.Vat vat, java.lang.Object service) {\n        return createProxy(vat, (org.asyncflows.core.util.sample.ATestQueue) service);\n    }\n\n    @javax.annotation.Generated(\"org.asyncflows.apt.AsynchronousProxyProcessor\")\n    private static final class ATestQueueAsyncProxy\u003cT\u003e implements org.asyncflows.core.util.sample.ATestQueue\u003cT\u003e {\n        private final org.asyncflows.core.vats.Vat vat;\n        private final org.asyncflows.core.util.sample.ATestQueue\u003cT\u003e service;\n\n        private ATestQueueAsyncProxy(final org.asyncflows.core.vats.Vat vat, final org.asyncflows.core.util.sample.ATestQueue\u003cT\u003e service) {\n            java.util.Objects.requireNonNull(vat);\n            java.util.Objects.requireNonNull(service);\n            this.vat = vat;\n            this.service = service;\n        }\n\n        @Override\n        public int hashCode() {\n            return System.identityHashCode(service);\n        }\n\n        @Override\n        public boolean equals(java.lang.Object o2) {\n            return this == o2 || (o2 != null \u0026\u0026 o2.getClass() == getClass() \u0026\u0026 ((ATestQueueAsyncProxy)o2).service == this.service);\n        }\n\n        @Override\n        public org.asyncflows.core.Promise\u003cT\u003e take() {\n            return org.asyncflows.core.CoreFlows.aLater(this.vat, () -\u003e this.service.take());\n        }\n\n        @Override\n        public void put(T element) {\n            org.asyncflows.core.CoreFlows.aOneWay(this.vat, () -\u003e this.service.put(element));\n        }\n    }\n}\n----\n\nThe rules are the following:\n\n* The default interface methods are not delegated, and the default implementation is used.\nThese methods are supposed to provide utility services.\n* The methods that are returning `Promise` are delegated to the Proxy's vat using aLater operator.\n* The methods that are returning void are delegated to the Proxy's vat using aOneWay operator.\n* Other methods just throw a `UnsupportedOperationException`\n\n=== Garbage Collection Consideration\n\nThe framework objects are generally garbage collected by Java.\nThere is no need to perform explicit cleanup for them, if they do not hold any sensitive resources like IO streams.\n\nThe object is prevented from garbage collection in the following cases:\n\n* There is a direct reference to object or its proxy\n* There is an event on the queue that references the object\n* There is a listener registered to some uncompleted promise, that is held by the external listener.\nThis usually means that there is some asynchronous operation is in progress.\n\nGenerally, the rules for garbage collection are the same as for normal Java code.\nBut we also need to consider promise chains as a call stack.\nSo references held by promises should be considered as stack references to objects.\n\nThe vat object is shared between many AsyncFlows objects and asynchronous operators.\nThe Vat might need to be stopped.\nHowever, this usually apply to Vats that occupy thread like `SelectorVat` or `SingleThreadVat`.\nEven for these vats starting/stopping is handled by the utility methods `doAsync(...)`\nand `SelectorVatUtil.run(...)`.\n\n=== Concurrency Considerations\n\nIt is assumed that asynchronous operations do not invoke blocking functionality.\nSo many simultaneous asynchronous operations will safely take their turns on the single queue.\nHowever, it is not always so as some operations require calls of non-asynchronous API or to perform CPU-intensive operations.\n\nCPU-bound operations should be generally delegated to the ForkJoin pool (`aForkJoinGet(...)`).\nIO-bound synchronous operations should be delegated to daemon thread pool (`aDaemonGet(...)`).\nIf you are in doubt, just send it to daemon pool.\nThere are utilities that start operations on corresponding pools using vats.These operations do not establish asynchronous context on corresponding pools, so they are quite lightweight and suitable to invocation of some synchronous method.\n\nIf asynchronous context need to be established, it is better to use `aLater(Vats.daemonVat(), ...)`\nor `aLater(Vats.forkJoinVat(), ...)`.\nThese operations will create a new vats that runs over corresponding pools.\n\n=== Request Queue\n\nIn the queue sample, the asynchronous operations are written in the way, that no new problems will happen if method will be called before some previous method finishes.\nIn Java synchronous code this is usually handled by the statement 'synchronized'.\nIn this framework similar functionality is provided by `RequestQueue`.\nThe biggest difference from Java synchronization is that nested invocations of request queue are not supported.\nOther major difference is that this utility class is indendent for use from single vat, so it should not be exposed outside of the asynchronous components.\n\nThe basic method of `RequestQueue` is `run(ASupplier\u003cT\u003e)`, this method has some utility variants like\n`runSeqWhile(...)`.\nThis method executes method if request queue is empty and no method is executing currently, and suspends execution putting it to the queue if there is some execution in progress.\nSo it is some kind of private event queue, but more flexible.\nThere are also suspend/resume utility methods that are analogs of Java wait/notify.\n\nAs example, lets consider `Semaphore` implementation similar to Java `Semaphore` class.\n\n[source,java]\n----\npublic interface ASemaphore {\n    void release(int permits);\n    void release();\n    Promise\u003cVoid\u003e acquire();\n    Promise\u003cVoid\u003e acquire(int permits);\n}\n----\n\nThe class in the library is implemented like the following:\n\n[source,java]\n----\npublic final class Semaphore implements ASemaphore, ExportableComponent\u003cASemaphore\u003e {\n    private final RequestQueue requests = new RequestQueue();\n    private int permits;\n\n    public Semaphore(final int permits) {\n        this.permits = permits;\n    }\n\n    @Override\n    public void release(final int releasedPermits) {\n        if (releasedPermits \u003c= 0) {\n            return;\n        }\n        permits += releasedPermits;\n        requests.resume();\n    }\n\n    @Override\n    public void release() {\n        release(1);\n    }\n\n    @Override\n    public Promise\u003cVoid\u003e acquire() {\n        return acquire(1);\n    }\n\n    @Override\n    public Promise\u003cVoid\u003e acquire(final int requestedPermits) {\n        if (requestedPermits \u003c= 0) {\n            return aFailure(new IllegalArgumentException(\"The requestedPermits must be positive: \" + requestedPermits));\n        }\n        return requests.runSeqWhile(() -\u003e {\n            if (requestedPermits \u003c= permits) {\n                permits -= requestedPermits;\n                return aFalse();\n            } else {\n                return requests.suspendThenTrue();\n            }\n        });\n    }\n\n    @Override\n    public ASemaphore export(final Vat vat) {\n        return UtilExporter.export(vat, this);\n    }\n}\n----\n\nThe method `acquire(...)` needs to be ordered to implement FIFO ordering.\nSome parts of the method do not need to be protected, and we can check input as we please.\nThe rest of method is the protected loop.\nIn the loop we check if there are permits available, and if they are, we just stop loop and this cause promise returned by run method to resolve as well.\nHowever, if they are not available, we suspend execution, and we repeat operation when suspend ends.\n\nThe operation `release(...)` does not need to be ordered.\nSo it is not protected by request queue.\nThe release method invokes `requests.resume()` to notify `acquire(...)` requests that new permits were added.\nThe promise returned from suspend resolves on it, and the acquisition loop continues.\nNew amount of permits might be sufficient or not.\nIt is decided in the context of the operation `acquire(...)`.\nIf there is no acquire operation pending, the resume operation is doing nothing.\n\nLet's see how it works in test:\n\n[source,java]\n----\n        final ArrayList\u003cInteger\u003e result = new ArrayList\u003c\u003e();\n        final Void t = doAsync(() -\u003e {\n            final ASemaphore semaphore = new Semaphore(0).export();\n            //noinspection Convert2MethodRef\n            return aAll(() -\u003e\n                            aSeq(\n                                    () -\u003e semaphore.acquire().listen(o -\u003e result.add(1))\n                            ).thenFlatGet(\n                                    () -\u003e semaphore.acquire(3).listen(o -\u003e result.add(2))\n                            ).thenFlatGet(\n                                    () -\u003e semaphore.acquire().listen(o -\u003e result.add(3))\n                            )\n            ).andLast(() -\u003e\n                    aSeq(\n                            () -\u003e aForRange(0, 10).toVoid()\n                    ).thenFlatGet(() -\u003e {\n                        result.add(-1);\n                        semaphore.release(2);\n                        return aVoid();\n                    }).thenFlatGet(\n                            () -\u003e aForRange(0, 10).toVoid()\n                    ).thenFlatGet(() -\u003e {\n                        result.add(-2);\n                        semaphore.release();\n                        return aVoid();\n                    }).thenFlatGet(\n                            () -\u003e aForRange(0, 10).toVoid()\n                    ).thenFlatGet(() -\u003e {\n                        result.add(-3);\n                        semaphore.release(3);\n                        return aVoid();\n                    }));\n        });\n        assertSame(null, t);\n        assertEquals(Arrays.asList(-1, 1, -2, -3,  2, 3), result);\n----\n\n== Troubleshooting\n\n=== Logging\n\nThe framework uses slf4j for logging.\nAll exceptions that are received during listener notification are logged on the debug level.\nIf you do not receive some events for some reason, you could try enabling debug logging for the framework.\n\nA good logging could greatly help troubleshooting the applications.\n\n=== Trace Provider\n\nThe execution trace of asynchronous operations is difficult to record.\nIn the framework, it is possible to enable call tracing for the application using system property:\n\n[source,properties]\n----\norg.asyncflows.core.trace.provider=EXCEPTION\n----\n\nIf this property is enabled, the stack trace will look like the following:\n\n[source]\n----\njava.lang.IllegalStateException: Test\n\tat org.asyncflows.core.CoreFlowsTest.lambda$null$3(CoreFlowsTest.java:51)\n\tat org.asyncflows.core.CoreFlows.aNow(CoreFlows.java:191)\n\tat org.asyncflows.core.CoreFlows.lambda$null$2(CoreFlows.java:256)\n\tat org.asyncflows.core.vats.BatchedVat.runBatch(BatchedVat.java:148)\n\tat org.asyncflows.core.vats.SingleThreadVatWithIdle.runInCurrentThread(SingleThreadVatWithIdle.java:63)\n\tat org.asyncflows.core.AsyncContext.doAsyncOutcome(AsyncContext.java:69)\n\tat org.asyncflows.core.AsyncContext.doAsync(AsyncContext.java:82)\n\t... 55 more\n\tSuppressed: org.asyncflows.core.trace.PromiseTraceExceptionProvider$PromiseTraceException\n\t\tat org.asyncflows.core.PromiseTraceExceptionProvider.recordTrace(PromiseTraceExceptionProvider.java:102)\n\t\tat org.asyncflows.core.Promise.\u003cinit\u003e(Promise.java:92)\n\t\tat org.asyncflows.core.CoreFlows.aResolver(CoreFlows.java:171)\n\t\tat org.asyncflows.core.CoreFlows.aLater(CoreFlows.java:255)\n\t\tat org.asyncflows.core.CoreFlows.aLater(CoreFlows.java:268)\n\t\tat org.asyncflows.core.CoreFlowsTest.lambda$testThrowLater$4(CoreFlowsTest.java:50)\n\t\tat org.asyncflows.core.CoreFlows.aNow(CoreFlows.java:191)\n\t\tat org.asyncflows.core.AsyncContext.lambda$doAsyncOutcome$1(AsyncContext.java:65)\n\t\t... 59 more\n----\n\nThe exception `org.asyncflows.core.PromiseTraceExceptionProvider$PromiseTraceException`\nis entry created by the exception trace provider.This provider is quite expensive from CPU perspective as it creates an exception for each unresolved promise, so it is suggested to use it only during problem investigation.\n\nThis feature is experimental.It is also possible to write own trace providers.Refer to interface\nlink:asyncflows-core/src/main/java/org/asyncflows/core/trace/PromiseTraceProvider.java[PromiseTraceProvider]\nfor more information.\n\n=== Debugging Considerations\n\nWhen debugging, the stack trace is not available directly, but it is still possible to examine asynchronous stack by starting from resolvers passed from upper contexts.\nThe Java saves variables in Java objects referenced by lambdas.\nIf trace feature is enabled, it is also possible to find out stack trace for location where promise was created.\n\nSo the debugging is more difficult, but it is still possible using framework.\n\n== Library\n\n=== Streams\n\nStreams library is similar to Java stream library, but there are some key differences.The first obvious difference\nis that asynchronous streams provide asynchronous stream access operations.The second difference is API design.\n\n==== Pull Streams\n\nAsynchronous streams provide two lean interfaces and there is no intention to provide additional operations here.\n\n[source,java]\n----\npublic interface AStream\u003cT\u003e extends ACloseable {\n    Promise\u003cMaybe\u003cT\u003e\u003e next();\n}\n\npublic interface ASink\u003cT\u003e extends ACloseable {\n    Promise\u003cVoid\u003e put(T value);\n    Promise\u003cVoid\u003e fail(Throwable error);\n    Promise\u003cVoid\u003e finished();\n}\n----\n\nThe stream operations like map, flatMap, filter, and others are provided by stream builders.Work with StreamBuilder\ntypically starts with some `AsyncStreams` class method like `aForRange` or `aForStream`.Stream building starts\nin `pull` mode.So all elements will be processed sequentially.The stream builder supports typical stream operations\nlike `map`, `filter`, `flatMap`, `leftFold`, and `collect`.These operations accept asynchronous operations instead of\nsynchronous ones.\n\n[source,java]\n----\n        final int rc = doAsync(() -\u003e\n                aForRange(0, 11)\n                        .filter(i -\u003e aBoolean(i % 2 == 0))\n                        .map(i -\u003e aValue(i / 2))\n                        .collect(Collectors.summingInt(e -\u003e e))\n        );\n        assertEquals(15, rc);\n----\n\nSome methods also have the variant `Sync` that accepts Java functional interfaces.\n\n[source,java]\n----\n        final int rc = doAsync(() -\u003e\n                aForRange(0, 11)\n                        .filterSync(i -\u003e i % 2 == 0)\n                        .mapSync(i -\u003e i / 2)\n                        .collect(Collectors.summingInt(e -\u003e e))\n        );\n        assertEquals(15, rc);\n----\n\nIt is also possible to specify processing window.\nThis window is basically prefetch buffer for a sequential stream.\nIf several stages take long time, it is reasonable to start processing next records at advance up to specified limit.\nThe example below specifies that exactly one element is pre-fetched.\nThe sample is also shows usage of `process(...)` method that could be used to implement reusable parts of processing pipeline.\n\n[source,java]\n----\n        final Function\u003cStreamBuilder\u003cInteger\u003e, StreamBuilder\u003cInteger\u003e\u003e delay =\n                s -\u003e s.map(a -\u003e aForRange(0, 10).toVoid().thenValue(a));\n        List\u003cInteger\u003e result = new ArrayList\u003c\u003e();\n        final int rc = doAsync(() -\u003e\n                aForRange(0, 10)\n                        .filter(i -\u003e aBoolean(i % 2 == 0))\n                        .mapSync(a -\u003e {\n                            result.add(a);\n                            return a;\n                        })\n                        .window(1)\n                        .process(delay)\n                        .mapSync(a -\u003e {\n                            result.add(-a);\n                            return a;\n                        })\n                        .map(i -\u003e aValue(i / 2))\n                        .collect(Collectors.summingInt(e -\u003e e))\n        );\n        assertEquals(10, rc);\n        assertEquals(Arrays.asList(0, 2, -0, 4, -2, 6, -4, 8, -6, -8), result);\n----\n\n==== 'All' Streams\n\nThe all stream process values in the same way, but the difference is that all steps between `.all()` call\nand final processing of values (or switch to `pull()`) are always processed, even in case of failures.This allows\nto ensure processing of group of objects even in case of failures.For example, to close a collection of streams,\neven if close operation on some of them fail.\n\nLike for `aAll*` operators, the processing done is parallel for all elements.However, it is possible to limit\namount of parallel processing using `.window(n)` call.In that case only several elements will be processed\nat the same time.This might be useful if the task is taxing on resources.\n\n[source,java]\n----\n        final int rc = doAsync(() -\u003e\n                aForRange(0, 11)\n                        .all(2)\n                        .filterSync(i -\u003e i % 2 == 0)\n                        .mapSync(i -\u003e i / 2)\n                        .collect(Collectors.summingInt(e -\u003e e))\n        );\n        assertEquals(15, rc);\n----\n\nNote, while each stage is parallel, the current implementation waits until previous element was passed to next stage before passing element to next stage.\nThis might introduce delays to processing, but maintain the same order as pull stream processing.\nMore optimized solution might be developed later.\n\n==== Working with resources\n\nStream is closeable resource, and it is possible to work with a stream and other closeable resources with\n`aTry` statement similar to Java language `try` statement.\nThe try statement accepts resource references, promises for resource references, and actions that open resources.\nThen it closes resource after it has been used.\nLet's define a simple resource.\n\n[source,java]\n----\n    public static class SampleResource implements ACloseable, ExportableComponent\u003cACloseable\u003e {\n        private final Cell\u003cBoolean\u003e closed;\n\n        public SampleResource(final Cell\u003cBoolean\u003e closed) {\n            this.closed = closed;\n        }\n\n        @Override\n        public Promise\u003cVoid\u003e close() {\n            closed.setValue(true);\n            return aVoid();\n        }\n\n        @Override\n        public ACloseable export(final Vat vat) {\n            return () -\u003e ResourceUtil.closeResource(vat, SampleResource.this);\n        }\n    }\n----\n\nThis resource just support close action.Also, to support work with resources there are classes\nCloseableBase and ChainedCloseableBase that simplify creating resource wrappers.Now, we could try\ndifferent options of working with resources:\n\n[source,java]\n----\n        final Cell\u003cBoolean\u003e r1 = new Cell\u003c\u003e(false);\n        final Cell\u003cBoolean\u003e r2 = new Cell\u003c\u003e(false);\n        final Cell\u003cBoolean\u003e r3 = new Cell\u003c\u003e(false);\n        doAsync(() -\u003e aTry(\n                () -\u003e aValue(new SampleResource(r1).export())\n        ).andChain(\n                value -\u003e aValue(new SampleResource(r2).export())\n        ).andChainSecond(\n                value -\u003e aValue(new SampleResource(r3).export())\n        ).run((value1, value2, value3) -\u003e aVoid()));\n        assertTrue(r1.getValue());\n        assertTrue(r2.getValue());\n        assertTrue(r3.getValue());\n----\n\nUp to three resources could be opened with one `aTry` operator.\nHowever, it is also possible to nest `aTry` operators, so previously opened resources are accessible in lexical scope.\n\n=== IO Library\n\n==== Core IO\n\nThe IO library is also built upon lean interfaces and different operations built upon it.\nThe following are core interfaces of the library:\n\n[source,java]\n----\npublic interface AInput\u003cB extends Buffer\u003e extends ACloseable {\n    Promise\u003cInteger\u003e read(B buffer);\n}\npublic interface AOutput\u003cB extends Buffer\u003e extends ACloseable {\n    Promise\u003cVoid\u003e write(B buffer);\n    Promise\u003cVoid\u003e flush();\n}\npublic interface AChannel\u003cB extends Buffer\u003e extends ACloseable {\n    Promise\u003cAInput\u003cB\u003e\u003e getInput();\n    Promise\u003cAOutput\u003cB\u003e\u003e getOutput();\n}\n----\n\nAs you could see, these interfaces are suitable for both character IO and byte IO. Some operations that work with these interfaces are\n[generic](asyncflows-io/src/main/java/org/asyncflows/io/IOUtil.java).\n\nThe following functionality is supported out of the box:\n\n* Character encoding(link:asyncflows-io/src/main/java/org/asyncflows/io/text/DecoderInput.java[DecoderInput]) / decoding(link:asyncflows-io/src/main/java/org/asyncflows/io/text/EncoderOutput.java[EncoderOutput])\n* Digesting (link:asyncflows-io/src/main/java/org/asyncflows/io/util/DigestingInput.java[DigestingInput]) and\nlink:asyncflows-io/src/main/java/org/asyncflows/io/util/DigestingOutput.java[DigestingOutput])\n* GZip (link:asyncflows-io/src/main/java/org/asyncflows/io/util/DigestingInput.java[GZipInput]) and\nlink:asyncflows-io/src/main/java/org/asyncflows/io/util/DigestingOutput.java[GZipOutput]), Deflate (link:asyncflows-io/src/main/java/org/asyncflows/io/util/DeflateOutput.java[DeflateOutput]), and Inflate (link:asyncflows-io/src/main/java/org/asyncflows/io/util/InflateInput.java[InflateInput])\n* Utility streams\n* Synchronous stream link:asyncflows-io/src/main/java/org/asyncflows/io/adapters[adapters].\n\n==== Network Library\n\nThere are two implementations of socket library based on traditional blocking sockets and selector library.\nThe later an implementation based on asynchronous sockets is planned to be tested.\n\nImplementation based on traditional blocking sockets API sometimes hangs on Windows, so it is not recommended to use if runtime also supports selector sockets.\nThis implementation is left only backward compatibility with non-complete Java runtimes.\n\nThe sockets are just byte channels with few additional operators, and they support the same operations.\nHowever, there are few additional operations.\n\n[source,java]\n----\npublic interface ASocket extends AChannel\u003cByteBuffer\u003e {\n    Promise\u003cVoid\u003e setOptions(SocketOptions options);\n    Promise\u003cVoid\u003e connect(SocketAddress address);\n    Promise\u003cSocketAddress\u003e getRemoteAddress();\n    Promise\u003cSocketAddress\u003e getLocalAddress();\n}\npublic interface AServerSocket extends ACloseable {\n    Promise\u003cSocketAddress\u003e bind(SocketAddress address, int backlog);\n    Promise\u003cSocketAddress\u003e bind(SocketAddress address);\n    Promise\u003cVoid\u003e setDefaultOptions(SocketOptions options);\n    Promise\u003cSocketAddress\u003e getLocalSocketAddress();\n    Promise\u003cASocket\u003e accept();\n}\npublic interface ASocketFactory {\n    Promise\u003cASocket\u003e makeSocket();\n    Promise\u003cAServerSocket\u003e makeServerSocket();\n    Promise\u003cADatagramSocket\u003e makeDatagramSocket();\n}\npublic interface ADatagramSocket extends ACloseable {\n    Promise\u003cVoid\u003e setOptions(SocketOptions options);\n    Promise\u003cVoid\u003e connect(SocketAddress address);\n    Promise\u003cVoid\u003e disconnect();\n    Promise\u003cSocketAddress\u003e getRemoteAddress();\n    Promise\u003cSocketAddress\u003e getLocalAddress();\n    Promise\u003cSocketAddress\u003e bind(SocketAddress address);\n    Promise\u003cVoid\u003e send(ByteBuffer buffer);\n    Promise\u003cVoid\u003e send(SocketAddress address, ByteBuffer buffer);\n    Promise\u003cSocketAddress\u003e receive(ByteBuffer buffer);\n}\n----\n\nThese interfaces could be used in the way similar to traditional synchronous code.\nSee link:asyncflows-io/src/test/java/org/asyncflows/io/net/samples/EchoServerSample.java[echo server]\nand link:asyncflows-io/src/test/java/org/asyncflows/io/net/samples/EchoClientSample.java[echo client]\nas examples.\n\n==== TLS support\n\nTLS implementation relies on Java SSLEngine for asynchronous processing, so it follows all restrictions enforced by it.Note, SSL protocols are not supported by Java's SSLEngine anymore, so the framework stick with TLS name.\n\nThe TLS implementation is just a ASocketFactory that wraps other socket factory.Interfaces are the same as for sockets with two additional operations on the socket:\n\n[source,java]\n----\npublic interface ATlsSocket extends ASocket {\n    Promise\u003cVoid\u003e handshake();\n    Promise\u003cSSLSession\u003e getSession();\n}\n----\n\nFirst one allows initiating handshake, the second one allows accessing session and examining certificates.\n\nThere are no TLS related parameters on TlsSocket factory, instead there are a factory methods for SSLEngine which allow configuring needed parameters for SSLEngine before using it in the processing:\n\n[source,java]\n----\npublic class TlsSocketFactory implements ASocketFactory, ExportableComponent\u003cASocketFactory\u003e {\n    public void setServerEngineFactory(final AFunction\u003cSocketAddress, SSLEngine\u003e serverEngineFactory) {\n       ...\n    }\n    public void setClientEngineFactory(final AFunction\u003cSocketAddress, SSLEngine\u003e clientEngineFactory) {\n        ...\n    }\n}\n----\n\nThese factories need to configure TLS parameters basing on SocketAddress.It is expected, that different TlsSocketFactory instances will be used for different security contexts.\n\n==== HTTP 1.1 support\n\nThe framework provides experimental support for HTTP 1.1 protocol on client and server side.\nThe code is currently more like low-level protocol implementation rather than ready to use application server.The neither side is finished, but it could be experimented with.\nHTTPS is not implemented at the moment.\n\nSee [unit test](asyncflows-protocol-http/src/test/java/org/asyncflows/protocol/http/core) for sample code.\n\n== How framework addresses the typical problems\n\n=== Back pressure\n\nMany asynchronous libraries have a back pressure problem.\nWhen one source of data provides more data than consumer might consume.\nSome frameworks did not have a solution for the problem (like Netty before 4.0), some introduce unnatural solutions like disabling/enabling reading (like Vert.x and modern Netty), some hide it inside framework (like Akka), or provide a separate event listeners for channels (like Apache HttpCore Async 5.x).\n\nHowever, there is no such problem with synchronous io in Java, as streams block if nothing could be written to it:\n\n[source,java]\n----\nlong length = 0;\nbyte[] b = new byte[4096]\nwhile(true)  {\n   int c = in.read(b)\n   if(c \u003c 0) {\n      break;\n   }\n   length += c;\n   out.write(b, 0, c);\n}\nreturn length;\n----\n\nThat is practically all.Back pressure propagates naturally via blocking.No more data will be read, if write is not complete.If there is error, it will be propagated to caller.\n\nThe framework provides practically the same approach.There is no explicit backpressure control.\nAnd instead of thread blocks there is waiting for events.\nThe output stream is accepting request, and return to caller when it is finished processing it, including sending data to downstream.\n\n[source,java]\n----\n    public final Promise\u003cLong\u003e copy(final AInput\u003cByteBuffer\u003e input, final AOutput\u003cByteBuffer\u003e output, int bufferSize) {\n        ByteBuffer buffer = ByteBuffer.allocate(bufferSize);\n        final long[] result = new long[1];\n        return aSeqWhile(\n                () -\u003e input.read(buffer).flatMap(value -\u003e {\n                    if (isEof(value)) {\n                        return aFalse();\n                    } else {\n                        result[0] += +value;\n                        buffer.flip();\n                        return output.write(buffer).thenFlatGet(() -\u003e {\n                            buffer.compact();\n                            return aTrue();\n                        });\n                    }\n                })\n        ).thenGet(() -\u003e result[0]);\n    }\n----\n\nThere are more code as asynchronous operations need to be handled and working with buffers is more complex\nthan with arrays, but still it is very similar to what is written for synchronous streams.\n\nSuch way of handling back pressure does not necessary limit parallelism.It is possible to use features of the\nframework to ensure that reads and writes are done in parallel when it makes sense.\n\n[source,java]\n----\n    public static Promise\u003cLong\u003e copy(final AInput\u003cByteBuffer\u003e input, final AOutput\u003cByteBuffer\u003e output, int buffers, int bufferSize) {\n        final SimpleQueue\u003cByteBuffer\u003e readQueue = new SimpleQueue\u003c\u003e();\n        final SimpleQueue\u003cByteBuffer\u003e writeQueue = new SimpleQueue\u003c\u003e();\n           final Cancellation cancellation = cancellation();\n        for (int i = 0; i \u003c buffers; i++) {\n            readQueue.put(ByteBuffer.allocate(bufferSize));\n        }\n        final long[] result = new long[1];\n        return aAll(\n                () -\u003e aSeqWhile(\n                           () -\u003e cancellation.run(readQueue::take).flatMap(\n                                   b -\u003e cancellation.run(() -\u003e input.read(b)).flatMap(c -\u003e {\n                            if (isEof(c)) {\n                                writeQueue.put(null);\n                                return aFalse();\n                            } else {\n                                result[0] += c;\n                                writeQueue.put(b);\n                                return aTrue();\n                            }\n                        }))\n                )\n        ).and(\n                () -\u003e aSeqWhile(\n                           () -\u003e cancellation.run(writeQueue::take).flatMap(b -\u003e {\n                            if(b == null) {\n                                return aFalse();\n                            } else {\n                                b.flip();\n                                   return cancellation.run(() -\u003e output.write(b)).thenGet(() -\u003e {\n                                    b.compact();\n                                    readQueue.put(b);\n                                    return true;\n                                });\n                            }\n                        })\n                )\n        ).map((a, b) -\u003e aValue(result[0]));\n    }\n----\n\nIn the provided sample, the read operation uses buffers to read when available, and writes when buffer with data is available.\nSo if writes are slower or reads are slower, the algorithm will adapt to the speed.\nThis algorithm makes sense with no more than four buffers, as one buffer is for reading, one for writing, and two are in flight over the queue.\n\n=== Control flow inversion\n\nMost of asynchronous libraries require inversion of control flow.\nMost of asynchronous frameworks use concepts like decoders and encoders.\nThese are two poor things that have to implement explicit tracking of the current state of reading or writing.\nIf there is a recursive state like xml or json, they have to keep the explicit stack of state.\n\nThe biggest problem with such approach is that such code is not readable as state of the process does not match state of the code.\nThis is exactly the same problem that is mentioned is the famous article Edsger W. Dijkstra \"Go To Statement Considered Harmful\".\nThere is excellent analysis of that article that translates the article to more modern context:\nhttp://david.tribble.com/text/goto.html[David R. Tribble \"Go To Statement Considered Harmful: A Retrospective\"].\nControl flow inversion causes the same problem as it was described by Edsger W. Dijkstra:\n\n[quote,Edsger W. Dijkstra,Go To Statement Considered Harmful,1968]\n____\nMy second remark is that our intellectual powers are rather geared to master static relations and that our powers to visualize processes evolving in time are relatively poorly developed.\nFor that reason we should do (as wise programmers aware of our limitations) our utmost to shorten the conceptual gap between the static program and the dynamic process, to make the correspondence between the program (spread out in text space) and the process (spread out in time) as trivial as possible.\n____\n\nIt is very hard to understand what is happening in the process and to what states it could go by analysis of the code.It is much simpler when control flow is evident from the code structure.AsyncFlows library provide such flow.\n\nI would say that direct event sending to some queue or actor is similar to \"go to\" operator in programming languages.At least it has the same properties.\n\n[quote,Edsger W. Dijkstra,Go To Statement Considered Harmful,1968]\n____\nThe unbridled use of the go to statement has an immediate consequence that it becomes terribly hard to find a meaningful set of coordinates in which to describe the process progress.Usually, people take into account as well the values of some well chosen variables, but this is out of the question because it is relative to the progress that the meaning of these values is to be understood!With the go to statement one can, of course, still describe the progress uniquely by a counter counting the number of actions performed since program start (viz. a kind of normalized clock).\nThe difficulty is that such a coordinate, although unique, is utterly unhelpful.In such a coordinate system it becomes an extremely complicated affair to define all those points of progress where, say, n equals the number of persons in the room minus one!\n____\n\nIf we have event handlers, that are to keep own state, we also do no have a context, that helps us to understand context.We need to consider all events to be possible at every moment of time.The pain is real.\nFor example of pain of Actor programming paradigm cased by event sending in Erlang context, one could watch the presentation https://www.infoq.com/presentations/Death-by-Accidental-Complexity[Death\nby Accidental Complexity].\nWhile presentation is using Erlang sample, the problems described are common for many other technologies, particularly Actor-based.\n\n[quote,Ulf Wiger,Death by Accidental Complexity (slide Apparent Problems at 26:49)]\n____\n* The whole matrix needs to be revisited if messages/features are added or removed\n* What we do in each cell is by no means obvious - depends on history\n* What to do when unexpected message arrives in a transition state is practically never specified (we must invent some reasonable response.)\n* Abstraction is broken, encapsulation is broken\n* Code reuse becomes practically impossible\n____\n\nThe core of the problem is the same as what was described by Edsger W. Dijkstra for \"go to\": the code structure does not mach control flow structure, so we could not reason about application state by reading code.\nThe solution to the problem is also the same: structured asynchronous programming.\nWhile Ulf Wiger identifies the problem correctly in the presentation, the proposed solution looks like poor man semi-structured programming using event filtering.\n\n== Inter-Process Communications\n\nThe AsyncFlows framework is intended to implement control flow inside the application.\nThere is no special means to organize inter-process communications.\nHowever, the libraries could be used to organize such communications.\nFor example, JAX-RS 2.0 supports asynchronous invocations in client and server contexts.\n\nThe most of inter-process communication protocols are currently based on the language and application independent meta-protocols, where exact choices it depends on the context.\nMost popular now are HTTP-based protocols, and additional transports like Web Sockets are also getting popular in some contexts.\nIn some specific situations even memory-mapped files works well.\nAs for message formats, there is a wide range of them starting from XML and JSON to ASN.1 and protobuf.\n\nPrescribing a specific solution is not practical in the current situation.\nThe framework is designed in the way that allows implementing most of such solutions over it.\nIf there is a ready to use asynchronous API, the framework might reuse it with some wrappers.\n\n== Java EE support\n\nTBD\n\n=== Spring Framework\n\nTBD\n\n=== Servlets\n\nTBD\n\n=== JAX-RS\n\nTBD\n\n== Comparison with other frameworks\n\n=== Actors (Akka)\n\nComparing with Scala actors, there are the following key points of difference.\n\n1. In the AsyncFlows framework, component and event queue are separated and one queue could support many small components.\nPractically, there is at least one one asynchronous micro-component for each asynchronous operation.In Scala, there are only one asynchronous component for each event queue.This leads to problems with resource management as state of component need to be tracked.\n\n2. Event dispatch in Akka is done explicitly and each queue supports only closed set of events.\nThere is no interfaces for components and even returning result is different each time.(TypedActors try to solve problem of explicit dispatch, but introduce own set of the problems due to blocking calls, and also still support only closed set of events).\nAsyncFlows support open set of events, as they translate to `Runnable` anyway.As many components could leave\n\n3. Actors are heavy-weight as they are integrated with event queue.They also need to be deleted explicitly to free resources.By comparison, AsyncFlows do not manage components explicitly, as they could garbage collected normally.\nSome Vats needs to be managed explicitly, but these vats are usually used as application starting point in the main thread or have the same lifetime as application (NIO).\nExecutorVat does not need to be explicitly stopped (the underlying executor needs to be stopped, but daemon executor creates and frees threads as needed and does not need to be stopped).\n\n4. As Akka Actors work with event queue directly, it is possible handle events not in the order they were sent to actor.\nAsyncFlows insists on handling events in the order they are received by a vat.Reordering of event handling still could be done by utility classes like RequestQueue.\n\nGenerally, AsyncFlows support more flexible management of asynchronous components, and their relationship to event queues.\nAlso, AsyncFlows support running the entire network application in the single thread, while Akka requires multiple threads by design.\n\n=== CompletableFuture\n\nJava's CompletableFuture is similar to AsyncFlows Promise.\nCompletableFuture has a lot of utility methods that implement much of functionality similar to provided by the AsyncFlows framework.\nHowever, AsyncObjects Framework shifts this functionality from Promise to operators that are built upon Promise (operation builders, static methods).\nThe difference is small, but it greatly affects usability as AsyncFlows does not need a lot of methods since many methods could be replaced by combination of existing method.\n\nThere was an experimental version of the framework that used CompletableFuture as foundation instead of promise.\nHowever, this version proved to be less usable, as it is more complex to listen for events, for example it is not possible just to listen to CompletableFuture w/o creating another completable future.\n\nAlso, the defaults for execution context are different.\nThe framework defaults to the current Vat.\nThe CompletableFuture defaults to ForkJoin pool.\nThis pool is generally not acceptable for IO operations, and IO could block it for indefinite time.\nSmall errors could lead to application blocking.\nPractically all invocations on CompletableFuture required explicit specification of target vat.\n\nAsyncFlows also has a lot of utility methods, that do not make sense as CompletableFuture API.\nFor example, loops, request queues, cancellation.\n\nAlso, CompletableFuture does not have an associated component model.\nIt was designed as an isolated class that would be useful in many contexts, rather than as a core part of something bigger.\n\n=== Netty\n\nThe netty is organized as multi-stage event processing.It works very well when uniform processing is needed.\nThe problem is that processing that is needed is often non-uniform.\nThere are generally recursive logical asynchronous processes built upon event streams.Netty requires implementing such processes using explicit stacks and other means.\n\nIn contrast, AsyncFlows allows to freely use recursion when needed, just like in normal synchronous code.\nThere is no need for inversion of control.\n\nUp to recent versions of Netty, the netty did not support back pressure regulation, and because of event notification approach, there were no natural way to specify it.The current way is still cumbersome.\n\nOn other hand, netty contains implementation of many network protocols.And it makes sense to reuse these implementations from AsyncFlows.There is plan to create a library that access Netty channels from AsyncFlows framework.\n\n=== Reactive Programming\n\nThe reactive programming is higher-level and more narrow paradigm than what is targeted by this framework.So it does not make sense to compare them directly.However, the concepts from reactive programming could be relatively easily implemented using framework constructs.\nThe reactive programming mixes several concepts together, i.e. data stream processing and tracking/propagating changes.These are somewhat different tasks, and have different data processing needs, for example with tracking changes there is no problem to drop intermediate changes, but for processing data streams this might be not acceptable.\n\nThe data stream processing is covered by stream library in AsyncFlows.\n\nThe event processing is not covered in standard library yet, but it could be implemented using standard means of asynchronous component development, like it is done in\nlink:samples/asyncflows-tracker/src/main/java/org/asyncflows/tracker[sample tracker library].\nThe link:samples/asyncflows-awt/src/test/java/org/asyncflows/ui/awt/TrackerSample.java[demo]\nreproduces some typical scenarios.\nJava 9 flows are more oriented to similar task, and there might be some integration in the future.\n\n=== On the Project Loom\n\nThe project Loom when integrated into Java, tries to solve the problem by other way.\nIt allows synchronous code to be executed by small chunks on the thread pool.\nSo, the execution will look a bit like AsyncFlows on low level, but it looks like a normal multithreaded Java code on high-level.\n\nHowever, the multithreaded programming in Java has two major problems:\n\n. There are performance problems when there are a lot of threads since each thread eats a lot of resources like stack.\n. It is difficult to reason about code that uses synchronization and low-level utilities from java.util.concurrent.\n\nThe project loom solves the first problem, but it does not affect the second problem.\nIt is possible to create a lot of threads, but it is still difficult to reason about them.\nThe AsyncFlows framework will benefit from the Project Loom, as it will allow using lightweight vats over system thread pool with as-needed lifecycle.\n\n== Other Programming Languages\n\nThe framework relies on Java 8 functional interfaces to create DSL. So if other language supports them in reasonable way, it is possible to use this DSL language in similar way.\n\n=== Groovy\n\nGroovy since version 2.4 supports java functional interfaces using closure syntax.However, sometimes more type annotations are needed, to specify parameter types if type checking is wanted.The syntax actually looks more nice for groovy.\n\n[source,groovy]\n----\n        def t = doAsync {\n            def failure = new Promise\u003cThrowable\u003e();\n            def suppressed = new Promise\u003cInteger\u003e();\n            aAll {\n                aAny(true) {\n                    aLater { aValue(1) }\n                } or {\n                    aValue(2)\n                } or {\n                    aFailure(new RuntimeException())\n                } suppressed {\n                    notifySuccess(suppressed.resolver(), it)\n                } suppressedFailureLast {\n                    notifySuccess(failure.resolver(), it);\n                }\n            } and {\n                failure\n            } andLast {\n                suppressed\n            }\n        }\n        assertEquals(2, t.getValue1().intValue());\n        assertEquals(RuntimeException.class, t.getValue2().getClass());\n        assertEquals(1, t.getValue3().intValue());\n----\n\nThere is much less visual noise in groovy version than in Java version of the same test.\nThe Groovy is a good choice of using with the framework if there is no special concerns about performance.\n\nNote, Groovy currently implements lambdas using inner classes, so more classes are generated comparing to Java 8 code.\nThis might lead to higher application start time.\n\n=== Kotlin\n\nThe Kotlin language also has compact syntax that support DSL creation.It is also possible to write a compact code with much less visual noise in Kotlin as well.\n\n[source,kotlin]\n----\n        val t = doAsync {\n            val failure = Promise\u003cThrowable\u003e()\n            val suppressed = Promise\u003cInt\u003e()\n            aAll {\n                aAny(true) {\n                    aLater { aValue(1) }\n                }.or {\n                    aFailure(RuntimeException())\n                }.or {\n                    aValue(2)\n                }.suppressed { v -\u003e\n                    notifySuccess(suppressed.resolver(), v)\n                }.suppressedFailureLast { ex -\u003e\n                    notifySuccess\u003cThrowable\u003e(failure.resolver(), ex)\n                }\n            }.and {\n                failure\n            }.andLast {\n                suppressed\n            }\n        }\n        assertEquals(2, t.value1)\n        assertEquals(RuntimeException::class.java, t.value2.javaClass)\n        assertEquals(1, t.value3)\n----\n\nSo Kotlin is also good language to write structured asynchronous code if you project allows for it.\n\nNote, Kotlin currently implement lambdas using inner classes, so more classes are generated comparing to Java 8 code.This might lead to higher application start time.\n\n==== Kotlin Coroutines\n\nCAUTION: Obsolete, it needs to be revised with flows and coroutines in 1.4.x+.\n\nThe https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md[Kotlin Corountines]\nis an experimental feature similar to C# async support, and there are some similar problems and advantages.\n\nThe extension is implemented as compiler extension with support library.\n\n1. There is no explicit safety frames.\nIt is not clear from lexical scope what code can execute w/o interleaving with other code.\nIn AsyncFlows, safe frame boundaries are more explicit.\n\n2. It is not always clear in what thread the code will be executed.In coroutines there is only one point for specifying context `launch(context){...}`, but after that each component is on its own.\nControlling execution context looks like\nhttps://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md#continuation-interceptor[quite\n complex].Controlling and clear understanding of the execution context is important in the following aspects:\n** Some code requires specific execution context to be used (For example for using with NIO Selectors or AWT/Swing components)\n** Some code is either CPU-bound (so it should be go to ForkJoin), and some code is blocking and IO-bound(so it should go to some unlimited thread pool).AsyncFlows solves it by the following means:\n*** The context normally is inherited from parent for asynchronous operation\n*** There are ways to change context explicitly (aSend, aLater, aPar)\n*** Each component has own context declaring during exporting, that is reestablished on each call.\n\n3. Coroutines provide very compact syntax for sequential operations, i.e. waiting and resuming until some ready to continue.\nBut coroutines provide little support from combining simultaneous operations (`aAll*`, `aAny*`, `aPar*`).\nThere is practically only fork operation.\npartial support is provided by contextual await() operations.\nThere is no support yet for combining them in the code explicitly.\nThe problem could be fixed by providing a richer library with operators similar to AsyncFlows.\n\n4. Base concurrency abstractions looks like more complex than in AsyncFlows.\nConcurrency context combines continuation scheduling, context variables, and many resume/suspend etc.\nPractically these are orthogonal aspects, and they may be decoupled (and they are decoupled in AsyncFlows):\n** Scheduling actions: Vat\n** Resuming/Suspending: Promise\n** Contextual variables: Components and Asynchronous operations with lexical scope\n\n5. Context combinators could provide more interesting methods of integration with legacy frameworks like Java EE.Some of these ideas could be also implemented in AsyncFlows with minor refactoring the current Vat API.\n\nAlso, coroutines are bound to Kotlin with compiler support.\nSo it is hard to write library code that is intended to be used by other programming languages.\nAsyncFlows is designed as mostly language-agnostic, and if language provides a reasonable integration with JVM, it is likely that AsyncFlows could be used with it.\n\nSome library extension might be done in the future to integrate with Kotlin coroutines, so it might be possible to get advantages of both approaches.\n\n=== Scala\n\nThe Scala is not directly supported as it wraps Java types and this causes multiple problems in different places, if AsyncFlows used directly.\nSo for the Scala, adapters are needed, and support for Scala collections needs to be implemented.\nSome code could be executed directly, but it is less usable than in other languages.\n\nGenerally, the framework ideas are well compatible with Scala, and few first research versions of the framework were implemented in Scala.This Java version is based on ideas from Scala version.\nAnd Java 8 finally allows more compact syntax to be used.\n\n*The future versions of the framework might provide Scala support again after the framework stabilization.However, comparing to Kotlin and Groovy, there is not so big productivity increase and there even some additional complications cased by features of Scala language.\nSo this feature has low priority.There is previous iteration of scala adapter at\nhttps://github.com/const/asyncflows/tree/63586493fb9d5a63c0c335df63fa396d894b0a5b/asyncobjects-scala[this link].\n\nIn the old sample code, control flow looked like the following:\n\n[source,scala]\n----\n    val list = new ListBuffer[Integer]\n    val rc: Int = doAsync {\n      aSeq {\n        list += 1\n        1\n      } map { value =\u003e\n        list += value + 1\n        throw new IllegalStateException\n      } thenDo {\n        list += -1\n        aValue(-1)\n      } failed {\n        case value: IllegalStateException =\u003e\n          list += 3\n          42\n      } finallyDo {\n        list += 4\n      }\n    }\n\n    assertEquals(42, rc)\n    assertEquals(List(1, 2, 3, 4), list)\n----\n\nIt looks the same as Groovy version (but with better typing), and it was a bit cleaner than Kotlin version.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconst%2Fasyncflows","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fconst%2Fasyncflows","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconst%2Fasyncflows/lists"}