Listening In

So it came to our attention recently that our application was making abundant use of the Observer/Listener pattern. For those not familiar with this pattern, you'd use this guy when you want the outside world to know about state changes in an object. This pattern is used often when developing with various architectural patterns, such as Model-View-Controller (MVC). Other examples, in Java, include many of the components in Swing, java.util.Observable, and java.beans.PropertyChangeListener.

I personally had issues with the extensive use of the listener pattern for us. Every time we added a new data class, we'd have to rewrite code for storing and notifying the listeners. Note that some of this could have been factored out into its own class. Nevertheless, if we ever changed the listener interface, change had to be made for everyone using that interface. Since we use Eclipse, this isn't too big of an issue, but it still bugged me a little. The final issue was, sometimes things needed to listen to events on EVERY instance of a data class, not just a specific instance. To make our lives a little easier, this required us to create a new type of listener that would be statically available (read: like a singleton).

My alternative was to create a messaging system. Before I started this messaging system, I thought about design so that I could generalize it so that it may be of use to others. A couple of the main design decisions that came up were:
  • There should be a concept of a message sender, receiver, and a delivery system to coordinate message sending and receiving.
  • There should be registration facilities to allow the system to become as type-safe and interface-like as possible.
  • Java annotations (retention set to RUNTIME) will be used to define messages and receiver methods
  • When registering a specific receiver instance to receive messages, weak references should be used so that a) the outside world doesn't have to concern themselves with unregistering the instance and b) considering (a), so that the garbage collector can destroy that instance (when necessary).

A test program I wrote up that uses this message system looks something like this. I personally find this a reasonably elegant system, for one that uses reflection. So what do we get out of this? I'll start with the cons (that I can think of) followed by (what I consider to be) the pros:
  • Cons
    • We lose a lot of compile-time error checking
    • We introduce some overhead, mainly due to using the reflection API
  • Pros
    • Adding or removing messages (generally) will require less work elsewhere in the code
    • Receivers only need to implement the messages they want to receive
    • Receivers are not required to name their methods as per an interface
    • Receivers can define what I call "catchall" methods, methods that accept all messages from a specified sender (this could also be done using the observable/listener pattern too, but I believe it would be a little less elegant)
    • Receivers define an accept method which allows them to dynamically control which instances they receive messages from

Currently I'm holding on to this until I feel it satisfies the needs of our score editing project completely, but after that I think I'll release it to the public so that someone else might find some use out of it.

Becoming a Jedi, err...JNI Master!

I myself am far from being a JNI master, since I only started doing my first JNI a few days ago. The problem we were having is that there is no way in Java to get some native behavior on OS X. For example, the closest to native you can get with Open/Save file dialogs is what you get from java.awt.FileDialog, which isn't very much.

Since we're developing in Swing it is key that if we do anything, it should be wrapped up in a neat little package that mimics existing Swing components. Not only that, but we want the behavior of any wrapper classes to be the exact same, or very similar to, the corresponding JComponent. Although it's far from being ready for public release, I currently have a pretty solid JNI library for the Open/Save dialogs in OS X. It's all wrapped up neatly in CarbonFileChooser, an extension to JFileChooser.

One issue that arose, at least for OS X, is that there are various threads that have to run independently: the AWT/Swing thread, and the AppKit thread. Hence, when one makes a native call that is going to be doing some GUI stuff or event-oriented callbacks to the AWT/Swing thread, one has to forward things along to the AppKit thread. This can be done via the performSelectorOnMainThread method. To achieve modality, I use the following code:

public int showSaveDialog(Component parent) {
dialogOpen = true;
result = CANCEL_OPTION;

cc_showSaveDialog(parent);
while(dialogOpen) {
try {
Thread.sleep(100);
} catch(InterruptedException e) { }
}

return result;
}

What happens is that when the dialog is disposed, JNI calls are executed to set the dialogOpen variable to false, breaking the loop. I've been debating trying out wait() and using JNI to wake up the object instead, but for now the above code gets the job done.

Eventually I'm going to release this code library to the public so that anyone can use it, and eventually I'll open-source it (when I'm too lazy to keep maintaining it). The beauty of this, if one is using Swing, is that you really don't change your code at all. Just create the CarbonFileChooser class and you're good to go. Right now things are simple, so just some basic things can be done. You can do the following:
  • Set the initial directory
  • Add choosable filters, set the initial file filter, and get the chosen file filter once the dialog is disposed
  • Get the selected file to open/save
And some things left to do:
  • Multiple file selection and retrieval
  • Show no filters if the "All Files" filter is the only one
  • Setting the initial file name for save dialogs
  • Update dialog to unselect files, as necessary, when filter changes

Java: not always so cross-platform

There's no doubting the fact that Java really makes one's life far easier in general when creating a piece of software that works on various platforms. But even with such power, there's always little things that really can make one's life a pain when creating a piece of software that is intended to be high quality.

One of the major sources of pain in Java is cross-platform GUIs. It's nice that Swing works "out-of-the-box" on most systems, but it often suffers from lacking in a "native" feel, even when using the system LaF. Also, it's sometimes hard to take advantage of platform-specific features that could really open up a world of possibilities for your app.

For our own project we decided to create plugins for various platforms that need more than the standard library offers. I'll talk about our plugin system in a future post. When we distribute platform-specific packages (e.g., a Mac OS X application bundle) we will include the appropriate plugin to extend the functionality of the app for that platform. We prefer this method over checking system properties so that a release never "breaks" when one of these properties magically changes. Anyways, some functionality we require includes:
  • Querying what platform we're on. The application does not suffer when the platform is unknown, but we can provide specific features and an enhanced UI based on a known platform.
  • Directory services. We want to know where the user stores their documents, where is their desktop, etc.
  • Platform-specific GUI components.
So nothing too interesting to talk about in the first 2, but for the last one I can provide a little snippet of our default behaviour:

public T getSwingComponent(Class componentClass, Object... args) {
//
Class[] classes = new Class[args.length];
for(int i = 0; i < args.length; ++i)
classes[i] = args[i].getClass();

//
try {
return componentClass.getConstructor(classes).newInstance(args);
} catch (SecurityException e) {
} catch (NoSuchMethodException e) {
} catch (IllegalArgumentException e) {
} catch (InstantiationException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
return null;
}
So if we want a JToolBar we simply go getSwingComponent(JToolBar.class) and that's it. The implementation provides variable arguments behaviour to elegantly allow usage of all valid constructors. The only thing we lose here is compile-time error checking for incorrect constructor arguments, but this is not too big of an issue for us at the moment. Our platform-specific plugins can override this method to check for various Swing classes, and return an alternate instance of that class if necessary. For example, our OS X plugin returns a simple extension to JMenuBar that removes all icons from any menus added to it (to adhere to the Apple Human Interface guidelines). Another component I plan to work on for OS X a native file dialog (I don't like java.awt.FileDialog). This will probably have me diving into some JNI, which is good because I would like to play around with it. If I can get something decent working there, I'll definitely look into releasing the JNI code publicly.

A really simple technique but it really helps enhance our application and give an improved native feel over what Swing offers.

Beginnings

So I'm going to start my blogging off with an introduction to my project: a free cross platform musical score editor (which currently has no name). Our team consists of just myself and a classmate from my undergrad. We previously worked on a team project during our undergrad (a required course), so we were already familiar with team development.

For me, projects come in two flavors:
  1. those I do simply for my own personal enjoyment, such as a game and,
  2. those that fill a need for me, such as small scripts to get repetitive tasks done.
The musical score editor falls into category 2, but it is definitely an enjoyable project too. I personally found myself unhappy with existing free software for editing scores. Since I focus on guitar, I was looking at something with a simple interface to whip up a guitar tab and be on my way. Probably the best I could find is TuxGuitar, but it was far from a pleasurable experience. This established a need for me, one whose solution we will eventually share with others. So with a project idea, the next thing was to lay out some basic requirements:
  • Cross-platform. I am an OS X user, and my friend is a Linux user.
  • An interface that is both simple for the first-time user, but powerful for the more advanced users.
  • Quick keyboard access to the most common commands to greatly improve throughput.
  • Fully-featured. We want users to be able to do just about anything and everything they'd want to do with their musical scores. Clearly this will take time, but it is our goal.
With these requirements in mind, we decided that Java would make our lives far simpler. We chose Swing over SWT for our GUI library, since we both know and enjoy Swing. Our goal is to eventually bring this project to a level comparable to that of commercial software. It's a big goal, but we're extremely motivated and really enjoy this project. Anyways, some things I plan to blog about in the near future:
  • Java: not always that cross-platform. Various topics on producing code and user-interfaces that feel more native.
  • Working with JNI.
  • Developing a flexible and easy-to-use plugin system.
  • Object-based rendering systems: the pros and the cons.
  • Other cool stuff!
We already have a highly functional and [mostly] stable version of our score editor internally, but we want our first public release to really be something amazing. We have many incredibly powerful features planned, some of which we have never seen before in the area of score editing. Hence, if you're reading this entry you should stay tuned for some good stuff! I'd post a teaser screenshot, but everyone likes a bit of suspense :)

Let's get 'er goin'

So it has been awhile since my last post, but I've been keeping myself busy with research and a large personal project that a friend and I are working on. It's a musical score editor written in Java. I'm keeping this post short but I think I will start blogging about that project, the issues we face, and the decisions we make to resolve these issues. I'll also talk about various design decisions we make, and maybe even some other stuff too, like our rendering system. Hopefully my future posts will provide useful insight and information on various topics surrounding development in Java.