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

Always Check for Open Source First!

This is a lesson I've learned the hard way. Typically, when we engineers approach a problem, we are excited about the prospect of solving it. That is, we almost immediately begin imagining how the code might work, or what sort of algorithm we might use. This is a hard habit to break, but if we don't force ourselves to gain a bit of discipline, we will often end up wasting a lot of time solving problems that have already been solved (sometimes many times over!) by other people. It is a very disappointing feeling to spend days or weeks implementing a partial solution to a complex problem, only to discover too late that somebody already wrote a solution years ago that does far more than yours ever will. I've often had to ask myself "Why did I bother with this?"

The simple fact of the matter is that before you start laying down code, or even writing up a design, you should take 15 to 30 minutes and search the Internet for open source implementations of the functionality you need. You should try to get in the habit of doing this consistently, so that it becomes a normal part of your thought process. Some sites that you should always include in your search:

SourceForge
Google Code Search
Java.net (if it's a Java project)
freshmeat

In addition to those sites, you should do some basic Google searches for the functionality you need. You will probably end up being surprised at just how much useful stuff you find. Many projects, had they taken this approach from Day One, could probably have built themselves almost entirely out of existing open source components, shaving development time to a tiny sliver of what it had been, and therefore saving money and making time available for the addition of truly new features.

Loading mentions Retweet
Filed under  //   developers   FOSS   Java   open source  
Posted December 15, 2009
// 1 Comment

Java's Future Lies In FOSS

I wrote this back in 2004 while living in Australia. It was published in CNet's Builder AU. It predated Sun's decision to release Java as an open source product, and in the end, many of the claims I made in this article turned out to be spot on.

Recently, much of the buzz in the software development community has been about one question: Should Sun Microsystems release Java under a free software license like the GNU General Public License (GPL)?

There are many valid reasons why Sun should. In fact, I predict that if Java is to survive in a world dominated by Microsoft for the long term, it must become Free Open Source Software (FOSS), where "free" means freedom, not zero-cost.

Currently, the source code for the classes that make up Java is mostly available for developers to view, but modifications of any kind are expressly forbidden (see the licence included with the Java SDK, in the "Supplemental License Terms", subsections B and D). This is the key reason why Java is not considered "Free Software". Being able to simply view the source to something does not make it FOSS, since creating modifications so that the software can evolve and adapt is more important to developers than simply reading about how existing code works.

It should also be noted that there are several third-party licences in the SDK, due to the fact that the SDK includes several technologies developed by entities outside of Sun. Converting Java to FOSS will require ensuring that these licences are compatible with a FOSS distribution model, or replacing the technologies with ones that are.

The benefits of a FOSS Java to developers will be enormous. Sun's "Bug Parade" is populated with thousands of unfixed bugs, many of them more than five years old. Even the simplest of bugs often goes unfixed, presumably because Sun lacks the manpower to fix everything, and must prioritise. There are, at the time of this writing, more than 7,500 open bugs filed against the SDK alone. An open source approach will not suffer from this. Bugs will be fixed almost as quickly as they are reported. The backlog of bugs will quickly disappear, as well. The quality of Java as a platform will instantly be boosted.

Not everyone, however, agrees that the benefits are worth the perceived risks. James Gosling, widely recognised as the "Father of Java", has played an important role in the development of this debate. In the April 12, 2004, entry in his blog he writes:

GPL software is not "free": it comes with a licence that has a strong political agenda. Like GPL software, the Java platform is "free" in many senses: you don't have to pay anything for the runtime or developers kit and you can get the sources for everything. Unlike GPLd software, the Java sources don't come with a viral infection clause that requires you to apply the GPL to your own code.

Gosling seems to feel that "freedom" requires absolutely no restrictions be present. On the contrary, those of us who live in modern western societies know that the presence of laws (that is, restrictions) is what enables us to remain free. This is the concept of "greatest liberty". The important thing is what those restrictions are. The same is true with the GPL, which grants very specific freedoms.

Gosling also implies that if Java were released under the GPL, that its so-called "viral infection clause" would require that all Java code written would automatically be under the GPL. This is a complete misunderstanding of how the GPL works. Linux, for example, is under the GPL, but programs written to run on it and use it need not be. Gosling is confusing the concepts of "program linking" and "writing for a platform".

Beyond these technical points, one might ask, "What is the big problem with making Java FOSS?" It's a complex question, and many in the Java community have provided excellent coverage of the issues. Joshua Marinacci is one that has covered this in his blog on java.net. He has covered many of the details, however, I believe he has made some critical errors in his argument, which must be refuted to understand why Java must become FOSS if it is to survive.

Marinacci points out four major "problems" that he claims would result from making Java FOSS. Probably the most important one is the first one on his list, which is echoed by the anti-FOSS Java camp worldwide: Java would become chaotic, and incompatible versions would pop up everywhere. Apparently there is a belief that only Sun's heavy-handed spec enforcement can keep this from happening (though it clearly failed to do so in a timely manner against Microsoft).

We already have good evidence that this will not happen. Linux is a platform under the GPL, and is based on a set of standards collectively called UNIX. UNIX is valuable mainly because of the uniformity of implementation of these standards on all flavours of UNIX, just as Java is valuable for the same reason. We do not see incompatible versions of Linux everywhere, though, even though there are many different and diverse distributions of it available. Most people see this diversity (read: freedom) as a good thing about Linux.

Similarly, the extremely popular database software called MySQL is available under the GPL, and the company makes no secret of this. MySQL is rapidly growing in the industry, and is creating a serious threat to purely commercial databases like SQL Server. Despite the fact that MySQL is GPL, nobody forks the code. Why not? Simple: doing so would create an incompatible code branch, and nobody stands to gain anything by doing that. The community is better served by working together to make MySQL better.

So there we have two spectacularly successful GPL products, both of which are giving Microsoft major headaches, and both of which depend upon standardisation. One has many distributions, the other only a few. This is why the fear that making Java FOSS would cause it to degenerate into chaos is unwarranted. It is more about paranoia than reason, more about control than progress.

FOSS works because it allows software to evolve like a biological organism, changing and improving in unpredictable ways over time to find solutions to seemingly intractable problems. If Java becomes FOSS, it will find ways around threats like Microsoft. If it does not, then those threats may eventually send it the way of the dinosaur. After all, having the comfortable predictability of being big and cold-blooded doesn't help you when the surprise meteor hits. Only being adaptable can keep the species alive.

Loading mentions Retweet
Filed under  //   FOSS   Gosling   GPL   Java   license   MySQL   open source   Sun  
Posted November 24, 2009
// 0 Comments