1
2
3
4
5
6
7 package nl.tudelft.simulation.event;
8
9 import java.io.IOException;
10 import java.io.ObjectOutputStream;
11 import java.io.Serializable;
12 import java.lang.reflect.Field;
13 import java.rmi.RemoteException;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.Collections;
17 import java.util.HashMap;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22
23 import nl.tudelft.simulation.event.ref.Reference;
24 import nl.tudelft.simulation.event.ref.StrongReference;
25 import nl.tudelft.simulation.event.ref.WeakReference;
26
27 /***
28 * The EventProducer forms the reference implementation of the
29 * EventProducerInterface. Objects extending this class are provided all the
30 * functionalities for registration and event firering.
31 * <p>
32 * (c) copyright 2002-2005 <a href="http://www.simulation.tudelft.nl">Delft
33 * University of Technology </a>, the Netherlands.
34 * <p>
35 * See for project information <a
36 * href="http://www.simulation.tudelft.nl/dsol/event">www.simulation.tudelft.nl/event
37 * </a> <br>
38 * License of use: <a href="http://www.gnu.org/copyleft/lesser.html">Lesser
39 * General Public License (LGPL) </a>, no warranty
40 *
41 * @author <a href="http://www.peter-jacobs.com">Peter Jacobs </a>
42 * @version $Revision: 1.8 $ $Date: 2005/08/04 12:08:32 $
43 * @since 1.5
44 */
45 public abstract class EventProducer implements EventProducerInterface,
46 Serializable {
47 /*** listeners is the collection of interested listeners */
48 protected Map<EventType, Reference<EventListenerInterface>[]> listeners = Collections
49 .synchronizedMap(new EventListenerMap<EventType, Reference<EventListenerInterface>[]>());
50
51 /***
52 * the semaphore used to lock on while performing thread sensitive
53 * operations.
54 */
55 private transient Object semaphore = new Object();
56
57 /*** the cache to prevent continuous reflection */
58 private transient EventType[] cache = null;
59
60 /***
61 * checks whether no duplicate short values are assigned to the producer. An
62 * eventproducer produces events of a certain eventType. This eventType
63 * functions as a marker for registration. If the eventProducer defines two
64 * eventTypes with an equal value, the marker function is lost. This method
65 * checks for this particular problem.
66 *
67 * @return returns whether every eventType in this class is unique.
68 */
69 private boolean checkEventType() {
70 EventType[] events = this.getEventTypes();
71 for (int i = 0; i < events.length; i++) {
72 for (int j = 0; j < events.length; j++) {
73 if (i != j && events[i].equals(events[j])) {
74 return false;
75 }
76 }
77 }
78 return true;
79 }
80
81 /***
82 * constructs a new EventProducer and checks for double values in events
83 */
84 public EventProducer() {
85 super();
86 if (!this.checkEventType()) {
87 throw new RuntimeException("EventProducer failed: "
88 + "more events have the same short value");
89 }
90 }
91
92 /***
93 * adds the listener as weak reference to the listener.
94 *
95 * @see nl.tudelft.simulation.event.EventProducerInterface
96 * #addListener(EventListenerInterface, EventType)
97 */
98 public synchronized boolean addListener(
99 final EventListenerInterface listener, final EventType eventType) {
100 return this.addListener(listener, eventType,
101 EventProducerInterface.FIRST_POSITION);
102 }
103
104 /***
105 * @see nl.tudelft.simulation.event.EventProducerInterface
106 * #addListener(nl.tudelft.simulation.event.EventListenerInterface,
107 * nl.tudelft.simulation.event.EventType, boolean)
108 */
109 public synchronized boolean addListener(
110 final EventListenerInterface listener, final EventType eventType,
111 final boolean weak) {
112 return this.addListener(listener, eventType,
113 EventProducerInterface.FIRST_POSITION, weak);
114 }
115
116 /***
117 * adds the listener as weak reference to the listener.
118 *
119 * @see nl.tudelft.simulation.event.EventProducerInterface
120 * #addListener(nl.tudelft.simulation.event.EventListenerInterface,
121 * nl.tudelft.simulation.event.EventType, short)
122 */
123 public synchronized boolean addListener(
124 final EventListenerInterface listener, final EventType eventType,
125 final short position) {
126 if (listener == null || position < EventProducerInterface.LAST_POSITION) {
127 return false;
128 }
129 return this.addListener(listener, eventType, position, false);
130 }
131
132 /***
133 * @see nl.tudelft.simulation.event.EventProducerInterface
134 * #addListener(nl.tudelft.simulation.event.EventListenerInterface,
135 * nl.tudelft.simulation.event.EventType, short, boolean)
136 */
137 @SuppressWarnings("unchecked")
138 public synchronized boolean addListener(
139 final EventListenerInterface listener, final EventType eventType,
140 final short position, final boolean weak) {
141 if (listener == null || position < EventProducerInterface.LAST_POSITION) {
142 return false;
143 }
144 synchronized (this.semaphore) {
145 Reference<EventListenerInterface> reference = null;
146 if (!weak) {
147 reference = new StrongReference<EventListenerInterface>(
148 listener);
149 } else {
150 reference = new WeakReference<EventListenerInterface>(listener);
151 }
152 if (this.listeners.containsKey(eventType)) {
153 Reference<EventListenerInterface>[] entries = this.listeners
154 .get(eventType);
155 for (int i = 0; i < entries.length; i++) {
156 if (listener.equals(entries[i].get())) {
157 return false;
158 }
159 }
160 List<Reference<EventListenerInterface>> entriesArray = new ArrayList<Reference<EventListenerInterface>>(
161 Arrays.asList(entries));
162 if (position == EventProducerInterface.LAST_POSITION) {
163 entriesArray.add(reference);
164 } else {
165 entriesArray.add(position, reference);
166 }
167 this.listeners.put(eventType, entriesArray
168 .toArray(new Reference[entriesArray.size()]));
169 } else {
170 Reference[] entries = { reference };
171 this.listeners.put(eventType, entries);
172 }
173 }
174 return true;
175 }
176
177 /***
178 * fires the event to the listener. This method is a hook method. The
179 * default implementation simply invokes the notify on the listener. In
180 * specific cases (filtering, storing, queuing, this method can be
181 * overwritten.
182 *
183 * @param listener
184 * the listener for this event
185 * @param event
186 * the event to fire
187 * @return the event
188 * @throws RemoteException
189 * on network failure.
190 */
191 protected synchronized EventInterface fireEvent(
192 final EventListenerInterface listener, final EventInterface event)
193 throws RemoteException {
194 listener.notify(event);
195 return event;
196 }
197
198 /***
199 * fires an event to subscribed listeners.
200 *
201 * @param event
202 * the event.
203 * @return the event.
204 */
205 protected synchronized EventInterface fireEvent(final EventInterface event) {
206 if (this.listeners.containsKey(event.getType())) {
207 synchronized (this.semaphore) {
208 Reference<EventListenerInterface>[] entries = this.listeners
209 .get(event.getType());
210 for (int i = 0; i < entries.length; i++) {
211 EventListenerInterface listener = entries[i].get();
212 try {
213 if (listener != null) {
214
215
216 this.fireEvent(listener, event);
217 } else {
218
219
220 this.removeListener(entries[i], event.getType());
221 }
222 } catch (RemoteException remoteException) {
223
224
225 this.removeListener(entries[i], event.getType());
226 }
227 }
228 }
229 }
230 return event;
231 }
232
233 /***
234 * fires a byte value to subscribed listeners subscribed to eventType.
235 *
236 * @param eventType
237 * the eventType of the event.
238 * @param value
239 * the value of the event.
240 * @return the byte value.
241 */
242 protected synchronized byte fireEvent(final EventType eventType,
243 final byte value) {
244 this.fireEvent(eventType, new Byte(value));
245 return value;
246 }
247
248 /***
249 * fires a boolean value to subscribed listeners subscribed to eventType.
250 *
251 * @param eventType
252 * the eventType of the event.
253 * @param value
254 * the value of the event.
255 * @return the byte value.
256 */
257 protected synchronized boolean fireEvent(final EventType eventType,
258 final boolean value) {
259 this.fireEvent(eventType, new Boolean(value));
260 return value;
261 }
262
263 /***
264 * fires a byte value to subscribed listeners subscribed to eventType. A
265 * timed event is fired.
266 *
267 * @param eventType
268 * the eventType of the event.
269 * @param value
270 * the value of the event.
271 * @param time
272 * a timestamp for the event.
273 * @return the byte value.
274 */
275 protected synchronized byte fireEvent(final EventType eventType,
276 final byte value, final double time) {
277 this.fireEvent(eventType, new Byte(value), time);
278 return value;
279 }
280
281 /***
282 * fires a boolean value to subscribed listeners subscribed to eventType. A
283 * timed event is fired.
284 *
285 * @param eventType
286 * the eventType of the event.
287 * @param value
288 * the value of the event.
289 * @param time
290 * a timestamp for the event.
291 * @return the byte value.
292 */
293 protected synchronized boolean fireEvent(final EventType eventType,
294 final boolean value, final double time) {
295 this.fireEvent(eventType, new Boolean(value), time);
296 return value;
297 }
298
299 /***
300 * fires a double value to subscribed listeners subscribed to eventType.
301 *
302 * @param eventType
303 * the eventType of the event.
304 * @param value
305 * the value of the event.
306 * @return the double value.
307 */
308 protected synchronized double fireEvent(final EventType eventType,
309 final double value) {
310 this.fireEvent(eventType, new Double(value));
311 return value;
312 }
313
314 /***
315 * fires a double value to subscribed listeners subscribed to eventType. A
316 * timed event is fired.
317 *
318 * @param eventType
319 * the eventType of the event.
320 * @param value
321 * the value of the event.
322 * @param time
323 * a timestamp for the event.
324 * @return the double value.
325 */
326 protected synchronized double fireEvent(final EventType eventType,
327 final double value, final double time) {
328 this.fireEvent(eventType, new Double(value), time);
329 return value;
330 }
331
332 /***
333 * fires an integer value to subscribed listeners subscribed to eventType.
334 *
335 * @param eventType
336 * the eventType of the event.
337 * @param value
338 * the value of the event.
339 * @return the integer value.
340 */
341 protected synchronized int fireEvent(final EventType eventType,
342 final int value) {
343 this.fireEvent(eventType, new Integer(value));
344 return value;
345 }
346
347 /***
348 * fires an integer value to subscribed listeners subscribed to eventType. A
349 * timed event is fired.
350 *
351 * @param eventType
352 * the eventType of the event.
353 * @param value
354 * the value of the event.
355 * @param time
356 * a timestamp for the event.
357 * @return the integer value.
358 */
359 protected synchronized int fireEvent(final EventType eventType,
360 final int value, final double time) {
361 this.fireEvent(eventType, new Integer(value), time);
362 return value;
363 }
364
365 /***
366 * fires a long value to subscribed listeners subscribed to eventType.
367 *
368 * @param eventType
369 * the eventType of the event.
370 * @param value
371 * the value of the event.
372 * @return the long value.
373 */
374 protected synchronized long fireEvent(final EventType eventType,
375 final long value) {
376 this.fireEvent(eventType, new Long(value));
377 return value;
378 }
379
380 /***
381 * fires a long value to subscribed listeners subscribed to eventType. A
382 * timed event is fired.
383 *
384 * @param eventType
385 * the eventType of the event.
386 * @param value
387 * the value of the event.
388 * @param time
389 * a timestamp for the event.
390 * @return the long value.
391 */
392 protected synchronized long fireEvent(final EventType eventType,
393 final long value, final double time) {
394 this.fireEvent(eventType, new Long(value), time);
395 return value;
396 }
397
398 /***
399 * fires a value to subscribed listeners subscribed to eventType.
400 *
401 * @param eventType
402 * the eventType of the event.
403 * @param value
404 * the value of the event.
405 * @return the Serializable value.
406 */
407 protected synchronized Object fireEvent(final EventType eventType,
408 final Object value) {
409 this.fireEvent(new Event(eventType, this, value));
410 return value;
411 }
412
413 /***
414 * fires a Serializable value to subscribed listeners subscribed to
415 * eventType. A timed event is fired.
416 *
417 * @param eventType
418 * the eventType of the event.
419 * @param value
420 * the value of the event.
421 * @param time
422 * a timestamp for the event.
423 * @return the Serializable value.
424 */
425 protected synchronized Object fireEvent(final EventType eventType,
426 final Object value, final double time) {
427 this.fireEvent(new TimedEvent(eventType, this, value, time));
428 return value;
429 }
430
431 /***
432 * fires a short value to subscribed listeners subscribed to eventType.
433 *
434 * @param eventType
435 * the eventType of the event.
436 * @param value
437 * the value of the event.
438 * @return the short value.
439 */
440 protected synchronized short fireEvent(final EventType eventType,
441 final short value) {
442 this.fireEvent(eventType, new Short(value));
443 return value;
444 }
445
446 /***
447 * fires a short value to subscribed listeners subscribed to eventType. A
448 * timed event is fired.
449 *
450 * @param eventType
451 * the eventType of the event.
452 * @param value
453 * the value of the event.
454 * @param time
455 * a timestamp for the event.
456 * @return the short value.
457 */
458 protected synchronized short fireEvent(final EventType eventType,
459 final short value, final double time) {
460 this.fireEvent(eventType, new Short(value), time);
461 return value;
462 }
463
464 /***
465 * @see nl.tudelft.simulation.event.EventProducerInterface#getEventTypes()
466 */
467 public synchronized EventType[] getEventTypes() {
468 if (this.cache != null) {
469 return this.cache;
470 }
471 List<Field> fieldList = new ArrayList<Field>();
472 Class<?> clazz = this.getClass();
473 while (clazz != null) {
474 Field[] declaredFields = clazz.getDeclaredFields();
475 for (int i = 0; i < declaredFields.length; i++) {
476 fieldList.add(declaredFields[i]);
477 }
478 clazz = clazz.getSuperclass();
479 }
480 Field[] fields = fieldList.toArray(new Field[fieldList.size()]);
481 Map<String, Object> result = new HashMap<String, Object>();
482 for (int i = 0; i < fields.length; i++) {
483 if (fields[i].getType().equals(EventType.class)) {
484 fields[i].setAccessible(true);
485 try {
486 if (!result.containsKey(fields[i].getName())) {
487 result.put(fields[i].getName(), fields[i].get(this));
488 }
489 } catch (Exception exception) {
490 exception.printStackTrace();
491 }
492 }
493 }
494 this.cache = result.values().toArray(new EventType[result.size()]);
495 return this.cache;
496 }
497
498 /***
499 * removes all the listeners from the producer.
500 *
501 * @return int the amount of removed listeners.
502 */
503 protected synchronized int removeAllListeners() {
504 int result = this.listeners.size();
505 this.listeners = null;
506 this.listeners = Collections
507 .synchronizedMap(new EventListenerMap<EventType, Reference<EventListenerInterface>[]>());
508 return result;
509 }
510
511 /***
512 * removes all the listeners of a class.
513 *
514 * @param ofClass
515 * the class or superclass.
516 * @return the number of listeners which were removed.
517 */
518 protected synchronized int removeAllListeners(final Class ofClass) {
519 Map<EventType, Reference<EventListenerInterface>[]> temp = new HashMap<EventType, Reference<EventListenerInterface>[]>(
520 this.listeners);
521 int result = 0;
522 synchronized (this.semaphore) {
523 Set<EventType> keys = temp.keySet();
524 for (Iterator<EventType> i = keys.iterator(); i.hasNext();) {
525 EventType type = i.next();
526 List<Reference<EventListenerInterface>> list = Arrays
527 .asList(this.listeners.get(type));
528 for (Iterator<Reference<EventListenerInterface>> ii = list
529 .iterator(); ii.hasNext();) {
530 Reference<EventListenerInterface> listener = ii.next();
531 if (listener.getClass().isAssignableFrom(ofClass)) {
532 this.removeListener(listener.get(), type);
533 result++;
534 }
535 }
536 }
537 }
538 return result;
539 }
540
541 /***
542 * @see nl.tudelft.simulation.event.EventProducerInterface
543 * #removeListener(EventListenerInterface, EventType)
544 */
545 @SuppressWarnings("unchecked")
546 public synchronized boolean removeListener(
547 final EventListenerInterface listener, final EventType eventType) {
548 if (!this.listeners.containsKey(eventType)) {
549 return false;
550 }
551 boolean result = false;
552 synchronized (this.semaphore) {
553 Reference<EventListenerInterface>[] entries = this.listeners
554 .get(eventType);
555 List<Reference<EventListenerInterface>> list = new ArrayList<Reference<EventListenerInterface>>(
556 Arrays.asList(entries));
557 for (Iterator<Reference<EventListenerInterface>> i = list
558 .iterator(); i.hasNext();) {
559 Reference<EventListenerInterface> reference = i.next();
560 EventListenerInterface entrie = reference.get();
561 if (entrie == null) {
562 i.remove();
563 } else {
564 if (listener.equals(entrie)) {
565 i.remove();
566 result = true;
567 }
568 }
569 }
570 this.listeners.put(eventType, list.toArray(new Reference[list
571 .size()]));
572 if (list.size() == 0) {
573 this.listeners.remove(eventType);
574 }
575 }
576 return result;
577 }
578
579 /***
580 * removes a reference from the subscription list
581 *
582 * @param reference
583 * the reference to remove
584 * @param eventType
585 * the eventType for which reference must be removed
586 * @return success whenever the reference is removes; otherwise returns
587 * false.
588 */
589 @SuppressWarnings("unchecked")
590 private synchronized boolean removeListener(
591 final Reference<EventListenerInterface> reference,
592 final EventType eventType) {
593 boolean success = false;
594 Reference<EventListenerInterface>[] entries = this.listeners.get(eventType);
595 List<Reference<EventListenerInterface>> list = new ArrayList<Reference<EventListenerInterface>>(
596 Arrays.asList(entries));
597 for (Iterator<Reference<EventListenerInterface>> i = list.iterator(); i
598 .hasNext();) {
599 if (i.next().equals(reference)) {
600 i.remove();
601 success = true;
602 }
603 }
604 Reference<EventListenerInterface>[] toArray = (Reference<EventListenerInterface>[]) list
605 .toArray(new Reference[list.size()]);
606 this.listeners.put(eventType, toArray);
607 if (list.size() == 0) {
608 this.listeners.remove(eventType);
609 }
610 return success;
611 }
612
613 /***
614 * writes a serializable method to stream
615 *
616 * @param out
617 * the outputstream
618 * @throws IOException
619 * on IOException
620 */
621 private synchronized void writeObject(final ObjectOutputStream out)
622 throws IOException {
623 out.defaultWriteObject();
624 }
625
626 /***
627 * reads a serializable method from stream
628 *
629 * @param in
630 * the inputstream
631 * @throws IOException
632 * on IOException
633 */
634 private synchronized void readObject(final java.io.ObjectInputStream in)
635 throws IOException, ClassNotFoundException {
636 in.defaultReadObject();
637 this.semaphore = new Object();
638 }
639 }