1 package org.djutils.rmi;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertNotEquals;
5 import static org.junit.Assert.assertNotNull;
6 import static org.junit.Assert.fail;
7
8 import java.net.InetAddress;
9 import java.net.MalformedURLException;
10 import java.net.URL;
11 import java.net.UnknownHostException;
12 import java.rmi.AccessException;
13 import java.rmi.AlreadyBoundException;
14 import java.rmi.NotBoundException;
15 import java.rmi.Remote;
16 import java.rmi.RemoteException;
17 import java.rmi.registry.Registry;
18 import java.util.LinkedHashSet;
19 import java.util.Set;
20
21 import org.djutils.exceptions.Try;
22 import org.djutils.logger.CategoryLogger;
23 import org.junit.Test;
24 import org.pmw.tinylog.Level;
25
26
27
28
29
30
31
32
33
34 public class RMITest
35 {
36
37
38
39
40
41
42 @SuppressWarnings("checkstyle:methodlength")
43 @Test
44 public void testRMIRegistry() throws RemoteException, AlreadyBoundException, NotBoundException
45 {
46 CategoryLogger.setAllLogLevel(Level.OFF);
47
48 Try.testFail(new Try.Execution()
49 {
50 @Override
51 public void execute() throws Throwable
52 {
53 RMIUtils.getRegistry(null, 1099);
54 }
55 }, "should have thrown NullPointerException", NullPointerException.class);
56 for (int port : new int[] {-1, 0, 100000, -10, 65536})
57 {
58 Try.testFail(new Try.Execution()
59 {
60 @Override
61 public void execute() throws Throwable
62 {
63 RMIUtils.getRegistry("localhost", port);
64 }
65 }, "should have thrown IllegalArgumentException", IllegalArgumentException.class);
66 }
67
68 Try.testFail(new Try.Execution()
69 {
70 @Override
71 public void execute() throws Throwable
72 {
73 RMIUtils.getRegistry("130.161.3.179", 41099);
74 }
75 }, "should have thrown RemoteException or AccessException", RemoteException.class);
76
77
78 Registry registry = RMIUtils.getRegistry("localhost", 1099);
79 assertNotNull(registry);
80 assertEquals(0, registry.list().length);
81
82
83 String key = "testKey";
84 RemoteObject remoteObject = new RemoteObject(key);
85 Try.testFail(new Try.Execution()
86 {
87 @Override
88 public void execute() throws Throwable
89 {
90 RMIUtils.bind(null, key, remoteObject);
91 }
92 }, "should have thrown NullPointerException", NullPointerException.class);
93 Try.testFail(new Try.Execution()
94 {
95 @Override
96 public void execute() throws Throwable
97 {
98 RMIUtils.bind(registry, null, remoteObject);
99 }
100 }, "should have thrown NullPointerException", NullPointerException.class);
101 Try.testFail(new Try.Execution()
102 {
103 @Override
104 public void execute() throws Throwable
105 {
106 RMIUtils.bind(registry, key, null);
107 }
108 }, "should have thrown NullPointerException", NullPointerException.class);
109 Try.testFail(new Try.Execution()
110 {
111 @Override
112 public void execute() throws Throwable
113 {
114 RMIUtils.bind(registry, "", remoteObject);
115 }
116 }, "should have thrown IllegalArgumentPointerException", IllegalArgumentException.class);
117
118
119 RMIUtils.bind(registry, key, remoteObject);
120 assertEquals(1, registry.list().length);
121 Try.testFail(new Try.Execution()
122 {
123 @Override
124 public void execute() throws Throwable
125 {
126 RMIUtils.bind(registry, key, remoteObject);
127 }
128 }, "should have thrown AlreadyBoundException", AlreadyBoundException.class);
129 assertEquals(1, registry.list().length);
130
131
132 Registry reg2 = RMIUtils.getRegistry("localhost", 1099);
133 assertNotNull(reg2);
134
135
136 assertEquals(1, reg2.list().length);
137
138
139 Try.testFail(new Try.Execution()
140 {
141 @Override
142 public void execute() throws Throwable
143 {
144 RMIUtils.lookup(null, key);
145 }
146 }, "should have thrown NullPointerException", NullPointerException.class);
147 Try.testFail(new Try.Execution()
148 {
149 @Override
150 public void execute() throws Throwable
151 {
152 RMIUtils.lookup(registry, null);
153 }
154 }, "should have thrown NullPointerException", NullPointerException.class);
155 Try.testFail(new Try.Execution()
156 {
157 @Override
158 public void execute() throws Throwable
159 {
160 RMIUtils.lookup(registry, "");
161 }
162 }, "should have thrown IllegalArgumentPointerException", IllegalArgumentException.class);
163
164
165 RemoteObject ro = (RemoteObject) RMIUtils.lookup(registry, key);
166 assertNotNull(ro);
167 assertEquals(remoteObject, ro);
168 assertEquals(key, ro.getName());
169
170
171 Try.testFail(new Try.Execution()
172 {
173 @Override
174 public void execute() throws Throwable
175 {
176 RMIUtils.rebind(null, key, remoteObject);
177 }
178 }, "should have thrown NullPointerException", NullPointerException.class);
179 Try.testFail(new Try.Execution()
180 {
181 @Override
182 public void execute() throws Throwable
183 {
184 RMIUtils.rebind(registry, null, remoteObject);
185 }
186 }, "should have thrown NullPointerException", NullPointerException.class);
187 Try.testFail(new Try.Execution()
188 {
189 @Override
190 public void execute() throws Throwable
191 {
192 RMIUtils.rebind(registry, key, null);
193 }
194 }, "should have thrown NullPointerException", NullPointerException.class);
195 Try.testFail(new Try.Execution()
196 {
197 @Override
198 public void execute() throws Throwable
199 {
200 RMIUtils.rebind(registry, "", remoteObject);
201 }
202 }, "should have thrown IllegalArgumentPointerException", IllegalArgumentException.class);
203
204
205 String otherKey = "otherKey";
206 RemoteObject otherObject = new RemoteObject(otherKey);
207 assertNotEquals(remoteObject, otherObject);
208 RMIUtils.rebind(registry, key, otherObject);
209 assertEquals(1, registry.list().length);
210 RemoteObject ro2 = (RemoteObject) registry.lookup(key);
211 assertNotNull(ro2);
212 assertEquals(otherObject, ro2);
213 assertNotEquals(key, ro2.getName());
214
215
216 Try.testFail(new Try.Execution()
217 {
218 @Override
219 public void execute() throws Throwable
220 {
221 RMIUtils.unbind(null, key);
222 }
223 }, "should have thrown NullPointerException", NullPointerException.class);
224 Try.testFail(new Try.Execution()
225 {
226 @Override
227 public void execute() throws Throwable
228 {
229 RMIUtils.unbind(registry, null);
230 }
231 }, "should have thrown NullPointerException", NullPointerException.class);
232 Try.testFail(new Try.Execution()
233 {
234 @Override
235 public void execute() throws Throwable
236 {
237 RMIUtils.unbind(registry, "");
238 }
239 }, "should have thrown IllegalArgumentPointerException", IllegalArgumentException.class);
240 Try.testFail(new Try.Execution()
241 {
242 @Override
243 public void execute() throws Throwable
244 {
245 RMIUtils.unbind(registry, otherKey);
246 }
247 }, "should have thrown NotBoundException", NotBoundException.class);
248
249
250 RMIUtils.rebind(registry, otherKey, remoteObject);
251 assertEquals(2, registry.list().length);
252 RMIUtils.unbind(registry, otherKey);
253 assertEquals(1, registry.list().length);
254
255
256 RMIUtils.closeRegistry(registry);
257 Try.testFail(new Try.Execution()
258 {
259 @Override
260 public void execute() throws Throwable
261 {
262 RMIUtils.lookup(registry, key);
263 }
264 }, "should have thrown an Exception");
265 Try.testFail(new Try.Execution()
266 {
267 @Override
268 public void execute() throws Throwable
269 {
270 RMIUtils.lookup(reg2, key);
271 }
272 });
273
274
275
276 Try.testFail(new Try.Execution()
277 {
278 @Override
279 public void execute() throws Throwable
280 {
281 RMIUtils.lookup(registry, key);
282 }
283 }, "did not get expected exception for lookup()");
284 Try.testFail(new Try.Execution()
285 {
286 @Override
287 public void execute() throws Throwable
288 {
289 RMIUtils.unbind(registry, key);
290 }
291 }, "did not get expected exception for unbind()");
292 Try.testFail(new Try.Execution()
293 {
294 @Override
295 public void execute() throws Throwable
296 {
297 RMIUtils.closeRegistry(registry);
298 }
299 }, "did not get expected exception for closeRegistry()");
300
301 CategoryLogger.setAllLogLevel(Level.INFO);
302 }
303
304
305
306
307
308
309 @Test
310 public void testRMIRegistryLocalHost() throws UnknownHostException
311 {
312 CategoryLogger.setAllLogLevel(Level.OFF);
313
314 for (String localHostName : new String[] {"localhost", "127.0.0.1", InetAddress.getLocalHost().getHostName(),
315 InetAddress.getLocalHost().getHostAddress()})
316 {
317 Registry registry = null;
318 try
319 {
320 registry = RMIUtils.getRegistry(localHostName, 1099);
321 }
322 catch (RemoteException exception)
323 {
324 fail("Creation of local registry failed for host " + localHostName + ", message was: "
325 + exception.getMessage());
326 }
327
328 try
329 {
330 assertNotNull(registry);
331 assertEquals(0, registry.list().length);
332 RMIUtils.closeRegistry(registry);
333 final Registry testRegistry = registry;
334 Try.testFail(new Try.Execution()
335 {
336 @Override
337 public void execute() throws Throwable
338 {
339 RMIUtils.lookup(testRegistry, "key");
340 }
341 }, "should have thrown an Exception");
342 }
343 catch (RemoteException exception)
344 {
345 fail("Access or closing of local registry failed for host " + localHostName + ", RemoteException message was: "
346 + exception.getMessage());
347 }
348 }
349
350 CategoryLogger.setAllLogLevel(Level.INFO);
351 }
352
353
354
355
356
357
358
359
360 @Test
361 public void testRMIObject() throws RemoteException, AlreadyBoundException, NotBoundException, MalformedURLException
362 {
363 CategoryLogger.setAllLogLevel(Level.OFF);
364
365
366 Producer producer = new Producer();
367 assertNotNull(producer);
368
369
370 final Listener[] listeners = new Listener[1];
371 listeners[0] = null;
372 Thread thread = new Thread(new Runnable()
373 {
374 @Override
375 public void run()
376 {
377 Listener listener = null;
378 try
379 {
380 listener = new Listener("listener");
381 }
382 catch (RemoteException | AlreadyBoundException | NotBoundException exception)
383 {
384 exception.printStackTrace();
385 fail(exception.getMessage());
386 }
387 assertNotNull(listener);
388 listeners[0] = listener;
389 }
390 });
391 thread.start();
392 int counter = 0;
393 while (listeners[0] == null && counter < 10)
394 {
395 try
396 {
397 Thread.sleep(100);
398 }
399 catch (InterruptedException e)
400 {
401
402 }
403 counter++;
404 }
405 if (counter >= 10)
406 {
407 fail("Could not start listener");
408 }
409 Listener listener = listeners[0];
410 listener.setLastMessage("");
411 producer.fire("test");
412 assertEquals("test", listener.getLastMessage());
413
414
415 Registry registry = producer.getRegistry();
416 RMIUtils.closeRegistry(registry);
417
418
419 Try.testFail(new Try.Execution()
420 {
421 @Override
422 public void execute() throws Throwable
423 {
424 new Producer(null, "producer");
425 }
426 }, "did not get expected exception", NullPointerException.class);
427 Try.testFail(new Try.Execution()
428 {
429 @Override
430 public void execute() throws Throwable
431 {
432 new Producer(new URL("http://localhost:1099"), null);
433 }
434 }, "did not get expected exception", NullPointerException.class);
435 Try.testFail(new Try.Execution()
436 {
437 @Override
438 public void execute() throws Throwable
439 {
440 new Producer(null, 1099, "producer");
441 }
442 }, "did not get expected exception", NullPointerException.class);
443 Try.testFail(new Try.Execution()
444 {
445 @Override
446 public void execute() throws Throwable
447 {
448 new Producer("localhost", -2, "producer");
449 }
450 }, "did not get expected exception", IllegalArgumentException.class);
451 Try.testFail(new Try.Execution()
452 {
453 @Override
454 public void execute() throws Throwable
455 {
456 new Producer("localhost", 1099, null);
457 }
458 }, "did not get expected exception", NullPointerException.class);
459
460
461 producer = new Producer(new URL("http", null, ""), "producer");
462 assertNotNull(producer);
463 assertNotNull(producer.getRegistry());
464 RMIUtils.closeRegistry(producer.getRegistry());
465 sleep(200);
466 producer = new Producer(new URL("http://127.0.0.1:1099"), "producer");
467 assertNotNull(producer);
468 assertNotNull(producer.getRegistry());
469 RMIUtils.closeRegistry(producer.getRegistry());
470 sleep(200);
471 producer = new Producer(new URL("http://localhost:1099"), "producer");
472 assertNotNull(producer);
473 assertNotNull(producer.getRegistry());
474 RMIUtils.closeRegistry(producer.getRegistry());
475 sleep(200);
476
477 CategoryLogger.setAllLogLevel(Level.INFO);
478 }
479
480
481
482
483 private static void sleep(final int msec)
484 {
485 try
486 {
487 Thread.sleep(msec);
488 }
489 catch (Exception exception)
490 {
491
492 }
493 }
494
495
496 protected static class RemoteObject implements Remote
497 {
498
499 private final String name;
500
501
502
503
504
505
506 public RemoteObject(final String name) throws RemoteException
507 {
508 this.name = name;
509 }
510
511
512
513
514 public String getName()
515 {
516 return this.name;
517 }
518
519
520 @Override
521 public int hashCode()
522 {
523 final int prime = 31;
524 int result = 1;
525 result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());
526 return result;
527 }
528
529
530 @SuppressWarnings("checkstyle:needbraces")
531 @Override
532 public boolean equals(final Object obj)
533 {
534 if (this == obj)
535 return true;
536 if (obj == null)
537 return false;
538 if (getClass() != obj.getClass())
539 return false;
540 RemoteObject other = (RemoteObject) obj;
541 if (this.name == null)
542 {
543 if (other.name != null)
544 return false;
545 }
546 else if (!this.name.equals(other.name))
547 return false;
548 return true;
549 }
550 }
551
552
553 public interface ListenerInterface extends Remote
554 {
555
556
557
558
559
560 String getName() throws RemoteException;
561
562
563
564
565
566
567 void notify(String payload) throws RemoteException;
568 }
569
570
571 public interface ProducerInterface extends Remote
572 {
573
574
575
576
577
578 void addListener(ListenerInterface listener) throws RemoteException;
579 }
580
581
582 public class Producer extends RMIObject implements ProducerInterface
583 {
584
585 private static final long serialVersionUID = 1L;
586
587
588 private Set<ListenerInterface> listeners = new LinkedHashSet<>();
589
590
591
592
593
594
595 public Producer() throws RemoteException, AlreadyBoundException
596 {
597 super("localhost", 1099, "producer");
598 }
599
600
601
602
603
604
605
606
607
608
609
610
611 public Producer(final String host, final int port, final String bindingKey)
612 throws RemoteException, AlreadyBoundException
613 {
614 super(host, port, bindingKey);
615 }
616
617
618
619
620
621
622
623
624
625
626 public Producer(final URL registryURL, final String bindingKey) throws RemoteException, AlreadyBoundException
627 {
628 super(registryURL, bindingKey);
629 }
630
631
632 @Override
633 public void addListener(final ListenerInterface listener) throws RemoteException
634 {
635 this.listeners.add(listener);
636 }
637
638
639
640
641
642
643 protected void fire(final String payload) throws RemoteException
644 {
645 for (ListenerInterface listener : this.listeners)
646 {
647 try
648 {
649 listener.notify(payload);
650 }
651 catch (Exception e)
652 {
653 fail("Notifying listener failed");
654 }
655 }
656 }
657 }
658
659
660 public class Listener extends RMIObject implements ListenerInterface
661 {
662
663 private static final long serialVersionUID = 1L;
664
665
666 private final String listenerName;
667
668
669 private String lastMessage;
670
671
672
673
674
675
676
677
678 public Listener(final String listenerName) throws RemoteException, AlreadyBoundException, NotBoundException
679 {
680 super("localhost", 1099, listenerName);
681 this.listenerName = listenerName;
682 ProducerInterface producer = (ProducerInterface) RMIUtils.lookup(getRegistry(), "producer");
683 producer.addListener(this);
684 }
685
686
687 @Override
688 public String getName() throws RemoteException
689 {
690 return this.listenerName;
691 }
692
693
694 @Override
695 public void notify(final String payload) throws RemoteException
696 {
697 this.lastMessage = payload;
698 }
699
700
701
702
703 public String getListenerName()
704 {
705 return this.listenerName;
706 }
707
708
709
710
711 public String getLastMessage()
712 {
713 return this.lastMessage;
714 }
715
716
717
718
719 public void setLastMessage(final String lastMessage)
720 {
721 this.lastMessage = lastMessage;
722 }
723 }
724
725 }