The Source for Java Technology Collaboration
User: Password:



Evan Summers

Evan Summers's Blog

Gooey Event Hub

Posted by evanx on February 16, 2007 at 08:36 AM | Comments (6)

Gooey Event Hub

We implement a event listener list singleton supporting weak references. Then we can add listeners to an object we wish to observe, and fire events to its observers, without implementing any such support in the observed objects eg. addListener(), removeListener(), fireEvent(). We can choose to fire an event in a background SwingWorker thread, or in the EDT eg. using invokeLater() or invokeAndWait(). So we might use this event hub as a basic event/message bus.



Code Snippet

We create BackgroundEvent and UpdateGuiEvent classes to enable some EDT switching as follows.

    public EventHubDemo() {
        ...
    public void actionPerformed(ActionEvent event) {
        if (checkForNewMessagesAction.equalsActionCommand(event)) {
           checkForNewMessagesAction.setEnabled(false);
           eventHub.fireEventInBackground(new BackgroundEvent(this, event));
        } ...
    }
    
    protected void doInBackground(ActionEvent event, JProgressBar progressBar) {
        if (checkForNewMessagesAction.equalsActionCommand(event)) {
           try {
              ...
              eventHub.fireEventAndWait(new UpdateGuiEvent(this, event));
           } catch (Exception e) {
              eventHub.fireEventAndWait(new ExceptionEvent(this, event, e));
           }
        } ...
    } 

where we wish to handle checkForNewMessagesAction in a background SwingWorker thread, and once completed, switch back into the EDT to update the GUI.


Demo

Launch   (EventHub, 150k/500k, unsandboxed, Java6)



Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Hi and thanks for your helpful code.

    I think I found a bug in the method processEvent(E event)
    it seems that you are only removing the last QEventHubListenerEntry removeEntry only whereas more than one may have entry.canRemove == true

    (I hope this comment is more helpful than the last one ;-) )

    Posted by: montechristos on February 27, 2007 at 02:29 AM


  • Thanks for your comment, and feedback. I wish people would make a habit of leaving of a comment...

    yes that is a (deliberate) bug/feature that you spotted ;) usually we fire events more than add/remove listeners, so i only bother to remove one (the last one) at a time, rather than create a List and add usually none, occassionally one, or (rarely) more than one, and removeAll() using that list (which is usually empty).

    But this is premature optimisation, which is, as they say, "the root of all evil" ;)

    but still it may well be a bug cos this code is not battle-hardened yet - so far it's just an exercise, to build a minimalist pub/sub event thingy

    Posted by: evanx on February 27, 2007 at 09:37 AM

  • For me it is not a habit, I just happen to have similar interests these days :-)

    Since you are traversing the listeners anyway to send the event, and since you are using a CopyOnWriteArrayList, you can remove orphan listeners and send events in one go, right? But your point is right about optimization.


    Keep up the good work!

    Posted by: montechristos on February 28, 2007 at 01:07 AM


  • yes, i take the opportunity of traversing listeners (to fire an event) to prune the list by one, if we find a listener entry that we can remove.

    i see that you are right - because we use CopyOnWriteArrayList, we can just remove the entry in the loop. In the case of ArrayList one needs to remove from the list after the loop.

    Thanks for the feedback - it is always most welcome! :)

    Posted by: evanx on February 28, 2007 at 01:19 AM

  • Hi! The target in GEventHubListenerEntry is mainly for anonymous listener from been garbaged collected if target been garbage collected. But since anonymous listener internally reference to the target(after compile,you can see that if you decompile class file) strongly .So the strongly referenced listener by GEventHubListenerEntry will inhibit target been garbage collected.So if target is a Panel and listener is an anonymous ActionListener.Then the panel and listener will never be garbarge collected even the Panel is closed.Now the only solution I can think of is to add a instance variable in my Panel to reference the anonymous listener and don't pass target to the GEventHub. Wondering if there any better solution!

    Posted by: huyi on November 08, 2007 at 05:37 PM

  • oh i didn't realise that anonymous inner classes strongly reference its outer class, but that does make sense.

    We need to strongly reference the unreferenced anonymous listener to prevent it being garbage collected. So i see the problem, because we dereference that strong reference to null only when the target is gc'ed - which you're saying will never happen because of the the internal strong reference in the anonymous listener - d'oh!

    the answer might be to instantiate a "child event hub" for transient panels, ie. an event hub instance per target panel or whatever, and register local anonomous listeners on that. So it's like a multi-event-type event list instance. In this case, the child event hub forward events up to the global parent singleton event hub. Then the panel, its own event hub and anonymous listeners can be be garbage collected in "one fell swoop."

    I've tried this out if you want to look at code in CVS for aptfoundation (GEventHub et al), and the demo application is in quitegooey project. Please feel free to email me to discuss if you have any questions, suggestions (evanx at dev.java.net)

    Thanks for picking this up!

    Posted by: evanx on November 10, 2007 at 05:58 AM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds