├── .gitignore ├── LICENSE ├── LICENSE.Apachev2 ├── LICENSE.BSD3 ├── LICENSE.CC0 ├── LICENSE.MIT ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle.kts ├── src └── dorkbox │ └── messageBus │ ├── AsyncPublicationMode.java │ ├── DispatchMode.java │ ├── MessageBus.java │ ├── SubscriptionMode.java │ ├── annotations │ ├── Listener.java │ ├── References.java │ ├── Subscribe.java │ └── Synchronized.java │ ├── common │ ├── ClassTree.java │ ├── MessageHandler.java │ └── MultiClass.java │ ├── dispatch │ ├── Dispatch.java │ ├── DispatchExact.java │ └── DispatchExactWithSuperTypes.java │ ├── error │ ├── DeadMessage.java │ ├── ErrorHandler.java │ ├── IPublicationErrorHandler.java │ ├── MessageBusException.java │ └── PublicationError.java │ ├── publication │ ├── ConversantDisruptor.java │ ├── DirectInvocation.java │ ├── LmaxDisruptor.java │ ├── Publisher.java │ └── disruptor │ │ ├── EventBusFactory.java │ │ ├── MessageHandler.java │ │ ├── MessageHolder.java │ │ ├── MessageType.java │ │ └── PublicationExceptionHandler.java │ └── subscription │ ├── Entry.java │ ├── Subscription.java │ ├── SubscriptionFactory.java │ ├── SubscriptionManager.java │ ├── asm │ ├── AsmFactory.java │ ├── AsmInvocation.java │ ├── AsmReflectiveInvocation.java │ ├── AsmSynchronizedInvocation.java │ ├── SubscriptionAsmStrong.java │ └── SubscriptionAsmWeak.java │ └── reflection │ ├── ReflectionFactory.java │ ├── ReflectionInvocation.java │ ├── ReflectionReflectiveInvocation.java │ ├── ReflectionSynchronizedInvocation.java │ ├── SubscriptionReflectionStrong.java │ └── SubscriptionReflectionWeak.java ├── src9 ├── dorkbox │ └── messageBus │ │ └── EmptyClass.java └── module-info.java └── test └── dorkbox └── messagebus ├── AllTests.java ├── AsyncFIFOBusTest.java ├── DeadMessageTest.java ├── MBassadorTest.java ├── MetadataReaderTest.java ├── MethodDispatchTest.java ├── MultiMessageTest.java ├── MultiTreeTest.java ├── SubscriptionManagerTest.java ├── SyncBusTest.java ├── SynchronizedHandlerTest.java ├── common ├── AssertSupport.java ├── ConcurrentExecutor.java ├── ListenerFactory.java ├── MessageBusTest.java ├── MessageManager.java ├── SubscriptionValidator.java └── TestUtil.java ├── listeners ├── AbstractMessageListener.java ├── ExceptionThrowingListener.java ├── ICountableListener.java ├── IMessageListener.java ├── IMultipartMessageListener.java ├── Listeners.java ├── MessageTypesListener.java ├── MultipartMessageListener.java ├── ObjectListener.java ├── Overloading.java └── StandardMessageListener.java └── messages ├── AbstractMessage.java ├── CountableMessage.java ├── ICountable.java ├── IMessage.java ├── IMultipartMessage.java ├── MessageTypes.java ├── MultipartMessage.java ├── StandardMessage.java ├── SubTestMessage.java └── TestMessage.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 2 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 3 | 4 | # User-specific stuff: 5 | .idea/**/workspace.xml 6 | .idea/**/tasks.xml 7 | .idea/dictionaries 8 | .idea/**/codeStyles/ 9 | .idea/**/codeStyleSettings.xml 10 | 11 | # Sensitive or high-churn files: 12 | .idea/**/dataSources/ 13 | .idea/**/dataSources.ids 14 | .idea/**/dataSources.xml 15 | .idea/**/dataSources.local.xml 16 | .idea/**/sqlDataSources.xml 17 | .idea/**/dynamic.xml 18 | .idea/**/uiDesigner.xml 19 | .idea/**/shelf/ 20 | 21 | 22 | # Gradle: 23 | .idea/**/gradle.xml 24 | .idea/**/libraries 25 | 26 | # CMake 27 | cmake-build-debug/ 28 | 29 | # Mongo Explorer plugin: 30 | .idea/**/mongoSettings.xml 31 | 32 | ## File-based project format: 33 | *.iws 34 | 35 | ## Plugin-specific files: 36 | 37 | 38 | # IntelliJ 39 | out/ 40 | 41 | # mpeltonen/sbt-idea plugin 42 | .idea_modules/ 43 | 44 | # JIRA plugin 45 | atlassian-ide-plugin.xml 46 | 47 | # Cursive Clojure plugin 48 | .idea/replstate.xml 49 | 50 | # Crashlytics plugin (for Android Studio and IntelliJ) 51 | com_crashlytics_export_strings.xml 52 | crashlytics.properties 53 | crashlytics-build.properties 54 | fabric.properties 55 | 56 | ###################### 57 | # End JetBrains IDEs # 58 | ###################### 59 | 60 | 61 | # From https://github.com/github/gitignore/blob/master/Gradle.gitignore 62 | .gradle 63 | /build/ 64 | 65 | # Ignore Gradle GUI config 66 | gradle-app.setting 67 | 68 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) 69 | !gradle-wrapper.jar 70 | !gradle-wrapper.properties 71 | 72 | # Cache of project 73 | .gradletasknamecache 74 | 75 | 76 | 77 | 78 | # From https://github.com/github/gitignore/blob/master/Java.gitignore 79 | *.class 80 | 81 | # Mobile Tools for Java (J2ME) 82 | .mtj.tmp/ 83 | 84 | 85 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 86 | hs_err_pid* 87 | 88 | *.DS_Store 89 | .AppleDouble 90 | .LSOverride 91 | 92 | # Icon must end with two \r 93 | Icon 94 | 95 | 96 | # Thumbnails 97 | ._* 98 | 99 | # Files that might appear in the root of a volume 100 | .DocumentRevisions-V100 101 | .fseventsd 102 | .Spotlight-V100 103 | .TemporaryItems 104 | .Trashes 105 | .VolumeIcon.icns 106 | .com.apple.timemachine.donotpresent 107 | 108 | # Directories potentially created on remote AFP share 109 | .AppleDB 110 | .AppleDesktop 111 | Network Trash Folder 112 | Temporary Items 113 | .apdisk 114 | 115 | 116 | 117 | ########################################################## 118 | # Specific to this module 119 | 120 | # iml files are generated by intellij/gradle now 121 | **/*.iml 122 | -------------------------------------------------------------------------------- /LICENSE.BSD3: -------------------------------------------------------------------------------- 1 | BSD License 2 | 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | * Neither the name of the nor the names of its contributors 14 | may be used to endorse or promote products derived from this software 15 | without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 21 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /LICENSE.MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | /////////////////////////////// 18 | ////// PUBLISH TO SONATYPE / MAVEN CENTRAL 19 | ////// TESTING : (to local maven repo) <'publish and release' - 'publishToMavenLocal'> 20 | ////// RELEASE : (to sonatype/maven central), <'publish and release' - 'publishToSonatypeAndRelease'> 21 | /////////////////////////////// 22 | 23 | gradle.startParameter.showStacktrace = ShowStacktrace.ALWAYS // always show the stacktrace! 24 | 25 | plugins { 26 | id("com.dorkbox.GradleUtils") version "3.18" 27 | id("com.dorkbox.Licensing") version "2.28" 28 | id("com.dorkbox.VersionUpdate") version "2.8" 29 | id("com.dorkbox.GradlePublish") version "1.20" 30 | 31 | kotlin("jvm") version "1.9.0" 32 | } 33 | object Extras { 34 | // set for the project 35 | const val description = "Lightweight, extremely fast, and zero-gc message/event bus for Java 8+" 36 | const val group = "com.dorkbox" 37 | const val version = "2.7" 38 | 39 | // set as project.ext 40 | const val name = "MessageBus" 41 | const val id = "MessageBus" 42 | const val vendor = "Dorkbox LLC" 43 | const val vendorUrl = "https://dorkbox.com" 44 | const val url = "https://git.dorkbox.com/dorkbox/MessageBus" 45 | 46 | val JAVA_VERSION = JavaVersion.VERSION_1_8.toString() 47 | } 48 | 49 | /////////////////////////////// 50 | ///// assign 'Extras' 51 | /////////////////////////////// 52 | GradleUtils.load("$projectDir/../../gradle.properties", Extras) 53 | GradleUtils.defaults() 54 | GradleUtils.compileConfiguration(JavaVersion.VERSION_1_8) 55 | GradleUtils.jpms(JavaVersion.VERSION_1_9) 56 | 57 | licensing { 58 | license(License.APACHE_2) { 59 | author(Extras.vendor) 60 | url(Extras.url) 61 | note(Extras.description) 62 | 63 | extra("MBassador", License.MIT) { 64 | copyright(2012) 65 | author("Benjamin Diedrichsen") 66 | url("https://github.com/bennidi/mbassador") 67 | } 68 | } 69 | } 70 | 71 | tasks.jar.get().apply { 72 | manifest { 73 | // https://docs.oracle.com/javase/tutorial/deployment/jar/packageman.html 74 | attributes["Name"] = Extras.name 75 | 76 | attributes["Specification-Title"] = Extras.name 77 | attributes["Specification-Version"] = Extras.version 78 | attributes["Specification-Vendor"] = Extras.vendor 79 | 80 | attributes["Implementation-Title"] = "${Extras.group}.${Extras.id}" 81 | attributes["Implementation-Version"] = GradleUtils.now() 82 | attributes["Implementation-Vendor"] = Extras.vendor 83 | 84 | attributes["Automatic-Module-Name"] = Extras.id 85 | } 86 | } 87 | 88 | dependencies { 89 | api("com.dorkbox:ClassUtils:1.3") 90 | api("com.dorkbox:Collections:2.4") 91 | api("com.dorkbox:Updates:1.1") 92 | api("com.dorkbox:Utilities:1.46") 93 | 94 | api("com.lmax:disruptor:3.4.4") 95 | api("com.conversantmedia:disruptor:1.2.21") 96 | 97 | api("org.ow2.asm:asm:9.5") 98 | api("com.esotericsoftware:reflectasm:1.11.9") 99 | 100 | implementation("org.slf4j:slf4j-api:2.0.7") 101 | 102 | 103 | testImplementation("junit:junit:4.13.2") 104 | testImplementation("ch.qos.logback:logback-classic:1.4.5") 105 | } 106 | 107 | publishToSonatype { 108 | groupId = Extras.group 109 | artifactId = Extras.id 110 | version = Extras.version 111 | 112 | name = Extras.name 113 | description = Extras.description 114 | url = Extras.url 115 | 116 | vendor = Extras.vendor 117 | vendorUrl = Extras.vendorUrl 118 | 119 | issueManagement { 120 | url = "${Extras.url}/issues" 121 | nickname = "Gitea Issues" 122 | } 123 | 124 | developer { 125 | id = "dorkbox" 126 | name = Extras.vendor 127 | email = "email@dorkbox.com" 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties 2 | org.gradle.jvmargs=-Dfile.encoding=UTF-8 3 | 4 | #org.gradle.warning.mode=(all,fail,none,summary) 5 | org.gradle.warning.mode=all 6 | 7 | #org.gradle.daemon=false 8 | # default is 3 hours, this is 1 minute 9 | org.gradle.daemon.idletimeout=60000 10 | 11 | #org.gradle.console=(auto,plain,rich,verbose) 12 | org.gradle.console=auto 13 | 14 | #org.gradle.logging.level=(quiet,warn,lifecycle,info,debug) 15 | org.gradle.logging.level=lifecycle 16 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dorkbox/MessageBus/1cccb72313dc6dcc60722468f8ce42be90f39702/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-8.3-all.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2018 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | rootProject.name = "MessageBus" 17 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/AsyncPublicationMode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus; 17 | 18 | public 19 | enum AsyncPublicationMode { 20 | 21 | /** 22 | * This is the default. 23 | *

24 | * This uses the LMAX disruptor for managing the ASYNC publication of messages. 25 | *

26 | * The Conversant Disruptor is shown to be faster, however the LMAX Disruptor DOES NOT generate any garbage when 27 | * running, while the Conversant Disruptor creates new `Runnable` for every invocation. 28 | */ 29 | LmaxDisruptor, 30 | 31 | /** 32 | * This uses the Conversant disruptor + (many) runnable for managing the ASYNC publication of messages. 33 | *

34 | * The Conversant Disruptor is shown to be faster than the LMAX disruptor, however the Conversant disruptor 35 | * relies on creating a `new Runnable()` for execution, where the LMAX Disruptor DOES NOT. 36 | */ 37 | ConversantDisruptor, 38 | } 39 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/DispatchMode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus; 17 | 18 | public 19 | enum DispatchMode { 20 | /** 21 | * Will only publish to listeners with this exact message signature. This is the fastest 22 | */ 23 | Exact, 24 | 25 | /** 26 | * Will publish to listeners with this exact message signature, as well as listeners that match the super class types signatures. 27 | */ 28 | ExactWithSuperTypes, 29 | } 30 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/SubscriptionMode.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus; 17 | 18 | public 19 | enum SubscriptionMode { 20 | /** 21 | * This is the default. 22 | *

23 | * We use strong references when saving the subscribed listeners (these are the classes & methods that receive messages). 24 | *

25 | * In certain environments (ie: spring), it is desirable to use weak references -- so that there are no memory leaks during 26 | * the container lifecycle (or, more specifically, so one doesn't have to manually manage the memory). 27 | */ 28 | StrongReferences, 29 | 30 | /** 31 | * Using weak references is a tad slower than using strong references, since there are additional steps taken when there are orphaned 32 | * references (when GC occurs) that have to be cleaned up. This cleanup occurs during message publication. 33 | */ 34 | WeakReferences 35 | } 36 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/annotations/Listener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messageBus.annotations; 24 | 25 | import java.lang.annotation.ElementType; 26 | import java.lang.annotation.Inherited; 27 | import java.lang.annotation.Retention; 28 | import java.lang.annotation.RetentionPolicy; 29 | import java.lang.annotation.Target; 30 | 31 | /** 32 | * This annotation is meant to carry configuration that is shared among all instances of the annotated 33 | * listener. Supported configurations are: 34 | *

35 | * Reference type: The bus will use either strong or weak references to its registered listeners, 36 | * depending on which reference type (@see References) is set 37 | * 38 | * @author bennidi 39 | * @author dorkbox, llc 40 | * Date: 2/6/16 41 | */ 42 | @Retention(value = RetentionPolicy.RUNTIME) 43 | @Target(value = {ElementType.TYPE, ElementType.ANNOTATION_TYPE}) 44 | @Inherited 45 | public 46 | @interface Listener { 47 | /** 48 | * By default, references to message listeners (these are the objects/methods that receive messages) are strong. See {@link dorkbox.messageBus.SubscriptionMode}). 49 | * 50 | * The benefits to use WEAK references, is to eliminate risks of memory leaks in managed environments (such as spring). 51 | * 52 | * the default here "Undefined" here so that the {@link dorkbox.messageBus.SubscriptionMode#StrongReferences} takes priority 53 | */ 54 | References references() default References.Undefined; 55 | } 56 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/annotations/References.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messageBus.annotations; 24 | 25 | /** 26 | * @author bennidi 27 | * Date: 3/29/13 28 | * @author dorkbox, llc 29 | * Date: 2/6/16 30 | */ 31 | public enum References { 32 | /** This is the default */ 33 | Undefined, 34 | 35 | 36 | /** 37 | * Strong references are faster than weak, as there are no extra steps necessary (to clean up the data structures) during 38 | * mesasge publication. 39 | */ 40 | Strong, 41 | 42 | /** 43 | * This is provided so memory management in containers (such as spring) is easier. This is slower access than Strong refs because of 44 | * the additional checks for orphan/GC'd objects in the subscription lists during publication. 45 | */ 46 | Weak 47 | } 48 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/annotations/Subscribe.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | * 24 | * Copyright 2015 dorkbox, llc 25 | * 26 | * Licensed under the Apache License, Version 2.0 (the "License"); 27 | * you may not use this file except in compliance with the License. 28 | * You may obtain a copy of the License at 29 | * 30 | * http://www.apache.org/licenses/LICENSE-2.0 31 | * 32 | * Unless required by applicable law or agreed to in writing, software 33 | * distributed under the License is distributed on an "AS IS" BASIS, 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | * See the License for the specific language governing permissions and 36 | * limitations under the License. 37 | */ 38 | package dorkbox.messageBus.annotations; 39 | 40 | import java.lang.annotation.ElementType; 41 | import java.lang.annotation.Inherited; 42 | import java.lang.annotation.Retention; 43 | import java.lang.annotation.RetentionPolicy; 44 | import java.lang.annotation.Target; 45 | 46 | /** 47 | * Marks a method of any subscribed class as a message event handler and configure the handler 48 | * using different properties. 49 | * 50 | * @author bennidi 51 | * Date: 2/8/12 52 | * @author dorkbox 53 | * Date: 2/2/15 54 | */ 55 | @Retention(value = RetentionPolicy.RUNTIME) 56 | @Inherited 57 | @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) 58 | public 59 | @interface Subscribe { 60 | 61 | /** 62 | * Define whether or not the subscription handler accepts sub types of the message type it declares in its 63 | * signature. 64 | */ 65 | boolean acceptSubtypes() default true; 66 | 67 | /** 68 | * Enable or disable the subscription. Disabled subscription handlers do not receive any messages. 69 | * 70 | * This property is useful for quick changes in configuration and necessary to subscription disable 71 | * handlers that have been declared by a superclass but do not apply to the subclass 72 | */ 73 | boolean enabled() default true; 74 | } 75 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/annotations/Synchronized.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messageBus.annotations; 24 | 25 | import java.lang.annotation.ElementType; 26 | import java.lang.annotation.Inherited; 27 | import java.lang.annotation.Retention; 28 | import java.lang.annotation.RetentionPolicy; 29 | import java.lang.annotation.Target; 30 | 31 | /** 32 | * A handler marked with this annotation is guaranteed to be invoked in a thread-safe manner, that is, no 33 | * other running message publication will be able to invoke this or any other synchronized handler of the same 34 | * listener until the handler completed. It is equal to wrapping the handler code in a synchronized{} block. 35 | * This feature will reduce performance of message publication. Try to avoid shared mutable state whenever possible 36 | * and use immutable data instead. 37 | *

38 | * Note: Unsynchronized handlers may be invoked concurrently with synchronized ones 39 | * 40 | * @author bennidi 41 | * Date: 3/31/13 42 | */ 43 | @Retention(value = RetentionPolicy.RUNTIME) 44 | @Inherited 45 | @Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE}) 46 | public 47 | @interface Synchronized {} 48 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/common/MultiClass.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.common; 17 | 18 | /** 19 | * @author dorkbox, llc 20 | * Date: 2/3/16 21 | */ 22 | public 23 | class MultiClass implements Comparable { 24 | private final int value; 25 | 26 | public 27 | MultiClass(int value) { 28 | this.value = value; 29 | } 30 | 31 | @Override 32 | public 33 | int compareTo(final MultiClass o) { 34 | if (value < o.value) { 35 | return -1; 36 | } 37 | else if (value == o.value) { 38 | return 0; 39 | } 40 | else { 41 | return 1; 42 | } 43 | } 44 | 45 | @Override 46 | public 47 | boolean equals(final Object o) { 48 | if (this == o) { 49 | return true; 50 | } 51 | if (o == null || getClass() != o.getClass()) { 52 | return false; 53 | } 54 | 55 | final MultiClass that = (MultiClass) o; 56 | 57 | return value == that.value; 58 | 59 | } 60 | 61 | @Override 62 | public 63 | int hashCode() { 64 | return value; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/dispatch/Dispatch.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.dispatch; 17 | 18 | 19 | import dorkbox.messageBus.error.ErrorHandler; 20 | import dorkbox.messageBus.publication.Publisher; 21 | import dorkbox.messageBus.subscription.SubscriptionManager; 22 | 23 | /** 24 | * @author dorkbox, llc 25 | * Date: 2/2/15 26 | */ 27 | public interface Dispatch { 28 | void publish(Publisher publisher, ErrorHandler errorHandler, SubscriptionManager subscriptionManager, Object message1); 29 | void publish(Publisher publisher, ErrorHandler errorHandler, SubscriptionManager subscriptionManager, Object message1, Object message2); 30 | void publish(Publisher publisher, ErrorHandler errorHandler, SubscriptionManager subscriptionManager, Object message1, Object message2, Object message3); 31 | } 32 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/error/DeadMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | * 24 | * Copyright 2015 dorkbox, llc 25 | * 26 | * Licensed under the Apache License, Version 2.0 (the "License"); 27 | * you may not use this file except in compliance with the License. 28 | * You may obtain a copy of the License at 29 | * 30 | * http://www.apache.org/licenses/LICENSE-2.0 31 | * 32 | * Unless required by applicable law or agreed to in writing, software 33 | * distributed under the License is distributed on an "AS IS" BASIS, 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | * See the License for the specific language governing permissions and 36 | * limitations under the License. 37 | */ 38 | package dorkbox.messageBus.error; 39 | 40 | /** 41 | * The dead message event is published whenever no message handlers could be found for a given message publication. 42 | * 43 | * @author bennidi 44 | * Date: 1/18/13 45 | * @author dorkbox, llc 46 | * Date: 2/2/15 47 | */ 48 | public final 49 | class DeadMessage { 50 | 51 | private final Object[] relatedMessages; 52 | 53 | public 54 | DeadMessage(Object message) { 55 | this.relatedMessages = new Object[1]; 56 | this.relatedMessages[0] = message; 57 | } 58 | 59 | public 60 | DeadMessage(Object message1, Object message2) { 61 | this.relatedMessages = new Object[2]; 62 | this.relatedMessages[0] = message1; 63 | this.relatedMessages[1] = message2; 64 | } 65 | 66 | public 67 | DeadMessage(Object message1, Object message2, Object message3) { 68 | this.relatedMessages = new Object[3]; 69 | this.relatedMessages[0] = message1; 70 | this.relatedMessages[1] = message2; 71 | this.relatedMessages[2] = message3; 72 | } 73 | 74 | public 75 | Object[] getMessages() { 76 | return this.relatedMessages; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/error/ErrorHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.error; 17 | 18 | import java.util.ArrayDeque; 19 | import java.util.Collection; 20 | 21 | /** 22 | * @author bennidi 23 | */ 24 | @SuppressWarnings("Duplicates") 25 | public final 26 | class ErrorHandler { 27 | private static final String LINE_SEPARATOR = System.getProperty("line.separator"); 28 | 29 | private static final String ERROR_HANDLER_MSG = 30 | "INFO: No error handler has been configured to handle exceptions during publication." + LINE_SEPARATOR + 31 | "Falling back to console logger." + LINE_SEPARATOR + 32 | "Publication error handlers can be added by calling MessageBus.addErrorHandler()" + LINE_SEPARATOR; 33 | 34 | // this handler will receive all errors that occur during message dispatch or message handling 35 | private final Collection errorHandlers = new ArrayDeque(); 36 | private boolean changedDefaults = false; 37 | 38 | 39 | public 40 | ErrorHandler() { 41 | } 42 | 43 | public synchronized 44 | void addErrorHandler(IPublicationErrorHandler handler) { 45 | changedDefaults = true; 46 | 47 | this.errorHandlers.add(handler); 48 | } 49 | 50 | public synchronized 51 | void handlePublicationError(PublicationError error) { 52 | if (!changedDefaults) { 53 | changedDefaults = true; 54 | 55 | // lazy-set the error handler + default message if none have been set 56 | if (this.errorHandlers.isEmpty()) { 57 | this.errorHandlers.add(new IPublicationErrorHandler.ConsoleLogger()); 58 | System.out.println(ERROR_HANDLER_MSG); 59 | } 60 | } 61 | 62 | for (IPublicationErrorHandler errorHandler : this.errorHandlers) { 63 | errorHandler.handleError(error); 64 | } 65 | } 66 | 67 | public synchronized 68 | void handleError(final String error, final Class listenerClass) { 69 | if (!changedDefaults) { 70 | changedDefaults = true; 71 | 72 | // lazy-set the error handler + default message if none have been set 73 | if (this.errorHandlers.isEmpty()) { 74 | this.errorHandlers.add(new IPublicationErrorHandler.ConsoleLogger()); 75 | System.out.println(ERROR_HANDLER_MSG); 76 | } 77 | } 78 | 79 | for (IPublicationErrorHandler errorHandler : this.errorHandlers) { 80 | errorHandler.handleError(error, listenerClass); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/error/IPublicationErrorHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messageBus.error; 24 | 25 | /** 26 | * Publication error handlers are provided with a publication error every time an error occurs during message publication. 27 | *

28 | * A handler might fail with an exception, not be accessible because of the presence of a security manager or other reasons might 29 | * lead to failures during the message publication process. 30 | *

31 | * 32 | * @author bennidi 33 | * Date: 2/22/12 34 | */ 35 | public 36 | interface IPublicationErrorHandler { 37 | 38 | /** 39 | * Handle the given publication error. 40 | * 41 | * @param error The PublicationError to handle. 42 | */ 43 | void handleError(PublicationError error); 44 | 45 | /** 46 | * Handle the given publication error. 47 | * 48 | * @param error The PublicationError to handle. 49 | * @param listenerClass The class that caused the error to occur 50 | */ 51 | void handleError(String error, final Class listenerClass); 52 | 53 | 54 | /** 55 | * The default error handler will simply log to standard out and print the stack trace if available. 56 | */ 57 | final 58 | class ConsoleLogger implements IPublicationErrorHandler { 59 | /** 60 | * {@inheritDoc} 61 | */ 62 | @Override 63 | public 64 | void handleError(final PublicationError error) { 65 | // Printout the error itself 66 | System.out.println(error); 67 | 68 | // Printout the stacktrace from the cause. 69 | if (error.getCause() != null) { 70 | error.getCause().printStackTrace(); 71 | } 72 | } 73 | 74 | /** 75 | * {@inheritDoc} 76 | */ 77 | @Override 78 | public 79 | void handleError(final String error, final Class listenerClass) { 80 | // Printout the error itself 81 | System.out.println(new StringBuilder().append(error).append(": ").append(listenerClass.getSimpleName()).toString()); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/error/MessageBusException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messageBus.error; 24 | 25 | /** 26 | * The universal exception type for message bus implementations. 27 | * 28 | * @author bennidi 29 | * Date: 3/29/13 30 | */ 31 | public 32 | class MessageBusException extends Exception { 33 | private static final long serialVersionUID = 1L; 34 | 35 | public 36 | MessageBusException() { 37 | } 38 | 39 | public 40 | MessageBusException(String message) { 41 | super(message); 42 | } 43 | 44 | public 45 | MessageBusException(String message, Throwable cause) { 46 | super(message, cause); 47 | } 48 | 49 | public 50 | MessageBusException(Throwable cause) { 51 | super(cause); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/error/PublicationError.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | * 24 | * Copyright 2015 dorkbox, llc 25 | * 26 | * Licensed under the Apache License, Version 2.0 (the "License"); 27 | * you may not use this file except in compliance with the License. 28 | * You may obtain a copy of the License at 29 | * 30 | * http://www.apache.org/licenses/LICENSE-2.0 31 | * 32 | * Unless required by applicable law or agreed to in writing, software 33 | * distributed under the License is distributed on an "AS IS" BASIS, 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | * See the License for the specific language governing permissions and 36 | * limitations under the License. 37 | */ 38 | package dorkbox.messageBus.error; 39 | 40 | import java.util.Arrays; 41 | 42 | /** 43 | * Publication errors are created when object publication fails 44 | * for some reason and contain details as to the cause and location 45 | * where they occurred. 46 | *

47 | * 48 | * @author bennidi 49 | * Date: 2/22/12 50 | * @author dorkbox, llc 51 | * Date: 2/2/15 52 | */ 53 | public 54 | class PublicationError { 55 | 56 | // Internal state 57 | private Throwable cause; 58 | private String message; 59 | private Object[] publishedObjects; 60 | 61 | 62 | /** 63 | * Default constructor. 64 | */ 65 | public 66 | PublicationError() { 67 | super(); 68 | } 69 | 70 | /** 71 | * @return The Throwable giving rise to this PublicationError. 72 | */ 73 | public 74 | Throwable getCause() { 75 | return this.cause; 76 | } 77 | 78 | /** 79 | * Assigns the cause of this PublicationError. 80 | * 81 | * @param cause A Throwable which gave rise to this PublicationError. 82 | * @return This PublicationError. 83 | */ 84 | public 85 | PublicationError setCause(Throwable cause) { 86 | this.cause = cause; 87 | return this; 88 | } 89 | 90 | public 91 | String getMessage() { 92 | return this.message; 93 | } 94 | 95 | public 96 | PublicationError setMessage(String message) { 97 | this.message = message; 98 | return this; 99 | } 100 | 101 | public 102 | Object[] getPublishedObject() { 103 | return this.publishedObjects; 104 | } 105 | 106 | public 107 | PublicationError setNoPublishedObject() { 108 | this.publishedObjects = new Object[0]; 109 | 110 | return this; 111 | } 112 | 113 | public 114 | PublicationError setPublishedObject(Object publishedObject) { 115 | this.publishedObjects = new Object[1]; 116 | this.publishedObjects[0] = publishedObject; 117 | 118 | return this; 119 | } 120 | 121 | public 122 | PublicationError setPublishedObject(Object publishedObject1, Object publishedObject2) { 123 | this.publishedObjects = new Object[2]; 124 | this.publishedObjects[0] = publishedObject1; 125 | this.publishedObjects[1] = publishedObject2; 126 | 127 | return this; 128 | } 129 | 130 | public 131 | PublicationError setPublishedObject(Object publishedObject1, Object publishedObject2, Object publishedObject3) { 132 | this.publishedObjects = new Object[3]; 133 | this.publishedObjects[0] = publishedObject1; 134 | this.publishedObjects[1] = publishedObject2; 135 | this.publishedObjects[2] = publishedObject3; 136 | 137 | return this; 138 | } 139 | 140 | /** 141 | * {@inheritDoc} 142 | */ 143 | @Override 144 | public 145 | String toString() { 146 | String newLine = System.getProperty("line.separator"); 147 | return "PublicationError{" + 148 | newLine + 149 | "\tcause=" + this.cause + 150 | newLine + 151 | "\tmessage='" + this.message + '\'' + 152 | newLine + 153 | "\tpublishedObject=" + Arrays.deepToString(this.publishedObjects) + 154 | '}'; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/publication/ConversantDisruptor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.publication; 17 | 18 | import java.lang.reflect.Method; 19 | import java.util.concurrent.ThreadPoolExecutor; 20 | import java.util.concurrent.TimeUnit; 21 | 22 | import com.conversantmedia.util.concurrent.DisruptorBlockingQueue; 23 | import com.conversantmedia.util.concurrent.SpinPolicy; 24 | import com.esotericsoftware.reflectasm.MethodAccess; 25 | 26 | import dorkbox.messageBus.error.ErrorHandler; 27 | import dorkbox.messageBus.subscription.asm.AsmInvocation; 28 | import dorkbox.messageBus.subscription.reflection.ReflectionInvocation; 29 | import dorkbox.util.NamedThreadFactory; 30 | 31 | public 32 | class ConversantDisruptor implements Publisher { 33 | 34 | private final Publisher syncPublisher; 35 | private final ThreadPoolExecutor threadExecutor; 36 | private final DisruptorBlockingQueue workQueue; 37 | 38 | public 39 | ConversantDisruptor(final int numberOfThreads) { 40 | this.syncPublisher = new DirectInvocation(); 41 | 42 | // ALWAYS round to the nearest power of 2 43 | int minQueueCapacity = 1 << (32 - Integer.numberOfLeadingZeros(numberOfThreads)); 44 | 45 | workQueue = new DisruptorBlockingQueue<>(minQueueCapacity, SpinPolicy.WAITING); 46 | threadExecutor = new ThreadPoolExecutor(numberOfThreads, numberOfThreads, 47 | 0L, TimeUnit.MILLISECONDS, workQueue, 48 | new NamedThreadFactory("MessageBus", true)); 49 | } 50 | 51 | public 52 | ConversantDisruptor(final ConversantDisruptor publisher) { 53 | this.syncPublisher = publisher.syncPublisher; 54 | this.threadExecutor = publisher.threadExecutor; 55 | this.workQueue = publisher.workQueue; 56 | } 57 | 58 | 59 | // ASM 60 | @Override 61 | public 62 | void publish(final ErrorHandler errorHandler, 63 | final AsmInvocation invocation, final Object listener, final MethodAccess handler, final int handleIndex, 64 | final Object message) { 65 | threadExecutor.submit(new Runnable() { 66 | @Override 67 | public 68 | void run() { 69 | syncPublisher.publish(errorHandler,invocation, listener, handler, handleIndex, message); 70 | } 71 | }); 72 | } 73 | 74 | @Override 75 | public 76 | void publish(final ErrorHandler errorHandler, 77 | final AsmInvocation invocation, final Object listener, final MethodAccess handler, final int handleIndex, 78 | final Object message1, 79 | final Object message2) { 80 | 81 | threadExecutor.submit(new Runnable() { 82 | @Override 83 | public 84 | void run() { 85 | syncPublisher.publish(errorHandler,invocation, listener, handler, handleIndex, message1, message2); 86 | } 87 | }); 88 | } 89 | 90 | @Override 91 | public 92 | void publish(final ErrorHandler errorHandler, 93 | final AsmInvocation invocation, final Object listener, final MethodAccess handler, final int handleIndex, 94 | final Object message1, final Object message2, final Object message3) { 95 | 96 | threadExecutor.submit(new Runnable() { 97 | @Override 98 | public 99 | void run() { 100 | syncPublisher.publish(errorHandler,invocation, listener, handler, handleIndex, message1, message2, message3); 101 | } 102 | }); 103 | } 104 | 105 | 106 | 107 | // REFLECTION 108 | @Override 109 | public 110 | void publish(final ErrorHandler errorHandler, 111 | final ReflectionInvocation invocation, final Object listener, final Method method, 112 | final Object message) { 113 | 114 | threadExecutor.submit(new Runnable() { 115 | @Override 116 | public 117 | void run() { 118 | syncPublisher.publish(errorHandler,invocation, listener, method, message); 119 | } 120 | }); 121 | } 122 | 123 | @Override 124 | public 125 | void publish(final ErrorHandler errorHandler, 126 | final ReflectionInvocation invocation, final Object listener, final Method method, 127 | final Object message1, final Object message2) { 128 | 129 | threadExecutor.submit(new Runnable() { 130 | @Override 131 | public 132 | void run() { 133 | syncPublisher.publish(errorHandler,invocation, listener, method, message1, message2); 134 | } 135 | }); 136 | } 137 | 138 | @Override 139 | public 140 | void publish(final ErrorHandler errorHandler, 141 | final ReflectionInvocation invocation, final Object listener, final Method method, 142 | final Object message1, final Object message2, final Object message3) { 143 | 144 | threadExecutor.submit(new Runnable() { 145 | @Override 146 | public 147 | void run() { 148 | syncPublisher.publish(errorHandler,invocation, listener, method, message1, message2, message3); 149 | } 150 | }); 151 | } 152 | 153 | @Override 154 | public 155 | boolean hasPendingMessages() { 156 | return threadExecutor.getActiveCount() > 0 || workQueue.isEmpty(); 157 | } 158 | 159 | @Override 160 | public 161 | void shutdown() { 162 | // This uses Thread.interrupt() 163 | threadExecutor.shutdownNow(); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/publication/DirectInvocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.publication; 17 | 18 | import java.lang.reflect.Method; 19 | 20 | import com.esotericsoftware.reflectasm.MethodAccess; 21 | 22 | import dorkbox.messageBus.error.ErrorHandler; 23 | import dorkbox.messageBus.error.PublicationError; 24 | import dorkbox.messageBus.subscription.asm.AsmInvocation; 25 | import dorkbox.messageBus.subscription.reflection.ReflectionInvocation; 26 | 27 | public 28 | class DirectInvocation implements Publisher { 29 | 30 | public 31 | DirectInvocation() { 32 | } 33 | 34 | // ASM 35 | @Override 36 | public 37 | void publish(final ErrorHandler errorHandler, 38 | final AsmInvocation invocation, final Object listener, final MethodAccess handler, final int handleIndex, 39 | final Object message) { 40 | try { 41 | invocation.invoke(listener, handler, handleIndex, message); 42 | } catch (Throwable e) { 43 | errorHandler.handlePublicationError(new PublicationError().setMessage("Error during publication of message.") 44 | .setCause(e) 45 | .setPublishedObject(message)); 46 | } 47 | } 48 | 49 | @Override 50 | public 51 | void publish(final ErrorHandler errorHandler, 52 | final AsmInvocation invocation, final Object listener, final MethodAccess handler, final int handleIndex, 53 | final Object message1, 54 | final Object message2) { 55 | 56 | try { 57 | invocation.invoke(listener, handler, handleIndex, message1, message2); 58 | } catch (Throwable e) { 59 | errorHandler.handlePublicationError(new PublicationError().setMessage("Error during publication of message.") 60 | .setCause(e) 61 | .setPublishedObject(message1, message2)); 62 | } 63 | 64 | } 65 | 66 | @Override 67 | public 68 | void publish(final ErrorHandler errorHandler, 69 | final AsmInvocation invocation, final Object listener, final MethodAccess handler, final int handleIndex, 70 | final Object message1, final Object message2, final Object message3) { 71 | 72 | 73 | try { 74 | invocation.invoke(listener, handler, handleIndex, message1, message2, message3); 75 | } catch (Throwable e) { 76 | errorHandler.handlePublicationError(new PublicationError().setMessage("Error during publication of message.") 77 | .setCause(e) 78 | .setPublishedObject(message1, message2, message3)); 79 | } 80 | } 81 | 82 | 83 | 84 | // REFLECTION 85 | @Override 86 | public 87 | void publish(final ErrorHandler errorHandler, 88 | final ReflectionInvocation invocation, final Object listener, final Method method, 89 | final Object message) { 90 | 91 | try { 92 | invocation.invoke(listener, method, message); 93 | } catch (Throwable e) { 94 | errorHandler.handlePublicationError(new PublicationError().setMessage("Error during publication of message.") 95 | .setCause(e) 96 | .setPublishedObject(message)); 97 | } 98 | } 99 | 100 | @Override 101 | public 102 | void publish(final ErrorHandler errorHandler, 103 | final ReflectionInvocation invocation, final Object listener, final Method method, 104 | final Object message1, final Object message2) { 105 | 106 | try { 107 | invocation.invoke(listener, method, message1, message2); 108 | } catch (Throwable e) { 109 | errorHandler.handlePublicationError(new PublicationError().setMessage("Error during publication of message.") 110 | .setCause(e) 111 | .setPublishedObject(message1, message2)); 112 | } 113 | } 114 | 115 | @Override 116 | public 117 | void publish(final ErrorHandler errorHandler, 118 | final ReflectionInvocation invocation, final Object listener, final Method method, 119 | final Object message1, final Object message2, final Object message3) { 120 | 121 | try { 122 | invocation.invoke(listener, method, message1, message2, message3); 123 | } catch (Throwable e) { 124 | errorHandler.handlePublicationError(new PublicationError().setMessage("Error during publication of message.") 125 | .setCause(e) 126 | .setPublishedObject(message1, message2, message3)); 127 | } 128 | } 129 | 130 | 131 | public 132 | boolean hasPendingMessages() { 133 | return false; 134 | } 135 | 136 | @Override 137 | public 138 | void shutdown() { 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/publication/Publisher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.publication; 17 | 18 | import java.lang.reflect.Method; 19 | 20 | import com.esotericsoftware.reflectasm.MethodAccess; 21 | 22 | import dorkbox.messageBus.error.ErrorHandler; 23 | import dorkbox.messageBus.subscription.asm.AsmInvocation; 24 | import dorkbox.messageBus.subscription.reflection.ReflectionInvocation; 25 | 26 | public 27 | interface Publisher { 28 | // ASM 29 | void publish(final ErrorHandler errorHandler, 30 | final AsmInvocation invocation, final Object listener, final MethodAccess handler, final int handleIndex, 31 | final Object message); 32 | 33 | void publish(final ErrorHandler errorHandler, 34 | final AsmInvocation invocation, final Object listener, final MethodAccess handler, final int handleIndex, 35 | final Object message1, 36 | final Object message2); 37 | 38 | void publish(final ErrorHandler errorHandler, 39 | final AsmInvocation invocation, final Object listener, final MethodAccess handler, final int handleIndex, 40 | final Object message1, final Object message2, final Object message3); 41 | 42 | // REFLECTION 43 | void publish(final ErrorHandler errorHandler, 44 | final ReflectionInvocation invocation, final Object listener, final Method method, 45 | final Object message); 46 | 47 | void publish(final ErrorHandler errorHandler, 48 | final ReflectionInvocation invocation, final Object listener, final Method method, 49 | final Object message1, final Object message2); 50 | 51 | void publish(final ErrorHandler errorHandler, 52 | final ReflectionInvocation invocation, final Object listener, final Method method, 53 | final Object message1, final Object message2, final Object message3); 54 | 55 | 56 | boolean hasPendingMessages(); 57 | void shutdown(); 58 | } 59 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/publication/disruptor/EventBusFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.publication.disruptor; 17 | 18 | import com.lmax.disruptor.EventFactory; 19 | 20 | /** 21 | * @author dorkbox, llc 22 | * Date: 2/2/15 23 | */ 24 | public class EventBusFactory implements EventFactory { 25 | 26 | public EventBusFactory() { 27 | } 28 | 29 | @Override 30 | public 31 | MessageHolder newInstance() { 32 | return new MessageHolder(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/publication/disruptor/MessageHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.publication.disruptor; 17 | 18 | import java.util.concurrent.atomic.AtomicBoolean; 19 | 20 | import com.lmax.disruptor.LifecycleAware; 21 | import com.lmax.disruptor.WorkHandler; 22 | 23 | import dorkbox.messageBus.publication.Publisher; 24 | 25 | /** 26 | * @author dorkbox, llc Date: 2/2/15 27 | */ 28 | public 29 | class MessageHandler implements WorkHandler, LifecycleAware { 30 | 31 | private final AtomicBoolean shutdown = new AtomicBoolean(false); 32 | private final Publisher syncPublisher; 33 | 34 | public 35 | MessageHandler(final Publisher syncPublisher) { 36 | this.syncPublisher = syncPublisher; 37 | } 38 | 39 | @Override 40 | public 41 | void onEvent(final MessageHolder event) throws Exception { 42 | switch (event.type) { 43 | // ASM INVOCATION 44 | case MessageType.ASM_ONE: 45 | // this is by far the most common case. 46 | syncPublisher.publish(event.errorHandler, event.asmInvocation, event.listener, event.handler, event.handleIndex, event.message1); 47 | event.clear(); 48 | return; 49 | case MessageType.ASM_TWO: 50 | syncPublisher.publish(event.errorHandler, event.asmInvocation, event.listener, event.handler, event.handleIndex, event.message1, event.message2); 51 | event.clear(); 52 | return; 53 | case MessageType.ASM_THREE: 54 | syncPublisher.publish(event.errorHandler, event.asmInvocation, event.listener, event.handler, event.handleIndex, event.message1, event.message2, event.message3); 55 | event.clear(); 56 | return; 57 | 58 | // REFLECT INVOCATION 59 | case MessageType.REFLECT_ONE: 60 | syncPublisher.publish(event.errorHandler, event.reflectionInvocation, event.listener, event.method, event.message1); 61 | event.clear(); 62 | return; 63 | case MessageType.REFLECT_TWO: 64 | syncPublisher.publish(event.errorHandler, event.reflectionInvocation, event.listener, event.method, event.message1, event.message2); 65 | event.clear(); 66 | return; 67 | case MessageType.REFLECT_THREE: 68 | syncPublisher.publish(event.errorHandler, event.reflectionInvocation, event.listener, event.method, event.message1, event.message2, event.message3); 69 | event.clear(); 70 | //noinspection UnnecessaryReturnStatement 71 | return; 72 | } 73 | } 74 | 75 | @Override 76 | public 77 | void onStart() { 78 | } 79 | 80 | @Override 81 | public synchronized 82 | void onShutdown() { 83 | shutdown.set(true); 84 | } 85 | 86 | public 87 | boolean isShutdown() { 88 | return shutdown.get(); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/publication/disruptor/MessageHolder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.publication.disruptor; 17 | 18 | import java.lang.reflect.Method; 19 | 20 | import com.esotericsoftware.reflectasm.MethodAccess; 21 | 22 | import dorkbox.messageBus.error.ErrorHandler; 23 | import dorkbox.messageBus.subscription.asm.AsmInvocation; 24 | import dorkbox.messageBus.subscription.reflection.ReflectionInvocation; 25 | 26 | /** 27 | * @author dorkbox, llc Date: 2/2/15 28 | */ 29 | public 30 | class MessageHolder { 31 | public int type = MessageType.ASM_ONE; 32 | 33 | public Object message1 = null; 34 | public Object message2 = null; 35 | public Object message3 = null; 36 | 37 | public ErrorHandler errorHandler = null; 38 | 39 | public AsmInvocation asmInvocation = null; 40 | public ReflectionInvocation reflectionInvocation = null; 41 | public Object listener = null; 42 | public Method method = null; 43 | public MethodAccess handler = null; 44 | public int handleIndex = 0; 45 | 46 | public 47 | MessageHolder() {} 48 | 49 | /** 50 | * Make sure objects do not live longer than they are supposed to 51 | */ 52 | public 53 | void clear() { 54 | type = MessageType.ASM_ONE; 55 | 56 | message1 = null; 57 | message2 = null; 58 | message3 = null; 59 | 60 | errorHandler = null; 61 | asmInvocation = null; 62 | reflectionInvocation = null; 63 | listener = null; 64 | method = null; 65 | 66 | handler = null; 67 | handleIndex = 0; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/publication/disruptor/MessageType.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.publication.disruptor; 17 | 18 | /** 19 | * @author dorkbox, llc Date: 2/2/15 20 | */ 21 | public final class MessageType { 22 | public static final int ASM_ONE = 1; 23 | public static final int REFLECT_ONE = 2; 24 | 25 | public static final int ASM_TWO = 3; 26 | public static final int REFLECT_TWO = 4; 27 | 28 | public static final int ASM_THREE = 5; 29 | public static final int REFLECT_THREE = 6; 30 | 31 | private MessageType() { 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/publication/disruptor/PublicationExceptionHandler.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.publication.disruptor; 17 | 18 | import com.lmax.disruptor.ExceptionHandler; 19 | 20 | import dorkbox.messageBus.error.ErrorHandler; 21 | import dorkbox.messageBus.error.PublicationError; 22 | 23 | /** 24 | * @author dorkbox, llc Date: 2/3/16 25 | */ 26 | public final class PublicationExceptionHandler implements ExceptionHandler { 27 | private final ErrorHandler errorHandler; 28 | 29 | public PublicationExceptionHandler(ErrorHandler errorHandler) { 30 | this.errorHandler = errorHandler; 31 | } 32 | 33 | @Override 34 | public void handleEventException(final Throwable e, final long sequence, final T event) { 35 | this.errorHandler.handlePublicationError(new PublicationError() 36 | .setMessage("Exception on lmax disruptor processing: " + sequence + " " + event.getClass() + "(" + event + ")") 37 | .setCause(e)); 38 | } 39 | 40 | @Override 41 | public void handleOnStartException(final Throwable e) { 42 | this.errorHandler.handlePublicationError(new PublicationError() 43 | .setMessage("Error starting the lmax disruptor") 44 | .setCause(e)); 45 | } 46 | 47 | @Override 48 | public void handleOnShutdownException(final Throwable e) { 49 | this.errorHandler.handlePublicationError(new PublicationError() 50 | .setMessage("Error stopping the lmax disruptor") 51 | .setCause(e)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/subscription/Entry.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.subscription; 17 | 18 | // 19 | // not thread-safe!!! 20 | // 21 | 22 | 23 | /** 24 | * @author bennidi 25 | * @author dorkbox, llc Date: 2/3/16 26 | */ 27 | public 28 | class Entry { 29 | private final T value; 30 | 31 | private Entry next; 32 | private Entry prev; 33 | 34 | public 35 | Entry(T value, Entry next) { 36 | if (next != null) { 37 | this.next = next; 38 | next.prev = this; 39 | } 40 | 41 | this.value = value; 42 | } 43 | 44 | public 45 | void remove() { 46 | if (this.prev != null) { 47 | this.prev.next = this.next; 48 | if (this.next != null) { 49 | this.next.prev = this.prev; 50 | } 51 | } 52 | else if (this.next != null) { 53 | this.next.prev = null; 54 | } 55 | 56 | // can not nullify references to help GC since running iterators might not see the entire set 57 | // if this element is their current element 58 | //next = null; 59 | //predecessor = null; 60 | } 61 | 62 | public 63 | Entry next() { 64 | return this.next; 65 | } 66 | 67 | public 68 | void clear() { 69 | this.next = null; 70 | } 71 | 72 | 73 | public 74 | T getValue() { 75 | return value; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/subscription/SubscriptionFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.subscription; 17 | 18 | import dorkbox.messageBus.common.MessageHandler; 19 | 20 | /** 21 | * @author dorkbox, llc Date: 2/3/16 22 | */ 23 | public 24 | interface SubscriptionFactory { 25 | Subscription create(final Class listenerClass, final MessageHandler handler); 26 | } 27 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/subscription/asm/AsmFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.subscription.asm; 17 | 18 | import dorkbox.messageBus.common.MessageHandler; 19 | import dorkbox.messageBus.subscription.Subscription; 20 | import dorkbox.messageBus.subscription.SubscriptionFactory; 21 | 22 | /** 23 | * @author dorkbox, llc Date: 2/3/16 24 | */ 25 | public 26 | class AsmFactory implements SubscriptionFactory { 27 | 28 | private final boolean useStrongReferencesByDefault; 29 | 30 | public 31 | AsmFactory(final boolean useStrongReferencesByDefault) { 32 | this.useStrongReferencesByDefault = useStrongReferencesByDefault; 33 | } 34 | 35 | @Override 36 | public 37 | Subscription create(final Class listenerClass, final MessageHandler handler) { 38 | // figure out what kind of references we want to use by default, as specified by MessageBus.useStrongReferencesByDefault 39 | final int referenceType = handler.getReferenceType(); 40 | if (referenceType == MessageHandler.UNDEFINED) { 41 | if (useStrongReferencesByDefault) { 42 | return new SubscriptionAsmStrong(listenerClass, handler); 43 | } 44 | else { 45 | return new SubscriptionAsmWeak(listenerClass, handler); 46 | } 47 | } 48 | else if (referenceType == MessageHandler.WEAK) { 49 | return new SubscriptionAsmWeak(listenerClass, handler); 50 | } 51 | else { 52 | return new SubscriptionAsmStrong(listenerClass, handler); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/subscription/asm/AsmInvocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | * 24 | * Copyright 2015 dorkbox, llc 25 | * 26 | * Licensed under the Apache License, Version 2.0 (the "License"); 27 | * you may not use this file except in compliance with the License. 28 | * You may obtain a copy of the License at 29 | * 30 | * http://www.apache.org/licenses/LICENSE-2.0 31 | * 32 | * Unless required by applicable law or agreed to in writing, software 33 | * distributed under the License is distributed on an "AS IS" BASIS, 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | * See the License for the specific language governing permissions and 36 | * limitations under the License. 37 | */ 38 | package dorkbox.messageBus.subscription.asm; 39 | 40 | import com.esotericsoftware.reflectasm.MethodAccess; 41 | 42 | /** 43 | * A handler invocation encapsulates the logic that is used to invoke a single 44 | * message handler to process a given message. 45 | * 46 | * A handler invocation might come in different flavours and can be composed 47 | * of various independent invocations by means of delegation (-> decorator pattern) 48 | * 49 | * If an exception is thrown during handler invocation it is wrapped and propagated 50 | * as a publication error 51 | * 52 | * @author bennidi 53 | * Date: 11/23/12 54 | * @author dorkbox, llc 55 | * Date: 2/2/15 56 | */ 57 | public 58 | interface AsmInvocation { 59 | 60 | /** 61 | * Invoke the message delivery logic of this handler 62 | * 63 | * @param listener The listener that will receive the message. This can be a reference to a method object 64 | * from the java reflection api or any other wrapper that can be used to invoke the handler 65 | * @param message The message to be delivered to the handler. This can be any object compatible with the object 66 | * type that the handler consumes 67 | * @param handler The handler (method) that will be called via reflection 68 | */ 69 | void invoke(Object listener, MethodAccess handler, int methodIndex, Object message) throws Throwable; 70 | 71 | /** 72 | * Invoke the message delivery logic of this handler 73 | * 74 | * @param listener The listener that will receive the message. This can be a reference to a method object 75 | * from the java reflection api or any other wrapper that can be used to invoke the handler 76 | * @param message1 The message to be delivered to the handler. This can be any object compatible with the object 77 | * type that the handler consumes 78 | * @param handler The handler (method) that will be called via reflection 79 | */ 80 | void invoke(Object listener, MethodAccess handler, int methodIndex, Object message1, Object message2) throws Throwable; 81 | 82 | /** 83 | * Invoke the message delivery logic of this handler 84 | * 85 | * @param listener The listener that will receive the message. This can be a reference to a method object 86 | * from the java reflection api or any other wrapper that can be used to invoke the handler 87 | * @param message1 The message to be delivered to the handler. This can be any object compatible with the object 88 | * type that the handler consumes 89 | * @param handler The handler (method) that will be called via reflection 90 | */ 91 | void invoke(Object listener, MethodAccess handler, int methodIndex, Object message1, Object message2, Object message3) throws Throwable; 92 | } 93 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/subscription/asm/AsmReflectiveInvocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | * 24 | * Copyright 2015 dorkbox, llc 25 | * 26 | * Licensed under the Apache License, Version 2.0 (the "License"); 27 | * you may not use this file except in compliance with the License. 28 | * You may obtain a copy of the License at 29 | * 30 | * http://www.apache.org/licenses/LICENSE-2.0 31 | * 32 | * Unless required by applicable law or agreed to in writing, software 33 | * distributed under the License is distributed on an "AS IS" BASIS, 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | * See the License for the specific language governing permissions and 36 | * limitations under the License. 37 | */ 38 | package dorkbox.messageBus.subscription.asm; 39 | 40 | import com.esotericsoftware.reflectasm.MethodAccess; 41 | 42 | /** 43 | * Uses reflection to invoke a message handler for a given message. 44 | * 45 | * @author bennidi 46 | * Date: 11/23/12 47 | * @author dorkbox, llc 48 | * Date: 2/2/15 49 | */ 50 | public 51 | class AsmReflectiveInvocation implements AsmInvocation { 52 | 53 | public 54 | AsmReflectiveInvocation() { 55 | super(); 56 | } 57 | 58 | @Override 59 | public 60 | void invoke(final Object listener, final MethodAccess handler, final int methodIndex, final Object message) throws Throwable { 61 | handler.invoke(listener, methodIndex, message); 62 | } 63 | 64 | @Override 65 | public 66 | void invoke(final Object listener, final MethodAccess handler, final int methodIndex, final Object message1, final Object message2) throws Throwable { 67 | handler.invoke(listener, methodIndex, message1, message2); 68 | } 69 | 70 | @Override 71 | public 72 | void invoke(final Object listener, final MethodAccess handler, final int methodIndex, final Object message1, final Object message2, final Object message3) throws Throwable { 73 | handler.invoke(listener, methodIndex, message1, message2, message3); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/subscription/asm/AsmSynchronizedInvocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | * 24 | * Copyright 2015 dorkbox, llc 25 | * 26 | * Licensed under the Apache License, Version 2.0 (the "License"); 27 | * you may not use this file except in compliance with the License. 28 | * You may obtain a copy of the License at 29 | * 30 | * http://www.apache.org/licenses/LICENSE-2.0 31 | * 32 | * Unless required by applicable law or agreed to in writing, software 33 | * distributed under the License is distributed on an "AS IS" BASIS, 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | * See the License for the specific language governing permissions and 36 | * limitations under the License. 37 | */ 38 | package dorkbox.messageBus.subscription.asm; 39 | 40 | import com.esotericsoftware.reflectasm.MethodAccess; 41 | 42 | /** 43 | * Synchronizes message handler invocations for all handlers that specify @Synchronized 44 | * 45 | * @author bennidi 46 | * Date: 3/31/13 47 | * @author dorkbox, llc 48 | * Date: 2/2/15 49 | */ 50 | public 51 | class AsmSynchronizedInvocation implements AsmInvocation { 52 | 53 | private final AsmInvocation delegate; 54 | 55 | public 56 | AsmSynchronizedInvocation(AsmInvocation delegate) { 57 | this.delegate = delegate; 58 | } 59 | 60 | @Override 61 | public 62 | void invoke(final Object listener, final MethodAccess handler, final int methodIndex, final Object message) throws Throwable { 63 | synchronized (listener) { 64 | this.delegate.invoke(listener, handler, methodIndex, message); 65 | } 66 | } 67 | 68 | @Override 69 | public 70 | void invoke(final Object listener, final MethodAccess handler, int methodIndex, final Object message1, final Object message2) throws Throwable { 71 | synchronized (listener) { 72 | this.delegate.invoke(listener, handler, methodIndex, message1, message2); 73 | } 74 | } 75 | 76 | @Override 77 | public 78 | void invoke(final Object listener, final MethodAccess handler, final int methodIndex, final Object message1, final Object message2, final Object message3) throws Throwable { 79 | synchronized (listener) { 80 | this.delegate.invoke(listener, handler, methodIndex, message1, message2, message3); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/subscription/asm/SubscriptionAsmStrong.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | * 24 | * Copyright 2015 dorkbox, llc 25 | * 26 | * Licensed under the Apache License, Version 2.0 (the "License"); 27 | * you may not use this file except in compliance with the License. 28 | * You may obtain a copy of the License at 29 | * 30 | * http://www.apache.org/licenses/LICENSE-2.0 31 | * 32 | * Unless required by applicable law or agreed to in writing, software 33 | * distributed under the License is distributed on an "AS IS" BASIS, 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | * See the License for the specific language governing permissions and 36 | * limitations under the License. 37 | */ 38 | package dorkbox.messageBus.subscription.asm; 39 | 40 | import java.lang.reflect.Method; 41 | 42 | import com.esotericsoftware.reflectasm.MethodAccess; 43 | 44 | import dorkbox.messageBus.common.MessageHandler; 45 | import dorkbox.messageBus.error.ErrorHandler; 46 | import dorkbox.messageBus.subscription.Entry; 47 | import dorkbox.messageBus.publication.Publisher; 48 | import dorkbox.messageBus.subscription.Subscription; 49 | 50 | /** 51 | * A subscription is a container that manages exactly one message handler of all registered 52 | * message listeners of the same class, i.e. all subscribed instances (excluding subclasses) of a message 53 | * will be referenced in the subscription created for a message. 54 | *

55 | * There will be as many unique subscription objects per message listener class as there are message handlers 56 | * defined in the message listeners class hierarchy. 57 | *

58 | * This class uses the "single writer principle", so that the subscription are only MODIFIED by a single thread, 59 | * but are READ by X number of threads (in a safe way). This uses object thread visibility/publication to work. 60 | * 61 | * @author bennidi 62 | * @author dorkbox, llc 63 | * Date: 2/2/15 64 | */ 65 | @SuppressWarnings("Duplicates") 66 | final 67 | class SubscriptionAsmStrong extends Subscription { 68 | private final AsmInvocation invocation; 69 | 70 | private final MethodAccess handlerAccess; 71 | private final int methodIndex; 72 | 73 | public 74 | SubscriptionAsmStrong(final Class listenerClass, final MessageHandler handler) { 75 | // we use ASM here 76 | super(listenerClass, handler); 77 | 78 | AsmInvocation invocation = new AsmReflectiveInvocation(); 79 | if (handler.isSynchronized()) { 80 | invocation = new AsmSynchronizedInvocation(invocation); 81 | } 82 | 83 | this.invocation = invocation; 84 | 85 | // we use ASM here 86 | Method method = handler.getMethod(); 87 | this.handlerAccess = MethodAccess.get(method.getDeclaringClass()); 88 | this.methodIndex = this.handlerAccess.getIndex(method.getName(), handler.getHandledMessages()); 89 | } 90 | 91 | @Override 92 | public 93 | Entry createEntry(final Object listener, final Entry head) { 94 | return new Entry(listener, head); 95 | } 96 | 97 | @Override 98 | public 99 | boolean publish(final Publisher publisher, final ErrorHandler errorHandler, 100 | final Object message) { 101 | 102 | final MethodAccess handler = this.handlerAccess; 103 | final int handleIndex = this.methodIndex; 104 | final AsmInvocation invocation = this.invocation; 105 | 106 | Entry head = headREF.get(this); 107 | Entry current = head; 108 | Object listener; 109 | while (current != null) { 110 | listener = current.getValue(); 111 | current = current.next(); 112 | 113 | publisher.publish(errorHandler, invocation, listener, handler, handleIndex, message); 114 | } 115 | 116 | return head != null; // true if we have something to publish to, otherwise false 117 | } 118 | 119 | @Override 120 | public 121 | boolean publish(final Publisher publisher, final ErrorHandler errorHandler, 122 | final Object message1, final Object message2) { 123 | 124 | final MethodAccess handler = this.handlerAccess; 125 | final int handleIndex = this.methodIndex; 126 | final AsmInvocation invocation = this.invocation; 127 | 128 | Entry head = headREF.get(this); 129 | Entry current = head; 130 | Object listener; 131 | while (current != null) { 132 | listener = current.getValue(); 133 | current = current.next(); 134 | 135 | publisher.publish(errorHandler, invocation, listener, handler, handleIndex, message1, message2); 136 | } 137 | 138 | return head != null; // true if we have something to publish to, otherwise false 139 | } 140 | 141 | @Override 142 | public 143 | boolean publish(final Publisher publisher, final ErrorHandler errorHandler, 144 | final Object message1, final Object message2, final Object message3) { 145 | 146 | final MethodAccess handler = this.handlerAccess; 147 | final int handleIndex = this.methodIndex; 148 | final AsmInvocation invocation = this.invocation; 149 | 150 | Entry head = headREF.get(this); 151 | Entry current = head; 152 | Object listener; 153 | while (current != null) { 154 | listener = current.getValue(); 155 | current = current.next(); 156 | 157 | publisher.publish(errorHandler, invocation, listener, handler, handleIndex, message1, message2, message3); 158 | } 159 | 160 | return head != null; // true if we have something to publish to, otherwise false 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/subscription/reflection/ReflectionFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messageBus.subscription.reflection; 17 | 18 | import dorkbox.messageBus.common.MessageHandler; 19 | import dorkbox.messageBus.subscription.Subscription; 20 | import dorkbox.messageBus.subscription.SubscriptionFactory; 21 | 22 | /** 23 | * @author dorkbox, llc 24 | * Date: 2/3/16 25 | */ 26 | public 27 | class ReflectionFactory implements SubscriptionFactory { 28 | 29 | private final boolean useStrongReferencesByDefault; 30 | 31 | public 32 | ReflectionFactory(final boolean useStrongReferencesByDefault) { 33 | this.useStrongReferencesByDefault = useStrongReferencesByDefault; 34 | } 35 | 36 | @Override 37 | public 38 | Subscription create(final Class listenerClass, final MessageHandler handler) { 39 | // figure out what kind of references we want to use by default, as specified by MessageBus.useStrongReferencesByDefault 40 | final int referenceType = handler.getReferenceType(); 41 | if (referenceType == MessageHandler.UNDEFINED) { 42 | if (useStrongReferencesByDefault) { 43 | return new SubscriptionReflectionStrong(listenerClass, handler); 44 | } 45 | else { 46 | return new SubscriptionReflectionWeak(listenerClass, handler); 47 | } 48 | } 49 | else if (referenceType == MessageHandler.WEAK) { 50 | return new SubscriptionReflectionWeak(listenerClass, handler); 51 | } 52 | else { 53 | return new SubscriptionReflectionStrong(listenerClass, handler); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/subscription/reflection/ReflectionInvocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | * 24 | * Copyright 2015 dorkbox, llc 25 | * 26 | * Licensed under the Apache License, Version 2.0 (the "License"); 27 | * you may not use this file except in compliance with the License. 28 | * You may obtain a copy of the License at 29 | * 30 | * http://www.apache.org/licenses/LICENSE-2.0 31 | * 32 | * Unless required by applicable law or agreed to in writing, software 33 | * distributed under the License is distributed on an "AS IS" BASIS, 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | * See the License for the specific language governing permissions and 36 | * limitations under the License. 37 | */ 38 | package dorkbox.messageBus.subscription.reflection; 39 | 40 | import java.lang.reflect.Method; 41 | 42 | /** 43 | * A handler invocation encapsulates the logic that is used to invoke a single 44 | * message handler to process a given message. 45 | * 46 | * A handler invocation might come in different flavours and can be composed 47 | * of various independent invocations by means of delegation (-> decorator pattern) 48 | * 49 | * If an exception is thrown during handler invocation it is wrapped and propagated 50 | * as a publication error 51 | * 52 | * @author bennidi 53 | * Date: 11/23/12 54 | * @author dorkbox, llc 55 | * Date: 2/2/15 56 | */ 57 | public 58 | interface ReflectionInvocation { 59 | 60 | /** 61 | * Invoke the message delivery logic of this handler 62 | * 63 | * @param listener The listener that will receive the message. This can be a reference to a method object 64 | * from the java reflection api or any other wrapper that can be used to invoke the handler 65 | * @param message The message to be delivered to the handler. This can be any object compatible with the object 66 | * type that the handler consumes 67 | * @param handler The handler (method) that will be called via reflection 68 | */ 69 | void invoke(Object listener, Method handler, Object message) throws Throwable; 70 | 71 | /** 72 | * Invoke the message delivery logic of this handler 73 | * 74 | * @param listener The listener that will receive the message. This can be a reference to a method object 75 | * from the java reflection api or any other wrapper that can be used to invoke the handler 76 | * @param message1 The message to be delivered to the handler. This can be any object compatible with the object 77 | * type that the handler consumes 78 | * @param handler The handler (method) that will be called via reflection 79 | */ 80 | void invoke(Object listener, Method handler, Object message1, Object message2) throws Throwable; 81 | 82 | /** 83 | * Invoke the message delivery logic of this handler 84 | * 85 | * @param listener The listener that will receive the message. This can be a reference to a method object 86 | * from the java reflection api or any other wrapper that can be used to invoke the handler 87 | * @param message1 The message to be delivered to the handler. This can be any object compatible with the object 88 | * type that the handler consumes 89 | * @param handler The handler (method) that will be called via reflection 90 | */ 91 | void invoke(Object listener, Method handler, Object message1, Object message2, Object message3) throws Throwable; 92 | } 93 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/subscription/reflection/ReflectionReflectiveInvocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | * 24 | * Copyright 2015 dorkbox, llc 25 | * 26 | * Licensed under the Apache License, Version 2.0 (the "License"); 27 | * you may not use this file except in compliance with the License. 28 | * You may obtain a copy of the License at 29 | * 30 | * http://www.apache.org/licenses/LICENSE-2.0 31 | * 32 | * Unless required by applicable law or agreed to in writing, software 33 | * distributed under the License is distributed on an "AS IS" BASIS, 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | * See the License for the specific language governing permissions and 36 | * limitations under the License. 37 | */ 38 | package dorkbox.messageBus.subscription.reflection; 39 | 40 | import java.lang.reflect.Method; 41 | 42 | /** 43 | * Uses reflection to invoke a message handler for a given message. 44 | * 45 | * @author bennidi 46 | * Date: 11/23/12 47 | * @author dorkbox, llc 48 | * Date: 2/2/15 49 | */ 50 | public 51 | class ReflectionReflectiveInvocation implements ReflectionInvocation { 52 | 53 | public 54 | ReflectionReflectiveInvocation() { 55 | super(); 56 | } 57 | 58 | @Override 59 | public 60 | void invoke(final Object listener, final Method handler, final Object message) throws Throwable { 61 | handler.invoke(listener, message); 62 | } 63 | 64 | @Override 65 | public 66 | void invoke(final Object listener, final Method handler, final Object message1, final Object message2) throws Throwable { 67 | handler.invoke(listener, message1, message2); 68 | } 69 | 70 | @Override 71 | public 72 | void invoke(final Object listener, final Method handler, final Object message1, final Object message2, final Object message3) throws Throwable { 73 | handler.invoke(listener, message1, message2, message3); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/subscription/reflection/ReflectionSynchronizedInvocation.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | * 24 | * Copyright 2015 dorkbox, llc 25 | * 26 | * Licensed under the Apache License, Version 2.0 (the "License"); 27 | * you may not use this file except in compliance with the License. 28 | * You may obtain a copy of the License at 29 | * 30 | * http://www.apache.org/licenses/LICENSE-2.0 31 | * 32 | * Unless required by applicable law or agreed to in writing, software 33 | * distributed under the License is distributed on an "AS IS" BASIS, 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | * See the License for the specific language governing permissions and 36 | * limitations under the License. 37 | */ 38 | package dorkbox.messageBus.subscription.reflection; 39 | 40 | import java.lang.reflect.Method; 41 | 42 | /** 43 | * Synchronizes message handler invocations for all handlers that specify @Synchronized 44 | * 45 | * @author bennidi 46 | * Date: 3/31/13 47 | * @author dorkbox, llc 48 | * Date: 2/2/15 49 | */ 50 | public 51 | class ReflectionSynchronizedInvocation implements ReflectionInvocation { 52 | 53 | private final ReflectionInvocation delegate; 54 | 55 | public 56 | ReflectionSynchronizedInvocation(ReflectionInvocation delegate) { 57 | this.delegate = delegate; 58 | } 59 | 60 | @Override 61 | public 62 | void invoke(final Object listener, final Method handler, final Object message) throws Throwable { 63 | synchronized (listener) { 64 | this.delegate.invoke(listener, handler, message); 65 | } 66 | } 67 | 68 | @Override 69 | public 70 | void invoke(final Object listener, Method handler, final Object message1, final Object message2) throws Throwable { 71 | synchronized (listener) { 72 | this.delegate.invoke(listener, handler, message1, message2); 73 | } 74 | } 75 | 76 | @Override 77 | public 78 | void invoke(final Object listener, final Method handler, final Object message1, final Object message2, final Object message3) throws Throwable { 79 | synchronized (listener) { 80 | this.delegate.invoke(listener, handler, message1, message2, message3); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/dorkbox/messageBus/subscription/reflection/SubscriptionReflectionStrong.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | * 23 | * 24 | * Copyright 2015 dorkbox, llc 25 | * 26 | * Licensed under the Apache License, Version 2.0 (the "License"); 27 | * you may not use this file except in compliance with the License. 28 | * You may obtain a copy of the License at 29 | * 30 | * http://www.apache.org/licenses/LICENSE-2.0 31 | * 32 | * Unless required by applicable law or agreed to in writing, software 33 | * distributed under the License is distributed on an "AS IS" BASIS, 34 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 35 | * See the License for the specific language governing permissions and 36 | * limitations under the License. 37 | */ 38 | package dorkbox.messageBus.subscription.reflection; 39 | 40 | import java.lang.reflect.Method; 41 | 42 | import dorkbox.messageBus.common.MessageHandler; 43 | import dorkbox.messageBus.error.ErrorHandler; 44 | import dorkbox.messageBus.subscription.Entry; 45 | import dorkbox.messageBus.subscription.Subscription; 46 | import dorkbox.messageBus.publication.Publisher; 47 | 48 | /** 49 | * A subscription is a container that manages exactly one message handler of all registered 50 | * message listeners of the same class, i.e. all subscribed instances (excluding subclasses) of a message 51 | * will be referenced in the subscription created for a message. 52 | *

53 | * There will be as many unique subscription objects per message listener class as there are message handlers 54 | * defined in the message listeners class hierarchy. 55 | *

56 | * This class uses the "single writer principle", so that the subscription are only MODIFIED by a single thread, 57 | * but are READ by X number of threads (in a safe way). This uses object thread visibility/publication to work. 58 | * 59 | * @author bennidi 60 | * @author dorkbox, llc 61 | * Date: 2/2/15 62 | */ 63 | @SuppressWarnings("Duplicates") 64 | final 65 | class SubscriptionReflectionStrong extends Subscription { 66 | private final Method method; 67 | private final ReflectionInvocation invocation; 68 | 69 | public 70 | SubscriptionReflectionStrong(final Class listenerClass, final MessageHandler handler) { 71 | // we use "normal java" here 72 | super(listenerClass, handler); 73 | 74 | ReflectionInvocation invocation = new ReflectionReflectiveInvocation(); 75 | if (handler.isSynchronized()) { 76 | invocation = new ReflectionSynchronizedInvocation(invocation); 77 | } 78 | 79 | this.invocation = invocation; 80 | method = handler.getMethod(); 81 | } 82 | 83 | @Override 84 | public 85 | Entry createEntry(final Object listener, final Entry head) { 86 | return new Entry(listener, head); 87 | } 88 | 89 | @Override 90 | public 91 | boolean publish(final Publisher publisher, final ErrorHandler errorHandler, 92 | final Object message) { 93 | 94 | final Method method = this.method; 95 | final ReflectionInvocation invocation = this.invocation; 96 | 97 | Entry head = headREF.get(this); 98 | Entry current = head; 99 | Object listener; 100 | while (current != null) { 101 | listener = current.getValue(); 102 | current = current.next(); 103 | 104 | publisher.publish(errorHandler, invocation, listener, method, message); 105 | } 106 | 107 | return head != null; // true if we have something to publish to, otherwise false 108 | } 109 | 110 | @Override 111 | public 112 | boolean publish(final Publisher publisher, final ErrorHandler errorHandler, 113 | final Object message1, final Object message2) { 114 | 115 | final Method method = this.method; 116 | final ReflectionInvocation invocation = this.invocation; 117 | 118 | Entry head = headREF.get(this); 119 | Entry current = head; 120 | Object listener; 121 | while (current != null) { 122 | listener = current.getValue(); 123 | current = current.next(); 124 | 125 | publisher.publish(errorHandler, invocation, listener, method, message1, message2); 126 | } 127 | 128 | return head != null; // true if we have something to publish to, otherwise false 129 | } 130 | 131 | @Override 132 | public 133 | boolean publish(final Publisher publisher, final ErrorHandler errorHandler, 134 | final Object message1, final Object message2, final Object message3) { 135 | 136 | final Method method = this.method; 137 | final ReflectionInvocation invocation = this.invocation; 138 | 139 | Entry head = headREF.get(this); 140 | Entry current = head; 141 | Object listener; 142 | while (current != null) { 143 | listener = current.getValue(); 144 | current = current.next(); 145 | 146 | publisher.publish(errorHandler, invocation, listener, method, message1, message2, message3); 147 | } 148 | 149 | return head != null; // true if we have something to publish to, otherwise false 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src9/dorkbox/messageBus/EmptyClass.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2023 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package dorkbox.messageBus; 18 | 19 | /** 20 | * Required for intellij to not complain regarding `module-info` for a multi-release jar. 21 | * This file is completely ignored by the gradle build process 22 | */ 23 | public 24 | class EmptyClass {} 25 | -------------------------------------------------------------------------------- /src9/module-info.java: -------------------------------------------------------------------------------- 1 | module dorkbox.MessageBus { 2 | exports dorkbox.messageBus; 3 | 4 | requires transitive dorkbox.classUtils; 5 | requires transitive dorkbox.collections; 6 | requires transitive dorkbox.updates; 7 | requires transitive dorkbox.utilities; 8 | 9 | requires transitive com.conversantmedia.disruptor; 10 | requires transitive com.lmax.disruptor; 11 | requires transitive org.objectweb.asm; 12 | requires transitive com.esotericsoftware.reflectasm; 13 | 14 | requires transitive org.slf4j; 15 | 16 | requires transitive kotlin.stdlib; 17 | } 18 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/AllTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus; 24 | 25 | import org.junit.runner.RunWith; 26 | import org.junit.runners.Suite; 27 | 28 | /** 29 | * Test suite for running all available unit tests 30 | * 31 | * @author bennidi 32 | * Date: 11/23/12 33 | */ 34 | @RunWith(Suite.class) 35 | @Suite.SuiteClasses({ 36 | MBassadorTest.class, 37 | MetadataReaderTest.class, 38 | MethodDispatchTest.class, 39 | DeadMessageTest.class, 40 | SynchronizedHandlerTest.class, 41 | SubscriptionManagerTest.class, 42 | AsyncFIFOBusTest.class, 43 | MultiTreeTest.class, 44 | MultiMessageTest.class, 45 | }) 46 | public class AllTests { 47 | } 48 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/AsyncFIFOBusTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus; 24 | 25 | import java.util.LinkedList; 26 | import java.util.List; 27 | 28 | import org.junit.Test; 29 | 30 | import dorkbox.messageBus.MessageBus; 31 | import dorkbox.messageBus.annotations.Subscribe; 32 | import dorkbox.messagebus.common.MessageBusTest; 33 | 34 | /** 35 | * NOTE: the async publication is truly async. There is no guaranteed order to when it's handled. 36 | * 37 | * @author bennidi 38 | * Date: 3/30/14 39 | */ 40 | public class AsyncFIFOBusTest extends MessageBusTest { 41 | 42 | @Test 43 | public void testSingleThreadedSyncFIFO(){ 44 | // create a fifo bus with 1000 concurrently subscribed listeners 45 | MessageBus fifoBus = new MessageBus(); 46 | 47 | List listeners = new LinkedList(); 48 | for(int i = 0; i < 1000 ; i++){ 49 | Listener listener = new Listener(); 50 | listeners.add(listener); 51 | fifoBus.subscribe(listener); 52 | } 53 | 54 | // prepare set of messages in increasing order 55 | int[] messages = new int[1000]; 56 | for(int i = 0; i < messages.length ; i++){ 57 | messages[i] = i; 58 | } 59 | // publish in ascending order 60 | for(Integer message : messages) { 61 | fifoBus.publish(message); 62 | } 63 | 64 | while(fifoBus.hasPendingMessages()) { 65 | pause(1000); 66 | } 67 | 68 | for(Listener listener : listeners){ 69 | assertEquals(messages.length, listener.receivedSync.size()); 70 | for(int i=0; i < messages.length; i++){ 71 | assertEquals(messages[i], listener.receivedSync.get(i)); 72 | } 73 | } 74 | fifoBus.shutdown(); 75 | } 76 | 77 | public static class Listener { 78 | 79 | private List receivedSync = new LinkedList(); 80 | 81 | @Subscribe 82 | public void handleSync(Integer message){ 83 | synchronized (this.receivedSync) { 84 | this.receivedSync.add(message); 85 | } 86 | } 87 | 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/DeadMessageTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus; 24 | 25 | import java.util.concurrent.atomic.AtomicInteger; 26 | 27 | import org.junit.Before; 28 | import org.junit.Test; 29 | 30 | import dorkbox.messageBus.MessageBus; 31 | import dorkbox.messageBus.annotations.Subscribe; 32 | import dorkbox.messageBus.error.DeadMessage; 33 | import dorkbox.messagebus.common.ConcurrentExecutor; 34 | import dorkbox.messagebus.common.ListenerFactory; 35 | import dorkbox.messagebus.common.MessageBusTest; 36 | import dorkbox.messagebus.common.TestUtil; 37 | import dorkbox.messagebus.listeners.IMessageListener; 38 | import dorkbox.messagebus.listeners.MessageTypesListener; 39 | import dorkbox.messagebus.listeners.ObjectListener; 40 | 41 | /** 42 | * Verify correct behaviour in case of message publications that do not have any matching subscriptions 43 | * 44 | * @author bennidi 45 | * Date: 1/18/13 46 | */ 47 | public class DeadMessageTest extends MessageBusTest { 48 | 49 | private static final AtomicInteger deadMessages = new AtomicInteger(0); 50 | 51 | @Override 52 | @Before 53 | public void beforeTest(){ 54 | deadMessages.set(0); 55 | } 56 | 57 | 58 | @Test 59 | public void testDeadMessage(){ 60 | final MessageBus bus = createBus(); 61 | ListenerFactory listeners = new ListenerFactory() 62 | .create(InstancesPerListener, IMessageListener.DefaultListener.class) 63 | .create(InstancesPerListener, IMessageListener.DisabledListener.class) 64 | .create(InstancesPerListener, MessageTypesListener.DefaultListener.class) 65 | .create(InstancesPerListener, MessageTypesListener.DisabledListener.class) 66 | .create(InstancesPerListener, DeadMessagHandler.class) 67 | .create(InstancesPerListener, Object.class); 68 | 69 | 70 | ConcurrentExecutor.runConcurrent(TestUtil.subscriber(bus, listeners), ConcurrentUnits); 71 | 72 | Runnable publishUnhandledMessage = new Runnable() { 73 | @Override 74 | public void run() { 75 | for(int i=0; i < IterationsPerThread; i++){ 76 | int variation = i % 3; 77 | switch (variation){ 78 | case 0:bus.publish(new Object());break; 79 | case 1:bus.publish(i);break; 80 | case 2:bus.publish(String.valueOf(i));break; 81 | } 82 | } 83 | 84 | } 85 | }; 86 | 87 | ConcurrentExecutor.runConcurrent(publishUnhandledMessage, ConcurrentUnits); 88 | 89 | assertEquals(InstancesPerListener * IterationsPerThread * ConcurrentUnits, deadMessages.get()); 90 | } 91 | 92 | 93 | 94 | @Test 95 | public void testUnsubscribingAllListeners() { 96 | final MessageBus bus = createBus(); 97 | ListenerFactory deadMessageListener = new ListenerFactory() 98 | .create(InstancesPerListener, DeadMessagHandler.class); 99 | 100 | ListenerFactory objectListener = new ListenerFactory() 101 | .create(InstancesPerListener, ObjectListener.class); 102 | 103 | ConcurrentExecutor.runConcurrent(TestUtil.subscriber(bus, deadMessageListener), ConcurrentUnits); 104 | 105 | // Only dead message handlers available 106 | bus.publish(new Object()); 107 | 108 | // The message should be caught as dead message since there are no subscribed listeners 109 | assertEquals(InstancesPerListener, deadMessages.get()); 110 | 111 | // Clear deadmessage for future tests 112 | deadMessages.set(0); 113 | 114 | // Add object listeners and publish again 115 | ConcurrentExecutor.runConcurrent(TestUtil.subscriber(bus, objectListener), ConcurrentUnits); 116 | bus.publish(new Object()); 117 | 118 | // verify that no dead message events were produced 119 | assertEquals(0, deadMessages.get()); 120 | 121 | // Unsubscribe all object listeners 122 | ConcurrentExecutor.runConcurrent(TestUtil.unsubscriber(bus, objectListener), ConcurrentUnits); 123 | 124 | // Only dead message handlers available 125 | bus.publish(new Object()); 126 | 127 | // The message should be caught, as it's the only listener 128 | assertEquals(InstancesPerListener, deadMessages.get()); 129 | } 130 | 131 | public static class DeadMessagHandler { 132 | @Subscribe 133 | public void handle(DeadMessage message){ 134 | deadMessages.incrementAndGet(); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/MethodDispatchTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus; 24 | 25 | import org.junit.Test; 26 | 27 | import dorkbox.messageBus.MessageBus; 28 | import dorkbox.messageBus.annotations.Subscribe; 29 | import dorkbox.messagebus.common.MessageBusTest; 30 | 31 | /** 32 | * Very simple test to verify dispatch to correct message handler 33 | * 34 | * @author bennidi 35 | * Date: 1/17/13 36 | */ 37 | public class MethodDispatchTest extends MessageBusTest { 38 | 39 | private boolean listener1Called = false; 40 | private boolean listener2Called = false; 41 | 42 | 43 | 44 | // a simple event listener 45 | public class EventListener1 { 46 | 47 | @Subscribe 48 | public void handleString(String s) { 49 | MethodDispatchTest.this.listener1Called = true; 50 | } 51 | 52 | } 53 | 54 | // the same handlers as its super class 55 | public class EventListener2 extends EventListener1 { 56 | 57 | // redefine handler implementation (not configuration) 58 | @Override 59 | public void handleString(String s) { 60 | MethodDispatchTest.this.listener2Called = true; 61 | } 62 | 63 | } 64 | 65 | @Test 66 | public void testDispatch1(){ 67 | MessageBus bus = createBus(); 68 | EventListener2 listener2 = new EventListener2(); 69 | bus.subscribe(listener2); 70 | bus.publish("jfndf"); 71 | assertTrue(this.listener2Called); 72 | assertFalse(this.listener1Called); 73 | 74 | EventListener1 listener1 = new EventListener1(); 75 | bus.subscribe(listener1); 76 | bus.publish("jfndf"); 77 | assertTrue(this.listener1Called); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/MultiMessageTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 dorkbox, llc 3 | */ 4 | package dorkbox.messagebus; 5 | 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | 8 | import org.junit.Test; 9 | 10 | import dorkbox.messageBus.DispatchMode; 11 | import dorkbox.messageBus.MessageBus; 12 | import dorkbox.messageBus.SubscriptionMode; 13 | import dorkbox.messageBus.annotations.Subscribe; 14 | import dorkbox.messagebus.common.MessageBusTest; 15 | 16 | /** 17 | * @author dorkbox, llc 18 | * Date: 2/2/15 19 | */ 20 | @SuppressWarnings("Duplicates") 21 | public class MultiMessageTest extends MessageBusTest { 22 | 23 | private static AtomicInteger count = new AtomicInteger(0); 24 | 25 | @Test 26 | public void testMultiMessageSendingExact() { 27 | MessageBus bus = new MessageBus(DispatchMode.Exact, SubscriptionMode.StrongReferences, 28 | Runtime.getRuntime() 29 | .availableProcessors() / 2); 30 | MultiListener listener1 = new MultiListener(); 31 | bus.subscribe(listener1); 32 | bus.unsubscribe(listener1); 33 | 34 | bus.publish("s"); 35 | bus.publish("s", "s"); 36 | bus.publish("s", "s", "s"); 37 | bus.publish(1, "s"); 38 | bus.publish(1, 2, "s"); 39 | bus.publish(new Integer[] {1, 2, 3, 4, 5, 6}); 40 | 41 | assertEquals(0, count.get()); 42 | 43 | bus.subscribe(listener1); 44 | 45 | bus.publish("s"); // 1 46 | bus.publish("s", "s"); // 1 47 | bus.publish("s", "s", "s"); // 1 48 | bus.publish(1, "s"); // 0 49 | bus.publish(1, 2, "s"); // 1 50 | bus.publish(new Integer[] {1, 2, 3, 4, 5, 6}); // 1 51 | 52 | assertEquals(5, count.get()); 53 | count.set(0); 54 | } 55 | 56 | @Test 57 | public void testMultiMessageSendingExactAndSuper() { 58 | MessageBus bus = new MessageBus(DispatchMode.ExactWithSuperTypes, SubscriptionMode.StrongReferences, 59 | Runtime.getRuntime() 60 | .availableProcessors() / 2); 61 | MultiListener listener1 = new MultiListener(); 62 | bus.subscribe(listener1); 63 | bus.unsubscribe(listener1); 64 | 65 | bus.publish("s"); 66 | bus.publish("s", "s"); 67 | bus.publish("s", "s", "s"); 68 | bus.publish(1, "s"); 69 | bus.publish(1, 2, "s"); 70 | bus.publish(new Integer[] {1, 2, 3, 4, 5, 6}); 71 | 72 | assertEquals(0, count.get()); 73 | 74 | bus.subscribe(listener1); 75 | 76 | bus.publish("s"); // 2 77 | bus.publish("s", "s"); // 2 78 | bus.publish("s", "s", "s"); // 4 79 | bus.publish(1, "s"); // 0 80 | bus.publish(1, 2, "s"); // 1 81 | bus.publish(new Integer[] {1, 2, 3, 4, 5, 6}); // 2 82 | 83 | assertEquals(11, count.get()); 84 | count.set(0); 85 | } 86 | 87 | public static class MultiListener { 88 | @Subscribe 89 | public void handleSync(Object o) { 90 | count.getAndIncrement(); 91 | System.err.println("match Object"); 92 | } 93 | 94 | @Subscribe 95 | public void handleSync(String o1, Object o2) { 96 | count.getAndIncrement(); 97 | System.err.println("match String, Object"); 98 | } 99 | 100 | @Subscribe 101 | public void handleSync(String o1) { 102 | count.getAndIncrement(); 103 | System.err.println("match String"); 104 | } 105 | 106 | @Subscribe 107 | public void handleSync(String o1, String o2) { 108 | count.getAndIncrement(); 109 | System.err.println("match String, String"); 110 | } 111 | 112 | @Subscribe 113 | public void handleSync(String o1, String o2, String o3) { 114 | count.getAndIncrement(); 115 | System.err.println("match String, String, String"); 116 | } 117 | 118 | @Subscribe 119 | public void handleSync(Object o1, String o2, String o3) { 120 | count.getAndIncrement(); 121 | System.err.println("match Object, String, String"); 122 | } 123 | 124 | @Subscribe 125 | public void handleSync(String o1, Object o2, String o3) { 126 | count.getAndIncrement(); 127 | System.err.println("match String, Object, String"); 128 | } 129 | 130 | @Subscribe 131 | public void handleSync(String o1, Object o2, Object o3) { 132 | count.getAndIncrement(); 133 | System.err.println("match String, Object, Object"); 134 | } 135 | 136 | @Subscribe 137 | public void handleSync(Integer o1, Integer o2, String o3) { 138 | count.getAndIncrement(); 139 | System.err.println("match Integer, Integer, String"); 140 | } 141 | 142 | @Subscribe 143 | public void handleSync(String... o) { 144 | count.getAndIncrement(); 145 | System.err.println("match String[]"); 146 | } 147 | 148 | @Subscribe 149 | public void handleSync(Integer... o) { 150 | count.getAndIncrement(); 151 | System.err.println("match Integer[]"); 152 | } 153 | 154 | @Subscribe 155 | public void handleSync(Object... o) { 156 | count.getAndIncrement(); 157 | System.err.println("match Object[]"); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/MultiTreeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 dorkbox, llc 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package dorkbox.messagebus; 17 | 18 | import org.junit.Test; 19 | 20 | import dorkbox.messageBus.common.ClassTree; 21 | import dorkbox.messageBus.common.MultiClass; 22 | import dorkbox.messagebus.common.AssertSupport; 23 | 24 | public class MultiTreeTest extends AssertSupport { 25 | 26 | @Test 27 | public void testObjectTree() { 28 | ClassTree> tree = new ClassTree>(); 29 | 30 | final MultiClass a = tree.get(String.class); 31 | final MultiClass b = tree.get(Object.class); 32 | final MultiClass c = tree.get(String.class, String.class); 33 | final MultiClass d = tree.get(Object.class, Object.class); 34 | final MultiClass e = tree.get(String.class, String.class, String.class); 35 | 36 | 37 | // we never can remove elements, unless we CLEAR the entire thing (usually at shutdown) 38 | assertNotNull(a); 39 | assertNotNull(b); 40 | assertNotNull(c); 41 | assertNotNull(d); 42 | assertNotNull(e); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/SynchronizedHandlerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus; 24 | 25 | import java.util.concurrent.atomic.AtomicInteger; 26 | 27 | import org.junit.Assert; 28 | import org.junit.Test; 29 | 30 | import dorkbox.messageBus.MessageBus; 31 | import dorkbox.messageBus.annotations.Subscribe; 32 | import dorkbox.messageBus.annotations.Synchronized; 33 | import dorkbox.messagebus.common.MessageBusTest; 34 | 35 | /** 36 | * Todo: Add javadoc 37 | * 38 | * @author bennidi 39 | * Date: 3/31/13 40 | */ 41 | public class SynchronizedHandlerTest extends MessageBusTest { 42 | 43 | private static AtomicInteger counter = new AtomicInteger(0); 44 | private static int numberOfMessages = 1000; 45 | private static int numberOfListeners = 1000; 46 | 47 | @Test 48 | public void testSynchronizedWithSynchronousInvocation() { 49 | counter.set(0); 50 | 51 | MessageBus bus = createBus(); 52 | for(int i = 0; i < numberOfListeners; i++){ 53 | SynchronizedWithSynchronousDelivery handler = new SynchronizedWithSynchronousDelivery(); 54 | bus.subscribe(handler); 55 | } 56 | 57 | for (int i = 0; i < numberOfMessages; i++) { 58 | bus.publish(new Object()); 59 | } 60 | 61 | int totalCount = numberOfListeners * numberOfMessages; 62 | 63 | System.err.println("Testing: " + totalCount); 64 | 65 | // wait for last publication 66 | while (bus.hasPendingMessages()) { 67 | pause(100); 68 | } 69 | 70 | Assert.assertEquals(totalCount, counter.get()); 71 | } 72 | 73 | public static class SynchronizedWithSynchronousDelivery { 74 | @Subscribe 75 | @Synchronized 76 | public void handleMessage(Object o){ 77 | counter.getAndIncrement(); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/common/AssertSupport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.common; 24 | 25 | import org.junit.After; 26 | import org.junit.Assert; 27 | import org.junit.Before; 28 | import org.junit.Rule; 29 | import org.junit.rules.TestName; 30 | import org.slf4j.Logger; 31 | import org.slf4j.LoggerFactory; 32 | 33 | import java.lang.ref.WeakReference; 34 | 35 | /** 36 | * @author bennidi 37 | */ 38 | public class AssertSupport { 39 | 40 | private Runtime runtime = Runtime.getRuntime(); 41 | protected Logger logger = LoggerFactory.getLogger(getClass().getSimpleName()); 42 | private volatile long testExecutionStart; 43 | 44 | @Rule 45 | public TestName name = new TestName(); 46 | 47 | 48 | @Before 49 | public void beforeTest(){ 50 | this.logger.info("Running test " + getTestName()); 51 | this.testExecutionStart = System.currentTimeMillis(); 52 | } 53 | 54 | @After 55 | public void afterTest(){ 56 | this.logger.info(String.format("Finished " + getTestName() + ": " + (System.currentTimeMillis() - this.testExecutionStart) + " ms")); 57 | } 58 | 59 | 60 | public void pause(long ms) { 61 | try { 62 | Thread.sleep(ms); 63 | } catch (InterruptedException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | 68 | public void pause() { 69 | pause(10); 70 | } 71 | 72 | public String getTestName(){ 73 | return getClass().getSimpleName() + "." + this.name.getMethodName(); 74 | } 75 | 76 | public void runGC() { 77 | WeakReference ref = new WeakReference(new Object()); 78 | while(ref.get() != null) { 79 | this.runtime.gc(); 80 | pause(); 81 | } 82 | } 83 | 84 | public void fail(String message) { 85 | Assert.fail(message); 86 | } 87 | 88 | public static 89 | void fail() { 90 | Assert.fail(); 91 | } 92 | 93 | public void assertTrue(Boolean condition) { 94 | Assert.assertTrue(condition); 95 | } 96 | 97 | public void assertTrue(String message, Boolean condition) { 98 | Assert.assertTrue(message, condition); 99 | } 100 | 101 | public void assertFalse(Boolean condition) { 102 | Assert.assertFalse(condition); 103 | } 104 | 105 | public void assertNull(Object object) { 106 | Assert.assertNull(object); 107 | } 108 | 109 | public void assertNotNull(Object object) { 110 | Assert.assertNotNull(object); 111 | } 112 | 113 | public void assertFalse(String message, Boolean condition) { 114 | Assert.assertFalse(message, condition); 115 | } 116 | 117 | public void assertEquals(Object expected, Object actual) { 118 | Assert.assertEquals(expected, actual); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/common/ConcurrentExecutor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.common; 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | import java.util.concurrent.Callable; 28 | import java.util.concurrent.ExecutorService; 29 | import java.util.concurrent.Executors; 30 | import java.util.concurrent.Future; 31 | import java.util.concurrent.TimeUnit; 32 | 33 | /** 34 | * Run various tests concurrently. A given instance of runnable will be used to spawn and start 35 | * as many threads as specified by an additional parameter or (if multiple runnables have been 36 | * passed to the method) one thread for each runnable. 37 | *

38 | * Date: 2/14/12 39 | * 40 | * @Author bennidi 41 | */ 42 | public class ConcurrentExecutor { 43 | 44 | 45 | public static void runConcurrent(final Runnable unit, int numberOfConcurrentExecutions) { 46 | Runnable[] units = new Runnable[numberOfConcurrentExecutions]; 47 | // create the tasks and schedule for execution 48 | for (int i = 0; i < numberOfConcurrentExecutions; i++) { 49 | units[i] = unit; 50 | } 51 | runConcurrent(units); 52 | } 53 | 54 | 55 | public static void runConcurrent(int numberOfConcurrentExecutions, final Runnable... units) { 56 | Runnable[] runnables = new Runnable[numberOfConcurrentExecutions * units.length]; 57 | // create the tasks and schedule for execution 58 | for (int i = 0; i < numberOfConcurrentExecutions; i++) { 59 | for(int k = 0; k < units.length; k++) { 60 | runnables[k * numberOfConcurrentExecutions +i] = units[k]; 61 | } 62 | } 63 | runConcurrent(runnables); 64 | } 65 | 66 | 67 | public static void runConcurrent(final Runnable... units) { 68 | ExecutorService executor = Executors.newCachedThreadPool(); 69 | List> returnValues = new ArrayList>(); 70 | 71 | // create the tasks and schedule for execution 72 | for (final Runnable unit : units) { 73 | Callable wrapper = new Callable() { 74 | @Override 75 | public Long call() throws Exception { 76 | long start = System.currentTimeMillis(); 77 | unit.run(); 78 | return System.currentTimeMillis() - start; 79 | } 80 | }; 81 | returnValues.add(executor.submit(wrapper)); 82 | } 83 | 84 | 85 | // wait until all tasks have been executed 86 | try { 87 | executor.shutdown();// tells the thread pool to execute all waiting tasks 88 | executor.awaitTermination(5, TimeUnit.MINUTES); 89 | } catch (InterruptedException e) { 90 | // unlikely that this will happen 91 | e.printStackTrace(); 92 | } 93 | 94 | for(Future task : returnValues){ 95 | try { 96 | task.get(); 97 | } catch (Exception e) { 98 | throw new RuntimeException(e); 99 | } 100 | } 101 | 102 | } 103 | 104 | 105 | } 106 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/common/ListenerFactory.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.common; 24 | 25 | import java.util.*; 26 | import java.util.concurrent.atomic.AtomicInteger; 27 | 28 | import static org.junit.Assert.fail; 29 | 30 | /** 31 | * The factory can be used to declaratively specify how many instances of some given classes 32 | * should be created. It will create those instances using reflection and provide a list containing those instances. 33 | * The factory also holds strong references to the instances such that GC will not interfere with tests unless the 34 | * factory is explicitly cleared. 35 | * 36 | * @author bennidi 37 | * Date: 11/22/12 38 | */ 39 | @SuppressWarnings("ALL") 40 | public 41 | class ListenerFactory { 42 | 43 | private Map requiredBeans = new HashMap(); 44 | private volatile List generatedListeners; 45 | private int requiredSize = 0; 46 | 47 | public 48 | int getNumberOfListeners(Class listener) { 49 | return requiredBeans.containsKey(listener) ? requiredBeans.get(listener) : 0; 50 | } 51 | 52 | public 53 | ListenerFactory create(int numberOfInstances, Class clazz) { 54 | requiredBeans.put(clazz, numberOfInstances); 55 | requiredSize += numberOfInstances; 56 | return this; 57 | } 58 | 59 | public 60 | ListenerFactory create(int numberOfInstances, Class... classes) { 61 | for (Class clazz : classes) { 62 | create(numberOfInstances, clazz); 63 | } 64 | return this; 65 | } 66 | 67 | public 68 | ListenerFactory create(int numberOfInstances, Collection classes) { 69 | for (Class clazz : classes) { 70 | create(numberOfInstances, clazz); 71 | } 72 | return this; 73 | } 74 | 75 | 76 | @SuppressWarnings("unchecked") 77 | public synchronized 78 | List getAll() { 79 | if (generatedListeners != null) { 80 | return generatedListeners; 81 | } 82 | List listeners = new ArrayList(requiredSize); 83 | try { 84 | for (Class clazz : requiredBeans.keySet()) { 85 | int numberOfRequiredBeans = requiredBeans.get(clazz); 86 | for (int i = 0; i < numberOfRequiredBeans; i++) { 87 | listeners.add(clazz.newInstance()); 88 | } 89 | } 90 | } catch (Exception e) { 91 | // if instantiation fails, counts will be incorrect 92 | // -> fail early here 93 | fail("There was a problem instantiating a listener " + e); 94 | } 95 | Collections.shuffle(listeners); 96 | generatedListeners = Collections.unmodifiableList(listeners); 97 | return generatedListeners; 98 | } 99 | 100 | // not thread-safe but not yet used concurrently 101 | public synchronized 102 | void clear() { 103 | generatedListeners = null; 104 | requiredBeans.clear(); 105 | } 106 | 107 | /** 108 | * Create a thread-safe read-only iterator 109 | *

110 | * NOTE: Iterator is not perfectly synchronized with mutator methods of the list of generated listeners 111 | * In theory, it is possible that the list is changed while iterators are still running which should be avoided. 112 | * 113 | * @return 114 | */ 115 | public 116 | Iterator iterator() { 117 | getAll(); 118 | final AtomicInteger current = new AtomicInteger(0); 119 | 120 | return new Iterator() { 121 | @Override 122 | public 123 | boolean hasNext() { 124 | return current.get() < generatedListeners.size(); 125 | } 126 | 127 | @Override 128 | public 129 | Object next() { 130 | int index = current.getAndIncrement(); 131 | return index < generatedListeners.size() ? generatedListeners.get(index) : null; 132 | } 133 | 134 | @Override 135 | public 136 | void remove() { 137 | throw new UnsupportedOperationException("Iterator is read only"); 138 | } 139 | }; 140 | } 141 | 142 | 143 | } 144 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/common/MessageBusTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.common; 24 | 25 | import org.junit.Before; 26 | 27 | import dorkbox.messageBus.MessageBus; 28 | import dorkbox.messageBus.error.IPublicationErrorHandler; 29 | import dorkbox.messageBus.error.PublicationError; 30 | import dorkbox.messagebus.messages.MessageTypes; 31 | 32 | /** 33 | * A base test that provides a factory for message bus that makes tests fail if any 34 | * publication error occurs 35 | * 36 | * @author bennidi 37 | * Date: 3/2/13 38 | */ 39 | public abstract 40 | class MessageBusTest extends AssertSupport { 41 | 42 | // this value probably needs to be adjusted depending on the performance of the underlying plattform 43 | // otherwise the tests will fail since asynchronous processing might not have finished when 44 | // evaluation is run 45 | protected static final int InstancesPerListener = 5000; 46 | protected static final int ConcurrentUnits = 10; 47 | protected static final int IterationsPerThread = 100; 48 | 49 | protected static final IPublicationErrorHandler TestFailingHandler = new IPublicationErrorHandler() { 50 | @Override 51 | public 52 | void handleError(PublicationError error) { 53 | error.getCause().printStackTrace(); 54 | fail(); 55 | } 56 | 57 | @Override 58 | public 59 | void handleError(final String error, final Class listenerClass) { 60 | System.err.println(error + " " + listenerClass); 61 | } 62 | }; 63 | 64 | @Before 65 | public 66 | void setUp() { 67 | MessageTypes.resetAll(); 68 | } 69 | 70 | 71 | public 72 | MessageBus createBus() { 73 | MessageBus bus = new MessageBus(); 74 | bus.addErrorHandler(TestFailingHandler); 75 | return bus; 76 | } 77 | 78 | public 79 | MessageBus createBus(ListenerFactory listeners) { 80 | MessageBus bus = new MessageBus(); 81 | bus.addErrorHandler(TestFailingHandler); 82 | ConcurrentExecutor.runConcurrent(TestUtil.subscriber(bus, listeners), ConcurrentUnits); 83 | return bus; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/common/SubscriptionValidator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.common; 24 | 25 | import java.util.ArrayDeque; 26 | import java.util.Arrays; 27 | import java.util.Collection; 28 | import java.util.HashSet; 29 | import java.util.LinkedList; 30 | import java.util.List; 31 | import java.util.Set; 32 | 33 | import dorkbox.messageBus.subscription.Subscription; 34 | import dorkbox.messageBus.subscription.SubscriptionManager; 35 | 36 | /** 37 | * @author bennidi 38 | * Date: 5/25/13 39 | */ 40 | public class SubscriptionValidator extends AssertSupport { 41 | 42 | public class Expectation { 43 | private Class listener; 44 | 45 | private Expectation(Class listener) { 46 | this.listener = listener; 47 | } 48 | 49 | public SubscriptionValidator handles(Class... messages) { 50 | for (Class message : messages) { 51 | expect(this.listener, message); 52 | } 53 | 54 | return SubscriptionValidator.this; 55 | } 56 | } 57 | 58 | private class ValidationEntry { 59 | private Class subscriber; 60 | private Class messageType; 61 | 62 | private ValidationEntry(Class messageType, Class subscriber) { 63 | this.messageType = messageType; 64 | this.subscriber = subscriber; 65 | } 66 | } 67 | 68 | private List validations = new LinkedList(); 69 | private Set messageTypes = new HashSet(); 70 | private ListenerFactory subscribedListener; // the subscribed listeners are used to assert the size of the subscriptions 71 | 72 | public SubscriptionValidator(ListenerFactory subscribedListener) { 73 | this.subscribedListener = subscribedListener; 74 | } 75 | 76 | public Expectation listener(Class subscriber) { 77 | return new Expectation(subscriber); 78 | } 79 | 80 | private SubscriptionValidator expect(Class subscriber, Class messageType) { 81 | this.validations.add(new ValidationEntry(messageType, subscriber)); 82 | this.messageTypes.add(messageType); 83 | 84 | return this; 85 | } 86 | 87 | private Collection getEntries(Class messageType) { 88 | Collection matching = new LinkedList(); 89 | for (ValidationEntry validationValidationEntry : this.validations) { 90 | 91 | if (validationValidationEntry.messageType.equals(messageType)) { 92 | matching.add(validationValidationEntry); 93 | } 94 | } 95 | return matching; 96 | } 97 | 98 | // match subscriptions with existing validation entries 99 | // for each tuple of subscriber and message type the specified number of listeners must exist 100 | public void validate(SubscriptionManager subManager) { 101 | for (Class messageType : this.messageTypes) { 102 | Collection validationEntries = getEntries(messageType); 103 | 104 | // we split subs + superSubs into TWO calls. 105 | Collection collection = new ArrayDeque(8); 106 | Subscription[] subscriptions = subManager.getSubs(messageType); // can return null 107 | if (subscriptions != null) { 108 | collection.addAll(Arrays.asList(subscriptions)); 109 | } 110 | 111 | subscriptions = subManager.getSuperSubs(messageType); // NOT return null 112 | collection.addAll(Arrays.asList(subscriptions)); 113 | 114 | assertEquals(validationEntries.size(), collection.size()); 115 | 116 | 117 | for (ValidationEntry validationValidationEntry : validationEntries) { 118 | Subscription matchingSub = null; 119 | // one of the subscriptions must belong to the subscriber type 120 | for (Subscription sub : collection) { 121 | if (belongsTo(sub, validationValidationEntry.subscriber)) { 122 | matchingSub = sub; 123 | break; 124 | } 125 | } 126 | assertNotNull(matchingSub); 127 | assertEquals(this.subscribedListener.getNumberOfListeners(validationValidationEntry.subscriber), matchingSub.size()); 128 | } 129 | } 130 | } 131 | 132 | 133 | /** 134 | * Check whether this subscription manages a message handler of the given message listener class 135 | */ 136 | // only in unit test 137 | public boolean belongsTo(Subscription subscription, Class listener) { 138 | return subscription.getListenerClass() == listener; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/common/TestUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.common; 24 | 25 | import java.util.Iterator; 26 | import java.util.List; 27 | 28 | import dorkbox.messageBus.MessageBus; 29 | import dorkbox.messageBus.subscription.SubscriptionManager; 30 | 31 | /** 32 | * Todo: Add javadoc 33 | * 34 | * @author bennidi 35 | * Date: 11/22/12 36 | */ 37 | public class TestUtil { 38 | 39 | 40 | public static Runnable subscriber(final SubscriptionManager manager, final ListenerFactory listeners) { 41 | final Iterator source = listeners.iterator(); 42 | return new Runnable() { 43 | @Override public void run() { 44 | Object next; 45 | while ((next = source.next()) != null) { 46 | manager.subscribe(next); 47 | } 48 | } 49 | }; 50 | } 51 | 52 | public static Runnable unsubscriber(final SubscriptionManager manager, final ListenerFactory listeners) { 53 | final Iterator source = listeners.iterator(); 54 | return new Runnable() { 55 | @Override public void run() { 56 | Object next; 57 | while ((next = source.next()) != null) { 58 | manager.unsubscribe(next); 59 | } 60 | } 61 | }; 62 | } 63 | 64 | public static Runnable subscriber(final MessageBus bus, final ListenerFactory listeners) { 65 | final Iterator source = listeners.iterator(); 66 | return new Runnable() { 67 | @Override public void run() { 68 | Object next; 69 | while ((next = source.next()) != null) { 70 | bus.subscribe(next); 71 | } 72 | } 73 | }; 74 | } 75 | 76 | public static Runnable unsubscriber(final MessageBus bus, final ListenerFactory listeners) { 77 | final Iterator source = listeners.iterator(); 78 | return new Runnable() { 79 | @Override public void run() { 80 | Object next; 81 | while ((next = source.next()) != null) { 82 | bus.unsubscribe(next); 83 | } 84 | } 85 | }; 86 | } 87 | 88 | public static void setup(final MessageBus bus, final List listeners, int numberOfThreads) { 89 | Runnable[] setupUnits = new Runnable[numberOfThreads]; 90 | int partitionSize; 91 | if (listeners.size() >= numberOfThreads) { 92 | partitionSize = (int) Math.floor(listeners.size() / numberOfThreads); 93 | } 94 | else { 95 | partitionSize = 1; 96 | numberOfThreads = listeners.size(); 97 | } 98 | 99 | for (int i = 0; i < numberOfThreads; i++) { 100 | final int partitionStart = i * partitionSize; 101 | final int partitionEnd = i + 1 < numberOfThreads ? partitionStart + partitionSize + 1 : listeners.size(); 102 | setupUnits[i] = new Runnable() { 103 | 104 | private List listenerSubset = listeners.subList(partitionStart, partitionEnd); 105 | 106 | @Override public void run() { 107 | for (Object listener : this.listenerSubset) { 108 | bus.subscribe(listener); 109 | } 110 | } 111 | }; 112 | 113 | } 114 | 115 | ConcurrentExecutor.runConcurrent(setupUnits); 116 | 117 | } 118 | 119 | public static void setup(MessageBus bus, ListenerFactory listeners, int numberOfThreads) { 120 | setup(bus, listeners.getAll(), numberOfThreads); 121 | 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/listeners/AbstractMessageListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.listeners; 24 | 25 | import dorkbox.messageBus.annotations.Subscribe; 26 | import dorkbox.messagebus.messages.AbstractMessage; 27 | 28 | /** 29 | * @author bennidi 30 | * Date: 5/24/13 31 | */ 32 | public class AbstractMessageListener { 33 | 34 | private static abstract class BaseListener { 35 | 36 | @Subscribe 37 | public void handle(AbstractMessage message){ 38 | message.handled(this.getClass()); 39 | } 40 | 41 | } 42 | 43 | public static class DefaultListener extends BaseListener { 44 | 45 | @Override 46 | public void handle(AbstractMessage message){ 47 | super.handle(message); 48 | } 49 | } 50 | 51 | public static class NoSubtypesListener extends BaseListener { 52 | 53 | @Override 54 | @Subscribe(acceptSubtypes = false) 55 | public void handle(AbstractMessage message){ 56 | super.handle(message); 57 | } 58 | } 59 | 60 | 61 | public static class DisabledListener extends BaseListener { 62 | 63 | @Override 64 | @Subscribe(enabled = false) 65 | public void handle(AbstractMessage message){ 66 | super.handle(message); 67 | } 68 | 69 | } 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/listeners/ExceptionThrowingListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.listeners; 24 | 25 | import dorkbox.messageBus.annotations.Subscribe; 26 | import dorkbox.messagebus.messages.StandardMessage; 27 | 28 | /** 29 | * @author bennidi 30 | * Date: 5/25/13 31 | */ 32 | public class ExceptionThrowingListener { 33 | 34 | 35 | // this handler will be invoked asynchronously 36 | @Subscribe() 37 | public void handle(StandardMessage message) { 38 | throw new RuntimeException("This is an expected exception"); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/listeners/ICountableListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.listeners; 24 | 25 | import dorkbox.messageBus.annotations.Subscribe; 26 | import dorkbox.messagebus.messages.ICountable; 27 | 28 | /** 29 | * 30 | * @author bennidi 31 | * Date: 5/24/13 32 | */ 33 | public class ICountableListener { 34 | 35 | private static abstract class BaseListener { 36 | @Subscribe 37 | public void handle(ICountable message){ 38 | message.handled(this.getClass()); 39 | } 40 | } 41 | 42 | public static class DefaultListener extends BaseListener { 43 | @Override 44 | public void handle(ICountable message){ 45 | super.handle(message); 46 | } 47 | } 48 | 49 | public static class NoSubtypesListener extends BaseListener { 50 | @Override 51 | @Subscribe(acceptSubtypes = false) 52 | public void handle(ICountable message){ 53 | super.handle(message); 54 | } 55 | } 56 | 57 | public static class DisabledListener extends BaseListener { 58 | @Override 59 | @Subscribe(enabled = false) 60 | public void handle(ICountable message){ 61 | super.handle(message); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/listeners/IMessageListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.listeners; 24 | 25 | import dorkbox.messageBus.annotations.Subscribe; 26 | import dorkbox.messagebus.messages.IMessage; 27 | 28 | /** 29 | * 30 | * @author bennidi 31 | * Date: 5/24/13 32 | */ 33 | public class IMessageListener { 34 | 35 | private static abstract class BaseListener { 36 | @Subscribe 37 | public void handle(IMessage message){ 38 | message.handled(this.getClass()); 39 | } 40 | } 41 | 42 | 43 | public static class DefaultListener extends BaseListener { 44 | @Override 45 | public void handle(IMessage message){ 46 | super.handle(message); 47 | } 48 | } 49 | 50 | 51 | public static class NoSubtypesListener extends BaseListener { 52 | 53 | @Override 54 | @Subscribe(acceptSubtypes = false) 55 | public void handle(IMessage message){ 56 | super.handle(message); 57 | } 58 | } 59 | 60 | 61 | public static class DisabledListener extends BaseListener { 62 | @Override 63 | @Subscribe(enabled = false) 64 | public void handle(IMessage message){ 65 | super.handle(message); 66 | } 67 | 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/listeners/IMultipartMessageListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.listeners; 24 | 25 | import dorkbox.messageBus.annotations.Subscribe; 26 | import dorkbox.messagebus.messages.IMultipartMessage; 27 | 28 | /** 29 | * 30 | * @author bennidi 31 | * Date: 5/24/13 32 | */ 33 | public class IMultipartMessageListener { 34 | 35 | private static abstract class BaseListener { 36 | @Subscribe 37 | public void handle(IMultipartMessage message){ 38 | message.handled(this.getClass()); 39 | } 40 | } 41 | 42 | public static class DefaultListener extends BaseListener { 43 | @Override 44 | public void handle(IMultipartMessage message){ 45 | super.handle(message); 46 | } 47 | } 48 | 49 | public static class NoSubtypesListener extends BaseListener { 50 | @Override 51 | @Subscribe(acceptSubtypes = false) 52 | public void handle(IMultipartMessage message){ 53 | super.handle(message); 54 | } 55 | } 56 | 57 | public static class DisabledListener extends BaseListener { 58 | @Override 59 | @Subscribe(enabled = false) 60 | public void handle(IMultipartMessage message){ 61 | super.handle(message); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/listeners/Listeners.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.listeners; 24 | 25 | import java.util.Arrays; 26 | import java.util.Collection; 27 | import java.util.Collections; 28 | import java.util.HashSet; 29 | import java.util.List; 30 | import java.util.Set; 31 | 32 | /** 33 | * User: benjamin 34 | * Date: 6/26/13 35 | */ 36 | public class Listeners { 37 | 38 | private static final List Synchronous = Collections.unmodifiableList(Arrays.asList(new Class[]{ 39 | MessageTypesListener.DefaultListener.class, 40 | IMessageListener.DefaultListener.class, 41 | StandardMessageListener.DefaultListener.class, 42 | MultipartMessageListener.DefaultListener.class, 43 | ICountableListener.DefaultListener.class, 44 | IMultipartMessageListener.DefaultListener.class})); 45 | 46 | private static final List SubtypeRejecting = Collections.unmodifiableList(Arrays.asList(new Class[]{ 47 | MessageTypesListener.NoSubtypesListener.class, 48 | IMessageListener.NoSubtypesListener.class, 49 | StandardMessageListener.NoSubtypesListener.class, 50 | MultipartMessageListener.NoSubtypesListener.class, 51 | ICountableListener.NoSubtypesListener.class, 52 | IMultipartMessageListener.NoSubtypesListener.class})); 53 | 54 | private static final List NoHandlers = Collections.unmodifiableList(Arrays.asList(new Class[]{ 55 | MessageTypesListener.DisabledListener.class, 56 | IMessageListener.DisabledListener.class, 57 | StandardMessageListener.DisabledListener.class, 58 | MultipartMessageListener.DisabledListener.class, 59 | ICountableListener.DisabledListener.class, 60 | IMultipartMessageListener.DisabledListener.class, 61 | Object.class,String.class})); 62 | 63 | 64 | private static final List HandlesIMessage = Collections.unmodifiableList(Arrays.asList(new Class[]{ 65 | IMessageListener.DefaultListener.class, 66 | IMessageListener.NoSubtypesListener.class, 67 | IMultipartMessageListener.DefaultListener.class, 68 | IMultipartMessageListener.NoSubtypesListener.class, 69 | MessageTypesListener.DefaultListener.class, 70 | MessageTypesListener.NoSubtypesListener.class, 71 | StandardMessageListener.DefaultListener.class, 72 | StandardMessageListener.NoSubtypesListener.class, 73 | MultipartMessageListener.DefaultListener.class, 74 | MultipartMessageListener.NoSubtypesListener.class})); 75 | 76 | private static final List HandlesStandardessage = Collections.unmodifiableList(Arrays.asList(new Class[]{ 77 | IMessageListener.DefaultListener.class, 78 | ICountableListener.DefaultListener.class, 79 | StandardMessageListener.DefaultListener.class, 80 | StandardMessageListener.NoSubtypesListener.class})); 81 | 82 | 83 | public static Collection synchronous(){ 84 | return Synchronous; 85 | } 86 | 87 | public static Collection subtypeRejecting(){ 88 | return SubtypeRejecting; 89 | } 90 | 91 | public static Collection noHandlers(){ 92 | return NoHandlers; 93 | } 94 | 95 | public static Collection handlesIMessage(){ 96 | return HandlesIMessage; 97 | } 98 | 99 | public static Collection handlesStandardMessage(){ 100 | return HandlesStandardessage; 101 | } 102 | 103 | 104 | public static Collection join(Collection...listenerSets){ 105 | Set join = new HashSet(); 106 | for(Collection listeners : listenerSets) { 107 | join.addAll(listeners); 108 | } 109 | for(Collection listeners : listenerSets) { 110 | join.retainAll(listeners); 111 | } 112 | return join; 113 | } 114 | 115 | 116 | 117 | 118 | } 119 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/listeners/MessageTypesListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.listeners; 24 | 25 | import dorkbox.messageBus.annotations.Subscribe; 26 | import dorkbox.messagebus.messages.MessageTypes; 27 | 28 | /** 29 | * @author bennidi 30 | * Date: 5/24/13 31 | */ 32 | public class MessageTypesListener { 33 | 34 | private static abstract class BaseListener { 35 | @Subscribe 36 | public void handle(MessageTypes message){ 37 | message.handled(this.getClass()); 38 | } 39 | } 40 | 41 | public static class DefaultListener extends BaseListener { 42 | @Override 43 | public void handle(MessageTypes message){ 44 | super.handle(message); 45 | } 46 | } 47 | 48 | public static class NoSubtypesListener extends BaseListener { 49 | @Override 50 | @Subscribe(acceptSubtypes = false) 51 | public void handle(MessageTypes message){ 52 | super.handle(message); 53 | } 54 | } 55 | 56 | 57 | public static class DisabledListener extends BaseListener { 58 | @Override 59 | @Subscribe(enabled = false) 60 | public void handle(MessageTypes message){ 61 | super.handle(message); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/listeners/MultipartMessageListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.listeners; 24 | 25 | import dorkbox.messageBus.annotations.Subscribe; 26 | import dorkbox.messagebus.messages.MultipartMessage; 27 | 28 | /** 29 | * @author bennidi 30 | * Date: 5/24/13 31 | */ 32 | public class MultipartMessageListener { 33 | 34 | private static abstract class BaseListener { 35 | 36 | @Subscribe 37 | public void handle(MultipartMessage message){ 38 | message.handled(this.getClass()); 39 | } 40 | 41 | } 42 | 43 | public static class DefaultListener extends BaseListener { 44 | 45 | @Override 46 | public void handle(MultipartMessage message){ 47 | super.handle(message); 48 | } 49 | } 50 | 51 | public static class NoSubtypesListener extends BaseListener { 52 | 53 | @Override 54 | @Subscribe(acceptSubtypes = false) 55 | public void handle(MultipartMessage message){ 56 | super.handle(message); 57 | } 58 | } 59 | 60 | 61 | public static class DisabledListener extends BaseListener { 62 | 63 | @Override 64 | @Subscribe(enabled = false) 65 | public void handle(MultipartMessage message){ 66 | super.handle(message); 67 | } 68 | 69 | } 70 | 71 | 72 | } 73 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/listeners/ObjectListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.listeners; 24 | 25 | import java.util.Collections; 26 | import java.util.LinkedList; 27 | import java.util.List; 28 | 29 | import dorkbox.messageBus.annotations.Subscribe; 30 | 31 | 32 | public class ObjectListener { 33 | 34 | private List handledMessages = Collections.synchronizedList(new LinkedList()); 35 | 36 | @Subscribe() 37 | public void handle(Object message){ 38 | this.handledMessages.add(message); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/listeners/Overloading.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.listeners; 24 | 25 | import dorkbox.messageBus.annotations.Subscribe; 26 | import dorkbox.messagebus.messages.AbstractMessage; 27 | 28 | /** 29 | * Some handlers and message types to test correct functioning of overloaded message handlers 30 | */ 31 | public class Overloading { 32 | 33 | public static class TestMessageA extends AbstractMessage {} 34 | 35 | public static class TestMessageB extends AbstractMessage {} 36 | 37 | public static class ListenerSub extends ListenerBase { 38 | @Subscribe 39 | public void handleEvent(TestMessageB event) { 40 | event.handled(this.getClass()); 41 | } 42 | } 43 | 44 | public static class ListenerBase { 45 | /** 46 | * (!) If this method is removed, NO event handler will be called. 47 | */ 48 | @Subscribe 49 | public void handleEventWithNonOverloadedMethodName(TestMessageA event) { 50 | event.handled(this.getClass()); 51 | } 52 | 53 | @Subscribe 54 | public void handleEvent(TestMessageA event) { 55 | event.handled(this.getClass()); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/listeners/StandardMessageListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.listeners; 24 | 25 | import dorkbox.messageBus.annotations.Subscribe; 26 | import dorkbox.messagebus.messages.StandardMessage; 27 | 28 | /** 29 | * 30 | * @author bennidi 31 | * Date: 5/24/13 32 | */ 33 | public class StandardMessageListener { 34 | 35 | private static abstract class BaseListener { 36 | 37 | @Subscribe() 38 | public void handle(StandardMessage message){ 39 | message.handled(this.getClass()); 40 | } 41 | 42 | } 43 | 44 | public static class DefaultListener extends BaseListener { 45 | 46 | @Override 47 | public void handle(StandardMessage message){ 48 | super.handle(message); 49 | } 50 | } 51 | 52 | public static class NoSubtypesListener extends BaseListener { 53 | 54 | @Override 55 | @Subscribe(acceptSubtypes = false) 56 | public void handle(StandardMessage message){ 57 | super.handle(message); 58 | } 59 | } 60 | 61 | 62 | public static class DisabledListener extends BaseListener { 63 | 64 | @Override 65 | @Subscribe(enabled = false) 66 | public void handle(StandardMessage message){ 67 | super.handle(message); 68 | } 69 | 70 | } 71 | 72 | 73 | } 74 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/messages/AbstractMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.messages; 24 | 25 | import java.util.HashMap; 26 | import java.util.Map; 27 | import java.util.concurrent.locks.ReentrantReadWriteLock; 28 | 29 | /** 30 | * 31 | * @author bennidi 32 | * Date: 5/24/13 33 | */ 34 | public abstract class AbstractMessage implements IMessage{ 35 | 36 | private Map handledByListener = new HashMap(); 37 | private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); 38 | 39 | 40 | @Override 41 | public void reset() { 42 | lock.writeLock().lock(); 43 | try { 44 | handledByListener.clear(); 45 | }finally { 46 | lock.writeLock().unlock(); 47 | } 48 | } 49 | 50 | @Override 51 | public void handled(Class listener) { 52 | lock.writeLock().lock(); 53 | try { 54 | Integer count = handledByListener.get(listener); 55 | if(count == null){ 56 | handledByListener.put(listener, 1); 57 | } 58 | else{ 59 | handledByListener.put(listener, count + 1); 60 | } 61 | }finally { 62 | lock.writeLock().unlock(); 63 | } 64 | } 65 | 66 | @Override 67 | public int getTimesHandled(Class listener) { 68 | lock.readLock().lock(); 69 | try { 70 | return handledByListener.containsKey(listener) 71 | ? handledByListener.get(listener) 72 | : 0; 73 | }finally { 74 | lock.readLock().unlock(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/messages/CountableMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.messages; 24 | 25 | /** 26 | * 27 | * @author bennidi 28 | * Date: 5/24/13 29 | */ 30 | public class CountableMessage extends AbstractMessage implements ICountable{ 31 | } 32 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/messages/ICountable.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.messages; 24 | 25 | /** 26 | * Interface analogous to IMessage. Exists to test more complex class/interface hierarchies 27 | * 28 | * @author bennidi 29 | * Date: 5/24/13 30 | */ 31 | public interface ICountable { 32 | 33 | void reset(); 34 | 35 | void handled(Class listener); 36 | 37 | int getTimesHandled(Class listener); 38 | } 39 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/messages/IMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.messages; 24 | 25 | /** 26 | * 27 | * @author bennidi 28 | * Date: 5/24/13 29 | */ 30 | public interface IMessage { 31 | 32 | void reset(); 33 | 34 | void handled(Class listener); 35 | 36 | int getTimesHandled(Class listener); 37 | 38 | } 39 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/messages/IMultipartMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.messages; 24 | 25 | /** 26 | * 27 | * @author bennidi 28 | * Date: 5/24/13 29 | */ 30 | public interface IMultipartMessage extends IMessage, ICountable { 31 | } 32 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/messages/MessageTypes.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.messages; 24 | 25 | import java.util.HashMap; 26 | import java.util.Map; 27 | import java.util.concurrent.locks.ReentrantReadWriteLock; 28 | 29 | /** 30 | * Enum used to test handlers that consume enumerations. 31 | * 32 | * @author bennidi 33 | * Date: 5/24/13 34 | */ 35 | public enum MessageTypes implements IMessage{ 36 | 37 | Simple, 38 | Persistent, 39 | Multipart; 40 | 41 | private Map handledByListener = new HashMap(); 42 | private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); 43 | 44 | public static void resetAll(){ 45 | for(MessageTypes m : values()) 46 | m.reset(); 47 | } 48 | 49 | 50 | @Override 51 | public void reset() { 52 | try { 53 | lock.writeLock().lock(); 54 | handledByListener.clear(); 55 | }finally { 56 | lock.writeLock().unlock(); 57 | } 58 | } 59 | 60 | @Override 61 | public void handled(Class listener) { 62 | try { 63 | lock.writeLock().lock(); 64 | Integer count = handledByListener.get(listener); 65 | if(count == null){ 66 | handledByListener.put(listener, 1); 67 | } 68 | else{ 69 | handledByListener.put(listener, count + 1); 70 | } 71 | }finally { 72 | lock.writeLock().unlock(); 73 | } 74 | } 75 | 76 | @Override 77 | public int getTimesHandled(Class listener) { 78 | try { 79 | lock.readLock().lock(); 80 | return handledByListener.containsKey(listener) 81 | ? handledByListener.get(listener) 82 | : 0; 83 | }finally { 84 | lock.readLock().unlock(); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/messages/MultipartMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.messages; 24 | 25 | /** 26 | * 27 | * @author bennidi 28 | * Date: 5/24/13 29 | */ 30 | public class MultipartMessage extends AbstractMessage implements ICountable, IMultipartMessage { 31 | } 32 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/messages/StandardMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.messages; 24 | 25 | /** 26 | * @author bennidi 27 | * Date: 5/24/13 28 | */ 29 | public class StandardMessage extends AbstractMessage implements ICountable { 30 | } 31 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/messages/SubTestMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.messages; 24 | 25 | /** 26 | * 27 | * @author bennidi 28 | * Date: 11/22/12 29 | */ 30 | public class SubTestMessage extends TestMessage { 31 | 32 | } 33 | -------------------------------------------------------------------------------- /test/dorkbox/messagebus/messages/TestMessage.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 Benjamin Diedrichsen 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining 5 | * a copy of this software and associated documentation files (the 6 | * "Software"), to deal in the Software without restriction, including 7 | * without limitation the rights to use, copy, modify, merge, publish, 8 | * distribute, sublicense, and/or sell copies of the Software, and to 9 | * permit persons to whom the Software is furnished to do so, subject to 10 | * the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be 13 | * included in all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | package dorkbox.messagebus.messages; 24 | 25 | import java.util.concurrent.atomic.AtomicInteger; 26 | 27 | /** 28 | * 29 | * 30 | * @author bennidi 31 | * Date: 11/22/12 32 | */ 33 | public class TestMessage { 34 | 35 | public AtomicInteger counter = new AtomicInteger(); 36 | 37 | } 38 | --------------------------------------------------------------------------------