View Javadoc
1   package org.djutils.event.remote;
2   
3   import static org.junit.Assert.assertEquals;
4   import static org.junit.Assert.assertFalse;
5   import static org.junit.Assert.assertTrue;
6   import static org.junit.Assert.fail;
7   
8   import java.io.Serializable;
9   import java.lang.reflect.Field;
10  import java.net.MalformedURLException;
11  import java.net.URL;
12  import java.rmi.AlreadyBoundException;
13  import java.rmi.RemoteException;
14  import java.util.Arrays;
15  import java.util.LinkedHashSet;
16  import java.util.List;
17  
18  import org.djutils.event.Event;
19  import org.djutils.event.EventInterface;
20  import org.djutils.event.EventListenerInterface;
21  import org.djutils.event.EventProducerInterface;
22  import org.djutils.event.EventType;
23  import org.djutils.event.TimedEvent;
24  import org.djutils.event.TimedEventType;
25  import org.djutils.event.ref.Reference;
26  import org.djutils.event.ref.ReferenceType;
27  import org.djutils.exceptions.Try;
28  import org.djutils.metadata.MetaData;
29  import org.djutils.metadata.ObjectDescriptor;
30  import org.djutils.rmi.RMIUtils;
31  import org.junit.Test;
32  
33  /**
34   * RemoteEventTest makes some very basic tests for the RemoteEventListener and RemoteEventProducer.
35   * <p>
36   * Copyright (c) 2019-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
37   * BSD-style license. See <a href="https://djutils.org/docs/current/djutils/licenses.html">DJUTILS License</a>.
38   * <p>
39   * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
40   */
41  public class RemoteEventPubSubTest
42  {
43      /**
44       * Test the construction of the RemoteEventListsner and RemoteEventProducer.
45       * @throws RemoteException on remote error
46       * @throws AlreadyBoundException when producer or listener is already bound in the RMI registry
47       * @throws MalformedURLException on URL error
48       */
49      @Test
50      public void testRemoteEventListenerProducer() throws RemoteException, AlreadyBoundException, MalformedURLException
51      {
52          TestRemoteEventProducer producer = new TestRemoteEventProducer();
53          try
54          {
55              TestRemoteEventListener listener = new TestRemoteEventListener("listener");
56              assertFalse(producer.hasListeners());
57              assertEquals(0, producer.numberOfListeners(TestRemoteEventProducer.REMOTE_EVENT_1));
58              assertEquals(0, producer.getEventTypesWithListeners().size());
59              assertEquals(0, producer.getListenerReferences(TestRemoteEventProducer.REMOTE_EVENT_1).size());
60              boolean addListenerOK = producer.addListener(listener, TestRemoteEventProducer.REMOTE_EVENT_1);
61              assertTrue(addListenerOK);
62              assertTrue(producer.hasListeners());
63              assertEquals(1, producer.numberOfListeners(TestRemoteEventProducer.REMOTE_EVENT_1));
64              assertEquals(1, producer.getEventTypesWithListeners().size());
65              assertEquals(1, producer.getListenerReferences(TestRemoteEventProducer.REMOTE_EVENT_1).size());
66              assertEquals(listener, producer.getListenerReferences(TestRemoteEventProducer.REMOTE_EVENT_1).get(0).get());
67  
68              String string = "abc123";
69              listener.setExpectedObject(string);
70              producer.fireEvent(new Event(TestRemoteEventProducer.REMOTE_EVENT_1, producer, string));
71              assertEquals(string, listener.getReceivedEvent().getContent());
72              assertEquals(TestRemoteEventProducer.REMOTE_EVENT_1, listener.getReceivedEvent().getType());
73              assertEquals(producer, listener.getReceivedEvent().getSourceId());
74  
75              listener.setExpectedObject(Boolean.valueOf(true));
76              producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, true);
77              listener.setExpectedObject(Boolean.valueOf(false));
78              producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, false);
79  
80              listener.setExpectedObject(Byte.valueOf((byte) 87));
81              producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, (byte) 87);
82  
83              listener.setExpectedObject(Character.valueOf('a'));
84              producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, 'a');
85  
86              listener.setExpectedObject(Short.valueOf((short) -234));
87              producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, (short) -234);
88  
89              listener.setExpectedObject(Float.valueOf(458.9f));
90              producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, 458.9f);
91  
92              listener.setExpectedObject(Double.valueOf(123.456d));
93              producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, 123.456d);
94  
95              listener.setExpectedObject(Integer.valueOf(12345));
96              producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, 12345);
97  
98              listener.setExpectedObject(Long.valueOf(123456L));
99              producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, 123456L);
100 
101             listener.setExpectedObject("abcde");
102             producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, "abcde");
103 
104             listener.setExpectedObject(null);
105             producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1);
106 
107             // remove listener tests
108             producer.removeListener(listener, TestRemoteEventProducer.REMOTE_EVENT_2);
109             listener.setExpectedObject(Byte.valueOf((byte) 87));
110             producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, (byte) 87);
111 
112             producer.removeListener(listener, TestRemoteEventProducer.REMOTE_EVENT_1);
113             listener.setExpectingNotification(false);
114             producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, 12345);
115 
116             addListenerOK = producer.addListener(listener, TestRemoteEventProducer.REMOTE_EVENT_2);
117             assertTrue(addListenerOK);
118             addListenerOK = producer.addListener(listener, TestRemoteEventProducer.REMOTE_EVENT_1);
119             assertTrue(addListenerOK);
120             listener.setExpectingNotification(true);
121             listener.setExpectedObject(Double.valueOf(123.456d));
122             producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, 123.456d);
123             assertEquals(TestRemoteEventProducer.REMOTE_EVENT_1, listener.getReceivedEvent().getType());
124             listener.setExpectedObject(Double.valueOf(234.567d));
125             producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_2, 234.567d);
126             assertEquals(TestRemoteEventProducer.REMOTE_EVENT_2, listener.getReceivedEvent().getType());
127 
128             int nrRemovedListeners = producer.removeAllListeners();
129             assertEquals(2, nrRemovedListeners);
130             listener.setExpectingNotification(false);
131             listener.setExpectedObject(Byte.valueOf((byte) 87));
132             producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, (byte) 87);
133             producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_2, 12345);
134 
135             addListenerOK = producer.addListener(listener, TestRemoteEventProducer.REMOTE_EVENT_2);
136             assertTrue(addListenerOK);
137             addListenerOK = producer.addListener(listener, TestRemoteEventProducer.REMOTE_EVENT_1);
138             assertTrue(addListenerOK);
139             listener.setExpectingNotification(true);
140             listener.setExpectedObject(Double.valueOf(123.456d));
141             producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, 123.456d);
142             assertEquals(TestRemoteEventProducer.REMOTE_EVENT_1, listener.getReceivedEvent().getType());
143             listener.setExpectedObject(Double.valueOf(234.567d));
144             producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_2, 234.567d);
145             assertEquals(TestRemoteEventProducer.REMOTE_EVENT_2, listener.getReceivedEvent().getType());
146 
147             TestRemoteTimedEventListener<Double> timedListener = new TestRemoteTimedEventListener<>("timedListener");
148             addListenerOK = producer.addListener(timedListener, TestRemoteEventProducer.TIMED_REMOTE_EVENT_1);
149             assertTrue(addListenerOK);
150             timedListener.setExpectingNotification(true);
151             timedListener.setExpectedObject(Double.valueOf(12.34d));
152             listener.setExpectedObject(Double.valueOf(12.34d));
153             producer.fireTimedEvent(new TimedEvent<Double>(TestRemoteEventProducer.TIMED_REMOTE_EVENT_1, producer,
154                     Double.valueOf(12.34d), 12.01d));
155             assertEquals(12.01, timedListener.getReceivedEvent().getTimeStamp(), 0.001);
156 
157             nrRemovedListeners = producer.removeAllListeners(TestRemoteEventListener.class);
158             assertEquals(2, nrRemovedListeners);
159             listener.setExpectingNotification(false);
160             timedListener.setExpectingNotification(true);
161             timedListener.setExpectedObject(Byte.valueOf((byte) 87));
162             producer.fireTimedEvent(TestRemoteEventProducer.TIMED_REMOTE_EVENT_1, (byte) 87, Double.valueOf(13.02d));
163             assertEquals(13.02, timedListener.getReceivedEvent().getTimeStamp(), 0.001);
164 
165             nrRemovedListeners = producer.removeAllListeners();
166             assertEquals(1, nrRemovedListeners);
167         }
168         catch (RemoteException | AlreadyBoundException exception)
169         {
170             throw exception;
171         }
172         finally
173         {
174             // clean up the registry
175             RMIUtils.closeRegistry(producer.getRegistry());
176         }
177     }
178 
179     /**
180      * Test the RemoteEventProducer and RemoteEventListener for verified / unverified events.
181      * @throws RemoteException on remote error
182      * @throws AlreadyBoundException when producer or listener is already bound in the RMI registry
183      * @throws MalformedURLException on URL error
184      */
185     @Test
186     @SuppressWarnings("checkstyle:methodlength")
187     public void testRemoteEventVerificationPubSub() throws RemoteException, AlreadyBoundException, MalformedURLException
188     {
189         TestRemoteEventProducer producer = new TestRemoteEventProducer();
190         try
191         {
192             TestRemoteEventListener listener = new TestRemoteEventListener("listener");
193             EventType eventType = new EventType("STRING_TYPE",
194                     new MetaData("STRING", "string", new ObjectDescriptor("String", "string", String.class)));
195 
196             boolean addListenerOK = producer.addListener(listener, eventType);
197             assertTrue(addListenerOK);
198 
199             Try.testFail(new Try.Execution()
200             {
201                 @Override
202                 public void execute() throws Throwable
203                 {
204                     listener.setExpectedObject(Boolean.valueOf(true));
205                     producer.fireEvent(eventType, true);
206                 }
207             }, "expected ClassCastException", ClassCastException.class);
208 
209             Try.testFail(new Try.Execution()
210             {
211                 @Override
212                 public void execute() throws Throwable
213                 {
214                     listener.setExpectedObject(Byte.valueOf((byte) 87));
215                     producer.fireEvent(eventType, (byte) 87);
216                 }
217             }, "expected ClassCastException", ClassCastException.class);
218 
219             Try.testFail(new Try.Execution()
220             {
221                 @Override
222                 public void execute() throws Throwable
223                 {
224                     listener.setExpectedObject(Character.valueOf('a'));
225                     producer.fireEvent(eventType, 'a');
226                 }
227             }, "expected ClassCastException", ClassCastException.class);
228 
229             Try.testFail(new Try.Execution()
230             {
231                 @Override
232                 public void execute() throws Throwable
233                 {
234                     listener.setExpectedObject(Short.valueOf((short) -234));
235                     producer.fireEvent(eventType, (short) -234);
236                 }
237             }, "expected ClassCastException", ClassCastException.class);
238 
239             Try.testFail(new Try.Execution()
240             {
241                 @Override
242                 public void execute() throws Throwable
243                 {
244                     listener.setExpectedObject(Float.valueOf(458.9f));
245                     producer.fireEvent(eventType, 458.9f);
246                 }
247             }, "expected ClassCastException", ClassCastException.class);
248 
249             Try.testFail(new Try.Execution()
250             {
251                 @Override
252                 public void execute() throws Throwable
253                 {
254                     listener.setExpectedObject(Double.valueOf(123.456d));
255                     producer.fireEvent(eventType, 123.456d);
256                 }
257             }, "expected ClassCastException", ClassCastException.class);
258 
259             Try.testFail(new Try.Execution()
260             {
261                 @Override
262                 public void execute() throws Throwable
263                 {
264                     listener.setExpectedObject(Integer.valueOf(12345));
265                     producer.fireEvent(eventType, 12345);
266                 }
267             }, "expected ClassCastException", ClassCastException.class);
268 
269             Try.testFail(new Try.Execution()
270             {
271                 @Override
272                 public void execute() throws Throwable
273                 {
274                     listener.setExpectedObject(Long.valueOf(123456L));
275                     producer.fireEvent(eventType, 123456L);
276                 }
277             }, "expected ClassCastException", ClassCastException.class);
278 
279             Try.testFail(new Try.Execution()
280             {
281                 @Override
282                 public void execute() throws Throwable
283                 {
284                     listener.setExpectedObject(new String[] {"a", "b"});
285                     producer.fireEvent(eventType, new String[] {"a", "b"});
286                 }
287             }, "expected IndexOutOfBoundsException", IndexOutOfBoundsException.class);
288 
289             Try.testFail(new Try.Execution()
290             {
291                 @Override
292                 public void execute() throws Throwable
293                 {
294                     listener.setExpectedObject(Double.valueOf(1.2));
295                     producer.fireEvent(eventType, Double.valueOf(1.2));
296                 }
297             }, "expected ClassCastException", ClassCastException.class);
298 
299             listener.setExpectedObject("abc");
300             producer.fireUnverifiedEvent(new Event(eventType, producer, "abc"));
301 
302             listener.setExpectedObject(Boolean.valueOf(true));
303             producer.fireUnverifiedEvent(eventType, true);
304 
305             listener.setExpectedObject(Byte.valueOf((byte) 87));
306             producer.fireUnverifiedEvent(eventType, (byte) 87);
307 
308             listener.setExpectedObject(Character.valueOf('a'));
309             producer.fireUnverifiedEvent(eventType, 'a');
310 
311             listener.setExpectedObject(Short.valueOf((short) -234));
312             producer.fireUnverifiedEvent(eventType, (short) -234);
313 
314             listener.setExpectedObject(Float.valueOf(458.9f));
315             producer.fireUnverifiedEvent(eventType, 458.9f);
316 
317             listener.setExpectedObject(Double.valueOf(123.456d));
318             producer.fireUnverifiedEvent(eventType, 123.456d);
319 
320             listener.setExpectedObject(Integer.valueOf(12345));
321             producer.fireUnverifiedEvent(eventType, 12345);
322 
323             listener.setExpectedObject(Long.valueOf(123456L));
324             producer.fireUnverifiedEvent(eventType, 123456L);
325 
326             listener.setExpectedObject(new String[] {"a", "b"});
327             producer.fireUnverifiedEvent(eventType, new String[] {"a", "b"});
328 
329             listener.setExpectedObject(Double.valueOf(1.2));
330             producer.fireUnverifiedEvent(eventType, Double.valueOf(1.2));
331 
332             listener.setExpectedObject(null);
333             producer.fireUnverifiedEvent(eventType);
334 
335             producer.removeAllListeners();
336         }
337         catch (RemoteException | AlreadyBoundException exception)
338         {
339             throw exception;
340         }
341         finally
342         {
343             // clean up the registry
344             RMIUtils.closeRegistry(producer.getRegistry());
345         }
346     }
347 
348     /**
349      * Test the construction of the RemoteEventListsner and RemoteEventProducer.
350      * @throws RemoteException on remote error
351      * @throws AlreadyBoundException when producer or listener is already bound in the RMI registry
352      * @throws MalformedURLException on URL error
353      */
354     @Test
355     public void testTimedRemoteEventListenerProducer() throws RemoteException, AlreadyBoundException, MalformedURLException
356     {
357         TestRemoteEventProducer producer = new TestRemoteEventProducer();
358         try
359         {
360             TestRemoteTimedEventListener<Double> timedListener = new TestRemoteTimedEventListener<>("timedListener");
361             TimedEventType timedEventType = new TimedEventType("TIMED_TEST_TYPE", MetaData.NO_META_DATA);
362 
363             boolean addListenerOK = producer.addListener(timedListener, timedEventType);
364             assertTrue(addListenerOK);
365 
366             String string = "abc123";
367             timedListener.setExpectedObject(string);
368             producer.fireTimedEvent(new TimedEvent<Double>(timedEventType, producer, string, 12.01d));
369             assertEquals(string, timedListener.getReceivedEvent().getContent());
370             assertEquals(timedEventType, timedListener.getReceivedEvent().getType());
371             assertEquals(producer, timedListener.getReceivedEvent().getSourceId());
372             assertEquals(12.01d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
373 
374             timedListener.setExpectedObject(Boolean.valueOf(true));
375             producer.fireTimedEvent(timedEventType, true, Double.valueOf(12.02d));
376             assertEquals(12.02d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
377             timedListener.setExpectedObject(Boolean.valueOf(false));
378             producer.fireTimedEvent(timedEventType, false, Double.valueOf(12.03d));
379             assertEquals(12.03d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
380 
381             timedListener.setExpectedObject(Byte.valueOf((byte) 87));
382             producer.fireTimedEvent(timedEventType, (byte) 87, Double.valueOf(12.04d));
383             assertEquals(12.04d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
384 
385             timedListener.setExpectedObject(Character.valueOf('X'));
386             producer.fireTimedEvent(timedEventType, 'X', Double.valueOf(12.14d));
387             assertEquals(12.14d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
388 
389             timedListener.setExpectedObject(Short.valueOf((short) -234));
390             producer.fireTimedEvent(timedEventType, (short) -234, Double.valueOf(12.05d));
391             assertEquals(12.05d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
392 
393             timedListener.setExpectedObject(Float.valueOf(246.8f));
394             producer.fireTimedEvent(timedEventType, 246.8f, Double.valueOf(12.15d));
395             assertEquals(12.15d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
396 
397             timedListener.setExpectedObject(Double.valueOf(123.456d));
398             producer.fireTimedEvent(timedEventType, 123.456d, Double.valueOf(12.06d));
399             assertEquals(12.06d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
400 
401             timedListener.setExpectedObject(Integer.valueOf(12345));
402             producer.fireTimedEvent(timedEventType, 12345, Double.valueOf(12.07d));
403             assertEquals(12.07d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
404 
405             timedListener.setExpectedObject(Long.valueOf(123456L));
406             producer.fireTimedEvent(timedEventType, 123456L, Double.valueOf(12.08d));
407             assertEquals(12.08d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
408 
409             timedListener.setExpectedObject(null);
410             producer.fireTimedEvent(timedEventType, null, Double.valueOf(12.09d));
411             assertEquals(12.09d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
412 
413             timedListener.setExpectedObject("abc");
414             producer.fireUnverifiedTimedEvent(new TimedEvent<Double>(timedEventType, producer, "abc", Double.valueOf(12.10d)));
415             assertEquals(12.10d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
416 
417             timedListener.setExpectedObject(null);
418             producer.fireUnverifiedTimedEvent(timedEventType, Double.valueOf(12.11d));
419             assertEquals(12.11d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
420 
421             producer.removeAllListeners();
422         }
423         catch (RemoteException | AlreadyBoundException | MalformedURLException exception)
424         {
425             throw exception;
426         }
427         finally
428         {
429             // clean up the registry
430             RMIUtils.closeRegistry(producer.getRegistry());
431         }
432     }
433 
434     /**
435      * Test the RemoteEventProducer and RemoteTimedEventListener for verified / unverified events.
436      * @throws RemoteException on remote error
437      * @throws AlreadyBoundException when producer or listener is already bound in the RMI registry
438      * @throws MalformedURLException on URL error
439      */
440     @Test
441     @SuppressWarnings("checkstyle:methodlength")
442     public void testRemoteTimedEventVerificationPubSub() throws RemoteException, AlreadyBoundException, MalformedURLException
443     {
444         TestRemoteEventProducer producer = new TestRemoteEventProducer();
445         try
446         {
447             TestRemoteTimedEventListener<Double> timedListener = new TestRemoteTimedEventListener<>("listener");
448             TimedEventType timedEventType = new TimedEventType("TIMED_STRING_TYPE",
449                     new MetaData("STRING", "string", new ObjectDescriptor("String", "string", String.class)));
450 
451             boolean addListenerOK = producer.addListener(timedListener, timedEventType);
452             assertTrue(addListenerOK);
453 
454             Try.testFail(new Try.Execution()
455             {
456                 @Override
457                 public void execute() throws Throwable
458                 {
459                     timedListener.setExpectedObject(Boolean.valueOf(true));
460                     producer.fireTimedEvent(timedEventType, true, Double.valueOf(12.01d));
461                 }
462             }, "expected ClassCastException", ClassCastException.class);
463 
464             Try.testFail(new Try.Execution()
465             {
466                 @Override
467                 public void execute() throws Throwable
468                 {
469                     timedListener.setExpectedObject(Byte.valueOf((byte) 87));
470                     producer.fireTimedEvent(timedEventType, (byte) 87, Double.valueOf(12.02d));
471                 }
472             }, "expected ClassCastException", ClassCastException.class);
473 
474             Try.testFail(new Try.Execution()
475             {
476                 @Override
477                 public void execute() throws Throwable
478                 {
479                     timedListener.setExpectedObject(Character.valueOf('a'));
480                     producer.fireTimedEvent(timedEventType, 'a', Double.valueOf(12.03d));
481                 }
482             }, "expected ClassCastException", ClassCastException.class);
483 
484             Try.testFail(new Try.Execution()
485             {
486                 @Override
487                 public void execute() throws Throwable
488                 {
489                     timedListener.setExpectedObject(Short.valueOf((short) -234));
490                     producer.fireTimedEvent(timedEventType, (short) -234, Double.valueOf(12.04d));
491                 }
492             }, "expected ClassCastException", ClassCastException.class);
493 
494             Try.testFail(new Try.Execution()
495             {
496                 @Override
497                 public void execute() throws Throwable
498                 {
499                     timedListener.setExpectedObject(Float.valueOf(458.9f));
500                     producer.fireTimedEvent(timedEventType, 458.9f, Double.valueOf(12.05d));
501                 }
502             }, "expected ClassCastException", ClassCastException.class);
503 
504             Try.testFail(new Try.Execution()
505             {
506                 @Override
507                 public void execute() throws Throwable
508                 {
509                     timedListener.setExpectedObject(Double.valueOf(123.456d));
510                     producer.fireTimedEvent(timedEventType, 123.456d, Double.valueOf(12.06d));
511                 }
512             }, "expected ClassCastException", ClassCastException.class);
513 
514             Try.testFail(new Try.Execution()
515             {
516                 @Override
517                 public void execute() throws Throwable
518                 {
519                     timedListener.setExpectedObject(Integer.valueOf(12345));
520                     producer.fireTimedEvent(timedEventType, 12345, Double.valueOf(12.07d));
521                 }
522             }, "expected ClassCastException", ClassCastException.class);
523 
524             Try.testFail(new Try.Execution()
525             {
526                 @Override
527                 public void execute() throws Throwable
528                 {
529                     timedListener.setExpectedObject(Long.valueOf(123456L));
530                     producer.fireTimedEvent(timedEventType, 123456L, Double.valueOf(12.08d));
531                 }
532             }, "expected ClassCastException", ClassCastException.class);
533 
534             Try.testFail(new Try.Execution()
535             {
536                 @Override
537                 public void execute() throws Throwable
538                 {
539                     timedListener.setExpectedObject(new String[] {"a", "b"});
540                     producer.fireTimedEvent(timedEventType, new String[] {"a", "b"}, Double.valueOf(12.09d));
541                 }
542             }, "expected IndexOutOfBoundsException", IndexOutOfBoundsException.class);
543 
544             Try.testFail(new Try.Execution()
545             {
546                 @Override
547                 public void execute() throws Throwable
548                 {
549                     timedListener.setExpectedObject(Double.valueOf(1.2));
550                     producer.fireTimedEvent(timedEventType, Double.valueOf(1.2), Double.valueOf(12.10d));
551                 }
552             }, "expected ClassCastException", ClassCastException.class);
553 
554             timedListener.setExpectedObject(Boolean.valueOf(true));
555             producer.fireUnverifiedTimedEvent(timedEventType, true, Double.valueOf(12.01d));
556             assertEquals(12.01d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
557 
558             timedListener.setExpectedObject(Byte.valueOf((byte) 87));
559             producer.fireUnverifiedTimedEvent(timedEventType, (byte) 87, Double.valueOf(12.02d));
560             assertEquals(12.02d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
561 
562             timedListener.setExpectedObject(Character.valueOf('a'));
563             producer.fireUnverifiedTimedEvent(timedEventType, 'a', Double.valueOf(12.03d));
564             assertEquals(12.03d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
565 
566             timedListener.setExpectedObject(Short.valueOf((short) -234));
567             producer.fireUnverifiedTimedEvent(timedEventType, (short) -234, Double.valueOf(12.04d));
568             assertEquals(12.04d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
569 
570             timedListener.setExpectedObject(Float.valueOf(458.9f));
571             producer.fireUnverifiedTimedEvent(timedEventType, 458.9f, Double.valueOf(12.05d));
572             assertEquals(12.05d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
573 
574             timedListener.setExpectedObject(Double.valueOf(123.456d));
575             producer.fireUnverifiedTimedEvent(timedEventType, 123.456d, Double.valueOf(12.06d));
576             assertEquals(12.06d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
577 
578             timedListener.setExpectedObject(Integer.valueOf(12345));
579             producer.fireUnverifiedTimedEvent(timedEventType, 12345, Double.valueOf(12.07d));
580             assertEquals(12.07d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
581 
582             timedListener.setExpectedObject(Long.valueOf(123456L));
583             producer.fireUnverifiedTimedEvent(timedEventType, 123456L, Double.valueOf(12.08d));
584             assertEquals(12.08d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
585 
586             timedListener.setExpectedObject(new String[] {"a", "b"});
587             producer.fireUnverifiedTimedEvent(timedEventType, new String[] {"a", "b"}, Double.valueOf(12.09d));
588             assertEquals(12.09d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
589 
590             timedListener.setExpectedObject(Double.valueOf(1.2));
591             producer.fireUnverifiedTimedEvent(timedEventType, Double.valueOf(1.2), Double.valueOf(12.10d));
592             assertEquals(12.10d, timedListener.getReceivedEvent().getTimeStamp().doubleValue(), 0.001);
593 
594             producer.removeAllListeners();
595         }
596         catch (RemoteException | AlreadyBoundException | MalformedURLException exception)
597         {
598             throw exception;
599         }
600         finally
601         {
602             // clean up the registry
603             RMIUtils.closeRegistry(producer.getRegistry());
604         }
605     }
606 
607     /**
608      * Test the EventProducer for strong and weak references, and for position information.
609      * @throws SecurityException on error retrieving listener map
610      * @throws NoSuchFieldException on error retrieving listener map
611      * @throws IllegalAccessException on error retrieving listener map
612      * @throws IllegalArgumentException on error retrieving listener map
613      * @throws RemoteException on network exception
614      * @throws AlreadyBoundException when RMI registry not cleaned
615      */
616     @Test
617     public void testEventStrongWeakPos() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException,
618             SecurityException, RemoteException, AlreadyBoundException
619     {
620         TestRemoteEventProducer producer = new TestRemoteEventProducer();
621         try
622         {
623             TestRemoteEventListener listener = new TestRemoteEventListener("listener");
624 
625             // test illegal parameters and null pointer exceptions in adding a listener
626             try
627             {
628                 producer.addListener(null, TestRemoteEventProducer.REMOTE_EVENT_1);
629                 fail("null listener should have thrown an exception");
630             }
631             catch (NullPointerException npe)
632             {
633                 // Ignore expected exception
634             }
635             boolean addListenerOK =
636                     producer.addListener(listener, TestRemoteEventProducer.REMOTE_EVENT_1, -10, ReferenceType.STRONG);
637             assertFalse(addListenerOK);
638             Try.testFail(new Try.Execution()
639             {
640                 @Override
641                 public void execute() throws Throwable
642                 {
643                     producer.addListener(listener, null);
644                 }
645             }, "expected NullPointerException", NullPointerException.class);
646             Try.testFail(new Try.Execution()
647             {
648                 @Override
649                 public void execute() throws Throwable
650                 {
651                     producer.addListener(listener, TestRemoteEventProducer.REMOTE_EVENT_1, null);
652                 }
653             }, "expected NullPointerException", NullPointerException.class);
654             Try.testFail(new Try.Execution()
655             {
656                 @Override
657                 public void execute() throws Throwable
658                 {
659                     producer.addListener(listener, TestRemoteEventProducer.REMOTE_EVENT_1, 0, null);
660                 }
661             }, "expected NullPointerException", NullPointerException.class);
662 
663             // test whether weak and strong calls to addListener work, and whether positions can be provided
664             assertFalse(producer.hasListeners());
665             assertEquals(0, producer.numberOfListeners(TestRemoteEventProducer.REMOTE_EVENT_1));
666             assertEquals(new LinkedHashSet<EventType>(), producer.getEventTypesWithListeners());
667 
668             addListenerOK = producer.addListener(listener, TestRemoteEventProducer.REMOTE_EVENT_1);
669             assertTrue(addListenerOK);
670             assertTrue(producer.hasListeners());
671             assertEquals(1, producer.numberOfListeners(TestRemoteEventProducer.REMOTE_EVENT_1));
672             assertEquals(new LinkedHashSet<EventType>(Arrays.asList(TestRemoteEventProducer.REMOTE_EVENT_1)),
673                     producer.getEventTypesWithListeners());
674 
675             addListenerOK = producer.addListener(listener, TestRemoteEventProducer.REMOTE_EVENT_2, ReferenceType.WEAK);
676             assertTrue(addListenerOK);
677             assertEquals(1, producer.numberOfListeners(TestRemoteEventProducer.REMOTE_EVENT_1));
678             assertEquals(1, producer.numberOfListeners(TestRemoteEventProducer.REMOTE_EVENT_2));
679             assertEquals(
680                     new LinkedHashSet<EventType>(
681                             Arrays.asList(TestRemoteEventProducer.REMOTE_EVENT_1, TestRemoteEventProducer.REMOTE_EVENT_2)),
682                     producer.getEventTypesWithListeners());
683 
684             // check false for adding same listener second time
685             addListenerOK = producer.addListener(listener, TestRemoteEventProducer.REMOTE_EVENT_2, ReferenceType.WEAK);
686             assertFalse(addListenerOK);
687             assertEquals(1, producer.numberOfListeners(TestRemoteEventProducer.REMOTE_EVENT_1));
688             assertEquals(1, producer.numberOfListeners(TestRemoteEventProducer.REMOTE_EVENT_2));
689             assertEquals(
690                     new LinkedHashSet<EventType>(
691                             Arrays.asList(TestRemoteEventProducer.REMOTE_EVENT_1, TestRemoteEventProducer.REMOTE_EVENT_2)),
692                     producer.getEventTypesWithListeners());
693 
694             // check LAST_POSITION and FIRST_POSITION
695             TestRemoteEventListener listener2 = new TestRemoteEventListener("listener2");
696             TestRemoteEventListener listener3 = new TestRemoteEventListener("listener3");
697             addListenerOK = producer.addListener(listener2, TestRemoteEventProducer.REMOTE_EVENT_2,
698                     EventProducerInterface.LAST_POSITION);
699             addListenerOK = producer.addListener(listener3, TestRemoteEventProducer.REMOTE_EVENT_2,
700                     EventProducerInterface.FIRST_POSITION);
701             assertEquals(3, producer.numberOfListeners(TestRemoteEventProducer.REMOTE_EVENT_2));
702 
703             // check whether positions have been inserted okay: listener3 - listener - listener2
704             List<Reference<EventListenerInterface>> listenerList =
705                     producer.getListenerReferences(TestRemoteEventProducer.REMOTE_EVENT_2);
706             assertEquals(3, listenerList.size());
707             assertEquals(listener3, listenerList.get(0).get());
708             assertEquals(listener, listenerList.get(1).get());
709             assertEquals(listener2, listenerList.get(2).get());
710 
711             producer.removeAllListeners();
712         }
713         catch (RemoteException | AlreadyBoundException exception)
714         {
715             throw exception;
716         }
717         finally
718         {
719             // clean up the registry
720             RMIUtils.closeRegistry(producer.getRegistry());
721         }
722     }
723 
724     /**
725      * Test the EventProducer for a weak reference that is removed by the garbage collector.
726      * @throws SecurityException on error retrieving listener map
727      * @throws NoSuchFieldException on error retrieving listener map
728      * @throws IllegalAccessException on error retrieving listener map
729      * @throws IllegalArgumentException on error retrieving listener map
730      * @throws RemoteException on network exception
731      * @throws AlreadyBoundException when RMI registry not cleaned
732      */
733     @Test
734     public void testEventProducerWeakRemoval() throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException,
735             SecurityException, RemoteException, AlreadyBoundException
736     {
737         TestRemoteEventProducer producer = new TestRemoteEventProducer();
738         try
739         {
740             TestRemoteEventListener listener = new TestRemoteEventListener("listener");
741             boolean addListenerOK = producer.addListener(listener, TestRemoteEventProducer.REMOTE_EVENT_1, ReferenceType.WEAK);
742             assertTrue(addListenerOK);
743             assertTrue(producer.hasListeners());
744             assertEquals(1, producer.numberOfListeners(TestRemoteEventProducer.REMOTE_EVENT_1));
745 
746             // fire an event -- should arrive
747             listener.setExpectingNotification(true);
748             listener.setExpectedObject(Integer.valueOf(12));
749             producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, 12);
750 
751             List<Reference<EventListenerInterface>> listenerList =
752                     producer.getListenerReferences(TestRemoteEventProducer.REMOTE_EVENT_1);
753             assertEquals(1, listenerList.size());
754             Reference<EventListenerInterface> ref = listenerList.get(0);
755             // simulate clearing by GC (the list is a safe copy, but the reference is original)
756             Field referent = ref.getClass().getDeclaredField("referent");
757             referent.setAccessible(true);
758             referent.set(ref, new java.lang.ref.WeakReference<EventListenerInterface>(null));
759             referent.setAccessible(false);
760 
761             // fire an event -- should not arrive
762             listener.setExpectingNotification(false);
763             producer.fireEvent(TestRemoteEventProducer.REMOTE_EVENT_1, 34);
764             assertFalse(producer.hasListeners());
765             assertEquals(0, producer.numberOfListeners(TestRemoteEventProducer.REMOTE_EVENT_1));
766 
767             producer.removeAllListeners();
768         }
769         catch (RemoteException | AlreadyBoundException exception)
770         {
771             throw exception;
772         }
773         finally
774         {
775             // clean up the registry
776             RMIUtils.closeRegistry(producer.getRegistry());
777         }
778     }
779 
780     /** */
781     protected static class TestRemoteEventProducer extends RemoteEventProducer
782     {
783         /** */
784         private static final long serialVersionUID = 20191230L;
785 
786         /** */
787         public static final EventType REMOTE_EVENT_1 = new EventType("REMOTE_EVENT_1", MetaData.NO_META_DATA);
788 
789         /** */
790         public static final EventType REMOTE_EVENT_2 = new EventType("REMOTE_EVENT_2", MetaData.NO_META_DATA);
791 
792         /** */
793         public static final TimedEventType TIMED_REMOTE_EVENT_1 =
794                 new TimedEventType("TIMED_REMOTE_EVENT_1", MetaData.NO_META_DATA);
795 
796         /**
797          * Construct a RemoteEventProducer.
798          * @throws RemoteException on error
799          * @throws AlreadyBoundException on error
800          */
801         public TestRemoteEventProducer() throws RemoteException, AlreadyBoundException
802         {
803             super("127.0.0.1", 1099, "producer");
804         }
805 
806         /** {@inheritDoc} */
807         @Override
808         public Serializable getSourceId()
809         {
810             return "producer";
811         }
812     }
813 
814     /** */
815     protected static class TestRemoteEventListener extends RemoteEventListener
816     {
817         /** */
818         private static final long serialVersionUID = 20191230L;
819 
820         /** expect notification or not. */
821         private boolean expectingNotification = true;
822 
823         /** expected object in notify. */
824         private Object expectedObject;
825 
826         /** received event. */
827         private EventInterface receivedEvent;
828 
829         /**
830          * @param key String; the key under which the listener will be registered in RMI
831          * @throws RemoteException on error
832          * @throws AlreadyBoundException on error
833          */
834         public TestRemoteEventListener(final String key) throws RemoteException, AlreadyBoundException
835         {
836             super("localhost", 1099, key);
837         }
838 
839         /**
840          * @param expectingNotification set expectingNotification
841          */
842         public void setExpectingNotification(final boolean expectingNotification)
843         {
844             this.expectingNotification = expectingNotification;
845         }
846 
847         /**
848          * @param expectedObject set expectedObject
849          */
850         public void setExpectedObject(final Object expectedObject)
851         {
852             this.expectedObject = expectedObject;
853         }
854 
855         /**
856          * @return receivedEvent
857          */
858         public EventInterface getReceivedEvent()
859         {
860             return this.receivedEvent;
861         }
862 
863         /** {@inheritDoc} */
864         @Override
865         public void notify(final EventInterface event) throws RemoteException
866         {
867             if (!this.expectingNotification)
868             {
869                 fail("Received event " + event + " unexpectedly");
870             }
871             this.receivedEvent = event;
872             if (this.expectedObject != null && event.getContent() != null && this.expectedObject.getClass().isArray()
873                     && event.getContent().getClass().isArray())
874             {
875                 Object[] e = (Object[]) this.expectedObject;
876                 Object[] r = (Object[]) event.getContent();
877                 assertEquals(e.length, r.length);
878                 for (int i = 0; i < e.length; i++)
879                 {
880                     assertEquals(e[i], r[i]);
881                 }
882             }
883             else
884             {
885                 assertEquals(this.expectedObject, event.getContent());
886             }
887         }
888     }
889 
890     /**
891      * RemoteTimedEventListener.
892      * @param <C> the comparable time type
893      */
894     protected static class TestRemoteTimedEventListener<C extends Comparable<C> & Serializable> extends RemoteEventListener
895     {
896         /** */
897         private static final long serialVersionUID = 20191230L;
898 
899         /** expect notification or not. */
900         private boolean expectingNotification = true;
901 
902         /** expected object in notify. */
903         private Object expectedObject;
904 
905         /** received event. */
906         private TimedEvent<C> receivedEvent;
907 
908         /**
909          * @param key String; key used to bind to the RMI registry
910          * @throws RemoteException on error
911          * @throws AlreadyBoundException on error
912          * @throws MalformedURLException on URL error
913          */
914         public TestRemoteTimedEventListener(final String key)
915                 throws RemoteException, AlreadyBoundException, MalformedURLException
916         {
917             super(new URL("http://127.0.0.1:1099"), key);
918         }
919 
920         /**
921          * @param expectingNotification set expectingNotification
922          */
923         public void setExpectingNotification(final boolean expectingNotification)
924         {
925             this.expectingNotification = expectingNotification;
926         }
927 
928         /**
929          * @param expectedObject set expectedObject
930          */
931         public void setExpectedObject(final Object expectedObject)
932         {
933             this.expectedObject = expectedObject;
934         }
935 
936         /**
937          * @return receivedEvent
938          */
939         public TimedEvent<C> getReceivedEvent()
940         {
941             return this.receivedEvent;
942         }
943 
944         /** {@inheritDoc} */
945         @SuppressWarnings("unchecked")
946         @Override
947         public void notify(final EventInterface event) throws RemoteException
948         {
949             if (!this.expectingNotification)
950             {
951                 fail("Received event " + event + " unexpectedly");
952             }
953             if (!(event instanceof TimedEvent))
954             {
955                 fail("Received event " + event + " is not a TimedEvent");
956             }
957             this.receivedEvent = (TimedEvent<C>) event;
958             if (this.expectedObject != null && event.getContent() != null && this.expectedObject.getClass().isArray()
959                     && event.getContent().getClass().isArray())
960             {
961                 Object[] e = (Object[]) this.expectedObject;
962                 Object[] r = (Object[]) event.getContent();
963                 assertEquals(e.length, r.length);
964                 for (int i = 0; i < e.length; i++)
965                 {
966                     assertEquals(e[i], r[i]);
967                 }
968             }
969             else
970             {
971                 assertEquals(this.expectedObject, event.getContent());
972             }
973         }
974     }
975 }