ListenerManager
interface allows plugin to register listener on a specific server. addNotificationListener
method is used to register the listener. Notifications are filtered based on NotificationFilter
parameter to this method. When NotificationFilter parameter is null, default filter is used. Default filter is specified using notification.xml. Listener is registered on the server delegate object of the specified server.
{@link JobListener}
interface provides notifications of Job
executions. The {@link TriggerListener}
interface provides notifications of Trigger
firings. The {@link SchedulerListener}
interface provides notifications of Scheduler
events and errors. Listeners can be associated with local schedulers through the {@link ListenerManager} interface. Listener registration order is preserved, and hence notification of listeners will be in the order in which they were registered.
@author jhouse @since 2.0 - previously listeners were managed directly on the Scheduler interface.Tricky Java... When an object registered as listener becomes unused, the fact that the listener list holds a reference to it prevents it from beeing fred by the garbage collector. This ends up in objects not being fred, and growing listener lists of unused objects. This is bad, and listener lists are a very common source of memory leak! Beware! A naive and developper-unfriendly approach would be to tell all registering objects to unregister before they are unsued... This is easy to do in C++ where there are proper destructors, but in Java the finalize() method is precisely called by the garbage collector, which won't call it in the present case since the listener list still holds a reference. Back to the beginning. An even-more developer unfriendly approach would impose a constraint on all objects using objects registered as listeners to do the cleanup, but this is a real mess and does not even work for other reasons (for example, think of inner classes registering private members as listeners, or other awful cases where the object using another object using another object using... has no way of unregistering a listerner without modifying drastically the API just for that). Weak references were introduced in Java 1.2 to solve this problem. If only weak references to an object remains, the garbage collector discards it. The get() method of the weak reference holder then returns null. A queue can be used to be notified when this happens, as the application does not decides when the object is finalized (this is handled by the garbage collector thread). Thus, weak reference pointers may become invalid any time! For JSynoptic, we have an additional problem. The same object may be registered as listener several times, but should be notified only once. See EndNotificationListener for a concrete example of this. Also, a Set is not adapted to hold only one reference of each listener. If an object is registered twice by two different paths and unregistered only once, it is still expected to be notified by the second registering path. Hence, it must still be present in the listener list, which would not be the case using a Set. The solution is of course reference counting, which is applied on the register/unregister operation. This is complementary to the WeakReference mecanism : if an object forgets to unregister or doesn't have the occasion to do it before being thrown away, then the weak reference mecanism will still discard it even if the refcount field is >1, which is what we want. On the other hand, if the refcount field goes down to 0, the object is removed from the listener list, but this does not necessarily mean the listener is unused. It may just have unregistered and live its life as usual. As in this case the listener list does not hold any reference to the object, it cannot be the source for a memory leak. So, the refcount field is NOT related to the weak reference mecanism. It is necessary for another reason entirely, as decribed above. See the notes below for more fun with the ReferenceCountedPointer class. It holds a weak reference to the ListenerManager, so as to avoid the same problem as above, but for the managers themselves.
private void createListenerManager() { lm = new ListenerManager( "ucar.nc2.util.DatasetCollectionManager$EventListener", "ucar.nc2.util.DatasetCollectionManager$Event", "setMessage"); } public void addEventListener(EventListener l) { lm.addListener(l); } public void removeEventListener(EventListener l) { lm.removeListener(l); } public class Event extends java.util.EventObject { private String message; Event(String message) { super(DatasetCollectionManager.this); this.message = message; } public String getMessage() { return message; } } public static interface EventListener { public void setMessage(DatasetCollectionManager.Event event); } lm.sendEvent(event);@author John Caron
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|