• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
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  * @since 3.0
44  */
45 public class EventUtilsTest extends AbstractLangTest {
46     @Test
testConstructor()47     public void testConstructor() {
48         assertNotNull(new EventUtils());
49         final Constructor<?>[] cons = EventUtils.class.getDeclaredConstructors();
50         assertEquals(1, cons.length);
51         assertTrue(Modifier.isPublic(cons[0].getModifiers()));
52         assertTrue(Modifier.isPublic(EventUtils.class.getModifiers()));
53         assertFalse(Modifier.isFinal(EventUtils.class.getModifiers()));
54     }
55 
56     @Test
testAddEventListener()57     public void testAddEventListener() {
58         final PropertyChangeSource src = new PropertyChangeSource();
59         final EventCountingInvocationHandler handler = new EventCountingInvocationHandler();
60         final PropertyChangeListener listener = handler.createListener(PropertyChangeListener.class);
61         assertEquals(0, handler.getEventCount("propertyChange"));
62         EventUtils.addEventListener(src, PropertyChangeListener.class, listener);
63         assertEquals(0, handler.getEventCount("propertyChange"));
64         src.setProperty("newValue");
65         assertEquals(1, handler.getEventCount("propertyChange"));
66     }
67 
68     @Test
testAddEventListenerWithNoAddMethod()69     public void testAddEventListenerWithNoAddMethod() {
70         final PropertyChangeSource src = new PropertyChangeSource();
71         final EventCountingInvocationHandler handler = new EventCountingInvocationHandler();
72         final ObjectChangeListener listener = handler.createListener(ObjectChangeListener.class);
73         final IllegalArgumentException e =
74                 assertThrows(IllegalArgumentException.class, () -> EventUtils.addEventListener(src, ObjectChangeListener.class, listener));
75         assertEquals("Class " + src.getClass().getName() + " does not have a public add" + ObjectChangeListener.class.getSimpleName() + " method which takes a parameter of type " + ObjectChangeListener.class.getName() + ".",
76                 e.getMessage());
77     }
78 
79     @Test
testAddEventListenerThrowsException()80     public void testAddEventListenerThrowsException() {
81         final ExceptionEventSource src = new ExceptionEventSource();
82         assertThrows(RuntimeException.class, () ->
83             EventUtils.addEventListener(src, PropertyChangeListener.class, e -> {
84                 // Do nothing!
85             })
86         );
87     }
88 
89     @Test
testAddEventListenerWithPrivateAddMethod()90     public void testAddEventListenerWithPrivateAddMethod() {
91         final PropertyChangeSource src = new PropertyChangeSource();
92         final EventCountingInvocationHandler handler = new EventCountingInvocationHandler();
93         final VetoableChangeListener listener = handler.createListener(VetoableChangeListener.class);
94         final IllegalArgumentException e =
95                 assertThrows(IllegalArgumentException.class, () -> EventUtils.addEventListener(src, VetoableChangeListener.class, listener));
96         assertEquals("Class " + src.getClass().getName() + " does not have a public add" + VetoableChangeListener.class.getSimpleName() + " method which takes a parameter of type " + VetoableChangeListener.class.getName() + ".",
97                 e.getMessage());
98     }
99 
100     @Test
testBindEventsToMethod()101     public void testBindEventsToMethod() {
102         final PropertyChangeSource src = new PropertyChangeSource();
103         final EventCounter counter = new EventCounter();
104         EventUtils.bindEventsToMethod(counter, "eventOccurred", src, PropertyChangeListener.class);
105         assertEquals(0, counter.getCount());
106         src.setProperty("newValue");
107         assertEquals(1, counter.getCount());
108     }
109 
110 
111     @Test
testBindEventsToMethodWithEvent()112     public void testBindEventsToMethodWithEvent() {
113         final PropertyChangeSource src = new PropertyChangeSource();
114         final EventCounterWithEvent counter = new EventCounterWithEvent();
115         EventUtils.bindEventsToMethod(counter, "eventOccurred", src, PropertyChangeListener.class);
116         assertEquals(0, counter.getCount());
117         src.setProperty("newValue");
118         assertEquals(1, counter.getCount());
119     }
120 
121 
122     @Test
testBindFilteredEventsToMethod()123     public void testBindFilteredEventsToMethod() {
124         final MultipleEventSource src = new MultipleEventSource();
125         final EventCounter counter = new EventCounter();
126         EventUtils.bindEventsToMethod(counter, "eventOccurred", src, MultipleEventListener.class, "event1");
127         assertEquals(0, counter.getCount());
128         src.listeners.fire().event1(new PropertyChangeEvent(new Date(), "Day", Integer.valueOf(0), Integer.valueOf(1)));
129         assertEquals(1, counter.getCount());
130         src.listeners.fire().event2(new PropertyChangeEvent(new Date(), "Day", Integer.valueOf(1), Integer.valueOf(2)));
131         assertEquals(1, counter.getCount());
132     }
133 
134     public interface MultipleEventListener {
event1(PropertyChangeEvent e)135         void event1(PropertyChangeEvent e);
136 
event2(PropertyChangeEvent e)137         void event2(PropertyChangeEvent e);
138     }
139 
140     public static class EventCounter {
141         private int count;
142 
eventOccurred()143         public void eventOccurred() {
144             count++;
145         }
146 
getCount()147         public int getCount() {
148             return count;
149         }
150     }
151 
152     public static class EventCounterWithEvent {
153         private int count;
154 
eventOccurred(final PropertyChangeEvent e)155         public void eventOccurred(final PropertyChangeEvent e) {
156             count++;
157         }
158 
getCount()159         public int getCount() {
160             return count;
161         }
162     }
163 
164 
165     private static class EventCountingInvocationHandler implements InvocationHandler {
166         private final Map<String, Integer> eventCounts = new TreeMap<>();
167 
createListener(final Class<L> listenerType)168         public <L> L createListener(final Class<L> listenerType) {
169             return listenerType.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
170                     new Class[]{listenerType},
171                     this));
172         }
173 
getEventCount(final String eventName)174         public int getEventCount(final String eventName) {
175             final Integer count = eventCounts.get(eventName);
176             return count == null ? 0 : count.intValue();
177         }
178 
179         @Override
invoke(final Object proxy, final Method method, final Object[] args)180         public Object invoke(final Object proxy, final Method method, final Object[] args) {
181             final Integer count = eventCounts.get(method.getName());
182             if (count == null) {
183                 eventCounts.put(method.getName(), Integer.valueOf(1));
184             } else {
185                 eventCounts.put(method.getName(), Integer.valueOf(count.intValue() + 1));
186             }
187             return null;
188         }
189     }
190 
191     public static class MultipleEventSource {
192         private final EventListenerSupport<MultipleEventListener> listeners = EventListenerSupport.create(MultipleEventListener.class);
193 
addMultipleEventListener(final MultipleEventListener listener)194         public void addMultipleEventListener(final MultipleEventListener listener) {
195             listeners.addListener(listener);
196         }
197     }
198 
199     public static class ExceptionEventSource {
addPropertyChangeListener(final PropertyChangeListener listener)200         public void addPropertyChangeListener(final PropertyChangeListener listener) {
201             throw new RuntimeException();
202         }
203     }
204 
205     public static class PropertyChangeSource {
206         private final EventListenerSupport<PropertyChangeListener> listeners = EventListenerSupport.create(PropertyChangeListener.class);
207 
208         private String property;
209 
setProperty(final String property)210         public void setProperty(final String property) {
211             final String oldValue = this.property;
212             this.property = property;
213             listeners.fire().propertyChange(new PropertyChangeEvent(this, "property", oldValue, property));
214         }
215 
addVetoableChangeListener(final VetoableChangeListener listener)216         protected void addVetoableChangeListener(final VetoableChangeListener listener) {
217             // Do nothing!
218         }
219 
addPropertyChangeListener(final PropertyChangeListener listener)220         public void addPropertyChangeListener(final PropertyChangeListener listener) {
221             listeners.addListener(listener);
222         }
223 
removePropertyChangeListener(final PropertyChangeListener listener)224         public void removePropertyChangeListener(final PropertyChangeListener listener) {
225             listeners.removeListener(listener);
226         }
227     }
228 }
229