pax_global_header00006660000000000000000000000064130506007460014513gustar00rootroot0000000000000052 comment=95934188c634ecb4371905cf046ea378b4302783 event-studio-v-1.0.6/000077500000000000000000000000001305060074600144105ustar00rootroot00000000000000event-studio-v-1.0.6/.gitignore000066400000000000000000000002541305060074600164010ustar00rootroot00000000000000*.class .classpath .project .settings/ target/ *.iml *.ipr .idea .DS_Store # Gradle Files # ################ .gradle .m2 # Package Files # *.jar *.war *.ear /bin /build event-studio-v-1.0.6/.travis.yml000066400000000000000000000001151305060074600165160ustar00rootroot00000000000000language: java jdk: - openjdk7 - oraclejdk7 - openjdk6 - oraclejdk8 event-studio-v-1.0.6/LICENSE000066400000000000000000000260751305060074600154270ustar00rootroot00000000000000Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. event-studio-v-1.0.6/README.md000066400000000000000000000263571305060074600157040ustar00rootroot00000000000000 EventStudio ===================== [![Build Status](https://travis-ci.org/torakiki/event-studio.png?branch=master)](https://travis-ci.org/torakiki/event-studio) [![License](http://img.shields.io/badge/license-APLv2-blue.svg)](http://www.apache.org/licenses/LICENSE-2.0.html) EventStudio is yet another pure Java event bus implementation providing pub/sub pattern with events queue capabilities for intra-jvm event communication. Why? --------- There are many different libraries with slightly different approaches implementing the pub/sub pattern but none of them was a perfect match for the problem I was trying to solve. #### The problem Working on a rich client software that can have multiple modules/plugins and: + I wanted to be able to send events to the whole application (every listener subscribed on a given event) + I wanted to be able to send events to a single module (every listener belonging to a given module and subscribed on a given event) + I wanted the event to be queued in case no listener was listening and delivered as soon as a listener registers. + I wanted listeners to be able to define at runtime what module they belong to. The idea was to create components (e.g. a SpecializedComboBox) listening for events (e.g. DisableEvent) and be able to reuse those components in different modules. I couldn't use the classical annotation approach with some topic/filter static value since every new instance of the component needed to be registered as listener for the module creating it. #### Enter the Station The solution I found was to mimic a network of radio stations. For those familiar with [RabbitMQ](http://www.rabbitmq.com/), the architecture is loosely resembling a [DirectExchange](http://www.rabbitmq.com/tutorials/tutorial-four-java.html) where the event class is the binding key. ![alt text](https://raw.github.com/torakiki/event-studio/master/src/graphics/event-studio.png "EventStudio diagram") #### In a nutshell `Listeners`s registers themselves on a `Station` for a specific event class and publishers can broadcast their events to a `Station`. ##### Additionally * A `Supervisor` can be registered on a `Station` and it will be notified of every message going through the `Station` before handing it to the `Listeners`s. * Publishers can broadcast to all the `Station`s * Undelivered events are stored in a queue and delivered as soon as `Listener`s for those events register. Features/Characteristics --------- + Minimal dependencies ([slf4j](http://www.slf4j.org/)) + Thread safe + Fully unit tested + Fully documented + Super simple API + Any pojo can be an event + Programatically add/remove support to add/remove listeners to/from a given station + Annotation support to add listeners to a station with runtime name (any pojo can be a listener) + Broadcast to a given station or every station + `Supervisor` of a `Station` to be notified of every message going through the `Station` + Enqueue undelivered events and deliver them as soon as a listener registers + Strong/Soft/Weak listeners reference support + Prioritize listeners to enforce an execution order + Quick and dirty, super simple veto system + Helper methods to completely hide the `Station` abstraction and behave like a traditional pub/sub event bus + Strict event class matching (i.e. child events are not notified to listeners registered on parent events) + Singleton pattern provided but **not** enforced #### What is not there + Async listeners execution Maven coordinates ---------- ``` org.sejda eventstudio 1.0.5 ``` Examples -------- ##### Assuming the following: ``` public class ParentEvent { } public class ChildEvent extends ParentEvent { } public class ParentListener implements Listener { public void onEvent(ParentEvent event) { System.out.println("Got it!"); } } public class GenParentListener implements Listener { public void onEvent(T event) { System.out.println("Got it!"); } } ``` ### Add listeners Add them without specifying a `Station` name for a traditional Pub/Sub pattern, hiding the `Station` abstraction or add them to a specific station. ``` import static org.eventstudio.StaticStudio.eventStudio; ..... public void initListenersTraditional() { eventStudio().add(new ParentListener()); eventStudio().add(new ParentListener(), 1, ReferenceStrength.SOFT); eventStudio().add(ChildEvent.class, new GenParentListener()); eventStudio().add(ChildEvent.class, new GenParentListener(), 0, ReferenceStrength.STRONG); } public void initListenersWithStation() { eventStudio().add(new ParentListener(), "MyStation"); eventStudio().add(new ParentListener(), "MyStation", 1, ReferenceStrength.WEAK); eventStudio().add(ChildEvent.class, new GenParentListener(), "MyStation"); eventStudio().add(ChildEvent.class, new GenParentListener(), "MyStation", 0, ReferenceStrength.STRONG); } ``` ### Add a supervisor Define a supervisor: ``` public class MyStationSupervisor implements Supervisor{ public void inspect(Object event) { System.out.println("All good!"); } } ``` And register it: ``` public void initSupervisor() { eventStudio().supervisor(new MyStationSupervisor()); eventStudio().supervisor(new MyStationSupervisor(), "MyStation"); } ``` ### Remove listeners ``` ParentListener parentListener = new ParentListener(); GenParentListener genericListener = new GenParentListener(); .... public void removeListeners() { eventStudio().remove(parentListener); eventStudio().remove(parentListener, "MyStation"); eventStudio().remove(ChildEvent.class, genericListener, "MyStation"); eventStudio().remove(ChildEvent.class, genericListener); } ``` ###Broadcast Broadcast events without specifying a `Station` name for a traditional Pub/Sub pattern, hiding the `Station` abstraction or broadcast them to a specific station or to all the `Station`s. ``` public void broadcast() { eventStudio().broadcast(new ParentEvent()); eventStudio().broadcast(new ParentEvent(), "MyStation"); eventStudio().broadcastToEveryStation(new ChildEvent()); } ``` ###Clear Clear a `Station`, events won't be notified anymore. ``` public void clear() { eventStudio().clear(); eventStudio().clear( "MyStation"); } ``` ###Veto Every `Listener` is allowed to veto the event it is listening for by throwing a `BroadcastInterruptionException`, broadcast of the event will be interrupted and lower priority `Listener`s won't receive it. ``` public class VetoListener implements Listener { public void onEvent(ParentEvent event) { if(some condition){ throw new BroadcastInterruptionException("You won't get any!"); } System.out.println("Got it!"); } } ``` Annotation -------- Any annotated pojo can be registered as a listener. Use the `@EventListener` annotation on a single parameter method. ``` public class Foo{ @EventListener private void onParent(ParentEvent event){ System.out.println("Got it!"); } @EventListener(priority=1, strength=ReferenceStrength.SOFT) private void onChild(ChildEvent event){ System.out.println("Got it!"); } } ``` and add the pojo to EventStudio. No `Station` is specified, traditional Pub/Sub. ``` public void addAnnotated() { eventStudio().addAnnotatedListeners(new Foo()); } ``` ###Annotation+Station with runtime name You can specify the `Station` name of an annotated method or the `Station` name for all the annotated methods of a pojo. `Station` names defined on annotated methods have precedence over the pojo `Station` definition. `Enum` and `String` values can be used as station name. ``` public class Foo { @EventStation private String station = "MyStation"; @EventListener private void onParent(ParentEvent event) { System.out.println("Got it!"); } @EventListener(station = "AnotherStation") private void onChild(ChildEvent event) { System.out.println("Got it!"); } } ``` And finally, also methods returning `Enum` and `String` can be annotated to retrieve a runtime value for the `Station` name. ``` public class SpecializedComboBox { private String moduleName; public SpecializedComboBox(String moduleName) { this.moduleName = moduleName; } @EventStation private String stationName() { return this.moduleName; } @EventListener private void onDisable(DisableEvent event) { this.setEnabled(false); } } ``` and add the pojo to EventStudio: ``` public void addAnnotated() { eventStudio().addAnnotatedListeners(new SpecializedComboBox("ModuleA")); eventStudio().addAnnotatedListeners(new SpecializedComboBox("ModuleB")); } ``` and broadcast event to the module: ``` public void disableModuleA() { eventStudio().broadcast(new DisableEvent(), "ModuleA"); } ``` ###Annotation and inheritance ####Station: annotated field Any annotated field (public, protected, default (package) access, and private fields, but excludes inherited fields) with the `@EventStation` is discovered and used as `Station`. ####Station: annotated method Any annotated method (including protected, default (package) access, private, public declared by the class or interface and those inherited from superclasses and superinterfaces) with the `@EventStation` is discovered and used as `Station`. ####Listeners: annotated methods Any annotated method (including protected, default (package) access, private, public declared by the class or interface and those inherited from superclasses and superinterfaces) with the `@EventListener` is discovered and used as `Listener`. ####Inheritance In case of overridden methods no funky logic is applied trying to guess what the user intentions are, if you override an annotated method (either with `@EventStation` or `@EventListener`) and you want it to be discovered, it has to be annotated as well. In short if a method is overridden, annotations are not inherited. Consider making your annotated methods as final to avoid subclasses to override them causing unexpected behaviors. ``` public class ParentListener { @EventListener public void listen(String event) { // do something } } public class ChildListener extends ParentListener { @Override public void listen(String event) { // do something else } } .... eventStudio().addAnnotatedListeners(new ChildListener()); ``` In the previous case no listener is discovered because the annotated method is overridden. ####Method invocation Annotated methods are reflectively invoked using dynamic method lookup as documented in The Java Language Specification, Second Edition, section 15.12.4.4. See the [javadoc] (http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/reflect/Method.html#invoke%28java.lang.Object,%20java.lang.Object...%29). event-studio-v-1.0.6/build.gradle000066400000000000000000000052641305060074600166760ustar00rootroot00000000000000apply plugin: 'java' apply plugin: 'maven' apply plugin: 'signing' apply from: 'http://tellurianring.com/projects/gradle-plugins/gradle-release/apply.groovy' group = 'org.sejda' description = "A simple even bus implementation providing pub/sub event exchange between components" ext.isReleaseVersion = !version.endsWith("SNAPSHOT") sourceCompatibility = 1.5 targetCompatibility = 1.5 repositories { maven { url "http://repo.maven.apache.org/maven2" } } dependencies { compile group: 'org.slf4j', name: 'slf4j-api', version:'1.7.22' testCompile group: 'junit', name: 'junit', version:'4.12' testCompile group: 'ch.qos.logback', name: 'logback-classic', version:'1.2.1' testCompile group: 'org.mockito', name: 'mockito-all', version:'1.10.19' } task sourcesJar(type: Jar, dependsOn:classes) { classifier = 'sources' from sourceSets.main.allSource } task javadocJar(type: Jar, dependsOn:javadoc) { classifier = 'javadoc' from javadoc.destinationDir } artifacts { archives sourcesJar archives javadocJar } release { tagPrefix = 'v' failOnPublishNeeded = false failOnCommitNeeded = false } signing { required { isReleaseVersion } sign configurations.archives } uploadArchives { repositories { mavenDeployer { beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") { authentication(userName: sonatypeUsername, password: sonatypePassword) } pom.project { name 'EventStudio' packaging 'jar' description 'A simple even bus implementation providing pub/sub event exchange between components' url 'https://github.com/torakiki/event-studio/' scm { url 'scm:git@github.com:torakiki/event-studio.git' connection 'scm:git@github.com:torakiki/event-studio.git' developerConnection 'scm:git@github.com:torakiki/event-studio.git' } licenses { license { name 'The Apache Software License, Version 2.0' url 'http://www.apache.org/licenses/LICENSE-2.0.txt' distribution 'repo' comments 'ASLv2' } } developers { developer { id 'torakiki' name 'Andrea Vacondio' email 'andrea.vacondio@gmail.com' } } } } } } event-studio-v-1.0.6/development/000077500000000000000000000000001305060074600167325ustar00rootroot00000000000000event-studio-v-1.0.6/development/eclipse/000077500000000000000000000000001305060074600203565ustar00rootroot00000000000000event-studio-v-1.0.6/development/eclipse/checkstyle plugin/000077500000000000000000000000001305060074600237735ustar00rootroot00000000000000event-studio-v-1.0.6/development/eclipse/checkstyle plugin/checkstyle.xml000066400000000000000000000105431305060074600266560ustar00rootroot00000000000000 event-studio-v-1.0.6/development/eclipse/checkstyle plugin/suppression.xml000066400000000000000000000003611305060074600271070ustar00rootroot00000000000000 event-studio-v-1.0.6/development/eclipse/code_format.xml000066400000000000000000000716541305060074600233770ustar00rootroot00000000000000 event-studio-v-1.0.6/development/eclipse/codetemplates.xml000066400000000000000000000017611305060074600237360ustar00rootroot00000000000000event-studio-v-1.0.6/development/eclipse/eclipse_compiler_settings.epf000066400000000000000000000070611305060074600263140ustar00rootroot00000000000000#Tue Jun 25 15:48:31 CEST 2013 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error file_export_version=3.0 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=disabled /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedImport=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.source=1.7 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.compliance=1.7 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error @org.eclipse.jdt.core=3.8.2.v20120814-155456 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.fieldHiding=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.assertIdentifier=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.emptyStatement=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=disabled /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.enumIdentifier=error /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error \!/= /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedParameter=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=disabled /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=disabled /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning event-studio-v-1.0.6/gradle.properties000066400000000000000000000000611305060074600177610ustar00rootroot00000000000000version=1.0.6 sonatypeUsername= sonatypePassword=event-studio-v-1.0.6/settings.gradle000066400000000000000000000000421305060074600174240ustar00rootroot00000000000000rootProject.name = 'eventstudio' event-studio-v-1.0.6/src/000077500000000000000000000000001305060074600151775ustar00rootroot00000000000000event-studio-v-1.0.6/src/graphics/000077500000000000000000000000001305060074600167775ustar00rootroot00000000000000event-studio-v-1.0.6/src/graphics/event-studio.png000066400000000000000000000605571305060074600221500ustar00rootroot00000000000000‰PNG  IHDR0»{¤]sBIT|dˆ pHYs ë ëåÖDÒtEXtSoftwarewww.inkscape.org›î< IDATxœìwtU‡ŸmÙ4ÒHé „Nè zS"J/PE)‚ E±+Š~¢±ˆ ‚t¤ :ɦ÷Þ“móý²fITð>çäœÝ™{ß$3¿yï[d’$I@ ÜBÈÛ@ ‚E@ ·BÀ@ ¸åF Á-‡0@ n9„€@pË!Œ@ ‚[!`@ Ür#à–C@ ·BÀ@ ¸åF Á-‡0@ n9„€@pË!Œ@ ‚[!`@ Ür#à–CÙØ‚ë ×SðÆHÅÅm‰àPuë†å=÷4¶Ám‹L’$©±ÕcLI!ýž{Ðzx4¶)‚À¦°§ßol3‚Ûán¬­‘ìíÛ Á q"¥>>mŠà°MIÁiÇŽÆ6CÐÀhu:~þíO~Úñ'Q±‰$¤fQ¢3 “)@&3ßY’@2àêh‹‡‹þÞ<:õ~ºth×8Æ×€”´ ¾üö';E\rɹHȑɕö•$# îÍíðrs¦S»V<5c*Nu³.Œ@ÐÄæÖD˜ÿƒ‘V¯gÃæD'g!É*ßÐk‚•’Ö^,œõýzu«c+ožÔôLžYö.‡O#-§¨JÁr=$£o;zvnÇKógãæÒ¼V6 #4q„€¹5æ¿Ã¦ŸwðÁ_•˜^ª›ÐR+•Œ¶-ø|ÅK´ðp¯“1o†R­–§_YÁŸýMJV!Èjÿý$Ɉ‡£ ÃîêÅÏ>…\~scŠ ^@ n£ÑÈSKÞ`Ñò•\LȪ3ñP¬“8~>ŽSç‡m“ŽŸ”šÆ°IòͯûIÉ.®ñ “ÉIÉ)fíæ] Ÿ<‹ÔôÌ›G@ nܼ|FN}Œ¿î£ ÄP?“Èd$eñôóÔ‹oÔÏÕ°ï¯cŒœ6‡ˆ¨¤z’ IƉ ñ ›ò;÷ÿuÃÇ #Ô¼¼¼Æ6A 4ŠKJ5m6GÏÅ¢—ÊsçL½—ôÛH?± ;7Ôé|yEz6mßÏÂWVÔé¸ÕqàÈ }vñé…¦Àã½?2}¿WæÍ¨»Éd2âÓ xêå·9ñÏÙ:T dddбcÇÆ6C 4&ÏYĹ˜4du´¤R´ønû^Þû|m½ÎŸ”Â/¾Izž¶^繚”ìbf.ZJ\BrF ¨ñññ¤¤¤ðÄO0jÔ(Dì»@ðßäéWßæÐ©K7•…S[ K¬\÷#¿ìÜ[?ã1yÎbâÓóëeüë—VÀÄ9‹(.)­Ñþ¢à¶@§ÓÃåË—)**bìØ±5:®´´µZmz¿oß>Ôj5ü1gÏžeĈ,]º”ÒÒR<==:t(ýû÷Gvu= ‘ÑëõìÝ»—””BBB ½é쎚rôèQ¶mÛ†ÑhD’$ŒF#ǧOŸ>u:F£áìÙ³Œ5ªNǽQþ:v’Í4-5Ù…:Þøð ÷ë]çÅáž}ã}ÎÆ¤6¨géj.Æ¥ó›°bÉÂëî+<0‚[­VKPP­ZµâÑGeË–-dfVÑž››Ë¹s瀲 b÷îÝ0` `çÎìÙ³‡ððp¦L™ÂÎ;Ùºu+'Ož¤gÏž¦‚µµuƒ}¿º@ne…ÊÓ…£#2eÓ{f‘[Yá4mö¢sóMsöìYBBBøá‡¸té ,àôéÓõ>ï±cÇØ¹s'ÁÁÁ„„„о}{\\\ê|ž .ðõ×_×ÉX§OŸ¦  à¦Ž]úÞ*² jæ¨O.'¤ó껟Öé˜ñ‰Éìùä´Z-K–,aúôé<÷ÜsÜ}÷ÝÄÇÇ3fÌŽ;F`` þþþ 4€éÓ§³qãFBCC "22²Á¿ãÍ oÖ »aðí׹Ϳ$ ]b"%gÏ’»u+Æ r oo..hcb0deÕ™-(ÐFFb¨"Z¦Vc{×]è’’Èݼ¹Îæ½Q”Í›£nÕ ??,üüPºº‚\Nö×_StäH£ÙUV®\ÉìÙ³yê©§*m+--eÅŠœ¹\ŽB¡ 00©S§šÍyàÀÖ¯_ϧŸ–Ýdu:wÞy'»víB©T²xñb~ýõWüýýyì±Ç5jz½žþýûsß}÷ñÅ_àïïÏòåË áùçŸ'!!þýû3tèP/^|ÓçêèÑ£Œ3†îÝ»3qâD†Š……ÅuûmÏÎE'Þô¼u‰9[vîgîŒ)uÖ‚`Ñkï’–SR¹Zp#š]̼—ßâûÏß½æ~Â#¸¥¸té@§Ó™> "** I’HNNæÀèõzüüüX¸ð_7ä_ýE¯^½0:tFÃܹsyì±ÇÈÏÏçôéÓš-)µnݚ˗/бcÇyª­-r++Ü—,Ánøpd*ŧNQ°{7EGŽ ‰AåáA³!CP67¯‚i†ËO`ÙºuÚc7b.O<…Ÿ_Õ;òòÌÄTcÐlȚϜI³ÁƒQ·l‰ÂÁ…²zèáR×xxx°cÇþþûïJñY?ü0,\¸˜˜&L˜@LL O<ñùùùÌ™3‡Å‹3eÊHxx¸i?I’þøcÞxã îºë.öìÙS+ñ0cÆ ._¾ÌŒ3غu+mÚ´aæÌ™ìÙ³çšÇ½ûÙ:ŠJµš».ILÏãÓµßÖÉX1ñ‰œ<Ù$Ä 24qdde_s7áÔ9’$QTT„MÅ'ÿäðáÃèt:z÷îBQ,·xñbvíÚEXX³fÍâ믿¦C‡ñàƒ¢R©ðôô$00öíÛ3vìXÞzë-~ÿýwÌÑ£GéÑ£VVVØÚÚòÈ#€¥¥%ééé&ÁHTTcÆŒaéÒ¥ :”Î;³lÙ²›þ~õ‰Ãý÷£tqAKÚ›ob,,4Û®°·Ç¦woŒEEd¡9†¼<Ÿx¢±Í@Ÿ–FÁÞ½hcbÐÆÄà8q"êààÆ6«FÌ™3‡ââb“gdΜ9<õÔS( 6lØ@\\^^^´lÙ233Q(øûû³`Á† ‚½½=ƒàÉ'Ÿ$))‰¤¤$ÒÒÒ=z4z½ž±cÇòì³ÏòÌ3Ï —ËÉÈÈàØ±c( är9;wÆÇLJ‰'²nÝ:.\Èúõë™VVVõvk‹e›6ä|ÿ}%ñ`ÈÍ%oûöZÍ!³°(‹©Q(Ч¥!éõµ¯¦s*]]1dd`,)¹¡cööÈ,,Ðgd”5Ы‚ü+qPåH5¼a6xíµ×xíµ×8yò$?ü0®®®ÜÿýØÙÙáéé €££#ÎÎÎdff"—ËiÙ²¥i gggÓ~åcfgg“’’‚^¯gýúõÈårär¹Iä” –wÞy§’M=ô÷Þ{/3gÎdÿþý¬[·([Òrww§eË–ÈårÚµkGHHÖÖÖØÚÚš^›æ©©€ £¨¨È´,ŽB¡ÀÑÑÑ´Orr26là믿ÆÙÙ™… ^¥xøaÛï¤å “7­[ftb I)´ð¬]«ÿœkRâÊÚŸ #¨rrr8sæLµo¼ñjµš3gΠT*ÑW¸©]¾|™ñãÇSRRBzz:_|ñ£FâÈ‘#,[¶ŒÏ>ûŒ—^z‰^½zÆš5k())!((ˆ¼¼<.^¼ˆÑhdäÈ‘”––¢P(ðóóC’$‚‚‚8|øp•6õë×777,X@¯^½LŸøá‡<õÔStîÜzõêÅsÏ=Àwß}gÊÞP*•üþ»yïfÍšÕê<Ö7Šò¥!cÍÜÝ2• ¯>0-•8M›†ã•§e€ì¯¿¦ðÀìFŽÄºkW,|}ÿu7h££ÉZ¿í  prÂãµ×]¹‘8ÏžTÁ¦ÌU«(>u …Ë—£ON&eéÒJöY¶m‹ã¤I¨<<Êæ”$ôééälÚDÑñã•öw{þyT^^¤,Y‚eëÖØòŠ5“óÍ7ìÛW£ss+ʘ1c8uê?ü0:uâÔ©S„††¢Ñh(((À××—øøx3QpµHËåFÚ·oOvv6K–,ÁÁÁ<ÞâZ¢uëÖ8::²`ÁFŒa **Šgžy…BV«¥´´r`lE¯‹¿¿? 5úþ½{÷6{_.¶ÊyóÍ7ùꫯ˜>Þ$ô:ĸqã0FÂÂÂxì±Ç€²x“Y³f±£BSË%K–0mÚ4¼½½iݺ5©©©¬]»–Î;›]3 …ÉÓéççG×®]éÙ³'wÞy'o¾ùæMŸ«x€§Ÿ~ú†ŽIͬ» öºD&WpᲦVc\¸EJf.M1$6¿¨”øÄdü}ZT¹]˜Û˜óçÏlvQ¸t:{÷î5eüþûïœ={–°°0š7oΦM›Ìöê©§xàèС 8Ñ£GcccÃßÿm ÈëÕ«­ZµâàÁƒ ª$ÙºukŽ=jz_ƒ2uêTÚ´iÃO<Á”)SÐét¬ZµŠ/¿ü’   \\\øì³Ï 00Ðä’hß¾½)}úVÃh4’œŒ¼†Þ€ü]»pš6 ë.]°|ÿ}ŠŽ§øäIJ£¢0æW.P% d­YƒÓôé¨<=)2>úˆ¢ ÂY‚ë¼yØ NááÃèªx:·½óNR—-C«ù÷o{×]8M›†Ý¨Q·•€™6mÛ¶mã§Ÿ~"$$„]»vÑúJ0ö„ èܹ3Ìœ9“6W–CCCM"Ê„NÅkÅ·ß~‹»{ÙÒÄË/¿Ì„ ˆˆˆÀÎÎŽ;î¸(‹›ñ÷÷G©T¢P(P(¸ººšÆ˜>}:Ó§O7³ÕÞޞ͛7SRRB~~¾YÚuFÆ¿žWWWΞý·´ü'Ÿ|RÛÓpSiÞÅUxˆš ™9µkq’–‘E©N\qýL¬†&¯¨˜È˜x!`þ‹L:•uëÖ™Ý̯&;;›ï¿ÿžüü|BCCMEÚŽ9Âã?Nß¾}Q©Tx{{sß}÷±|ùr¾ûî;œœœ*ÎàÁƒÙ·o/^äwÞaÿþý¬\¹ooo²³ÿ(W(` ’`ãÆ¦÷ƒh·lÙÂÇÌ—_~‰›› .4¹´:TëóÕ”?ÍÆÆÆKLLŒéull, ØXY±%$¿ŽY°grìGFncƒm¿~Øöë’„V£¡ðÈòwí‚›ˆñ¨¸DT‘¢cÇÐÆÅaáç‡ÜÖ¶N2Šš ŒL­¦èÄ 3ñPzáû÷Ó,, »#È\µªÒñù¿ýf&^ öíÃaÜ8,¼½A¡¸©sÐiÓ¦I˜TE«V­*•°··ÇÞÞÞô¾bü €¯¯¯ÙûJ×777SŒØbiii žoÊFJµõãu³äTŽs»’·pݵ$9§ÏžgнªÜ.ÌmLpp0QQQ¦‹Îùóçùæ›oHIIaÒ¤Iôë×yóæÑ©S'<==Y¶l™™™Œ;–M›61{öl¦M›ViÌÈÈHºwï^圶¶¶ >œáÇ3dÈú÷ïÏÊ•+™7oo¾ù&kÖ¬áÒ¥KDFFÒ£G,--±±±!-- WWW‚ƒƒÍ‚íî¿ÿ~S ŸÏ<óL=­ú¡  ÀL\ý“ššŠ‹‹ ¾¾¾¦Ÿnݺ1vìXÓ{Û¢"Ò'N¤ÆÏ€’DÞ/¿P°w/V;bÕ±#þþ(± Ä"0›^½H{ûí›2¥˶mQ8;—Ç^YŸ–_‰qPº¸ ­£º›PTÁ#W‘¢#Gh†êªo9%UyÝ  YYÈ==Q:9¡OO¯µÕ‘@ÓûŠÕ›oôum¯Ë±š’- ñ½ô#)™FPÝ|VåàÚܑޭƒ°µ±âÏC'ÈÍ¿¶@9þù„nݺ1mÚ4ºvíj*æV•€)((@§ÓáèèHqq1ß|ó  `âĉlß¾V­ZáææÆêÕ«ñðð`íÚµ¦”kwww6lø·“kMì“ÌÌÌk ”ÜÜ\¼¼¼ÌJXX~~~øúúâíí}ݧЛMw6æç—-] Àµ Ù AXw¿?Ž'’YMPuX÷ì‰ãøñ(ª/ž¥¸*FéfQ]y²7TSYYe¹AYaÉÂl{5Åø¤+˲j2Nê ^¼’¢ ˜Õg¹Ñ×µ=¾.ÇjJ¶4Ä÷2JšßŽPÜ%`Nýú^nÿ.qÝ5ñqr/^;ÆÅÚÊ__ß›>/Ù%qùyPÏ^˜í_½M—v­HJÍ ¯ @_²ró™6ÿŸ¬¦ µdÄûVBÀ4 ©©©8p€{ï½·ÆÇH’Daa!666&å|êÔ)V®\I||<;väñÇÇËË‹ÂÂBúõëÇêÕ«qvvfòäɦ¥ž?þ˜™3g2wî\³ñ;Æ‚ èÖ­={öäí·ß¦´´”Þ½{Å¥K—8|ø0ãÆ#**Š;ƒ2qâD ƒ©F ”-G•¯ÛØØ0nÜ8Þ{ï=T*•ÙÒPEÊENS£¼0ÞµŠÁ`ÀÇÇÇL téÒÅôÚËËËì5&Z†ÌU«Š‹±0ëîÝÉüßÿjœ­¤ ¤ùŒHZ-Yk×Rræ Æüü²”fIÂeî\¬BCë®Ö•qªmœYþyS)¾u¶¶¶•â?·&ûÏ=ÀùØ´ëïXKÖÿôÿ\ˆÂÝʼn·Ÿ{¼FÇ„vêÄ{ï½qÓs?}†Q-D_Ïýiwì=œ%ï[¯àãÉ/_¼ÅÊWÐydÕ©Ò ¹ŒÕ/QÖ¹€)1èÙ™Å_é±äiKдh :ä29 *¹ µBE7g¸ାµúÊÔ†ììl^zé¥k ˜¼¼<¶nÝÊØ±cÙ¾};óçÏG¡P`aaÁæÍ› âôéÓL:•V­Z±iÓ&–.]ʪU«¸|ù2-[¶¤ÿþ,X°€o¾ù(óôëׯÒ|ëׯgÖ¬YŒ?žË—/£×뉉‰ÁÃÃNGË–-‰ŒŒ4æ?žÍ›7Ó»woî»ï>³ÒåÞÞÞÄÅÅÕá«_t: f‚¤b J||¼©LùO@@ 0½w­æé¿)Spà¶ S*Q::¢¯ÆÃq5Ö=z S(ÈÞ´‰‚Ý»+mWÖq}j*JWW”NNh+ÄI™æ»’.^ŸË@€}³†Y>ZñyÙõzXÿž5;@’pv²¿þ~×ÀÏÛ ‡fVdäÕo ò{«Í«kâ’øzËï<ùÀý8;9‘•Sé;[+<ݪ¿ÆÖ‰€)1èù:ú4Ç3bÉ+ÉÅÚ‡½Üˆ5P<Ù•}‘Ÿ5¶(U¶ø6såñ^·½˜ñ÷÷'..Ž””>øà<==;v,îîîüõ×_<ÿüóäææ2lØ0²²²˜:u*{öì¡sçμþúë<òÈ#ìÚµ‹iÓ¦‘žžÎš5k8räÛ¶mã­·Þ"%%Å,£Çßßß´„Ô¡C~øá¦L™bfS`` k×®E¯×³jÕ*ºvíŠF£A.—›¼,4-ë¨Õj~ú駆;iµ ¨¨ˆ¸¸¸*ƒccccINNÆÙÙÙL tîÜ™1cƘÞW r¼](oè(étèsþ½h”‡«n Hueɯª%¥³3Ê+Û¯Fº2®ü—–t‰‰X¶oUÇŽ;Vi»UçÎè“®ßôM ¨ ®Í д¼}j¥Œ±#kWöÁÙÉ‘fÖ–õ.`ªÂÚRMqI)ÙÕdRy:;âíUõuj)`tF#ÿ‹:ξ¤ Øë³°—KØAÒÉà@è ÈÉLቿbñµ÷â‰;ð°²­YMµZ½½=&Là ==pæÌ<==ùóÏ?ùûï¿ åôéÓØØØÐùÊEzÖ¬Y,]º”ââb.\¸Àƒ>È¢E‹˜2e ÇçÒ¥K 0€Gy„ÔÔTÜÜÜ8~ü8111FfÏžMÏž=™8q"ݺuã?þà£>bÖ¬Y¸¸¸ÀêÕ«qwwÇÆÆ¹\α*nM‰œœœ*…IùOvv6žžžf¥ÿþ¦øŸ[" âFqž3‡‚½{)9s¦Rº³L­ÆáJyvmT”YNy]‹ §Ñ_É"³îÙÓ,Z¦Tâ8q¢)˜÷j*Ž[SòÿøÛ±îÙ“‚½{Mõe ,À×ö®»Ê–+ÔêƒÇá·SÚÄ’Ö¼ÜèÕ%´Öãûµ :%·,ª9>žL¼{0kÜ¡šeì ¿ªÓ§Ë¹i³+%ŠÕ—ÓL—‰ÌP«8–2ð–r)ÉÎeá‘Dzy´av«ºÐn1éÙ³§©{ëÁƒÙ¼y3÷Üs¦ÒÞîîîFJJJ°´´D­VSRRBii)üñ÷Þ{/ãÇ'%%…ØØX4 ]»våù矧ÿþ´jÕ ¥RɈ#ÈÉÉÁÕÕ•þù‡Í›7SXXÈÛo¿M@@€©i[SB’$RSS¯¢Õj+ÅŸtêÔÉ,þäfkàÜÊXuè€u×®è32ÐÆÆ¢ONFÒjQº¸`Õ¹3rŒÅÅd~õ•ÙqÅÿÃý÷cݽ;žeõ^ †21tî…bÛ·/6={¢pp øÔ)ä––XwïŽÌÊ ­FƒÅ•¿©Š;†ÝÈ‘4 ê];´qq`4’·cGµiÙúÌLò~ùû{îÁuÑ" öî5²³é×¹¥eYï¢kŒq#¨ƒ‚p¬u§º²$æN³!C0dg“^EÙ|ÁíMïn¡øz4çRBÍ–[ _O7ŠÚßN»ÿnö;‹¶šƒ-_½õÉi™, @Ê IDAT[¹¶Ê}”rãu½K7uuçüAN&Ÿ¡…¬ÈäQs¶vÄZyl Œhõ:J ZòJ ¸:fÈB^R.ÿ$ãÑœ–w†½ª~3š   Sq(€>}úAxx8~~~deeaccƒ››Æ ãƒ>`þüù¬[·ŽvíÚáààÀ¨Q£8p 8p€ùó盺3Ϙ1ƒéÓ§£Ñh*Õ}°µµ55Tklôz=‰‰‰U “˜˜âãã±°°0'¾¾¾ôë×Ï,þäêtAdó Ö;£nÝkgg³m’Á@áÁƒämÛfVmʲzÒß}»‘#Qyx`Ý¥ Èd”œ?çÎQzñ"™_|ã„ X¶iSÖsI’ÐÆÅ‘¾lãÇW)`´qqd|ô͆E鿆u×® “QtôèuÅGîæÍèSRpœ2…faa¦Ï%%d¯[WVϦŽYY•Õ‡¹ …“Š+ÁðzëÛ{™[P52™Œ­ƒ¸ŸÑd‚Æm-Ìš:®NÆ ëÓ o7¢’*Ç¡Ô56ÖVlüp)ÍlmùàBŠŠ«îkäåÂÀjê¿”sC¦Ä gÞñmè ãð”™öØ—6Î5K_J|~*ÿ¤^ädÚt†Çsé)-ŒfÆ¡oy%t8­ìœ¯1Ò­E`` ›7o6ei4SæN@@—/_6¥/Y²„É“'óÁвeK~øá ¬ZmDD—/_æý÷߯ԀL¥RU/ MII‰)þ¤ªÙ¤¤$œœœÌÄI‡5j”éýÕ}W5£`÷n vïF¦R¡hÞ¥ƒÈdè³²0df^³µ@ÉÙ³”œ­&¥( ¸ƒ.îä\Æ¿™jø3yîïm|Ôs,î– ^ßòÏ?ÿ0yòdœ9yò$Ï_¹àöêՋ ݃ª­0ëääDuóÇ{3äååUKff&f¥oß¾L™2ÅÒ”;:ßH:ú””Jž–Z«Õ–-/5$’T&\2šfÓ9Áí›KsFê˧ßüŠñ:Á¼öÍøëÇÊÕ¡¯Å©ó®[Ô­G[ ^^0û†Æ¿óίàLtêu÷?j ût­ñ؇Nœá™7?aíÛ/ÐÒß›Ñ3_}ð}ˆŸŽ¿î¸50¯Fì†Âxlê¡Ö­…5ÓÚfËåÝJ8eú\ø³˜{t ÿë=–fʦ׫áFéܹ3¯¼ò =zô >>ž·ß~ÛT'dÉ’%lÝ¿¤¥¥]3þ¤¸¸¸RüÉÈ‘#M¯[´hñŸŒ?·/ÏÍ}„]Žr1þÚ±0 ¹œ ßk VuL×ö!Ø5³¡CHÝ;´Æµ¹#é™9D\,{À—a¤Oç¶„¶k}s_¢är9/Î{”‡½F^ѵ['8ØÙâ`Wód›Ø„V½ö4ý{†²ôƒ/ñötÃÛóßú.ÇNŸ'¿°¬`§“­š…³¦Õ(< Fw˜âΕ~7yÍ#|~¼¸ËÌ£e¿ 'K{\¬éêÑ;óô¨ÑAýI)È@“óoc6¥ Üõ©Ì;þ Ÿ÷¼¾"kêš:µvéÒ¥Ql0 $%%]S (•ÊJñ'}úô1½vssñ'à?……JÅŠçç1cñ«¤d×ùø¯ÌŸA×öÿö›Z¾¸ì^±}Ïa¦Î$‰Ž-½XùFý<ìöïÝ1ƒú°qÛ^J븲]ï.í‘Éd¼8÷ÁJÛMy’Sç.c¥’3ùžÁ ½«oÆ”IÕ–¹,#WWÊãmÄÃpívâÓÚ6‹ÙpöWN§]¬~b ›g{Â[ 4sÆÅæ&³òïÊ[S%5÷‡ d¸gËkÚ!€ÒÒR³WÇ¡$&&âààPI Tü©ØHиSRÊz!ùø4¶)‚À6%'‘â}[òãö<óÆÇdhtÞ@~þê\›×ë<Óæ>ÃŽ§0Ö&½ø‘#1ôŽŽ¬ùàõëï|…ëz`Þ=w}V×ï‘€£IxÚºÐË«£és_{š[9Yl í&+emä1¹¡’7ÍΙ ÅÕ ¯ŽCIOOÇÝÝÝLôêÕ‹ &˜âO¬E6…@ ÜáÃ’œ’Æ;_|K^qtª–$üÜíùtù õ.^V¿ócg<ɡӗDÄ(åнmŸ¿½ôÆŽ»ÖÆôÒ".gÇÒ¢W ¶G ‡g{äI;ù’™X9ËQ—Áÿ"3«eÕoÊV [XXˆ···™@6l˜YüIÅŠ¼@ ¨[f?0O7^yï3âÓòë-½Z†‘öAž¬ÿè <\ë¶]Gu(r¾ûü]潸œm{\7&¦6ØY+Ö›·—,D~ƒÎ‰k ˜/ÂÕ˜[¯Õ“K ZÒ‹²q³ùWU:ª›U¹¯ÜÈ©ÌXàÖ0F£ñº e2Y¥%^½z™^»»»‹ø@ hdÆ £Gh{|êN]ŠÇPÇ)ÈÍ,ôíÒÏV¼ŒÚ¢a“X” ¼ú,}·þƲV“^Ç"M2âåÜŒù3'3eì蛳ñZã Òqn€ûäÕÆJU}A¼¢â,âŠòð±¾±¾* …N§«6þ¤¼A ™8 aÈ!¦÷å¤@дñtseÛºOXñéj¶þ±¨„ŒZ×R±¶ÑÊÏ“ççÎäΞ5OW®î5„ÞÝ:ñÂò9q‘ä¬ÕbYI’ðp²¡Wç¶¼òôãµZ«VÀ$ç£ÕæßôÀ7‚ʼˆÎX½»Ê‰"6hN²¸]åÎÊ AQQQµÁ±±±±¦>DJ÷îݹÿþûMñ'66·GM@ ”-¹,šý0ó™Îgë6±é—?ˆOÉ$¯H‹L^u°«‘IzÜ›ÛÑÂÝ™9L`ø€;ëÙêšãåîÆêw_%5=“¥ï~‘SgILÏAo”Q³% K•/Úû³ôé9x¹»]ÿ°ëP­€ù%ávÆÂZõ8ª)½/EºêÓÓ,e_Ŭ²³³« Ž%//¯RüÉ AƒL¯½½½Eü‰@ üQ)•Ì~`"³˜È…H ßÿòGœ#)-“âR-:­^Þ`ÄÖJ¥Z…­µnÍÖ—1Ãb׬é63vsiÎÇËž§¤TËÁ£'øiÇŸDÅ$–•N§G«7R¢Õ¡Tȱ¶´ÀÆÊ;[k‚ü¼÷PîèÖù†ã\®Eµ&2?Û/-|±¾jÉ(>ïÚ•Cµ†›K]+ox­ÆF£±RüI÷îÝÍâOêò ‚Û žòÓ{ƒÁHvn.YÙ¹è z¼Üݰ·«:Þ³©c©¶ ¬o/ÂúþÛ«¨¸¤”¬œ²²sifkƒ‡›K½ÇíT+`ô=õíGP+,o5Ðì3­A‡&'ñšÇi ¥U~®×ëIHH¨VœÄÅÅakkk&N‚ƒƒ8p é}óæõŸ¢&ܲfÍPÉå(“ª/½-hz¨BCÛAB¡ãì䈳ÓíYcËÊR—»[, Õ”jŒÎX¿¦­s £‚ûãhiŒ{ á$úkÄÀHÚR>øôÒÌ»'''ãââb&Pºté½÷ÞkŠ?±µmºî9 *d668íÜÙØfA“¢zÌuDÄõèéÕVÍýÌ>SÈ8YÙãb퀕²r¦QrA:{b]wl½ÞÀ7MBBF£OOOÆŽKëÖ­ $ €€€\]]kõ=@ 4=ª0jEíÖ®n¬‘U|^ k"~¦´ñ- ++öîÙ€V«%&&FƒF£!**Šï¾ûލ¨(¢££Ël¹"f* ›ÀÀ@|}}±hàÜzàF‘´ZŠ>ø©´ê¥SAÓDŠzøðÆ6C ¸m©VÀX©ÔÀ€¬’\þJ8Í„“¥šÍ¨”ÿk¶……-[¶¤e˪{$¥¥¥e8GeãÆh4RSSñòòªVàˆz,‚¦€1)‰‚o¾AçåÕØ¦në={„€ê‘jŒ#ç²Àú&n’ ÒÉ×™}f”Œ”èµëKH-Ì$./…¤üTn´çeUËOÕáêꊫ«+½zõª´­¤¤„èèh3sèÐ!4 ÑÑÑXXX˜ ›ŠÇÇÇ¥²Fͼ‚Úck‹Qê[‹”kgS ‚ÚQí¸»³7G,°ææR–wÇ»f7ê›E+o³ºéaiiIëÖ­iݺu¥m’$‘œœlZ–Òh4ìß¿Ÿ¯¾ú FCff&>>>Uzn°··¯@ T¦ZÓÅÉƒÒ é iÏuÉ,xÈ»M½Ï#“ÉðôôÄÓÓ“>}úTÚ^XXhw£ÑhسgQQQÄÄÄ`kk[¥ç&00-ZˆZ2@ðÀh4’’žABR ç/k¸‡µ•%î.ÍñtsÅÃÝ…v­Z¢Pˆ{ÂrÍ5;WгÒQ5¡¾¥m?³ÈÆÆ†öíÛÓ¾}ûJÛŒF#‰‰‰&aÅÎ;M¯óóóñõõ­Òs R½à¦°¨ˆ-¿ýÉÏ¿ï%:>‰ìüBò JÑÈd $$ŒH’kµ ·æöx¹9Ú.„ÇÁ§…gc…[‚k ˜Iþy-3в’†²çšH2º¹Ôgsì:A.—ãíí··7ýû÷¯´=//ÏÌsÉo¿ý†F£!..GGÇj—¦<==E'j@ h‚ddeóÜpäÔY’Òs‘äo±rdW<ï2d “#Jô›šGljO]曟ÿ cH /ΟEÛ–Aò=n®)`ÚØ;co뉮PÓ$¼09Šæ<Ö²gc›QkìììèÔ©:uª´Í`0g&p~ýõWÓë’’üýý«8þþþXYYU1£@ ê‹Â¢"^Z±’?#1=¯¬[³üÆ“w¤pæãn£Pܱ’$‰O½Í¡R©&88¸Êíéééf5oNœ8Áwß}‡F£!99OOÏjcoœëÍn@ÐðìܹƒÁÀ!Cj5NDDùùùH’„ÑhÄh4rÇwÔy¬˜˜š7oN³fM£ƒóûÿ[ÇGk §P@ÇÖAì\ÿ¾iû÷?Æù¨Ø:™+·HÏw۠վ§Ë_¬“1ojô&—Éx¿ÛhfþEi" ¨#dv¼Ði(N·vlGBBnnnlÞ¼™S§NñØcáéÙ°‘æ...¸¸¸Ð³gå8¢ÒÒR¢££ÍboŽ9b*ê§P(ªÍšòõõE¥ªïÞåÁÈÈH‚ƒƒYµj3gάÕXO=õ=zô`üøñ?~œ’’’Z ˜x;;;<<<ËåÈårºvíZçæ©§žâ‘GaèСu:îÍðÛž|úõf“xiô’Œ_÷çÅ·>âå…slÞ¦LÿÂÔ v¿›Y‡¤¹6¥Þ=1F f†ô£}Ý®kL.\¸@tt4´iÓ†òõ×_ÊgŸ}†R©$;;£ÑÈÂ… Ü>µZMHH!!!Un//êW.p:ĺuëÐh4dddТE‹jŽ£ãíÙ>^ ¨oÖ¬YÃøñãùâ‹/ÌLAAÖÖÖdff¢R©ppp0;.;;›œœ|}}‘Ë夥¥qîÜ9ŒF#–––tëÖ ¹\ŽÁ`àèÑ£\¸p1cƘy7Μ9ñcǸóÎ; 4{áÂ\\\عs'ãÇG&“ñÜsÏUŠÙÛ¿?mÛ¶5µdÉÈÈàâÅ‹ÜqÇú(óæÍà™gžaõêÕ“““ÃöíÛ1 ”””‘‘ALL mÛ¶E.—³eË4 >>>,^¼˜èèhÔj5ëׯçÍ7ßdÊ”),Z´///Þÿ}.]ºÄ„  dèСèõzd2deea4‘$ ~ÿýwöíÛÇsÏ=ÀÇŒ$IÜqÇ<÷ÜsìÛ·ððpÆǸqãxôÑGùý÷ßyÿý÷i×®ÁÁÁ„„„péÒ%‚‚‚&,,Œ>}úàîî^«sûÚk¯±aÃ^yåºvíÊäÉ“2dÈu½FF£‘ÇŸÄÌÂZÍ_òŠô|²îî>G‡ÿvÅ÷öñ© VtΆèÓl9Ž»”‡… R 3°TþZ +ºÆ(U#)’%ͼø¢ó0¬·Ï²ÄÅ‹ÍjÂ8;;sîÜ9Ó¶^xÁäÚ2dmÛ¶eÍš5¬Y³†‘#GröìYúöíKaa!>>>¼úê«´k×ÎlžÔÔTÜÜÜ8þ|•5hêkkkÚµkWÉ(»W,ê§Ñhؽ{7_|ñQQQäææâëë[mCͦ²Þ}+#·²Bá舱¸c~>’^ߨ&™!·¶Æá¾û0ää»eKc›2 {{dj5†ÌÌF;_þù§IäO›6/¾ø‚÷Þ{ø·ÖÔš5kHMM¥OŸ>Ì›7ˆˆV¯^F£ÁÆÆ†yóæñòË/ó¿ÿýÏTºá0áèèÈ×_ ”]‡öïßÏÀY¸p!üñíÚµC’$Ú´iCqq12™ŒÔÔT.\¸€¥¥å•Ó%cÁ‚ØÙÙ!—˱··gçÎLŸ>aÆ™ÌúõëÙ±c)))|òÉ'ÄÅÅakkˤI“1b>ú(r¹µZÍÆ2ÌŸþiòÄøùùUY~¢":ŽÌÌL ¬à¨R©$77,--éÚµ+]»veÅŠìÝ»— 60{öl/^Ì£>ZíØ_|ó§.ÄB#W#‹KÍaÁÒ|ñÎ+jGcsÓ‹”ý;Òß=€÷Î >?™-Q‡°¬Åï4]R#Yºðx«Þtk~ûuݽxñ¢YöÑ?þÈìÙ³¸|ù2wß}7™™™üõ×_lÚ´ [[[yäæÎKbb"^^^ìÛ·™LÆ… 9r$‘‘‘lÞ¼™çŸ;;;‚ƒƒ‰‰‰1ûG,,,¤´´´Á;lËd2Z´hA‹-èׯ_¥íùùùfq7†?þøFCll,öööÕ.Myyy‰ˆüj7k†ÝðáØÞy'r›7Hº„JÎ#÷çŸ1þû$iáãƒÂÙmL †¬¬:³Å"0…½=ÚÈH y•Ë1ÈÔjlïº ]bb£ ¹•Ö={bݵ+êV­•?‰Kº¤$rü‘¢'Ô¦¯¾úŠAƒÃwÜÁk¯½ÆòåËQ«ÕÈd2FŒ€››¥¥¥äååqìØ1îºë.l®üÎÃÃÃM×(ó ”#—ËéÝ»·é}PP†œœ222˜?>F£ƒÁ€­­-çÏŸG&“ѹsg“x)çÓO?­´„ˆ§§'û÷ïG¡PàææF`` û÷ïàÞ{ïÅ`0˜óòòÉd•lŠŠŠªÒþê8þ<³fÍB.—3qâDÜÝÝY±b …‚çž{Î,æ'##ƒˆˆΜ9CË–-MKeU¡ÓëYûý/è¥&L"“³ÿD'Ïœ'´]å^~ÿjeåiÕŒ7» #½´ˆ÷Ï$6/ôù8H%×íb-FZ¥=NÖLöîÀ÷[&¹•ˆ‹‹C­VóôÓO“‘‘Arr2#GŽ$55S:kkklllLÍ õz=jµkkk²³³ùøãIIIA­V£P(HHHÀÃÃE‹±cÇüýýY¾|9ëׯ§eË–H’ĬY³Ø¸q#!!!H’ÄO?ý„‡‡‘‘‘Ó¶mÛ-ãh4šZ¥€WE³fÍèØ±#;v¬´Í`0o&pvìØaz]TT„ŸŸ_µí­­ëÔÖ[¹µ5î/¾ˆÒÙI«¥øÔ) ÙÙÈ­­Qººbáë‹ÊÛ›ÂÐV0¶b{çd®ZEá_Õ™=ö#GbJÚŠΜ©¼ƒÑˆ!/c~~Íy£¨ƒƒqš6 C^º¤$Œùù¨Z´@åå…óã“»e ¹?ýÔ öäçç³mÛ6âããÙ±cG™j5›7ofܸqÈd2³¿o¹\Ž^¯§U«V¬_¿ÞôyVV–IlXXXPZZjvÌÕƒ{{{¬­­y÷ÝwiÓÆ¼ï܉'°°°0ûìZ•Á|ðA¾üòKÔj5S§NÀÛÛƒÁÀ?þhZײ©\´888W…¾š:pðàA³ÏÆŒcö~ãÆ¬]»–„„&NœÈwß}G‹-®9îûŸ¯ãR\Ð4š² t¼¹r5߬|«±Mi4ê$LÜEmÍ«UÍöÄ‹œÏI¡X_‚ΠGgÔc” (åJ,X©Ôت¬˜ìB_W_Tÿ§è . ÕjÙ²e ÎÎÎ|öÙgÈd2¢££Íºa[YYammÍÅ‹iÕª6l $$GGGf̘¿¿?³fÍ¢¸¸˜5kÖPZZÊ®]»L•xúô郇‡¶¶¶¬Y³†ýû÷“žžŽJ¥"%%[[[yá…P©Th4^|ñE ”‰¦ääd …)S*99™Áƒ›<> B¡ÀÏÏ??? Pi{NNŽY¿©óçϳmÛ6¢¢¢HHHÀÙÙ¹Ú¥)ww÷Û¶%ƒÃ¸q(ÑFG“¶b…™—@aoMïÞ‹‹ÉBs ¹¹$>ñD£Ú IE'NÿÛo”^ºôfƒã8aö£GSü÷ßhcë&5öZlÚ´‰²iÓ&Ógß}÷Ÿ}öãÆ«Òóh0èÕ«QQQìØ±ƒ:°råJFŽ ÀwÞÉ;#««+=zô¨r £ÑhZzøá‡™;w.nnnìÙ³‡E‹Uù?#“Éøí·ßˆ5ySÂÃÃqvvfìØ±<óÌ3H’Ä믿€ŸŸƒfòäÉ<üðèT*Ž?γÏ>[åøåfÔ¨Q,^¼˜£GòØcU›pPŽ?ÎË/¿L·nÝj|Ì®G06ñRÎ嘴:ÿÑ,кÍsm™Óªrš®A’né:.u……÷ÝwŸÙg={öä÷ß7ûlùòå„……áííMrr2?]yê»pá3fÌ mÛ¶üðÃäççãççG^^’$™ŽONN¦U«Vlݺ•'Ÿ|Ò”æ\üfkkkZgNOOgÔ¨Q <­VKÏž=iݺ5YYY(•J~þùgfΜ‰B¡àǤsçÎøùùUùï¹çÜÝÝùôÓOk®ƒƒƒ]ºt¡K—.•¶ét:âââÌNyÀbTTz½Þ$h®8þþþf.ò[ Ë+OÍ9ß_I¼@™`ÈÛ¾½VsÈ,,P8:"S(Ч¥5HœˆL­Féâ‚!#cÉe€(©Tè32 ÂÿJ9%”DDT>P’Èÿí7¬BC± Á²uë0—.]âá‡6ûlôèѬ_¿žüü|BCCÍš¾öëוJ…\.gÍš5¼üòËdgg3dÈ-ZÀ°að¶¶æèÑ£„„„УGò+x½†nŠ9{á…èØ±#»wï [·n¨Õj<==™>}º™]=ô‰‰‰$%%!—Ë‘Éd  Ì£üöÛo£×ëÍ2¥Ê= Û·oÇÆÆÆô€Ò©S'³Šáaaa&ïððáÃéÓ§µâ]±bÅ íŸ_PHbjf­æ¬Ò²Ù¶sc† jlS™$Uñß,htt:) ·\|lÛ¶gžy…B‘‘‘œ={–ÂÂBÚ¶m˦M›ðòò"<<œ.]º°råJFÍСCyì±ÇÌÆÿõ×_ùðÃ),,D¥RñÏ?ÿÄ@ó IDATžžÎ±cÇX°`{öìA&“‘™™IóæÍY¶lGeàÀxzz^Éæ­[·²lÙ2bccILLlÒŽŒŒ ³¥©Š18III¸»»W»4UžòÙPbbȘ6Òšd¢ÉdxÿïÈ Ò–/§äüùë¢VãõÞ{ÈT*dJ%’V‹tå½n…‡`7jÖ]»báãå¿_£‘Òèh²×¯Gm:NÙ¼9ŠÜ ¤ÒR¤ 1 ™Ÿ|Bñ?ÿ ppÀãõ×Ñ%%‘úJå DËvípœ4 •»{Ùœ’„>-œM›ªŒKq_²¥‡)Ï?e»vØ ŽòÊMÑX\Lö† ^‰Ã¨)NÓ¦a{×]äÿþ;Ù6ÔèÛ”œ®,ÿnm¾ùis—~pUsFsê³ÝµÒ«=ë?z£ÞçiŠÔ¹FP7¨TªJk²#FŒ`øðáÈd2 MYL666üñÇÌ;£Ñˆ»»»ÉÎçŸΰaÃð÷÷G’$ sæÌa÷îÝøúúréÒ%úöí ”­ûøøÊòåËMo©©© 2„Y³fUi¯N§ã駟櫯¾â‰'žàÒ¥K&Ž?NHHˆi;)Þ:;;ãììL÷îÝ+m+--5µd(6›6m2½–ËåÕ.MùúúVŠhP$ }j**OOlÃÂ(½|ùúÞƒ¢Ã‡Q‡„ òð 4* }JŠi³>=ÝôºYXRi)…”y3 ÔþþX¶oû’%¤¾öÿöî<ºé2{üø;{Ò%M÷–²W X)²he©€²‹a¾3è èGà'Å‘™q嫎ãAåŒÔ¾Ì8(*ˆ# ¨,eZöR¡û’¦I›&ùüþHše )÷uç$ùlOã‘^žç>÷Χ®a™ÑSW‡}ûvŒhcc©=pÀ/9ØUQá}¡R¡6™P˜õŠ1‚è©S°ïÚE}Aºví0õïïÍKùäªV­ò»Fe4¢6™ˆ5Šˆ¡CqìÞMMNºädÂú÷'ö@±Û[•”«oÈýª/(8çkDÛñÅæ-g ^‚©ªÚì!Í•ù_D´¨qV#<<Üoý¶[·n¬]»ð®…××{+DÞ{ï½X­V&NœÀý÷ßÏŒ3¨¯¯§¸¸µZÍܹs}Á†Á`à½÷Þc×®]<ôÐC2mÚ4òòòš%Â5µdÉúôéCff&ýû÷gûöí¾{NŸ>.]ºpôèQÔj5o¼ñ†_/§“'Oé·eúµ×^Ãår1{ölvìØÁºuëøÛßþvÁßáÙ ºwïîÿé ýjÞäää°bÅ >Lqq1)))gnRSS/Ë.°êõë‰ùÝïëßãÂ…Øwí±gu‡L”U\.ʳ³‰ùýïÑ%'Sóõ×-&ñ–,\ˆóرfË0a™™Ä=ðÑS§RøÌ3xl6ʳ³‰Ÿ=ml,Õ_~Im $Þh,, K®%¯¾Šã»ï|ÇŒ={?gQcÇbß¾ú“'›]1dEóçûÍ E FÌo‹yìØs`Œééè;vD©­Åñãç<~ÑvÔØ/ѺsUU¼š4Á&L¤ÑhüvÍš5‹Y§%IþûßÿfþüùÔÕÕѽ{w_¯£Ç{Œ)S¦‘‘ÁСC}I»¥¥¥têÔ)àó***xúé§ùàƒp:ôïߟœœ¦M›†¢(`–{îAÕr ó3k mÃNW EõÜ¥¥Þóâ÷Jk)8Qj¡¨ †€ÇÁ»Ë*~Îô©©ÔîÝKéâÅw/ILL óæÍkS¿È__mFýæ~v8qYž5nØ ö¹Žs“²ˆ}¯cÑS3t@_îŸ×¼æ‹A¯“mÔBœ‰Z­fܸqÍ>W©Tüë_ÿòËí #==Ý»w“››K·nÝ|Çòòò|ï;tèà÷¯¼ÂÂB’’’¨¬¬D¥Rù5ÌÍÍeÁ‚Œ7ŽcÇŽù«ÕÊàÁƒéÛ·/qqq,X°€wÞy‡víÚñùçŸçK\îׯß}÷   €°{÷îËÀœMDDdddø}îÛ…t÷¯;|˜ºÃ‡Q"²²»ñFÊÞ~ûœ1®¹†ØéÓñ8”ggS»w/›Í»¥YQˆøaL ž·&»œj÷Eþ…ªÒ鈟=CZµP²hÑym óÕV¡Íyyf_þ÷õ÷šÍ~-~z“Çã™EK9YTêw,¼¡êÕHqAºuëæ 4zÿý÷}%ÏûôéãûüСCŒá­Y‘‘ÁÛo¿Mß¾}Y¿~=¹¹¹Üzë­?~œ´´4ß5N§“ÒÒR_NyÿÊ/^L=X¶l‹-bíÚµLŸ>åË—óÃ?лwo:vìˆÅb!!!ÔÔTRSS}­ œN'V«Õ—ÔÖ5推ôz4 îsÌ- »é&Ðh¨\¹Û¦MÍŽ·4r¾\EEhãâÐÆÄ̽Ñ4ÍMwI](•VKü¬YÓÓ©;tˆ’W^Aq^š¦µ"tÄF›ñÖ¿ô³O–î¶ìþ‰Éc‡¬˜fjy&±­“F\-RNËOX²d‰¯²æO<Á#|ØWHoÛ¶mX­V†ŽÇãÁáp™™ xgmî¿ÿ~_ œ?þ‡ÃÁÌ™3éÑ£=zô ÿþèt:zöìIqq±oz|åÊ• 8:\Òï)(¦›§wC“;¥¡8œº…% ]r2xiF®I²¦‹ÎiÌæV ³þ—_0¦§c¼þú€;†L}ûzÇsêT«îÛ•VKÜCaìÕ çÑ£”¼ü²ï;W·¾×]Ë¿×mõåÍ3ѨÕdô¼†÷ŒgÛw{9q²è´3:·O¾¬cº’¿ ‡¸ªèt: ¹F£‘×^{½{÷²eË xwù,X°€G}Ô—_ÓÒ2”ÙlæŽ;î`ýúõlܸ‘Õ«W3gÎÀÛ$sZCð4Æ cøðáØívV®\ÉÏ?ÿLXX)))@ðcß±óèÑDŽéºëpž8ÖÏ?÷Ö”i«¤ëš5DÝq sçbÛ¼ÙWÈ.bÈTF#¶¯¾º(;žÂ23}3:j“‰„Çx^]^ï½wÁÏ¡Åe¦Kû$N•¹lÏ|ìù׈µ˜6¨?·Éä…¹0ç¹WýÎiÅÍ™Í[©\-$€W¼ØØXbcc}ïï»ï>ßëÁƒ³bÅ –.]ʲeˈ';;»Yò0xg`µ@¸ñÆÙ±c)))1uêTJKKY»v-©©©¬X±‚´´4555äççcµZéÑ£÷Ýw÷ÝwIIILž<™^xüü|²²²˜4iR‹Õ‹/•ŠåË ëÓCÏž„–—¢¸ÝÔ|û-Ö5kpùOG»JJ(Y°ó˜1ÞªµýúJEíÏ?ÃþýÔ8@Ù;ï}Ï=Þ¥ôtPœùù”<ÿ<–©S0ÎãÇ)]¼˜È‘#Ñ&&Ö¿?¨TÔlßg`ª>úWQÑ¿ù ‘Çû>÷8T¼û.¶Ïÿ‹jªÉìÑ™ryÎ5_H´=£o̶¢¨.Ï2Ò—ßîàÿ>ÛÀô{Æñü£÷“ýŸÏùaCC]E!½[竲þK#é…$Ú¤ªª* ýªéN™2…;v V«éÖ­Ý»wçÅ_D¯×óÓO?1cÆ Ün7/¿ü27ß|³¯ÅÂÚµkÉÍÍõýùÇ?þÁ®]»xóÍ7Y³f àmçv»™;w.O=õz½ž'žx‚ºº:ß’ÙùjU/¤&T:šØX´ »¹\åå¸ËÊ.¸ñ¢Ê`@—œŒÊh¤þøñ˳ԢRyzp•”xw¯ð¿º¤RÛR[çdؤ?Wx[ÿ¥ì…”’Ï÷k—ñÌ¢¥¼šý!I_,v‰—·7Û•Df`D›EÔiɨ+V¬¼Õrðk‡PQQá«o“››Ë¤I“.8x¹J}=®ÂB¿¾Få¾uug\ú¹$å×ÀEˆ 0ô1›ËÅ©xÊ$Fˆ‹`ýúõ :­VË'Ÿ|ÂK/½Ä5×\ÃÒ¥K/øÞç›#‚Kr`Ú®o¶ïâÁy/PXyy·Ú‡4̾w"Ϙvö“¯Àq…“&4IÓ¶­øx O-x‹rÛå©Ô¦W3aø>ûÄey^(%$!„¢•¦LƒÑ`äÙ…op¢¸ú¢÷äj*6ÒÀïÏ#÷ß{ÉžФ¯Bqî5ŒO—-¢w·v¨i¡éèP"y}þ\ ^F!„8O)I‰|±ü ¦ß=’Ž ‘(÷Ù/:E!Þ¬gBVÖ½ÿ:·Ê<û5W!Éâ '90¡Ir`®>v‡ƒ¿ÍÚ¯¶pìT¨u­º^åq‘ŵ©øû_æÐ!åêmÔx.$€â 'Lh’æêUçt²zÝ>[ÿ5Ç NQ\V‰Õ^GÓ…J¥öæË(L‘aFÌ&:¥$1fØî5ŒÈˆð³?DH¯Bq1ôz&ŤñÞNÑÅ¥eürªˆÒò N•RVYIç)¤vî@‡ä$¢¥¦Ëy‘Fˆ+œÚbA§Ó¡-.öPD+h{õ öÄ"!.–„¸Ø³Ÿ(ZE–„Brd’B!BŽ0B!„9À!„"äH#„Bˆ#Œ"hêwìÀñÖ[¸öP„!Fv! !‚ÂþÁXß{ú°0 eeÄfg£éÜ9ØÃB„™BEí_àLJB1›©mßžšÅ‹ƒ=$!D‘FÚ¨(T6šÊJôýúyDBˆP"Œ"("ÿþwÌ11„ÛlD Œñž{‚=$!D‘!„B„™Bâpà)+ ö0„!Hš9 !‚¢þ§Ÿ¨š=·FƒV§#æ£P Á–"DÈ’"(*ÿð¬n7*»KF‘ùKG%„²„$„ Ån‡†µÙÜ !BŠÌÀ!‚Â}ì¿ý-nƒ]X–¥KQÇÆ{XBˆ!Œ"¨<§N¡NJ•*ØCB„ `„Brd’"(”ª**|wu5úÔTÌ {HBˆ"I¼Bˆ °þíoØ<ì11ØŽÁ±ti°‡$„!À!‚ÂýË/( u_Üaa¸Ož òˆ„¡D!DP„ϘþÈÔee‹‹1Ýyg°‡$„!’Ä+„×¾}Ôçä`?^¶P !ZE!„B„YBB!DÈ‘F!„!G!„B„ `„Br¤¯W8Oq1åC‡¢DG{(¢tíÛcY¹2ØÃ¢Í’Fˆ+œb·ãާ®K—`E´‚¦°0ØC¢M“%$!„B„ `„Br$€B!DÈ‘F!„!G!„B„ `„Br$€B!DÈ‘F!„!G!„B„ `„Br$€B!DÈ‘F!„!Gš9 цé:t@ÆbAq8p[­8Çc³{h>³™„'žÀUXHÉ+¯mÚøxTZï_‰õEEàñ>/1•Z«¤Å府CB4!Œm¡G¢'OF¨ƒµ¢àÌϧtÑ"\ee¾Ã231¤¦R³u+ÎcÇ.ÚX"† A×¾=¶©Ô¡Y£A—”n÷E{æùHxä´II”ggcûê«€ç%Λ‡ÆlæÔ_ÿJý‰—sˆBˆ&$€¢ÑµkGœ9¨ôzêƾs'îŠ Ôaah0ed ïÔ uX4 `ŒééD ‚óèÑ‹À˜úôÁÔ§Ž À(N'öœ\ååí™*êŽ;¨Ù²Åé öP„-Fˆ6Æ2i*½žš­[){ãfÇ+W®Dߥ ®ÊÊ Œ®9OM ¥K–{>žêj4 ‘Æaýüó`GÑ `„hc ©©ToØÐâ9ΣG}£R¡ïÐux8š¸8ô;ú»ÊÊðÔÔøÞ«ÃÃÑwíŠ6&4\……8óó›åÕ¨´ZtíÚ¡6™Ð&$øß·¤ÃJ£A—’‚ât^b4 úŽÑ&$à*)ÁyâîfltÉɨt:êOžDq¹ÐDGcHKC¥×SŸŸóøñ¿€ªO?%zÊÌcÇbÛ´ ÃqÆó…Á!Œm‰J…J¯¼I©ÎÇÏ~‰Á@Ò3ÏøÞ[&N„‰}ïËßyÛ×_ÿðØzõµÿF¥¶–Ê>¢ú¿ÿE@íwߘßýÎïš’… qìÙƒÚl&é™g¨ÿåNÍ›ç?8Ë„ ˜ÇŽ•ÊïPõ—_Rù¯¡Ô×û}7s&ºví89w.QwÞIøM7ù¯Ù²…ò¥K[LÀu?Ž}çNÂn¼‘ÈQ£¨Zµ*àyBˆà’Fˆ¶DQpž8ášk0‰«¨È¶%Ð%õõ”.YBÄС{ö¤zÃêòò|ÇGŽø^ë±}û-u¹¹¸JKQ©Õè»vÅÕ_|Ñâs+W­"¬_?̷ߎmýzÜVëYÇ*„¸¼$€¢©úÏHxì1ô;“ôä“¸ŠŠpìÙCÝÁƒÔþü3žÚZÿ Ünì99ÓÓ¡gOœ‡aÏÉ xïSýk³ÚýûqüðIO=…åٶ ¥®{NŽw¤sgj vïÞsþ9ô]º>p J]EÏ=‡«¸€ºÜ\{öôÌ3{õ”‘ãÇ›]¯‰áÔ_þ‚Çn÷~°o®“'I˜;—È#ÎÀ¸ ±}ó C‡b?žŠ÷ß?çq !.)d'DS»?EÏ?ïËõÐ&&9r$q3g’²x1ñ³f¡‰‰9¯{Ÿ¼4ª/(Àyìšèh4QQç=ö¦"†• Û¦M¾à¥‘»²Ò»\Dde¼¾ê³Ï~ ^ÔîßÇfC‹J§;ãó«V¯Fq:‰:m\Üùÿ BˆKBf`„hƒêòò(|òI´ññ320té‚©OÔáá˜úö%¹gOŠž}–ú“'[}o}‡„ ˆ6.MT*ÀWCE‡û"ìpÒ5ܯvÿþ€Çk÷íó>/!!àñ––¨Ü••¨#"ÐÄÄà**jñùîŠ ª7lÀKqî$€¢ilHØ’ÆÜÍæ—«ÒXˆ®¥œÅÒð¢ùÒ‹!-­Å@ÃÝPO柦®aûvø AGÜ|3ÀY·‰_(¥®ë'Ÿ`¹ûîKú,!Ĺ“Fˆ6¦ÝK/a¹ûn´±±ÍŽºu#úþÇ÷ßûkœÉ0^{mÀk«äFdeùIÚÄDbî½·Åñ4î 2edüÛ—_â¶Z1¦§yÛm~Ç"n¹…°nðkÖœó=Ï—mÓ&\%%{öDyÉŸ'„8;É¢QGFb3ó˜1xl6ê QêëÑÆÅùfAê (?­¶‰='ËĉÒÒh÷òËxl6‡Êå˩پêuë<cÏž´_¼˜Ú}ûP™LRS©=pWi)¦ŒŒfã©ùæ¢ÆŽÅtýõ¤¼ò žêjE¡ìÍ7©ýé§Om-ÙÙÄΘAôÔ©D B}AÚvíÐwìˆârQñþûeÇÓÙ(n7U«Vû§?µz)LqiH#DSøä“˜®¿SFÚÄD_o$we%u¹¹Ø¾ùû¶m¾Ý8<§æÍ#"+ ]r2ê¨(T*•¯–Š«´”¢çž#zÊ ©©{÷¦¾ ÛÆT~ø!æñãQëõ¾%£FîÊJNþùÏDfe¡MLD‰J¥Biè1¤¸\Ô5@§³ïÞMý“Ob™4 ]§N„ef⮨Àñý÷T­Z…3?¿Ù5Î#GðX­-Ö¬q;†âp ÔÕù}^wäîÊÊfµcÕlߎ©O4f³wÜ—0yXqv*EḭB\‰ÜÇŽQ:mu]º{(¢" ‰Y·.ØÃ¢Í’pxÈIDAT!„B„ `„Br$€B!DÈ‘F!„!G!„B„ `„Br$€B!DÈ‘F!„!G!„B„ `„Br¤’W:• JKÑh4Á‰hEš> qII/$!®tŠ‚sãFh¡9¡¸2iºtAÓ½{°‡!D›%ŒB!BŽäÀ!„"äH#„Bˆ#ŒB!BŽ0B!„9À!„"äH#„Bˆóÿ–ïæ¹É>IEND®B`‚event-studio-v-1.0.6/src/graphics/event-studio.svg000066400000000000000000000347251305060074600221610ustar00rootroot00000000000000 image/svg+xml Station1 Station2 StationN P broadcast SomeEvent broadcast AnotherEvent L 1 L 3 L 2 SomeEvent --> AnotherEvent --> event-studio-v-1.0.6/src/main/000077500000000000000000000000001305060074600161235ustar00rootroot00000000000000event-studio-v-1.0.6/src/main/java/000077500000000000000000000000001305060074600170445ustar00rootroot00000000000000event-studio-v-1.0.6/src/main/java/org/000077500000000000000000000000001305060074600176335ustar00rootroot00000000000000event-studio-v-1.0.6/src/main/java/org/sejda/000077500000000000000000000000001305060074600207215ustar00rootroot00000000000000event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/000077500000000000000000000000001305060074600232725ustar00rootroot00000000000000event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/Annotations.java000066400000000000000000000150471305060074600264410ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 15/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.sejda.eventstudio.util.RequireUtils.requireNotNull; import static org.sejda.eventstudio.util.StringUtils.isBlank; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.sejda.eventstudio.annotation.EventListener; import org.sejda.eventstudio.annotation.EventStation; import org.sejda.eventstudio.exception.EventStudioException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility methods processing beans to find annotated method or fields and register reflective listeners. * * @author Andrea Vacondio * */ final class Annotations { private static final Logger LOG = LoggerFactory.getLogger(Annotations.class); private Annotations() { // utility } public static ReflectiveMetadata process(Object bean) throws IllegalAccessException, InvocationTargetException { requireNotNull(bean); LOG.trace("Processing {} for annotated listeners", bean); // TODO process public and private String station = getStationNameFromFieldIfAny(bean); ReflectiveMetadata metadata = new ReflectiveMetadata(); for (Method method : getMethods(bean)) { if (isBlank(station)) { station = getStationNameIfAnnotated(method, bean); } addIfAnnotated(metadata, method); } metadata.station = station; return metadata; } /** * @param bean * @return a list containing all the public methods (inherited and not) and all the private, package and protected (not inherited) */ private static List getMethods(Object bean) { List methods = new LinkedList(Arrays.asList(bean.getClass().getMethods())); for (Method method : bean.getClass().getDeclaredMethods()) { if (!Modifier.isPublic(method.getModifiers())) { methods.add(method); } } return methods; } private static void addIfAnnotated(ReflectiveMetadata metadata, Method method) { EventListener listenerAnnotation = method.getAnnotation(EventListener.class); if (listenerAnnotation != null) { Class[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length != 1) { throw new EventStudioException( "@EventListener annotated method expected to be a single parameter method"); } LOG.trace("Found @EventListener annotated method {}", method); metadata.put(listenerAnnotation.station(), new ReflectiveListenerDescriptor(listenerAnnotation, method)); } } private static String getStationNameIfAnnotated(Method method, Object bean) throws InvocationTargetException, IllegalAccessException { if (method.isAnnotationPresent(EventStation.class)) { if (method.getParameterTypes().length > 0) { throw new EventStudioException("@EventStation annotated method expected to be a no parameters method."); } method.setAccessible(true); LOG.trace("Found @EventStation annotated method {}", method); if (method.getReturnType().isEnum()) { return method.invoke(bean).toString(); } return (String) method.invoke(bean); } return null; } /** * @param bean * @throws IllegalAccessException * @return a String value with the name of the station if an annotated field was found, null otherwise. */ private static String getStationNameFromFieldIfAny(Object bean) throws IllegalAccessException { for (Field field : bean.getClass().getDeclaredFields()) { if (field.getAnnotation(EventStation.class) != null) { field.setAccessible(true); Object value = field.get(bean); if (value.getClass().isEnum()) { return value.toString(); } return (String) value; } } return null; } /** * Holds metadata retrieved from the reflective inspection of a bean * * @author Andrea Vacondio * */ static class ReflectiveMetadata { private String station; private Map> descriptors = new HashMap>(); private void put(String station, ReflectiveListenerDescriptor descriptor) { List current = descriptors.get(station); if (current == null) { current = new ArrayList(); descriptors.put(station, current); } current.add(descriptor); } public String getStation() { return station; } public Map> getDescriptors() { return descriptors; } } /** * Descriptor of a reflective listener holding information needed to create the listener * * @author Andrea Vacondio * */ static class ReflectiveListenerDescriptor { private EventListener listenerAnnotation; private Method method; public ReflectiveListenerDescriptor(EventListener listenerAnnotation, Method method) { this.listenerAnnotation = listenerAnnotation; this.method = method; } public EventListener getListenerAnnotation() { return listenerAnnotation; } public Method getMethod() { return method; } } } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/DefaultEventStudio.java000066400000000000000000000200431305060074600277120ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 10/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.sejda.eventstudio.util.RequireUtils.requireNotNull; import static org.sejda.eventstudio.util.StringUtils.defaultString; import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.Map.Entry; import org.sejda.eventstudio.Annotations.ReflectiveListenerDescriptor; import org.sejda.eventstudio.Annotations.ReflectiveMetadata; import org.sejda.eventstudio.exception.EventStudioException; /** * Default implementation of {@link EventStudio}. It doesn't enforce a Singleton pattern and it's up to the user to decide how to use it and how many EventStudio the application * needs. A singleton implementation with lazy initialization is provided with {@link org.sejda.eventstudio.StaticStudio} where the typical usage is: * *
 * {@code
 * import static org.eventstudio.StaticStudio.eventStudio;
 * 
 * public class Foo{
 *     void doSomethingAndNotify(){
 *        .....
 *        eventStudio.broadcast(new ImFinished(), "station");
 *     } 
 * }
 * }
 * 
*

* Hidden Station: The hidden station is a pre-built station with "hidden.station" name that is used to hide the station abstraction. Helper method are provided by * {@link DefaultEventStudio} where the station name parameter is missing from the parameters list and the {@link DefaultEventStudio#HIDDEN_STATION} is used, providing a more * traditional event bus pub/sub pattern. *

* * @author Andrea Vacondio * */ public class DefaultEventStudio implements EventStudio { /** * A reserved station name that is used to hide the station abstraction. Using the provided helper methods the station concept remains totally hidden and {@link EventStudio} * can be used as a more traditional Event Bus with pub/sub pattern. */ public static final String HIDDEN_STATION = "hidden.station"; private Stations stations = new Stations(); public void add(Listener listener, String station, int priority, ReferenceStrength strength) { stations.getStation(station).add(listener, priority, strength); } public void add(Listener listener, String station) { add(listener, station, 0, ReferenceStrength.STRONG); } public void add(Class eventClass, Listener listener, String station) { add(eventClass, listener, station, 0, ReferenceStrength.STRONG); } public void add(Class eventClass, Listener listener, String station, int priority, ReferenceStrength strength) { stations.getStation(station).add(eventClass, listener, priority, strength); } public void addAnnotatedListeners(Object bean) { try { ReflectiveMetadata metadata = Annotations.process(bean); for (Entry> current : metadata.getDescriptors().entrySet()) { String station = defaultString(metadata.getStation(), HIDDEN_STATION); stations.getStation(defaultString(current.getKey(), station)).addAll(bean, current.getValue()); } } catch (IllegalAccessException e) { throw new EventStudioException("An error occurred processing the input bean", e); } catch (InvocationTargetException e) { throw new EventStudioException("An error occurred processing the input bean", e); } } /** * Adds a {@link Listener} (with the given priority and strength ) to the hidden station listening for the given event class, hiding the station abstraction. * * @see EventStudio#add(Listener, String, int, ReferenceStrength) * @see DefaultEventStudio#HIDDEN_STATION */ public void add(Class eventClass, Listener listener, int priority, ReferenceStrength strength) { add(eventClass, listener, HIDDEN_STATION, priority, strength); } /** * Adds a {@link Listener} (with the given priority and strength ) to the hidden station, hiding the station abstraction. * * @see EventStudio#add(Listener, String, int, ReferenceStrength) * @see DefaultEventStudio#HIDDEN_STATION */ public void add(Listener listener, int priority, ReferenceStrength strength) { add(listener, HIDDEN_STATION, priority, strength); } /** * Adds a {@link Listener} to the hidden station, hiding the station abstraction. * * @see EventStudio#add(Listener, String) * @see DefaultEventStudio#HIDDEN_STATION */ public void add(Listener listener) { add(listener, HIDDEN_STATION); } /** * Adds a {@link Listener} to the hidden station listening for the given event class, hiding the station abstraction. * * @see EventStudio#add(Class, Listener, String) * @see DefaultEventStudio#HIDDEN_STATION */ public void add(Class eventClass, Listener listener) { add(eventClass, listener, HIDDEN_STATION); } /** * Adds a {@link Supervisor} to the hidden station, hiding the station abstraction. * * @param supervisor * @see EventStudio#supervisor(Supervisor, String) * @see DefaultEventStudio#HIDDEN_STATION */ public void supervisor(Supervisor supervisor) { supervisor(supervisor, HIDDEN_STATION); } public void supervisor(Supervisor supervisor, String station) { requireNotNull(supervisor); stations.getStation(station).supervior(supervisor); } public boolean remove(Listener listener, String station) { return stations.getStation(station).remove(listener); } public boolean remove(Class eventClass, Listener listener, String station) { return stations.getStation(station).remove(eventClass, listener); } /** * Removes the given listener from the hidden station, hiding the station abstraction. * * @return true if the listener was found and removed * @see EventStudio#remove(Listener, String) * @see DefaultEventStudio#HIDDEN_STATION */ public boolean remove(Listener listener) { return remove(listener, HIDDEN_STATION); } /** * Removes the given listener listening on the given event, from the hidden station, hiding the station abstraction. * * @return true if the listener was found and removed * @see EventStudio#remove(Listener, String) * @see DefaultEventStudio#HIDDEN_STATION */ public boolean remove(Class eventClass, Listener listener) { return remove(eventClass, listener, HIDDEN_STATION); } public void clear(String station) { stations.clear(station); } /** * Clears the hidden station * * @see EventStudio#clear(String) * @see DefaultEventStudio#HIDDEN_STATION */ public void clear() { stations.clear(HIDDEN_STATION); } public void broadcast(Object event, String station) { stations.getStation(station).broadcast(event); } /** * Boradcast the event to the hidden station * * @see EventStudio#broadcast(Object, String) * @see DefaultEventStudio#HIDDEN_STATION */ public void broadcast(Object event) { stations.getStation(HIDDEN_STATION).broadcast(event); } public void broadcastToEveryStation(Object event) { for (Station station : stations.getStations()) { station.broadcast(event); } } } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/Entity.java000066400000000000000000000035701305060074600254160ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 12/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.sejda.eventstudio.util.RequireUtils.requireNotNull; import java.lang.ref.Reference; /** * Holder for an instance. * * @author Andrea Vacondio * @param * the type of the referent */ interface Entity { /** * @return the instance or null if nothing is available */ T get(); /** * Holds an entity referenced using the input {@link Reference} * * @author Andrea Vacondio * * @param */ static class ReferencedEntity implements Entity { private Reference reference; ReferencedEntity(Reference reference) { requireNotNull(reference); this.reference = reference; } public T get() { return reference.get(); } } /** * A strongly referenced entity * * @author Andrea Vacondio * * @param */ static class StrongEntity implements Entity { private T referent; StrongEntity(T referent) { this.referent = referent; } public T get() { return referent; } } } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/Envelope.java000066400000000000000000000026461305060074600257220ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 12/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.sejda.eventstudio.util.RequireUtils.requireNotNull; /** * Hold an event and the state of its notification * * @author Andrea Vacondio * */ class Envelope { private boolean notified = false; private Object event; Envelope(Object event) { requireNotNull(event); this.event = event; } /** * @return true if some listeners has been notified */ public boolean isNotified() { return notified; } public Object getEvent() { return event; } /** * set this event as notified */ public void notified() { if (!notified) { this.notified = true; } } } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/EventStudio.java000066400000000000000000000122201305060074600264030ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 09/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; /** * An {@link EventStudio} is a thread-safe central place allowing broadcast of events to {@link Listener}s to registered on a Station. Stations are created internally as soon as a * listener is added but it's up to the user to clear a station when it's not needed anymore. {@link Listener}s can be added multiple times either to different or the same station * and they will be called as many times as they have been added. *

* As a general rule null parameters are not allowed (either station names, listeners, supervisors.. ) *

* * @author Andrea Vacondio * */ public interface EventStudio { String MAX_QUEUE_SIZE_PROP = "eventstudio.max.queue.size"; /** * Adds the given {@link Listener} to the given station using default priority(0) ad default strength {@link ReferenceStrength#STRONG}. */ void add(Listener listener, String station); /** * Adds the given {@link Listener} to the given station using the given priority (low values mean higher priority) and strength. */ void add(Listener listener, String station, int priority, ReferenceStrength strength); /** * Adds the given {@link Listener}, listening for the given event class, to the given station using default priority(0) ad default strength {@link ReferenceStrength#STRONG}. * This add method is useful when a listener can listen for a hierarchy of events. * * @see EventStudio#add(Class, Listener, String, int, ReferenceStrength) */ void add(Class eventClass, Listener listener, String station); /** * Adds the given {@link Listener}, listening for the given event class, to the given station using the given priority (low values mean higher priority) and strength. This add * method is useful when a listener can listen for a hierarchy of events: * *
     * {@code
     * class BroadListener{@code  implements Listener} { 
     *     void onEvent(ParentEvent e){
     *           LOG.debug(e);
     *     }
     * }
     * 
     * class X {
     *   public void init() {
     *     EventStudio studio = ....
     *     studio.add(ChildEvent.class, new BroadListener{@code }(), "mystation");
     *     studio.add(AnotherChildEvent.class, new BroadListener{@code ()}, "mystation");
     *     ...
     *   }
     * }
     * 
     * }
     * 
*/ void add(Class eventClass, Listener listener, String station, int priority, ReferenceStrength strength); /** * Discovers annotated method on the the given bean and adds them as {@link Listener}s * * @param bean * @see org.sejda.eventstudio.annotation.EventListener * @see org.sejda.eventstudio.annotation.EventStation */ void addAnnotatedListeners(Object bean); /** * Sets a {@link Supervisor} for the given station. It will be notified of every event broadcasted to the station prior its delivery to the proper {@link Listener}s allowing * event inspection. *

* {@link Supervisor}s cannot be removed but they can be replaces. See {@link Supervisor#SLACKER} *

*/ void supervisor(Supervisor supervisor, String station); /** * Removes the first occurrence of the given {@link Listener} from the given station. * * @return true if the listener was successfully removed */ boolean remove(Listener listener, String station); /** * Removes the first occurrence of the given {@link Listener} listening for the given event, from the given station * * @return true if the listener was successfully removed */ boolean remove(Class eventClass, Listener listener, String station); /** * Clear the given station removing the whole station from the {@link EventStudio} which means that {@link Listener}s and {@link Supervisor} will not be notified anymore. A * station with the same name can be recreated. */ void clear(String station); /** * Broadcasts the given event to the given station. {@link Listener}s listening the given station and bound to the event class will be notified. */ void broadcast(Object event, String station); /** * Broadcasts the given event to every station. {@link Listener}s bound to the event class (no matter the station they are listening) will be notified. */ void broadcastToEveryStation(Object event); } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/Listener.java000066400000000000000000000020421305060074600257200ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 09/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; /** * Listener for events of the generic type * * @author Andrea Vacondio * @param * type of the event the listener is interested in */ public interface Listener { /** * Notify the listener of the given event * * @param event */ void onEvent(T event); } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/Listeners.java000066400000000000000000000207671305060074600261210ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 11/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.sejda.eventstudio.util.RequireUtils.requireNotNull; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.sejda.eventstudio.Annotations.ReflectiveListenerDescriptor; import org.sejda.eventstudio.exception.BroadcastInterruptionException; import org.sejda.eventstudio.exception.EventStudioException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A thread-safe holder for the listeners * * @author Andrea Vacondio * */ class Listeners { private static final Logger LOG = LoggerFactory.getLogger(Listeners.class); private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private Map, TreeSet> listeners = new HashMap, TreeSet>(); void add(Class eventClass, Listener listener, int priority, ReferenceStrength strength) { lock.writeLock().lock(); try { TreeSet set = nullSafeGetListenerHolders(eventClass); set.add(new ListenerReferenceHolder(priority, strength.getReference(new DefaultListenerWrapper(listener)))); } finally { lock.writeLock().unlock(); } } public Set> addAll(Object bean, List descriptors) { Set> updatedEventClasses = new HashSet>(); lock.writeLock().lock(); try { for (ReflectiveListenerDescriptor current : descriptors) { Class eventClass = current.getMethod().getParameterTypes()[0]; TreeSet set = nullSafeGetListenerHolders(eventClass); set.add(new ListenerReferenceHolder(current.getListenerAnnotation().priority(), current.getListenerAnnotation().strength() .getReference(new ReflectiveListenerWrapper(bean, current.getMethod())))); updatedEventClasses.add(eventClass); } } finally { lock.writeLock().unlock(); } return updatedEventClasses; } private TreeSet nullSafeGetListenerHolders(Class eventClass) { TreeSet set = listeners.get(eventClass); if (set == null) { set = new TreeSet(); listeners.put(eventClass, set); } return set; } /** * Removes the listener if present. It also removes the listeners set from * the map if the set is empty. * * @param eventClass * @param listener * @return true if the listener was present and has been removed */ boolean remove(Class eventClass, Listener listener) { lock.readLock().lock(); TreeSet set = listeners.get(eventClass); if (set != null) { lock.readLock().unlock(); lock.writeLock().lock(); try { DefaultListenerWrapper wrapper = new DefaultListenerWrapper(listener); for (ListenerReferenceHolder current : set) { if (wrapper.equals(current.getListenerWrapper())) { return removeListenerAndSetIfNeeded(eventClass, current, set); } } return false; } finally { lock.writeLock().unlock(); } } lock.readLock().unlock(); return false; } /** * Removes the listener if present. It also removes the listeners set from * the map if the set is empty. * * @param eventClass * @param listener * @return true if the listener was present and has been removed */ boolean remove(Class eventClass, ListenerReferenceHolder listener) { lock.readLock().lock(); TreeSet set = listeners.get(eventClass); if (set != null) { lock.readLock().unlock(); lock.writeLock().lock(); try { return removeListenerAndSetIfNeeded(eventClass, listener, set); } finally { lock.writeLock().unlock(); } } lock.readLock().unlock(); return false; } private boolean removeListenerAndSetIfNeeded(Class eventClass, ListenerReferenceHolder listener, TreeSet set) { if (set.remove(listener)) { if (set.isEmpty()) { listeners.remove(eventClass); LOG.trace("Removed empty listeners set for {}", eventClass); } return true; } return false; } /** * @param eventClass * @return A sorted set containing the listeners queue for the given class. */ List nullSafeGetListeners(Class eventClass) { requireNotNull(eventClass); lock.readLock().lock(); try { TreeSet set = listeners.get(eventClass); if (set == null) { return Collections.emptyList(); } return new ArrayList(set); } finally { lock.readLock().unlock(); } } /** * Wraps a listener defined either explicitly or picked up by the annotation * processor * * @author Andrea Vacondio * */ interface ListenerWrapper { void onEvent(Envelope event); } /** * Listener wrapper around an explicitly defined {@link Listener} * * @author Andrea Vacondio * */ @SuppressWarnings({ "rawtypes", "unchecked" }) private static final class DefaultListenerWrapper implements ListenerWrapper { private Listener wrapped; private DefaultListenerWrapper(Listener wrapped) { this.wrapped = wrapped; } public void onEvent(Envelope event) { wrapped.onEvent(event.getEvent()); event.notified(); } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((wrapped == null) ? 0 : wrapped.hashCode()); return result; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || !(o instanceof DefaultListenerWrapper)) { return false; } DefaultListenerWrapper other = (DefaultListenerWrapper) o; return wrapped.equals(other.wrapped); } } /** * Reflective invocation of an annotated listener * * @author Andrea Vacondio * */ private static final class ReflectiveListenerWrapper implements ListenerWrapper { private Object bean; private Method method; public ReflectiveListenerWrapper(Object bean, Method method) { this.bean = bean; this.method = method; this.method.setAccessible(true); } public void onEvent(Envelope event) { try { method.invoke(bean, event.getEvent()); } catch (IllegalAccessException e) { throw new EventStudioException("Exception invoking reflective method", e); } catch (InvocationTargetException e) { if (e.getCause() instanceof BroadcastInterruptionException) { throw (BroadcastInterruptionException) e.getCause(); } throw new EventStudioException("Reflective method invocation exception", e); } event.notified(); } } /** * Holder for a {@link ListenerWrapper} * * @author Andrea Vacondio * */ static class ListenerReferenceHolder implements Comparable { int priority = 0; private Entity reference; public ListenerReferenceHolder(int priority, Entity reference) { requireNotNull(reference); this.priority = priority; this.reference = reference; } public int compareTo(ListenerReferenceHolder o) { if (this.priority < o.priority) { return -1; } if (this.priority > o.priority) { return 1; } // same priority int retVal = this.hashCode() - o.hashCode(); // same hashcode but not equals. This shouldn't happen but according // to hascode documentation is not required and since we don't want // ListenerReferenceHolder to // disappear from the TreeSet we return an arbitrary integer != from // 0 if (retVal == 0 && !this.equals(o)) { retVal = -1; } return retVal; } public ListenerWrapper getListenerWrapper() { return reference.get(); } } } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/ReferenceStrength.java000066400000000000000000000031511305060074600275520ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 09/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; /** * Possible reference strengths of the listeners * * @author Andrea Vacondio * */ public enum ReferenceStrength { STRONG { @Override Entity getReference(T referent) { return new Entity.StrongEntity(referent); } }, SOFT { @Override Entity getReference(T referent) { return new Entity.ReferencedEntity(new SoftReference(referent)); } }, WEAK { @Override Entity getReference(T referent) { return new Entity.ReferencedEntity(new WeakReference(referent)); } }; /** * * @param referent * @return the referent wrapped with the appropriate {@link Entity} instance. */ abstract Entity getReference(T referent); } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/StaticStudio.java000066400000000000000000000025171305060074600265610ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 15/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; /** * Singleton pattern providing lazy initialization. * * @author Andrea Vacondio * */ public final class StaticStudio { private StaticStudio() { // hide } public static DefaultEventStudio eventStudio() { return DefaultEventStudioHolder.STUDIO; } /** * Lazy initialization * * @author Andrea Vacondio * */ private static final class DefaultEventStudioHolder { private DefaultEventStudioHolder() { // hide constructor } static final DefaultEventStudio STUDIO = new DefaultEventStudio(); } } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/Station.java000066400000000000000000000157711305060074600255710ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 09/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.sejda.eventstudio.EventStudio.MAX_QUEUE_SIZE_PROP; import static org.sejda.eventstudio.util.ReflectionUtils.inferParameterClass; import static org.sejda.eventstudio.util.RequireUtils.requireNotBlank; import static org.sejda.eventstudio.util.RequireUtils.requireNotNull; import java.util.List; import java.util.Set; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.LinkedBlockingQueue; import org.sejda.eventstudio.Annotations.ReflectiveListenerDescriptor; import org.sejda.eventstudio.Listeners.ListenerReferenceHolder; import org.sejda.eventstudio.Listeners.ListenerWrapper; import org.sejda.eventstudio.exception.BroadcastInterruptionException; import org.sejda.eventstudio.exception.EventStudioException; import org.sejda.eventstudio.util.ReflectionUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A {@link Station} is a place where broadcaster events are actually transmitted to the registered {@link Listener}s * * @author Andrea Vacondio * */ class Station { private static final Logger LOG = LoggerFactory.getLogger(Station.class); private ConcurrentMap, BlockingQueue> queues = new ConcurrentHashMap, BlockingQueue>(); private Listeners listeners = new Listeners(); private volatile Supervisor supervisor = Supervisor.SLACKER; private final String name; Station(String name) { requireNotBlank(name); this.name = name; } private BlockingQueue getQueue(Class clazz) { BlockingQueue queue = queues.get(clazz); if (queue == null) { final BlockingQueue value = new LinkedBlockingQueue(Integer.getInteger(MAX_QUEUE_SIZE_PROP, Integer.MAX_VALUE)); queue = queues.putIfAbsent(clazz, value); if (queue == null) { queue = value; } } return queue; } public void broadcast(Object event) { LOG.debug("{}: Broadcasting {}", this, event); requireNotNull(event); LOG.trace("{}: Supervisor {} about to inspect", this, supervisor); supervisor.inspect(event); LOG.trace("{}: Listeners about to listen", this); try { doBroadcast(event); } catch (BroadcastInterruptionException e) { LOG.info("Broadcasting was interrupted.", e); } } private boolean doBroadcast(Object event) { List eventListeners = listeners.nullSafeGetListeners(event.getClass()); LOG.debug("{}: Found {} listeners", this, eventListeners.size()); Envelope enveloped = new Envelope(event); for (ListenerReferenceHolder holder : eventListeners) { ListenerWrapper listener = holder.getListenerWrapper(); if (listener != null) { LOG.trace("{}: Notifing event {} to {}", this, event, listener); listener.onEvent(enveloped); } else { LOG.debug("{}: Removing garbage collected listener from the station", this); listeners.remove(event.getClass(), holder); } } if (!enveloped.isNotified()) { LOG.debug("{}: No one is listening for {}, enqueuing for future listeners", this, event); if (!getQueue(event.getClass()).offer(event)) { LOG.warn("{}: Max capacity might be reached, unable to store unlistened event, it's going to be lost {}", this, event); } } return enveloped.isNotified(); } void add(Listener listener, int priority, ReferenceStrength strength) { requireNotNull(listener); @SuppressWarnings("unchecked") Class eventClass = ReflectionUtils.inferParameterClass(listener.getClass(), "onEvent"); if (eventClass == null) { throw new EventStudioException("Unable to infer the listened event class."); } add(eventClass, listener, priority, strength); } void add(Class eventClass, Listener listener, int priority, ReferenceStrength strength) { requireNotNull(eventClass); requireNotNull(listener); LOG.debug("{}: Adding listener {} [priority={} strength={}]", this, listener, priority, strength); listeners.add(eventClass, listener, priority, strength); broadcastEnqueuedEventsFor(eventClass); } void addAll(Object bean, List descriptors) { requireNotNull(descriptors); LOG.debug("{}: Adding {} reflective listeners for {}", this, descriptors.size(), bean); Set> updatedEventClasses = listeners.addAll(bean, descriptors); for (Class updatedClass : updatedEventClasses) { broadcastEnqueuedEventsFor(updatedClass); } } private void broadcastEnqueuedEventsFor(Class updatedClass) { BlockingQueue queue = getQueue(updatedClass); Object event = null; boolean keepBroadcasting = true; while (keepBroadcasting && (event = queue.poll()) != null) { LOG.debug("{}: Found enqueued event {}, now broadcasting it.", this, event); keepBroadcasting = doBroadcast(event); } } boolean remove(Listener listener) { requireNotNull(listener); @SuppressWarnings("unchecked") Class eventClass = inferParameterClass(listener.getClass(), "onEvent"); if (eventClass == null) { throw new EventStudioException("Unable to infer the listened event class."); } return remove(eventClass, listener); } boolean remove(Class eventClass, Listener listener) { requireNotNull(eventClass); requireNotNull(listener); LOG.debug("{}: Removing listener {} [eventClass={}]", this, listener, eventClass); return listeners.remove(eventClass, listener); } /** * @return name of the station */ String name() { return name; } public void supervior(Supervisor supervisor) { requireNotNull(supervisor); this.supervisor = supervisor; } @Override public String toString() { return String.format("Station[%s]", name); } } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/Stations.java000066400000000000000000000046371305060074600257530ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 10/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.sejda.eventstudio.util.RequireUtils.requireNotBlank; import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * A thread safe holder for {@link Station}. Provides methods to access to the {@link Station}s of the {@link EventStudio} creating a new one when requred. * * @author Andrea Vacondio * */ class Stations { private static final Logger LOG = LoggerFactory.getLogger(Stations.class); private ConcurrentMap stations = new ConcurrentHashMap(); /** * @param stationName * @return the station with the given name. It safely creates a new {@link Station} if a station with the given name does not exist. * @throws IllegalArgumentException * if the station name is blank or null */ Station getStation(String stationName) { requireNotBlank(stationName); Station station = stations.get(stationName); if (station == null) { final Station value = new Station(stationName); station = stations.putIfAbsent(stationName, value); if (station == null) { station = value; LOG.debug("Created station {}", station); } } return station; } /** * @return the collection of the configured stations * @see ConcurrentHashMap#values() */ Collection getStations() { return stations.values(); } void clear(String station) { LOG.debug("Clearing station {}", station); stations.remove(station); } } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/Supervisor.java000066400000000000000000000025731305060074600263250ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 09/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; /** * A {@link Supervisor} can inspect every event transmitted to a {@link Station} before it's handed over to the station {@link Listener}s interested in that type of event. * * @author Andrea Vacondio * */ public interface Supervisor { /** * Empty implementation of the {@link Supervisor}. */ Supervisor SLACKER = new Supervisor() { public void inspect(Object event) { // give me a break! } @Override public String toString() { return "SLACKER"; } }; /** * Inspect the event * * @param event */ void inspect(Object event); } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/annotation/000077500000000000000000000000001305060074600254445ustar00rootroot00000000000000event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/annotation/EventListener.java000066400000000000000000000034771305060074600311110ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 15/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.sejda.eventstudio.ReferenceStrength; /** * Annotated methods will be registered as Listener for the event in the method signature. Method signature must have a single parameter from which the event class will be * inferred. Multiple methods on the same pojo can be annotated. * * @author Andrea Vacondio * */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface EventListener { /** * @return the priority for this listener, low numbers mean high priority. */ int priority() default 0; /** * @return the station for this listener. If nothing is specified the {@link EventStation} annotated field or method will be used. */ String station() default ""; /** * @return the reference strength for this listener. */ ReferenceStrength strength() default ReferenceStrength.STRONG; } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/annotation/EventStation.java000066400000000000000000000027341305060074600307400ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 15/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Annotation to allow the definition of an event station with it's name defined at runtime when the annotation is processed. A {@link String} or {@link Enum} field or a method * returning a {@link String} or {@link Enum} can be annotated and all the {@link EventListener} found in the pojo will be registered as listener for the given station. * * @author Andrea Vacondio * */ @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.FIELD }) public @interface EventStation { // nothing } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/exception/000077500000000000000000000000001305060074600252705ustar00rootroot00000000000000BroadcastInterruptionException.java000066400000000000000000000020201305060074600342520ustar00rootroot00000000000000event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/exception/* * This file is part of the EventStudio source code * Created on 09/ott/2014 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.exception; /** * Exception thrown by listeners to interrupt broadcast of an event. * * @author Andrea Vacondio * */ public class BroadcastInterruptionException extends EventStudioException { public BroadcastInterruptionException(String message) { super(message); } } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/exception/EventStudioException.java000066400000000000000000000022341305060074600322640ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 12/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.exception; /** * Exception thrown by the event studio library * * @author Andrea Vacondio * */ public class EventStudioException extends RuntimeException { public EventStudioException(String message, Throwable cause) { super(message, cause); } public EventStudioException(String message) { super(message); } public EventStudioException(Throwable cause) { super(cause); } } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/util/000077500000000000000000000000001305060074600242475ustar00rootroot00000000000000event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/util/ReflectionUtils.java000066400000000000000000000035301305060074600302260ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 10/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.util; import java.lang.reflect.Method; import java.lang.reflect.Type; /** * Utility class used to infer the parameter type of an input method of an input class * * @author Andrea Vacondio * */ public final class ReflectionUtils { private ReflectionUtils() { // hide } /** * Given a concrete class and a method name, it tries to infer the Class of the first parameter of the method * * @param clazz * @param methodName * @return the class or null if nothing found */ @SuppressWarnings("rawtypes") public static Class inferParameterClass(Class clazz, String methodName) { Method[] methods = clazz.getMethods(); for (Method method : methods) { if (method.getName().equals(methodName) && !method.isBridge()) { Type[] types = method.getGenericParameterTypes(); for (Type type : types) { if (type instanceof Class && !((Class) type).isInterface()) { return ((Class) type); } } } } return null; } } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/util/RequireUtils.java000066400000000000000000000033271305060074600275540ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 10/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.util; import static org.sejda.eventstudio.util.StringUtils.isBlank; /** * Utility class with some helper method to check validity of input arguments * * @author Andrea Vacondio * */ public final class RequireUtils { private RequireUtils() { // hide } /** * Requires that the input string is not blank * * @param victim * @throws IllegalArgumentException * if the input is blank */ public static void requireNotBlank(String victim) { if (isBlank(victim)) { throw new IllegalArgumentException("The input string cannot be blank"); } } /** * Requires that the input argument is not null * * @param victim * @throws IllegalArgumentException * if the input is null */ public static void requireNotNull(Object victim) { if (victim == null) { throw new IllegalArgumentException("The input object cannot be null"); } } } event-studio-v-1.0.6/src/main/java/org/sejda/eventstudio/util/StringUtils.java000066400000000000000000000026371305060074600274110ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 15/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.util; /** * Simple utility methods {@link String} related. * * @author Andrea Vacondio * */ public final class StringUtils { private StringUtils() { // utility } public static boolean isBlank(String input) { return input == null || input.trim().length() <= 0; } public static boolean isNotBlank(String input) { return !isBlank(input); } /** * @param input * @param defaultValue * @return the unchanged input if it's not blank, the default value otherwise */ public static String defaultString(String input, String defaultValue) { return StringUtils.isBlank(input) ? defaultValue : input; } } event-studio-v-1.0.6/src/test/000077500000000000000000000000001305060074600161565ustar00rootroot00000000000000event-studio-v-1.0.6/src/test/java/000077500000000000000000000000001305060074600170775ustar00rootroot00000000000000event-studio-v-1.0.6/src/test/java/org/000077500000000000000000000000001305060074600176665ustar00rootroot00000000000000event-studio-v-1.0.6/src/test/java/org/sejda/000077500000000000000000000000001305060074600207545ustar00rootroot00000000000000event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/000077500000000000000000000000001305060074600233255ustar00rootroot00000000000000event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/AnnotationsTest.java000066400000000000000000000160671305060074600273370ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 16/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.junit.Assert.assertEquals; import java.lang.reflect.InvocationTargetException; import java.util.List; import org.junit.Test; import org.sejda.eventstudio.Annotations.ReflectiveListenerDescriptor; import org.sejda.eventstudio.Annotations.ReflectiveMetadata; import org.sejda.eventstudio.annotation.EventListener; import org.sejda.eventstudio.annotation.EventStation; import org.sejda.eventstudio.exception.EventStudioException; /** * @author Andrea Vacondio * */ public class AnnotationsTest { @Test public void stationField() throws IllegalAccessException, InvocationTargetException { ReflectiveMetadata metadata = Annotations.process(new StationField()); assertEquals("StationField", metadata.getStation()); assertEquals(1, metadata.getDescriptors().size()); } @Test public void stationFieldEnum() throws IllegalAccessException, InvocationTargetException { ReflectiveMetadata metadata = Annotations.process(new StationFieldEnum()); assertEquals("CHUCK", metadata.getStation()); assertEquals(0, metadata.getDescriptors().size()); } @Test public void stationMethod() throws IllegalAccessException, InvocationTargetException { ReflectiveMetadata metadata = Annotations.process(new StationMethod()); assertEquals("myStation", metadata.getStation()); assertEquals(2, metadata.getDescriptors().get("").size()); } @Test public void stationMethodEnum() throws IllegalAccessException, InvocationTargetException { ReflectiveMetadata metadata = Annotations.process(new StationMethodEnum()); assertEquals("NORRIS", metadata.getStation()); assertEquals(0, metadata.getDescriptors().size()); } @Test(expected = EventStudioException.class) public void wrongListener() throws IllegalAccessException, InvocationTargetException { Annotations.process(new WrongListener()); } @Test(expected = EventStudioException.class) public void wrongStation() throws IllegalAccessException, InvocationTargetException { Annotations.process(new WrongStation()); } @Test public void listenerWithStation() throws IllegalAccessException, InvocationTargetException { ReflectiveMetadata metadata = Annotations.process(new ListenerWithStation()); assertEquals(1, metadata.getDescriptors().get("MyPersonalStation").size()); } @Test public void inheritedListeners() throws IllegalAccessException, InvocationTargetException { ReflectiveMetadata metadata = Annotations.process(new ChildListener()); List parentStation = metadata.getDescriptors().get("parentStation"); assertEquals(1, parentStation.size()); assertEquals("inheritedListen", parentStation.get(0).getMethod().getName()); } @Test public void privateListeners() throws IllegalAccessException, InvocationTargetException { ReflectiveMetadata metadata = Annotations.process(new ChildListener()); List childStation = metadata.getDescriptors().get("childStation"); assertEquals(1, childStation.size()); assertEquals("privateListen", childStation.get(0).getMethod().getName()); } @Test public void overriddenNotAnnotatedListeners() throws IllegalAccessException, InvocationTargetException { ReflectiveMetadata metadata = Annotations.process(new ChildListener()); List hiddenStation = metadata.getDescriptors().get(""); assertEquals(null, hiddenStation); } @Test public void overriddenAnnotateListeners() throws IllegalAccessException, InvocationTargetException { ReflectiveMetadata metadata = Annotations.process(new AnnotatedChildListener()); List hiddenStation = metadata.getDescriptors().get(""); assertEquals(1, hiddenStation.size()); assertEquals("listen", hiddenStation.get(0).getMethod().getName()); assertEquals(AnnotatedChildListener.class, hiddenStation.get(0).getMethod().getDeclaringClass()); } public static class ParentListener { @EventListener public void listen(String event) { // nothing } @EventListener(station = "parentStation") public void inheritedListen(String event) { // nothing } } public static class ChildListener extends ParentListener { @Override public void listen(String event) { // nothing } @EventListener(station = "childStation") private void privateListen(String another) { // nothing } } public static class AnnotatedChildListener extends ParentListener { @EventListener public void listen(String event) { // nothing } @EventListener(station = "childStation") private void privateListen(String another) { // nothing } } public static class WrongStation { @EventStation public String withParams(Object first) { return first.toString(); } } public static class WrongListener { @EventListener public void twoParams(Object first, Object second) { } } public static class StationField { @EventStation private String station = "StationField"; @EventListener public void listenFor(Object event) { // nothing } } public static class StationMethod { @EventStation String stationName() { return "myStation"; } @EventListener public void first(Object event) { // nothing } @EventListener public void second(Object event) { // nothing } } public static class ListenerWithStation { @EventListener(station = "MyPersonalStation") public void listenFor(Object event) { // nothing } } public enum WhateverEnum { CHUCK, NORRIS; } public static class StationFieldEnum { @EventStation private WhateverEnum station = WhateverEnum.CHUCK; } public static class StationMethodEnum { @EventStation WhateverEnum stationName() { return WhateverEnum.NORRIS; } } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/DefaultEventStudioTest.java000066400000000000000000000156051305060074600306150ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 15/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.mockito.Matchers.anyListOf; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.sejda.eventstudio.DefaultEventStudio; import org.sejda.eventstudio.Listener; import org.sejda.eventstudio.ReferenceStrength; import org.sejda.eventstudio.Station; import org.sejda.eventstudio.Stations; import org.sejda.eventstudio.Supervisor; import org.sejda.eventstudio.Annotations.ReflectiveListenerDescriptor; /** * @author Andrea Vacondio * */ public class DefaultEventStudioTest { private static final String STATION = "station"; @Mock private Station anotherStation, station, hidden; @Mock private Stations stations; @Mock private Supervisor supervisor; @Mock private Listener listener; @Mock private Object event; @InjectMocks private DefaultEventStudio victim; @Before public void initMocks() { MockitoAnnotations.initMocks(this); when(stations.getStation(DefaultEventStudio.HIDDEN_STATION)).thenReturn(hidden); when(stations.getStation(STATION)).thenReturn(station); when(stations.getStation("anotherStation")).thenReturn(anotherStation); List stationsCollection = new ArrayList(); stationsCollection.add(hidden); stationsCollection.add(station); when(stations.getStations()).thenReturn(stationsCollection); } @Test public void addHiddenStation() { victim.add(listener); verify(stations).getStation(DefaultEventStudio.HIDDEN_STATION); verify(hidden).add(listener, 0, ReferenceStrength.STRONG); } @Test public void addHiddenStationWithEventClass() { victim.add(Object.class, listener); verify(stations).getStation(DefaultEventStudio.HIDDEN_STATION); verify(hidden).add(Object.class, listener, 0, ReferenceStrength.STRONG); } @Test public void addStation() { victim.add(listener, STATION); verify(stations).getStation(STATION); verify(station).add(listener, 0, ReferenceStrength.STRONG); } @Test public void addStationWithEventClass() { victim.add(Object.class, listener, STATION); verify(stations).getStation(STATION); verify(station).add(Object.class, listener, 0, ReferenceStrength.STRONG); } @Test public void addHiddenStationWithPriority() { victim.add(listener, 1, ReferenceStrength.SOFT); verify(stations).getStation(DefaultEventStudio.HIDDEN_STATION); verify(hidden).add(listener, 1, ReferenceStrength.SOFT); } @Test public void addHiddenStationWithPriorityAndEventClass() { victim.add(Object.class, listener, 1, ReferenceStrength.SOFT); verify(stations).getStation(DefaultEventStudio.HIDDEN_STATION); verify(hidden).add(Object.class, listener, 1, ReferenceStrength.SOFT); } @Test public void addStationWithPriority() { victim.add(listener, STATION, 1, ReferenceStrength.SOFT); verify(stations).getStation(STATION); verify(station).add(listener, 1, ReferenceStrength.SOFT); } @Test public void addStationWithPriorityAndEventClass() { victim.add(Object.class, listener, STATION, 1, ReferenceStrength.SOFT); verify(stations).getStation(STATION); verify(station).add(Object.class, listener, 1, ReferenceStrength.SOFT); } @Test(expected = IllegalArgumentException.class) public void nullSupervisor() { victim.supervisor(null); } @Test public void removeHidden() { victim.remove(listener); verify(stations).getStation(DefaultEventStudio.HIDDEN_STATION); verify(hidden).remove(listener); } @Test public void removeHiddenWithClass() { victim.remove(Object.class, listener); verify(stations).getStation(DefaultEventStudio.HIDDEN_STATION); verify(hidden).remove(Object.class, listener); } @Test public void removeFromStation() { victim.remove(listener, STATION); verify(stations).getStation(STATION); verify(station).remove(listener); } @Test public void removeFromStationWithClass() { victim.remove(Object.class, listener, STATION); verify(stations).getStation(STATION); verify(station).remove(Object.class, listener); } @Test public void SupervisorHidden() { victim.supervisor(supervisor); verify(stations).getStation(DefaultEventStudio.HIDDEN_STATION); verify(hidden).supervior(supervisor); } @Test public void Supervisor() { victim.supervisor(supervisor, STATION); verify(stations).getStation(STATION); verify(station).supervior(supervisor); } @Test public void clearHidden() { victim.clear(); verify(stations).clear(DefaultEventStudio.HIDDEN_STATION); } @Test public void clear() { victim.clear(STATION); verify(stations).clear(STATION); } @Test public void broadcastHidden() { victim.broadcast(event); verify(stations).getStation(DefaultEventStudio.HIDDEN_STATION); verify(hidden).broadcast(event); } @Test public void broadcastStation() { victim.broadcast(event, STATION); verify(stations).getStation(STATION); verify(station).broadcast(event); } @Test public void broadcastAll() { victim.broadcastToEveryStation(event); verify(hidden).broadcast(event); verify(station).broadcast(event); } @Test public void addAnnotatedListeners() { TestAnnotatedBean bean = new TestAnnotatedBean(); victim.addAnnotatedListeners(bean); verify(stations).getStation(STATION); verify(stations).getStation("anotherStation"); verify(station).addAll(eq(bean), anyListOf(ReflectiveListenerDescriptor.class)); verify(anotherStation).addAll(eq(bean), anyListOf(ReflectiveListenerDescriptor.class)); } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/EntityTest.java000066400000000000000000000032301305060074600263020ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 14/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import java.lang.ref.SoftReference; import org.junit.Test; import org.sejda.eventstudio.Entity; import org.sejda.eventstudio.Entity.ReferencedEntity; import org.sejda.eventstudio.Entity.StrongEntity; /** * @author Andrea Vacondio * */ public class EntityTest { @Test public void testNull() { Entity victim = new StrongEntity(null); assertNull(victim.get()); } @Test public void testStrong() { Object referent = new Object(); Entity victim = new StrongEntity(referent); assertEquals(referent, victim.get()); } @Test public void testReference() { Object referent = new Object(); Entity victim = new ReferencedEntity(new SoftReference(referent)); assertEquals(referent, victim.get()); } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/EnvelopeTest.java000066400000000000000000000030301305060074600266010ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 14/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; import org.sejda.eventstudio.Envelope; /** * @author Andrea Vacondio * */ public class EnvelopeTest { @Test(expected = IllegalArgumentException.class) public void testNull() { new Envelope(null); } @Test public void testGet() { Object message = new Object(); Envelope victim = new Envelope(message); assertEquals(message, victim.getEvent()); } @Test public void isNotified() { Object message = new Object(); Envelope victim = new Envelope(message); assertFalse(victim.isNotified()); victim.notified(); assertTrue(victim.isNotified()); } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/ListenersTest.java000066400000000000000000000170451305060074600270070ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 14/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.sejda.eventstudio.util.StringUtils.defaultString; import java.lang.reflect.InvocationTargetException; import java.util.List; import java.util.Map.Entry; import org.junit.Before; import org.junit.Test; import org.sejda.eventstudio.Annotations.ReflectiveListenerDescriptor; import org.sejda.eventstudio.Annotations.ReflectiveMetadata; import org.sejda.eventstudio.Listeners.ListenerReferenceHolder; import org.sejda.eventstudio.annotation.EventListener; /** * @author Andrea Vacondio * */ public class ListenersTest { private Listeners victim; @Before public void setUp() { victim = new Listeners(); } @Test public void add() { assertTrue(victim.nullSafeGetListeners(TestEvent.class).isEmpty()); victim.add(TestEvent.class, new TestListener(), 0, ReferenceStrength.STRONG); assertFalse(victim.nullSafeGetListeners(TestEvent.class).isEmpty()); assertEquals(1, victim.nullSafeGetListeners(TestEvent.class).size()); } @Test public void addSameListener() { TestListener listener = new TestListener(); victim.add(TestEvent.class, listener, 0, ReferenceStrength.STRONG); victim.add(TestEvent.class, listener, -1, ReferenceStrength.STRONG); assertEquals(2, victim.nullSafeGetListeners(TestEvent.class).size()); } @Test public void addManyDiffenent() { victim.add(AnotherTestEvent.class, new AnotherTestListener(), 0, ReferenceStrength.STRONG); victim.add(TestEvent.class, new TestListener(), -1, ReferenceStrength.STRONG); victim.add(TestEvent.class, new SecondTestListener(), -1, ReferenceStrength.STRONG); assertEquals(2, victim.nullSafeGetListeners(TestEvent.class).size()); assertEquals(1, victim.nullSafeGetListeners(AnotherTestEvent.class).size()); } @Test public void remove() { TestListener listener = new TestListener(); assertTrue(victim.nullSafeGetListeners(TestEvent.class).isEmpty()); victim.add(TestEvent.class, listener, 0, ReferenceStrength.STRONG); assertFalse(victim.nullSafeGetListeners(TestEvent.class).isEmpty()); victim.remove(TestEvent.class, listener); assertTrue(victim.nullSafeGetListeners(TestEvent.class).isEmpty()); } @Test public void removeMany() { TestListener listener = new TestListener(); SecondTestListener listener2 = new SecondTestListener(); AnotherTestListener anotherListener = new AnotherTestListener(); victim.add(TestEvent.class, listener, 0, ReferenceStrength.STRONG); victim.add(TestEvent.class, listener2, 0, ReferenceStrength.WEAK); victim.add(AnotherTestEvent.class, anotherListener, 0, ReferenceStrength.SOFT); assertFalse(victim.nullSafeGetListeners(TestEvent.class).isEmpty()); assertFalse(victim.nullSafeGetListeners(AnotherTestEvent.class).isEmpty()); assertTrue(victim.remove(TestEvent.class, listener2)); assertTrue(victim.remove(AnotherTestEvent.class, anotherListener)); assertTrue(victim.nullSafeGetListeners(AnotherTestEvent.class).isEmpty()); assertEquals(1, victim.nullSafeGetListeners(TestEvent.class).size()); } @Test public void removeHolder() { TestListener listener = new TestListener(); assertTrue(victim.nullSafeGetListeners(TestEvent.class).isEmpty()); victim.add(TestEvent.class, listener, 0, ReferenceStrength.STRONG); for (ListenerReferenceHolder holder : victim.nullSafeGetListeners(TestEvent.class)) { assertTrue(victim.remove(TestEvent.class, holder)); } assertTrue(victim.nullSafeGetListeners(TestEvent.class).isEmpty()); } @Test public void falseRemove() { TestListener listener = new TestListener(); AnotherTestListener anotherListener = new AnotherTestListener(); victim.add(TestEvent.class, listener, 0, ReferenceStrength.STRONG); assertFalse(victim.remove(AnotherTestEvent.class, anotherListener)); } @Test public void priorityOrder() throws IllegalAccessException, InvocationTargetException { TestListener prio0 = new TestListener(); TestListener prio1 = new TestListener(); TestListener prio2 = new TestListener(); TestListener prio3 = new TestListener(); TestListener prio4 = new TestListener(); TestListener prio5 = new TestListener(); TestListener prio6 = new TestListener(); TestListener prio7 = new TestListener(); TestListener prio8 = new TestListener(); TestListener prio9 = new TestListener(); victim.add(TestEvent.class, prio7, 7, ReferenceStrength.STRONG); victim.add(TestEvent.class, prio9, 9, ReferenceStrength.STRONG); victim.add(TestEvent.class, prio0, 0, ReferenceStrength.STRONG); victim.add(TestEvent.class, prio1, 1, ReferenceStrength.STRONG); victim.add(TestEvent.class, prio2, 2, ReferenceStrength.STRONG); victim.add(TestEvent.class, prio5, 5, ReferenceStrength.STRONG); victim.add(TestEvent.class, prio6, 6, ReferenceStrength.STRONG); victim.add(TestEvent.class, prio8, 8, ReferenceStrength.STRONG); victim.add(TestEvent.class, prio3, 3, ReferenceStrength.STRONG); victim.add(TestEvent.class, prio4, 4, ReferenceStrength.STRONG); ReflectiveTestListener bean = new ReflectiveTestListener(); ReflectiveMetadata metadata = Annotations.process(bean); for (List descriptors : metadata.getDescriptors().values()) { victim.addAll(bean, descriptors); } List listeners = victim.nullSafeGetListeners(TestEvent.class); assertEquals(Integer.MIN_VALUE, listeners.get(0).priority); assertEquals(0, listeners.get(1).priority); assertEquals(1, listeners.get(2).priority); assertEquals(2, listeners.get(3).priority); assertEquals(3, listeners.get(4).priority); assertEquals(4, listeners.get(5).priority); assertEquals(4, listeners.get(6).priority); assertEquals(5, listeners.get(7).priority); assertEquals(6, listeners.get(8).priority); assertEquals(7, listeners.get(9).priority); assertEquals(8, listeners.get(10).priority); assertEquals(9, listeners.get(11).priority); assertEquals(Integer.MAX_VALUE, listeners.get(12).priority); } private static class AnotherTestListener implements Listener { public void onEvent(AnotherTestEvent event) { // nothing } } private static class SecondTestListener implements Listener { public void onEvent(TestEvent event) { // nothing } } private static class TestListener implements Listener { public void onEvent(TestEvent event) { // nothing } } private static class ReflectiveTestListener implements Listener { @EventListener(priority = 4) public void onEvent(TestEvent event) { // nothing } @EventListener(priority = Integer.MIN_VALUE) public void onSuperPrioEvent(TestEvent event) { // nothing } @EventListener(priority = Integer.MAX_VALUE) public void onLowestPrioEvent(TestEvent event) { // nothing } } private static class TestEvent { // nothing } private static class AnotherTestEvent { // nothing } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/StaticStudioTest.java000066400000000000000000000020101305060074600274400ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 16/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.junit.Assert.assertNotNull; import org.junit.Test; import org.sejda.eventstudio.StaticStudio; /** * @author Andrea Vacondio * */ public class StaticStudioTest { @Test public void notNull() { assertNotNull(StaticStudio.eventStudio()); } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/StationTest.java000066400000000000000000000203621305060074600264540ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 14/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import java.lang.reflect.InvocationTargetException; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.runners.MockitoJUnitRunner; import org.sejda.eventstudio.Annotations.ReflectiveMetadata; import org.sejda.eventstudio.annotation.EventListener; import org.sejda.eventstudio.exception.BroadcastInterruptionException; import org.sejda.eventstudio.exception.EventStudioException; /** * @author Andrea Vacondio * */ @RunWith(MockitoJUnitRunner.class) public class StationTest { private Station victim; @Mock private Listener mockListener; @Mock private Listener anotherMockListener; @Mock private Object bean; @Before public void setUp() { victim = new Station("victim"); } @After public void tearDown() { victim.remove(mockListener); victim.remove(anotherMockListener); System.clearProperty(EventStudio.MAX_QUEUE_SIZE_PROP); } @Test public void name() { assertEquals("victim", victim.name()); } @Test(expected = IllegalArgumentException.class) public void addNullListener() { victim.add(null, 0, ReferenceStrength.WEAK); } @Test(expected = IllegalArgumentException.class) public void addNullListenerLong() { victim.add(Object.class, null, 0, ReferenceStrength.WEAK); } @Test(expected = IllegalArgumentException.class) public void nullEvent() { victim.add(null, mockListener, 0, ReferenceStrength.WEAK); } @Test(expected = IllegalArgumentException.class) public void nullBroadcastEvent() { victim.broadcast(null); } @Test(expected = IllegalArgumentException.class) public void nullAddAll() { victim.addAll(bean, null); } @Test public void supervisor() { Supervisor supervisor = mock(Supervisor.class); Object event = new Object(); victim.supervior(supervisor); victim.broadcast(event); verify(supervisor).inspect(event); } @Test public void addAndBroadcast() { Object event = new Object(); victim.add(Object.class, mockListener, 0, ReferenceStrength.STRONG); victim.add(Object.class, anotherMockListener, 0, ReferenceStrength.STRONG); victim.broadcast(event); verify(mockListener).onEvent(event); verify(anotherMockListener).onEvent(event); } @Test public void annotatedAddAndBroadcast() throws IllegalAccessException, InvocationTargetException { Object event = new Object(); TestPrioritizedAnnotatedBean bean = new TestPrioritizedAnnotatedBean(); ReflectiveMetadata metadata = Annotations.process(bean); TestPrioritizedAnnotatedBean spy = spy(bean); victim.addAll(spy, metadata.getDescriptors().get("")); victim.broadcast(event); verify(spy).first(event); verify(spy).second(event); } @Test public void priority() { Object event = new Object(); InOrder inOrder = Mockito.inOrder(anotherMockListener, mockListener); victim.add(mockListener, 0, ReferenceStrength.STRONG); victim.add(anotherMockListener, -1, ReferenceStrength.STRONG); victim.broadcast(event); inOrder.verify(anotherMockListener).onEvent(event); inOrder.verify(mockListener).onEvent(event); } @Test public void broadcastInterrupted() { Object event = new Object(); doThrow(BroadcastInterruptionException.class).when(anotherMockListener).onEvent(any()); victim.add(mockListener, 0, ReferenceStrength.STRONG); victim.add(anotherMockListener, -1, ReferenceStrength.STRONG); victim.broadcast(event); verify(anotherMockListener).onEvent(event); verify(mockListener, never()).onEvent(event); } @Test public void broadcastAndAdd() { Object event = new Object(); victim.broadcast(event); victim.broadcast(event); victim.add(Object.class, mockListener, 0, ReferenceStrength.STRONG); verify(mockListener, times(2)).onEvent(event); } @Test public void broadcastAndAddAnnotated() throws IllegalAccessException, InvocationTargetException { Object event = new Object(); victim.broadcast(event); TestPrioritizedAnnotatedBean bean = new TestPrioritizedAnnotatedBean(); ReflectiveMetadata metadata = Annotations.process(bean); TestPrioritizedAnnotatedBean spy = spy(bean); victim.addAll(spy, metadata.getDescriptors().get("")); verify(spy).first(event); verify(spy).second(event); } @Test public void broadcastInterruptedAnnotated() throws IllegalAccessException, InvocationTargetException { Object event = new Object(); TestInterruptingPrioritizedAnnotatedBean bean = new TestInterruptingPrioritizedAnnotatedBean(); ReflectiveMetadata metadata = Annotations.process(bean); TestInterruptingPrioritizedAnnotatedBean spy = spy(bean); victim.addAll(spy, metadata.getDescriptors().get("")); victim.broadcast(event); verify(spy).first(event); verify(spy, never()).second(event); } @Test public void removeAndBroadcast() { Object event = new Object(); victim.add(Object.class, mockListener, 0, ReferenceStrength.STRONG); victim.remove(mockListener); victim.broadcast(event); verify(mockListener, never()).onEvent(event); } @Test public void removeExplicitAndBroadcast() { Object event = new Object(); victim.add(Object.class, mockListener, 0, ReferenceStrength.STRONG); victim.remove(Object.class, mockListener); victim.broadcast(event); verify(mockListener, never()).onEvent(event); } @Test(expected = EventStudioException.class) public void failingAdd() { SecondTestListener listener = new SecondTestListener(); victim.add(listener, 0, ReferenceStrength.STRONG); } @Test(expected = EventStudioException.class) public void failingRemove() { SecondTestListener listener = new SecondTestListener(); victim.remove(listener); } @Test public void capacity() { System.setProperty(EventStudio.MAX_QUEUE_SIZE_PROP, "3"); victim.broadcast(new Object()); victim.broadcast(new Object()); victim.broadcast(new Object()); victim.broadcast(new Object()); victim.broadcast(new Object()); victim.broadcast(new Object()); victim.add(Object.class, mockListener, 0, ReferenceStrength.STRONG); verify(mockListener, times(3)).onEvent(any(Object.class)); } private class SecondTestListener implements Listener { public void onEvent(T event) { // nothing } } private class TestInterruptingPrioritizedAnnotatedBean { @EventListener(priority = 1) public void first(Object event) { throw new BroadcastInterruptionException(""); } @EventListener(priority = 2) public void second(Object event) { } } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/StationsTest.java000066400000000000000000000033621305060074600266400ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 14/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.junit.Before; import org.junit.Test; import org.sejda.eventstudio.Station; import org.sejda.eventstudio.Stations; /** * @author Andrea Vacondio * */ public class StationsTest { private Stations victim; @Before public void setUp() { victim = new Stations(); } @Test public void get() { assertNotNull(victim.getStation("ChuckNorris")); } @Test(expected = IllegalArgumentException.class) public void notBlank() { victim.getStation(" "); } @Test public void same() { Station one = victim.getStation("ChuckNorris"); Station two = victim.getStation("ChuckNorris"); assertEquals(one, two); } @Test public void clear() { victim.getStation("ChuckNorris"); assertEquals(1, victim.getStations().size()); victim.clear("ChuckNorris"); assertEquals(0, victim.getStations().size()); } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/TestAnnotatedBean.java000066400000000000000000000024471305060074600275420ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 16/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import org.sejda.eventstudio.ReferenceStrength; import org.sejda.eventstudio.annotation.EventListener; import org.sejda.eventstudio.annotation.EventStation; /** * @author Andrea Vacondio * */ public class TestAnnotatedBean { @EventStation private static final String STATION = "station"; @EventListener public void listener(Object event) { // do something } @EventListener(station = "anotherStation", priority = 2, strength = ReferenceStrength.SOFT) public void anotherListener(Object event) { // do something } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/TestPrioritizedAnnotatedBean.java000066400000000000000000000021551305060074600317630ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 16/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio; import org.sejda.eventstudio.ReferenceStrength; import org.sejda.eventstudio.annotation.EventListener; /** * @author Andrea Vacondio * */ public class TestPrioritizedAnnotatedBean { @EventListener(priority = 1) public void first(Object event) { } @EventListener(priority = 2, strength = ReferenceStrength.SOFT) public void second(Object event) { } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/shakedown/000077500000000000000000000000001305060074600253105ustar00rootroot00000000000000event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/shakedown/AnnotatedTestListener.java000066400000000000000000000023701305060074600324400ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 20/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.shakedown; import java.util.Random; import org.sejda.eventstudio.ReferenceStrength; import org.sejda.eventstudio.annotation.EventListener; /** * @author Andrea Vacondio * */ public class AnnotatedTestListener { @EventListener(priority = 1) public void first(AnotherMyEvent event) { System.out.println(new Random().nextInt()); } @EventListener(priority = 2, strength = ReferenceStrength.WEAK) public void second(MyEvent event) { System.out.println(new Random().nextInt()); } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/shakedown/AnotherAnnotatedListener.java000066400000000000000000000026171305060074600331250ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 20/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.shakedown; import java.util.Random; import org.sejda.eventstudio.ReferenceStrength; import org.sejda.eventstudio.annotation.EventListener; import org.sejda.eventstudio.annotation.EventStation; /** * @author Andrea Vacondio * */ public class AnotherAnnotatedListener { @EventStation private static final String STATION = "station"; @EventListener public void listener(MyEvent event) { System.out.println(new Random().nextInt()); } @EventListener(station = "anotherStation", priority = 2, strength = ReferenceStrength.SOFT) public void anotherListener(OtherMyEvent event) { System.out.println(new Random().nextInt()); } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/shakedown/AnotherMyEvent.java000066400000000000000000000015161305060074600310660ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 20/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.shakedown; /** * @author Andrea Vacondio * */ public class AnotherMyEvent extends MyEvent { } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/shakedown/MyEvent.java000066400000000000000000000014671305060074600275520ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 20/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.shakedown; /** * @author Andrea Vacondio * */ public class MyEvent { } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/shakedown/OtherMyEvent.java000066400000000000000000000015141305060074600305450ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 20/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.shakedown; /** * @author Andrea Vacondio * */ public class OtherMyEvent extends MyEvent { } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/shakedown/ShakedownTest.java000066400000000000000000000102221305060074600307330ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 20/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.shakedown; import static org.sejda.eventstudio.StaticStudio.eventStudio; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.sejda.eventstudio.DefaultEventStudio; import org.sejda.eventstudio.ReferenceStrength; /** * @author Andrea Vacondio * */ public class ShakedownTest { private ExecutorService executor = Executors.newFixedThreadPool(10); private List stations = new ArrayList(); private Set> tasks = new HashSet>(); @Before public void setUp() { stations.add("station"); stations.add("anotherStation"); stations.add(DefaultEventStudio.HIDDEN_STATION); TestListener listener = new TestListener(); for (int i = 0; i < 2000; i++) { tasks.add(new BroadcastTask(new MyEvent())); tasks.add(new BroadcastTask(new AnotherMyEvent())); tasks.add(new BroadcastTask(new OtherMyEvent())); } for (int i = 0; i < 200; i++) { tasks.add(new RemoveTask(listener)); tasks.add(new AddTask(listener)); tasks.add(new AddAnnotatedTask(new AnnotatedTestListener())); tasks.add(new AddAnnotatedTask(new AnotherAnnotatedListener())); tasks.add(new ClearTask()); } } @After public void tearDown() throws InterruptedException { executor.shutdown(); executor.awaitTermination(5 * 60, TimeUnit.SECONDS); } @Test public void shakedown() throws InterruptedException { executor.invokeAll(tasks); } private class RemoveTask implements Callable { private TestListener listener; public RemoveTask(TestListener listener) { this.listener = listener; } public Void call() { eventStudio().remove(listener, stations.get(new Random().nextInt(3))); return null; } } private class AddTask implements Callable { private TestListener listener; public AddTask(TestListener listener) { this.listener = listener; } public Void call() { Random rand = new Random(); eventStudio().add(listener, stations.get(rand.nextInt(3)), rand.nextInt(1000), ReferenceStrength.STRONG); return null; } } private class AddAnnotatedTask implements Callable { private Object bean; public AddAnnotatedTask(Object bean) { this.bean = bean; } public Void call() { eventStudio().addAnnotatedListeners(bean); return null; } } private class BroadcastTask implements Callable { private MyEvent event; public BroadcastTask(MyEvent event) { this.event = event; } public Void call() { eventStudio().broadcast(this.event, stations.get(new Random().nextInt(3))); return null; } } private class ClearTask implements Callable { public Void call() { eventStudio().clear(stations.get(new Random().nextInt(3))); return null; } } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/shakedown/TestListener.java000066400000000000000000000020371305060074600306020ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 20/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.shakedown; import java.util.Random; import org.sejda.eventstudio.Listener; /** * @author Andrea Vacondio * */ public class TestListener implements Listener { private Random rand = new Random(); public void onEvent(MyEvent event) { System.out.println(rand.nextInt()); } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/util/000077500000000000000000000000001305060074600243025ustar00rootroot00000000000000event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/util/ReflectionUtilsTest.java000066400000000000000000000033671305060074600311310ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 14/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.util; import static org.junit.Assert.assertEquals; import org.junit.Test; import org.sejda.eventstudio.Listener; import org.sejda.eventstudio.util.ReflectionUtils; /** * @author Andrea Vacondio * */ public class ReflectionUtilsTest { @Test public void testInfer() { TestListener victim = new TestListener(); assertEquals(TestEvent.class, ReflectionUtils.inferParameterClass(victim.getClass(), "onEvent")); } @Test public void testFailingInfer() { SecondTestListener victim = new SecondTestListener(); assertEquals(null, ReflectionUtils.inferParameterClass(victim.getClass(), "onEvent")); } private class TestListener implements Listener { public void onEvent(TestEvent event) { // nothing } } private static class TestEvent { } private class SecondTestListener implements Listener { public void onEvent(T event) { // nothing } } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/util/RequireUtilsTest.java000066400000000000000000000027001305060074600304410ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 14/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.util; import static org.sejda.eventstudio.util.RequireUtils.requireNotBlank; import static org.sejda.eventstudio.util.RequireUtils.requireNotNull; import org.junit.Test; /** * @author Andrea Vacondio * */ public class RequireUtilsTest { @Test(expected = IllegalArgumentException.class) public void nullArg() { requireNotNull(null); } @Test(expected = IllegalArgumentException.class) public void blankArg() { requireNotBlank(" "); } @Test(expected = IllegalArgumentException.class) public void emptyArg() { requireNotBlank(""); } @Test(expected = IllegalArgumentException.class) public void nullStringArg() { requireNotBlank(null); } } event-studio-v-1.0.6/src/test/java/org/sejda/eventstudio/util/StringUtilsTest.java000066400000000000000000000035351305060074600303020ustar00rootroot00000000000000/* * This file is part of the EventStudio source code * Created on 15/nov/2013 * Copyright 2013 by Andrea Vacondio (andrea.vacondio@gmail.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.sejda.eventstudio.util; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; import org.sejda.eventstudio.util.StringUtils; /** * @author Andrea Vacondio * */ public class StringUtilsTest { @Test public void isBlank() { assertTrue(StringUtils.isBlank("")); assertTrue(StringUtils.isBlank(" ")); assertTrue(StringUtils.isBlank(null)); assertFalse(StringUtils.isBlank("ChuckNorris")); } @Test public void isNotBlank() { assertFalse(StringUtils.isNotBlank("")); assertFalse(StringUtils.isNotBlank(" ")); assertFalse(StringUtils.isNotBlank(null)); assertTrue(StringUtils.isNotBlank("ChuckNorris")); } @Test public void defaultString() { assertEquals("default", StringUtils.defaultString(" ", "default")); assertEquals("default", StringUtils.defaultString("", "default")); assertEquals("default", StringUtils.defaultString(null, "default")); assertEquals("input", StringUtils.defaultString("input", "default")); } } event-studio-v-1.0.6/src/test/resources/000077500000000000000000000000001305060074600201705ustar00rootroot00000000000000event-studio-v-1.0.6/src/test/resources/logback-test.xml000066400000000000000000000005301305060074600232670ustar00rootroot00000000000000 %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n