1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.lang3.event;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertNotNull;
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24
25 import java.beans.PropertyChangeEvent;
26 import java.beans.PropertyChangeListener;
27 import java.beans.VetoableChangeListener;
28 import java.lang.reflect.Constructor;
29 import java.lang.reflect.InvocationHandler;
30 import java.lang.reflect.Method;
31 import java.lang.reflect.Modifier;
32 import java.lang.reflect.Proxy;
33 import java.util.Date;
34 import java.util.Map;
35 import java.util.TreeMap;
36
37 import javax.naming.event.ObjectChangeListener;
38
39 import org.apache.commons.lang3.AbstractLangTest;
40 import org.junit.jupiter.api.Test;
41
42
43
44
45 public class EventUtilsTest extends AbstractLangTest {
46 public static class EventCounter {
47 private int count;
48
49 public void eventOccurred() {
50 count++;
51 }
52
53 public int getCount() {
54 return count;
55 }
56 }
57
58 public static class EventCounterWithEvent {
59 private int count;
60
61 public void eventOccurred(final PropertyChangeEvent e) {
62 count++;
63 }
64
65 public int getCount() {
66 return count;
67 }
68 }
69
70 private static final class EventCountingInvocationHandler implements InvocationHandler {
71 private final Map<String, Integer> eventCounts = new TreeMap<>();
72
73 public <L> L createListener(final Class<L> listenerType) {
74 return listenerType.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
75 new Class[]{listenerType},
76 this));
77 }
78
79 public int getEventCount(final String eventName) {
80 final Integer count = eventCounts.get(eventName);
81 return count == null ? 0 : count.intValue();
82 }
83
84 @Override
85 public Object invoke(final Object proxy, final Method method, final Object[] args) {
86 final Integer count = eventCounts.get(method.getName());
87 if (count == null) {
88 eventCounts.put(method.getName(), Integer.valueOf(1));
89 } else {
90 eventCounts.put(method.getName(), Integer.valueOf(count.intValue() + 1));
91 }
92 return null;
93 }
94 }
95
96 public static class ExceptionEventSource {
97 public void addPropertyChangeListener(final PropertyChangeListener listener) {
98 throw new RuntimeException();
99 }
100 }
101
102 public interface MultipleEventListener {
103 void event1(PropertyChangeEvent e);
104
105 void event2(PropertyChangeEvent e);
106 }
107
108 public static class MultipleEventSource {
109 private final EventListenerSupport<MultipleEventListener> listeners = EventListenerSupport.create(MultipleEventListener.class);
110
111 public void addMultipleEventListener(final MultipleEventListener listener) {
112 listeners.addListener(listener);
113 }
114 }
115
116
117 public static class PropertyChangeSource {
118 private final EventListenerSupport<PropertyChangeListener> listeners = EventListenerSupport.create(PropertyChangeListener.class);
119
120 private String property;
121
122 public void addPropertyChangeListener(final PropertyChangeListener listener) {
123 listeners.addListener(listener);
124 }
125
126 protected void addVetoableChangeListener(final VetoableChangeListener listener) {
127
128 }
129
130 public void removePropertyChangeListener(final PropertyChangeListener listener) {
131 listeners.removeListener(listener);
132 }
133
134 public void setProperty(final String property) {
135 final String oldValue = this.property;
136 this.property = property;
137 listeners.fire().propertyChange(new PropertyChangeEvent(this, "property", oldValue, property));
138 }
139 }
140
141
142 @Test
143 public void testAddEventListener() {
144 final PropertyChangeSource src = new PropertyChangeSource();
145 final EventCountingInvocationHandler handler = new EventCountingInvocationHandler();
146 final PropertyChangeListener listener = handler.createListener(PropertyChangeListener.class);
147 assertEquals(0, handler.getEventCount("propertyChange"));
148 EventUtils.addEventListener(src, PropertyChangeListener.class, listener);
149 assertEquals(0, handler.getEventCount("propertyChange"));
150 src.setProperty("newValue");
151 assertEquals(1, handler.getEventCount("propertyChange"));
152 }
153
154 @Test
155 public void testAddEventListenerThrowsException() {
156 final ExceptionEventSource src = new ExceptionEventSource();
157 assertThrows(RuntimeException.class, () ->
158 EventUtils.addEventListener(src, PropertyChangeListener.class, e -> {
159
160 })
161 );
162 }
163
164 @Test
165 public void testAddEventListenerWithNoAddMethod() {
166 final PropertyChangeSource src = new PropertyChangeSource();
167 final EventCountingInvocationHandler handler = new EventCountingInvocationHandler();
168 final ObjectChangeListener listener = handler.createListener(ObjectChangeListener.class);
169 final IllegalArgumentException e =
170 assertThrows(IllegalArgumentException.class, () -> EventUtils.addEventListener(src, ObjectChangeListener.class, listener));
171 assertEquals("Class " + src.getClass().getName() + " does not have a public add" + ObjectChangeListener.class.getSimpleName() + " method which takes a parameter of type " + ObjectChangeListener.class.getName() + ".",
172 e.getMessage());
173 }
174
175 @Test
176 public void testAddEventListenerWithPrivateAddMethod() {
177 final PropertyChangeSource src = new PropertyChangeSource();
178 final EventCountingInvocationHandler handler = new EventCountingInvocationHandler();
179 final VetoableChangeListener listener = handler.createListener(VetoableChangeListener.class);
180 final IllegalArgumentException e =
181 assertThrows(IllegalArgumentException.class, () -> EventUtils.addEventListener(src, VetoableChangeListener.class, listener));
182 assertEquals("Class " + src.getClass().getName() + " does not have a public add" + VetoableChangeListener.class.getSimpleName() + " method which takes a parameter of type " + VetoableChangeListener.class.getName() + ".",
183 e.getMessage());
184 }
185
186
187 @Test
188 public void testBindEventsToMethod() {
189 final PropertyChangeSource src = new PropertyChangeSource();
190 final EventCounter counter = new EventCounter();
191 EventUtils.bindEventsToMethod(counter, "eventOccurred", src, PropertyChangeListener.class);
192 assertEquals(0, counter.getCount());
193 src.setProperty("newValue");
194 assertEquals(1, counter.getCount());
195 }
196
197 @Test
198 public void testBindEventsToMethodWithEvent() {
199 final PropertyChangeSource src = new PropertyChangeSource();
200 final EventCounterWithEvent counter = new EventCounterWithEvent();
201 EventUtils.bindEventsToMethod(counter, "eventOccurred", src, PropertyChangeListener.class);
202 assertEquals(0, counter.getCount());
203 src.setProperty("newValue");
204 assertEquals(1, counter.getCount());
205 }
206
207 @Test
208 public void testBindFilteredEventsToMethod() {
209 final MultipleEventSource src = new MultipleEventSource();
210 final EventCounter counter = new EventCounter();
211 EventUtils.bindEventsToMethod(counter, "eventOccurred", src, MultipleEventListener.class, "event1");
212 assertEquals(0, counter.getCount());
213 src.listeners.fire().event1(new PropertyChangeEvent(new Date(), "Day", Integer.valueOf(0), Integer.valueOf(1)));
214 assertEquals(1, counter.getCount());
215 src.listeners.fire().event2(new PropertyChangeEvent(new Date(), "Day", Integer.valueOf(1), Integer.valueOf(2)));
216 assertEquals(1, counter.getCount());
217 }
218
219 @Test
220 public void testConstructor() {
221 assertNotNull(new EventUtils());
222 final Constructor<?>[] cons = EventUtils.class.getDeclaredConstructors();
223 assertEquals(1, cons.length);
224 assertTrue(Modifier.isPublic(cons[0].getModifiers()));
225 assertTrue(Modifier.isPublic(EventUtils.class.getModifiers()));
226 assertFalse(Modifier.isFinal(EventUtils.class.getModifiers()));
227 }
228 }