mechanicalSPIRIT

Brandon Franklin's blog

Java Programming Tip: Building Your Own Event Bus

Most of us have worked with various types of event handling in Java. There's of course the basic Observer/Observable pair, but beyond that there are all sorts of MouseEvents, ComponentEvents, PropertyChangeEvents, and many others. These are great, and are a well-established pattern for keeping code loosely coupled. However, they all share the similar attribute of requiring that a listener be attached directly to the source of the events. This has two major downsides.

First of all, it forces the code to remove listeners in order to prevent many types of memory leaks, which is particularly annoying in cases where it's not trivial to institute a "cleanup" pass, essentially mirroring the behavior that would, in C++, be recognized as a "destructor". This sort of cleanup code tends to pollute the code in general, and is difficult to maintain over time. It seems somebody always forgets to null out that one critical field...

Secondly, and perhaps more importantly, this approach can make for some very ugly designs when building a large, interconnected application such as a complex GUI system. In such systems, components more often care about what kind of event is being fired somewhere--anywhere!--than they do about who is firing it. The components don't really want to attach as listeners to a source. They want to attach as listeners to an event type.

This is when it's time to think about using an event bus!

The exact design of your particular event bus can vary depending on your needs. I've written a few over the years and they've been quite different beasts. However, there's one that I have written that I generally use as a template when starting a new event bus. I call it the SmartEventBus. It consists of just 2 classes! Here's the code, with most comments and some minor sections removed for brevity: (NOTE: Uses Java 5 language syntax)

public abstract class SmartEvent<S> {

    private S source;

    private long timestamp;

    public SmartEvent(final S source) {
        this.source = source;

        timestamp = System.nanoTime();
    }

    public S getSource() {
        return source;
    }

    public long getTimestamp() {
        return timestamp;
    }

}


import java.lang.ref.*;
import java.lang.reflect.*;
import java.util.*;

public class SmartEventBus {

    private static SmartEventBus INSTANCE = null;

    private Map<Class, Set<WeakReference<Object>>> listeners = new HashMap<Class, Set<WeakReference<Object>>>();

    static public SmartEventBus getBus() {
        if( INSTANCE == null ) {
            INSTANCE = new SmartEventBus();
        }
        return INSTANCE;
    }

    private SmartEventBus() {
    }

    private Iterator<Class> superclassIterator(final Class clazz) {

        Set<Class> set = new LinkedHashSet<Class>();

        Class<?> superClass = clazz;
        while (superClass != null) {
            set.add(superClass);
            superClass = superClass.getSuperclass();
        }

        return set.iterator();
    }

    public synchronized void addListener(final Object listener) {

        // Pull out all the "hear" methods
        Set<Method> hearMethods = new HashSet<Method>();
        for (Method method : listener.getClass().getMethods()) {
            if (method.getName().equals("hear")) {
                hearMethods.add(method);
            }
        }

        // Examine every "hear" method
        for (Method method : hearMethods) {

            Class[] paramTypes = method.getParameterTypes();

            // Disqualify malformed candidates
            if ((paramTypes.length == 1)
                    && (SmartEvent.class.isAssignableFrom(paramTypes[0]))) {
                addTypeSpecificListener(listener, paramTypes[0]);
            }
        }

    }

    private void addTypeSpecificListener(final Object listener, final Class type) {

        // Get or create the Set of listeners for this type
        Set<WeakReference<Object>> typeListeners = listeners.get(type);
        if (typeListeners == null) {
            typeListeners = new HashSet<WeakReference<Object>>();
            listeners.put(type, typeListeners);
        }

        // Add the listener
        typeListeners.add(new WeakReference<Object>(listener));

    }

    public void fire(final SmartEvent event) {

        for (Iterator<Class> iter = superclassIterator(event.getClass()); iter.hasNext();) {

            Class type = iter.next();
            if (type.equals(Object.class)) {
                continue;
            }

            Set<WeakReference<Object>> typeListeners = listeners.get(type);
            if (typeListeners != null) {

                Collection<WeakReference<Object>> deadRefs = new LinkedList<WeakReference<Object>>();
                for (WeakReference<Object> listenerRef : typeListeners) {
                    Object listener = listenerRef.get();
                    if (listener != null) {

                        Method method = null;
                        try {
                            method = listener.getClass().getMethod("hear", type);

                        }
                        catch (NoSuchMethodException nsme) {
                            // This should theoretically never be true,
                            // but try to handle it gracefully anyway.
                            deadRefs.add(listenerRef);
                            continue;
                        }

                        Object result = null;
                        try {
                            result = method.invoke(listener, event);
                        }
                        catch (IllegalAccessException iae) {
                            iae.printStackTrace();
                        }
                        catch (InvocationTargetException ite) {
                            ite.printStackTrace();
                        }

                    }
                    else {
                        deadRefs.add(listenerRef);
                    }
                }
                typeListeners.removeAll(deadRefs);
            }
        }

    }

}

The SmartEvent class is, obviously, the base class that is used to represent events that get passed around the system. In your own event bus, it could contain just about anything you want, but mine contains simply a source object (parameterized) and a timestamp. This class gets extended into your entire event hierarchy.

The SmartEventBus is a singleton, because you use it like a service, getting a handle to it any time you need to use it. When an object adds itself as a listener, it is examined to find any and all methods beginning with the word "hear". The methods that have exactly one parameter will have the datatype of that parameter recorded in the bus as the type of event that the method cares about. In other words, when a class adds itself as a listener, it adds itself as a listener to everything it listens to. There's no interface to implement, and if the code changes such that the listener shouldn't care about a particular event type anymore, the developer need only delete the associated "hear" method. I'll leave more detailed analysis of the above source code up to the reader.

Since writing this original event bus, I've seen and written some other variations. One notable example is in the open source Buoy GUI framework. It uses a reflective system similar to my SmartEventBus. A more recent example is one that I wrote that uses the newly-added annotations framework in Java 5 syntax to mark the methods, rather than a naming convention. This means your listener methods look more like this:

@EventListener
public void handleSomeEvent(EventType e) {
...
}

While this is appealing in the sense that it frees one from onerous naming conventions and relies upon a more powerful reflective analysis, I find that it can sometimes be a bit frustrating in daily practice to not have a single, easily sorted "name group" of methods. For example, having all of your methods begin with "hear" causes them to be grouped in the outline view of Eclipse. It's a minor annoyance, but worth noting anyway.

In the end, there are as many ways to develop event buses as there are applications that need them, but by understanding some existing approaches and thinking about reflection rather than interface implementation, new doors can be opened to you that you may not have even realized existed.

Loading mentions Retweet
Filed under  //   events   Java   programming   tip  
Posted January 9, 2010
// 3 Comments

Java Programming Tip: Using Reflection to Call Any Method (Even a Private One!)

Many of us have encountered the following situation: You are coding a tricky algorithm and discover that a very useful method for doing what you're doing already exists. Alas, it's private, or perhaps "package" visible (in a package that you're not in!) and you have no way of accessing it. You end up duplicating the code yourself, perhaps grumbling under your breath about how the other developer should have made the useful method public. I have some good news for you. By using Java's built-in reflection API, you can actually call any method you want under most circumstances!

How? It's easy. It all comes down to the setAccessible(boolean) method of the AccessibleObject class, of which Method is a subclass. Let's take a look at some example code. First, a class that contains our "target method", the one we want to call but can't access:

public class Foo {

   private boolean same(int x, int y) {
       return ( x == y );
   }

}

Here's a class that uses reflection and "setAccessible" to call the method (NOTE: uses Java 5 language features):

public class Bar implements Runnable {

    static public void main(String... args) {
         new Bar().run();
    }

    public void run() {
        try {
            Foo foo = new Foo();
            Method targetMethod = foo.getClass().getDeclaredMethod( "same", int.class, int.class );

            // This is the magic line
            targetMethod.setAccessible(true);

            Boolean result = (Boolean)targetMethod.invoke( foo, 4, 4 );
            System.out.println( result );
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

}

Pretty easy, isn't it? You can also call static methods using this approach. Let's imagine that the method in our Foo class had been static. In that case, here's what we would have done instead:

public class Bar implements Runnable {

    static public void main(String... args) {
        new Bar().run();
    }

    public void run() {
        try {
            Method targetMethod = Foo.class.getDeclaredMethod( "same", int.class, int.class );

            // This is the magic line
            targetMethod.setAccessible(true);

            Boolean result = (Boolean)targetMethod.invoke( Foo.class, 4, 4 );
            System.out.println( result );
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

}

Notice that the difference is simply that we cannot use an instance of Foo to get the class object, and that during the invocation of the method we use the class itself as the first parameter, rather than an instance.

This technique isn't foolproof. Every time you call "setAccessible", the installed security manager (if there is one) is given an opportunity to block the call. However, I've not yet encountered a situation in which this was actually blocked. That said, just because you can do something doesn't mean you should, so be sure to use this approach with caution, and certainly only when you absolutely must! After all, it is fundamentally "breaking the rules" that are being expressed in the code itself.

Loading mentions Retweet
Filed under  //   Java   programming   reflection   tip  
Posted December 27, 2009
// 0 Comments

Java Programming Tip: Why Not to Obfuscate

Obfuscation is a seductive mistress! At several places where I've worked, the management's perception was that obfuscation was absolutely necessary to protect the company's intellectual property. After all, with so many clever algorithms and so much custom code in there, it must be very important to ensure that all those sneaky hackers out there don't figure out our secrets! Right?

Well...Maybe. But not really.

Okay, perhaps I'm not being fair. Yes, without obfuscation involved, it truly is extremely easy to decompile Java bytecode into completely readable sourcecode. Yes, it really would be a trivial issue to essentially build the entire source tree of a product up from just a single copy of the runtime code. And yes, programs that will do this for you are incredibly easy to find on the Internet with a quick Google search. I'll give them that much. I concede those points.

Where we differ, however, is on that "very important" part. Is it "very important" to do this? Is it even worth it at all? I assert that it is not, and I'm happy to back that up with some explanations.

First of all, obfuscating your code may give you a sense of security, but it is an illusion. Any interested party who truly has something to gain from understanding your algorithms (such as a corporate competitor) is not going to be thwarted by methods being renamed to "a3()". If they care that much, they will spend the time (and money) to carefully pore through your obfuscated code, looking at "what it's doing" rather than "what it says", and they'll eventually figure it out. Don't believe me? Hackers have been doing this with compiled assembly language for years. How do you think they write all those crazy "cracker" programs that route the code around checking that there's a CD in the drive, etc.? And those are just some kids with a little free time! When you bring a team of experienced coders and a corporate payroll into the picture, your obfuscated Java source doesn't stand a chance.

So that argument deserves to leave skidmarks on the bowl. The only "hackers" you're going to deter with obfuscation are hobbyists who don't pose any actual threat to you anyway.

Beyond the basic ineffectiveness of obfuscation, it actually makes some things worse. I can tell you from experience, nothing is quite as frustrating as running a production build of your product and getting a stack trace that looks like this:

Exception in thread "main" java.lang.NullPointerException
    at a.q.a.b.m3(unknown:unknown)
    at a.x.e.a.a1(unknown:unknown)
    at t.a.h.b.b2(unknown:unknown)
    at t.b.a.a.c2(unknown:unknown)
    at b.c.a.a.a2(unknown:unknown)

Yeah. Great.

Better yet, wait until you get a stack trace like that emailed to you from a customer who just got that in a logfile. Or even better, wait until your Support Department guy calls you up asking what it means! That's the reality of it, folks. That's the bit that they don't mention on the back of the Obfuscation Software 2010 box. Oh, I know, some of the obfuscators generate little "lookup tables" so you can try to make sense of that gibberish, but let's get real: The end result is, it wastes a huge amount of developer time that would be better spent actually fixing the bug that a real stack trace would have made obvious.

As if this wasn't already bad enough, it gets worse! By employing obfuscation, you completely destroy your ability to use reflection in your product. Reflection encodes everything as hardcoded strings, like "com.company.MyClassName". That stuff doesn't get converted by the obfuscator, at least not by any obfuscator that I've ever seen. So what you get is code that looks fine, compiles fine, even runs fine during your tests, but as soon as it goes to production and gets run through the obfuscator, BOOM! It's broken. You've essentially destroyed your ability to use a very powerful feature of the Java language. I ask you again, was it worth it?

Finally, the very act of employing an obfuscator introduces more complexity to your build process. It's yet another step, another thing you need to automate in your build script, or have some poor human being execute by hand. It's yet another piece of software to manage. It's yet another moving part! If you're like most software shops I've worked at, the last thing you need is more moving parts!

So please stop the madness. When your boss says "We need to start obfuscating!" or when you start a new job and see that they're employing obfuscation already, pipe up. Explain these issues. Ask them to think about the pros and cons. Maybe, just maybe, you won't be seduced by this femme fatale like so many others have been.

Loading mentions Retweet
Filed under  //   Java   obfuscation   programming   tip  
Posted December 21, 2009
// 0 Comments

Java Programming Tip: Keyed Singletons

Most Java programmers are familiar with the "singleton" pattern, shown in this snippet:

public class MyService {

    static private MyService INSTANCE = null;

    static public MyService getInstance() {
        if( INSTANCE == null ) {
            INSTANCE = new MyService();
        }

        return INSTANCE;
    }

    private MyService() {
    }

}

However, I've found that sometimes in a complex application, it can be useful to have instances of particular classes that act like singletons, but only in terms of a specific context. For example, perhaps you are working on an application that allows you to edit "projects" of some sort, and within the scope of each project you only want exactly one instance of a particular service, such as an "Undo Manager" or a "History Manager". You want it to work like a utility class, but it needs to maintain state that is specific to the context in which it's being used.

My solution to this problem has been to use what I call a "keyed singleton" pattern. It's easy to implement, as shown here (NOTE: uses Java 5 language syntax):

public class MyService {

    static private final Map<Object,MyService> INSTANCES = new HashMap<Object,MyService>();

    static public MyService getInstance(Object key) {
        MyService service = null;

        if( INSTANCES.get(key) == null ) {
            service = new MyService();
            INSTANCES.put(key, service);
        }

        return service;
    }

    private MyService() {
    }

}

In the above example, instances are lazily initialized just like you'd expect from a singleton implementation, but then they're added to a Map which tracks every instance based on the key it was created with. One will quickly notice that there's a problem with using this approach in some cases, though, which is that there's no obvious removal semantic. In other words, you'll quickly end up with a lot of instances in your Map and no way to get rid of them. Also, if you are using large objects (such as some kind of Project class) as your keys, then you could be creating a rather severe memory leak. You could add a removal method, but I have a better way!

Just substitute in this line:

    static private final Map<Object,MyService> INSTANCES = new WeakHashMap<Object,MyService>();

Instantly you have now made all of the references to your keys into "weak references," meaning the Map itself cannot prevent garbage collection of the key instances. Better yet, when one of the keys is garbage collected, its associated value entry is removed from the Map as well. In this way, careful use of a keyed singleton pattern can provide a scoped, self-cleaning service management framework.

Loading mentions Retweet
Filed under  //   Java   programming   tip  
Posted December 18, 2009
// 0 Comments