mechanicalSPIRIT

B.T. Franklin's blog

Java Programming Tip: Configure Swing Classes Instead of Extending Them

I've worked on a number of Swing-based applications over the years, both in a professional capacity and on my own, and I've seen a variety of approaches taken to building up what can only be called GUI frameworks dedicated to the construction of each particular application. There are two general types of approach that I have seen, one of which is much better at expanding and growing over time than the other. Sadly, the one that is most commonly used seems to be the one that is not so great at growing, but to the casual observer might seem the more obvious choice.

The two approaches I'm referring to are Composition and Inheritance.

These two design philosophies are by no means specific to GUI frameworks. In fact, there are reams of text written on just comparing the virtues of the two approaches. However, in the context of Swing, the question can be seen in a new light. Composition is a much stronger approach for building Swing frameworks with longevity, hands down.

What on earth am I talking about, you ask? Well, in general the idea of Inheritance is that you extend a class and add functionality to it. In terms of Swing classes, this usually translates into extending a class to specialize it into the exact component you want. Composition, in contrast, is all about keeping references to objects from your own objects, which in Swing translates into building up a component hierarchy by calling the various "set" methods to configure the constituent components rather than extending them to configure those same settings.

Let's speak of this in more concrete terms. We all know JFrame. I've seen plenty of cases where JFrame was extended into, say, MyApplicationFrame. The MyApplicationFrame class doesn't really add any functionality to JFrame. It merely calls some set methods from the constructor, and perhaps launches a main application thread. This is clearly an Inheritance approach, but a misguided one. The same thing could have been accomplished by simply instantiating a JFrame from a "launcher" class, configuring the JFrame by calling its API, starting any threads from the launcher, and then gracefully exiting the launching code and allowing the configured JFrame to live its life.

Some skeptics out there might be saying, "But why is that any better? What's wrong with extending the class if I know I want to configure it the same way every time anyway?" There are a few reasons, but let me respond first by asking, would you extend JTextField just to set its text to something that you happen to always use as a default, such as "No text entered"? I doubt it. Why should you deal with other JComponents any differently?

When you use Inheritance instead of Composition, you end up dragging along a lot of API that, beyond being useless or meaningless in your context, could actually wreak havoc if you haven't accounted for it. You are, in essence, creating another class with all of the same API as the extended class. Is that really what you wanted? Have you thought through the consequences of calling all of those methods on your new class? And do you even want those methods to ever be called at all? Probably not.

Perhaps more importantly, by using Composition your code will become much more flexible and maintainable. Changes in the Swing API will rarely, if ever, impact you. And should you ever want to change to a different GUI toolkit, such as SWT, or even Buoy, you will be able to do so without any impact to the code that is calling your code. You isolate the API. The value of that can hardly be overstated.

Filed under  //   Java   programming   tip  

Java Programming Tip: Creating "Method Bridges" using Public + Default Visibility

In Java, the default visibility for classes, methods, and fields is "package", meaning only code that is in the same package as the code in question can access it. However, sometimes it is useful to create large chunks of logic that need to communicate mainly amongst themselves, but should also be accessible by a limited subset of external code. This can be accomplished using what I call a "method bridge".

Let's imagine you have a few package-visible classes and their package-visible methods:

class Foo1 {
    void bar1() {
        ...
    }
}


class Foo2 {
    void bar2() {
        ...
    }
}


class Foo3 {
    void bar3() {
        ...
    }

    void bar4() {
        ...
    }
}

Keep in mind that the basic idea here is that these classes are actually quite tightly-coupled. Perhaps they were originally one large class that has been refactored into several smaller ones, but still maintain a lot of crosstalk. Or perhaps they are simply such specific types of logic that there is just no value in exposing them to the rest of your application. Whatever the reason, I'm assuming that there are solid design goals in making these guys only package-visible.

Hooking this code into your application can now be done in a controlled manner through your method bridge:

final public class Bridge {

    final private Foo1 foo1 = new Foo1();
    final private Foo2 foo2 = new Foo2();
    final private Foo3 foo3 = new Foo3();

    public void bar1() {
        foo1.bar1();
    }

    public void bar2() {
        foo2.bar2();
    }

    public void bar3() {
        foo3.bar3();
    }

    public void bar4() {
        foo3.bar4();
    }

}

Notice that by using this approach, the fact that bar3() and bar4() are both called on the same classtype (and instance, even) is completely concealed from the user of the bridge. This means the internals of the package structure itself can easily be refactored and reorganized without any external code having to change. The bar4() method could easily be moved to the Foo2 class and nobody would be the wiser. Similarly, access to a method can be removed completely simply be removing it from the Bridge class, allowing classes in the package to continue using the method but denying outside code from seeing it.

Filed under  //   Java   programming   tip  

Java Programming Tip: Using Actions in Swing

One poorly-understood area of Swing seems to be the Action class. I don't know how many times I've seen big blocks of code stuffed to the brim setting various attributes of JButtons or JMenuItems and attaching listeners left and right. Wow! What if I told you all that stuff could be done in a single line, like this:

JButton activatorButton = new JButton( new ActivationAction() );

It's true! JButton has (and most of the other interactive Swing components have) a constructor that takes nothing but a single Action. From this Action, Swing is able to configure nearly everything else of importance about the component.

Actions are interesting little classes. In general, you create one by extending AbstractAction to represent a single specific user action, not in terms of the component being triggered, but rather in terms of the user's desired result, such as "Save File". In the Action's constructor, you build up a set of attributes stored by the Action, which are then retrieved by the component (such as the JButton) when the Action is attached. Moreover, the Action serves as a listener to the component, so when the JButton is pressed, the Action is the class that hears the call.

This design enables your application to be written in terms of a set of actions rather than a set of buttons. It's much easier to add and remove entire blocks of functionality (since multiple components can utilize the same Action class) and it removes a lot of the complexity introduced by having "a listener for everything".

In my opinion, this is one of the most elegant aspects of the Swing framework, and sadly, also one of the most underutilized.

Filed under  //   Java   Swing   programming  

Java Programming Tip: Lost in DEFINED_VALUES - Datatypes vs. Constants

There are plenty of situations where you need to identify a few particular "types" of something in your code. For example, maybe you have three kinds of files: User Files, Administrator Files, and Log Files. Generally, the first solution I've seen people employ is to immediately start defining constants somewhere: USER_FILE, ADMIN_FILE, LOG_FILE. You probably know what I'm talking about. Chances are you've even done it. I know I have! Particularly before the introduction of typesafe enums in Java 5, this use of constants was commonplace.

It's a bad idea. The reason why may not be obvious, but let me tell you a story and perhaps it will become clear.

I was once asked to write an event bus to synchronize an application's internal state. I've posted previously about how to properly build an event bus, but at the time it was my first attempt to do so, and I really had no idea what I was doing. I began by writing a big interface file that contained all of the types of events you could possibly fire, defined with Strings associated. You know, stuff like this:

final String COMPONENT_CHANGED_EVENT = "ComponentChanged";

final String MOUSE_PRESSED_EVENT = "MousePressed";

Of course, beyond that, each event could have various specific variables associated with it:

final String COMPONENT_CHANGED_EVENT_COMPONENT_TYPE = "ComponentType";

final String MOUSE_PRESSED_EVENT_BUTTON_ID = "ButtonID";

final String MOUSE_PRESSED_EVENT_TIMESTAMP = "Timestamp";

You get the idea. There were only a handful of events to begin with, so it seemed like a reasonable solution at the time, and had the added benefit (I assumed) of linking the event types to nice human readable names that you could print out if you wanted to.

As you might imagine, the application continued to grow. New event types were introduced, and with them came new variables. Soon the interface file was screen after screen of inscrutable definitions. Worse yet, identifying the type of event in the code that was receiving the events amounted to gigantic switch statements checking for specific entries out of this interface file. It was a bad scene. I wished I could undo it. In fact, I still wish that today. I hope the coders who came after me replaced every bit of it with something more sensible!

So what should I have done instead? I should have utilized the Java language properly, leveraging its strong awareness of datatype, rather than trying to essentially redefine the concept of datatype on my own. I should have extended a common "Event" datatype, and then extended those subtypes further. Beyond simplifying the process of detecting and filtering event types, this would have allowed me to group variable definitions with their specific associated event datatype by putting them inside its definition, rather than by trying to "match the names" in a single huge file.

As misguided as my strategy was, it's not that uncommon, sadly. Most developers don't take it to the same extent, but I've seen it to varying degrees, and it's always ugly. So, if you find yourself trying to identify the "type" of anything by using static final fields or anything similar, stop and think for a moment. Investigate using typesafe enums. Investigate using true datatypes. Down the road you'll thank yourself for it (and maybe you'll remember to thank me, too)!

Filed under  //   Java   constants   datatypes   events   programming   tip  

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.

Filed under  //   Java   events   programming   tip  

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.

Filed under  //   Java   programming   reflection   tip  

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.

Filed under  //   Java   obfuscation   programming   tip  

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.

Filed under  //   Java   programming   tip  

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.

Filed under  //   FOSS   Java   developers   open source  

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.

Filed under  //   FOSS   GPL   Gosling   Java   MySQL   Sun   license   open source