From c50b8b3c494756e5779da4e4cb28cd6bacfe0c0e Mon Sep 17 00:00:00 2001 From: 7orivorian <7orivorian+github@gmail.com> Date: Wed, 3 Jul 2024 02:35:47 -0400 Subject: [PATCH 01/30] Bump version from 3.3.0 -> 4.0.0 Signed-off-by: 7orivorian <7orivorian+github@gmail.com> --- README.md | 6 +++--- pom.xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 83e33ab..a7c8365 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Lightweight Java event library created and maintained by [7orivorian](https://gi com.github.7orivorian Wraith - 3.3.0 + 4.0.0 ``` @@ -51,13 +51,13 @@ repositories { ```gradle dependencies { - implementation 'com.github.7orivorian:Wraith:3.3.0' + implementation 'com.github.7orivorian:Wraith:4.0.0' } ``` ### Other -Download a `.jar` file from [releases](https://github.com/7orivorian/Wraith/releases/tag/3.3.0) +Download a `.jar` file from [releases](https://github.com/7orivorian/Wraith/releases/tag/4.0.0) # Building diff --git a/pom.xml b/pom.xml index c829fcb..8bafb7e 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ me.tori Wraith jar - 3.3.0 + 4.0.0 From f17ce4be5137957dbb509f3b59704c251ba3cb9c Mon Sep 17 00:00:00 2001 From: 7orivorian <7orivorian+github@gmail.com> Date: Wed, 3 Jul 2024 02:36:12 -0400 Subject: [PATCH 02/30] Remove features deprecated in 3.3.0 Signed-off-by: 7orivorian <7orivorian+github@gmail.com> --- .../java/me/tori/wraith/bus/EventBus.java | 95 +------------------ .../tori/wraith/bus/InvertableEventBus.java | 54 ----------- .../tori/wraith/bus/TargetableEventBus.java | 55 ----------- .../targetedevent/TargetedEventTest.java | 33 +++++-- 4 files changed, 26 insertions(+), 211 deletions(-) delete mode 100644 src/main/java/me/tori/wraith/bus/InvertableEventBus.java delete mode 100644 src/main/java/me/tori/wraith/bus/TargetableEventBus.java diff --git a/src/main/java/me/tori/wraith/bus/EventBus.java b/src/main/java/me/tori/wraith/bus/EventBus.java index 7879c69..e22d11d 100644 --- a/src/main/java/me/tori/wraith/bus/EventBus.java +++ b/src/main/java/me/tori/wraith/bus/EventBus.java @@ -35,7 +35,7 @@ import java.util.function.Supplier; /** - * Default implementation of {@link IEventBus}, {@link TargetableEventBus}, and {@link InvertableEventBus}. + * Default implementation of {@link IEventBus}. * *

Manages event subscription, dispatching, and listener registration. * @@ -43,7 +43,7 @@ * @since 1.0.0 */ @SuppressWarnings({"rawtypes", "unchecked"}) -public class EventBus implements TargetableEventBus, InvertableEventBus { +public class EventBus implements IEventBus { /** * The amount of {@linkplain EventBus} instances that have been created @@ -244,97 +244,6 @@ public boolean dispatch(Object event, Class type, boolean invertPriority) { return false; } - /** - * Dispatches the given event to the target listener class - * - * @param event the {@linkplain IClassTargetingEvent} to be dispatched - * @return {@code true} if the given event was {@linkplain IStatusEvent suppressed or terminated} by any listener, - * {@code false} otherwise - * @throws NullPointerException if the given event is {@code null} - * @throws UnsupportedOperationException if this event bus is {@link #shutdown} - * @deprecated This method's functionality is now built into {@link #dispatch(Object)}. - */ - @Deprecated(since = "3.3.0", forRemoval = true) - @Override - public boolean dispatchTargeted(IClassTargetingEvent event) { - return dispatchTargeted(event, null); - } - - /** - * Dispatches the given {@link IClassTargetingEvent} to the target listener class. - * - *

The {@code type} parameter serves as a filtering mechanism for listeners, enabling you to selectively invoke - * listeners based on their type, allowing for more targeted event handling. - * - * @param event the {@linkplain IClassTargetingEvent} to be dispatched - * @param type the type of listener to invoke (can be {@code null}) - * @return {@code true} if the given event is {@linkplain IStatusEvent suppressed or terminated} by any listener, - * {@code false} otherwise - * @throws NullPointerException if the given event is {@code null} - * @throws UnsupportedOperationException if this event bus is {@link #shutdown} - * @deprecated This method's functionality is now built into {@link #dispatch(Object, Class)}. - */ - @Deprecated(since = "3.3.0", forRemoval = true) - @Override - public boolean dispatchTargeted(IClassTargetingEvent event, Class type) { - return dispatch(event, type); - } - - /** - * Dispatches an event to listeners in order of inverse-priority. - * E.g., the lowest priority listeners will be invoked before the highest priority listeners. - * - * @param event the event to be dispatched - * @return {@code true} if the given event is {@linkplain IStatusEvent suppressed or terminated} by any listener, - * {@code false} otherwise - * @throws NullPointerException if the given event is {@code null} - * @throws UnsupportedOperationException if this event bus is {@link #shutdown} - * @deprecated This method's functionality is now built into {@link #dispatch(Object)}. - */ - @Deprecated(since = "3.3.0", forRemoval = true) - @Override - public boolean dispatchInverted(Object event) { - return dispatchInverted(event, null); - } - - /** - * Dispatches an event to listeners in order of inverse-priority. - * E.g., the lowest priority listeners will be invoked before the highest priority listeners. - * - *

The {@code type} parameter serves as a filtering mechanism for listeners, enabling you to selectively invoke - * listeners based on their type, allowing for more targeted event handling. - * - * @param event the event to be dispatched - * @param type the type of listener to invoke (can be {@code null}) - * @return {@code true} if the given event is {@linkplain IStatusEvent suppressed or terminated} by any listener, - * {@code false} otherwise - * @throws NullPointerException if the given event is {@code null} - * @throws UnsupportedOperationException if this event bus is {@link #shutdown} - * @deprecated This method's functionality is now built into {@link #dispatch(Object)}. - */ - @Deprecated(since = "3.3.0", forRemoval = true) - @Override - public boolean dispatchInverted(Object event, Class type) { - Objects.requireNonNull(event, "Cannot dispatch a null event to event bus " + id + "!"); - if (isShutdown()) { - throw new UnsupportedOperationException("Dispatcher " + id + " is shutdown!"); - } else { - taskExecutor.onEvent(event); - - dispatchToEachListener( - event, - this.listeners.get(event.getClass()), - listener -> listener.isAcceptableType(type) && IClassTargetingEvent.isListenerTargetedByEvent(listener, event), - true - ); - - if (event instanceof IStatusEvent e) { - return e.isSuppressed() || e.isTerminated(); - } - } - return false; - } - /** * Schedules a task to be executed. * diff --git a/src/main/java/me/tori/wraith/bus/InvertableEventBus.java b/src/main/java/me/tori/wraith/bus/InvertableEventBus.java deleted file mode 100644 index a49ecbc..0000000 --- a/src/main/java/me/tori/wraith/bus/InvertableEventBus.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2021-2024 7orivorian. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package me.tori.wraith.bus; - -import me.tori.wraith.event.status.IStatusEvent; - -/** - * @author 7orivorian - * @since 3.0.0 - * @deprecated This event bus' functionality is now built into the {@linkplain IEventBus standard event bus}. - */ -@Deprecated(since = "3.3.0", forRemoval = true) -public interface InvertableEventBus extends IEventBus { - - /** - * @param event the event to be dispatched - * @return {@code true} if the given event is {@linkplain IStatusEvent suppressed or terminated} by any listener, - * {@code false} otherwise - * @see EventBus#dispatchInverted(Object) - * @deprecated This method's functionality is now handled by {@link #dispatch(Object, boolean)}. - */ - @Deprecated(since = "3.3.0", forRemoval = true) - boolean dispatchInverted(Object event); - - /** - * @param event the event to be dispatched - * @param type the type of listener to invoke (can be {@code null}) - * @return {@code true} if the given event is {@linkplain IStatusEvent suppressed or terminated} by any listener, - * {@code false} otherwise - * @see EventBus#dispatchInverted(Object, Class) - * @deprecated This method's functionality is now handled by {@link #dispatch(Object, Class, boolean)}. - */ - @Deprecated(since = "3.3.0", forRemoval = true) - boolean dispatchInverted(Object event, Class type); -} \ No newline at end of file diff --git a/src/main/java/me/tori/wraith/bus/TargetableEventBus.java b/src/main/java/me/tori/wraith/bus/TargetableEventBus.java deleted file mode 100644 index 6bc6752..0000000 --- a/src/main/java/me/tori/wraith/bus/TargetableEventBus.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2021-2024 7orivorian. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package me.tori.wraith.bus; - -import me.tori.wraith.event.status.IStatusEvent; -import me.tori.wraith.event.targeted.IClassTargetingEvent; - -/** - * @author 7orivorian - * @since 3.0.0 - * @deprecated This event bus' functionality is now built into the {@linkplain IEventBus standard event bus}. - */ -@Deprecated(since = "3.3.0", forRemoval = true) -public interface TargetableEventBus extends IEventBus { - - /** - * @param event the {@linkplain IClassTargetingEvent} to dispatch - * @return {@code true} if the given event was {@linkplain IStatusEvent suppressed or terminated} by any listener, - * {@code false} otherwise - * @see EventBus#dispatchTargeted(IClassTargetingEvent) - * @deprecated This method's functionality is now built into {@link #dispatch(Object)} - */ - @Deprecated(since = "3.3.0", forRemoval = true) - boolean dispatchTargeted(IClassTargetingEvent event); - - /** - * @param event the {@linkplain IClassTargetingEvent} to dispatch - * @param type the type of listener to invoke (can be {@code null}) - * @return {@code true} if the given event was {@linkplain IStatusEvent suppressed or terminated} by any listener, - * {@code false} otherwise - * @see EventBus#dispatchTargeted(IClassTargetingEvent, Class) - * @deprecated This method's functionality is now built into {@link #dispatch(Object)} - */ - @Deprecated(since = "3.3.0", forRemoval = true) - boolean dispatchTargeted(IClassTargetingEvent event, Class type); -} \ No newline at end of file diff --git a/src/main/test/me/tori/wraith/targetedevent/TargetedEventTest.java b/src/main/test/me/tori/wraith/targetedevent/TargetedEventTest.java index b0186d8..e716b2d 100644 --- a/src/main/test/me/tori/wraith/targetedevent/TargetedEventTest.java +++ b/src/main/test/me/tori/wraith/targetedevent/TargetedEventTest.java @@ -42,36 +42,51 @@ public void testTargetedEvent() { bus.subscribe(new Subscriber() {{ registerListeners( - new MyListener(), - new OtherListener() + new MyListener(0), + new OtherListener(1) ); }}); TestEvent event = new TestEvent(MyListener.class); - assertFalse(bus.dispatchTargeted(event)); + assertFalse(bus.dispatch(event)); + } + + @Test + public void testTargetedEvent2() { + final EventBus bus = new EventBus(); + + bus.subscribe(new Subscriber() {{ + registerListeners( + new MyListener(1), + new OtherListener(0) + ); + }}); + + TestEvent event = new TestEvent(MyListener.class); + assertFalse(bus.dispatch(event)); } static class MyListener extends EventListener { - public MyListener() { - super(TestEvent.class); + public MyListener(int priority) { + super(TestEvent.class, priority); } @Override public void invoke(TestEvent event) { - + event.setSuppressed(false); } } static class OtherListener extends EventListener { - public OtherListener() { - super(TestEvent.class); + public OtherListener(int priority) { + super(TestEvent.class, priority); } @Override public void invoke(TestEvent event) { - event.terminate(); + event.suppress(); } } From cef7b656cc3d978ac423d3ffde1a4770d0f34f30 Mon Sep 17 00:00:00 2001 From: 7orivorian <7orivorian+github@gmail.com> Date: Wed, 3 Jul 2024 22:58:44 -0400 Subject: [PATCH 03/30] Add IndexedHashSet Signed-off-by: 7orivorian <7orivorian+github@gmail.com> --- .../me/tori/wraith/util/IndexedHashSet.java | 119 ++++++++++++++++++ .../tori/wraith/util/IndexedHashSetTest.java | 90 +++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 src/main/java/me/tori/wraith/util/IndexedHashSet.java create mode 100644 src/main/test/me/tori/wraith/util/IndexedHashSetTest.java diff --git a/src/main/java/me/tori/wraith/util/IndexedHashSet.java b/src/main/java/me/tori/wraith/util/IndexedHashSet.java new file mode 100644 index 0000000..9d8206a --- /dev/null +++ b/src/main/java/me/tori/wraith/util/IndexedHashSet.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2024 7orivorian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package me.tori.wraith.util; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.ListIterator; +import java.util.function.Predicate; + +/** + * @author 7orivorian + * @since 4.0.0 + */ +public class IndexedHashSet { + + private final ArrayList list; + private final HashSet set; + + public IndexedHashSet() { + this.list = new ArrayList<>(); + this.set = new HashSet<>(); + } + + public boolean add(E element) { + if (set.add(element)) { + list.add(element); + return true; + } + return false; + } + + public boolean add(int index, E element) { + if (set.add(element)) { + list.add(index, element); + return true; + } + return false; + } + + public E get(int index) { + return list.get(index); + } + + public E remove(int index) { + E element = list.remove(index); + set.remove(element); + return element; + } + + @SuppressWarnings("SuspiciousMethodCalls") + public boolean remove(Object element) { + if (set.remove(element)) { + list.remove(element); + return true; + } + return false; + } + + public boolean removeIf(Predicate filter) { + boolean removed = false; + Iterator it = list.iterator(); + while (it.hasNext()) { + E element = it.next(); + if (filter.test(element)) { + it.remove(); + set.remove(element); + removed = true; + } + } + return removed; + } + + public int size() { + return list.size(); + } + + @SuppressWarnings("SuspiciousMethodCalls") + public boolean contains(Object element) { + return set.contains(element); + } + + public boolean isEmpty() { + return list.isEmpty(); + } + + public ListIterator listIterator(int index) { + return list.listIterator(index); + } + + public void clear() { + list.clear(); + set.clear(); + } + + @Override + public String toString() { + return list.toString(); + } +} \ No newline at end of file diff --git a/src/main/test/me/tori/wraith/util/IndexedHashSetTest.java b/src/main/test/me/tori/wraith/util/IndexedHashSetTest.java new file mode 100644 index 0000000..b33e6ae --- /dev/null +++ b/src/main/test/me/tori/wraith/util/IndexedHashSetTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 7orivorian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package me.tori.wraith.util; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.Objects; + +/** + * @author 7orivorian + * @since 4.0.0 + */ +public class IndexedHashSetTest { + + @Test + public void testNoDuplicatesAllowed() { + IndexedHashSet set = new IndexedHashSet<>(); + set.add("A"); + set.add("A"); + set.add("B"); + + Assertions.assertEquals(2, set.size()); + } + + @Test + public void testInsert() { + IndexedHashSet set = new IndexedHashSet<>() {{ + add("A"); + add("B"); + add("C"); + }}; + set.add(0, "Z"); + + Assertions.assertEquals("Z", set.get(0)); + Assertions.assertEquals("A", set.get(1)); + Assertions.assertEquals("B", set.get(2)); + Assertions.assertEquals("C", set.get(3)); + Assertions.assertThrows(IndexOutOfBoundsException.class, () -> set.get(4)); + } + + @Test + public void testIndexBounds() { + IndexedHashSet set = new IndexedHashSet<>() {{ + add("A"); + add("B"); + add("C"); + }}; + + Assertions.assertThrows(IndexOutOfBoundsException.class, () -> set.get(-1)); + Assertions.assertThrows(IndexOutOfBoundsException.class, () -> set.get(3)); + } + + @Test + public void testRemoveIf() { + IndexedHashSet set = new IndexedHashSet<>() {{ + add("A"); + add("B"); + add("C"); + add("a"); + add("b"); + add("c"); + }}; + set.removeIf(s -> Objects.equals(s, s.toUpperCase())); + + Assertions.assertEquals(3, set.size()); + Assertions.assertEquals("a", set.get(0)); + Assertions.assertEquals("b", set.get(1)); + Assertions.assertEquals("c", set.get(2)); + } +} \ No newline at end of file From 7260ec1ed8305400f7eb8654151b8aff9672563c Mon Sep 17 00:00:00 2001 From: 7orivorian <7orivorian+github@gmail.com> Date: Wed, 3 Jul 2024 23:00:42 -0400 Subject: [PATCH 04/30] Refactor benchmarks Signed-off-by: 7orivorian <7orivorian+github@gmail.com> --- .../wraith/benchmarking/BenchmarkMain.java | 37 +++++++++++++++++++ .../tori/wraith/benchmarking/MyBenchmark.java | 6 --- 2 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 src/main/test/me/tori/wraith/benchmarking/BenchmarkMain.java diff --git a/src/main/test/me/tori/wraith/benchmarking/BenchmarkMain.java b/src/main/test/me/tori/wraith/benchmarking/BenchmarkMain.java new file mode 100644 index 0000000..9738e62 --- /dev/null +++ b/src/main/test/me/tori/wraith/benchmarking/BenchmarkMain.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024 7orivorian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package me.tori.wraith.benchmarking; + +import org.openjdk.jmh.Main; + +import java.io.IOException; + +/** + * @author 7orivorian + * @since 4.0.0 + */ +public class BenchmarkMain { + + public static void main(String[] args) throws IOException { + Main.main(args); + } +} \ No newline at end of file diff --git a/src/main/test/me/tori/wraith/benchmarking/MyBenchmark.java b/src/main/test/me/tori/wraith/benchmarking/MyBenchmark.java index b7d3660..ce6c364 100644 --- a/src/main/test/me/tori/wraith/benchmarking/MyBenchmark.java +++ b/src/main/test/me/tori/wraith/benchmarking/MyBenchmark.java @@ -24,10 +24,8 @@ import me.tori.wraith.bus.EventBus; import me.tori.wraith.listener.EventListener; import me.tori.wraith.subscriber.Subscriber; -import org.openjdk.jmh.Main; import org.openjdk.jmh.annotations.*; -import java.io.IOException; import java.util.concurrent.TimeUnit; /** @@ -36,10 +34,6 @@ */ public class MyBenchmark { - public static void main(String[] args) throws IOException { - Main.main(args); - } - @State(Scope.Thread) public static class BenchmarkState { MyListener myListener; From debe40d9cb05c7a93c1aa2fbb7728901aadea3f1 Mon Sep 17 00:00:00 2001 From: 7orivorian <7orivorian+github@gmail.com> Date: Wed, 3 Jul 2024 23:01:34 -0400 Subject: [PATCH 05/30] Fix broken PersistencyTest Signed-off-by: 7orivorian <7orivorian+github@gmail.com> --- src/main/test/me/tori/wraith/persistency/PersistencyTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/test/me/tori/wraith/persistency/PersistencyTest.java b/src/main/test/me/tori/wraith/persistency/PersistencyTest.java index 56bec70..41519bb 100644 --- a/src/main/test/me/tori/wraith/persistency/PersistencyTest.java +++ b/src/main/test/me/tori/wraith/persistency/PersistencyTest.java @@ -70,7 +70,7 @@ public MyListener(int persists) { @Override public void invoke(MyEvent event) { - event.terminate(); + event.suppress(); } } From c2f5df054c5d737f6e6bf582147639739afb143f Mon Sep 17 00:00:00 2001 From: 7orivorian <7orivorian+github@gmail.com> Date: Wed, 3 Jul 2024 23:01:51 -0400 Subject: [PATCH 06/30] Reduce the amount of iterations in PersistencyTest Signed-off-by: 7orivorian <7orivorian+github@gmail.com> --- src/main/test/me/tori/wraith/persistency/PersistencyTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/test/me/tori/wraith/persistency/PersistencyTest.java b/src/main/test/me/tori/wraith/persistency/PersistencyTest.java index 41519bb..06c2fb7 100644 --- a/src/main/test/me/tori/wraith/persistency/PersistencyTest.java +++ b/src/main/test/me/tori/wraith/persistency/PersistencyTest.java @@ -57,7 +57,7 @@ public void testIndefiniteEvent() { registerListener(new MyListener(0)); // <= 0 means persist indefinitely }}); - for (int i = 0; i < 1_000_000; i++) { + for (int i = 0; i < 1_000; i++) { Assertions.assertTrue(bus.dispatch(new MyEvent())); } } From ec1f30ffdd483d8060ddcc957410a84b6df71c01 Mon Sep 17 00:00:00 2001 From: 7orivorian <7orivorian+github@gmail.com> Date: Wed, 3 Jul 2024 23:02:50 -0400 Subject: [PATCH 07/30] Update IEventBus documentation Signed-off-by: 7orivorian <7orivorian+github@gmail.com> --- src/main/java/me/tori/wraith/bus/IEventBus.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/me/tori/wraith/bus/IEventBus.java b/src/main/java/me/tori/wraith/bus/IEventBus.java index a2167af..041422d 100644 --- a/src/main/java/me/tori/wraith/bus/IEventBus.java +++ b/src/main/java/me/tori/wraith/bus/IEventBus.java @@ -27,13 +27,15 @@ import me.tori.wraith.subscriber.ISubscriber; /** + * An event bus that allows for the subscription, registration, and dispatching of events to listeners. + * * @author 7orivorian * @since 1.0.0 */ public interface IEventBus { /** - * Default priority that used when no other priority is specified + * Default priority used when no other priority is specified. * * @see EventListener#EventListener(Class) * @see EventListener#EventListener(Class, Class) From d0c921cf0d09594cfae9042e7085266fbab31725 Mon Sep 17 00:00:00 2001 From: 7orivorian <7orivorian+github@gmail.com> Date: Wed, 3 Jul 2024 23:04:26 -0400 Subject: [PATCH 08/30] Rearrange EventListener & LambdaEventListener constructor parameters Signed-off-by: 7orivorian <7orivorian+github@gmail.com> --- .../java/me/tori/wraith/listener/EventListener.java | 12 ++++++------ .../me/tori/wraith/listener/LambdaEventListener.java | 4 ++-- src/main/java/me/tori/wraith/listener/Listener.java | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/main/java/me/tori/wraith/listener/EventListener.java b/src/main/java/me/tori/wraith/listener/EventListener.java index 3b428a4..70992c5 100644 --- a/src/main/java/me/tori/wraith/listener/EventListener.java +++ b/src/main/java/me/tori/wraith/listener/EventListener.java @@ -52,7 +52,7 @@ public abstract class EventListener implements Listener { * @throws NullPointerException if {@code target} is {@code null}. */ public EventListener(@NotNull Class target) { - this(target, IEventBus.DEFAULT_PRIORITY, null); + this(target, null, IEventBus.DEFAULT_PRIORITY, DEFAULT_PERSISTENCE); } /** @@ -63,7 +63,7 @@ public EventListener(@NotNull Class target) { * @throws NullPointerException if {@code target} is {@code null}. */ public EventListener(@NotNull Class target, int priority) { - this(target, priority, null); + this(target, null, priority, DEFAULT_PERSISTENCE); } /** @@ -74,7 +74,7 @@ public EventListener(@NotNull Class target, int priority) { * @throws NullPointerException if {@code target} is {@code null}. */ public EventListener(@NotNull Class target, @Nullable Class type) { - this(target, IEventBus.DEFAULT_PRIORITY, type); + this(target, type, IEventBus.DEFAULT_PRIORITY, DEFAULT_PERSISTENCE); } /** @@ -85,8 +85,8 @@ public EventListener(@NotNull Class target, @Nullable Class type) * @param type The type of events that this listener can handle. Can be {@code null}. * @throws NullPointerException if {@code target} is {@code null}. */ - public EventListener(@NotNull Class target, int priority, @Nullable Class type) { - this(target, type, priority, 0); + public EventListener(@NotNull Class target, @Nullable Class type, int priority) { + this(target, type, priority, DEFAULT_PERSISTENCE); } /** @@ -102,9 +102,9 @@ public EventListener(@NotNull Class target, int priority, @Nullable C */ public EventListener(@NotNull Class target, @Nullable Class type, int priority, int persists) { Objects.requireNonNull(target); - this.priority = priority; this.target = target; this.type = type; + this.priority = priority; this.persists = persists; this.indefinitePersistence = persists <= 0; } diff --git a/src/main/java/me/tori/wraith/listener/LambdaEventListener.java b/src/main/java/me/tori/wraith/listener/LambdaEventListener.java index a6b89ee..e344122 100644 --- a/src/main/java/me/tori/wraith/listener/LambdaEventListener.java +++ b/src/main/java/me/tori/wraith/listener/LambdaEventListener.java @@ -88,8 +88,8 @@ public LambdaEventListener(@NotNull Class target, @Nullable Class * @param invokable The invokable action to be executed when the event is dispatched. * @throws NullPointerException if {@code target} is {@code null}. */ - public LambdaEventListener(@NotNull Class target, int priority, @Nullable Class type, @NotNull Invokable invokable) { - super(target, priority, type); + public LambdaEventListener(@NotNull Class target, @Nullable Class type, int priority, @NotNull Invokable invokable) { + super(target, type, priority); Objects.requireNonNull(invokable); this.invokable = invokable; } diff --git a/src/main/java/me/tori/wraith/listener/Listener.java b/src/main/java/me/tori/wraith/listener/Listener.java index 5cf68d1..c1d5259 100644 --- a/src/main/java/me/tori/wraith/listener/Listener.java +++ b/src/main/java/me/tori/wraith/listener/Listener.java @@ -38,6 +38,8 @@ */ public interface Listener extends Invokable { + int DEFAULT_PERSISTENCE = 0; + /** * Gets the priority level of this listener for event handling. * From af935878049753355cd5f2aa295572623bbdfdb4 Mon Sep 17 00:00:00 2001 From: 7orivorian <7orivorian+github@gmail.com> Date: Thu, 4 Jul 2024 01:17:25 -0400 Subject: [PATCH 09/30] Rewrote IndexedHashSet Signed-off-by: 7orivorian <7orivorian+github@gmail.com> --- .../me/tori/wraith/util/IndexedHashSet.java | 79 +++++++++---------- 1 file changed, 39 insertions(+), 40 deletions(-) diff --git a/src/main/java/me/tori/wraith/util/IndexedHashSet.java b/src/main/java/me/tori/wraith/util/IndexedHashSet.java index 9d8206a..02b1469 100644 --- a/src/main/java/me/tori/wraith/util/IndexedHashSet.java +++ b/src/main/java/me/tori/wraith/util/IndexedHashSet.java @@ -22,98 +22,97 @@ package me.tori.wraith.util; import java.util.ArrayList; -import java.util.HashSet; +import java.util.HashMap; import java.util.Iterator; -import java.util.ListIterator; +import java.util.Objects; import java.util.function.Predicate; /** * @author 7orivorian * @since 4.0.0 */ -public class IndexedHashSet { +public class IndexedHashSet extends ArrayList { - private final ArrayList list; - private final HashSet set; + private final HashMap map; public IndexedHashSet() { - this.list = new ArrayList<>(); - this.set = new HashSet<>(); + this.map = new HashMap<>(); } + @Override public boolean add(E element) { - if (set.add(element)) { - list.add(element); + Objects.requireNonNull(element); + if (map.put(element, true) == null) { + super.add(element); return true; } return false; } - public boolean add(int index, E element) { - if (set.add(element)) { - list.add(index, element); - return true; + @Override + public void add(int index, E element) { + Objects.requireNonNull(element); + rangeCheckForAdd(index); + if (map.put(element, true) == null) { + super.add(index, element); } - return false; - } - - public E get(int index) { - return list.get(index); } + @Override public E remove(int index) { - E element = list.remove(index); - set.remove(element); + E element = super.remove(index); + map.remove(element); return element; } - @SuppressWarnings("SuspiciousMethodCalls") + @Override public boolean remove(Object element) { - if (set.remove(element)) { - list.remove(element); + if (map.remove(element) != null) { + super.remove(element); return true; } return false; } + @Override public boolean removeIf(Predicate filter) { + Objects.requireNonNull(filter); boolean removed = false; - Iterator it = list.iterator(); + Iterator it = iterator(); while (it.hasNext()) { E element = it.next(); if (filter.test(element)) { it.remove(); - set.remove(element); + map.remove(element); removed = true; } } return removed; } - public int size() { - return list.size(); - } - + @Override @SuppressWarnings("SuspiciousMethodCalls") public boolean contains(Object element) { - return set.contains(element); + return map.containsKey(element); } - public boolean isEmpty() { - return list.isEmpty(); + @Override + public void clear() { + super.clear(); + map.clear(); } - public ListIterator listIterator(int index) { - return list.listIterator(index); + public ArrayList asList() { + return new ArrayList<>(this); } - public void clear() { - list.clear(); - set.clear(); + private void rangeCheckForAdd(int index) { + if ((index > size()) || (index < 0)) { + throw new IndexOutOfBoundsException(outOfBoundsMsg(index)); + } } - @Override - public String toString() { - return list.toString(); + private String outOfBoundsMsg(int index) { + return "Index: " + index + ", Size: " + size(); } } \ No newline at end of file From 8cde0b022749e9b12c5707226433dbd1c5dd4bd7 Mon Sep 17 00:00:00 2001 From: 7orivorian <7orivorian+github@gmail.com> Date: Thu, 4 Jul 2024 01:20:29 -0400 Subject: [PATCH 10/30] Minor documentation refactors Signed-off-by: 7orivorian <7orivorian+github@gmail.com> --- src/main/java/me/tori/wraith/bus/EventBus.java | 8 ++++---- src/main/java/me/tori/wraith/listener/EventListener.java | 4 ++-- src/main/java/me/tori/wraith/subscriber/ISubscriber.java | 7 ++++--- src/main/java/me/tori/wraith/subscriber/Subscriber.java | 7 ++++--- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/main/java/me/tori/wraith/bus/EventBus.java b/src/main/java/me/tori/wraith/bus/EventBus.java index e22d11d..1b6c107 100644 --- a/src/main/java/me/tori/wraith/bus/EventBus.java +++ b/src/main/java/me/tori/wraith/bus/EventBus.java @@ -36,11 +36,11 @@ /** * Default implementation of {@link IEventBus}. + *

+ * Manages subscription, listener registration, and event dispatching. * - *

Manages event subscription, dispatching, and listener registration. - * - * @author 7orivorian - * @since 1.0.0 + * @author 7orivorian + * @since 1.0.0 */ @SuppressWarnings({"rawtypes", "unchecked"}) public class EventBus implements IEventBus { diff --git a/src/main/java/me/tori/wraith/listener/EventListener.java b/src/main/java/me/tori/wraith/listener/EventListener.java index 70992c5..f97555c 100644 --- a/src/main/java/me/tori/wraith/listener/EventListener.java +++ b/src/main/java/me/tori/wraith/listener/EventListener.java @@ -32,10 +32,10 @@ * Event listeners provide event handling logic with specified priorities, target classes, and types. * * @param The type of event this listener is designed to handle. - * @author 7orivorian + * @author 7orivorian * @see Listener * @see Invokable - * @since 1.0.0 + * @since 1.0.0 */ public abstract class EventListener implements Listener { diff --git a/src/main/java/me/tori/wraith/subscriber/ISubscriber.java b/src/main/java/me/tori/wraith/subscriber/ISubscriber.java index 1936bd6..fcaf39b 100644 --- a/src/main/java/me/tori/wraith/subscriber/ISubscriber.java +++ b/src/main/java/me/tori/wraith/subscriber/ISubscriber.java @@ -27,11 +27,12 @@ /** * Represents a subscriber that can register and manage event listeners. - *

An instance of a class implementing this interface can subscribe to an event bus by registering listeners. + *

+ * An instance of a class implementing this interface can subscribe to an event bus by registering listeners. * - * @author 7orivorian + * @author 7orivorian * @see Subscriber - * @since 1.0.0 + * @since 1.0.0 */ public interface ISubscriber { diff --git a/src/main/java/me/tori/wraith/subscriber/Subscriber.java b/src/main/java/me/tori/wraith/subscriber/Subscriber.java index a0faa12..b160461 100644 --- a/src/main/java/me/tori/wraith/subscriber/Subscriber.java +++ b/src/main/java/me/tori/wraith/subscriber/Subscriber.java @@ -30,12 +30,13 @@ import java.util.List; /** - * A concrete implementation of {@link ISubscriber} that manages event listeners and their registration. + * The default implementation of {@link ISubscriber} that manages event listeners and their registration. + *

* This class provides methods to register single or multiple event listeners and retrieve registered listeners. * - * @author 7orivorian + * @author 7orivorian * @see ISubscriber - * @since 1.0.0 + * @since 1.0.0 */ public class Subscriber implements ISubscriber { From 62bc8a6894a4864f25d0448a9df88c7db0e669eb Mon Sep 17 00:00:00 2001 From: 7orivorian <7orivorian+github@gmail.com> Date: Thu, 4 Jul 2024 01:20:49 -0400 Subject: [PATCH 11/30] Add PriorityTest Signed-off-by: 7orivorian <7orivorian+github@gmail.com> --- .../me/tori/wraith/priority/PriorityTest.java | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/main/test/me/tori/wraith/priority/PriorityTest.java diff --git a/src/main/test/me/tori/wraith/priority/PriorityTest.java b/src/main/test/me/tori/wraith/priority/PriorityTest.java new file mode 100644 index 0000000..6a0b90a --- /dev/null +++ b/src/main/test/me/tori/wraith/priority/PriorityTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 7orivorian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package me.tori.wraith.priority; + +import me.tori.wraith.bus.EventBus; +import me.tori.wraith.event.status.StatusEvent; +import me.tori.wraith.listener.LambdaEventListener; +import me.tori.wraith.subscriber.Subscriber; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author 7orivorian + * @since 4.0.0 + */ +public class PriorityTest { + + @Test + public void testPriority() { + final EventBus bus = new EventBus(); + bus.subscribe(new Subscriber() {{ + registerListener(new LambdaEventListener<>(MyEvent.class, 5, event -> event.setFlag(true))); + registerListener(new LambdaEventListener<>(MyEvent.class, 4, event -> { + event.setFlag(false); + event.terminate(); + })); + registerListener(new LambdaEventListener<>(MyEvent.class, 3, event -> event.setFlag(true))); + registerListener(new LambdaEventListener<>(MyEvent.class, 2, event -> event.setFlag(true))); + registerListener(new LambdaEventListener<>(MyEvent.class, 1, event -> event.setFlag(true))); + registerListener(new LambdaEventListener<>(MyEvent.class, 0, event -> event.setFlag(true))); + }}); + + MyEvent event = new MyEvent(); + Assertions.assertTrue(bus.dispatch(event)); + Assertions.assertFalse(event.flag()); + } + + static class MyEvent extends StatusEvent { + + private boolean flag; + + MyEvent() { + this.flag = true; + } + + public boolean flag() { + return flag; + } + + public void setFlag(boolean flag) { + this.flag = flag; + } + } +} \ No newline at end of file From 4e21120c9c7684280a138098904e00d1d5833324 Mon Sep 17 00:00:00 2001 From: 7orivorian <7orivorian+github@gmail.com> Date: Thu, 4 Jul 2024 01:21:50 -0400 Subject: [PATCH 12/30] Fix incorrect equals & hashCode methods in EventListener Signed-off-by: 7orivorian <7orivorian+github@gmail.com> --- .../tori/wraith/listener/EventListener.java | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/src/main/java/me/tori/wraith/listener/EventListener.java b/src/main/java/me/tori/wraith/listener/EventListener.java index f97555c..9a62c20 100644 --- a/src/main/java/me/tori/wraith/listener/EventListener.java +++ b/src/main/java/me/tori/wraith/listener/EventListener.java @@ -177,25 +177,18 @@ public boolean equals(Object o) { } EventListener that = (EventListener) o; - if (priority != that.priority) { - return false; - } - if (indefinitePersistence != that.indefinitePersistence) { - return false; - } - if (!Objects.equals(type, that.type)) { - return false; - } - return target.equals(that.target); + return (priority == that.priority) + && (indefinitePersistence == that.indefinitePersistence) + && target.equals(that.target) + && Objects.equals(type, that.type); } @Override public int hashCode() { int result = target.hashCode(); - result = 31 * result + Objects.hashCode(type); - result = 31 * result + priority; - result = 31 * result + Boolean.hashCode(indefinitePersistence); - result = 31 * result + persists; + result = (31 * result) + Objects.hashCode(type); + result = (31 * result) + priority; + result = (31 * result) + Boolean.hashCode(indefinitePersistence); return result; } From 5b6370f4dbd9108a7646a91142ed3e1786ca8f21 Mon Sep 17 00:00:00 2001 From: 7orivorian <7orivorian+github@gmail.com> Date: Thu, 4 Jul 2024 01:23:48 -0400 Subject: [PATCH 13/30] Subscribers now link to event buses in order to propagate listener registration Signed-off-by: 7orivorian <7orivorian+github@gmail.com> --- .../java/me/tori/wraith/bus/EventBus.java | 89 ++++++++++------- .../tori/wraith/subscriber/ISubscriber.java | 36 +++++++ .../me/tori/wraith/subscriber/Subscriber.java | 75 ++++++++++++-- .../wraith/registration/RegistrationTest.java | 99 +++++++++++++++++++ 4 files changed, 257 insertions(+), 42 deletions(-) create mode 100644 src/main/test/me/tori/wraith/registration/RegistrationTest.java diff --git a/src/main/java/me/tori/wraith/bus/EventBus.java b/src/main/java/me/tori/wraith/bus/EventBus.java index 1b6c107..a54e436 100644 --- a/src/main/java/me/tori/wraith/bus/EventBus.java +++ b/src/main/java/me/tori/wraith/bus/EventBus.java @@ -27,12 +27,11 @@ import me.tori.wraith.subscriber.ISubscriber; import me.tori.wraith.task.ScheduledTask; import me.tori.wraith.task.TaskExecutor; +import me.tori.wraith.util.IndexedHashSet; import java.util.*; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.function.Predicate; -import java.util.function.Supplier; /** * Default implementation of {@link IEventBus}. @@ -67,7 +66,7 @@ public class EventBus implements IEventBus { /** * A {@link ConcurrentHashMap} of this event bus' {@link Listener listeners} */ - private final ConcurrentHashMap, List> listeners; + private final ConcurrentHashMap, IndexedHashSet> listeners; /** * A {@link TaskExecutor} that manages the scheduling and execution of tasks associated with events. It provides * a mechanism to associate event classes with queues of tasks and ensures their orderly execution when the @@ -106,15 +105,20 @@ public static int getInstanceCount() { @Override public void subscribe(ISubscriber subscriber) { Objects.requireNonNull(subscriber, "Cannot subscribe null to event bus " + id + "!"); + + subscribers.add(subscriber); + subscriber.linkToBus(this); + Collection> listeners = subscriber.getListeners(); - if (listeners.size() == 1) { - register(listeners.iterator().next()); - } else { - for (Listener listener : listeners) { - register(listener); + if (!listeners.isEmpty()) { + if (listeners.size() == 1) { + register(listeners.iterator().next()); + } else { + for (Listener listener : listeners) { + register(listener); + } } } - subscribers.add(subscriber); } /** @@ -128,15 +132,20 @@ public void subscribe(ISubscriber subscriber) { @Override public void unsubscribe(ISubscriber subscriber) { Objects.requireNonNull(subscriber, "Cannot unsubscribe null from event bus " + id + "!"); + + subscribers.remove(subscriber); + subscriber.unlinkFromBus(this); + Collection> listeners = subscriber.getListeners(); - if (listeners.size() == 1) { - unregister(listeners.iterator().next()); - } else { - for (Listener listener : listeners) { - unregister(listener); + if (!listeners.isEmpty()) { + if (listeners.size() == 1) { + unregister(listeners.iterator().next()); + } else { + for (Listener listener : listeners) { + unregister(listener); + } } } - subscribers.remove(subscriber); } /** @@ -149,7 +158,7 @@ public void unsubscribe(ISubscriber subscriber) { public void register(Listener listener) { Objects.requireNonNull(listener, "Cannot register null listener to event bus " + id + "!"); - List listeners = this.listeners.computeIfAbsent(listener.getTarget(), target -> new CopyOnWriteArrayList<>()); + IndexedHashSet listeners = this.listeners.computeIfAbsent(listener.getTarget(), target -> new IndexedHashSet<>()); final int size = listeners.size(); int index = 0; for (; index < size; index++) { @@ -307,28 +316,36 @@ public int getId() { * they are processed in normal order * @since 3.2.0 */ - private void dispatchToEachListener(Object event, List listeners, Predicate predicate, boolean invertPriority) { - if (listeners != null && !listeners.isEmpty()) { - ListIterator iterator; - Supplier supplier; + @SuppressWarnings("DuplicatedCode") + private void dispatchToEachListener(Object event, IndexedHashSet listeners, Predicate predicate, boolean invertPriority) { + if ((listeners != null) && !listeners.isEmpty()) { + final ArrayList li = listeners.asList(); if (invertPriority) { - iterator = listeners.listIterator(listeners.size()); - supplier = () -> (iterator.hasPrevious() ? iterator.previous() : null); - } else { - iterator = listeners.listIterator(0); - supplier = () -> (iterator.hasNext() ? iterator.next() : null); - } - Listener listener; - while ((listener = supplier.get()) != null) { - if (!predicate.test(listener)) { - continue; + for (int i = li.size() - 1; i >= 0; i--) { + Listener listener = li.get(i); + if (!predicate.test(listener)) { + continue; + } + listener.invoke(event); + if ((event instanceof IStatusEvent e) && e.isTerminated()) { + break; + } + if (!listener.shouldPersist()) { + listeners.remove(listener); + } } - listener.invoke(event); - if ((event instanceof IStatusEvent e) && e.isTerminated()) { - break; - } - if (!listener.shouldPersist()) { - listeners.remove(listener); + } else { + for (Listener listener : li) { + if (!predicate.test(listener)) { + continue; + } + listener.invoke(event); + if ((event instanceof IStatusEvent e) && e.isTerminated()) { + break; + } + if (!listener.shouldPersist()) { + listeners.remove(listener); + } } } } diff --git a/src/main/java/me/tori/wraith/subscriber/ISubscriber.java b/src/main/java/me/tori/wraith/subscriber/ISubscriber.java index fcaf39b..29638be 100644 --- a/src/main/java/me/tori/wraith/subscriber/ISubscriber.java +++ b/src/main/java/me/tori/wraith/subscriber/ISubscriber.java @@ -21,6 +21,7 @@ package me.tori.wraith.subscriber; +import me.tori.wraith.bus.IEventBus; import me.tori.wraith.listener.Listener; import java.util.Collection; @@ -55,10 +56,45 @@ public interface ISubscriber { @SuppressWarnings("unchecked") > T[] registerListeners(T... listeners); + /** + * Unregisters a single event listener from this subscriber. + * + * @param listener The event listener to unregister. + * @param The type of the listener. + * @return {@code true} if this subscriber contained the specified listener, {@code false} otherwise. + */ + > boolean unregisterListener(T listener); + + /** + * Unregisters multiple event listeners from this subscriber. + * + * @param listeners The event listeners to unregister. + * @param The type of the listeners. + * @return {@code true} if this subscriber was changed as a result of the call, {@code false} otherwise. + */ + @SuppressWarnings("unchecked") + > boolean unregisterListeners(T... listeners); + /** * Retrieves a collection of event listeners registered with this subscriber. * * @return A collection of registered event listeners. */ Collection> getListeners(); + + /** + * Links this subscriber to the specified event bus. + * + * @param eventBus The event bus to link to this subscriber. Must not be {@code null}. + * @throws NullPointerException If the {@code eventBus} is {@code null}. + */ + void linkToBus(IEventBus eventBus); + + /** + * Unlinks this subscriber from the specified event bus. + * + * @param eventBus The event bus to unlink from this subscriber. Must not be {@code null}. + * @throws NullPointerException If the {@code eventBus} is {@code null}. + */ + void unlinkFromBus(IEventBus eventBus); } \ No newline at end of file diff --git a/src/main/java/me/tori/wraith/subscriber/Subscriber.java b/src/main/java/me/tori/wraith/subscriber/Subscriber.java index b160461..ce9f0c8 100644 --- a/src/main/java/me/tori/wraith/subscriber/Subscriber.java +++ b/src/main/java/me/tori/wraith/subscriber/Subscriber.java @@ -21,13 +21,12 @@ package me.tori.wraith.subscriber; +import me.tori.wraith.bus.IEventBus; import me.tori.wraith.listener.Listener; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; /** * The default implementation of {@link ISubscriber} that manages event listeners and their registration. @@ -40,6 +39,7 @@ */ public class Subscriber implements ISubscriber { + private final Set<@NotNull IEventBus> linkedBuses = Collections.newSetFromMap(new ConcurrentHashMap<>()); private final List<@NotNull Listener> listeners = new ArrayList<>(); /** @@ -52,6 +52,9 @@ public class Subscriber implements ISubscriber { @Override public > T registerListener(@NotNull T listener) { listeners.add(listener); + if (!linkedBuses.isEmpty()) { + linkedBuses.forEach(bus -> bus.register(listener)); + } return listener; } @@ -65,10 +68,39 @@ public > T registerListener(@NotNull T listener) { @SafeVarargs @Override public final > T[] registerListeners(@NotNull T... listeners) { - this.listeners.addAll(Arrays.asList(listeners)); + final List<@NotNull T> list = Arrays.asList(listeners); + this.listeners.addAll(list); + if (!linkedBuses.isEmpty()) { + linkedBuses.forEach(bus -> list.forEach(bus::register)); + } return listeners; } + /** + * Unregisters a single event listener from this subscriber. + * + * @param listener The event listener to unregister. + * @param The type of the listener. + * @return {@code true} if this subscriber contained the specified listener, {@code false} otherwise. + */ + @Override + public > boolean unregisterListener(T listener) { + return listeners.remove(listener); + } + + /** + * Unregisters multiple event listeners from this subscriber. + * + * @param listeners The event listeners to unregister. + * @param The type of the listeners. + * @return {@code true} if this subscriber was changed as a result of the call, {@code false} otherwise. + */ + @SafeVarargs + @Override + public final > boolean unregisterListeners(T... listeners) { + return this.listeners.removeAll(Arrays.asList(listeners)); + } + /** * Retrieves a collection of event listeners registered with this subscriber. * @@ -79,10 +111,41 @@ public Collection> getListeners() { return listeners; } + /** + * Links this subscriber to the specified event bus. + *

+ * This method adds the given {@code eventBus} to the {@linkplain #linkedBuses set of event buses that this subscriber is linked to}. + * Once linked, the event bus can register the event listeners managed by this subscriber. + * + * @param eventBus The event bus to link to this subscriber. Must not be {@code null}. + * @throws NullPointerException If the {@code eventBus} is {@code null}. + */ + @Override + public void linkToBus(IEventBus eventBus) { + Objects.requireNonNull(eventBus, "Cannot subscribe to a null event bus"); + linkedBuses.add(eventBus); + } + + /** + * Unlinks this subscriber from the specified event bus. + *

+ * This method removes the given {@code eventBus} from the {@linkplain #linkedBuses set of event buses that this subscriber is linked to}. + * Once unlinked, the event bus will no longer register the event listeners managed by this subscriber. + * + * @param eventBus The event bus to unlink from this subscriber. Must not be {@code null}. + * @throws NullPointerException If the {@code eventBus} is {@code null}. + */ + @Override + public void unlinkFromBus(IEventBus eventBus) { + Objects.requireNonNull(eventBus, "Cannot unsubscribe from a null event bus"); + linkedBuses.remove(eventBus); + } + @Override public String toString() { return "Subscriber{" + - "listeners=" + listeners + + "busRefs=" + linkedBuses + + ", listeners=" + listeners + '}'; } } \ No newline at end of file diff --git a/src/main/test/me/tori/wraith/registration/RegistrationTest.java b/src/main/test/me/tori/wraith/registration/RegistrationTest.java new file mode 100644 index 0000000..7afa6bf --- /dev/null +++ b/src/main/test/me/tori/wraith/registration/RegistrationTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024 7orivorian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package me.tori.wraith.registration; + +import me.tori.wraith.bus.EventBus; +import me.tori.wraith.event.status.IStatusEvent; +import me.tori.wraith.event.status.StatusEvent; +import me.tori.wraith.listener.LambdaEventListener; +import me.tori.wraith.subscriber.Subscriber; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author 7orivorian + * @since 4.0.0 + */ +public class RegistrationTest { + + @Test + public void testResistration() { + final EventBus bus = new EventBus(); + final LambdaEventListener listener = new LambdaEventListener<>( + StatusEvent.class, + IStatusEvent::terminate + ); + + bus.register(listener); + Assertions.assertTrue(bus.dispatch(new StatusEvent())); + + bus.unregister(listener); + Assertions.assertFalse(bus.dispatch(new StatusEvent())); + } + + @Test + public void testSubscription() { + final EventBus bus = new EventBus(); + final Subscriber subscriber = new Subscriber() {{ + registerListener(new LambdaEventListener<>(StatusEvent.class, IStatusEvent::terminate)); + }}; + + bus.subscribe(subscriber); + Assertions.assertTrue(bus.dispatch(new StatusEvent())); + + bus.unsubscribe(subscriber); + Assertions.assertFalse(bus.dispatch(new StatusEvent())); + } + + @Test + public void testLateSubscription() { + final String expectedMessage = "Hello world!"; + + final EventBus bus = new EventBus(); + final Subscriber subscriber = new Subscriber(); + + bus.subscribe(subscriber); + + subscriber.registerListener(new LambdaEventListener<>(MyEvent.class, event -> event.setMessage(expectedMessage))); + + MyEvent event = new MyEvent(null); + bus.dispatch(event); + + Assertions.assertEquals(expectedMessage, event.message()); + } + + static final class MyEvent { + private String message; + + MyEvent(String message) { + this.message = message; + } + + public String message() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + } +} \ No newline at end of file From 00f6f8250045b8d256a397d05e65e048db37cccf Mon Sep 17 00:00:00 2001 From: Tori <7orivorian+github@gmail.com> Date: Mon, 29 Jul 2024 02:38:11 -0400 Subject: [PATCH 14/30] Refactor path Signed-off-by: Tori <7orivorian+github@gmail.com> --- README.md | 4 +- .../tori/example/expanded/ExampleEvent.java | 8 +- .../example/expanded/ExampleListener.java | 6 +- .../tori/example/expanded/ExampleMain.java | 8 +- .../example/expanded/ExampleSubscriber.java | 8 +- .../persistence/PersistenceExample.java | 10 +- .../tori/example/simple/SimpleExample.java | 10 +- .../statusevents/SupressionExample.java | 12 +- .../statusevents/TerminationExample.java | 12 +- .../taskexecutor/TaskExecutorExample.java | 8 +- pom.xml | 12 +- .../{me => dev}/tori/wraith/bus/EventBus.java | 21 ++-- .../tori/wraith/bus/IEventBus.java | 10 +- .../tori/wraith/event/staged/EventStage.java | 2 +- .../wraith/event/staged/IStagedEvent.java | 2 +- .../tori/wraith/event/staged/StagedEvent.java | 4 +- .../wraith/event/status/IStatusEvent.java | 7 +- .../tori/wraith/event/status/StatusEvent.java | 2 +- .../event/targeted/ClassTargetingEvent.java | 9 +- .../event/targeted/IClassTargetingEvent.java | 9 +- .../tori/wraith/listener/EventListener.java | 4 +- .../tori/wraith/listener/Invokable.java | 2 +- .../wraith/listener/LambdaEventListener.java | 2 +- .../tori/wraith/listener/Listener.java | 4 +- .../tori/wraith/listener/ListenerBuilder.java | 4 +- .../tori/wraith/subscriber/ISubscriber.java | 6 +- .../tori/wraith/subscriber/Subscriber.java | 6 +- .../tori/wraith/task/ScheduledTask.java | 2 +- .../tori/wraith/task/TaskExecutor.java | 2 +- .../tori/wraith/util/IndexedHashSet.java | 2 +- src/main/test/dev/tori/wraith/Main.java | 70 ++++++++++++ .../wraith/benchmarking/BenchmarkMain.java | 2 +- .../tori/wraith/benchmarking/MyBenchmark.java | 8 +- .../wraith/persistency/PersistencyTest.java | 10 +- .../tori/wraith/priority/PriorityTest.java | 10 +- .../wraith/registration/RegistrationTest.java | 12 +- .../wraith/statusevent/StatusEventTest.java | 10 +- .../targetedevent/TargetedEventTest.java | 107 ++++++++++++++++-- .../wraith/taskexecutor/TaskExecutorTest.java | 6 +- .../tori/wraith/util/IndexedHashSetTest.java | 3 +- 40 files changed, 304 insertions(+), 132 deletions(-) rename examples/java/{me => dev}/tori/example/expanded/ExampleEvent.java (90%) rename examples/java/{me => dev}/tori/example/expanded/ExampleListener.java (92%) rename examples/java/{me => dev}/tori/example/expanded/ExampleMain.java (92%) rename examples/java/{me => dev}/tori/example/expanded/ExampleSubscriber.java (90%) rename examples/java/{me => dev}/tori/example/persistence/PersistenceExample.java (91%) rename examples/java/{me => dev}/tori/example/simple/SimpleExample.java (91%) rename examples/java/{me => dev}/tori/example/statusevents/SupressionExample.java (90%) rename examples/java/{me => dev}/tori/example/statusevents/TerminationExample.java (89%) rename examples/java/{me => dev}/tori/example/taskexecutor/TaskExecutorExample.java (93%) rename src/main/java/{me => dev}/tori/wraith/bus/EventBus.java (95%) rename src/main/java/{me => dev}/tori/wraith/bus/IEventBus.java (95%) rename src/main/java/{me => dev}/tori/wraith/event/staged/EventStage.java (97%) rename src/main/java/{me => dev}/tori/wraith/event/staged/IStagedEvent.java (97%) rename src/main/java/{me => dev}/tori/wraith/event/staged/StagedEvent.java (97%) rename src/main/java/{me => dev}/tori/wraith/event/status/IStatusEvent.java (96%) rename src/main/java/{me => dev}/tori/wraith/event/status/StatusEvent.java (98%) rename src/main/java/{me => dev}/tori/wraith/event/targeted/ClassTargetingEvent.java (89%) rename src/main/java/{me => dev}/tori/wraith/event/targeted/IClassTargetingEvent.java (91%) rename src/main/java/{me => dev}/tori/wraith/listener/EventListener.java (99%) rename src/main/java/{me => dev}/tori/wraith/listener/Invokable.java (98%) rename src/main/java/{me => dev}/tori/wraith/listener/LambdaEventListener.java (99%) rename src/main/java/{me => dev}/tori/wraith/listener/Listener.java (98%) rename src/main/java/{me => dev}/tori/wraith/listener/ListenerBuilder.java (98%) rename src/main/java/{me => dev}/tori/wraith/subscriber/ISubscriber.java (96%) rename src/main/java/{me => dev}/tori/wraith/subscriber/Subscriber.java (98%) rename src/main/java/{me => dev}/tori/wraith/task/ScheduledTask.java (99%) rename src/main/java/{me => dev}/tori/wraith/task/TaskExecutor.java (99%) rename src/main/java/{me => dev}/tori/wraith/util/IndexedHashSet.java (99%) create mode 100644 src/main/test/dev/tori/wraith/Main.java rename src/main/test/{me => dev}/tori/wraith/benchmarking/BenchmarkMain.java (97%) rename src/main/test/{me => dev}/tori/wraith/benchmarking/MyBenchmark.java (94%) rename src/main/test/{me => dev}/tori/wraith/persistency/PersistencyTest.java (91%) rename src/main/test/{me => dev}/tori/wraith/priority/PriorityTest.java (92%) rename src/main/test/{me => dev}/tori/wraith/registration/RegistrationTest.java (91%) rename src/main/test/{me => dev}/tori/wraith/statusevent/StatusEventTest.java (92%) rename src/main/test/{me => dev}/tori/wraith/targetedevent/TargetedEventTest.java (51%) rename src/main/test/{me => dev}/tori/wraith/taskexecutor/TaskExecutorTest.java (96%) rename src/main/test/{me => dev}/tori/wraith/util/IndexedHashSetTest.java (97%) diff --git a/README.md b/README.md index a7c8365..aa5030f 100644 --- a/README.md +++ b/README.md @@ -204,8 +204,6 @@ public class ExampleSubscriber extends Subscriber { To dispatch an event, call one of the `dispatch` methods defined in `EventBus`, passing your event as a parameter: ```java -import me.tori.wraith.event.staged.EventStage; - public class Example { private static final IEventBus EVENT_BUS = new EventBus(); @@ -223,7 +221,7 @@ public class Example { -Please explore the [example folder](./examples/java/me/tori/example) for _even more_ Wraith implementations! +Please explore the [example folder](./examples/java/dev/tori/example) for _even more_ Wraith implementations! # Contributing diff --git a/examples/java/me/tori/example/expanded/ExampleEvent.java b/examples/java/dev/tori/example/expanded/ExampleEvent.java similarity index 90% rename from examples/java/me/tori/example/expanded/ExampleEvent.java rename to examples/java/dev/tori/example/expanded/ExampleEvent.java index 3b1a423..720637c 100644 --- a/examples/java/me/tori/example/expanded/ExampleEvent.java +++ b/examples/java/dev/tori/example/expanded/ExampleEvent.java @@ -19,11 +19,11 @@ * THE SOFTWARE. */ -package me.tori.example.expanded; +package dev.tori.example.expanded; -import me.tori.wraith.event.staged.EventStage; -import me.tori.wraith.event.staged.IStagedEvent; -import me.tori.wraith.event.status.StatusEvent; +import dev.tori.wraith.event.staged.EventStage; +import dev.tori.wraith.event.staged.IStagedEvent; +import dev.tori.wraith.event.status.StatusEvent; /** * Example event. diff --git a/examples/java/me/tori/example/expanded/ExampleListener.java b/examples/java/dev/tori/example/expanded/ExampleListener.java similarity index 92% rename from examples/java/me/tori/example/expanded/ExampleListener.java rename to examples/java/dev/tori/example/expanded/ExampleListener.java index 7d0ebaf..327b2a1 100644 --- a/examples/java/me/tori/example/expanded/ExampleListener.java +++ b/examples/java/dev/tori/example/expanded/ExampleListener.java @@ -19,10 +19,10 @@ * THE SOFTWARE. */ -package me.tori.example.expanded; +package dev.tori.example.expanded; -import me.tori.wraith.event.staged.EventStage; -import me.tori.wraith.listener.EventListener; +import dev.tori.wraith.event.staged.EventStage; +import dev.tori.wraith.listener.EventListener; /** * Example listener. diff --git a/examples/java/me/tori/example/expanded/ExampleMain.java b/examples/java/dev/tori/example/expanded/ExampleMain.java similarity index 92% rename from examples/java/me/tori/example/expanded/ExampleMain.java rename to examples/java/dev/tori/example/expanded/ExampleMain.java index 25b663f..757d124 100644 --- a/examples/java/me/tori/example/expanded/ExampleMain.java +++ b/examples/java/dev/tori/example/expanded/ExampleMain.java @@ -19,11 +19,11 @@ * THE SOFTWARE. */ -package me.tori.example.expanded; +package dev.tori.example.expanded; -import me.tori.wraith.bus.EventBus; -import me.tori.wraith.bus.IEventBus; -import me.tori.wraith.event.staged.EventStage; +import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.bus.IEventBus; +import dev.tori.wraith.event.staged.EventStage; /** * Example program. diff --git a/examples/java/me/tori/example/expanded/ExampleSubscriber.java b/examples/java/dev/tori/example/expanded/ExampleSubscriber.java similarity index 90% rename from examples/java/me/tori/example/expanded/ExampleSubscriber.java rename to examples/java/dev/tori/example/expanded/ExampleSubscriber.java index f3cf156..4e3c8de 100644 --- a/examples/java/me/tori/example/expanded/ExampleSubscriber.java +++ b/examples/java/dev/tori/example/expanded/ExampleSubscriber.java @@ -19,11 +19,11 @@ * THE SOFTWARE. */ -package me.tori.example.expanded; +package dev.tori.example.expanded; -import me.tori.wraith.event.staged.EventStage; -import me.tori.wraith.listener.LambdaEventListener; -import me.tori.wraith.subscriber.Subscriber; +import dev.tori.wraith.event.staged.EventStage; +import dev.tori.wraith.listener.LambdaEventListener; +import dev.tori.wraith.subscriber.Subscriber; /** * Example subscriber. diff --git a/examples/java/me/tori/example/persistence/PersistenceExample.java b/examples/java/dev/tori/example/persistence/PersistenceExample.java similarity index 91% rename from examples/java/me/tori/example/persistence/PersistenceExample.java rename to examples/java/dev/tori/example/persistence/PersistenceExample.java index b6cbc6f..cb194c5 100644 --- a/examples/java/me/tori/example/persistence/PersistenceExample.java +++ b/examples/java/dev/tori/example/persistence/PersistenceExample.java @@ -19,12 +19,12 @@ * THE SOFTWARE. */ -package me.tori.example.persistence; +package dev.tori.example.persistence; -import me.tori.wraith.bus.EventBus; -import me.tori.wraith.bus.IEventBus; -import me.tori.wraith.listener.LambdaEventListener; -import me.tori.wraith.subscriber.Subscriber; +import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.bus.IEventBus; +import dev.tori.wraith.listener.LambdaEventListener; +import dev.tori.wraith.subscriber.Subscriber; /** * A simple example of listener persistence. diff --git a/examples/java/me/tori/example/simple/SimpleExample.java b/examples/java/dev/tori/example/simple/SimpleExample.java similarity index 91% rename from examples/java/me/tori/example/simple/SimpleExample.java rename to examples/java/dev/tori/example/simple/SimpleExample.java index 3d6fdfa..a887f4e 100644 --- a/examples/java/me/tori/example/simple/SimpleExample.java +++ b/examples/java/dev/tori/example/simple/SimpleExample.java @@ -19,12 +19,12 @@ * THE SOFTWARE. */ -package me.tori.example.simple; +package dev.tori.example.simple; -import me.tori.wraith.bus.EventBus; -import me.tori.wraith.event.status.StatusEvent; -import me.tori.wraith.listener.LambdaEventListener; -import me.tori.wraith.subscriber.Subscriber; +import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.status.StatusEvent; +import dev.tori.wraith.listener.LambdaEventListener; +import dev.tori.wraith.subscriber.Subscriber; /** * One-class example. diff --git a/examples/java/me/tori/example/statusevents/SupressionExample.java b/examples/java/dev/tori/example/statusevents/SupressionExample.java similarity index 90% rename from examples/java/me/tori/example/statusevents/SupressionExample.java rename to examples/java/dev/tori/example/statusevents/SupressionExample.java index f62abf0..1ec766d 100644 --- a/examples/java/me/tori/example/statusevents/SupressionExample.java +++ b/examples/java/dev/tori/example/statusevents/SupressionExample.java @@ -19,13 +19,13 @@ * THE SOFTWARE. */ -package me.tori.example.statusevents; +package dev.tori.example.statusevents; -import me.tori.wraith.bus.EventBus; -import me.tori.wraith.bus.IEventBus; -import me.tori.wraith.event.status.StatusEvent; -import me.tori.wraith.listener.LambdaEventListener; -import me.tori.wraith.subscriber.Subscriber; +import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.bus.IEventBus; +import dev.tori.wraith.event.status.StatusEvent; +import dev.tori.wraith.listener.LambdaEventListener; +import dev.tori.wraith.subscriber.Subscriber; /** * @author 7orivorian diff --git a/examples/java/me/tori/example/statusevents/TerminationExample.java b/examples/java/dev/tori/example/statusevents/TerminationExample.java similarity index 89% rename from examples/java/me/tori/example/statusevents/TerminationExample.java rename to examples/java/dev/tori/example/statusevents/TerminationExample.java index 5a2a4f1..64fe8e5 100644 --- a/examples/java/me/tori/example/statusevents/TerminationExample.java +++ b/examples/java/dev/tori/example/statusevents/TerminationExample.java @@ -19,13 +19,13 @@ * THE SOFTWARE. */ -package me.tori.example.statusevents; +package dev.tori.example.statusevents; -import me.tori.wraith.bus.EventBus; -import me.tori.wraith.bus.IEventBus; -import me.tori.wraith.event.status.StatusEvent; -import me.tori.wraith.listener.LambdaEventListener; -import me.tori.wraith.subscriber.Subscriber; +import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.bus.IEventBus; +import dev.tori.wraith.event.status.StatusEvent; +import dev.tori.wraith.listener.LambdaEventListener; +import dev.tori.wraith.subscriber.Subscriber; /** * @author 7orivorian diff --git a/examples/java/me/tori/example/taskexecutor/TaskExecutorExample.java b/examples/java/dev/tori/example/taskexecutor/TaskExecutorExample.java similarity index 93% rename from examples/java/me/tori/example/taskexecutor/TaskExecutorExample.java rename to examples/java/dev/tori/example/taskexecutor/TaskExecutorExample.java index f94777c..435f040 100644 --- a/examples/java/me/tori/example/taskexecutor/TaskExecutorExample.java +++ b/examples/java/dev/tori/example/taskexecutor/TaskExecutorExample.java @@ -19,11 +19,11 @@ * THE SOFTWARE. */ -package me.tori.example.taskexecutor; +package dev.tori.example.taskexecutor; -import me.tori.wraith.bus.EventBus; -import me.tori.wraith.task.ScheduledTask; -import me.tori.wraith.task.TaskExecutor; +import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.task.ScheduledTask; +import dev.tori.wraith.task.TaskExecutor; /** * A simple example showing how to use the {@link TaskExecutor} diff --git a/pom.xml b/pom.xml index 8bafb7e..792c511 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ Java event library https://github.com/7orivorian/Wraith - me.tori + dev.tori Wraith jar 4.0.0 @@ -22,7 +22,7 @@ 7orivorian - Tori Vii + Tori https://7ori.dev @@ -60,6 +60,14 @@ UTF-8 + + + github + GitHub 7orivorian Apache Maven Packages + https://maven.pkg.github.com/7orivorian/Wraith + + + diff --git a/src/main/java/me/tori/wraith/bus/EventBus.java b/src/main/java/dev/tori/wraith/bus/EventBus.java similarity index 95% rename from src/main/java/me/tori/wraith/bus/EventBus.java rename to src/main/java/dev/tori/wraith/bus/EventBus.java index a54e436..b3bbd62 100644 --- a/src/main/java/me/tori/wraith/bus/EventBus.java +++ b/src/main/java/dev/tori/wraith/bus/EventBus.java @@ -19,15 +19,15 @@ * THE SOFTWARE. */ -package me.tori.wraith.bus; +package dev.tori.wraith.bus; -import me.tori.wraith.event.status.IStatusEvent; -import me.tori.wraith.event.targeted.IClassTargetingEvent; -import me.tori.wraith.listener.Listener; -import me.tori.wraith.subscriber.ISubscriber; -import me.tori.wraith.task.ScheduledTask; -import me.tori.wraith.task.TaskExecutor; -import me.tori.wraith.util.IndexedHashSet; +import dev.tori.wraith.event.status.IStatusEvent; +import dev.tori.wraith.event.targeted.IClassTargetingEvent; +import dev.tori.wraith.listener.Listener; +import dev.tori.wraith.subscriber.ISubscriber; +import dev.tori.wraith.task.ScheduledTask; +import dev.tori.wraith.task.TaskExecutor; +import dev.tori.wraith.util.IndexedHashSet; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -223,8 +223,9 @@ public boolean dispatch(Object event, boolean invertPriority) { * The {@code type} parameter serves as a filtering mechanism for listeners, enabling you to selectively invoke * listeners based on their type, allowing for more targeted event handling. * - * @param event the event to be dispatched - * @param type the type of listener to invoke (can be {@code null}) + * @param event the event to be dispatched + * @param type the type of listener to invoke (can be {@code null}) + * @param invertPriority flag to dispatch the event in inverse listener priority * @return {@code true} if the given event is {@linkplain IStatusEvent suppressed or terminated} by any listener, * {@code false} otherwise * @throws NullPointerException if the given event is {@code null} diff --git a/src/main/java/me/tori/wraith/bus/IEventBus.java b/src/main/java/dev/tori/wraith/bus/IEventBus.java similarity index 95% rename from src/main/java/me/tori/wraith/bus/IEventBus.java rename to src/main/java/dev/tori/wraith/bus/IEventBus.java index 041422d..c34e6e4 100644 --- a/src/main/java/me/tori/wraith/bus/IEventBus.java +++ b/src/main/java/dev/tori/wraith/bus/IEventBus.java @@ -19,12 +19,12 @@ * THE SOFTWARE. */ -package me.tori.wraith.bus; +package dev.tori.wraith.bus; -import me.tori.wraith.event.status.IStatusEvent; -import me.tori.wraith.listener.EventListener; -import me.tori.wraith.listener.Listener; -import me.tori.wraith.subscriber.ISubscriber; +import dev.tori.wraith.subscriber.ISubscriber; +import dev.tori.wraith.event.status.IStatusEvent; +import dev.tori.wraith.listener.EventListener; +import dev.tori.wraith.listener.Listener; /** * An event bus that allows for the subscription, registration, and dispatching of events to listeners. diff --git a/src/main/java/me/tori/wraith/event/staged/EventStage.java b/src/main/java/dev/tori/wraith/event/staged/EventStage.java similarity index 97% rename from src/main/java/me/tori/wraith/event/staged/EventStage.java rename to src/main/java/dev/tori/wraith/event/staged/EventStage.java index 10cbdda..b9f76a9 100644 --- a/src/main/java/me/tori/wraith/event/staged/EventStage.java +++ b/src/main/java/dev/tori/wraith/event/staged/EventStage.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package me.tori.wraith.event.staged; +package dev.tori.wraith.event.staged; /** * Represents the possible stages at which an event can occur. diff --git a/src/main/java/me/tori/wraith/event/staged/IStagedEvent.java b/src/main/java/dev/tori/wraith/event/staged/IStagedEvent.java similarity index 97% rename from src/main/java/me/tori/wraith/event/staged/IStagedEvent.java rename to src/main/java/dev/tori/wraith/event/staged/IStagedEvent.java index 870843e..9462cb3 100644 --- a/src/main/java/me/tori/wraith/event/staged/IStagedEvent.java +++ b/src/main/java/dev/tori/wraith/event/staged/IStagedEvent.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package me.tori.wraith.event.staged; +package dev.tori.wraith.event.staged; /** * An interface representing a staged event, indicating the stage at which the event is occurring. diff --git a/src/main/java/me/tori/wraith/event/staged/StagedEvent.java b/src/main/java/dev/tori/wraith/event/staged/StagedEvent.java similarity index 97% rename from src/main/java/me/tori/wraith/event/staged/StagedEvent.java rename to src/main/java/dev/tori/wraith/event/staged/StagedEvent.java index bc332a4..111a5d4 100644 --- a/src/main/java/me/tori/wraith/event/staged/StagedEvent.java +++ b/src/main/java/dev/tori/wraith/event/staged/StagedEvent.java @@ -19,12 +19,10 @@ * THE SOFTWARE. */ -package me.tori.wraith.event.staged; +package dev.tori.wraith.event.staged; import org.jetbrains.annotations.NotNull; -import java.util.Objects; - /** * Represents a staged event implementation that specifies the stage at which the event occurs. * diff --git a/src/main/java/me/tori/wraith/event/status/IStatusEvent.java b/src/main/java/dev/tori/wraith/event/status/IStatusEvent.java similarity index 96% rename from src/main/java/me/tori/wraith/event/status/IStatusEvent.java rename to src/main/java/dev/tori/wraith/event/status/IStatusEvent.java index 5d17741..d1a6282 100644 --- a/src/main/java/me/tori/wraith/event/status/IStatusEvent.java +++ b/src/main/java/dev/tori/wraith/event/status/IStatusEvent.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package me.tori.wraith.event.status; +package dev.tori.wraith.event.status; import org.jetbrains.annotations.NotNull; @@ -45,8 +45,13 @@ public interface IStatusEvent { /** * Sets the status of this event. + *

+ * Note: + * This method should not be called directly. * * @param status the new {@link EventStatus} to set. + * @see #suppress() + * @see #terminate() */ void setEventStatus(@NotNull EventStatus status); diff --git a/src/main/java/me/tori/wraith/event/status/StatusEvent.java b/src/main/java/dev/tori/wraith/event/status/StatusEvent.java similarity index 98% rename from src/main/java/me/tori/wraith/event/status/StatusEvent.java rename to src/main/java/dev/tori/wraith/event/status/StatusEvent.java index 86ff702..f0a3292 100644 --- a/src/main/java/me/tori/wraith/event/status/StatusEvent.java +++ b/src/main/java/dev/tori/wraith/event/status/StatusEvent.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package me.tori.wraith.event.status; +package dev.tori.wraith.event.status; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/me/tori/wraith/event/targeted/ClassTargetingEvent.java b/src/main/java/dev/tori/wraith/event/targeted/ClassTargetingEvent.java similarity index 89% rename from src/main/java/me/tori/wraith/event/targeted/ClassTargetingEvent.java rename to src/main/java/dev/tori/wraith/event/targeted/ClassTargetingEvent.java index bff8530..4d16c3c 100644 --- a/src/main/java/me/tori/wraith/event/targeted/ClassTargetingEvent.java +++ b/src/main/java/dev/tori/wraith/event/targeted/ClassTargetingEvent.java @@ -19,9 +19,10 @@ * THE SOFTWARE. */ -package me.tori.wraith.event.targeted; +package dev.tori.wraith.event.targeted; -import me.tori.wraith.listener.Listener; +import dev.tori.wraith.listener.Listener; +import org.jetbrains.annotations.Nullable; /** * A basic implementation of the {@link IClassTargetingEvent} interface. @@ -34,6 +35,7 @@ @SuppressWarnings("ClassCanBeRecord") public class ClassTargetingEvent implements IClassTargetingEvent { + @Nullable private final Class> targetClass; /** @@ -41,7 +43,7 @@ public class ClassTargetingEvent implements IClassTargetingEvent { * * @param targetClass The class representing the type of listeners to be targeted by this event. */ - public ClassTargetingEvent(Class> targetClass) { + public ClassTargetingEvent(@Nullable Class> targetClass) { this.targetClass = targetClass; } @@ -50,6 +52,7 @@ public ClassTargetingEvent(Class> targetClass) { * * @return The class that represents the type of listeners targeted by this event. */ + @Nullable @Override public Class> getTargetClass() { return targetClass; diff --git a/src/main/java/me/tori/wraith/event/targeted/IClassTargetingEvent.java b/src/main/java/dev/tori/wraith/event/targeted/IClassTargetingEvent.java similarity index 91% rename from src/main/java/me/tori/wraith/event/targeted/IClassTargetingEvent.java rename to src/main/java/dev/tori/wraith/event/targeted/IClassTargetingEvent.java index 413e57a..f4d1f19 100644 --- a/src/main/java/me/tori/wraith/event/targeted/IClassTargetingEvent.java +++ b/src/main/java/dev/tori/wraith/event/targeted/IClassTargetingEvent.java @@ -19,9 +19,10 @@ * THE SOFTWARE. */ -package me.tori.wraith.event.targeted; +package dev.tori.wraith.event.targeted; -import me.tori.wraith.listener.Listener; +import dev.tori.wraith.listener.Listener; +import org.jetbrains.annotations.Nullable; /** * An interface representing an event that targets a specific class of listeners. @@ -55,6 +56,7 @@ static boolean isListenerTargetedByEvent(Listener listener, Object event) { * * @return The class that represents the type of listeners targeted by this event. */ + @Nullable Class> getTargetClass(); /** @@ -68,6 +70,7 @@ static boolean isListenerTargetedByEvent(Listener listener, Object event) { * @since 3.3.0 */ default boolean isListenerTargeted(Listener listener) { - return getTargetClass().isInstance(listener); + Class> targetClass = getTargetClass(); + return (targetClass == null) || targetClass.isInstance(listener); } } \ No newline at end of file diff --git a/src/main/java/me/tori/wraith/listener/EventListener.java b/src/main/java/dev/tori/wraith/listener/EventListener.java similarity index 99% rename from src/main/java/me/tori/wraith/listener/EventListener.java rename to src/main/java/dev/tori/wraith/listener/EventListener.java index 9a62c20..a6eab4e 100644 --- a/src/main/java/me/tori/wraith/listener/EventListener.java +++ b/src/main/java/dev/tori/wraith/listener/EventListener.java @@ -19,9 +19,9 @@ * THE SOFTWARE. */ -package me.tori.wraith.listener; +package dev.tori.wraith.listener; -import me.tori.wraith.bus.IEventBus; +import dev.tori.wraith.bus.IEventBus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/me/tori/wraith/listener/Invokable.java b/src/main/java/dev/tori/wraith/listener/Invokable.java similarity index 98% rename from src/main/java/me/tori/wraith/listener/Invokable.java rename to src/main/java/dev/tori/wraith/listener/Invokable.java index d8594ff..685ceb1 100644 --- a/src/main/java/me/tori/wraith/listener/Invokable.java +++ b/src/main/java/dev/tori/wraith/listener/Invokable.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package me.tori.wraith.listener; +package dev.tori.wraith.listener; /** * A functional interface representing a callable object that can handle or process an event. diff --git a/src/main/java/me/tori/wraith/listener/LambdaEventListener.java b/src/main/java/dev/tori/wraith/listener/LambdaEventListener.java similarity index 99% rename from src/main/java/me/tori/wraith/listener/LambdaEventListener.java rename to src/main/java/dev/tori/wraith/listener/LambdaEventListener.java index e344122..174a32d 100644 --- a/src/main/java/me/tori/wraith/listener/LambdaEventListener.java +++ b/src/main/java/dev/tori/wraith/listener/LambdaEventListener.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package me.tori.wraith.listener; +package dev.tori.wraith.listener; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/me/tori/wraith/listener/Listener.java b/src/main/java/dev/tori/wraith/listener/Listener.java similarity index 98% rename from src/main/java/me/tori/wraith/listener/Listener.java rename to src/main/java/dev/tori/wraith/listener/Listener.java index c1d5259..3e418cc 100644 --- a/src/main/java/me/tori/wraith/listener/Listener.java +++ b/src/main/java/dev/tori/wraith/listener/Listener.java @@ -19,9 +19,9 @@ * THE SOFTWARE. */ -package me.tori.wraith.listener; +package dev.tori.wraith.listener; -import me.tori.wraith.bus.EventBus; +import dev.tori.wraith.bus.EventBus; import java.util.List; import java.util.function.Consumer; diff --git a/src/main/java/me/tori/wraith/listener/ListenerBuilder.java b/src/main/java/dev/tori/wraith/listener/ListenerBuilder.java similarity index 98% rename from src/main/java/me/tori/wraith/listener/ListenerBuilder.java rename to src/main/java/dev/tori/wraith/listener/ListenerBuilder.java index 2c02670..edb7bf9 100644 --- a/src/main/java/me/tori/wraith/listener/ListenerBuilder.java +++ b/src/main/java/dev/tori/wraith/listener/ListenerBuilder.java @@ -19,9 +19,9 @@ * THE SOFTWARE. */ -package me.tori.wraith.listener; +package dev.tori.wraith.listener; -import me.tori.wraith.bus.IEventBus; +import dev.tori.wraith.bus.IEventBus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/src/main/java/me/tori/wraith/subscriber/ISubscriber.java b/src/main/java/dev/tori/wraith/subscriber/ISubscriber.java similarity index 96% rename from src/main/java/me/tori/wraith/subscriber/ISubscriber.java rename to src/main/java/dev/tori/wraith/subscriber/ISubscriber.java index 29638be..7394dc3 100644 --- a/src/main/java/me/tori/wraith/subscriber/ISubscriber.java +++ b/src/main/java/dev/tori/wraith/subscriber/ISubscriber.java @@ -19,10 +19,10 @@ * THE SOFTWARE. */ -package me.tori.wraith.subscriber; +package dev.tori.wraith.subscriber; -import me.tori.wraith.bus.IEventBus; -import me.tori.wraith.listener.Listener; +import dev.tori.wraith.bus.IEventBus; +import dev.tori.wraith.listener.Listener; import java.util.Collection; diff --git a/src/main/java/me/tori/wraith/subscriber/Subscriber.java b/src/main/java/dev/tori/wraith/subscriber/Subscriber.java similarity index 98% rename from src/main/java/me/tori/wraith/subscriber/Subscriber.java rename to src/main/java/dev/tori/wraith/subscriber/Subscriber.java index ce9f0c8..619b417 100644 --- a/src/main/java/me/tori/wraith/subscriber/Subscriber.java +++ b/src/main/java/dev/tori/wraith/subscriber/Subscriber.java @@ -19,10 +19,10 @@ * THE SOFTWARE. */ -package me.tori.wraith.subscriber; +package dev.tori.wraith.subscriber; -import me.tori.wraith.bus.IEventBus; -import me.tori.wraith.listener.Listener; +import dev.tori.wraith.bus.IEventBus; +import dev.tori.wraith.listener.Listener; import org.jetbrains.annotations.NotNull; import java.util.*; diff --git a/src/main/java/me/tori/wraith/task/ScheduledTask.java b/src/main/java/dev/tori/wraith/task/ScheduledTask.java similarity index 99% rename from src/main/java/me/tori/wraith/task/ScheduledTask.java rename to src/main/java/dev/tori/wraith/task/ScheduledTask.java index 54e4041..907b9c6 100644 --- a/src/main/java/me/tori/wraith/task/ScheduledTask.java +++ b/src/main/java/dev/tori/wraith/task/ScheduledTask.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package me.tori.wraith.task; +package dev.tori.wraith.task; import org.jetbrains.annotations.NotNull; diff --git a/src/main/java/me/tori/wraith/task/TaskExecutor.java b/src/main/java/dev/tori/wraith/task/TaskExecutor.java similarity index 99% rename from src/main/java/me/tori/wraith/task/TaskExecutor.java rename to src/main/java/dev/tori/wraith/task/TaskExecutor.java index e2beb99..1f3a3f3 100644 --- a/src/main/java/me/tori/wraith/task/TaskExecutor.java +++ b/src/main/java/dev/tori/wraith/task/TaskExecutor.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package me.tori.wraith.task; +package dev.tori.wraith.task; import java.util.ArrayList; import java.util.concurrent.ConcurrentHashMap; diff --git a/src/main/java/me/tori/wraith/util/IndexedHashSet.java b/src/main/java/dev/tori/wraith/util/IndexedHashSet.java similarity index 99% rename from src/main/java/me/tori/wraith/util/IndexedHashSet.java rename to src/main/java/dev/tori/wraith/util/IndexedHashSet.java index 02b1469..d8a5c09 100644 --- a/src/main/java/me/tori/wraith/util/IndexedHashSet.java +++ b/src/main/java/dev/tori/wraith/util/IndexedHashSet.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package me.tori.wraith.util; +package dev.tori.wraith.util; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/main/test/dev/tori/wraith/Main.java b/src/main/test/dev/tori/wraith/Main.java new file mode 100644 index 0000000..99fcf5b --- /dev/null +++ b/src/main/test/dev/tori/wraith/Main.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2024 7orivorian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package dev.tori.wraith; + +import dev.tori.wraith.event.targeted.IClassTargetingEvent; +import dev.tori.wraith.listener.Listener; +import org.jetbrains.annotations.Nullable; + +/** + * @author 7orivorian + * @since 4.0.0 + */ +public class Main { + + public static void main(String[] args) { + + } + + public class Event implements IClassTargetingEvent { + + @Nullable + private final Class> target; + + public Event(@Nullable Class> target) { + this.target = target; + } + + @Nullable + @Override + public Class> getTargetClass() { + return target; + } + } + + static final class MessageEvent { + + private String message; + + public MessageEvent() { + this.message = "nothing to say"; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + } +} \ No newline at end of file diff --git a/src/main/test/me/tori/wraith/benchmarking/BenchmarkMain.java b/src/main/test/dev/tori/wraith/benchmarking/BenchmarkMain.java similarity index 97% rename from src/main/test/me/tori/wraith/benchmarking/BenchmarkMain.java rename to src/main/test/dev/tori/wraith/benchmarking/BenchmarkMain.java index 9738e62..9d04611 100644 --- a/src/main/test/me/tori/wraith/benchmarking/BenchmarkMain.java +++ b/src/main/test/dev/tori/wraith/benchmarking/BenchmarkMain.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package me.tori.wraith.benchmarking; +package dev.tori.wraith.benchmarking; import org.openjdk.jmh.Main; diff --git a/src/main/test/me/tori/wraith/benchmarking/MyBenchmark.java b/src/main/test/dev/tori/wraith/benchmarking/MyBenchmark.java similarity index 94% rename from src/main/test/me/tori/wraith/benchmarking/MyBenchmark.java rename to src/main/test/dev/tori/wraith/benchmarking/MyBenchmark.java index ce6c364..9b2ccf0 100644 --- a/src/main/test/me/tori/wraith/benchmarking/MyBenchmark.java +++ b/src/main/test/dev/tori/wraith/benchmarking/MyBenchmark.java @@ -19,11 +19,11 @@ * THE SOFTWARE. */ -package me.tori.wraith.benchmarking; +package dev.tori.wraith.benchmarking; -import me.tori.wraith.bus.EventBus; -import me.tori.wraith.listener.EventListener; -import me.tori.wraith.subscriber.Subscriber; +import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.listener.EventListener; +import dev.tori.wraith.subscriber.Subscriber; import org.openjdk.jmh.annotations.*; import java.util.concurrent.TimeUnit; diff --git a/src/main/test/me/tori/wraith/persistency/PersistencyTest.java b/src/main/test/dev/tori/wraith/persistency/PersistencyTest.java similarity index 91% rename from src/main/test/me/tori/wraith/persistency/PersistencyTest.java rename to src/main/test/dev/tori/wraith/persistency/PersistencyTest.java index 06c2fb7..13fefed 100644 --- a/src/main/test/me/tori/wraith/persistency/PersistencyTest.java +++ b/src/main/test/dev/tori/wraith/persistency/PersistencyTest.java @@ -19,12 +19,12 @@ * THE SOFTWARE. */ -package me.tori.wraith.persistency; +package dev.tori.wraith.persistency; -import me.tori.wraith.bus.EventBus; -import me.tori.wraith.event.status.StatusEvent; -import me.tori.wraith.listener.EventListener; -import me.tori.wraith.subscriber.Subscriber; +import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.status.StatusEvent; +import dev.tori.wraith.listener.EventListener; +import dev.tori.wraith.subscriber.Subscriber; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/src/main/test/me/tori/wraith/priority/PriorityTest.java b/src/main/test/dev/tori/wraith/priority/PriorityTest.java similarity index 92% rename from src/main/test/me/tori/wraith/priority/PriorityTest.java rename to src/main/test/dev/tori/wraith/priority/PriorityTest.java index 6a0b90a..71efd95 100644 --- a/src/main/test/me/tori/wraith/priority/PriorityTest.java +++ b/src/main/test/dev/tori/wraith/priority/PriorityTest.java @@ -19,12 +19,12 @@ * THE SOFTWARE. */ -package me.tori.wraith.priority; +package dev.tori.wraith.priority; -import me.tori.wraith.bus.EventBus; -import me.tori.wraith.event.status.StatusEvent; -import me.tori.wraith.listener.LambdaEventListener; -import me.tori.wraith.subscriber.Subscriber; +import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.status.StatusEvent; +import dev.tori.wraith.listener.LambdaEventListener; +import dev.tori.wraith.subscriber.Subscriber; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/src/main/test/me/tori/wraith/registration/RegistrationTest.java b/src/main/test/dev/tori/wraith/registration/RegistrationTest.java similarity index 91% rename from src/main/test/me/tori/wraith/registration/RegistrationTest.java rename to src/main/test/dev/tori/wraith/registration/RegistrationTest.java index 7afa6bf..3f7bb1a 100644 --- a/src/main/test/me/tori/wraith/registration/RegistrationTest.java +++ b/src/main/test/dev/tori/wraith/registration/RegistrationTest.java @@ -19,13 +19,13 @@ * THE SOFTWARE. */ -package me.tori.wraith.registration; +package dev.tori.wraith.registration; -import me.tori.wraith.bus.EventBus; -import me.tori.wraith.event.status.IStatusEvent; -import me.tori.wraith.event.status.StatusEvent; -import me.tori.wraith.listener.LambdaEventListener; -import me.tori.wraith.subscriber.Subscriber; +import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.status.IStatusEvent; +import dev.tori.wraith.event.status.StatusEvent; +import dev.tori.wraith.listener.LambdaEventListener; +import dev.tori.wraith.subscriber.Subscriber; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/src/main/test/me/tori/wraith/statusevent/StatusEventTest.java b/src/main/test/dev/tori/wraith/statusevent/StatusEventTest.java similarity index 92% rename from src/main/test/me/tori/wraith/statusevent/StatusEventTest.java rename to src/main/test/dev/tori/wraith/statusevent/StatusEventTest.java index 03cff8e..0c1bb6c 100644 --- a/src/main/test/me/tori/wraith/statusevent/StatusEventTest.java +++ b/src/main/test/dev/tori/wraith/statusevent/StatusEventTest.java @@ -19,12 +19,12 @@ * THE SOFTWARE. */ -package me.tori.wraith.statusevent; +package dev.tori.wraith.statusevent; -import me.tori.wraith.bus.EventBus; -import me.tori.wraith.event.status.StatusEvent; -import me.tori.wraith.listener.LambdaEventListener; -import me.tori.wraith.subscriber.Subscriber; +import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.status.StatusEvent; +import dev.tori.wraith.listener.LambdaEventListener; +import dev.tori.wraith.subscriber.Subscriber; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/src/main/test/me/tori/wraith/targetedevent/TargetedEventTest.java b/src/main/test/dev/tori/wraith/targetedevent/TargetedEventTest.java similarity index 51% rename from src/main/test/me/tori/wraith/targetedevent/TargetedEventTest.java rename to src/main/test/dev/tori/wraith/targetedevent/TargetedEventTest.java index e716b2d..9dfe183 100644 --- a/src/main/test/me/tori/wraith/targetedevent/TargetedEventTest.java +++ b/src/main/test/dev/tori/wraith/targetedevent/TargetedEventTest.java @@ -19,17 +19,17 @@ * THE SOFTWARE. */ -package me.tori.wraith.targetedevent; - -import me.tori.wraith.bus.EventBus; -import me.tori.wraith.event.status.StatusEvent; -import me.tori.wraith.event.targeted.IClassTargetingEvent; -import me.tori.wraith.listener.EventListener; -import me.tori.wraith.listener.Listener; -import me.tori.wraith.subscriber.Subscriber; +package dev.tori.wraith.targetedevent; + +import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.status.StatusEvent; +import dev.tori.wraith.event.targeted.IClassTargetingEvent; +import dev.tori.wraith.listener.EventListener; +import dev.tori.wraith.listener.Listener; +import dev.tori.wraith.subscriber.Subscriber; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.*; /** * @author 7orivorian @@ -37,7 +37,7 @@ public class TargetedEventTest { @Test - public void testTargetedEvent() { + public void testTargetedEventWithLowerPriority() { final EventBus bus = new EventBus(); bus.subscribe(new Subscriber() {{ @@ -52,7 +52,7 @@ public void testTargetedEvent() { } @Test - public void testTargetedEvent2() { + public void testTargetedEventWithHigherPriority() { final EventBus bus = new EventBus(); bus.subscribe(new Subscriber() {{ @@ -66,6 +66,57 @@ public void testTargetedEvent2() { assertFalse(bus.dispatch(event)); } + @Test + public void testNestedClassTargetNestedListener() { + final EventBus bus = new EventBus(); + + bus.subscribe(new Subscriber() {{ + registerListeners( + new MyParentListener.MyNestedListener(0) + ); + }}); + + TestEvent event = new TestEvent(MyParentListener.MyNestedListener.class); + bus.dispatch(event); + + // Dispatched to nested target + assertEquals(2, event.getValue()); + } + + @Test + public void parentListenerNestedTarget() { + final EventBus bus = new EventBus(); + + bus.subscribe(new Subscriber() {{ + registerListeners( + new MyParentListener(0) + ); + }}); + + TestEvent event = new TestEvent(MyParentListener.MyNestedListener.class); + bus.dispatch(event); + + // Not dispatched to parent of nested target + assertEquals(0, event.getValue()); + } + + @Test + public void testParentOfNestedClassTarget() { + final EventBus bus = new EventBus(); + + bus.subscribe(new Subscriber() {{ + registerListeners( + new MyParentListener.MyNestedListener(0) + ); + }}); + + TestEvent event = new TestEvent(MyParentListener.class); + bus.dispatch(event); + + // Dispatched to nested listener if the parent is targeted + assertEquals(2, event.getValue()); + } + static class MyListener extends EventListener { public MyListener(int priority) { @@ -90,17 +141,51 @@ public void invoke(TestEvent event) { } } + static class MyParentListener extends EventListener { + + public MyParentListener(int priority) { + super(TestEvent.class, priority); + } + + @Override + public void invoke(TestEvent event) { + event.setValue(1); + } + + static class MyNestedListener extends MyParentListener { + + public MyNestedListener(int priority) { + super(priority); + } + + @Override + public void invoke(TestEvent event) { + event.setValue(2); + } + } + } + static class TestEvent extends StatusEvent implements IClassTargetingEvent { private final Class> targetClass; + private int value; public TestEvent(Class> target) { this.targetClass = target; + this.value = 0; } @Override public Class> getTargetClass() { return targetClass; } + + public int getValue() { + return value; + } + + public void setValue(int value) { + this.value = value; + } } } \ No newline at end of file diff --git a/src/main/test/me/tori/wraith/taskexecutor/TaskExecutorTest.java b/src/main/test/dev/tori/wraith/taskexecutor/TaskExecutorTest.java similarity index 96% rename from src/main/test/me/tori/wraith/taskexecutor/TaskExecutorTest.java rename to src/main/test/dev/tori/wraith/taskexecutor/TaskExecutorTest.java index a735a2d..f2783ca 100644 --- a/src/main/test/me/tori/wraith/taskexecutor/TaskExecutorTest.java +++ b/src/main/test/dev/tori/wraith/taskexecutor/TaskExecutorTest.java @@ -19,10 +19,10 @@ * THE SOFTWARE. */ -package me.tori.wraith.taskexecutor; +package dev.tori.wraith.taskexecutor; -import me.tori.wraith.task.ScheduledTask; -import me.tori.wraith.task.TaskExecutor; +import dev.tori.wraith.task.ScheduledTask; +import dev.tori.wraith.task.TaskExecutor; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; diff --git a/src/main/test/me/tori/wraith/util/IndexedHashSetTest.java b/src/main/test/dev/tori/wraith/util/IndexedHashSetTest.java similarity index 97% rename from src/main/test/me/tori/wraith/util/IndexedHashSetTest.java rename to src/main/test/dev/tori/wraith/util/IndexedHashSetTest.java index b33e6ae..1882998 100644 --- a/src/main/test/me/tori/wraith/util/IndexedHashSetTest.java +++ b/src/main/test/dev/tori/wraith/util/IndexedHashSetTest.java @@ -19,8 +19,9 @@ * THE SOFTWARE. */ -package me.tori.wraith.util; +package dev.tori.wraith.util; +import dev.tori.wraith.util.IndexedHashSet; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; From b0bf305af8e159546a1dbfb3539c0942f4dc6d38 Mon Sep 17 00:00:00 2001 From: Tori <7orivorian+github@gmail.com> Date: Mon, 29 Jul 2024 20:17:33 -0400 Subject: [PATCH 15/30] Impl new class targeting system (1/x) Signed-off-by: Tori <7orivorian+github@gmail.com> --- .../example/expanded/ExampleListener.java | 3 +- .../example/expanded/ExampleSubscriber.java | 3 +- .../persistence/PersistenceExample.java | 3 +- .../tori/example/simple/SimpleExample.java | 9 +- .../statusevents/SupressionExample.java | 5 +- .../statusevents/TerminationExample.java | 5 +- .../java/dev/tori/wraith/bus/EventBus.java | 50 ++--- .../java/dev/tori/wraith/bus/IEventBus.java | 41 ++-- .../java/dev/tori/wraith/event/Target.java | 174 ++++++++++++++++ .../tori/wraith/listener/EventListener.java | 96 +++------ .../wraith/listener/LambdaEventListener.java | 74 +++---- .../dev/tori/wraith/listener/Listener.java | 45 +---- .../tori/wraith/listener/ListenerBuilder.java | 49 ++--- src/main/test/dev/tori/wraith/Main.java | 103 ++++++++-- src/main/test/dev/tori/wraith/MainTwo.java | 94 +++++++++ .../tori/wraith/benchmarking/MyBenchmark.java | 3 +- .../wraith/persistency/PersistencyTest.java | 3 +- .../tori/wraith/priority/PriorityTest.java | 13 +- .../wraith/registration/RegistrationTest.java | 10 +- .../wraith/statusevent/StatusEventTest.java | 9 +- .../targetedevent/TargetedEventTest.java | 191 ------------------ 21 files changed, 522 insertions(+), 461 deletions(-) create mode 100644 src/main/java/dev/tori/wraith/event/Target.java create mode 100644 src/main/test/dev/tori/wraith/MainTwo.java delete mode 100644 src/main/test/dev/tori/wraith/targetedevent/TargetedEventTest.java diff --git a/examples/java/dev/tori/example/expanded/ExampleListener.java b/examples/java/dev/tori/example/expanded/ExampleListener.java index 327b2a1..0942fc1 100644 --- a/examples/java/dev/tori/example/expanded/ExampleListener.java +++ b/examples/java/dev/tori/example/expanded/ExampleListener.java @@ -21,6 +21,7 @@ package dev.tori.example.expanded; +import dev.tori.wraith.event.Target; import dev.tori.wraith.event.staged.EventStage; import dev.tori.wraith.listener.EventListener; @@ -33,7 +34,7 @@ class ExampleListener extends EventListener { public ExampleListener() { - super(ExampleEvent.class); + super(Target.fine(ExampleEvent.class)); } @Override diff --git a/examples/java/dev/tori/example/expanded/ExampleSubscriber.java b/examples/java/dev/tori/example/expanded/ExampleSubscriber.java index 4e3c8de..f7028fd 100644 --- a/examples/java/dev/tori/example/expanded/ExampleSubscriber.java +++ b/examples/java/dev/tori/example/expanded/ExampleSubscriber.java @@ -21,6 +21,7 @@ package dev.tori.example.expanded; +import dev.tori.wraith.event.Target; import dev.tori.wraith.event.staged.EventStage; import dev.tori.wraith.listener.LambdaEventListener; import dev.tori.wraith.subscriber.Subscriber; @@ -35,7 +36,7 @@ class ExampleSubscriber extends Subscriber { public ExampleSubscriber() { registerListener( - new LambdaEventListener<>(ExampleEvent.class, event -> { + new LambdaEventListener(Target.fine(ExampleEvent.class), event -> { if (event.getStage() == EventStage.PRE) { event.setMessage("Hello world!"); } diff --git a/examples/java/dev/tori/example/persistence/PersistenceExample.java b/examples/java/dev/tori/example/persistence/PersistenceExample.java index cb194c5..eec5f97 100644 --- a/examples/java/dev/tori/example/persistence/PersistenceExample.java +++ b/examples/java/dev/tori/example/persistence/PersistenceExample.java @@ -23,6 +23,7 @@ import dev.tori.wraith.bus.EventBus; import dev.tori.wraith.bus.IEventBus; +import dev.tori.wraith.event.Target; import dev.tori.wraith.listener.LambdaEventListener; import dev.tori.wraith.subscriber.Subscriber; @@ -40,7 +41,7 @@ class PersistenceExample { private static final Subscriber SUBSCRIBER = new Subscriber() {{ // Register a listener that prints a single // String event & is then removed from the event bus - registerListener(new LambdaEventListener<>(String.class, null, IEventBus.DEFAULT_PRIORITY, 1, System.out::println)); + registerListener(new LambdaEventListener(Target.fine(String.class), IEventBus.DEFAULT_PRIORITY, 1, System.out::println)); }}; public static void main(String[] args) { diff --git a/examples/java/dev/tori/example/simple/SimpleExample.java b/examples/java/dev/tori/example/simple/SimpleExample.java index a887f4e..7e7173c 100644 --- a/examples/java/dev/tori/example/simple/SimpleExample.java +++ b/examples/java/dev/tori/example/simple/SimpleExample.java @@ -22,6 +22,7 @@ package dev.tori.example.simple; import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.Target; import dev.tori.wraith.event.status.StatusEvent; import dev.tori.wraith.listener.LambdaEventListener; import dev.tori.wraith.subscriber.Subscriber; @@ -44,7 +45,7 @@ public static void main(String[] args) { bus.subscribe(subscriber); // Create a simple event - SimpleEvent event = new SimpleEvent("Pie is delicious <3"); + StringEvent event = new StringEvent("Pie is delicious <3"); // Dispatch our event bus.dispatch(event); @@ -54,16 +55,16 @@ private static final class SimpleSubscriber extends Subscriber { public SimpleSubscriber() { registerListener( - new LambdaEventListener<>(SimpleEvent.class, event -> System.out.println(event.getMessage())) + new LambdaEventListener(Target.fine(StringEvent.class), event -> System.out.println(event.getMessage())) ); } } - private static final class SimpleEvent extends StatusEvent { + private static final class StringEvent extends StatusEvent { private final String message; - public SimpleEvent(String message) { + public StringEvent(String message) { this.message = message; } diff --git a/examples/java/dev/tori/example/statusevents/SupressionExample.java b/examples/java/dev/tori/example/statusevents/SupressionExample.java index 1ec766d..512e313 100644 --- a/examples/java/dev/tori/example/statusevents/SupressionExample.java +++ b/examples/java/dev/tori/example/statusevents/SupressionExample.java @@ -23,6 +23,7 @@ import dev.tori.wraith.bus.EventBus; import dev.tori.wraith.bus.IEventBus; +import dev.tori.wraith.event.Target; import dev.tori.wraith.event.status.StatusEvent; import dev.tori.wraith.listener.LambdaEventListener; import dev.tori.wraith.subscriber.Subscriber; @@ -36,11 +37,11 @@ public class SupressionExample { private static final IEventBus EVENT_BUS = new EventBus(); private static final Subscriber SUBSCRIBER = new Subscriber() {{ registerListeners( - new LambdaEventListener<>(StringEvent.class, 1, event -> { + new LambdaEventListener(Target.fine(StringEvent.class), 1, event -> { event.message = "Hello world!"; event.suppress(); }), - new LambdaEventListener<>(StringEvent.class, 0, event -> { + new LambdaEventListener(Target.fine(StringEvent.class), 0, event -> { event.message = "I do not greet"; }) ); diff --git a/examples/java/dev/tori/example/statusevents/TerminationExample.java b/examples/java/dev/tori/example/statusevents/TerminationExample.java index 64fe8e5..aaccd5a 100644 --- a/examples/java/dev/tori/example/statusevents/TerminationExample.java +++ b/examples/java/dev/tori/example/statusevents/TerminationExample.java @@ -23,6 +23,7 @@ import dev.tori.wraith.bus.EventBus; import dev.tori.wraith.bus.IEventBus; +import dev.tori.wraith.event.Target; import dev.tori.wraith.event.status.StatusEvent; import dev.tori.wraith.listener.LambdaEventListener; import dev.tori.wraith.subscriber.Subscriber; @@ -36,11 +37,11 @@ public class TerminationExample { private static final IEventBus EVENT_BUS = new EventBus(); private static final Subscriber SUBSCRIBER = new Subscriber() {{ registerListeners( - new LambdaEventListener<>(StringEvent.class, 1, event -> { + new LambdaEventListener(Target.fine(StringEvent.class), 1, event -> { event.message = "Hello world!"; event.terminate(); }), - new LambdaEventListener<>(StringEvent.class, 0, event -> { + new LambdaEventListener(Target.fine(StringEvent.class), 0, event -> { event.message = "I do not greet"; }) ); diff --git a/src/main/java/dev/tori/wraith/bus/EventBus.java b/src/main/java/dev/tori/wraith/bus/EventBus.java index b3bbd62..3ff1cb5 100644 --- a/src/main/java/dev/tori/wraith/bus/EventBus.java +++ b/src/main/java/dev/tori/wraith/bus/EventBus.java @@ -21,13 +21,14 @@ package dev.tori.wraith.bus; +import dev.tori.wraith.event.Target; import dev.tori.wraith.event.status.IStatusEvent; -import dev.tori.wraith.event.targeted.IClassTargetingEvent; import dev.tori.wraith.listener.Listener; import dev.tori.wraith.subscriber.ISubscriber; import dev.tori.wraith.task.ScheduledTask; import dev.tori.wraith.task.TaskExecutor; import dev.tori.wraith.util.IndexedHashSet; +import org.jetbrains.annotations.NotNull; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -158,7 +159,7 @@ public void unsubscribe(ISubscriber subscriber) { public void register(Listener listener) { Objects.requireNonNull(listener, "Cannot register null listener to event bus " + id + "!"); - IndexedHashSet listeners = this.listeners.computeIfAbsent(listener.getTarget(), target -> new IndexedHashSet<>()); + IndexedHashSet listeners = this.listeners.computeIfAbsent(listener.getTarget().clazz(), target -> new IndexedHashSet<>()); final int size = listeners.size(); int index = 0; for (; index < size; index++) { @@ -178,43 +179,43 @@ public void register(Listener listener) { @Override public void unregister(Listener listener) { Objects.requireNonNull(listener, "Cannot unregister null listener from event bus " + id + "!"); - listeners.get(listener.getTarget()).removeIf(l -> l.equals(listener)); + listeners.get(listener.getTarget().clazz()).removeIf(l -> l.equals(listener)); } /** - * Convenience method to dispatch an event with no {@linkplain Listener#getType() listener type} restriction, and + * Convenience method to dispatch an event with no {@linkplain Target target listener}, and * normal processing priority. * - * @see #dispatch(Object, Class, boolean) + * @see #dispatch(Object, Target, boolean) * @since 3.3.0 */ @Override public boolean dispatch(Object event) { - return dispatch(event, null, false); + return dispatch(event, Target.none(), false); } /** - * Convenience method to dispatch an event with an optional {@linkplain Listener#getType() listener type} restriction, and + * Convenience method to dispatch an event with an optional {@linkplain Target target listener} and * normal processing priority. * - * @see #dispatch(Object, Class, boolean) - * @since 3.3.0 + * @see #dispatch(Object, Target, boolean) + * @since 4.0.0 */ @Override - public boolean dispatch(Object event, Class type) { - return dispatch(event, type, false); + public boolean dispatch(Object event, Target target) { + return dispatch(event, target, false); } /** - * Convenience method to dispatch an event with no {@linkplain Listener#getType() listener type} restriction, and + * Convenience method to dispatch an event with no {@linkplain Target target listener}, and * optional inverted processing priority. * - * @see #dispatch(Object, Class, boolean) - * @since 3.3.0 + * @see #dispatch(Object, Target, boolean) + * @since 4.0.0 */ @Override public boolean dispatch(Object event, boolean invertPriority) { - return dispatch(event, null, invertPriority); + return dispatch(event, Target.none(), invertPriority); } /** @@ -223,27 +224,28 @@ public boolean dispatch(Object event, boolean invertPriority) { * The {@code type} parameter serves as a filtering mechanism for listeners, enabling you to selectively invoke * listeners based on their type, allowing for more targeted event handling. * - * @param event the event to be dispatched - * @param type the type of listener to invoke (can be {@code null}) - * @param invertPriority flag to dispatch the event in inverse listener priority + * @param event the event to be dispatched. + * @param target the {@linkplain Target target listener} to invoke. + * @param invertPriority flag to dispatch the event in inverse listener priority. * @return {@code true} if the given event is {@linkplain IStatusEvent suppressed or terminated} by any listener, - * {@code false} otherwise + * {@code false} otherwise. * @throws NullPointerException if the given event is {@code null} * @throws UnsupportedOperationException if this event bus is {@link #shutdown} - * @since 3.3.0 + * @since 4.0.0 */ @Override - public boolean dispatch(Object event, Class type, boolean invertPriority) { + public boolean dispatch(Object event, Target target, boolean invertPriority) { Objects.requireNonNull(event, "Cannot dispatch a null event to event bus " + id + "!"); + Objects.requireNonNull(target, "Cannot dispatch an event with a null target to event bus " + id + "!"); if (isShutdown()) { - throw new UnsupportedOperationException("Dispatcher " + id + " is shutdown!"); + throw new UnsupportedOperationException("Event bus " + id + " is shutdown!"); } else { taskExecutor.onEvent(event); dispatchToEachListener( event, - this.listeners.get(event.getClass()), - listener -> listener.isAcceptableType(type) && IClassTargetingEvent.isListenerTargetedByEvent(listener, event), + listeners.get(event.getClass()), + listener -> target.targets(listener.getClass()) && listener.getTarget().targets(event.getClass()), invertPriority ); diff --git a/src/main/java/dev/tori/wraith/bus/IEventBus.java b/src/main/java/dev/tori/wraith/bus/IEventBus.java index c34e6e4..aafd5dd 100644 --- a/src/main/java/dev/tori/wraith/bus/IEventBus.java +++ b/src/main/java/dev/tori/wraith/bus/IEventBus.java @@ -21,31 +21,31 @@ package dev.tori.wraith.bus; -import dev.tori.wraith.subscriber.ISubscriber; +import dev.tori.wraith.event.Target; import dev.tori.wraith.event.status.IStatusEvent; import dev.tori.wraith.listener.EventListener; import dev.tori.wraith.listener.Listener; +import dev.tori.wraith.subscriber.ISubscriber; /** * An event bus that allows for the subscription, registration, and dispatching of events to listeners. * - * @author 7orivorian - * @since 1.0.0 + * @author 7orivorian + * @since 1.0.0 */ public interface IEventBus { /** * Default priority used when no other priority is specified. * - * @see EventListener#EventListener(Class) - * @see EventListener#EventListener(Class, Class) + * @see EventListener#EventListener(Target) */ int DEFAULT_PRIORITY = 0; /** * Subscribes the specified subscriber to this event bus. * - * @param subscriber the {@link ISubscriber} to be subscribed + * @param subscriber the {@link ISubscriber} to be subscribed. * @see #register(Listener) */ void subscribe(ISubscriber subscriber); @@ -53,7 +53,7 @@ public interface IEventBus { /** * Unsubscribes the specified subscriber from this event bus. * - * @param subscriber the {@link ISubscriber} to be unsubscribed + * @param subscriber the {@link ISubscriber} to be unsubscribed. * @see #unregister(Listener) */ void unsubscribe(ISubscriber subscriber); @@ -61,21 +61,21 @@ public interface IEventBus { /** * Registers the specified listener to this event bus. * - * @param listener the {@link Listener} to be registered + * @param listener the {@link Listener} to be registered. */ void register(Listener listener); /** * Unregisters the specified listener from this event bus. * - * @param listener the {@link Listener} to be unregistered + * @param listener the {@link Listener} to be unregistered. */ void unregister(Listener listener); /** * Dispatches the specified event to all registered listeners. * - * @param event the event to be dispatched + * @param event the event to be dispatched. * @return {@code true} if the given event is {@linkplain IStatusEvent suppressed or terminated} by any listener, * {@code false} otherwise. */ @@ -84,35 +84,38 @@ public interface IEventBus { /** * Dispatches the specified event to all registered listeners of the specified type. * - * @param event the event to be dispatched - * @param type the type of listener to invoke (can be {@code null}) + * @param event the event to be dispatched. + * @param target the {@linkplain Target target class} of listener to invoke. * @return {@code true} if the given event is {@linkplain IStatusEvent suppressed or terminated} by any listener, * {@code false} otherwise. + * @since 4.0.0 */ - boolean dispatch(Object event, Class type); + boolean dispatch(Object event, Target target); /** * Dispatches the specified event to all registered listeners, with the option to invert the processing priority. * - * @param event the event to be dispatched + * @param event the event to be dispatched. * @param invertPriority if {@code true}, listeners are processed in order of inverse priority; otherwise, - * they are processed in normal order + * they are processed in normal order. * @return {@code true} if the given event is {@linkplain IStatusEvent suppressed or terminated} by any listener, * {@code false} otherwise. + * @since 3.3.0 */ boolean dispatch(Object event, boolean invertPriority); /** * Dispatches the specified event to all registered listeners of the specified type, with the option to invert the processing priority. * - * @param event the event to be dispatched - * @param type the type of listener to invoke (can be {@code null}) + * @param event the event to be dispatched. + * @param target the {@linkplain Target target class} of listener to invoke. * @param invertPriority if {@code true}, listeners are processed in order of inverse priority; otherwise, - * they are processed in normal order + * they are processed in normal order. * @return {@code true} if the given event is {@linkplain IStatusEvent suppressed or terminated} by any listener, * {@code false} otherwise. + * @since 4.0.0 */ - boolean dispatch(Object event, Class type, boolean invertPriority); + boolean dispatch(Object event, Target target, boolean invertPriority); /** * Shuts down this event bus, preventing future events from being dispatched. diff --git a/src/main/java/dev/tori/wraith/event/Target.java b/src/main/java/dev/tori/wraith/event/Target.java new file mode 100644 index 0000000..7daad3e --- /dev/null +++ b/src/main/java/dev/tori/wraith/event/Target.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2024 7orivorian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package dev.tori.wraith.event; + +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +/** + * Represents a class target with a specified targeting strategy. + * This class is used to determine if a given class matches the target class according to the targeting strategy. + * + * @author 7orivorian + * @since 4.0.0 + */ +public class Target { + + @Nullable + private final Class clazz; + @NotNull + private final TargetingRule rule; + + /** + * Constructs a new {@link Target}. + * + * @param clazz the target class. + * @param rule the targeting rule. + */ + @Contract(pure = true) + private Target(@Nullable Class clazz, @NotNull TargetingRule rule) { + this.clazz = clazz; + this.rule = rule; + } + + /** + * Returns a {@code ClassTarget} with no specific target. + * + * @return a {@code ClassTarget} with no specific target. + */ + @NotNull + public static Target none() { + return new Target(null, TargetingRule.FINE); + } + + /** + * Returns a {@code ClassTarget} with the specified target and {@link TargetingRule#FINE FINE} targeting. + * + * @param target the target class. + * @return a {@code ClassTarget} with the specified target and {@link TargetingRule#FINE FINE} targeting. + */ + @NotNull + public static Target fine(@Nullable Class target) { + return new Target(target, TargetingRule.FINE); + } + + /** + * Returns a {@code ClassTarget} with the specified target and {@link TargetingRule#CASCADE CASCADE} targeting. + * + * @param target the target class. + * @return a {@code ClassTarget} with the specified target and {@link TargetingRule#CASCADE CASCADE} targeting. + */ + @NotNull + public static Target cascade(@Nullable Class target) { + return new Target(target, TargetingRule.CASCADE); + } + + /** + * Returns a {@code ClassTarget} with the specified target and {@link TargetingRule#REVERSE_CASCADE REVERSE_CASCADE} targeting. + * + * @param target the target class. + * @return a {@code ClassTarget} with the specified target and {@link TargetingRule#REVERSE_CASCADE REVERSE_CASCADE} targeting. + */ + @NotNull + public static Target reverseCascade(@Nullable Class target) { + return new Target(target, TargetingRule.REVERSE_CASCADE); + } + + /** + * Checks if the target class matches the given class according to the targeting rule. + * + * @param clazz the class to check. + * @return {@code true} if the class matches the target, {@code false} otherwise. + */ + public boolean targets(@NotNull Class clazz) { + if (this.clazz == null) { + return true; // Null target class will target anything + } + return rule.isMatch(clazz, this.clazz); + } + + /** + * Returns the target class. + * + * @return the target class, {@code null} if no target is set. + */ + @Nullable + public Class clazz() { + return clazz; + } + + /** + * Returns the targeting rule. + * + * @return the targeting rule. + */ + @NotNull + public TargetingRule rule() { + return rule; + } + + @Override + public String toString() { + return "ClassTarget{" + + "target=" + clazz + + ", matching=" + rule + + '}'; + } + + /** + * Enumeration of targeting rules. + */ + public enum TargetingRule { + /** + * The class must exactly equal the target class. + */ + FINE { + @Override + public boolean isMatch(Class clazz, Class target) { + return Objects.equals(clazz, target); + } + }, + /** + * The class must be a subclass or implementation of the target class. + */ + CASCADE { + @Override + public boolean isMatch(Class clazz, Class target) { + return target.isAssignableFrom(clazz); + } + }, + /** + * The target class must be a subclass or implementation of the given class. + */ + REVERSE_CASCADE { + @Override + public boolean isMatch(Class clazz, Class target) { + return clazz.isAssignableFrom(target); + } + }; + + public abstract boolean isMatch(Class clazz, Class target); + } +} \ No newline at end of file diff --git a/src/main/java/dev/tori/wraith/listener/EventListener.java b/src/main/java/dev/tori/wraith/listener/EventListener.java index a6eab4e..fa426e5 100644 --- a/src/main/java/dev/tori/wraith/listener/EventListener.java +++ b/src/main/java/dev/tori/wraith/listener/EventListener.java @@ -22,14 +22,15 @@ package dev.tori.wraith.listener; import dev.tori.wraith.bus.IEventBus; +import dev.tori.wraith.event.Target; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Objects; /** * An abstract base class for event listeners that implements the {@link Listener} interface. - * Event listeners provide event handling logic with specified priorities, target classes, and types. + * Event listeners provide event handling logic with specified targets and priorities. * * @param The type of event this listener is designed to handle. * @author 7orivorian @@ -39,71 +40,49 @@ */ public abstract class EventListener implements Listener { - protected final @NotNull Class target; - protected final @Nullable Class type; + @NotNull + protected final Target target; protected final int priority; protected final boolean indefinitePersistence; protected int persists; /** - * Constructs an event listener with default priority and no specified type. - * - * @param target The target class that this listener is designed to handle events for. - * @throws NullPointerException if {@code target} is {@code null}. - */ - public EventListener(@NotNull Class target) { - this(target, null, IEventBus.DEFAULT_PRIORITY, DEFAULT_PERSISTENCE); - } - - /** - * Constructs an event listener with a specified priority and no specified type. - * - * @param target The target class that this listener is designed to handle events for. - * @param priority The priority level of this listener for event handling. - * @throws NullPointerException if {@code target} is {@code null}. - */ - public EventListener(@NotNull Class target, int priority) { - this(target, null, priority, DEFAULT_PERSISTENCE); - } - - /** - * Constructs an event listener with default priority and a specified type. + * Constructs an event listener with default {@linkplain IEventBus#DEFAULT_PRIORITY priority} and {@linkplain #DEFAULT_PERSISTENCE persistence}. * - * @param target The target class that this listener is designed to handle events for. - * @param type The type of events that this listener can handle. Can be {@code null}. + * @param target This listener's {@linkplain Target target class}. * @throws NullPointerException if {@code target} is {@code null}. */ - public EventListener(@NotNull Class target, @Nullable Class type) { - this(target, type, IEventBus.DEFAULT_PRIORITY, DEFAULT_PERSISTENCE); + @Contract(pure = true) + public EventListener(@NotNull Target target) { + this(target, IEventBus.DEFAULT_PRIORITY, DEFAULT_PERSISTENCE); } /** - * Constructs an event listener with a specified priority and type. + * Constructs an event listener with a specified {@code priority} and {@linkplain #DEFAULT_PERSISTENCE default persistence}. * - * @param target The target class that this listener is designed to handle events for. + * @param target This listener's {@link Target}. * @param priority The priority level of this listener for event handling. - * @param type The type of events that this listener can handle. Can be {@code null}. * @throws NullPointerException if {@code target} is {@code null}. */ - public EventListener(@NotNull Class target, @Nullable Class type, int priority) { - this(target, type, priority, DEFAULT_PERSISTENCE); + @Contract(pure = true) + public EventListener(@NotNull Target target, int priority) { + this(target, priority, DEFAULT_PERSISTENCE); } /** - * Constructs an event listener with a specified priority and type. + * Constructs an event listener with a specified {@code priority} and {@code persists}. * - * @param target The target class that this listener is designed to handle events for. - * @param type The type of events that this listener can handle. Can be {@code null}. + * @param target This listener's {@link Target}. * @param priority The priority level of this listener for event handling. * @param persists How many events this listener should handle before being killed. - * A value {@code <= 0} will flag this listener to {@linkplain #indefinitePersistence persist indefinitely}. + * A value {@code <= 0} will {@linkplain #indefinitePersistence flag this listener to persist indefinitely}. * @throws NullPointerException if {@code target} is {@code null}. * @since 3.2.0 */ - public EventListener(@NotNull Class target, @Nullable Class type, int priority, int persists) { + @Contract(pure = true) + public EventListener(@NotNull Target target, int priority, int persists) { Objects.requireNonNull(target); this.target = target; - this.type = type; this.priority = priority; this.persists = persists; this.indefinitePersistence = persists <= 0; @@ -120,24 +99,13 @@ public int getPriority() { } /** - * Gets the type of events that this listener can handle. - * - * @return The type of events that this listener can handle, or {@code null} if no type is specified. - */ - @Nullable - @Override - public Class getType() { - return type; - } - - /** - * Gets the target class that this listener is designed to handle events for. + * Gets the {@link Target} of this listener. * - * @return The target class that this listener is designed to handle events for. + * @return The {@link Target} of this listener. */ @NotNull @Override - public Class getTarget() { + public Target getTarget() { return target; } @@ -147,7 +115,7 @@ public Class getTarget() { * or if the {@linkplain EventListener#persists internal persistence counter} is greater than zero * after being decremented. * - * @return {@code true} if the listener should persist, {@code false} otherwise + * @return {@code true} if the listener should persist, {@code false} otherwise. * @since 3.2.0 */ @Override @@ -159,7 +127,7 @@ public boolean shouldPersist() { * Indicates whether this listener is inherently persistent. * A listener is considered inherently persistent if the {@linkplain #indefinitePersistence} flag is set to {@code true}. * - * @return {@code true} if the listener is inherently persistent, {@code false} otherwise + * @return {@code true} if the listener is inherently persistent, {@code false} otherwise. * @since 3.2.0 */ @Override @@ -168,25 +136,24 @@ public boolean hasIndefinitePersistence() { } @Override - public boolean equals(Object o) { - if (this == o) { + @Contract(value = "null -> false", pure = true) + public boolean equals(Object obj) { + if (this == obj) { return true; } - if ((o == null) || (getClass() != o.getClass())) { + if ((obj == null) || (getClass() != obj.getClass())) { return false; } - EventListener that = (EventListener) o; + EventListener that = (EventListener) obj; return (priority == that.priority) && (indefinitePersistence == that.indefinitePersistence) - && target.equals(that.target) - && Objects.equals(type, that.type); + && target.equals(that.target); } @Override public int hashCode() { int result = target.hashCode(); - result = (31 * result) + Objects.hashCode(type); result = (31 * result) + priority; result = (31 * result) + Boolean.hashCode(indefinitePersistence); return result; @@ -196,7 +163,6 @@ public int hashCode() { public String toString() { return "EventListener{" + "target=" + target + - ", type=" + type + ", priority=" + priority + ", indefinitePersistence=" + indefinitePersistence + ", persists=" + persists + diff --git a/src/main/java/dev/tori/wraith/listener/LambdaEventListener.java b/src/main/java/dev/tori/wraith/listener/LambdaEventListener.java index 174a32d..0f1ce8a 100644 --- a/src/main/java/dev/tori/wraith/listener/LambdaEventListener.java +++ b/src/main/java/dev/tori/wraith/listener/LambdaEventListener.java @@ -21,8 +21,9 @@ package dev.tori.wraith.listener; +import dev.tori.wraith.event.Target; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Objects; @@ -31,82 +32,53 @@ * This provides a convenient way to create event listeners using lambda expressions. * * @param The type of event handled by this listener. - * @author 7orivorian - * @since 1.3.0 + * @author 7orivorian + * @since 1.3.0 */ public class LambdaEventListener extends EventListener { - protected final @NotNull Invokable invokable; + @NotNull + protected final Invokable invokable; /** - * Constructs a new `LambdaEventListener` with the given target class and invokable action. + * Constructs a new {@link LambdaEventListener} with the given target and invokable action. * - * @param target The target class of the event. + * @param target This listener's {@link Target}. * @param invokable The invokable action to be executed when the event is dispatched. * @throws NullPointerException if {@code target} is {@code null}. */ - public LambdaEventListener(@NotNull Class target, @NotNull Invokable invokable) { + public LambdaEventListener(@NotNull Target target, @NotNull Invokable invokable) { super(target); Objects.requireNonNull(invokable); this.invokable = invokable; } /** - * Constructs a new `LambdaEventListener` with the given target class, priority, and invokable action. + * Constructs a new {@link LambdaEventListener} with the given target, priority, and invokable action. * - * @param target The target class of the event. + * @param target This listener's {@link Target}. * @param priority The priority of this listener. * @param invokable The invokable action to be executed when the event is dispatched. * @throws NullPointerException if {@code target} is {@code null}. */ - public LambdaEventListener(@NotNull Class target, int priority, @NotNull Invokable invokable) { + public LambdaEventListener(@NotNull Target target, int priority, @NotNull Invokable invokable) { super(target, priority); Objects.requireNonNull(invokable); this.invokable = invokable; } /** - * Constructs a new `LambdaEventListener` with the given target class, type, and invokable action. + * Constructs a new {@link LambdaEventListener} with the given target, priority, and invokable action. * - * @param target The target class of the event. - * @param type The type of the event. - * @param invokable The invokable action to be executed when the event is dispatched. - * @throws NullPointerException if {@code target} is {@code null}. - */ - public LambdaEventListener(@NotNull Class target, @Nullable Class type, @NotNull Invokable invokable) { - super(target, type); - Objects.requireNonNull(invokable); - this.invokable = invokable; - } - - /** - * Constructs a new `LambdaEventListener` with the given target class, priority, type, and invokable action. - * - * @param target The target class of the event. - * @param priority The priority of this listener. - * @param type The type of the event. - * @param invokable The invokable action to be executed when the event is dispatched. - * @throws NullPointerException if {@code target} is {@code null}. - */ - public LambdaEventListener(@NotNull Class target, @Nullable Class type, int priority, @NotNull Invokable invokable) { - super(target, type, priority); - Objects.requireNonNull(invokable); - this.invokable = invokable; - } - - /** - * Constructs a new {@code LambdaEventListener} with the given target class, priority, type, and invokable action. - * - * @param target The target class of the event. - * @param type The type of the event. + * @param target This listener's {@link Target}. * @param priority The priority of this listener. * @param persists How many events this listener should handle before being killed. - * A value {@code <= 0} will flag this listener to {@linkplain #indefinitePersistence persist indefinitely}. + * A value of {@code <= 0} will flag this listener to {@linkplain #indefinitePersistence persist indefinitely}. * @param invokable The invokable action to be executed when the event is dispatched. * @throws NullPointerException if {@code target} is {@code null}. */ - public LambdaEventListener(@NotNull Class target, @Nullable Class type, int priority, int persists, @NotNull Invokable invokable) { - super(target, type, priority, persists); + public LambdaEventListener(@NotNull Target target, int priority, int persists, @NotNull Invokable invokable) { + super(target, priority, persists); Objects.requireNonNull(invokable); this.invokable = invokable; } @@ -122,18 +94,19 @@ public void invoke(E event) { } @Override - public boolean equals(Object o) { - if (this == o) { + @Contract(value = "null -> false", pure = true) + public boolean equals(Object obj) { + if (this == obj) { return true; } - if ((o == null) || (getClass() != o.getClass())) { + if ((obj == null) || (getClass() != obj.getClass())) { return false; } - if (!super.equals(o)) { + if (!super.equals(obj)) { return false; } - LambdaEventListener that = (LambdaEventListener) o; + LambdaEventListener that = (LambdaEventListener) obj; return invokable.equals(that.invokable); } @@ -148,7 +121,6 @@ public int hashCode() { public String toString() { return "LambdaEventListener{" + "target=" + target + - ", type=" + type + ", priority=" + priority + ", indefinitePersistence=" + indefinitePersistence + ", persists=" + persists + diff --git a/src/main/java/dev/tori/wraith/listener/Listener.java b/src/main/java/dev/tori/wraith/listener/Listener.java index 3e418cc..c9b8fc8 100644 --- a/src/main/java/dev/tori/wraith/listener/Listener.java +++ b/src/main/java/dev/tori/wraith/listener/Listener.java @@ -22,19 +22,20 @@ package dev.tori.wraith.listener; import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.Target; +import dev.tori.wraith.util.IndexedHashSet; +import org.jetbrains.annotations.NotNull; -import java.util.List; -import java.util.function.Consumer; import java.util.function.Predicate; /** * An interface representing an event listener with priority, type, and target class information. * * @param The type of event this listener is designed to handle. - * @author 7orivorian + * @author 7orivorian * @see EventListener * @see Invokable - * @since 1.0.0 + * @since 1.0.0 */ public interface Listener extends Invokable { @@ -48,24 +49,19 @@ public interface Listener extends Invokable { int getPriority(); /** - * Gets the type of events that this listener can handle. + * Gets the {@linkplain Target target class} of this listener. * - * @return The type of events that this listener can handle, or {@code null} if no type is specified. + * @return the {@linkplain Target target class} of this listener. + * @since 4.0.0 */ - Class getType(); - - /** - * Gets the target class that this listener is designed to handle events for. - * - * @return The target class that this listener is designed to handle events for. - */ - Class getTarget(); + @NotNull + Target getTarget(); /** * Determines whether this listener should persist after being invoked. * * @return {@code true} if the listener should persist, {@code false} otherwise. - * @see EventBus#forEachListener(List, Predicate, Consumer, boolean) + * @see EventBus#dispatchToEachListener(Object, IndexedHashSet, Predicate, boolean) * @since 3.2.0 */ @SuppressWarnings("JavadocReference") @@ -82,23 +78,4 @@ default boolean shouldPersist() { default boolean hasIndefinitePersistence() { return true; } - - /** - * Checks if the provided type is acceptable for this listener. - *

- * This default method evaluates whether the given type is acceptable by comparing it with - * the type associated with this listener. It returns {@code true} if any of the following conditions are met: - *

- * - * @param type the class type to check for acceptability - * @return {@code true} if the type is acceptable, {@code false} otherwise. - * @since 3.3.0 - */ - default boolean isAcceptableType(Class type) { - return (type == null) || (getType() == null) || (getType() == type); - } } \ No newline at end of file diff --git a/src/main/java/dev/tori/wraith/listener/ListenerBuilder.java b/src/main/java/dev/tori/wraith/listener/ListenerBuilder.java index edb7bf9..356dabd 100644 --- a/src/main/java/dev/tori/wraith/listener/ListenerBuilder.java +++ b/src/main/java/dev/tori/wraith/listener/ListenerBuilder.java @@ -22,8 +22,8 @@ package dev.tori.wraith.listener; import dev.tori.wraith.bus.IEventBus; +import dev.tori.wraith.event.Target; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Objects; @@ -37,8 +37,7 @@ *
  * {@code
  * EventListener listener = new ListenerBuilder<>()
- *     .target(MyEvent.class)
- *     .type(SomeSpecificType.class)
+ *     .target(ClassTarget.fine(MyEvent.class))
  *     .priority(5)
  *     .persists(10)
  *     .invokable(event -> handleEvent(event))
@@ -53,40 +52,28 @@
  */
 public class ListenerBuilder {
 
-    private Class target = null;
-    private @Nullable Class type = null;
+    private Target target = null;
     private int priority = IEventBus.DEFAULT_PRIORITY;
     private int persists = -1;
     private boolean persistent = true;
     private Invokable invokable = null;
 
     /**
-     * Sets the target class for this listener.
+     * Sets the {@link Target} for this listener.
      *
-     * @param target the class of the event this listener will handle
-     * @return this {@code ListenerBuilder} instance
+     * @param target This listener's {@link Target}.
+     * @return this {@code ListenerBuilder} instance.
      */
-    public ListenerBuilder target(@NotNull Class target) {
+    public ListenerBuilder target(@NotNull Target target) {
         this.target = target;
         return this;
     }
 
-    /**
-     * Sets the specific type for this listener.
-     *
-     * @param type the specific type of event this listener will handle
-     * @return this {@code ListenerBuilder} instance
-     */
-    public ListenerBuilder type(@Nullable Class type) {
-        this.type = type;
-        return this;
-    }
-
     /**
      * Sets the priority for this listener.
      *
-     * @param priority the priority of the listener
-     * @return this {@code ListenerBuilder} instance
+     * @param priority the priority of the listener.
+     * @return this {@code ListenerBuilder} instance.
      */
     public ListenerBuilder priority(int priority) {
         this.priority = priority;
@@ -98,8 +85,8 @@ public ListenerBuilder priority(int priority) {
      * 

* Overrides {@link #persistent}. * - * @param persists the number of events this listener should handle before being removed - * @return this {@code ListenerBuilder} instance + * @param persists the number of events this listener should handle before being removed. + * @return this {@code ListenerBuilder} instance. */ public ListenerBuilder persists(int persists) { this.persists = persists; @@ -112,8 +99,8 @@ public ListenerBuilder persists(int persists) { *

* Overrides {@link #persists}. * - * @param persistent {@code true} if the listener should be persistent, {@code false} otherwise - * @return this {@code ListenerBuilder} instance + * @param persistent {@code true} if the listener should be persistent, {@code false} otherwise. + * @return this {@code ListenerBuilder} instance. */ public ListenerBuilder persistent(boolean persistent) { this.persistent = persistent; @@ -127,7 +114,7 @@ public ListenerBuilder persistent(boolean persistent) { * Sets the invokable action for this listener. * * @param invokable the action to be invoked when an event is handled - * @return this {@code ListenerBuilder} instance + * @return this {@code ListenerBuilder} instance. */ public ListenerBuilder invokable(@NotNull Invokable invokable) { this.invokable = invokable; @@ -137,9 +124,9 @@ public ListenerBuilder invokable(@NotNull Invokable invokable) { /** * Builds and returns an {@link EventListener} with the configured properties. * - * @return a new {@link EventListener} instance - * @throws NullPointerException if the target or invokable is not set - * @throws IllegalArgumentException if there is a mismatch between persistence settings + * @return a new {@link EventListener} instance. + * @throws NullPointerException if the target or invokable is not set. + * @throws IllegalArgumentException if there is a mismatch between persistence settings. */ @NotNull public EventListener build() { @@ -150,7 +137,7 @@ public EventListener build() { "Persistency missmatch. persistent=" + persistent + " and persists=" + persists + " is not allowed." ); } - return new EventListener<>(target, type, priority, persists) { + return new EventListener<>(target, priority, persists) { @Override public void invoke(T event) { invokable.invoke(event); diff --git a/src/main/test/dev/tori/wraith/Main.java b/src/main/test/dev/tori/wraith/Main.java index 99fcf5b..82f22b8 100644 --- a/src/main/test/dev/tori/wraith/Main.java +++ b/src/main/test/dev/tori/wraith/Main.java @@ -21,9 +21,8 @@ package dev.tori.wraith; -import dev.tori.wraith.event.targeted.IClassTargetingEvent; -import dev.tori.wraith.listener.Listener; -import org.jetbrains.annotations.Nullable; +import dev.tori.wraith.event.Target; +import dev.tori.wraith.listener.EventListener; /** * @author 7orivorian @@ -32,39 +31,105 @@ public class Main { public static void main(String[] args) { + /*Target target = Target.reverseCascade(null); + System.out.println(target.targets(ParentListenerOne.class)); + System.out.println(target.targets(ParentListenerOne.NestedListenerOne.class)); + System.out.println(target.targets(ParentListenerOne.NestedListenerOther.class)); + System.out.println(target.targets(ParentListenerOne.NestedListenerOne.DoubleNestedListenerOne.class)); + + System.out.println(target.targets(ParentListenerTwo.class)); + System.out.println(target.targets(ParentListenerTwo.NestedListenerTwo.class));*/ + + Target target = Target.cascade(Object.class); + System.out.println(target.targets(Event.class)); + +/* final EventBus bus = new EventBus(); + bus.subscribe(new Subscriber() {{ + registerListeners( + new ParentListenerOne(), + new ParentListenerOne.NestedListenerOne(), + new ParentListenerOne.NestedListenerOne.DoubleNestedListenerOne(), + new ParentListenerOne.NestedListenerOther(), + new ParentListenerTwo(), + new ParentListenerTwo.NestedListenerTwo() + ); + }}); + + Event event = new Event(); + bus.dispatch(event); + System.out.println(event); + + Event.NestedEvent nestedEvent = new Event.NestedEvent(); + bus.dispatch(nestedEvent); + System.out.println(nestedEvent);*/ } - public class Event implements IClassTargetingEvent { + static class ParentListenerOne extends EventListener { - @Nullable - private final Class> target; + public ParentListenerOne() { + super(Target.cascade(Event.class)); + } - public Event(@Nullable Class> target) { - this.target = target; + @Override + public void invoke(Event event) { + event.mod(); + } + + static class NestedListenerOne extends ParentListenerOne { + + static class DoubleNestedListenerOne extends NestedListenerOne { + + } + } + + static class NestedListenerOther extends EventListener { + + public NestedListenerOther() { + super(Target.fine(Event.class)); + } + + @Override + public void invoke(Event event) { + event.mod(); + } + } + } + + static class ParentListenerTwo extends EventListener { + + public ParentListenerTwo() { + super(Target.fine(Event.class)); } - @Nullable @Override - public Class> getTargetClass() { - return target; + public void invoke(Event event) { + event.mod(); + } + + static class NestedListenerTwo extends ParentListenerTwo { + } } - static final class MessageEvent { + static class Event { - private String message; + private int mods = 0; - public MessageEvent() { - this.message = "nothing to say"; + public void mod() { + this.mods++; } - public String getMessage() { - return message; + @Override + public String toString() { + return "mods=" + mods; } - public void setMessage(String message) { - this.message = message; + static class NestedEvent extends Event { + + static class DoubleNestedEvent extends NestedEvent { + + } } } } \ No newline at end of file diff --git a/src/main/test/dev/tori/wraith/MainTwo.java b/src/main/test/dev/tori/wraith/MainTwo.java new file mode 100644 index 0000000..712f180 --- /dev/null +++ b/src/main/test/dev/tori/wraith/MainTwo.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2024 7orivorian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package dev.tori.wraith; + +import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.Target; +import dev.tori.wraith.event.targeted.ClassTargetingEvent; +import dev.tori.wraith.listener.EventListener; +import dev.tori.wraith.listener.Listener; +import dev.tori.wraith.subscriber.Subscriber; + +/** + * @author 7orivorian + * @since 4.0.0 + */ +public class MainTwo { + + public static void main(String[] args) { + final EventBus bus = new EventBus(); + bus.subscribe(new Subscriber() {{ + registerListeners( + new ListenerOne(), + new ListenerTwo() + ); + }}); + + TestEvent event = new TestEvent(null); + + bus.dispatch(event); + + System.out.println(event); + } + + static class ListenerOne extends EventListener { + + public ListenerOne() { + super(Target.fine(TestEvent.class)); + } + + @Override + public void invoke(TestEvent event) { + event.mod(); + } + } + + static class ListenerTwo extends EventListener { + + public ListenerTwo() { + super(Target.fine(TestEvent.class)); + } + + @Override + public void invoke(TestEvent event) { + event.mod(); + } + } + + static class TestEvent extends ClassTargetingEvent { + + private int mods = 0; + + public TestEvent(Class> target) { + super(target); + } + + public void mod() { + this.mods++; + } + + @Override + public String toString() { + return "mods=" + mods; + } + } +} \ No newline at end of file diff --git a/src/main/test/dev/tori/wraith/benchmarking/MyBenchmark.java b/src/main/test/dev/tori/wraith/benchmarking/MyBenchmark.java index 9b2ccf0..0f2511e 100644 --- a/src/main/test/dev/tori/wraith/benchmarking/MyBenchmark.java +++ b/src/main/test/dev/tori/wraith/benchmarking/MyBenchmark.java @@ -22,6 +22,7 @@ package dev.tori.wraith.benchmarking; import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.Target; import dev.tori.wraith.listener.EventListener; import dev.tori.wraith.subscriber.Subscriber; import org.openjdk.jmh.annotations.*; @@ -72,7 +73,7 @@ public MySubscriber() { public static class MyListener extends EventListener { public MyListener() { - super(MyEvent.class); + super(Target.fine(MyEvent.class)); } @Override diff --git a/src/main/test/dev/tori/wraith/persistency/PersistencyTest.java b/src/main/test/dev/tori/wraith/persistency/PersistencyTest.java index 13fefed..2513c07 100644 --- a/src/main/test/dev/tori/wraith/persistency/PersistencyTest.java +++ b/src/main/test/dev/tori/wraith/persistency/PersistencyTest.java @@ -22,6 +22,7 @@ package dev.tori.wraith.persistency; import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.Target; import dev.tori.wraith.event.status.StatusEvent; import dev.tori.wraith.listener.EventListener; import dev.tori.wraith.subscriber.Subscriber; @@ -65,7 +66,7 @@ public void testIndefiniteEvent() { static class MyListener extends EventListener { public MyListener(int persists) { - super(MyEvent.class, null, 0, persists); + super(Target.fine(MyEvent.class), 0, persists); } @Override diff --git a/src/main/test/dev/tori/wraith/priority/PriorityTest.java b/src/main/test/dev/tori/wraith/priority/PriorityTest.java index 71efd95..52d1588 100644 --- a/src/main/test/dev/tori/wraith/priority/PriorityTest.java +++ b/src/main/test/dev/tori/wraith/priority/PriorityTest.java @@ -22,6 +22,7 @@ package dev.tori.wraith.priority; import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.Target; import dev.tori.wraith.event.status.StatusEvent; import dev.tori.wraith.listener.LambdaEventListener; import dev.tori.wraith.subscriber.Subscriber; @@ -38,15 +39,15 @@ public class PriorityTest { public void testPriority() { final EventBus bus = new EventBus(); bus.subscribe(new Subscriber() {{ - registerListener(new LambdaEventListener<>(MyEvent.class, 5, event -> event.setFlag(true))); - registerListener(new LambdaEventListener<>(MyEvent.class, 4, event -> { + registerListener(new LambdaEventListener(Target.fine(MyEvent.class), 5, event -> event.setFlag(true))); + registerListener(new LambdaEventListener(Target.fine(MyEvent.class), 4, event -> { event.setFlag(false); event.terminate(); })); - registerListener(new LambdaEventListener<>(MyEvent.class, 3, event -> event.setFlag(true))); - registerListener(new LambdaEventListener<>(MyEvent.class, 2, event -> event.setFlag(true))); - registerListener(new LambdaEventListener<>(MyEvent.class, 1, event -> event.setFlag(true))); - registerListener(new LambdaEventListener<>(MyEvent.class, 0, event -> event.setFlag(true))); + registerListener(new LambdaEventListener(Target.fine(MyEvent.class), 3, event -> event.setFlag(true))); + registerListener(new LambdaEventListener(Target.fine(MyEvent.class), 2, event -> event.setFlag(true))); + registerListener(new LambdaEventListener(Target.fine(MyEvent.class), 1, event -> event.setFlag(true))); + registerListener(new LambdaEventListener(Target.fine(MyEvent.class), 0, event -> event.setFlag(true))); }}); MyEvent event = new MyEvent(); diff --git a/src/main/test/dev/tori/wraith/registration/RegistrationTest.java b/src/main/test/dev/tori/wraith/registration/RegistrationTest.java index 3f7bb1a..219bf42 100644 --- a/src/main/test/dev/tori/wraith/registration/RegistrationTest.java +++ b/src/main/test/dev/tori/wraith/registration/RegistrationTest.java @@ -22,6 +22,7 @@ package dev.tori.wraith.registration; import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.Target; import dev.tori.wraith.event.status.IStatusEvent; import dev.tori.wraith.event.status.StatusEvent; import dev.tori.wraith.listener.LambdaEventListener; @@ -38,8 +39,8 @@ public class RegistrationTest { @Test public void testResistration() { final EventBus bus = new EventBus(); - final LambdaEventListener listener = new LambdaEventListener<>( - StatusEvent.class, + final LambdaEventListener listener = new LambdaEventListener( + Target.fine(StatusEvent.class), IStatusEvent::terminate ); @@ -54,7 +55,7 @@ public void testResistration() { public void testSubscription() { final EventBus bus = new EventBus(); final Subscriber subscriber = new Subscriber() {{ - registerListener(new LambdaEventListener<>(StatusEvent.class, IStatusEvent::terminate)); + registerListener(new LambdaEventListener(Target.fine(StatusEvent.class), IStatusEvent::terminate)); }}; bus.subscribe(subscriber); @@ -73,7 +74,7 @@ public void testLateSubscription() { bus.subscribe(subscriber); - subscriber.registerListener(new LambdaEventListener<>(MyEvent.class, event -> event.setMessage(expectedMessage))); + subscriber.registerListener(new LambdaEventListener(Target.fine(MyEvent.class), event -> event.setMessage(expectedMessage))); MyEvent event = new MyEvent(null); bus.dispatch(event); @@ -82,6 +83,7 @@ public void testLateSubscription() { } static final class MyEvent { + private String message; MyEvent(String message) { diff --git a/src/main/test/dev/tori/wraith/statusevent/StatusEventTest.java b/src/main/test/dev/tori/wraith/statusevent/StatusEventTest.java index 0c1bb6c..55b0533 100644 --- a/src/main/test/dev/tori/wraith/statusevent/StatusEventTest.java +++ b/src/main/test/dev/tori/wraith/statusevent/StatusEventTest.java @@ -22,6 +22,7 @@ package dev.tori.wraith.statusevent; import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.event.Target; import dev.tori.wraith.event.status.StatusEvent; import dev.tori.wraith.listener.LambdaEventListener; import dev.tori.wraith.subscriber.Subscriber; @@ -40,11 +41,11 @@ public void testSupression() { MySubscriber subscriber = new MySubscriber() {{ registerListeners( - new LambdaEventListener<>(StatusEvent.class, 1, event -> { + new LambdaEventListener(Target.fine(StatusEvent.class), 1, event -> { this.counter = 1; event.suppress(); }), - new LambdaEventListener<>(StatusEvent.class, 0, event -> { + new LambdaEventListener(Target.fine(StatusEvent.class), 0, event -> { this.counter++; }) ); @@ -61,11 +62,11 @@ public void testTermination() { MySubscriber subscriber = new MySubscriber() {{ registerListeners( - new LambdaEventListener<>(StatusEvent.class, 1, event -> { + new LambdaEventListener(Target.fine(StatusEvent.class), 1, event -> { this.counter = 1; event.terminate(); }), - new LambdaEventListener<>(StatusEvent.class, 0, event -> { + new LambdaEventListener(Target.fine(StatusEvent.class), 0, event -> { this.counter = 1_000; }) ); diff --git a/src/main/test/dev/tori/wraith/targetedevent/TargetedEventTest.java b/src/main/test/dev/tori/wraith/targetedevent/TargetedEventTest.java deleted file mode 100644 index 9dfe183..0000000 --- a/src/main/test/dev/tori/wraith/targetedevent/TargetedEventTest.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2021-2024 7orivorian. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package dev.tori.wraith.targetedevent; - -import dev.tori.wraith.bus.EventBus; -import dev.tori.wraith.event.status.StatusEvent; -import dev.tori.wraith.event.targeted.IClassTargetingEvent; -import dev.tori.wraith.listener.EventListener; -import dev.tori.wraith.listener.Listener; -import dev.tori.wraith.subscriber.Subscriber; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -/** - * @author 7orivorian - */ -public class TargetedEventTest { - - @Test - public void testTargetedEventWithLowerPriority() { - final EventBus bus = new EventBus(); - - bus.subscribe(new Subscriber() {{ - registerListeners( - new MyListener(0), - new OtherListener(1) - ); - }}); - - TestEvent event = new TestEvent(MyListener.class); - assertFalse(bus.dispatch(event)); - } - - @Test - public void testTargetedEventWithHigherPriority() { - final EventBus bus = new EventBus(); - - bus.subscribe(new Subscriber() {{ - registerListeners( - new MyListener(1), - new OtherListener(0) - ); - }}); - - TestEvent event = new TestEvent(MyListener.class); - assertFalse(bus.dispatch(event)); - } - - @Test - public void testNestedClassTargetNestedListener() { - final EventBus bus = new EventBus(); - - bus.subscribe(new Subscriber() {{ - registerListeners( - new MyParentListener.MyNestedListener(0) - ); - }}); - - TestEvent event = new TestEvent(MyParentListener.MyNestedListener.class); - bus.dispatch(event); - - // Dispatched to nested target - assertEquals(2, event.getValue()); - } - - @Test - public void parentListenerNestedTarget() { - final EventBus bus = new EventBus(); - - bus.subscribe(new Subscriber() {{ - registerListeners( - new MyParentListener(0) - ); - }}); - - TestEvent event = new TestEvent(MyParentListener.MyNestedListener.class); - bus.dispatch(event); - - // Not dispatched to parent of nested target - assertEquals(0, event.getValue()); - } - - @Test - public void testParentOfNestedClassTarget() { - final EventBus bus = new EventBus(); - - bus.subscribe(new Subscriber() {{ - registerListeners( - new MyParentListener.MyNestedListener(0) - ); - }}); - - TestEvent event = new TestEvent(MyParentListener.class); - bus.dispatch(event); - - // Dispatched to nested listener if the parent is targeted - assertEquals(2, event.getValue()); - } - - static class MyListener extends EventListener { - - public MyListener(int priority) { - super(TestEvent.class, priority); - } - - @Override - public void invoke(TestEvent event) { - event.setSuppressed(false); - } - } - - static class OtherListener extends EventListener { - - public OtherListener(int priority) { - super(TestEvent.class, priority); - } - - @Override - public void invoke(TestEvent event) { - event.suppress(); - } - } - - static class MyParentListener extends EventListener { - - public MyParentListener(int priority) { - super(TestEvent.class, priority); - } - - @Override - public void invoke(TestEvent event) { - event.setValue(1); - } - - static class MyNestedListener extends MyParentListener { - - public MyNestedListener(int priority) { - super(priority); - } - - @Override - public void invoke(TestEvent event) { - event.setValue(2); - } - } - } - - static class TestEvent extends StatusEvent implements IClassTargetingEvent { - - private final Class> targetClass; - private int value; - - public TestEvent(Class> target) { - this.targetClass = target; - this.value = 0; - } - - @Override - public Class> getTargetClass() { - return targetClass; - } - - public int getValue() { - return value; - } - - public void setValue(int value) { - this.value = value; - } - } -} \ No newline at end of file From 148350aa2c5c8e13dbd3b8aabf0edc657475ba94 Mon Sep 17 00:00:00 2001 From: Tori <7orivorian+github@gmail.com> Date: Tue, 30 Jul 2024 22:04:25 -0400 Subject: [PATCH 16/30] Update IndexedHashSet Signed-off-by: Tori <7orivorian+github@gmail.com> --- .../java/dev/tori/wraith/util/IndexedHashSet.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/dev/tori/wraith/util/IndexedHashSet.java b/src/main/java/dev/tori/wraith/util/IndexedHashSet.java index d8a5c09..0b34ae8 100644 --- a/src/main/java/dev/tori/wraith/util/IndexedHashSet.java +++ b/src/main/java/dev/tori/wraith/util/IndexedHashSet.java @@ -21,10 +21,10 @@ package dev.tori.wraith.util; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Objects; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.util.*; import java.util.function.Predicate; /** @@ -91,6 +91,7 @@ public boolean removeIf(Predicate filter) { } @Override + @Contract(pure = true) @SuppressWarnings("SuspiciousMethodCalls") public boolean contains(Object element) { return map.containsKey(element); @@ -102,8 +103,8 @@ public void clear() { map.clear(); } - public ArrayList asList() { - return new ArrayList<>(this); + public List immutableList() { + return Collections.unmodifiableList(this); } private void rangeCheckForAdd(int index) { @@ -112,6 +113,8 @@ private void rangeCheckForAdd(int index) { } } + @NotNull + @Contract(pure = true) private String outOfBoundsMsg(int index) { return "Index: " + index + ", Size: " + size(); } From cd9bb35cdf786c61a2b0a9249b14218a6eb40429 Mon Sep 17 00:00:00 2001 From: Tori <7orivorian+github@gmail.com> Date: Tue, 30 Jul 2024 22:48:32 -0400 Subject: [PATCH 17/30] Update PersistenceTest Signed-off-by: Tori <7orivorian+github@gmail.com> --- ...rsistencyTest.java => PersistenceTest.java} | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) rename src/main/test/dev/tori/wraith/persistency/{PersistencyTest.java => PersistenceTest.java} (85%) diff --git a/src/main/test/dev/tori/wraith/persistency/PersistencyTest.java b/src/main/test/dev/tori/wraith/persistency/PersistenceTest.java similarity index 85% rename from src/main/test/dev/tori/wraith/persistency/PersistencyTest.java rename to src/main/test/dev/tori/wraith/persistency/PersistenceTest.java index 2513c07..696dd57 100644 --- a/src/main/test/dev/tori/wraith/persistency/PersistencyTest.java +++ b/src/main/test/dev/tori/wraith/persistency/PersistenceTest.java @@ -29,29 +29,33 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.util.concurrent.ThreadLocalRandom; + /** * @author 7orivorian * @since 3.2.0 */ -public class PersistencyTest { +public class PersistenceTest { @Test - public void testEventPersistency() { + public void testRandomPersistence() { final EventBus bus = new EventBus(); + final int persists = ThreadLocalRandom.current().nextInt(1, 101); + bus.subscribe(new Subscriber() {{ - registerListener(new MyListener(3)); + registerListener(new MyListener(persists)); }}); - Assertions.assertTrue(bus.dispatch(new MyEvent())); - Assertions.assertTrue(bus.dispatch(new MyEvent())); - Assertions.assertTrue(bus.dispatch(new MyEvent())); + for (int i = 0; i < persists; i++) { + Assertions.assertTrue(bus.dispatch(new MyEvent())); + } Assertions.assertFalse(bus.dispatch(new MyEvent())); } @Test - public void testIndefiniteEvent() { + public void testIndefinitePersistence() { final EventBus bus = new EventBus(); bus.subscribe(new Subscriber() {{ From 786cdeae74e6d9abd1635c2920d79cb3b230b39e Mon Sep 17 00:00:00 2001 From: Tori <7orivorian+github@gmail.com> Date: Wed, 31 Jul 2024 00:31:12 -0400 Subject: [PATCH 18/30] Abstracted event bus implementations Signed-off-by: Tori <7orivorian+github@gmail.com> --- .../dev/tori/wraith/bus/AbstractEventBus.java | 342 ++++++++++++++++++ .../java/dev/tori/wraith/bus/EventBus.java | 269 +------------- .../dev/tori/wraith/bus/OpenEventBus.java | 133 +++++++ .../java/dev/tori/wraith/event/Target.java | 96 +++-- .../dev/tori/wraith/listener/Listener.java | 12 +- 5 files changed, 552 insertions(+), 300 deletions(-) create mode 100644 src/main/java/dev/tori/wraith/bus/AbstractEventBus.java create mode 100644 src/main/java/dev/tori/wraith/bus/OpenEventBus.java diff --git a/src/main/java/dev/tori/wraith/bus/AbstractEventBus.java b/src/main/java/dev/tori/wraith/bus/AbstractEventBus.java new file mode 100644 index 0000000..1a326d5 --- /dev/null +++ b/src/main/java/dev/tori/wraith/bus/AbstractEventBus.java @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2021-2024 7orivorian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package dev.tori.wraith.bus; + +import dev.tori.wraith.event.Target; +import dev.tori.wraith.event.status.IStatusEvent; +import dev.tori.wraith.listener.Listener; +import dev.tori.wraith.subscriber.ISubscriber; +import dev.tori.wraith.task.ScheduledTask; +import dev.tori.wraith.task.TaskExecutor; +import dev.tori.wraith.util.IndexedHashSet; +import org.jetbrains.annotations.Contract; + +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Predicate; + +/** + * Abstract implementation of {@link IEventBus}. + *

+ * Manages subscription and task scheduling. + * + * @author 7orivorian + * @since 4.0.0 + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +public abstract class AbstractEventBus implements IEventBus { + + /** + * The amount of {@linkplain AbstractEventBus} instances that have been created + */ + private static int instances = 0; + + /** + * This event bus's id + */ + protected final int id; + /** + * Indicates whether this event bus is shutdown. + *

Shut-down event dispatchers cannot dispatch events, and throw {@link UnsupportedOperationException} when + * attempting to do so + */ + protected boolean shutdown; + /** + * A {@link Set} of this event bus' {@link ISubscriber subscribers} + */ + protected final Set subscribers; + /** + * A {@link TaskExecutor} that manages the scheduling and execution of tasks associated with events. It provides + * a mechanism to associate event classes with queues of tasks and ensures their orderly execution when the + * corresponding events are dispatched. + * + * @see #scheduleTask(ScheduledTask) + */ + protected final TaskExecutor taskExecutor; + + /** + * Creates a new event bus instance + */ + public AbstractEventBus() { + this.id = instances++; + this.shutdown = false; + this.subscribers = Collections.newSetFromMap(new ConcurrentHashMap<>()); + this.taskExecutor = new TaskExecutor(); + } + + /** + * @return The amount of {@linkplain AbstractEventBus} instances that have been created. + */ + @Contract(pure = true) + public static int getInstanceCount() { + return instances; + } + + /** + * Subscribes a {@link ISubscriber subscriber} to this event bus and registers all the + * subscriber's {@link Listener listeners} + * + * @param subscriber the {@link ISubscriber} to be subscribed + * @throws NullPointerException if the given {@link ISubscriber} is {@code null} + * @see #register(Listener) + */ + @Override + public void subscribe(ISubscriber subscriber) { + Objects.requireNonNull(subscriber, "Cannot subscribe null to event bus " + id + "!"); + + subscribers.add(subscriber); + subscriber.linkToBus(this); + + Collection> listeners = subscriber.getListeners(); + if (!listeners.isEmpty()) { + if (listeners.size() == 1) { + register(listeners.iterator().next()); + } else { + for (Listener listener : listeners) { + register(listener); + } + } + } + } + + /** + * Unsubscribes a {@link ISubscriber subscriber} from this event bus and unregisters all the + * subscriber's {@link Listener listeners} + * + * @param subscriber the {@link ISubscriber} to be unsubscribed + * @throws NullPointerException if the given {@link ISubscriber} is {@code null} + * @see #unregister(Listener) + */ + @Override + public void unsubscribe(ISubscriber subscriber) { + Objects.requireNonNull(subscriber, "Cannot unsubscribe null from event bus " + id + "!"); + + subscribers.remove(subscriber); + subscriber.unlinkFromBus(this); + + Collection> listeners = subscriber.getListeners(); + if (!listeners.isEmpty()) { + if (listeners.size() == 1) { + unregister(listeners.iterator().next()); + } else { + for (Listener listener : listeners) { + unregister(listener); + } + } + } + } + + /** + * Registers a {@link Listener listener} to this event bus + * + * @param listener the {@link Listener} to be registered + * @throws NullPointerException if the given {@link Listener} is {@code null} + */ + @Override + public abstract void register(Listener listener); + + /** + * Unregisters a {@link Listener listener} from this event bus. A listener will no longer be invoked by events dispatched by this event bus + * + * @param listener the {@link Listener} to be unregistered + * @throws NullPointerException if the given {@link Listener} is {@code null} + */ + @Override + public abstract void unregister(Listener listener); + + /** + * Convenience method to dispatch an event with no {@linkplain Target target listener}, and + * normal processing priority. + * + * @see #dispatch(Object, Target, boolean) + */ + @Override + public boolean dispatch(Object event) { + return dispatch(event, Target.all(), false); + } + + /** + * Convenience method to dispatch an event with an optional {@linkplain Target target listener} and + * normal processing priority. + * + * @see #dispatch(Object, Target, boolean) + */ + @Override + public boolean dispatch(Object event, Target target) { + return dispatch(event, target, false); + } + + /** + * Convenience method to dispatch an event with a universal {@linkplain Target target listener} and + * optional inverted processing priority. + * + * @see #dispatch(Object, Target, boolean) + */ + @Override + public boolean dispatch(Object event, boolean invertPriority) { + return dispatch(event, Target.all(), invertPriority); + } + + /** + * Dispatches the given event to all valid registered listeners. + *

+ * The {@code type} parameter serves as a filtering mechanism for listeners, enabling you to selectively invoke + * listeners based on their type, allowing for more targeted event handling. + * + * @param event the event to be dispatched. + * @param target the {@linkplain Target target listener} to invoke. + * @param invertPriority flag to dispatch the event in inverse listener priority. + * @return {@code true} if the given event is {@linkplain IStatusEvent suppressed or terminated} by any listener, + * {@code false} otherwise. + * @throws NullPointerException if the given event is {@code null} + * @throws UnsupportedOperationException if this event bus is {@link #shutdown} + */ + @Override + public abstract boolean dispatch(Object event, Target target, boolean invertPriority); + + /** + * Schedules a task to be executed. + * + * @param task The task to be executed. + * @see TaskExecutor#schedule(ScheduledTask) + * @see ScheduledTask + */ + public void scheduleTask(ScheduledTask task) { + taskExecutor.schedule(task); + } + + /** + * Clears all tasks associated with events from the underlying {@link #taskExecutor}, effectively + * resetting the task scheduling within this {@link AbstractEventBus}. + * + * @see TaskExecutor#clear() + */ + public void clearTaskExecutor() { + taskExecutor.clear(); + } + + /** + * Logs a warning message and shuts down this event bus, preventing future events from being dispatched. + * + * @implNote Shut-down event dispatchers cannot dispatch events, and throw {@link UnsupportedOperationException} + * when attempting to do so. + */ + @Override + public void shutdown() { + shutdown = true; + } + + /** + * @return {@code true} if this event bus is shut down + * @implNote Shut-down event dispatchers cannot dispatch events, and throw {@link UnsupportedOperationException} + * when attempting to do so. + */ + @Override + public boolean isShutdown() { + return shutdown; + } + + /** + * @return the {@code id} of this event bus + */ + public int getId() { + return id; + } + + /** + * Applies a given action to each {@linkplain Listener} in a list that matches a specified predicate. + * Listeners are processed either in normal order or in reverse order based on the + * {@code invertPriority} flag. + * Listeners that should not persist are removed from the list after the action is applied. + * + * @param event the event to be handled by each listener that satisfies the predicate + * @param listeners the list of listeners to be processed + * @param predicate the condition that each listener must satisfy to have the action applied + * @param invertPriority if {@code true}, listeners are processed in order of inverse priority; otherwise, + * they are processed in normal order + */ + @SuppressWarnings("DuplicatedCode") + protected final void dispatchToEachListener(Object event, IndexedHashSet listeners, Predicate predicate, boolean invertPriority) { + if ((listeners != null) && !listeners.isEmpty()) { + if (invertPriority) { + for (int i = listeners.size() - 1; i >= 0; i--) { + Listener listener = listeners.get(i); + if (!predicate.test(listener)) { + continue; + } + listener.invoke(event); + if ((event instanceof IStatusEvent e) && e.isTerminated()) { + break; + } + if (!listener.shouldPersist()) { + listeners.remove(listener); + } + } + } else { + for (int i = 0; i < listeners.size(); i++) { + Listener listener = listeners.get(i); + if (!predicate.test(listener)) { + continue; + } + listener.invoke(event); + if ((event instanceof IStatusEvent e) && e.isTerminated()) { + break; + } + if (!listener.shouldPersist()) { + listeners.remove(listener); + } + } + } + } + } + + /** + * Checks if this event bus is equal to another object. + *

+ * If the given object is an event bus, it is only considered equal if {@code this.id == that.id}. + * + * @param o the object to compare with + * @return {@code true} if the object is equal to this event bus, {@code false} otherwise + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if ((o == null) || (getClass() != o.getClass())) { + return false; + } + AbstractEventBus that = (AbstractEventBus) o; + return id == that.id; + } + + @Override + public int hashCode() { + return id; + } + + @Override + public abstract String toString(); +} \ No newline at end of file diff --git a/src/main/java/dev/tori/wraith/bus/EventBus.java b/src/main/java/dev/tori/wraith/bus/EventBus.java index 3ff1cb5..fba09b6 100644 --- a/src/main/java/dev/tori/wraith/bus/EventBus.java +++ b/src/main/java/dev/tori/wraith/bus/EventBus.java @@ -24,129 +24,33 @@ import dev.tori.wraith.event.Target; import dev.tori.wraith.event.status.IStatusEvent; import dev.tori.wraith.listener.Listener; -import dev.tori.wraith.subscriber.ISubscriber; -import dev.tori.wraith.task.ScheduledTask; -import dev.tori.wraith.task.TaskExecutor; import dev.tori.wraith.util.IndexedHashSet; -import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Predicate; /** - * Default implementation of {@link IEventBus}. + * An implementation of {@link AbstractEventBus}. *

- * Manages subscription, listener registration, and event dispatching. + * Manages listener registration, event dispatching, and task execution. * * @author 7orivorian * @since 1.0.0 */ -@SuppressWarnings({"rawtypes", "unchecked"}) -public class EventBus implements IEventBus { +@SuppressWarnings("rawtypes") +public class EventBus extends AbstractEventBus { /** - * The amount of {@linkplain EventBus} instances that have been created - */ - private static int instances = 0; - - /** - * This event bus's id - */ - private final int id; - /** - * Indicates whether this event bus is shutdown. - *

Shut-down event dispatchers cannot dispatch events, and throw {@link UnsupportedOperationException} when - * attempting to do so - */ - private boolean shutdown; - /** - * A {@link Set} of this event bus' {@link ISubscriber subscribers} - */ - private final Set subscribers; - /** - * A {@link ConcurrentHashMap} of this event bus' {@link Listener listeners} + * A {@link ConcurrentHashMap} of {@link Listener listeners} registered to this event bus. */ private final ConcurrentHashMap, IndexedHashSet> listeners; - /** - * A {@link TaskExecutor} that manages the scheduling and execution of tasks associated with events. It provides - * a mechanism to associate event classes with queues of tasks and ensures their orderly execution when the - * corresponding events are dispatched. - * - * @see #scheduleTask(ScheduledTask) - */ - private final TaskExecutor taskExecutor; /** * Creates a new event bus instance */ public EventBus() { - this.id = instances++; - this.shutdown = false; - this.subscribers = Collections.newSetFromMap(new ConcurrentHashMap<>()); + super(); this.listeners = new ConcurrentHashMap<>(); - this.taskExecutor = new TaskExecutor(); - } - - /** - * @return The amount of {@linkplain EventBus} instances that have been created. - */ - public static int getInstanceCount() { - return instances; - } - - /** - * Subscribes a {@link ISubscriber subscriber} to this event bus and registers all the - * subscriber's {@link Listener listeners} - * - * @param subscriber the {@link ISubscriber} to be subscribed - * @throws NullPointerException if the given {@link ISubscriber} is {@code null} - * @see #register(Listener) - */ - @Override - public void subscribe(ISubscriber subscriber) { - Objects.requireNonNull(subscriber, "Cannot subscribe null to event bus " + id + "!"); - - subscribers.add(subscriber); - subscriber.linkToBus(this); - - Collection> listeners = subscriber.getListeners(); - if (!listeners.isEmpty()) { - if (listeners.size() == 1) { - register(listeners.iterator().next()); - } else { - for (Listener listener : listeners) { - register(listener); - } - } - } - } - - /** - * Unsubscribes a {@link ISubscriber subscriber} from this event bus and unregisters all the - * subscriber's {@link Listener listeners} - * - * @param subscriber the {@link ISubscriber} to be unsubscribed - * @throws NullPointerException if the given {@link ISubscriber} is {@code null} - * @see #unregister(Listener) - */ - @Override - public void unsubscribe(ISubscriber subscriber) { - Objects.requireNonNull(subscriber, "Cannot unsubscribe null from event bus " + id + "!"); - - subscribers.remove(subscriber); - subscriber.unlinkFromBus(this); - - Collection> listeners = subscriber.getListeners(); - if (!listeners.isEmpty()) { - if (listeners.size() == 1) { - unregister(listeners.iterator().next()); - } else { - for (Listener listener : listeners) { - unregister(listener); - } - } - } } /** @@ -182,42 +86,6 @@ public void unregister(Listener listener) { listeners.get(listener.getTarget().clazz()).removeIf(l -> l.equals(listener)); } - /** - * Convenience method to dispatch an event with no {@linkplain Target target listener}, and - * normal processing priority. - * - * @see #dispatch(Object, Target, boolean) - * @since 3.3.0 - */ - @Override - public boolean dispatch(Object event) { - return dispatch(event, Target.none(), false); - } - - /** - * Convenience method to dispatch an event with an optional {@linkplain Target target listener} and - * normal processing priority. - * - * @see #dispatch(Object, Target, boolean) - * @since 4.0.0 - */ - @Override - public boolean dispatch(Object event, Target target) { - return dispatch(event, target, false); - } - - /** - * Convenience method to dispatch an event with no {@linkplain Target target listener}, and - * optional inverted processing priority. - * - * @see #dispatch(Object, Target, boolean) - * @since 4.0.0 - */ - @Override - public boolean dispatch(Object event, boolean invertPriority) { - return dispatch(event, Target.none(), invertPriority); - } - /** * Dispatches the given event to all valid registered listeners. *

@@ -256,129 +124,6 @@ public boolean dispatch(Object event, Target target, boolean invertPriority) { return false; } - /** - * Schedules a task to be executed. - * - * @param task The task to be executed. - * @see TaskExecutor#schedule(ScheduledTask) - * @see ScheduledTask - */ - public void scheduleTask(ScheduledTask task) { - taskExecutor.schedule(task); - } - - /** - * Clears all tasks associated with events from the underlying {@link #taskExecutor}, effectively - * resetting the task scheduling within this {@link EventBus}. - * - * @see TaskExecutor#clear() - */ - public void clearTaskExecutor() { - taskExecutor.clear(); - } - - /** - * Logs a warning message and shuts down this event bus, preventing future events from being dispatched. - * - * @implNote Shut-down event dispatchers cannot dispatch events, and throw {@link UnsupportedOperationException} - * when attempting to do so. - */ - @Override - public void shutdown() { - shutdown = true; - } - - /** - * @return {@code true} if this event bus is shut down - * @implNote Shut-down event dispatchers cannot dispatch events, and throw {@link UnsupportedOperationException} - * when attempting to do so. - */ - @Override - public boolean isShutdown() { - return shutdown; - } - - /** - * @return the {@code id} of this event bus - * @since 3.1.0 - */ - public int getId() { - return id; - } - - /** - * Applies a given action to each {@linkplain Listener} in a list that matches a specified predicate. - * Listeners are processed either in normal order or in reverse order based on the - * {@code invertPriority} flag. - * Listeners that should not persist are removed from the list after the action is applied. - * - * @param event the event to be handled by each listener that satisfies the predicate - * @param listeners the list of listeners to be processed - * @param predicate the condition that each listener must satisfy to have the action applied - * @param invertPriority if {@code true}, listeners are processed in order of inverse priority; otherwise, - * they are processed in normal order - * @since 3.2.0 - */ - @SuppressWarnings("DuplicatedCode") - private void dispatchToEachListener(Object event, IndexedHashSet listeners, Predicate predicate, boolean invertPriority) { - if ((listeners != null) && !listeners.isEmpty()) { - final ArrayList li = listeners.asList(); - if (invertPriority) { - for (int i = li.size() - 1; i >= 0; i--) { - Listener listener = li.get(i); - if (!predicate.test(listener)) { - continue; - } - listener.invoke(event); - if ((event instanceof IStatusEvent e) && e.isTerminated()) { - break; - } - if (!listener.shouldPersist()) { - listeners.remove(listener); - } - } - } else { - for (Listener listener : li) { - if (!predicate.test(listener)) { - continue; - } - listener.invoke(event); - if ((event instanceof IStatusEvent e) && e.isTerminated()) { - break; - } - if (!listener.shouldPersist()) { - listeners.remove(listener); - } - } - } - } - } - - /** - * Checks if this event bus is equal to another object. - *

- * If the given object is an event bus, it is only considered equal if {@code this.id == that.id}. - * - * @param o the object to compare with - * @return {@code true} if the object is equal to this event bus, {@code false} otherwise - */ - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if ((o == null) || (getClass() != o.getClass())) { - return false; - } - EventBus that = (EventBus) o; - return id == that.id; - } - - @Override - public int hashCode() { - return id; - } - @Override public String toString() { return "EventBus{" + diff --git a/src/main/java/dev/tori/wraith/bus/OpenEventBus.java b/src/main/java/dev/tori/wraith/bus/OpenEventBus.java new file mode 100644 index 0000000..c1bfd8e --- /dev/null +++ b/src/main/java/dev/tori/wraith/bus/OpenEventBus.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2021-2024 7orivorian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package dev.tori.wraith.bus; + +import dev.tori.wraith.event.Target; +import dev.tori.wraith.event.status.IStatusEvent; +import dev.tori.wraith.listener.Listener; +import dev.tori.wraith.util.IndexedHashSet; + +import java.util.Comparator; +import java.util.Objects; + +/** + * An implementation of {@link AbstractEventBus}. + *

+ * Manages listener registration, event dispatching, and task execution. + * + * @author 7orivorian + * @since 1.0.0 + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +public class OpenEventBus extends AbstractEventBus { + + /** + * An {@link IndexedHashSet} of {@link Listener listeners} registered to this event bus. + */ + private final IndexedHashSet listeners; + + /** + * Creates a new event bus instance + */ + public OpenEventBus() { + super(); + this.listeners = new IndexedHashSet<>(); + } + + /** + * Registers a {@link Listener listener} to this event bus + * + * @param listener the {@link Listener} to be registered + * @throws NullPointerException if the given {@link Listener} is {@code null} + */ + @Override + public void register(Listener listener) { + Objects.requireNonNull(listener, "Cannot register null listener to event bus " + id + "!"); + + listeners.add(listener); + listeners.sort(Comparator.naturalOrder()); + } + + /** + * Unregisters a {@link Listener listener} from this event bus. A listener will no longer be invoked by events dispatched by this event bus + * + * @param listener the {@link Listener} to be unregistered + * @throws NullPointerException if the given {@link Listener} is {@code null} + */ + @Override + public void unregister(Listener listener) { + Objects.requireNonNull(listener, "Cannot unregister null listener from event bus " + id + "!"); + listeners.removeIf(l -> l.equals(listener)); + } + + /** + * Dispatches the given event to all valid registered listeners. + *

+ * The {@code type} parameter serves as a filtering mechanism for listeners, enabling you to selectively invoke + * listeners based on their type, allowing for more targeted event handling. + * + * @param event the event to be dispatched. + * @param target the {@linkplain Target target listener} to invoke. + * @param invertPriority flag to dispatch the event in inverse listener priority. + * @return {@code true} if the given event is {@linkplain IStatusEvent suppressed or terminated} by any listener, + * {@code false} otherwise. + * @throws NullPointerException if the given event is {@code null} + * @throws UnsupportedOperationException if this event bus is {@link #shutdown} + * @since 4.0.0 + */ + @Override + public boolean dispatch(Object event, Target target, boolean invertPriority) { + Objects.requireNonNull(event, "Cannot dispatch a null event to event bus " + id + "!"); + Objects.requireNonNull(target, "Cannot dispatch an event with a null target to event bus " + id + "!"); + if (isShutdown()) { + throw new UnsupportedOperationException("Event bus " + id + " is shutdown!"); + } else { + taskExecutor.onEvent(event); + + dispatchToEachListener( + event, + listeners, + listener -> target.targets(listener.getClass()) && listener.getTarget().targets(event.getClass()), + invertPriority + ); + + if (event instanceof IStatusEvent e) { + return e.isSuppressed() || e.isTerminated(); + } + } + return false; + } + + public IndexedHashSet getListeners() { + return listeners; + } + + @Override + public String toString() { + return "EventBus{" + + "id=" + id + + ", shutdown=" + shutdown + + ", subscribers=" + subscribers + + ", listeners=" + listeners + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/dev/tori/wraith/event/Target.java b/src/main/java/dev/tori/wraith/event/Target.java index 7daad3e..1c9a799 100644 --- a/src/main/java/dev/tori/wraith/event/Target.java +++ b/src/main/java/dev/tori/wraith/event/Target.java @@ -23,7 +23,6 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import java.util.Objects; @@ -36,7 +35,7 @@ */ public class Target { - @Nullable + @NotNull private final Class clazz; @NotNull private final TargetingRule rule; @@ -48,52 +47,52 @@ public class Target { * @param rule the targeting rule. */ @Contract(pure = true) - private Target(@Nullable Class clazz, @NotNull TargetingRule rule) { + private Target(@NotNull Class clazz, @NotNull TargetingRule rule) { this.clazz = clazz; this.rule = rule; } /** - * Returns a {@code ClassTarget} with no specific target. + * Returns a {@link Target} that matches any class. * - * @return a {@code ClassTarget} with no specific target. + * @return a {@link Target} that matches any class. */ @NotNull - public static Target none() { - return new Target(null, TargetingRule.FINE); + public static Target all() { + return new Target(Object.class, TargetingRule.CASCADE); } /** - * Returns a {@code ClassTarget} with the specified target and {@link TargetingRule#FINE FINE} targeting. + * Returns a {@link Target} with the specified target and {@link TargetingRule#FINE FINE} targeting. * - * @param target the target class. - * @return a {@code ClassTarget} with the specified target and {@link TargetingRule#FINE FINE} targeting. + * @param clazz the target class. + * @return a {@link Target} with the specified target and {@link TargetingRule#FINE FINE} targeting. */ @NotNull - public static Target fine(@Nullable Class target) { - return new Target(target, TargetingRule.FINE); + public static Target fine(@NotNull Class clazz) { + return new Target(clazz, TargetingRule.FINE); } /** - * Returns a {@code ClassTarget} with the specified target and {@link TargetingRule#CASCADE CASCADE} targeting. + * Returns a {@link Target} with the specified target and {@link TargetingRule#CASCADE CASCADE} targeting. * - * @param target the target class. - * @return a {@code ClassTarget} with the specified target and {@link TargetingRule#CASCADE CASCADE} targeting. + * @param clazz the target class. + * @return a {@link Target} with the specified target and {@link TargetingRule#CASCADE CASCADE} targeting. */ @NotNull - public static Target cascade(@Nullable Class target) { - return new Target(target, TargetingRule.CASCADE); + public static Target cascade(@NotNull Class clazz) { + return new Target(clazz, TargetingRule.CASCADE); } /** - * Returns a {@code ClassTarget} with the specified target and {@link TargetingRule#REVERSE_CASCADE REVERSE_CASCADE} targeting. + * Returns a {@link Target} with the specified target and {@link TargetingRule#REVERSE_CASCADE REVERSE_CASCADE} targeting. * - * @param target the target class. - * @return a {@code ClassTarget} with the specified target and {@link TargetingRule#REVERSE_CASCADE REVERSE_CASCADE} targeting. + * @param clazz the target class. + * @return a {@link Target} with the specified target and {@link TargetingRule#REVERSE_CASCADE REVERSE_CASCADE} targeting. */ @NotNull - public static Target reverseCascade(@Nullable Class target) { - return new Target(target, TargetingRule.REVERSE_CASCADE); + public static Target reverseCascade(@NotNull Class clazz) { + return new Target(clazz, TargetingRule.REVERSE_CASCADE); } /** @@ -103,37 +102,60 @@ public static Target reverseCascade(@Nullable Class target) { * @return {@code true} if the class matches the target, {@code false} otherwise. */ public boolean targets(@NotNull Class clazz) { - if (this.clazz == null) { - return true; // Null target class will target anything + if (this.clazz == Object.class) { + //System.out.println(clazz); + return true; } - return rule.isMatch(clazz, this.clazz); + //System.out.println(clazz); + return rule.classesMatch(clazz, this.clazz); } /** - * Returns the target class. + * Returns the {@linkplain #clazz target class}. * - * @return the target class, {@code null} if no target is set. + * @return the {@linkplain #clazz target class}. */ - @Nullable + @NotNull public Class clazz() { return clazz; } /** - * Returns the targeting rule. + * Returns the {@linkplain #rule targeting rule}. * - * @return the targeting rule. + * @return the {@linkplain #rule targeting rule}. */ @NotNull public TargetingRule rule() { return rule; } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if ((obj == null) || (getClass() != obj.getClass())) { + return false; + } + + Target target = (Target) obj; + return clazz.equals(target.clazz) + && (rule == target.rule); + } + + @Override + public int hashCode() { + int result = clazz.hashCode(); + result = (31 * result) + rule.hashCode(); + return result; + } + @Override public String toString() { - return "ClassTarget{" + - "target=" + clazz + - ", matching=" + rule + + return "Target{" + + "clazz=" + clazz + + ", rule=" + rule + '}'; } @@ -146,7 +168,7 @@ public enum TargetingRule { */ FINE { @Override - public boolean isMatch(Class clazz, Class target) { + public boolean classesMatch(Class clazz, Class target) { return Objects.equals(clazz, target); } }, @@ -155,7 +177,7 @@ public boolean isMatch(Class clazz, Class target) { */ CASCADE { @Override - public boolean isMatch(Class clazz, Class target) { + public boolean classesMatch(Class clazz, Class target) { return target.isAssignableFrom(clazz); } }, @@ -164,11 +186,11 @@ public boolean isMatch(Class clazz, Class target) { */ REVERSE_CASCADE { @Override - public boolean isMatch(Class clazz, Class target) { + public boolean classesMatch(Class clazz, Class target) { return clazz.isAssignableFrom(target); } }; - public abstract boolean isMatch(Class clazz, Class target); + public abstract boolean classesMatch(Class clazz, Class target); } } \ No newline at end of file diff --git a/src/main/java/dev/tori/wraith/listener/Listener.java b/src/main/java/dev/tori/wraith/listener/Listener.java index c9b8fc8..b9b6a33 100644 --- a/src/main/java/dev/tori/wraith/listener/Listener.java +++ b/src/main/java/dev/tori/wraith/listener/Listener.java @@ -37,7 +37,7 @@ * @see Invokable * @since 1.0.0 */ -public interface Listener extends Invokable { +public interface Listener extends Invokable, Comparable> { int DEFAULT_PERSISTENCE = 0; @@ -78,4 +78,14 @@ default boolean shouldPersist() { default boolean hasIndefinitePersistence() { return true; } + + /** + * @param listener the listener to be compared. + * @apiNote This class has a natural ordering that is inconsistent with equals. + * @since 4.0.0 + */ + @Override + default int compareTo(@NotNull Listener listener) { + return listener.getPriority() - getPriority(); + } } \ No newline at end of file From 6c4aaf1b6f8867d919741485139bde8a6109fc1d Mon Sep 17 00:00:00 2001 From: Tori <7orivorian+github@gmail.com> Date: Wed, 31 Jul 2024 00:31:52 -0400 Subject: [PATCH 19/30] Duplicate unit tests for all event bus implementations Signed-off-by: Tori <7orivorian+github@gmail.com> --- .../persistency/PersistenceTest.java | 2 +- .../{ => eventbus}/priority/PriorityTest.java | 2 +- .../registration/RegistrationTest.java | 2 +- .../statusevent/StatusEventTest.java | 2 +- .../persistency/PersistenceTest.java} | 79 ++++++-------- .../openeventbus/priority/PriorityTest.java | 74 +++++++++++++ .../registration/RegistrationTest.java | 101 ++++++++++++++++++ .../statusevent/StatusEventTest.java | 90 ++++++++++++++++ 8 files changed, 304 insertions(+), 48 deletions(-) rename src/main/test/dev/tori/wraith/{ => eventbus}/persistency/PersistenceTest.java (98%) rename src/main/test/dev/tori/wraith/{ => eventbus}/priority/PriorityTest.java (98%) rename src/main/test/dev/tori/wraith/{ => eventbus}/registration/RegistrationTest.java (98%) rename src/main/test/dev/tori/wraith/{ => eventbus}/statusevent/StatusEventTest.java (98%) rename src/main/test/dev/tori/wraith/{MainTwo.java => openeventbus/persistency/PersistenceTest.java} (50%) create mode 100644 src/main/test/dev/tori/wraith/openeventbus/priority/PriorityTest.java create mode 100644 src/main/test/dev/tori/wraith/openeventbus/registration/RegistrationTest.java create mode 100644 src/main/test/dev/tori/wraith/openeventbus/statusevent/StatusEventTest.java diff --git a/src/main/test/dev/tori/wraith/persistency/PersistenceTest.java b/src/main/test/dev/tori/wraith/eventbus/persistency/PersistenceTest.java similarity index 98% rename from src/main/test/dev/tori/wraith/persistency/PersistenceTest.java rename to src/main/test/dev/tori/wraith/eventbus/persistency/PersistenceTest.java index 696dd57..c8b1157 100644 --- a/src/main/test/dev/tori/wraith/persistency/PersistenceTest.java +++ b/src/main/test/dev/tori/wraith/eventbus/persistency/PersistenceTest.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package dev.tori.wraith.persistency; +package dev.tori.wraith.eventbus.persistency; import dev.tori.wraith.bus.EventBus; import dev.tori.wraith.event.Target; diff --git a/src/main/test/dev/tori/wraith/priority/PriorityTest.java b/src/main/test/dev/tori/wraith/eventbus/priority/PriorityTest.java similarity index 98% rename from src/main/test/dev/tori/wraith/priority/PriorityTest.java rename to src/main/test/dev/tori/wraith/eventbus/priority/PriorityTest.java index 52d1588..e881eb8 100644 --- a/src/main/test/dev/tori/wraith/priority/PriorityTest.java +++ b/src/main/test/dev/tori/wraith/eventbus/priority/PriorityTest.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package dev.tori.wraith.priority; +package dev.tori.wraith.eventbus.priority; import dev.tori.wraith.bus.EventBus; import dev.tori.wraith.event.Target; diff --git a/src/main/test/dev/tori/wraith/registration/RegistrationTest.java b/src/main/test/dev/tori/wraith/eventbus/registration/RegistrationTest.java similarity index 98% rename from src/main/test/dev/tori/wraith/registration/RegistrationTest.java rename to src/main/test/dev/tori/wraith/eventbus/registration/RegistrationTest.java index 219bf42..41f89c4 100644 --- a/src/main/test/dev/tori/wraith/registration/RegistrationTest.java +++ b/src/main/test/dev/tori/wraith/eventbus/registration/RegistrationTest.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package dev.tori.wraith.registration; +package dev.tori.wraith.eventbus.registration; import dev.tori.wraith.bus.EventBus; import dev.tori.wraith.event.Target; diff --git a/src/main/test/dev/tori/wraith/statusevent/StatusEventTest.java b/src/main/test/dev/tori/wraith/eventbus/statusevent/StatusEventTest.java similarity index 98% rename from src/main/test/dev/tori/wraith/statusevent/StatusEventTest.java rename to src/main/test/dev/tori/wraith/eventbus/statusevent/StatusEventTest.java index 55b0533..d9e4620 100644 --- a/src/main/test/dev/tori/wraith/statusevent/StatusEventTest.java +++ b/src/main/test/dev/tori/wraith/eventbus/statusevent/StatusEventTest.java @@ -19,7 +19,7 @@ * THE SOFTWARE. */ -package dev.tori.wraith.statusevent; +package dev.tori.wraith.eventbus.statusevent; import dev.tori.wraith.bus.EventBus; import dev.tori.wraith.event.Target; diff --git a/src/main/test/dev/tori/wraith/MainTwo.java b/src/main/test/dev/tori/wraith/openeventbus/persistency/PersistenceTest.java similarity index 50% rename from src/main/test/dev/tori/wraith/MainTwo.java rename to src/main/test/dev/tori/wraith/openeventbus/persistency/PersistenceTest.java index 712f180..46cff95 100644 --- a/src/main/test/dev/tori/wraith/MainTwo.java +++ b/src/main/test/dev/tori/wraith/openeventbus/persistency/PersistenceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024 7orivorian. + * Copyright (c) 2021-2024 7orivorian. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -19,76 +19,67 @@ * THE SOFTWARE. */ -package dev.tori.wraith; +package dev.tori.wraith.openeventbus.persistency; -import dev.tori.wraith.bus.EventBus; +import dev.tori.wraith.bus.OpenEventBus; import dev.tori.wraith.event.Target; -import dev.tori.wraith.event.targeted.ClassTargetingEvent; +import dev.tori.wraith.event.status.StatusEvent; import dev.tori.wraith.listener.EventListener; -import dev.tori.wraith.listener.Listener; import dev.tori.wraith.subscriber.Subscriber; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.ThreadLocalRandom; /** * @author 7orivorian - * @since 4.0.0 + * @since 3.2.0 */ -public class MainTwo { +public class PersistenceTest { + + @Test + public void testRandomPersistence() { + final OpenEventBus bus = new OpenEventBus(); + + final int persists = ThreadLocalRandom.current().nextInt(1, 101); - public static void main(String[] args) { - final EventBus bus = new EventBus(); bus.subscribe(new Subscriber() {{ - registerListeners( - new ListenerOne(), - new ListenerTwo() - ); + registerListener(new MyListener(persists)); }}); - TestEvent event = new TestEvent(null); - - bus.dispatch(event); + for (int i = 0; i < persists; i++) { + Assertions.assertTrue(bus.dispatch(new MyEvent())); + } - System.out.println(event); + Assertions.assertFalse(bus.dispatch(new MyEvent())); } - static class ListenerOne extends EventListener { + @Test + public void testIndefinitePersistence() { + final OpenEventBus bus = new OpenEventBus(); - public ListenerOne() { - super(Target.fine(TestEvent.class)); - } + bus.subscribe(new Subscriber() {{ + registerListener(new MyListener(0)); // <= 0 means persist indefinitely + }}); - @Override - public void invoke(TestEvent event) { - event.mod(); + for (int i = 0; i < 1_000; i++) { + Assertions.assertTrue(bus.dispatch(new MyEvent())); } } - static class ListenerTwo extends EventListener { + static class MyListener extends EventListener { - public ListenerTwo() { - super(Target.fine(TestEvent.class)); + public MyListener(int persists) { + super(Target.fine(MyEvent.class), 0, persists); } @Override - public void invoke(TestEvent event) { - event.mod(); + public void invoke(MyEvent event) { + event.suppress(); } } - static class TestEvent extends ClassTargetingEvent { - - private int mods = 0; - - public TestEvent(Class> target) { - super(target); - } - - public void mod() { - this.mods++; - } + static class MyEvent extends StatusEvent { - @Override - public String toString() { - return "mods=" + mods; - } } } \ No newline at end of file diff --git a/src/main/test/dev/tori/wraith/openeventbus/priority/PriorityTest.java b/src/main/test/dev/tori/wraith/openeventbus/priority/PriorityTest.java new file mode 100644 index 0000000..482fcbd --- /dev/null +++ b/src/main/test/dev/tori/wraith/openeventbus/priority/PriorityTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024 7orivorian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package dev.tori.wraith.openeventbus.priority; + +import dev.tori.wraith.bus.OpenEventBus; +import dev.tori.wraith.event.Target; +import dev.tori.wraith.event.status.StatusEvent; +import dev.tori.wraith.listener.LambdaEventListener; +import dev.tori.wraith.subscriber.Subscriber; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author 7orivorian + * @since 4.0.0 + */ +public class PriorityTest { + + @Test + public void testPriority() { + final OpenEventBus bus = new OpenEventBus(); + bus.subscribe(new Subscriber() {{ + registerListener(new LambdaEventListener(Target.fine(MyEvent.class), 5, event -> event.setFlag(true))); + registerListener(new LambdaEventListener(Target.fine(MyEvent.class), 4, event -> { + event.setFlag(false); + event.terminate(); + })); + registerListener(new LambdaEventListener(Target.fine(MyEvent.class), 3, event -> event.setFlag(true))); + registerListener(new LambdaEventListener(Target.fine(MyEvent.class), 2, event -> event.setFlag(true))); + registerListener(new LambdaEventListener(Target.fine(MyEvent.class), 1, event -> event.setFlag(true))); + registerListener(new LambdaEventListener(Target.fine(MyEvent.class), 0, event -> event.setFlag(true))); + }}); + + MyEvent event = new MyEvent(); + Assertions.assertTrue(bus.dispatch(event)); + Assertions.assertFalse(event.flag()); + } + + static class MyEvent extends StatusEvent { + + private boolean flag; + + MyEvent() { + this.flag = true; + } + + public boolean flag() { + return flag; + } + + public void setFlag(boolean flag) { + this.flag = flag; + } + } +} \ No newline at end of file diff --git a/src/main/test/dev/tori/wraith/openeventbus/registration/RegistrationTest.java b/src/main/test/dev/tori/wraith/openeventbus/registration/RegistrationTest.java new file mode 100644 index 0000000..eb1c164 --- /dev/null +++ b/src/main/test/dev/tori/wraith/openeventbus/registration/RegistrationTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2024 7orivorian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package dev.tori.wraith.openeventbus.registration; + +import dev.tori.wraith.bus.OpenEventBus; +import dev.tori.wraith.event.Target; +import dev.tori.wraith.event.status.IStatusEvent; +import dev.tori.wraith.event.status.StatusEvent; +import dev.tori.wraith.listener.LambdaEventListener; +import dev.tori.wraith.subscriber.Subscriber; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author 7orivorian + * @since 4.0.0 + */ +public class RegistrationTest { + + @Test + public void testResistration() { + final OpenEventBus bus = new OpenEventBus(); + final LambdaEventListener listener = new LambdaEventListener( + Target.fine(StatusEvent.class), + IStatusEvent::terminate + ); + + bus.register(listener); + Assertions.assertTrue(bus.dispatch(new StatusEvent())); + + bus.unregister(listener); + Assertions.assertFalse(bus.dispatch(new StatusEvent())); + } + + @Test + public void testSubscription() { + final OpenEventBus bus = new OpenEventBus(); + final Subscriber subscriber = new Subscriber() {{ + registerListener(new LambdaEventListener(Target.fine(StatusEvent.class), IStatusEvent::terminate)); + }}; + + bus.subscribe(subscriber); + Assertions.assertTrue(bus.dispatch(new StatusEvent())); + + bus.unsubscribe(subscriber); + Assertions.assertFalse(bus.dispatch(new StatusEvent())); + } + + @Test + public void testLateSubscription() { + final String expectedMessage = "Hello world!"; + + final OpenEventBus bus = new OpenEventBus(); + final Subscriber subscriber = new Subscriber(); + + bus.subscribe(subscriber); + + subscriber.registerListener(new LambdaEventListener(Target.fine(MyEvent.class), event -> event.setMessage(expectedMessage))); + + MyEvent event = new MyEvent(null); + bus.dispatch(event); + + Assertions.assertEquals(expectedMessage, event.message()); + } + + static final class MyEvent { + + private String message; + + MyEvent(String message) { + this.message = message; + } + + public String message() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + } +} \ No newline at end of file diff --git a/src/main/test/dev/tori/wraith/openeventbus/statusevent/StatusEventTest.java b/src/main/test/dev/tori/wraith/openeventbus/statusevent/StatusEventTest.java new file mode 100644 index 0000000..e334445 --- /dev/null +++ b/src/main/test/dev/tori/wraith/openeventbus/statusevent/StatusEventTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024 7orivorian. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package dev.tori.wraith.openeventbus.statusevent; + +import dev.tori.wraith.bus.OpenEventBus; +import dev.tori.wraith.event.Target; +import dev.tori.wraith.event.status.StatusEvent; +import dev.tori.wraith.listener.LambdaEventListener; +import dev.tori.wraith.subscriber.Subscriber; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/** + * @author 7orivorian + * @since 3.2.0 + */ +public class StatusEventTest { + + @Test + public void testSupression() { + final OpenEventBus bus = new OpenEventBus(); + + MySubscriber subscriber = new MySubscriber() {{ + registerListeners( + new LambdaEventListener(Target.fine(StatusEvent.class), 1, event -> { + this.counter = 1; + event.suppress(); + }), + new LambdaEventListener(Target.fine(StatusEvent.class), 0, event -> { + this.counter++; + }) + ); + }}; + bus.subscribe(subscriber); + + Assertions.assertEquals(2, bus.getListeners().size()); + + Assertions.assertTrue(bus.dispatch(new StatusEvent())); + Assertions.assertEquals(2, subscriber.counter); + } + + @Test + public void testTermination() { + final OpenEventBus bus = new OpenEventBus(); + + MySubscriber subscriber = new MySubscriber() {{ + registerListeners( + new LambdaEventListener(Target.fine(StatusEvent.class), 1, event -> { + this.counter = 1; + event.terminate(); + }), + new LambdaEventListener(Target.fine(StatusEvent.class), 0, event -> { + this.counter = 1_000; + }) + ); + }}; + bus.subscribe(subscriber); + + Assertions.assertTrue(bus.dispatch(new StatusEvent())); + Assertions.assertEquals(1, subscriber.counter); + } + + private static class MySubscriber extends Subscriber { + + public int counter = 0; + + public MySubscriber() { + + } + } +} \ No newline at end of file From 20412d1b30a802e33408639dcfabd36cc5f7b359 Mon Sep 17 00:00:00 2001 From: Tori <7orivorian+github@gmail.com> Date: Wed, 31 Jul 2024 00:32:20 -0400 Subject: [PATCH 20/30] Refactor IndexedHashSetTest unit test Signed-off-by: Tori <7orivorian+github@gmail.com> --- src/main/test/dev/tori/wraith/util/IndexedHashSetTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/test/dev/tori/wraith/util/IndexedHashSetTest.java b/src/main/test/dev/tori/wraith/util/IndexedHashSetTest.java index 1882998..9fec4cc 100644 --- a/src/main/test/dev/tori/wraith/util/IndexedHashSetTest.java +++ b/src/main/test/dev/tori/wraith/util/IndexedHashSetTest.java @@ -21,7 +21,6 @@ package dev.tori.wraith.util; -import dev.tori.wraith.util.IndexedHashSet; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; From d39f915ceb840c46c091b77dd7bc7b7845d38be0 Mon Sep 17 00:00:00 2001 From: Tori <7orivorian+github@gmail.com> Date: Wed, 31 Jul 2024 00:32:45 -0400 Subject: [PATCH 21/30] Update MyBenchmark Signed-off-by: Tori <7orivorian+github@gmail.com> --- .../tori/wraith/benchmarking/MyBenchmark.java | 72 ++++--------------- 1 file changed, 12 insertions(+), 60 deletions(-) diff --git a/src/main/test/dev/tori/wraith/benchmarking/MyBenchmark.java b/src/main/test/dev/tori/wraith/benchmarking/MyBenchmark.java index 0f2511e..73abcac 100644 --- a/src/main/test/dev/tori/wraith/benchmarking/MyBenchmark.java +++ b/src/main/test/dev/tori/wraith/benchmarking/MyBenchmark.java @@ -24,7 +24,6 @@ import dev.tori.wraith.bus.EventBus; import dev.tori.wraith.event.Target; import dev.tori.wraith.listener.EventListener; -import dev.tori.wraith.subscriber.Subscriber; import org.openjdk.jmh.annotations.*; import java.util.concurrent.TimeUnit; @@ -33,80 +32,33 @@ * @author 7orivorian * @since 3.2.0 */ +@State(Scope.Thread) public class MyBenchmark { @State(Scope.Thread) public static class BenchmarkState { - MyListener myListener; - MySubscriber mySubscriber; + EventListener myListener; EventBus bus; @Setup(Level.Trial) public void setup() { bus = new EventBus(); - mySubscriber = new MySubscriber(); - myListener = new MyListener(); + myListener = new EventListener<>(Target.fine(Object.class)) { + @Override + public void invoke(Object event) { + + } + }; } } @Benchmark - @BenchmarkMode(Mode.AverageTime) + @BenchmarkMode(Mode.SingleShotTime) @OutputTimeUnit(TimeUnit.MILLISECONDS) - @Warmup(iterations = 1, time = 2) - @Measurement(iterations = 2, time = 2) + @Warmup(iterations = 10) + @Measurement(iterations = 100) @Fork(5) public void testMethod(BenchmarkState state) { - for (int i = 0; i < 1_000; i++) { - state.bus.register(state.myListener); - } - } - - public static class MySubscriber extends Subscriber { - - public MySubscriber() { - registerListener( - new MyListener() - ); - } - } - - public static class MyListener extends EventListener { - - public MyListener() { - super(Target.fine(MyEvent.class)); - } - - @Override - public void invoke(MyEvent event) { - System.out.println(event.content()); - } - - @Override - public boolean shouldPersist() { - return false; - } - } - - public static final class MyEvent { - - private String content; - - public MyEvent(String content) { - this.content = content; - } - - public String content() { - return content; - } - - public void setContent(String content) { - this.content = content; - } - - @Override - public String toString() { - return "MyEvent[" + - "content=" + content + ']'; - } + state.bus.register(state.myListener); } } \ No newline at end of file From 4e76b6c97b2c823d8a837ebda8f70993272e10df Mon Sep 17 00:00:00 2001 From: Tori <7orivorian+github@gmail.com> Date: Sun, 4 Aug 2024 21:16:42 -0400 Subject: [PATCH 22/30] Add unit test run config Signed-off-by: Tori <7orivorian+github@gmail.com> --- .run/test in Wraith.run.xml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .run/test in Wraith.run.xml diff --git a/.run/test in Wraith.run.xml b/.run/test in Wraith.run.xml new file mode 100644 index 0000000..2454a17 --- /dev/null +++ b/.run/test in Wraith.run.xml @@ -0,0 +1,12 @@ + + + +