├── .gitignore ├── CLA.md ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── jitpack.yml ├── settings.gradle.kts └── src ├── main └── java │ └── com │ └── github │ └── jneat │ └── minibus │ ├── EventBus.java │ ├── EventBusAsync.java │ ├── EventBusEvent.java │ ├── EventBusHandler.java │ ├── EventBusSimple.java │ ├── EventWrapper.java │ ├── FailureConsumer.java │ ├── WeakHandler.java │ └── utils │ ├── EventBroker.java │ ├── EventObservable.java │ └── EventObserver.java └── test └── java └── com └── github └── jneat └── minibus ├── Event.java ├── Event1.java ├── Event2.java ├── Event3.java ├── Event4.java ├── EventBusAsyncTest.java ├── Handler1.java ├── Handler2.java ├── Handler234.java ├── Handler3.java ├── Handler4Error.java └── utils ├── EventController.java ├── EventObservableTest.java ├── EventUIFormPanel.java └── KeyEvent.java /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | out 3 | 4 | .idea 5 | .gradle 6 | .nb-gradle-properties 7 | .nb-gradle 8 | -------------------------------------------------------------------------------- /CLA.md: -------------------------------------------------------------------------------- 1 | # Contributor agreement 2 | 3 | This contributor agreement (this "Agreement") applies to any Contribution you make to any Work in the current repository. 4 | 5 | This is a binding legal agreement on you and any organization you represent. If you are accepting this Agreement on behalf of your employer or other organization, you represent and warrant that you have the authority to agree to this Agreement on behalf of the organization. 6 | 7 | ### TLDR 8 | 9 | Repository owner do not want to have any legal bindings with you after your contribution 10 | like asking deceased person to approve some license changes etc. This is the main purpose of this Agreement. 11 | 12 | 13 | ### 1. Definitions 14 | 15 | "Contribution" means any original work, including any modification of or addition to an existing work, that you submit to this repository in any manner for inclusion in any Work. 16 | 17 | "we" and "us" means the owner of the current repository. 18 | 19 | "Work" means any project, work or materials owned or managed by the current repository owner. 20 | 21 | "You" and "your" means you and any organization on whose behalf you are entering this Agreement. 22 | 23 | ### 2. Copyright Assignment, License and Waiver 24 | 25 | (a) Assignment. By submitting a Contribution, you assign to us all right, title and interest in any copyright you have in the Contribution, and you waive any rights, including any moral rights, database rights, etc., that may affect your ownership of the copyright in the Contribution. 26 | 27 | (b) License to us. If your assignment in Section 2(a) is ineffective for any reason, you grant to us and to any recipient of any Work distributed by use, a perpetual, worldwide, transferable, non-exclusive, no-charge, royalty-free, irrevocable, and sublicensable licence to use, reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Contributions and any derivative work created based on a Contribution. If your license grant is ineffective for any reason, you irrevocably waive and covenant to not assert any claim you may have against us, our successors in interest, and any of our direct or indirect licensees and customers, arising out of our, our successors in interest's, or any of our direct or indirect licensees' or customers' use, reproduction, preparation of derivative works, public display, public performance, sublicense, and distribution of a Contribution. 28 | 29 | (c) License to you. We grant to you a perpetual, worldwide, transferable, non-exclusive, no-charge, royalty-free, irrevocable, and sublicensable license to use, reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute a Contribution and any derivative works you create based on a Contribution. 30 | 31 | ### 3. Patent License 32 | 33 | You grant to us and to any recipient of any Work distributed by us, a perpetual, worldwide, transferable, non-exclusive, no-charge, royalty-free, irrevocable, and sublicensable patent license to make, have made, use, sell, offer to sell, import, and otherwise transfer the Contribution in whole or in part, along or included in any Work under any patent you own, or license from a third party, that is necessarily infringed by the Contribution or by combination of the Contribution with any Work. 34 | 35 | ### 4. Your Representation and Warranties. 36 | 37 | By submitting a Contribution, you represent and warrant that: (a) each Contribution you submit is an original work and you can legally grant the rights set out in this Agreement; (b) the Contribution does not, and any exercise of the rights granted by you will not, infringe any third party's intellectual property or other right; and (c) you are not aware of any claims, suits, or actions pertaining to the Contribution. You will notify us immediately if you become aware or have reason to believe that any of your representations and warranties is or becomes inaccurate. 38 | 39 | ### 5. Intellectual Property 40 | 41 | Except for the assignment and licenses set forth in this Agreement, this Agreement does not transfer any right, title or interest in any intellectual property right of either party to the other. If you choose to provide us with suggestions, ideas for improvement, recommendations or other feedback, on any Work we may use your feedback without any restriction or payment. 42 | 43 | ### Miscellaneous 44 | 45 | Our contributor agreement is based on the mongoDB contributor agreement. 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 by rumatoest at github.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lightweight event bus for java application 2 | 3 | This is easiest way to integrate event processing into your application. 4 | Suits well for single instance application. 5 | Helps you to avoid adding 3rd party message brokers like RabbitMQ, ActiveMQ, HornetQ, etc. 6 | 7 | It is very simple event bus implementation, based on observable pattern. 8 | You can use it as dependency or modify it for your needs, it is just several hundreds lines of code. 9 | 10 | [![Release](https://jitpack.io/v/javaplugs/minibus.svg)](https://jitpack.io/#javaplugs/minibus) 11 | [API javadoc](https://jitpack.io/com/github/javaplugs/minibus/-SNAPSHOT/javadoc/) 12 | 13 | # Getting started 14 | 15 | For working example you can look into project tests. 16 | 17 | ## Installation 18 | You can add this artifact to your project using [JitPack](https://jitpack.io/#javaplugs/minibus). 19 | All versions list, instructions for gradle, maven, ivy etc. can be found by link above. 20 | 21 | To get latest commit use `master-SNAPSHOT` instead version number. 22 | 23 | This library using slf4j-api which should not output messages by default. 24 | You have to configure proper logger for slf4j in your project to view this messages. 25 | 26 | ## Define your events model 27 | 28 | You should define at least one event DTO that implements EventBusEvent interface. 29 | Also you can create your own Event interface that extends EventBusEvent and use it for your app events. 30 | 31 | ```java 32 | public class Event1 implements EventBusEvent { 33 | // with any properties you like 34 | }; 35 | 36 | public class Event2 implements EventBusEvent { 37 | // with any properties you like 38 | }; 39 | 40 | public class Event3 implements EventBusEvent { 41 | // with any properties you like 42 | }; 43 | ``` 44 | The main point here is that you can have different events with different properties. 45 | 46 | ## Implement handlers for your events 47 | Any handler should implement EventBusHandler interface. 48 | 49 | ### Basic handler 50 | Suitable for most cases. 51 | 52 | Basic handlers stored in hash map using event class as key. 53 | Thus handlers quantity should not affect choosing handler performance. 54 | 55 | ```java 56 | public class Handler1 extends EventBusHandler { 57 | @Override 58 | protected void handle(Event1 event) { 59 | // do something with event1 60 | } 61 | } 62 | 63 | public class Handler2 extends EventBusHandler { 64 | @Override 65 | protected void handle(Event2 event) { 66 | // do something with event2 67 | } 68 | } 69 | ``` 70 | 71 | ### Advanced handler 72 | Should use than you need to process different events in one place. 73 | 74 | Note that advanced handlers selecting approach can not be optimized. 75 | It is always O(N) where N is total number of handlers. 76 | 77 | ```java 78 | public class HandlerAdvanced extends EventBusHandler { 79 | 80 | // FIRST you must override this method and return null 81 | @Override 82 | protected Class getLinkedClass() { 83 | return null; 84 | } 85 | 86 | // SECOND override canHandle method 87 | // Should return true if you interested in processing particular event type 88 | @Override 89 | public boolean canHandle(Class cls) { 90 | // Always return true -> will handle any EventBusEvent 91 | return true; 92 | } 93 | 94 | @Override 95 | protected void handle(EventBusEvent event) { 96 | // do something with event1, event2 and event3 97 | } 98 | } 99 | ``` 100 | 101 | ## Initializing EventBus & subscribe handlers 102 | 103 | Two types of EventBus available: 104 | 105 | * EventBusAsync - run handlers in separate thread (suitable for most cases) 106 | * EventBusSimple - run handlers in current thread (good for tests) 107 | 108 | 109 | **Main thing to remember** - event handlers subscribed using weak links. 110 | You must have normal links to handlers in application if you do not want them to be unsubscribed. 111 | So you should have a collection with your handlers, that available for all app runtime. 112 | In spring application you may not worry about it if your handlers are singleton beans. 113 | 114 | **Spring (or other DI framework) example** 115 | 116 | ```java 117 | @Named 118 | public class EventBusBean { 119 | 120 | private final EventBus> bus; 121 | 122 | // DI framework should inject all available beans here as list 123 | @Inject 124 | EventBusBean(List handlers) { 125 | this.bus = new EventBusAsync<>(); 126 | handlers.stream().forEach(bus::subscribe); 127 | // No need to store link to handlers, because DI framework should treat them as singletons 128 | } 129 | 130 | // Just return event bus 131 | public EventBus bus() { 132 | return this.bus; 133 | } 134 | } 135 | ``` 136 | 137 | ## Publishing events 138 | 139 | All you need is to create event with valid event type and publish it to EventBus. 140 | 141 | ```java 142 | public class SomewhereInYourCode { 143 | // Considering that such variable exists: 144 | EventBusBean ebb; 145 | 146 | public void something() { 147 | // Publishing events 148 | ebb.bus().publish(new Event1()); 149 | ebb.bus().publish(new Event2()); 150 | } 151 | } 152 | ``` 153 | 154 | ## Publishing events with callback 155 | 156 | Also you can add callbacks on success or failure event processing. 157 | 158 | Because there can be many handlers to one event we pass handler to callback. 159 | You should receive as many success/failure calls as number of handlers subscribed to your event. 160 | 161 | ```java 162 | public class SomewhereInYourCode { 163 | // Considering that such variable exists: 164 | EventBusBean ebb; 165 | 166 | public void something() { 167 | ebb.bus().publish( 168 | new Event3(), 169 | (event, handler) -> { 170 | // Will be called on success processing for each handler 171 | }, 172 | (event, handler, excpetion) -> { 173 | // Will be called on processing error for each handler 174 | } 175 | ); 176 | } 177 | } 178 | ``` 179 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | val artifactGroup = "com.github.jneat" 2 | plugins { 3 | id("java") 4 | id("maven-publish") 5 | } 6 | 7 | repositories { 8 | mavenCentral() 9 | } 10 | 11 | dependencies { 12 | implementation("org.slf4j:slf4j-api:1.7.+") 13 | 14 | testImplementation("org.assertj:assertj-core:3.24.+") 15 | testImplementation("org.testng:testng:7.7.1") 16 | } 17 | 18 | tasks { 19 | java { 20 | sourceCompatibility = JavaVersion.VERSION_11 21 | targetCompatibility = JavaVersion.VERSION_11 22 | } 23 | 24 | test { 25 | useTestNG() 26 | testLogging.showStandardStreams = true 27 | } 28 | 29 | val sourcesJar by creating(Jar::class) { 30 | dependsOn(classes) 31 | classifier = "sources" 32 | from(sourceSets["main"].allSource) 33 | } 34 | 35 | val javadocJar by creating(Jar::class) { 36 | dependsOn(javadoc) 37 | classifier = "javadoc" 38 | from(javadoc.get().destinationDir) 39 | } 40 | 41 | artifacts { 42 | add("archives", sourcesJar) 43 | add("archives", javadocJar) 44 | } 45 | } 46 | 47 | publishing { 48 | publications { 49 | create("projectMvnPublication") { 50 | version = version 51 | groupId = artifactGroup 52 | from(components["java"]) 53 | artifact(tasks["sourcesJar"]) 54 | artifact(tasks["javadocJar"]) 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | version=0.0.0-SNAPSHOT -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jneat/minibus/aa29ed1e7a9b6fee4e88dd62d6cfe4aa2108166f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip 4 | networkTimeout=10000 5 | zipStoreBase=GRADLE_USER_HOME 6 | zipStorePath=wrapper/dists 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 147 | # shellcheck disable=SC3045 148 | MAX_FD=$( ulimit -H -n ) || 149 | warn "Could not query maximum file descriptor limit" 150 | esac 151 | case $MAX_FD in #( 152 | '' | soft) :;; #( 153 | *) 154 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 155 | # shellcheck disable=SC3045 156 | ulimit -n "$MAX_FD" || 157 | warn "Could not set maximum file descriptor limit to $MAX_FD" 158 | esac 159 | fi 160 | 161 | # Collect all arguments for the java command, stacking in reverse order: 162 | # * args from the command line 163 | # * the main class name 164 | # * -classpath 165 | # * -D...appname settings 166 | # * --module-path (only if needed) 167 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 168 | 169 | # For Cygwin or MSYS, switch paths to Windows format before running java 170 | if "$cygwin" || "$msys" ; then 171 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 172 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 173 | 174 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 175 | 176 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 177 | for arg do 178 | if 179 | case $arg in #( 180 | -*) false ;; # don't mess with options #( 181 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 182 | [ -e "$t" ] ;; #( 183 | *) false ;; 184 | esac 185 | then 186 | arg=$( cygpath --path --ignore --mixed "$arg" ) 187 | fi 188 | # Roll the args list around exactly as many times as the number of 189 | # args, so each arg winds up back in the position where it started, but 190 | # possibly modified. 191 | # 192 | # NB: a `for` loop captures its iteration list before it begins, so 193 | # changing the positional parameters here affects neither the number of 194 | # iterations, nor the values presented in `arg`. 195 | shift # remove old arg 196 | set -- "$@" "$arg" # push replacement arg 197 | done 198 | fi 199 | 200 | # Collect all arguments for the java command; 201 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 202 | # shell script including quotes and variable substitutions, so put them in 203 | # double quotes to make sure that they get re-expanded; and 204 | # * put everything else in single quotes, so that it's not re-expanded. 205 | 206 | set -- \ 207 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 208 | -classpath "$CLASSPATH" \ 209 | org.gradle.wrapper.GradleWrapperMain \ 210 | "$@" 211 | 212 | # Stop when "xargs" is not available. 213 | if ! command -v xargs >/dev/null 2>&1 214 | then 215 | die "xargs is not available" 216 | fi 217 | 218 | # Use "xargs" to parse quoted args. 219 | # 220 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 221 | # 222 | # In Bash we could simply go: 223 | # 224 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 225 | # set -- "${ARGS[@]}" "$@" 226 | # 227 | # but POSIX shell has neither arrays nor command substitution, so instead we 228 | # post-process each arg (as a line of input to sed) to backslash-escape any 229 | # character that might be a shell metacharacter, then use eval to reverse 230 | # that process (while maintaining the separation between arguments), and wrap 231 | # the whole thing up as a single "set" statement. 232 | # 233 | # This will of course break if any of these variables contains a newline or 234 | # an unmatched quote. 235 | # 236 | 237 | eval "set -- $( 238 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 239 | xargs -n1 | 240 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 241 | tr '\n' ' ' 242 | )" '"$@"' 243 | 244 | exec "$JAVACMD" "$@" 245 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /jitpack.yml: -------------------------------------------------------------------------------- 1 | jdk: 2 | - openjdk17 3 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "minibus" -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/minibus/EventBus.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package com.github.jneat.minibus; 25 | 26 | import java.util.function.BiConsumer; 27 | 28 | /** 29 | * Generic event bus interface. 30 | * I assume that there can be several possible implementations with different approach to 31 | * event/threads handling. 32 | */ 33 | public interface EventBus> { 34 | 35 | /** 36 | * Subscribe consumer to the event bus using weak link. 37 | *

38 | * Subscribing same object twice should not affect how many times subscriber will 39 | * be called per one event. 40 | * 41 | * @param subscriber The object to subscribe to the event bus. 42 | */ 43 | void subscribe(H subscriber); 44 | 45 | /** 46 | * Removes the specified consumer from the event bus subscription list. 47 | * Once removed, the specified object will no longer receive events posted to the 48 | * event bus. 49 | * 50 | * @param subscriber The object previous subscribed to the event bus. 51 | */ 52 | void unsubscribe(H subscriber); 53 | 54 | /** 55 | * Sends a event (message) to the bus which will be propagated to the appropriate subscribers (handlers). 56 | *

57 | * There is no specification given as to how the messages will be delivered, 58 | * and should be determine in each implementation. 59 | * 60 | * @param event Event to publish 61 | */ 62 | void publish(E event); 63 | 64 | /** 65 | * Sends a event (message) to the bus which will be propagated to the appropriate subscribers (handlers). 66 | * 67 | * @param event Event to publish 68 | * @param success Callback on success or null 69 | * @param failure Callback on error or null 70 | */ 71 | void publish( 72 | E event, 73 | BiConsumer success, 74 | FailureConsumer failure 75 | ); 76 | 77 | /** 78 | * Indicates whether the bus has pending events to publish. Since message/event 79 | * delivery can be asynchronous (on other threads), the method can be used to 80 | * start or stop certain actions based on all the events having been published. 81 | * I.e. perhaps before an application closes, etc. 82 | * 83 | * @return True if events are still being delivered. 84 | */ 85 | boolean hasPendingEvents(); 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/minibus/EventBusAsync.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package com.github.jneat.minibus; 25 | 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | 29 | import java.lang.ref.ReferenceQueue; 30 | import java.util.Collections; 31 | import java.util.Map; 32 | import java.util.Queue; 33 | import java.util.Set; 34 | import java.util.concurrent.ConcurrentHashMap; 35 | import java.util.concurrent.ConcurrentLinkedQueue; 36 | import java.util.concurrent.ExecutorService; 37 | import java.util.concurrent.Executors; 38 | import java.util.function.BiConsumer; 39 | 40 | /** 41 | * Async event bus that will run each event/handler call in separate thread. By default using CachedThreadPool to run 42 | * handlers. 43 | */ 44 | public class EventBusAsync> implements EventBus { 45 | 46 | private static final Logger logger = LoggerFactory.getLogger(EventBusAsync.class); 47 | 48 | private final Queue> eventsQueue = new ConcurrentLinkedQueue<>(); 49 | 50 | private final ReferenceQueue gcQueue = new ReferenceQueue<>(); 51 | 52 | private final Map, Set>> handlersCls = new ConcurrentHashMap<>(); 53 | 54 | private final Set> handlers = Collections.newSetFromMap(new ConcurrentHashMap<>()); 55 | 56 | private final ExecutorService handlersExecutor; 57 | 58 | /** 59 | * CAN OVERRIDE THIS METHOD. If you need to add some weirdo filters to events right before handler will be submitted 60 | * to executor. 61 | */ 62 | protected void submitHandler(H h, EventWrapper ew) { 63 | handlersExecutor.submit(() -> runHandlerWrapper(h, ew)); 64 | } 65 | 66 | /** 67 | * CAN OVERRIDE THIS METHOD. This executes in separate thread, passing event to handler 68 | */ 69 | protected void runHandler(H h, E e) throws Throwable { 70 | h.handleEvent(e); 71 | } 72 | 73 | /** 74 | * Create new EventBus instance with default presets. 75 | */ 76 | public EventBusAsync() { 77 | this(Executors.newCachedThreadPool()); 78 | } 79 | 80 | /** 81 | * Create instance with customer ExecutorService for event handlers. 82 | * 83 | * @param handlersExecutor Will be used to run event handler processing for each event 84 | */ 85 | public EventBusAsync(ExecutorService handlersExecutor) { 86 | this.handlersExecutor = handlersExecutor; 87 | Thread eventQueueThread = new Thread(this::eventsQueue, "EventQueue handlers thread"); 88 | eventQueueThread.setDaemon(true); 89 | eventQueueThread.start(); 90 | } 91 | 92 | @Override 93 | public void subscribe(H subscriber) { 94 | Class cls = subscriber.getLinkedClass(); 95 | if (cls == null) { 96 | handlers.add(new WeakHandler<>(subscriber, gcQueue)); 97 | } else { 98 | synchronized (this) { 99 | Set> hs = handlersCls.computeIfAbsent(cls, k -> Collections.newSetFromMap(new ConcurrentHashMap<>())); 100 | hs.add(new WeakHandler<>(subscriber, gcQueue)); 101 | } 102 | } 103 | } 104 | 105 | @Override 106 | public void unsubscribe(H subscriber) { 107 | Class cls = subscriber.getLinkedClass(); 108 | if (cls == null) { 109 | handlers.remove(new WeakHandler<>(subscriber, gcQueue)); 110 | } else { 111 | Set> set = handlersCls.get(cls); 112 | if (set != null) { 113 | set.remove(new WeakHandler<>(subscriber, gcQueue)); 114 | } 115 | } 116 | } 117 | 118 | @Override 119 | public void publish(E event) { 120 | publish(event, null, null); 121 | } 122 | 123 | @Override 124 | public void publish(E event, BiConsumer success, FailureConsumer failure) { 125 | if (event == null) { 126 | return; 127 | } 128 | eventsQueue.add(new EventWrapper<>(event, success, failure)); 129 | synchronized (eventsQueue) { 130 | eventsQueue.notifyAll(); 131 | } 132 | } 133 | 134 | @Override 135 | public boolean hasPendingEvents() { 136 | return !eventsQueue.isEmpty(); 137 | } 138 | 139 | private void eventsQueue() { 140 | while (true) { 141 | WeakHandler wh; 142 | while ((wh = (WeakHandler) gcQueue.poll()) != null) { 143 | Class cls = wh.getHandlerTypeClass(); 144 | if (cls == null) { 145 | handlers.remove(wh); 146 | } else { 147 | Set> set = handlersCls.get(cls); 148 | if (set != null) { 149 | set.remove(wh); 150 | } 151 | } 152 | } 153 | 154 | if (eventsQueue.isEmpty()) { 155 | synchronized (eventsQueue) { 156 | try { 157 | eventsQueue.wait(); 158 | } catch (InterruptedException e) { 159 | throw new RuntimeException(e); 160 | } 161 | } 162 | } 163 | 164 | EventWrapper ew = eventsQueue.poll(); 165 | if (ew != null && ew.event != null) { 166 | notifySubscribers(ew); 167 | } 168 | } 169 | } 170 | 171 | private void notifySubscribers(EventWrapper ew) { 172 | try { 173 | Set> hcls = handlersCls.get(ew.event.getClass()); 174 | if (hcls != null) { 175 | for (WeakHandler wh : hcls) { 176 | H eh = wh.get(); 177 | if (eh != null) { 178 | submitHandler(eh, ew); 179 | } 180 | } 181 | } 182 | 183 | for (WeakHandler wh : handlers) { 184 | H eh = wh.get(); 185 | if (eh != null && eh.canHandle(ew.event.getClass())) { 186 | submitHandler(eh, ew); 187 | } 188 | } 189 | } catch (Throwable th) { 190 | logger.error("Event processing fail {}. {}", ew.event.getClass().getSimpleName(), th.getMessage(), th); 191 | } 192 | } 193 | 194 | private void runHandlerWrapper(H handler, EventWrapper ew) { 195 | try { 196 | runHandler(handler, ew.event); 197 | if (ew.success != null) { 198 | ew.success.accept(ew.event, handler); 199 | } 200 | } catch (Throwable th) { 201 | logger.error("Handler {} fail on event {}. {}", handler.getClass().getSimpleName(), ew.event.getClass().getSimpleName(), th.getMessage(), th); 202 | if (ew.failure != null) { 203 | ew.failure.accept(ew.event, handler, th); 204 | } 205 | } 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/minibus/EventBusEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package com.github.jneat.minibus; 25 | 26 | /** 27 | * Immutable Event that can be processed in EventBus. 28 | * Note that you should take care about your events immutability. 29 | * We suggest you to use only final properties, and in a case if you need builder 30 | * for your message, you can use project lombok library for this purpose. 31 | */ 32 | public interface EventBusEvent { 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/minibus/EventBusHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package com.github.jneat.minibus; 25 | 26 | import java.lang.reflect.ParameterizedType; 27 | 28 | /** 29 | * EventBus event handler. 30 | * There is no restriction on how many handlers will be subscribed to one or another event type. 31 | * Keep in mind that handler will be subscribed to EventBus using weak link. 32 | */ 33 | public abstract class EventBusHandler { 34 | 35 | public Class eventClass; 36 | 37 | private Class getGenericTypeClass() { 38 | if (eventClass == null) { 39 | //noinspection unchecked 40 | eventClass = (Class)((ParameterizedType)getClass() 41 | .getGenericSuperclass()) 42 | .getActualTypeArguments()[0]; 43 | } 44 | return eventClass; 45 | } 46 | 47 | /** 48 | * Return exact event type class that must be handled by this handler. 49 | * Can return null in this case {@link EventBusHandler#canHandle} will be called each time 50 | * to decide if particular message should be handled. 51 | * 52 | * @return Compatible class or null 53 | */ 54 | protected Class getLinkedClass() { 55 | return getGenericTypeClass(); 56 | } 57 | 58 | /** 59 | * If {@link EventBusHandler#getLinkedClass} return null this method will be called to 60 | * check if current event can be handled here. 61 | * If getType() result is not null this method will not be called. 62 | * 63 | * @param cls Event class 64 | * @return True if event type can be handled or False. 65 | */ 66 | public boolean canHandle(Class cls) { 67 | return false; 68 | } 69 | 70 | public void handleEvent(EventBusEvent event) throws Throwable { 71 | this.handle(getGenericTypeClass().cast(event)); 72 | } 73 | 74 | /** 75 | * This method should handle event of appropriate type. 76 | */ 77 | public abstract void handle(E event) throws Throwable; 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/minibus/EventBusSimple.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package com.github.jneat.minibus; 25 | 26 | import org.slf4j.Logger; 27 | import org.slf4j.LoggerFactory; 28 | 29 | import java.lang.ref.ReferenceQueue; 30 | import java.util.Collections; 31 | import java.util.Set; 32 | import java.util.concurrent.ConcurrentHashMap; 33 | import java.util.concurrent.atomic.AtomicInteger; 34 | import java.util.function.BiConsumer; 35 | 36 | /** 37 | * Simple event bus with no background threads, if you have few handlers or do not want to have background threads. All 38 | * consumers will be called directly during event publishing. Publishing event handlers complexity is O(N) we just do 39 | * linear search without optimizations. 40 | */ 41 | public class EventBusSimple> implements EventBus { 42 | 43 | private static final Logger logger = LoggerFactory.getLogger(EventBusSimple.class); 44 | 45 | private final ReferenceQueue gcQueue = new ReferenceQueue(); 46 | 47 | private final AtomicInteger processing = new AtomicInteger(); 48 | 49 | private final Set> handlers = Collections.newSetFromMap(new ConcurrentHashMap<>()); 50 | 51 | /** 52 | * CAN OVERRIDE THIS METHOD. This actually runs handler. You can add some hooks here. 53 | */ 54 | protected void runHandler(H h, E e) throws Throwable { 55 | h.handleEvent(e); 56 | } 57 | 58 | @Override 59 | public void subscribe(H subscriber) { 60 | handlers.add(new WeakHandler<>(subscriber, gcQueue)); 61 | } 62 | 63 | @Override 64 | public void unsubscribe(H subscriber) { 65 | handlers.remove(new WeakHandler<>(subscriber, gcQueue)); 66 | } 67 | 68 | @Override 69 | public void publish(E event) { 70 | publish(event, null, null); 71 | } 72 | 73 | @Override 74 | public void publish(E event, BiConsumer success, FailureConsumer failure) { 75 | if (event == null) { 76 | return; 77 | } 78 | processing.incrementAndGet(); 79 | try { 80 | processEvent(new EventWrapper<>(event, success, failure)); 81 | } finally { 82 | processing.decrementAndGet(); 83 | } 84 | } 85 | 86 | @Override 87 | public boolean hasPendingEvents() { 88 | return processing.get() > 0; 89 | } 90 | 91 | private void processEvent(EventWrapper ew) { 92 | WeakHandler wh; 93 | //noinspection unchecked 94 | while ((wh = (WeakHandler) gcQueue.poll()) != null) { 95 | handlers.remove(wh); 96 | } 97 | if (ew != null) { 98 | notifySubscribers(ew); 99 | } 100 | } 101 | 102 | private void notifySubscribers(EventWrapper ew) { 103 | for (WeakHandler wh : handlers) { 104 | H eh = wh.get(); 105 | if (eh == null) { 106 | continue; 107 | } 108 | 109 | try { 110 | if (eh.getLinkedClass() == null) { 111 | if (eh.canHandle(ew.event.getClass())) { 112 | runHandlerWrapper(eh, ew); 113 | } 114 | } else if (eh.getLinkedClass().equals(ew.event.getClass())) { 115 | runHandlerWrapper(eh, ew); 116 | } 117 | } catch (Throwable th) { 118 | logger.error("Event processing fail {}. {}", ew.event.getClass().getSimpleName(), th.getMessage(), th); 119 | } 120 | } 121 | } 122 | 123 | private void runHandlerWrapper(H eh, EventWrapper ew) { 124 | try { 125 | runHandler(eh, ew.getEvent()); 126 | if (ew.success != null) { 127 | ew.success.accept(ew.event, eh); 128 | } 129 | } catch (Throwable ex) { 130 | logger.error("Handler processing fail for {}. {}", ew.event.getClass().getSimpleName(), ex.getMessage(), ex); 131 | if (ew.failure != null) { 132 | ew.failure.accept(ew.event, eh, ex); 133 | } 134 | } 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/minibus/EventWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package com.github.jneat.minibus; 25 | 26 | import java.util.function.BiConsumer; 27 | 28 | public class EventWrapper> { 29 | 30 | protected final E event; 31 | 32 | protected final BiConsumer success; 33 | 34 | protected final FailureConsumer failure; 35 | 36 | public EventWrapper( 37 | E event, 38 | BiConsumer success, 39 | FailureConsumer failure 40 | ) { 41 | this.event = event; 42 | this.success = success; 43 | this.failure = failure; 44 | } 45 | 46 | public E getEvent() { 47 | return this.event; 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/minibus/FailureConsumer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package com.github.jneat.minibus; 25 | 26 | @FunctionalInterface 27 | public interface FailureConsumer> { 28 | 29 | void accept(E event, H handler, Throwable th); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/minibus/WeakHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | package com.github.jneat.minibus; 25 | 26 | import java.lang.ref.ReferenceQueue; 27 | import java.lang.ref.WeakReference; 28 | 29 | /** 30 | * Provide weak link wrapper for handler class and expose some generic handlers methods. 31 | */ 32 | class WeakHandler> extends WeakReference { 33 | 34 | private final int hash; 35 | 36 | private final Class handlerTypeClass; 37 | 38 | WeakHandler(H handler, ReferenceQueue q) { 39 | super(handler, q); 40 | hash = handler.hashCode(); 41 | handlerTypeClass = handler.getLinkedClass(); 42 | } 43 | 44 | public Class getHandlerTypeClass() { 45 | return handlerTypeClass; 46 | } 47 | 48 | @Override 49 | public int hashCode() { 50 | return hash; 51 | } 52 | 53 | @Override 54 | public boolean equals(Object obj) { 55 | if (this == obj) { 56 | return true; 57 | } 58 | if (!(obj instanceof WeakHandler)) { 59 | return false; 60 | } 61 | 62 | Object t = this.get(); 63 | @SuppressWarnings("unchecked") 64 | Object u = ((WeakHandler) obj).get(); 65 | if (t == u) { 66 | return true; 67 | } 68 | if (t == null || u == null) { 69 | return false; 70 | } 71 | return t.equals(u); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/minibus/utils/EventBroker.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.jneat.minibus.utils; 26 | 27 | import com.github.jneat.minibus.EventBus; 28 | import com.github.jneat.minibus.EventBusAsync; 29 | import com.github.jneat.minibus.EventBusEvent; 30 | import com.github.jneat.minibus.EventBusHandler; 31 | import com.github.jneat.minibus.FailureConsumer; 32 | 33 | import java.util.HashMap; 34 | import java.util.Map; 35 | import java.util.function.BiConsumer; 36 | import java.util.function.Consumer; 37 | 38 | public class EventBroker { 39 | 40 | private static final EventBus> EVENT_BUS = new EventBusAsync<>(); 41 | 42 | private static final EventBroker INSTANCE = new EventBroker(); 43 | 44 | private final Map> registry = new HashMap<>(); 45 | 46 | public void subscribe(Consumer consumer, Class type, String handlerName) { 47 | EventBusHandler handler = new EventBusHandler() { 48 | private final Class handlerType = type; 49 | 50 | @Override 51 | protected Class getLinkedClass() { 52 | return handlerType; 53 | } 54 | 55 | @Override 56 | public void handle(T event) { 57 | consumer.accept(handlerType.cast(event)); 58 | } 59 | 60 | @Override 61 | public void handleEvent(EventBusEvent event) { 62 | this.handle(handlerType.cast(event)); 63 | } 64 | 65 | @Override 66 | public boolean canHandle(Class cls) { 67 | return handlerType.equals(cls); 68 | } 69 | }; 70 | this.subscribe(handler, handlerName); 71 | 72 | } 73 | 74 | public void subscribe(EventBusHandler handler, String handlerName) { 75 | 76 | if (handlerName != null && registry.containsKey(handlerName)) { 77 | //already subscribed 78 | return; 79 | } else { 80 | registry.put(handlerName, handler); 81 | } 82 | 83 | EVENT_BUS.subscribe(handler); 84 | } 85 | 86 | public void unsubscribe(String handlerName) { 87 | EventBusHandler handler = registry.get(handlerName); 88 | if (handler != null) { 89 | EVENT_BUS.unsubscribe(handler); 90 | registry.remove(handlerName); 91 | } 92 | } 93 | 94 | public void publish(EventBusEvent event) { 95 | EVENT_BUS.publish(event); 96 | } 97 | 98 | public void publish(EventBusEvent event, BiConsumer> success, 99 | FailureConsumer> failure) { 100 | EVENT_BUS.publish(event, success, failure); 101 | } 102 | 103 | public static EventBroker getInstance() { 104 | return INSTANCE; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/minibus/utils/EventObservable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.jneat.minibus.utils; 26 | 27 | import com.github.jneat.minibus.EventBusEvent; 28 | 29 | /** 30 | * A replacement for the now deprecated java.util.Observable pattern 31 | * @see java.util.Observable 32 | * 33 | */ 34 | public interface EventObservable { 35 | 36 | default void notifyObservers(E event){ 37 | EventBroker.getInstance().publish(event); 38 | } 39 | 40 | /* 41 | * A replacement method for java.util.Observable.notifyObserver 42 | */ 43 | default void register( EventObserver observer,Class eventType ){ 44 | EventBroker.getInstance().subscribe( 45 | (E event) -> observer.update(this,event), eventType , observer.getObserverName()); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/github/jneat/minibus/utils/EventObserver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.jneat.minibus.utils; 26 | 27 | import com.github.jneat.minibus.EventBusEvent; 28 | 29 | /** 30 | * A replacement for the now deprecated java.util.Observer pattern 31 | * 32 | * @see java.util.Observer 33 | */ 34 | public interface EventObserver { 35 | 36 | default String getObserverName() { 37 | return this.getClass().getName() + "Observer"; 38 | } 39 | 40 | void update(EventObservable observable, E event); 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/Event.java: -------------------------------------------------------------------------------- 1 | package com.github.jneat.minibus; 2 | 3 | import com.github.jneat.minibus.EventBusEvent; 4 | 5 | public interface Event extends EventBusEvent { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/Event1.java: -------------------------------------------------------------------------------- 1 | package com.github.jneat.minibus; 2 | 3 | public class Event1 implements Event { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/Event2.java: -------------------------------------------------------------------------------- 1 | package com.github.jneat.minibus; 2 | 3 | public class Event2 implements Event { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/Event3.java: -------------------------------------------------------------------------------- 1 | package com.github.jneat.minibus; 2 | 3 | public class Event3 implements Event { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/Event4.java: -------------------------------------------------------------------------------- 1 | package com.github.jneat.minibus; 2 | 3 | public class Event4 implements Event { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/EventBusAsyncTest.java: -------------------------------------------------------------------------------- 1 | package com.github.jneat.minibus; 2 | 3 | import org.testng.annotations.BeforeClass; 4 | import org.testng.annotations.Test; 5 | 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | import static org.assertj.core.api.Assertions.assertThat; 9 | 10 | public class EventBusAsyncTest { 11 | 12 | Handler1 h1 = new Handler1(); 13 | 14 | Handler2 h2 = new Handler2(); 15 | 16 | Handler3 h3 = new Handler3(); 17 | 18 | Handler4Error h4 = new Handler4Error(); 19 | 20 | Handler234 h234 = new Handler234(); 21 | 22 | @BeforeClass 23 | void init() { 24 | } 25 | 26 | @Test(priority = 10) 27 | void testAsync() throws InterruptedException { 28 | EventBusAsync> eventBus = new EventBusAsync<>(); 29 | eventBus.subscribe(h1); 30 | eventBus.subscribe(h2); 31 | eventBus.subscribe(h3); 32 | eventBus.subscribe(h234); 33 | eventBus.subscribe(h4); 34 | 35 | testBus(eventBus); 36 | } 37 | 38 | @Test(priority = 20) 39 | void testSimple() throws InterruptedException { 40 | EventBusSimple> eventBus = new EventBusSimple<>(); 41 | eventBus.subscribe(h1); 42 | eventBus.subscribe(h2); 43 | eventBus.subscribe(h3); 44 | eventBus.subscribe(h234); 45 | eventBus.subscribe(h4); 46 | 47 | testBus(eventBus); 48 | } 49 | 50 | private void testBus(EventBus> eb) throws InterruptedException { 51 | h1.counter.set(0); 52 | h2.counter.set(0); 53 | h3.counter.set(0); 54 | h234.counter.set(0); 55 | 56 | assertThat(h1.counter).hasValue(0); 57 | assertThat(h2.counter).hasValue(0); 58 | assertThat(h3.counter).hasValue(0); 59 | assertThat(h234.counter).hasValue(0); 60 | 61 | eb.publish(new Event1()); 62 | Thread.sleep(500); 63 | 64 | assertThat(h1.counter).hasValue(1); 65 | assertThat(h2.counter).hasValue(0); 66 | assertThat(h3.counter).hasValue(0); 67 | assertThat(h234.counter).hasValue(0); 68 | 69 | eb.publish(new Event2()); 70 | Thread.sleep(500); 71 | 72 | assertThat(h1.counter).hasValue(1); 73 | assertThat(h2.counter).hasValue(1); 74 | assertThat(h3.counter).hasValue(0); 75 | assertThat(h234.counter).hasValue(1); 76 | 77 | AtomicInteger e3success = new AtomicInteger(0); 78 | AtomicInteger e3error = new AtomicInteger(0); 79 | eb.publish(new Event3(), 80 | (e, h) -> { 81 | e3success.incrementAndGet(); 82 | }, (e, h, th) -> { 83 | e3error.incrementAndGet(); 84 | }); 85 | Thread.sleep(500); 86 | 87 | assertThat(e3success).hasValue(2); 88 | assertThat(e3error).hasValue(0); 89 | assertThat(h1.counter).hasValue(1); 90 | assertThat(h2.counter).hasValue(1); 91 | assertThat(h3.counter).hasValue(1); 92 | assertThat(h234.counter).hasValue(2); 93 | 94 | AtomicInteger e4success = new AtomicInteger(0); 95 | AtomicInteger e4error = new AtomicInteger(0); 96 | eb.publish(new Event4(), 97 | (e, h) -> { 98 | e4success.incrementAndGet(); 99 | }, (e, h, th) -> { 100 | e4error.incrementAndGet(); 101 | }); 102 | Thread.sleep(500); 103 | 104 | assertThat(e4success).hasValue(1); 105 | assertThat(e4error).hasValue(1); 106 | assertThat(h1.counter).hasValue(1); 107 | assertThat(h2.counter).hasValue(1); 108 | assertThat(h3.counter).hasValue(1); 109 | assertThat(h234.counter).hasValue(3); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/Handler1.java: -------------------------------------------------------------------------------- 1 | package com.github.jneat.minibus; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | public class Handler1 extends EventBusHandler { 6 | 7 | AtomicInteger counter = new AtomicInteger(); 8 | 9 | @Override 10 | public void handle(Event1 event) { 11 | counter.incrementAndGet(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/Handler2.java: -------------------------------------------------------------------------------- 1 | package com.github.jneat.minibus; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | public class Handler2 extends EventBusHandler { 6 | 7 | AtomicInteger counter = new AtomicInteger(); 8 | 9 | @Override 10 | public void handle(Event2 event) { 11 | counter.incrementAndGet(); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/Handler234.java: -------------------------------------------------------------------------------- 1 | package com.github.jneat.minibus; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | import java.util.logging.Logger; 5 | 6 | /** 7 | * This handler can handle multiple events by condition 8 | */ 9 | public class Handler234 extends EventBusHandler { 10 | 11 | private static final Logger logger = Logger.getLogger(Handler234.class.getSimpleName()); 12 | 13 | AtomicInteger counter = new AtomicInteger(); 14 | 15 | @Override 16 | protected Class getLinkedClass() { 17 | return null; 18 | } 19 | 20 | @Override 21 | public boolean canHandle(Class cls) { 22 | boolean h = cls.isAssignableFrom(Event2.class) 23 | || cls.isAssignableFrom(Event3.class) 24 | || cls.isAssignableFrom(Event4.class); 25 | logger.info("Result " + h + " for " + cls.getCanonicalName()); 26 | return h; 27 | } 28 | 29 | @Override 30 | public void handle(EventBusEvent event) { 31 | counter.incrementAndGet(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/Handler3.java: -------------------------------------------------------------------------------- 1 | package com.github.jneat.minibus; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | public class Handler3 extends EventBusHandler { 6 | 7 | AtomicInteger counter = new AtomicInteger(); 8 | 9 | @Override 10 | public void handle(Event3 event) { 11 | counter.incrementAndGet(); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/Handler4Error.java: -------------------------------------------------------------------------------- 1 | package com.github.jneat.minibus; 2 | 3 | public class Handler4Error extends EventBusHandler { 4 | 5 | @Override 6 | public void handle(Event4 event) { 7 | throw new UnsupportedOperationException("This error should be caught"); 8 | } 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/utils/EventController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.jneat.minibus.utils; 26 | 27 | public class EventController implements EventObservable { 28 | 29 | public void execute(){ 30 | // do some business logic here 31 | notifyObservers(new KeyEvent("Test Event")); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/utils/EventObservableTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.jneat.minibus.utils; 26 | 27 | import org.testng.annotations.Test; 28 | 29 | public class EventObservableTest { 30 | 31 | @Test 32 | public void notifyObservers() throws Exception { 33 | EventController controller = new EventController(); 34 | EventUIFormPanel panel = new EventUIFormPanel(); 35 | controller.register(panel,KeyEvent.class); 36 | controller.execute(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/utils/EventUIFormPanel.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.jneat.minibus.utils; 26 | 27 | public class EventUIFormPanel implements EventObserver{ 28 | 29 | 30 | @Override 31 | public void update(EventObservable observable, KeyEvent event) { 32 | System.out.println("Updating some UI components for event:"+event.getKey()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/com/github/jneat/minibus/utils/KeyEvent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2018 by rumatoest at github.com 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | package com.github.jneat.minibus.utils; 26 | 27 | import com.github.jneat.minibus.EventBusEvent; 28 | 29 | public class KeyEvent implements EventBusEvent { 30 | private String key; 31 | 32 | public KeyEvent(String key) { 33 | this.key = key; 34 | } 35 | 36 | public String getKey() { 37 | return key; 38 | } 39 | 40 | public void setKey(String key) { 41 | this.key = key; 42 | } 43 | } 44 | --------------------------------------------------------------------------------