{"id":36700205,"url":"https://github.com/envimate/message-mate","last_synced_at":"2026-01-12T11:37:33.673Z","repository":{"id":57719073,"uuid":"160176055","full_name":"envimate/message-mate","owner":"envimate","description":"Message-Mate is a library for building messaging architectures.  It provides components to integrate parts of your business logic in a loosely coupled fashion. This allows for applications to be highly extensible and easily tested.","archived":false,"fork":false,"pushed_at":"2019-10-04T16:46:12.000Z","size":1452,"stargazers_count":0,"open_issues_count":4,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-07-12T10:09:01.246Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/envimate.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-12-03T10:48:37.000Z","updated_at":"2019-10-04T16:46:15.000Z","dependencies_parsed_at":"2022-08-27T19:40:29.573Z","dependency_job_id":null,"html_url":"https://github.com/envimate/message-mate","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/envimate/message-mate","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/envimate%2Fmessage-mate","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/envimate%2Fmessage-mate/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/envimate%2Fmessage-mate/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/envimate%2Fmessage-mate/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/envimate","download_url":"https://codeload.github.com/envimate/message-mate/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/envimate%2Fmessage-mate/sbom","scorecard":{"id":378418,"data":{"date":"2025-08-11","repo":{"name":"github.com/envimate/message-mate","commit":"d71a375e074cedae682a9f10fe12e1b525a81c85"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.9,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Security-Policy","score":10,"reason":"security policy file detected","details":["Info: security policy file detected: github.com/envimate/.github/SECURITY.md:1","Info: Found linked content: github.com/envimate/.github/SECURITY.md:1","Info: Found disclosure, vulnerability, and/or timelines in security policy: github.com/envimate/.github/SECURITY.md:1","Info: Found text in security policy: github.com/envimate/.github/SECURITY.md:1"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T14:48:05.754Z","repository_id":57719073,"created_at":"2025-08-18T14:48:05.754Z","updated_at":"2025-08-18T14:48:05.754Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28338971,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T10:58:46.209Z","status":"ssl_error","status_checked_at":"2026-01-12T10:58:42.742Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2026-01-12T11:37:33.600Z","updated_at":"2026-01-12T11:37:33.656Z","avatar_url":"https://github.com/envimate.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# message-mate\nMessage-Mate is a library for building messaging architectures.\n\nIt provides components to integrate parts of your business \nlogic in a loosely coupled fashion. This allows for applications to be highly\nextensible and easily tested.\n\n## Maven Dependency\n[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.envimate.message-mate/core/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.envimate.message-mate/core)\n```\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.envimate.message-mate\u003c/groupId\u003e\n    \u003cartifactId\u003ecore\u003c/artifactId\u003e\n    \u003cversion\u003e...\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Motivation\nMessaging is a form of communication, that exchanges encapsulated messages between \nparts of an application or different applications. In contrast to other types of \nintegration it models both the carrier and the send messages as distinct\nconcepts of the application. This can provide several benefits if used correctly. But it \ncan also generate overhead and complexity. This library focuses on a lightweight \nimplementation of messaging patterns to be wire use cases and objects within one application. \nFor integrating different applications (over network, shared memory, ...) other libraries exist.\n\nThis library provides implementations for typical forms of message carriers like \nChannels or MesssageBus. Explicitly modelling these transport mechanisms as distinct\nobjects have an beneficiary influence on the coupling of independent parts of the \napplication. When parts of the application want to communicate with each other, they\nsend messages. The sender puts its message on the MessageBus. The MessageBus then \nensures, that the message is delivered to all subscribers. The sender does not need to know\nthe number or type of the subscribers. The subscribers have no knowledge about the sender.\nThis leads to a very loosely coupled integration. As sender and subscriber can be added or \nremoved dynamically during runtime, the application becomes very flexible. \n\nBoth, MessageBus and Channel, can be configured to provide asynchronous aspects using \nThreads. This simplifies code using these objects, as a lot of asynchronous \nand synchronization problems are already solved. Dynamically scaling out Threads only \nrequired to change the configuration Channels and MessageBus. The rest of the application\ncan remain mostly agnostic to it. \n\nThese messaging patterns ease the integration of Frameworks with the application's use cases.\nBut also the communication between use cases is greatly simplified with a MessageBus. Even\nat the scope of Domain Objects messaging patterns can provide loosely coupling and dynamism.\n\n## Installation\nTo use Message-Mate add the following Maven depedency to your 'pom.xml`:\n```java\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.envimate.message-mate\u003c/groupId\u003e\n    \u003cartifactId\u003ecore\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## Basic Concepts\n\n### Channel\nA common task in message driven architectures is sending messages from a bunch of producers to \nan arbitrary amount of consumers, handling errors and allowing to add Filters dynamically.\nIn MessageMate Channels provide these kind of properties:\n - add or remove sender and receiver dynamically\n - define the type of send messages, when sender and receiver have agreed on the format of the send messages\n - change the messages during the transportation via Filter: changing the contents of the message, blocking invalid messages,...\n - abstract configuration: once the Channel is created, the participants should be agnostic about the used configuration, e.g. whether the Channel is asynchronous\n - dynamic extension points: add Filter, add logging or even replace the subscriber during tests\n - monitoring: get information about the number of messages that got delivered successful, blocked or failed with exceptions\n \n#### Creating a Channel\nChannels can be created using the `ChannelBuilder` class:\n\n```java\nChannel\u003cTestMessage\u003e channel = ChannelBuilder.aChannel(TestMessage.class)\n    .forType(ChannelType.SYNCHRONOUS)\n    .withDefaultAction(Consume.consumeMessage(m -\u003e {\n        System.out.println(m);\n    }))\n    .build();\n\nchannel.send(new TestMessage());\n```\nChannels can be of type `SYNCHRONOUS` (which is the default) or of type `ASYNCHRONOUS`.\nSynchronous Channels will execute the delivery on the Thread calling `send`. Asynchronous\nChannels bring their own Threadpool with them. For more details on how to create and configure\nasynchronous Channels see [Configuring the Channel](#Configuring-the-Channel)\n\nAt the end of a Channel an Action is executed for each message. Actions abstract\nthe consumer part of the messaging. The simplest Action is the `Consume` Action \nwhich executes the given logic for each message that reached the end of the Channel. \nOther Actions allow dynamic subscriptions or jumps to other Channels.\n\n#### Actions\nEach message reaching the end of the Channel will be consumed by an Action. This can\nbe the default Action defined during creation time or a dynamically changed by Filter \n(explained below). Several default Actions exist:\n\n##### Consume\nA `Consume` Action calls the given Consumer function for every message that reached\nthe end of the Channel:\n\n```java\nAction\u003cT\u003e action = Consume.consumeMessage(processingContext -\u003e {\n    T payload = processingContext.getPayload();\n    System.out.println(payload);\n});\n```\n\nA shortcut exists, if only the payload is needed: \n```java\nAction\u003cT\u003e action = Consume.consumePayload(payload -\u003e {\n    System.out.println(payload);\n});\n```\n\n##### Subscription\nThe `Subscription` Action extends the `Consume` Action with the ability of having \nseveral consumers, called Subscriber. The `Subscription` Action allows adding and\nremoving Subscriber dynamically:\n\n```java\nSubscription\u003cObject\u003e subscription = Subscription.subscription();\n\nConsumer\u003cObject\u003e consumer = message -\u003e System.out.println(message);\n\nSubscriptionId subscriptionId = subscription.addSubscriber(consumer);\n\nsubscription.removeSubscriber(subscriptionId);\n\nSubscriber\u003cObject\u003e subscriber = ConsumerSubscriber.consumerSubscriber(consumer);\nSubscriptionId subscriptionId = subscription.addSubscriber(subscriber);\nsubscription.removeSubscriber(subscriber);\n\nboolean notEmpty = subsription.hasSubscribers();\n``` \nThe `addSubscriber` method is overloaded to accept either a java Consumer or \na `Subscriber` object. Classes implementing this interface get more control \nover the management of the SubscriptionId or the acceptance of messages, e.g. \nthey can preempt the delivery, so that other subscriber do receive the message. \nSee [Subscriber](#Subscriber) for more details. The `addSubscriber` methods returns a `SubscriptionId`, \nwhich is an unique UUID generated for each `Subscriber`. It can be used to uniquely \nidentify a Subscriber. The `removeSubscriber` method makes use of this to remove\nsubscriptions.\n\n##### Jump\nIn more complex messaging architectures larger processing logics are often split \ninto smaller, logical pieces by chaining Channels. Each Channel is then responsible\nfor a smaller part in this flow. These Channels can be connected via `Jump`\nActions. A `Jump` Action takes a message and sends it on the next Channel:\n\n```java\nChannel\u003cT\u003e nextChannel = ...;\nJump\u003cT\u003e jump = Jump.jumpTo(nextChannel);\n```\n\nThe reason to use `Jumps` and not a `Consume` calling `send` on the next Channel is \nthe control structure used in Channels. Messages send over Channels are\nenveloped in `ProcessingContext` objects. These context objects contain history information\nover past Channels useful for debugging.\nThe `Jump` Action handles these context information during the change of Channels\n(For more information about the `ProcessingContext` object see [Processing Context](#Processing-Context)).\n\n##### Adding Filter to Channel\nChannels provide an extensible mechanism for processing messages: Filter.\nA send message traverses all Filter before being consumed by the final Action.\nEach Filter has two options: It can allow the message to pass or it can block the message.\nA blocked message will stop its propagation through the remaining Filter and will never\nreach the final Action:\n\n```java\nchannel.addProcessFilter((processingContext, filterActions) -\u003e {\n    TestMessage message = processingContext.getPayload();\n    if (isValid()) {\n        message.validated = true;\n        filterActions.pass(processingContext);\n    } else {\n        filterActions.block(processingContext);\n    }\n});\n```\nCalling `filterActions.pass` will propagate the message to the next Filter. \n`filterActions.block` will stop the propagation. If none of these methods are called,\nthe message is also blocked. But not calling the `block` method should be avoided as \nFilter should be written as explicit as possible (Also the message is marked as \n`forgotten` and not as `blocked` in the `ChannelStatistics`).\n\nAs mentioned earlier, each message is always enveloped in a `ProcessingContext` control structure.\nTo get access to the original message use `getPayload`. But the `pass` and\n`block` methods again expect the `ProcessingContext` object. Filter can freely access the\n`ProcessingContext` object. The most common usage would be to replace the Action, that\nis executed at the Channel's end:\n\n```java\nchannel.addPostFilter((processingContext, filterActions) -\u003e {\n    if(!processingContext.actionWasChanged()) {\n        processingContext.changeAction(Consume.consumeMessage(m -\u003e {}));\n    }\n});\n```\n\nFilter can be added at three different stages: Pre, Process, Post. These three different\nextension points serve as coarse-grained ordering. All Filter in the Pre Stage are always\nexecuted before the Filter in the Process stage, which themselves execute before the Post Filter.\nWithin these stages the order of Filter follows the contract of java's concurrent list.\n\nFor each of three stages methods exists to query registered Filter and to remove \nFilter:\n```java\nList\u003cFilter\u003cProcessingContext\u003cT\u003e\u003e\u003e preFilter = channel.getPreFilter();\nList\u003cFilter\u003cProcessingContext\u003cT\u003e\u003e\u003e processFilter = channel.getProcessFilter();\nList\u003cFilter\u003cProcessingContext\u003cT\u003e\u003e\u003e postFilter = channel.getPostFilter();\n        \nchannel.removePreFilter(filter);\nchannel.removeProcessFilter(filter);\nchannel.removePostFilter(filter);        \n```\n\n##### Call and Return\nA special Action that can only be used inside a Filter is the `Call` Action. It is used\nto perform an immediate jump to a different Channel. The transport of the message is\nresumed the moment the other Channel executes a `Return` as it's final Action. This `Call`/`Return`\ncombination allows Filter to add arbitrarily complex logic dynamically to a Channel.\n\n```java\nChannel\u003cTestMessage\u003e differentChannel = ChannelBuilder.aChannel(TestMessage.class)\n    .withDefaultAction(Return.aReturn())\n    .build();\n\nchannel.addPostFilter((processingContext, filterActions) -\u003e {\n    Call.callTo(differentChannel, processingContext);\n    System.out.println(\"Returned from other Channel.\");\n    filterActions.pass(processingContext);\n});\n```\n`Calls` can be nested arbitrarily and don't need to return. But executing a `Return` without\na previous `Call` will result in an error.\n\nThe factory method `Call.callTo` executes the `Call` directly. If access to the `Call`\nobject is needed, a two step alternative exists:\n\n```java\nchannel.addPostFilter((processingContext, filterActions) -\u003e {\n    final Call\u003cTestMessage\u003e call = Call.prepareACall(differentChannel);\n    doSomethingWith(call);\n    call.execute(processingContext);\n});\n```\n\nOnce a `Call` and its matching `Return` object was executed, both objects are linked to each other:\n```java\n//suppose these are the two related actions\nReturn\u003cObject\u003e returnAction = Return.aReturn();\nCall\u003cObject\u003e callAction = Call.prepareACall(otherChannel);\n\n\nChannelProcessingFrame\u003cObject\u003e returnFrame = callAction.getReturnFrame();\nassertThat(returnFrame.getAction(), equalTo(returnAction));\n\nChannelProcessingFrame\u003cObject\u003e callFrame = returnAction.getRelatedCallFrame();\nassertThat(callFrame.getAction(), equalTo(callAction));\n\nChannel\u003cObject\u003e callActionTargetChannel = callAction.getTargetChannel();\n```\n\n#### Channel Statistics\nEach Channel provides basic logging in form of statistics itself: It logs the number of \nmessages, that were\n - accepted: message was received by Channel and transport was started. A message is always\n accepted or an exception is thrown\n - queued: asynchronous Channel can queue messages, if no Threads are available. This statistic\n resembles the number of currently waiting messages\n - blocked: number of messages that were blocked by Filter\n - forgotten: number of messages that were neither passed nor blocked by Filter\n - successful: number of messages that passed all Filter and executed the final Action without error\n - failed: if an exception is thrown during a Filter or the final Action, the \n message is marked as failed\n\n ```java\nChannelStatusInformation statusInformation = channel.getStatusInformation();\nChannelStatistics statistics = statusInformation.getChannelStatistics();\nBigInteger acceptedMessages = statistics.getAcceptedMessages();\nBigInteger queuedMessages = statistics.getQueuedMessages();\nBigInteger blockedMessages = statistics.getBlockedMessages();\nBigInteger forgottenMessages = statistics.getForgottenMessages();\nBigInteger successfulMessages = statistics.getSuccessfulMessages();\nBigInteger failedMessages = statistics.getFailedMessages();\nDate timestamp = statistics.getTimestamp();\n ```\nEach statistic contains a timestamp indicating the date, when the given numbers\nwere approximately valid.\n\n#### Closing the Channel\nEach Channel can be closed to free resources in case the Channel was stateful \n(Asynchronous Channels are stateful). The following methods exists:\n\n```java\nboolean finishRemainingTasks = true;\nchannel.close(finishRemainingTasks);\n\nboolean closed = channel.isClosed();\n\ntry {\n    boolean terminationSucceeded = channel.awaitTermination(5, MILLISECONDS);\n} catch (InterruptedException e) {\n    \n}\n```\n\nThese methods follow the contract, that classes from the standard java library with\nthese sort of methods abide to. Channel (as all closable Classes in MessageMate) \nalso implement the `AutoClosable` interface and can be used in a try-with-resources statement.\n\n#### Configuring the Channel\nConfiguring a Channel is done using the respective `ChannelBuilder` class' methods.\n\n```java\nChannelBuilder.aChannel()\n.forType(ChannelType.ASYNCHRONOUS)\n.withAsynchronousConfiguration(asyncConfig)\n.withDefaultAction(Subscription.subscription())\n.withChannelExceptionHandler(customExceptionHandler)\n.withActionHandlerSet(customActionHandlerSet)\n.build();\n```\n\nThe available Actions were discussed in [Actions](#Actions)\n\n##### Type\nThere exists two types of Channels: `ChannelType.SYNCHRONOUS`and `ChannelType.ASYNCHRONOUS`. Sending on synchronous\nChannels is executed on the Thread calling `send`. Asynchronous Channels provide their\nown Threads using a Threadpool. Asynchronous Channels require an additional \n`AsynchronousConfiguration`. \n\nThere exists two convenience methods to ease the creation of a fitting asynchronous\nconfiguration:\n\n```java\nint numberOfThreads = 5;\nAsynchronousConfiguration.constantPoolSizeAsynchronousPipeConfiguration(numberOfThreads);\nint maximumBoundOfQueuedMessages = 100;\nAsynchronousConfiguration.constantPoolSizeAsynchronousPipeConfiguration(numberOfThreads, maximumBoundOfQueuedMessages);\n```\n\nIn case a more fine-tuned configuration is needed, two constructor and getter are provided:\n```java\nAsynchronousConfiguration configuration = new AsynchronousConfiguration();\nconfiguration.setCorePoolSize(5);\n\nint corePoolSize = 5;\nint maximumPoolSize = 10;\nint maximumTimeout = 15;\nTimeUnit timeUnit = MILLISECONDS;\nLinkedBlockingQueue\u003cRunnable\u003e threadPoolWorkingQueue = new LinkedBlockingQueue\u003c\u003e();\nnew AsynchronousConfiguration(corePoolSize, maximumPoolSize, maximumTimeout, timeUnit, threadPoolWorkingQueue);\n```\nThese configuration properties are identically to those available for the java ThreadPoolExecutor\nclass, as the asynchronous Channel uses such underneath. For a comprehensive documentation please consult \nthe java doc of the ThreadPoolExecutor class.\n\n##### ChannelExceptionHandler\nThe default exception behaviour is to throw each exception on the Thread it occurs on.\nThis might not be sufficient for a multi-threaded configuration. Therefore a custom \nexception handler can be set, that gets access to all internal exceptions.\n```java\nChannelExceptionHandler\u003cT\u003e channelExceptionHandler = new ChannelExceptionHandler\u003cT\u003e() {\n    @Override\n    public boolean shouldSubscriberErrorBeHandledAndDeliveryAborted(ProcessingContext\u003cT\u003e message, Exception e) {\n        boolean abortDeliveryAndHandleError = true;\n        return abortDeliveryAndHandleError;\n    }\n\n    @Override\n    public void handleSubscriberException(ProcessingContext\u003cT\u003e message, Exception e) {\n\n    }\n\n    @Override\n    public void handleFilterException(ProcessingContext\u003cT\u003e message, Exception e) {\n\n    }\n};\n```\nWhen an exception occurs during the `accept` method of a subscriber, first the\n`shouldSubscriberErrorBeHandledAndDeliveryAborted` method is called. This method\ncan decide whether the exception should count as such and the delivery should be aborted.\nA `true` results in the message being marked as failed in the statistics.\nNo further subscriber gets the message delivered and the \n`handleSubscriberException` method is called in the end. Given a `false` the \nexception is ignored and the delivery continues normally.\n\nIn case of a Filter throwing an exception, the `handleFilterException` method is called.\nAn exception inside a Filter always counts as failed and aborts the propagation to \nsubsequent Filter or any final Action.\n\n##### ActionHandlerSet\nActions serve only as representative container for the information necessary to \nexecute them. Any logic regarding their execution is handled by the `ActionHandlers`. \nThis allows exchanging logic without changing Actions and makes debuging easier. The \n`ActionHandlerSet` contains one handler for each Action. \n\nWhen a message reaches the end of a Channel, the `ActionHandlerSet` serves as a \nlookup object for an `ActionHandler` matching the Channel's final Action. When a suitable \nhandler is found, its `handle` method is called. When no handler is registered an exception is thrown.\n\n```java\nActionHandlerSet\u003cObject\u003e defaultActionHandlerSet = DefaultActionHandlerSet.defaultActionHandlerSet();\ndefaultActionHandlerSet.registerActionHandler(CustomAction.class, new CustomActionHandler());\n        \nChannelBuilder.aChannel()\n.withActionHandlerSet(actionHandlerSet);\n```\n\nA more in depth explanation about writing custom Actions and `ActionHandlerSets` \nis given in [Custom Actions](#Custom-Actions).\n\n#### Processing Context\nChannels can be chained into arbitrary complex structures. The Channels are connected\nvia Actions (and Calls inside Filter). Filters within these Channels might share data or\nthe history might be of interest for debugging purpose. Since these type of information\nshould not be stored inside the payload itself, a wrapping context object is needed,\nthe `ProcessingContext`. \n\nEach message contains its own `ProcessingContext` object. It wraps the message's payload\nand optional error payload. Each `ProcessingContext` creates\na new unique `MessageId` for each message. Additionally, an optional `CorrelationId` can\nbe set or derived from the `MessageId`. `CorrelationIds` are used heavily in combination \nwith a `MessageBus` to link related messages to each other. Also more used in the context \nof a `MessageBus` is the `ProcessingContext's` `EventType`. The `MessageBus` explained \nlater uses these `EventTypes` to decide, to which subscribers the current message should \nbe routed. Each `ProcessingContext` also brings a meta data map from type\n`Map\u003cObject, Object\u003e` to store additional data about the message, which does not belong\nin the payload.\n\n```java\nT payload = processingContext.getPayload();\nObject errorPayload = processingContext.getErrorPayload();\nEventType eventType = processingContext.getEventType();\nMap\u003cObject, Object\u003e metaData = processingContext.getContextMetaData();\n\nMessageId messageId = processingContext.getMessageId();\nCorrelationId correlationId = processingContext.getCorrelationId();\nCorrelationId correlationIdForMessage = processingContext.generateCorrelationIdForAnswer();\nassertTrue(correlationIdForMessage.matches(messageId));\n```\n\nThe history of Channels is represented as a linked list of `ChannelProcessingFrames`.\nThis list includes a frame for each traversed Channel. Each frame contains a reference\nto its previous and next frame and to its respective Channel. When a Channel is traversed\nto its end, the actual final Action is also stored in the frame.\nThe `ProcessingContext` object serves as root object referencing the first, initial frame\nand the frame of the currently traversed Channel.\n\n```java\nChannelProcessingFrame\u003cT\u003e initialProcessingFrame = processingContext.getInitialProcessingFrame();\nChannel\u003cT\u003e channel = initialProcessingFrame.getChannel();\nChannelProcessingFrame\u003cT\u003e previousFrame = initialProcessingFrame.getPreviousFrame();\nChannelProcessingFrame\u003cT\u003e nextFrame = initialProcessingFrame.getNextFrame();\nAction\u003cT\u003e executedAction = initialProcessingFrame.getAction();\n```\n\nCalls are also included in the linked `ChannelProcessingFrames` list, although stored\na little bit differently. Let's suppose we have 4 Channels:\n - Channel A contains a Filter executing a Call to Channel B. The default Action of\n Channel A is a Jump to Channel D\n - Channel B is the target of the Call within Channel A. As default Action a Jump to\n Channel C is executed.\n - Channel C just executes a Return as Action returning the control to Channel A\n - Channel D is the last Channel with Consume as Action.\n \n ![Channel Call example](documentation/images/channel_call_sample.png)\n \n \nThe linked list of `ChannelProcessingFrames` would consist of the following 5 entries:\n1) a frame for Channel A with a Action `Call` as soon as the Call is executed\n2) a frame for Channel B with the default Action `Jump` to Channel C\n3) a frame for Channel C with the Action `Return` back to Channel A\n4) a frame for Channel A with the default Action `Jump` to Channel D\n5) a frame for Channel D with `Consume` as final Action \n\nSo in general one frame is added per Channel, except for a Call. In this case an extra\n`ChannelProcessingFrames` is added to indicate the branching of the flow.\n\nAdditionally the `ProcessingContext` object provides a MetaDataMap for sharing data between Channels \nor Filter.\n```java\nProcessingContext\u003cObject\u003e processingContext = ProcessingContext.processingContext(message);\n\nMap\u003cObject, Object\u003e metaData = processingContext.getContextMetaData();\n```\n\n\n### MessageBus\nChannels are restricted to a specific type. This can be a benefit as the format of the \ncommunication between producer and consumer is defined by the Channel itself. But this solution \ncomes short when several formats or communications are to be supported by the same\ntransport object.\n\nThe solution is a MessageBus. Any type of message can be send over a MessageBus. Subscribers\nare then able to pick the type of messages they are interested in via type-based subscription.\nThis makes integrating distinct parts of an application possible.\n\nA MessageBus is structured as follows:\n\n![Channel Call example](documentation/images/MessageBus.png)\n\n\nEvery message is accepted by the AcceptingChannel. The AcceptingChannel is responsible\nfor the configuration (synchronous or asynchronous) and can also contain Filter that\nneed access to all messages.\nMessages, that passed the AcceptingChannel, are distributed into subscriber-specific \nChannels. Every `EventType`, which has at least on subscriber, corresponds to a Channel,\nthat delivers all message of its type to its subscribers. On this Channel Filter \ncan be added, that are specific for all messages of this `EventType`.\n\n\n#### Using the MessageBus\n\n```java\nMessageBus messageBus = MessageBusBuilder.aMessageBus()\n    .forType(MessageBusType.SYNCHRONOUS)\n    .build();\n\n\nfinal EventType eventType = eventTypeFromString(\"requestX\");\n SubscriptionId subscriptionId = messageBus.subscribe(eventType, o -\u003e {\n     System.out.println(o);\n });\n        \n messageBus.send(eventType, new TestMessage());\n        \nmessageBus.unsubcribe(subscriptionId);\n```\n\nThe `MessageBusBuilder` is used to configure and create a MessageBus. \nThe `subscribe` method is again overloaded to either aaccept a Subscriber or a java \nconsumer. The first parameter defines the `EventType` of the subscription. \nAll messages of this type are delivered to all subscribers for this type. \nThe returned subscriptionId is used in case the subscriber should should be \nremoved to not received any more messages.\n\nAs discussed in [ProcesscingContext](#Processing-Context) earlier, messages can\ncontain a `CorrelationId` to express, that a set of messages are related. The \ntypical use case is sending a response/answer to a previous request. The\n`MessageBus` allows sending and subscribing messages based on `CorrelationIds`.\n\n\n```java\nCorrelationId correlationId = CorrelationId.newUniqueCorrelationId();\nmessageBus.subscribe(correlationId, processingContext -\u003e {\n    Object payload = processingContext.getPayload();\n    System.out.println(payload);\n});\n\nEventType eventType = EventType.eventTypeFromString(\"answerForX\");\nmessageBus.send(eventType, new TestMessage(), correlationId);\n```\n\nThe `CorrelationId` based subscriber gets access to the complete `ProcessingContext`\nobject, as it holds the `MessageId` and the `CorrelationId`. For the `EventType`\nbased `subscribe` function, a `subscribeRaw` version exists, in case the normal\nsubscriber needs access to the `ProcessingContext` object:\n\n\n```java\nmessageBus.subscribeRaw(eventType, processingContext -\u003e {\n    Object payload = processingContext.getPayload();\n    System.out.println(payload);\n});\n```\n\n\n#### Adding Filter to the MessageBus\nThe MessageBus can add Filters, that get access to all messages:\n\n```java\nfinal Filter\u003cObject\u003e filter = new Filter\u003cObject\u003e() {\n    @Override\n    public void apply(Object message, FilterActions\u003cObject\u003e filterActions) {\n        //filter logic\n    }\n};\nmessageBus.add(filter);\n\nList\u003cFilter\u003cObject\u003e\u003e allFilter = messageBus.getFilter();\n\nmessageBus.remove(filter);\n```\n\nIn case a more fine-grained filtering is needed, the MessageBus allows to query for\nthe specific Channel for a given tyoe. On this Channel Filter can be added as already\ndescribed in [Filter](#Adding-Filter-to-Channel)\n```java\nMessageBusStatusInformation statusInformation = messageBus.getStatusInformation();\nChannel\u003cTestMessage\u003e channel = statusInformation.getChannelFor(eventType);\nchannel.addPreFilter(filter);\nchannel.addProcessFilter(filter);\nchannel.addPostFilter(filter);\n```\n\nIn case the underlying `ProcessingContext` object is needed, an `addRaw` method \nis provided:\n\n```java\nmessageBus.addRaw(new Filter\u003cProcessingContext\u003cObject\u003e\u003e() {\n    @Override\n    public void apply(ProcessingContext\u003cObject\u003e processingContext, \n                      FilterActions\u003cProcessingContext\u003cObject\u003e\u003e filterActions) {\n        //filterLogic\n    }\n});\n```\n\n#### MessageBus Statistics\nSimilar to the Channel the MessageBus collects statistics about all messages:\n\n```java\nMessageBusStatusInformation statusInformation = messageBus.getStatusInformation();\nMessageBusStatistics statistics = statusInformation.getCurrentMessageStatistics();\nBigInteger acceptedMessages = statistics.getAcceptedMessages();\nBigInteger queuedMessages = statistics.getQueuedMessages();\nBigInteger blockedMessages = statistics.getBlockedMessages();\nBigInteger forgottenMessages = statistics.getForgottenMessages();\nBigInteger successfulMessages = statistics.getSuccessfulMessages();\nBigInteger failedMessages = statistics.getFailedMessages();\nDate timestamp = statistics.getTimestamp();\n```\n\nIt's important to note, that these statistics count only for the accepting channel.\nOnce, the message is given to the type specific channel and the `CorrelationId` \nbased subscribers, the result is no longer contained in the above statistics.\nFor instance, when a message has been successfully traversed the accepting channel\nand was delivered to the type specific channel, it is marked als successful. Errors\nin the type specific channel or the correlation based subscriber are not included.\nThe type specific statistic are collected as usual by the channel itself.\n\n#### MessageBus Debug Information\nthe `MessageBusStatusInformation`interface provides useful debug information.\nIt allows to query the currently registered subscriber and error listener.\n\n```java\nMessageBusStatusInformation statusInformation = messageBus.getStatusInformation();\nList\u003cSubscriber\u003c?\u003e\u003e allSubscribers = statusInformation.getAllSubscribers();\nMap\u003cClass\u003c?\u003e, List\u003cSubscriber\u003c?\u003e\u003e\u003e subscribersPerType = statusInformation.getSubscribersPerType();\nList\u003cMessageBusExceptionListener\u003c?\u003e\u003e exListener = statusInformation.getAllExceptionListener();\n```\n\n#### Closing the MessageBus\nThe methods to close the MessageBus are similar to those described for Channels in [Closing the Channel](#Closing-the-Channel):\n\n```java\nboolean finishRemainingTasks = true;\nmessageBus.close(finishRemainingTasks);\n\nboolean closed = messageBus.isClosed();\n\ntry {\n    boolean awaitSucceeded = messageBus.awaitTermination(5, SECONDS);\n} catch (InterruptedException e) {\n\n}\n```\n\n#### Configuring the MessageBus\nAll configuration is done using the `MessageBusBuilder` class. All configurable properties have default values. This creates\na synchronous MessageBus. The default `MessageBusExceptionHandler` throws all exceptions on the calling Thread. Whenever a\nclass specific Channel has to be created, a synchronous one is created by the default MessageBusChannelFactory. \n\n```java\nMessageBusBuilder.aMessageBus()\n.forType(MessageBusType.SYNCHRONOUS)\n.withAsynchronousConfiguration(asynchronousConfiguration)\n.withExceptionHandler(new MessageBusExceptionHandler() {\n    @Override\n    public boolean shouldDeliveryChannelErrorBeHandledAndDeliveryAborted(ProcessingContext\u003c?\u003e message, Exception e, Channel\u003c?\u003e channel) {\n        final boolean abortDeliveryAndHandleException = false;\n        return abortDeliveryAndHandleException;\n    }\n\n    @Override\n    public void handleDeliveryChannelException(ProcessingContext\u003c?\u003e message, Exception e, Channel\u003c?\u003e channel) {\n\n    }\n\n    @Override\n    public void handleFilterException(ProcessingContext\u003c?\u003e message, Exception e, Channel\u003c?\u003e channel) {\n\n    }\n})\n.withAChannelFactory(new MessageBusChannelFactory() {\n    @Override\n    public \u003cT\u003e Channel\u003c?\u003e createChannel(Class\u003cT\u003e tClass, Subscriber\u003cT\u003e subscriber, MessageBusExceptionHandler messageBusExceptionHandler) {\n        ChannelExceptionHandler\u003cT\u003e channelExceptionHandler = delegatingExceptionHandlerTo(messageBusExceptionHandler);\n        return ChannelBuilder.aChannel()\n            .withDefaultAction(Subscription.subscription())\n            .withChannelExceptionHandler(channelExceptionHandler)\n            .build();\n    }\n})\n.build();\n```\n\nThe type and the `AsynchronousConfiguration` are similar to those used for Channels \ndescribed in [Configuring the Channel](#Configuring-the-Channel).\n\nThe default MessageBusExceptionHandler throws all exceptions. It can be replaced using\n`withExceptionHandler` method. When an exception is thrown in one of the subscriber\nthe `shouldDeliveryChannelErrorBeHandledAndDeliveryAborted` is called to decide,\nwhether the exception should be handled and the delivery is aborted or whether the\nexception should be ignored. In case the exception should be handled, the message\nis marked as failed in the statistics and the `handleDeliveryChannelException`\nmethod is called. When an exception is raised in any Filter (general or class\nspecific Channel), the delivery is aborted, the message is marked as failed and\nthe control is given to `handleFilterException`. After each of the `handle_Exception`\nmethods all suitable exception listener are called.\n\nThe `MessageBusChannelFactory` is used to create the class-specific Channel, that delivers the\nmessages to the Subscribers for this class. The default implementation creates a synchronous Channel,\nthat redirect errors to the `MessageBusErrorHandler`. But in case more control over the\nconfiguration of these Channels is needed, a custom implementation can be given here. The \ncreation of a new happen Channel can be requested in two cases: First a subscriber is added \nfor a not yet known class. Second, an unknown message was sent. Then for the class of the message \nand all newly discovered parent classes, a new Channel is created.                                                                                        * discovered parent classes, a new {@code Channel} is created.\nCare has to be taken to handle or redirect the errors correctly. Also important to note is,\nthat the `close` call to the MessageBus will not be propagated to the `MessageBusChannelFactory`.\nIf a custom `MessageBusChannelFactory` contains state that requires a teardown, the \nsynchronisation with the `close` call has to be enforced manually.\n\n#### Dynamically adding exception listener\nOnce the MessageBus is created, the given `MessageBusExceptionHandler` can not be changed.\nBut since subscribers are added or removed to or from a MessageBus in a highly dynamical \nway, a static exception handler becomes a problem. Therefore the MessageBus provides a\nway to register exception listener for specific `EventType` or `CorrelationId` on the fly. \nThese listener will always be called after the `MessageBusExceptionHandler` received the \nexception.\n\n```java\nmessageBus.onException(correlationId, new MessageBusExceptionListener\u003cObject\u003e() {\n    @Override\n    public void accept(ProcessingContext\u003cObject\u003e processingContext, Exception e) {\n                \n    }\n});\n\nSubscriptionId subscriptionId = messageBus.onException(eventType, new MessageBusExceptionListener\u003cObject\u003e() {\n    @Override\n    public void accept(ProcessingContext\u003cObject\u003e processingContext, Exception e) {\n\n    }\n});\n\nmessageBus.unregisterExceptionListener(subscriptionId);\n```\n## Advance Concepts\n\n### QCEC\nA MessageBus allows for a loosely coupled form of communication, where Sender and \nSubscriber do not need to know from each other. They don't even know the number of the\nothers as members of both sides can join or leave dynamically. Configuring the MessageBus\nin an asynchronous way allows for independently integrated parts of the application.\n\nThe integration points between the different use cases and Frameworks are a fitting example\nfor the beneficiary use of an asynchronous MessageBus. But aspects like loose coupling\nand dynamic extensibility are of great benefit even in more coupled parts of the \napplication, like within a use cases. Use cases execute their logic by assembling different parts\nof the application. A MessageBus can be of great help here. `QCEC` defines concepts and\npractices how to use a MessageBus inside the context of use cases or components with \nsimilar requirements of loosely coupling, extensibility and testability while having\nmore shared context than integration between use cases and Frameworks.\n\nQCEC (qcc) stands for Query, Constraint, Event and Command. These four concepts when\ncombined with a synchronous MessageBus ease the assembling of logic into a use case.\nQueries are responsible to retrieve information out of other objects.\nConstraints inform others about a requirement, that, if violated, should rise an \nexception. The purpose of Events is to inform others or to share information with them.\nCommands perform updates on Domain Objects or Repositories.\n\n#### Queries\nUse cases need to retrieve information from the objects they interact with. Having a list\nof all objects of interest results in high coupling. By using a MessageBus, a message\ncan be distributed to these objects without the use case having too much knowledge\nabout them. The message is written as `Query`. This means, that subscriber \nupon receiving the `Query` object can use `Query` specific methods to store \ntheir data into the object. Let's take an example, in which we want to query all of our\napple trees about the number of apples they currently hold. We define a custom Query, \nthat is responsible to query how many apples all of our apple trees have:\n\n```java\nclass NumberOfApplesQuery implements Query\u003cInteger\u003e{\n    private int sumOfApples;\n        \n    public void reportPartialResult(int numberOfApples){\n        this.sumOfApples+=numberOfApples;\n    }\n        \n    @Override\n    public Integer result() {\n        return sumOfApples;\n    }\n}\n```\nThe `AppleTree` class can subscribe itself on the `NumberOfApplesQuery`. \nEach AppleTree reports its number of apples, whenever someone wants to know how many\napples there are:\n\n```java\nclass AppleTree {\n    public AppleTree(int numberOfApples, QueryResolver queryResolver) {\n        queryResolver.answer(NumberOfApplesQuery.class, numberOfApplesQuery -\u003e {\n            numberOfApplesQuery.reportPartialResult(numberOfApples);\n        });\n    }\n}\n```\n\nNow the use case does not not how to interact with `AppleTree` objects. He just\nneeds to send the query:\n\n```java\nMessageBus messageBus = MessageBusBuilder.aMessageBus()\n    .forType(MessageBusType.SYNCHRONOUS)\n    .build();\n\nQueryResolver queryResolver = QueryResolverFactory.aQueryResolver(messageBus);\n\nnew AppleTree(1, queryResolver);\nnew AppleTree(3, queryResolver);\n\nint numberOfApples = queryResolver.queryRequired(new NumberOfApplesQuery());\nassertEquals(4, numberOfApples);\n```\nExecuting a Query on the QueryResolver allows querying all AppleTrees about their stock.\nAlthough in this example the querying code already knows how many apples there are,\nit should be obvious, that the AppleTrees could be created somewhere else without\ncompromising the validity of the code. The querying code does not even know about\nthe existence of the AppleTrees. There could be different kinds of AppleTrees and the \nquerying code would still be the same.\n\nThere exists two different methods for querying `query` and `queryRequired`:\n```java\nOptional\u003cInteger\u003e optional = queryResolver.query(new NumberOfApplesQuery());\nint numberOfApples = optional.orElseThrow(() -\u003e new UnsupportedOperationException(\"Expected a query result.\"));\n        \nint numberOfApples = queryResolver.queryRequired(new NumberOfApplesQuery());\n```\n\nThe `query` method allows queries not having a result and therefore returning an\noptional. The `queryRequired` method throws an `UnsupportedOperationException` when\nthere is no result.\n\nThe `answer` method returns an `SubscriptionId` object. This can be used for the\n`unsubscribe` method to stop answering methods. The `answer` can also be used\non super classes or interfaces. In this case all subclasses will result in the \n`answer` method to be called with the respective instance.\n\n```java\nSubscriptionId subscriptionId = queryResolver.answer(Query.class, q -\u003e handle(q));\nqueryResolver.unsubscribe(subscriptionId);\n```\n\nPer default queries are delivered to all Subscribers and the result is returned\nafterwards. But queries can be stopped early, when it's apparent, that further\nSubscribers won't add value to the result. To stop a query early, override the \n`finished` method. Once it returns `true`, the query is stopped and the result\nis returned immediately.\n\n```java\nclass PreemptiveQuery implements Query\u003cObject\u003e {\n     private Object result;\n\n     public void setResult(Object result) {\n        this.result = result; \n     }\n\n     @Override\n     public Object result() {\n        return result; \n     }\n\n     @Override\n     public boolean finished() {\n         return result != null; \n     }\n}\n```\n\nWhen subscribing for queries, superclasses can be used. The underlying MessageBus \nensures, that all subclasses of the class used in `answer` will also call the\nconsumer. \n\n#### Constraints\nQueries are used to retrieve data from others. They should not throw an exception, \nbecause it would mix up the partially retrieved data with the exception. But it's often\nnecessary to ensure, that a specific constraint holds and if it does not, to raise an\nexception. This differs from queries in that way as a Constraint either holds or an \nexception is thrown. But a constraint will never return data.\n\nLet's suppose we want to ensure, that the usernames of users are unique. We use a \nConstraint:\n```java\nclass UniqueUsernameConstraint {\n     public String usernameToCheck;\n\n     public UniqueUsernameConstraint(String usernameToCheck) {\n        this.usernameToCheck = usernameToCheck;\n     }\n}\n```\n\nThe User class is responsible to protect the uniqueness of its username:\n```java\nclass User {\n    private String username;\n\n    public User(String username, ConstraintEnforcer constraintEnforcer) {\n        this.username = username;\n        constraintEnforcer.respondTo(UniqueUsernameConstraint.class, uniqueUsernameConstraint -\u003e {\n        if(uniqueUsernameConstraint.usernameToCheck.equals(username)){\n            throw new UsernameAlreadyInUseException(username);\n            }\n        });\n    }\n}\n```\nNow any code can send Constraints on the `ConstraintEnforcer` object\nto ensure, that the unique username constraint holds.\n\n```java\nMessageBus messageBus = MessageBusBuilder.aMessageBus()\n    .forType(MessageBusType.SYNCHRONOUS)\n    .build();\n\nConstraintEnforcer constraintEnforcer = ConstraintEnforcerFactory.aConstraintEnforcer(messageBus);\n        \nnew User(\"Tim\", constraintEnforcer);\n        \nconstraintEnforcer.enforce(new UniqueUsernameConstraint(\"Tim\"));\n```\n\nSimilar to the QueryResolver, the `respondTo` method allows for inheritance\nand interfaces. It also returns a `SubscriptionId` that\ncan be used as parameter for the `unsubscribe` method to stop responding to constraints.\n\nWhen subscribing for constraints, superclasses can be used. The underlying MessageBus \nensures, that all subclasses of the class used in `respondTo` will also call the\nconsumer. \n\n#### Events\nQueries retrieve information, constraints enforce rules and events are used to \nforward information. Events never return information\nand should not throw an exception. They are just used to indicate, that something happened.\n\nLet's suppose a very basic login use case: Given a username and password, a login is tried.\nIf it succeeded, an event is published to inform others, that the user went online. \n```java\nMessageBus messageBus = MessageBusBuilder.aMessageBus()\n    .forType(MessageBusType.SYNCHRONOUS)\n    .build();\n\nEventBus eventBus = EventBusFactory.aEventBus(messageBus);\n        \nboolean loginSuccessful = login(this.username, this.password);\nif(loginSuccessful){\n    eventBus.publish(new UserOnlineEvent(this.username));\n}else{\n    goBackToLoginForm();\n}\n\nclass UserOnlineEvent {\n    public String username;\n\n    public UserOnlineEvent(String username) {\n        this.username = username;\n    }\n}\n```\nThe code publishing the event does not care, what others do with the information or even \nif there are others. It is of no concern for its functionality that other receive the event.\n\nBut other components might be interested, when a user goes online:\n```java\nclass UserOnlineView {\n    private final List\u003cString\u003e userOnline = new ArrayList\u003c\u003e();\n\n    public UserOnlineView(EventBus eventBus) {\n        eventBus.reactTo(UserOnlineEvent.class, userOnlineEvent -\u003e {\n            final String username = userOnlineEvent.username;\n            userOnline.add(username);\n        });\n    }\n}\n```\nThe `UserOnlineView` is dependent on the event and its information. But it doesn't \ncare, who sent it. It just needs the information.\n\nThe `EventBus` has three methods: `reactTo` to add a subscriber for a class and all\nits subclasses. `publish` sends the Event on the underlying synchronous MessageBus.\nAnd `unsubscribe` removes the subscription for the given `SubscriptionId`.\n\nWhen subscribing for events, superclasses can be used. The underlying MessageBus \nensures, that all subclasses of the class used in `reactTo` will also call the\nconsumer. \n\n#### Commands\nAside from querying and aggregating data, use cases are responsible for a safe and secure\nupdate to the applications data. A common pattern is to model the update in form of\nCommands. A Command is a reusable abstraction over the the update. It gets the\nrequired parameter during its creation by the use case. During its invocation by the consuming\ncounterpart it gets all information to execute its task. By moving the update logic\nout of the use case into a distinct object, the update process becomes decoupled \nfrom the use case and therefore reusable and testable.\n\n#### DocumentBus\nIt's rarely the case that an application uses only Queries, Constraints or \nEvents. Most of the time it's a mixture of these three. Therefore it \nbecomes a burden to drag along a `QueryResolver`, a \n`ConstraintEnforcer` and an `EventBus`. It also becomes difficult to remember which\nSubscriptionId was used for which of these objects. Therefore the `DocumentBus`\nwas created to combine these concepts and provide an easier to use interface.\n\nIt provides three entry methods: `answer` for Queries, `ensure` for Constraints and \n`reactTo` for Events, which represent the three respective methods of the QueryResolver,\nConstraintEnforcer and EventBus. But the DocumentBus allows to enhance the subscription\nwith conditionals and an automatic unsubscription.\n\nLet's extend the AppleTree example with an DocumentBus. An AppleTree still reports his\nstock of apples to the `NumberOfApplesQuery`. But only if the query is from the owner\nof the tree. And the tree can only report as long as it is not cut down. Then it should\nstop its reporting and unsubscribe from the `NumberOfApplesQuery`.\n\n\n```java\nDocumentBus documentBus = DocumentBusBuilder.aDefaultDocumentBus();\n \nSubscriptionId subscriptionId = documentBus.answer(NumberOfAppleQuery.class)\n    .onlyIf(numberOfAppleQuery -\u003e numberOfAppleQuery.getOwner().equals(this.owner))\n    .until(AppleTreeCutDownEvent.class, appleTreeCutDownEvent -\u003e appleTreeCutDownEvent.getTree().equals(this))   \n    .using(numberOfAppleQuery -\u003e numberOfAppleQuery.reportPartial(this.numberOfApples))\n```\nThe `answer` method takes the Query, for which itself or its subclasses the Consumer\ngiven in `using` should be called. The `onlyIf` method can add arbitrary many conditions.\nOnly if all of them return `true` the Consumer given in `using` is called. \nThe `until` method allows for one or several automatic unsubscriptions. Whenever one of\nthese conditions return true, the subscription is removed and the AppleTree stops\nresponding to the `NumberOfAppleQuery`. The returned SubscriptionId identified \nsubscription for the query. It can be used to manually unsubscribe as long\nas an the `until` condition has not been met yet.\n\nThe same convenience interface exists for the Constraint's `ensure` and the \nEvent's `reactTo` method:\n\n\n```java\ndocumentBus.reactTo(AppleTreeCutDownEvent.class)\n    .until(AppleTreeCutDownEvent.class, appleTreeCutDownEvent -\u003e appleTreeCutDownEvent.getTree().equals(this))\n    .using(appleTreeCutDownEvent -\u003e releaseResources());\n        \ndocumentBus.ensure(TreeSpotFreeConstraint.class)\n    .until(AppleTreeCutDownEvent.class, appleTreeCutDownEvent -\u003e appleTreeCutDownEvent.getTree().equals(this))\n    .using(treeSpotFreeConstraint -\u003e {\n        if(treeSpotFreeConstraint.getSpot().equals(this.spot)){\n            throw new TreeSpotAlreadyOccupiedException(this.spot);\n        }\n    });\n```\n\nThe `onlyIf` methods also exists for `reactTo` and `ensure`.\n\nSending objects is similar to the distinct single objects:\n\n```java\nOptional\u003cInteger\u003e optional = documentBus.query(new NumberOfAppleQuery());\nint numberOfApples = documentBus.queryRequired(new NumberOfAppleQuery());\n\ndocumentBus.enforce(new TreeSpotFreeConstraint());\n        \ndocumentBus.publish(new AppleTreeCutDownEvent());\n```\n### Message Function\nImplementing a Request-Reply communication over an asynchronous MessageBus can be\nerror-prone. Once the request is send, numerous ways exist, how to respond to it.\nIt could be answered by different types for replies. Some model success responses, \nothers error responses. But also exceptions can occur and no regular response is ever\nsent. In case several requests are simultaneously active, responses and exceptions \nhave to be checked, if they correspond to the correct request.\n\nThe `MessageFunction` class simplifies this Request-Reply communication. When sending\na request over a `MessageFunction`, a `ResponseFuture` is returned. This will fulfill,\nonce a message with a `CorrelationId` is received, that matches the request`s \n`MessageId`, or an exception occured for either the request, or a correlated reply.\n\nThe future provides the methods `get`and `await`, which block the caller until a result\nis received or the optional timeout expired. The future also allows for a non blocking\nprocessing. Via the `then` method follow up actions can be defined, that are executed\nonce a the future is fulfilled.\n\nThe following example models the process of buying a number of apples from a farmer.\nThe `BuyAppleRequest` starts the negotiation. The farmer can accept the offer with \nan `AcceptOfferReply` or decline with a `DeclineOfferReply` based on his stock:\n\n```java\nclass Farmer {\n    private int stock;\n\n    public Farmer(MessageBus messageBus, int stock) {\n        this.stock = stock;\n        messageBus.subscribeRaw(buyAppleEventType, processingContext -\u003e {\n            BuyAppleRequest buyAppleRequest = processingContext.getPayload();\n            \n            CorrelationId correlationId = processingContext.generateCorrelationIdForAnswer();\n            \n            boolean acceptOffer = stock \u003e= buyAppleRequest.numberOfApples;\n            BuyAppleReply reply = new BuyAppleReply(acceptOffer);\n            messageBus.send(replyEventType, reply, correlationId);\n        });\n    }\n}\n\nclass BuyAppleRequest {\n    public int numberOfApples;\n\n    public BuyAppleRequest(int numberOfApples) {\n        this.numberOfApples = numberOfApples;\n    }\n}\n\n    \nclass BuyAppleReply  {\n    boolean accept;\n    \n    BuyAppleReply(boolean accept){\n        this.accept = accept;\n    }\n}\n\n```\nThe `CorrelationId` is necessary to match a reply to its corresponding request. Instead\nof implementing a lot of subscriber and error logic itself the client code makes use\nof a `MessageFunction`:\n\n```java\nMessageBus messageBus = MessageBusBuilder.aMessageBus()\n    .forType(MessageBusType.ASYNCHRONOUS)\n    .withAsynchronousConfiguration(asyncConfig)\n    .build();\n\nMessageFunction messageFunction = MessageFunctionBuilder.aMessageFunction(messageBus);\n\nnew Farmer(messageBus, 11);\n\nBuyAppleRequest request = new BuyAppleRequest(5);\nResponseFutureresponseFuture = messageFunction.request(buyAppleEventType, request);\nresponseFuture.then((response, errorResponse, exception) -\u003e {\n    if (exception != null) {\n        System.out.println(\"Exception occured: \" + exception);\n    } else {\n        if (errorResponse == null) {\n            System.out.println(\"payload received normally: \" + response);\n        } else {\n            System.out.println(\"error payload: \" + errorResponse);\n        }\n    }\n});\n```\nThe `then` method is invoked once the future fulfils. Inside the `FollowUpAction`, the exception \nshould be checked first. It is not null, if the request or the reply caused an exception. The \n`wasSuccessful` field is true, if no exception occurred and the `ProcessingContext` \nerror payload was null. Otherwise it is false. The `response` contains the payload of \nthe reply.\n\n#### ResponseFuture\nThe `ResponseFuture` implements the java `Future` interface. Therefore it \nprovides methods to query or wait on the result. But it also defines additional\nget and wait methods to access the received `ProcessingContext` or error payload.\n\n```java\ntry {\n    Object response = responseFuture.get();\n    Object errorResponse = responseFuture.getErrorResponse();\n    ProcessingContext\u003cObject\u003e processingContext = responseFuture.getRaw();\n} catch (InterruptedException | ExecutionException e) {\n    \n}\ntry {\nObject response = responseFuture.get(10, MILLISECONDS);\nObject errorResponse = responseFuture.getErrorResponse(10, MILLISECONDS);\nProcessingContext\u003cObject\u003e processingContext = responseFuture.getRaw(10, MILLISECONDS);\n} catch (InterruptedException | ExecutionException | TimeoutException e) {\n            \n}\n\nboolean noExceptionOrErrorResponse = responseFuture.wasSuccessful();\nboolean responseExceptionOrCancellationOccurred = responseFuture.isDone();\nresponseFuture.cancel(true);\nboolean cancelled = responseFuture.isCancelled();\n```\n\nThe `get` methods suspend the caller until a result was receied or the optional \ntimeout expired. Cancelling a the future, will block its fulfillment. The underlying\nrequest or anything except that, will not be cancelled. \n\nA future fulfills only once. So an exception during the sending of a request will fulfill\nthe future. Subsequent replies to the request will be ignored and won't trigger any \n`FollowUpActions` twice. At any time only one `FollowUpAction` is allowed. When the future\nis cancelled, no `FollowUpActions` will be executed. \n\n### Use case invocation\nIn [qcec](#qcec) we have seen, how to use messaging in the scope of a single use case. But\ninvoking use cases using messaging provides the same benefits: low coupling and high\nextensibility. Message-Mate provides several concepts to ease the configuration of the \napplication's use case invocation.\n\n#### UseCaseBus\nThe `UseCaseBus` is the most convenient form of invoking use cases over an asynchronous \n`MessageBus`. It provides an expressive builder interface to configure the invoked\nuse cases, their serializing and deserializing logic. The following example should make\nthe different steps more clear:\n\nWe want to invoke the `SampleUseCase` class over a `MessageBus`, that is shared between\nall use cases and probably some external frameworks handling http, websockets or other\nmessaging systems to foreign systems. The use case defines appropriate parameter objets:\n\n```java\nclass UseCaseParameter {\n    private final int someNumber;\n\n    UseCaseParameter(int someNumber) {\n        this.someNumber = someNumber;\n    }\n}\n\nclass SampleUseCase {\n\n    public UseCaseReturnValue doStuff(UseCaseParameter request) {\n        String message = \"Received: \" + request.someNumber;\n        return new UseCaseReturnValue(message);\n    }\n}\n\nclass UseCaseReturnValue {\n    private final String message;\n\n    UseCaseReturnValue(String message) {\n        this.message = message;\n    }\n}\n```\nWithout any helper classes, the use case could be invoked over the `MessageBus` as\nfollows:\n```java\nmessageBus.subscribe(useCaseEventType, o -\u003e {\n    SampleUseCase useCase = new SampleUseCase();\n    UseCaseReturnValue returnValue = useCase.doStuff((UseCaseParameter) o);\n    messageBus.send(useCaseResponseEventType, returnValue);\n});\n\nmessageBus.send(useCaseEventType, new UseCaseParameter(5));\n```\nThis solution has several problems. First of all, it becomes a burden to register \nall of the application's use cases or adapt to changes in those use cases.\nSecond, sending the parameter as it is over the message bus creates a higher \ncoupling as necessary. Each subscriber, that wants to access the objects\nof type `useCaseEventType` has to depend on the `UseCaseParameter.class`. Since\nthe use case cannot know of potential users of this class, it has to take great \ncare when changing the class. Therefore it is better to send data to and from\nuse cases in a serialized form: as a `Map\u003cString,Object\u003e`. Potential consumer\ncan take these map and extract only required data from it in a form, that \neach consumer can decide upon its own. In case of the use case it would be\nto deserialize it into a `UseCaseParameter` object:\n```java\nmessageBus.subscribe(useCaseEventType, map -\u003e {\n    SampleUseCase useCase = new SampleUseCase();\n    UseCaseParameter useCaseParameter = deserialize(map);\n    UseCaseReturnValue returnValue = useCase.doStuff(useCaseParameter);\n    Map\u003cString, Object\u003e serializedReturnValue = serialize(returnValue);\n    messageBus.send(useCaseResponseEventType, returnValue);\n});\n\nUseCaseParameter parameter = new UseCaseParameter(5);\nMap\u003cString, Object\u003e requestMap = serialize(parameter);\nmessageBus.send(useCaseEventType, parameter);\n```\n\nAllthough sending the data in a serialized form, the invocatio of the\nuse case became tidious, as three (de-)serialization steps have to be\ndone. If the returnValue would be of interest, a fourth and final\ndeserialization step would have been added to deserialize the\n`UseCaseReturnValue` back to the correct class. To make it more \ncomplicated, we do not reuse the the `UseCaseParameter` and \n`UseCaseReturnValue` classes, as they should only be owned by the use\ncase itself. We introduce two additional classes: \n\n```java\nclass UseCaseRequest {\n    private final int someNumber;\n\n    UseCaseRequest(int someNumber) {\n        this.someNumber = someNumber;\n    }\n}\n    \nclass UseCaseResponse {\n    private final String message;\n    \n    UseCaseResponse(String message) {\n        this.message = message;\n    }\n}\n```\n\nCode invoking the use case will use these classes, so that the\nparameter and return classes, that the use case uses, can be \nfreely changed, as the use case requires. Invocing the use case\nrequires the following 5 steps:\n1) Create a `UseCaseRequest` object, serialize it and send it on the\n`MessageBus`\n2) Take the serialized request and deserialize it to a `UseCaseParameter`.\n3) Invoke the use case with its single public method.\n4) Serialize the `UseCaseReturnValue` and send it back.\n5) Deserialize the response into a `UseCaseResponse` object.\n\nMaintaining these 5 steps becomes a burden for several use cases. Therefore\nthe `UseCaseBus` class was introduced. It provides a builder, that eases\nall the serialization/deserialization definitions and also the use case invocation.\nTaking the example from before, we can rewrite the code as follows:\n\n```java\nUseCaseBus useCaseBus = UseCaseInvocationBuilder.anUseCaseBus() \n    .invokingUseCase(SampleUseCase.class).forType(\"useCase1\").callingTheSingleUseCaseMethod() \n    .obtainingUseCaseInstancesUsingTheZeroArgumentConstructor()\n    .mappingRequestsToUseCaseParametersOfType(UseCaseParameter.class).using((targetType, map) -\u003e new UseCaseParameter((Integer) map.get(\"SampleUseCase.intParam\")))\n    .deserializingUseCaseResponsesOfType(UseCaseResponse.class).using((targetType, map) -\u003e new UseCaseResponse((String) map.get(\"SampleUseCase.returnValue\")))\n    .throwAnExceptionByDefaultIfNoParameterMappingCanBeApplied()\n    .serializingUseCaseRequestOfType(UseCaseRequest.class).using(useCaseRequest -\u003e Map.of(\"SampleUseCase.intParam\", useCaseRequest.someNumber))\n    .serializingResponseObjectsOfType(UseCaseReturnValue.class).using(caseReturnValue -\u003e Map.of(\"SampleUseCase.returnValue\", caseReturnValue.message))\n    .throwingAnExceptionByDefaultIfNoResponseMappingCanBeApplied()\n    .puttingExceptionObjectNamedAsExceptionIntoResponseMapByDefault()\n    .build(messageBus);\n```\nLet's explain each line step by step:\n1) Starting the configuration of the `UseCaseBus`\n2) defining which class to invoke for which type. Als defines, that the\nonly public method should be invoked. Alternatives to calling specific\nmethods in case not only a single method is present will be discussed later.\n3) `obtainingUseCaseInstancesUsingTheZeroArgumentConstructor`: For each request\na new use case instance will be created by using the constructor without parameters.\nAlternatively an injector can be set, that allows for greater control.\n4) Define the deserialization steps: `mappingRequestsToUseCaseParametersOfType`\n is responsible to create the use case method's parameter from the map send \n over the `MessageBus`.\n5) `deserializingUseCaseResponsesOfType`: After the invocation and the sending\nof the serialized return value, the fourth and last deserializing step is used\nto create an object from the response map.\n6) The deserialization definitions need a default mapping. This method throws\nan exception, whenever no matching deserialization is found.\n7) `serializingUseCaseRequestOfType` takes the request object and serialized it\non the `MessageBus`. It takes the `UseCaseRequest's` message property and\nstores it as `SampleUseCase.intParam` in the map. That's the reason, the \n`mappingRequestsToUseCaseParametersOfType` method took the `SampleUseCase.intParam`\nproperty.\n8) In case the use case returns a value, the `serializingResponseObjectsOfType`\nmethod allows for defining, how to put the value in a map.\n9) The serialization definitions also need a default value, which would be also\nthrow a exception.\n10) Use case methods can throw exceptions. These exceptions need also also to \nbe serialized, before sending them back to the caller (but as error payload).\nThe `puttingExceptionObjectNamedAsExceptionIntoResponseMapByDefault` will take\neach exception and put the exception object under `Exception` in the map.\n11) Set the used `MessageBus` and create the `useCaseBus`.\n\nOnce the `UseCaseBus` has been defined, it allows for invoking use cases and \nwaiting for their result with as follows:\n```jave \nEventType eventType = EventType.eventTypeFromString(\"useCase1\");\nUseCaseRequest useCaseRequest = new UseCaseRequest(5);\ntry {\n    PayloadAndErrorPayload\u003cUseCaseResponse, Void\u003e result = useCaseBus.invokeAndWait(eventType, useCaseRequest, UseCaseResponse.class, Void.class);\n    final UseCaseResponse response = result.getPayload();\n    System.out.println(response);\n} catch (InterruptedException | ExecutionException e) {\n    e.printStackTrace();\n}\n```\nThe `invokeAndWait` method takes the `EventType`, the data and two `Classes` as parameters. \nThe data will be serialized using the definitions from above and will be send \nto the use case assigned to the specific `EventType`. Once a response has been received,\nthe two classes are used to deserialize the response back to real objects.\n\nThe `invokeAndWait` method can also take an additional timeout. Also in case no \nfinal deserialization is needed, `invokeAndWaitNotDeserialized` versions exist,\nthat return the serialized `Map\u003cString, Object\u003e` payloads:\n\n```java\ntry {\n    PayloadAndErrorPayload\u003cUseCaseResponse, ErrorResponseClass\u003e result = useCaseBus.invokeAndWait(eventType, request, UseCaseResponse.class, ErrorResponseClass.class, 10, MILLISECONDS);\n    PayloadAndErrorPayload\u003cMap\u003cString, Object\u003e, Map\u003cString, Object\u003e\u003e result2 = useCaseBus.invokeAndWaitNotDeserialized(eventType, request);\n    PayloadAndErrorPayload\u003cMap\u003cString, Object\u003e, Map\u003cString, Object\u003e\u003e result3 = useCaseBus.invokeAndWaitNotDeserialized(eventType, request, 10, MILLISECONDS);\n} catch (InterruptedException | ExecutionException | TimeoutException e) {\n    e.printStackTrace();\n}\n```\n\nThe example above demonstrated the easiest form of configuring the `UseCaseBus`.\nBut in case a more complex setup is needed, most of the methods described above\nhave a more customizable version. \n\nInvoking the use case with `callingTheSingleUseCaseMethod` is the easiest way,\nas the method simplifies all of the (de)serialization and method calling.\nBut there exists cases, where the method cannot be used, for instance, if a use\ncase has more than one public method. Then the invocation has to be defined explicitely:\n```java\nUseCaseInvocationBuilder.anUseCaseBus()\n.invokingUseCase(SampleUseCase.class).forType(\"t1\").calling((sampleUseCase, o) -\u003e {\n    UseCaseParameter parameter = deserialize(o);\n    UseCaseReturnValue returnValue = sampleUseCase.doStuff(parameter);\n    Map\u003cString, Object\u003e responseMap = serialize(returnValue);\n    return responseMap;\n})\n.invokingUseCase(SampleUseCase.class).forType(\"t3\").callingVoid((sampleUseCase, o) -\u003e {\n    UseCaseParameter parameter = serialize(o);\n    sampleUseCase.doStuff(parameter);\n})\n.invokingUseCase(SampleUseCase.class).forType(\"t2\").callingBy((useCase, event, requestDeserializer, responseSerializer) -\u003e {\n    Map\u003cString, Object\u003e requestMap = (Map\u003cString, Object\u003e) event;\n    UseCaseParameter parameter = requestDeserializer.deserialize(UseCaseParameter.class, requestMap);\n    UseCaseReturnValue returnValue = useCase.doStuff(parameter);\n    return responseSerializer.serialize(returnValue);\n})\n```\nThe `calling` method takes java `BiFunction\u003cU, Object, Map\u003cString, Object\u003e\u003e`. This \nfunction gets the use case instance, the request map and should return the \nresponse map. All (de)serialization and method calling is defined by the user.\nThe `callingVoid` method is similar, except, that it expects the use case to not\nreturn a value. This results in an empty response map. The `callingBy` method\nprovides access to the use case instance, the request map, the configured\nserializer and deserializer. It expects a filled response map as return value.\n\nIn case a custom logic is needed, to instantiate the use cases, the\n`obtainingUseCaseInstancesUsing` method allows for defining a injector. For\neach request, the injector will be called.\n```java\n.obtainingUseCaseInstancesUsing(new UseCaseInstantiator() {\n    @Override\n    public \u003cT\u003e T instantiate(Class\u003cT\u003e type) {\n        return newInstance(type);\n    }\n})\n```\nThe deserialization definitions are usually class based. But in case more\nfine grained control, the `mappingRequestsToUseCaseParametersThat` or\n`deserializingUseCaseResponsesThat` methods exist, that take an \n`BiPredicate\u003cClass\u003c?\u003e, Map\u003cString, Object\u003e\u003e`, which also gets access to \nthe current map. In case a different default deserialization instead of throwing \nan exception is needed, use the `deserializeObjectsPerDefault` method.\n\n\nFor the serialization, similar functions exists: `serializingUseCaseRequestThat`\nand `serializingResponseObjectsThat` take a `Predicate\u003cObject\u003e`, with access\nto the current object, that should be mapped to a map. In case `null` values\nshould be mapped, the `serializinguseCaseRequestsOfTypeVoid` and \n`serializingResponseObjectsOfTypeVoid` methods exists, as `null.getClass()`\nwon't work. In case a different default serialization instead of throwing \nan exception is needed, use the `serializingObjectsByDefaultUsing` method.\n\nFor the exception serializing, the same overloaded methods exist.\n`serializingExceptionsOfType` takes a class for which to include the following\nmapping defined in the `using` method. `serializingExceptionsThat` takes\na `Predicate\u003cException\u003e` to decide, when to trigger. The \n`puttingExceptionObjectNamedAsExceptionIntoResponseMapByDefault` can be replaced\nby `serializingExceptionsByDefaultUsing` or \n`throwingAnExceptionIfNoExceptionMappingCanBeFound`. Please note, that the later\nwill throw an exception outside the exception mapping function. This later \nexception will not be mapped, but instead, will be thrown as exception on the\n`MessageBus`.\n\n\n#### UseCaseAdapter\nOnce `UseCaseBus` is configured invoking a use case is reduced to calling\n`invokeAndWait`. Although, this is very convenient to use, there exist\ncases, where more control is needed. A good example, is the functionality\nof the `ResponseFuture's` `then` method, which allows non blocking\nhandling of responses. The `invokeAndWait` method always blocks, so it\nis not a valid substitute. For these cases, where more control in the sending\nand waiting on messages is needed, the the `UseCaseInvocationBuilder`\ncan output a `UseCaseAdapter`, which fulfills only the use case invocation\npart of the `UseCaseBus`: It subscribes the defined use cases for their\nspecific `EventTypes` on the `MessageBus`. Whenever a fitting message\nis received, the target use case is invoked with the defined (de)serialization.\nBut the sending of requests and waiting of responses is left for the user. This\nallows for a more controlled sending, for instance using a `MessageFunction`.\nThe following example describes the differences, when using a `UseCaseAdapter`\ninstead of a `UseCaseBus`. The methods of the `UseCaseInvocationBuilder` are\nthe same as for the `UseCaseBus`.\n\n```java\nUseCaseAdapter useCaseAdapter = UseCaseInvocationBuilder.anUseCaseAdapter()\n    .invokingUseCase(SampleUseCase.class).forType(\"t1\").callingTheSingleUseCaseMethod()\n    .obtainingUseCaseInstancesUsingTheZeroArgumentConstructor()\n    .mappingRequestsToUseCaseParametersOfType(UseCaseParameter.class).using((targetType, map) -\u003e new UseCaseParameter((Integer) map.get(\"SampleUseCase.intParam\")))\n    .deserializingUseCaseResponsesOfType(UseCaseResponse.class).using((targetType, map) -\u003e new UseCaseResponse((String) map.get(\"SampleUseCase.returnValue\")))\n    .throwAnExceptionByDefaultIfNoParameterMappingCanBeApplied()\n    .serializingResponseObjectsOfType(UseCaseReturnValue.class).using(caseReturnValue -\u003e Map.of(\"SampleUseCase.returnValue\", caseReturnValue.message))\n    .serializingUseCaseRequestOfType(UseCaseRequest.class).using(useCaseRequest -\u003e Map.of(\"SampleUseCase.intParam\", useCaseRequest.someNumber))\n    .throwingAnExceptionByDefaultIfNoResponseMappingCanBeApplied()\n    .puttingExceptionObjectNamedAsExceptionIntoResponseMapByDefault()\n    .buildAsStandaloneAdapter();\n\nuseCaseAdapter.attachAndEnhance(messageBus);\n\nEventType eventType = EventType.eventTypeFromString(\"t1\");\nMessageFunction messageFunction = MessageFunctionBuilder.aMessageFunction(messageBus);\nResponseFuture responseFuture = messageFunction.request(eventType, mapData);        \n```\n\nThe `attachAndEnhance` function registers the use cases on the given `MessageBus`.\nIt returns a `SerializedMessageBus`, which is described further below:\n```java\nSerializedMessageBus serializedMessageBus = useCaseAdapter.attachAndEnhance(messageBus);\n```\n\nIt can also directly take an `SerializedMessageBus`:\n```java\nuseCaseAdapter.attachTo(serializedMessageBus);\n```\n\n#### Serialized MessageBus\nThe `UseCaseBus` simplifies invoking use cases. In case more control is needed when\nsending requests and handling responses, the `UseCaseAdapter` can be used. This\nworks for all use cases, that take parameter and return a single (or none) return \nvalue. But there exists use cases, that send extra messages on the `MessageBus`\nduring their execution. These messages should also be send in their serialized form to\nnot brake any code, that excepts only objects of type `Map\u003cString, Object\u003e` on \nthe `MessageBus`. This requirement forces use cases to know, how to serialize objects.\nBut this information is usually defined during the creation of the `UseCaseBus`/\n`UseCaseAdapter`. To not duplicate these kind of information, the `SerializedMessageBus`\nwas created. The `SerializedMessageBus` wraps a normal `MessageBus` and provides\nmethods to send messages, that are automatically serialized using the serializers\ndefined in the `UseCaseInvocationBuilder`, and receive responses deserialized like\nthe `UseCaseBus` would do.\n\nA `SerializedMessageBus` can be created using its factory method:\n```java\nSerializedMessageBus serializedMessageBus = SerializedMessageBus.aSerializedMessageBus(messageBus, deserializer, serializer);\n```\n\nBut since the serializer and deserializer are defined in the `UseCaseAdapter`, its normally better\nto let the `UseCaseAdapter` create the wrapping `SerializedMessageBus` with the correct deserializer\nand serializer:\n```java\nSerializedMessageBus serializedMessageBus = useCaseAdapter.attachAndEnhance(messageBus);\n```\nThe `attachAndEnhance` will add all necessary subscriber to the `MessageBus`. It will then \nwrap the bus and return it with the correct (de)serializers. \n\nThe resulting `SerializedMessageBus` can send both serialized and not yet serialized data:\n```java\n//sending raw data\nMap\u003cString, Object\u003e data = new HashMap\u003c\u003e();\nserializedMessageBus.send(eventType, data);\n\nCorrelationId correlationId = newUniqueCorrelationId();\nserializedMessageBus.send(eventType, data, correlationId);\n\nMap\u003cString, Object\u003e errorData = new HashMap\u003c\u003e();\nserializedMessageBus.send(eventType, data, errorData);\nserializedMessageBus.send(eventType, data, errorData, correlationId);\n\n\n//sending data, that is serialized first\nUseCaseRequest data = new UseCaseRequest(5);\nserializedMessageBus.serializeAndSend(eventType, data);\nserializedMessageBus.serializeAndSend(eventType, data, correlationId);\n\nErrorData errorData = new ErrorData();\nserializedMessageBus.serializeAndSend(eventType, data, errorData);\nserializedMessageBus.serializeAndSend(eventType, data, errorData, correlationId);\n```\n\nIt also allows for sending requests and waiting for their response:\n```java\n//not serialized\nMap\u003cString, Object\u003e data = new HashMap\u003c\u003e();\nPayloadAndErrorPayload\u003cMap\u003cString, Object\u003e, Map\u003cString, Object\u003e\u003e result = serializedMessageBus.invokeAndWait(eventType, data);\nPayloadAndErrorPayload\u003cMap\u003cString, Object\u003e, Map\u003cString, Object\u003e\u003e result = serializedMessageBus.invokeAndWait(eventType, data, 10, MILLISECONDS);\n\n//only serialize request data\nUseCaseRequest data = new UseCaseRequest(5);\nPayloadAndErrorPayload\u003cMap\u003cString, Object\u003e, Map\u003cString, Object\u003e\u003e result = serializedMessageBus.invokeAndWaitSerializedOnly(eventType, data);\nPayloadAndErrorPayload\u003cMap\u003cString, Object\u003e, Map\u003cString, Object\u003e\u003e result = serializedMessageBus.invokeAndWaitSerializedOnly(eventType, data, 10, MILLISECONDS);\n\n//serialize request and deserialize response\nPayloadAndErrorPayload\u003cUseCaseResponse, ErrorResponse\u003e result = serializedMessageBus.invokeAndWaitDeserialized(eventType, data, UseCaseResponse.class, ErrorResponse.class);\nPayloadAndErrorPayload\u003cUseCaseResponse, ErrorResponse\u003e result = serializedMessageBus.invokeAndWaitDeserialized(eventType, data, UseCaseResponse.class, ErrorResponse.class, 10, MILLISECONDS);\n```\n\nSimilar to the usual `MessageBus`, subscribers can be added and removed:\n```java\nSubscriber\u003cPayloadAndErrorPayload\u003cMap\u003cString, Object\u003e, Map\u003cString, Object\u003e\u003e\u003e subscriber = new Subscriber\u003cPayloadAndErrorPayload\u003cMap\u003cString, Object\u003e, Map\u003cString, Object\u003e\u003e\u003e() {\n    @Override\n    public AcceptingBehavior accept(PayloadAndErrorPayload\u003cMap\u003cString, Object\u003e, Map\u003cString, Object\u003e\u003e message) {\n        Map\u003cString, Object\u003e payload = message.getPayload();\n        Map\u003cString, Object\u003e errorPayload = message.getErrorPayload();\n        return AcceptingBehavior.MESSAGE_ACCEPTED;\n    }\n\n    @Override\n    public SubscriptionId getSubscriptionId() {\n        return subscriptionId;\n    }\n};\nserializedMessageBus.subscribe(eventType, subscriber);\nserializedMessageBus.subscribe(correlationId, subscriber);\n\nSubscriber\u003cPayloadAndErrorPayload\u003cUseCaseResponse, ErrorResponse\u003e\u003e subscriber = new Subscriber\u003cPayloadAndErrorPayload\u003cUseCaseResponse, ErrorResponse\u003e\u003e() {\n    @Override\n    public AcceptingBehavior accept(PayloadAndErrorPayload\u003cUseCaseResponse, ErrorResponse\u003e message) {\n        return AcceptingBehavior.MESSAGE_ACCEPTED;\n    }\n\n    @Override\n    public SubscriptionId getSubscriptionId() {\n        return subscriptionId;\n    }\n};\nserializedMessageBus.subscribeDeserialized(eventType, subscriber, UseCaseResponse.class, ErrorResponse.class);\nserializedMessageBus.subscribeDeserialized(correlationId, subscriber, UseCaseResponse.class, ErrorResponse.class);\n\nserializedMessageBus.unsubscribe(subscriptionId);\n```\n\n### Subscriber\nMost of the functions, that take an Subscriber object, are overloaded to take also\na Consumer object. Internally the Consumer object is mapped to a Subscriber, but the \nuser does not have to burden itself with the handling of SubscriptionIds. But implementing\nyour own Subscriber allows for greater control over the accepting and subscription mechanisms.\nThe `Subscriber` interface defines two methods:\n```java\npublic interface Subscriber\u003cT\u003e {\n\n    AcceptingBehavior accept(T message);\n\n    SubscriptionId getSubscriptionId();\n}\n```\nThe `accept` method is called, whenever an object of the type `T` is received. The message\nshould return an `AcceptingBehavior` object. This object can control, if the delivery of the\nmessage should be continued:\n```java\npublic AcceptingBehavior accept(Object message) {\n    boolean continueDelivery = handle(message);\n    return AcceptingBehavior.acceptingBehavior(continueDelivery);\n}\n```\nA `false` will stop the delivery of the message to subsequent subscriber. If the result\nis known statically, two convenience constants can be used:\n\n```java\nAcceptingBehavior.MESSAGE_ACCEPTED;\nAcceptingBehavior.MESSAGE_ACCEPTED_AND_STOP_DELIVERY;\n```\n\nThe second method `getSubscriptionId` should return a SubscriptionId, that is constant\nand unique for the Subscriber. The identification of an subscriber should be dependent\non the equality of the SubscriberId returned by this method. `equals` and `hashCode` \nshould behave accordingly.\n\nTwo convenience implementations of the `Subscriber` interface exist: The `ConsumerSubscriber`\nwhich creates a `Subscriber` from java `consume` and the `PreemptiveSubscriber`, which takes\na java `predicate`. The return value of the `predicate` is used to decide, if the\ndelivery is continued (return `true`) or if it is preempted (return `false`):\n\n```java\nConsumerSubscriber\u003cObject\u003e consumerSubscriber = ConsumerSubscriber.consumerSubscriber(m -\u003e {\n    System.out.println(m);\n});\n\nPreemptiveSubscriber\u003cObject\u003e preemptiveSubscriber = PreemptiveSubscriber.preemptiveSubscriber(m -\u003e {\n    if (shouldDeliveryContinue(m)) {\n        return true;\n    } else {\n        return false;\n    }\n});\n```\n \n### Custom Actions\nThe built-in Actions for Channels should cover most use cases. In case customization \nis needed, the `Action` interface can be implemented:\n\n```java\npublic interface Action\u003cT\u003e {}\n```\nIt does not define any methods. An Action is only a container for necessary data. All\nthe logic about executing the Action is done by the respective `ActionHandler`. For \nevery custom Action, there must be an `ActionHandler` specifically written for this Action:\n\n```java\npublic interface ActionHandler\u003cT extends Action\u003cR\u003e, R\u003e { \n    void handle(T action, ProcessingContext\u003cR\u003e processingContext);\n}\n```\nThe `ActionHandler` interface defines two generic parameter: `R` is the generic given by the\nAction. Normally it is inherited by the type of the Channel. `T` corresponds the Action\nfor which the ActionHandler is written. The `handle` method is called whenever a message\nwith the Action has reached the end of the Channel. The following example implements a logging Action.\nThis should clarify the generic parameter:\n\nWe define a custom `Log` Action, which contains a PrintStream as target.\n\n```java\nclass Log\u003cT\u003e implements Action\u003cT\u003e {\n    private final PrintStream stream = System.out;\n\n    public PrintStream getStream() {\n        return stream;\n    }\n}\n```\n\nAdditionally an `ActionHandler` is needed, so that Channel can execute the Log Action:\n\n```java\nclass LogActionHandler\u003cT\u003e implements ActionHandler\u003cLog\u003cT\u003e, T\u003e {\n     @Override\n     public void handle(Log\u003cT\u003e action, ProcessingContext\u003cT\u003e processingContext) {\n        final PrintStream stream = action.getStream();\n        stream.println(processingContext);\n     }\n}\n```\n\nWhen we want to use our Log Action, we have to make it known to the Channel. Each \nChannel has an `ActionHandlerSet` set during creation. Only those code Actions \ncan be used as final code Action of the code Channel, that have a matching \nActionHandler registered in the set. If an unknown Action is encountered, an \n`NoHandlerForUnknownActionException` is thrown.\n\nTo add your custom Action, register it the your custom `ActionHandlerSet`:\n```java\nActionHandlerSet\u003cObject\u003e actionHandlerSet = DefaultActionHandlerSet.defaultActionHandlerSet();\nactionHandlerSet.registerActionHandler(Log.class, new LogActionHandler\u003c\u003e());\nChannel\u003cObject\u003e channel = ChannelBuilder.aChannel(Object.class)\n    .withDefaultAction(new Log\u003c\u003e())\n    .withActionHandlerSet(actionHandlerSet)\n    .build();\n```\nWe used the default `ActionHandlerSet`, so that we do not have to register the built-in\nActions and their ActionHandlers ourselves. But a completely different set can be built from scratch\nanytime with:\n\n```java\nActionHandlerSet\u003cT\u003e actionHandlerSet = ActionHandlerSet.emptyActionHandlerSet();\n\n//manually registering all built-in actions\nactionHandlerSet.registerActionHandler(Consume.class, ConsumerActionHandler.consumerActionHandler());\nactionHandlerSet.registerActionHandler(Subscription.class, SubscriptionActionHandler.subscriptionActionHandler());\nactionHandlerSet.registerActionHandler(Jump.class, JumpActionHandler.jumpActionHandler());\nactionHandlerSet.registerActionHandler(Return.class, ReturnActionHandler.returnActionHandler());\nactionHandlerSet.registerActionHandler(Call.class, CallActionHandler.callActionHandler());\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fenvimate%2Fmessage-mate","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fenvimate%2Fmessage-mate","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fenvimate%2Fmessage-mate/lists"}