Thursday, March 20, 2008

The secret life of a DefaultTreeModel

This is a draft of a small tutorial I have been attempting to submit to Sun for inclusion in the official Java tutorial. Unfortunately they are very busy lately and have not had the time to review my work. My intent is to bring to light some of the subtleties of the DefaulTreeModel API that are not covered in the Java tutorial on JTree.

This tutorial will revolve around a demo application designed to show the difference between the right and wrong way to interact with DefaulTreeModel. Right clicking on any node in the tree will bring up a menu with a range of options.



Adding and Removing nodes in a DefaultTreeModel.

A DefaulTreeModel collects DefaultMutableTreeNodes together into a tree structure. At first glance the child modification methods like add() and remove() from DefaultMutableTreeNode look as if they overlap with the insertNodeInto() and removeNodeFromParent() from DefaulTreeModel. When the methods from DefaultTreeModel are used events are fired that update any JTree this model may be associated with. Simply modifying the DefaultMutableTreeNode does not. This can be demonstrated by the following chunk of code.

Example of the wrong way to remove a node.
TreePath currentSelection = tree.getSelectionPath();
if (currentSelection != null) {
    DefaultMutableTreeNode node = (DefaultMutableTreeNode)
    currentSelection.getLastPathComponent();
    node.removeFromParent();
}


Calls to methods like add() or remove() from DefaultMutableTreeNode need to be followed by a call to the DefaultTreeModel to notify the JTree of model changes. In our example a call to nodeStructureChanged() on the parent of the node being removed would have allowed the tree to be updated correctly. For adding or removing a single node from a tree the simplest solution is to call the insertNodeInto and removeNodeFromParent methods on DefaultTreeModel.

Example of the correct way to remove a node.
TreePath currentSelection = tree.getSelectionPath();
if (currentSelection != null) {
    DefaultMutableTreeNode node = (DefaultMutableTreeNode)
        currentSelection.getLastPathComponent();
    DefaultTreeModel model = ((DefaultTreeModel) tree.getModel());
    model.removeNodeFromParent(node);
}


There may be situations where multiple additions or removals happen in large blocks. In these cases the model may not need to be notified of a change until the bulk operation is completed. This is exemplified by the following code which adds multiple children to a node.

...
/**
 *
 * Adds 2 children, "even" and "odd". Even contains all the even numbers from zero to 49.
 * Odd contains all the odd numbers from zero to 49.
 */
TreePath currentSelection = tree.getSelectionPath();
if (currentSelection != null) {
    DefaultMutableTreeNode node = (DefaultMutableTreeNode)
        currentSelection.getLastPathComponent();
    DefaultTreeModel model = ((DefaultTreeModel) tree.getModel());

    DefaultMutableTreeNode odd = new DefaultMutableTreeNode("odd");
    node.add(odd);
    DefaultMutableTreeNode even = new DefaultMutableTreeNode("even");
    node.add(even);
    for (int i = 0; i < 50; i++) {
        if (i % 2 == 0) {
            even.add(new DefaultMutableTreeNode(i));
        } else {
            odd.add(new DefaultMutableTreeNode(i));
        }
    }
    // The above changes may not seem to take effect until nodeStructureChanged is called
    model.nodeStructureChanged(node);
}
...


This example creates 52 new nodes. If they were inserted with insertNodeInto() then 52 TreeNodesInserted events would have been fired. This way only one fireTreeStructureChanged event is fired after all the nodes are modified. Depending upon the particular needs of your application this may save some event processing.

Modifying user objects in a DefaultMutableTreeNodes.

Just as a DefaultTreeModel needs to be notified when children are added or removed for a node, so too does it need to be notified when the user object returned by getUserObject() is modified. Failure to do so could lead to rendering issues in the JTree. This is an example of what a such a situation might look like.



To avoid this make sure to call nodeChanged() on the model after any change that might effect the rendering of that node. Here is an example of code that will update correctly.

...
TreePath currentSelection = tree.getSelectionPath();
if (currentSelection != null) {
    DefaultMutableTreeNode node = (DefaultMutableTreeNode)
    currentSelection.getLastPathComponent();

    node.setUserObject("THIS IS A VERY LOOOOOOOOOOOOOOOOOOOOONG STRING");

    DefaultTreeModel model = ((DefaultTreeModel) tree.getModel());
    model.nodeChanged(node);
}
...


When updated correctly the tree will display the entire string.



Conclusion
As a general rule any time the data associated with your DefaulTreeModel changes it is important to update the model. Proper use of the DefaulTreeModel will limit the number of times you must explicitly do this.

I've made the source code for the example available for download.

As I said this is a draft of a tutorial. I'm looking for feedback on what can be improved and added while staying within the scope of the DefaulTreeModel/DefaultMutableTreeNode.

Monday, March 10, 2008

Try and Try Again

While working on the code in my last post it occurred to me that reusable exception handling was decent idea. It might even be nice to create a version of try that takes a parameter that handed specific types of exceptions.

Example:
try {
FileReader fr = new FileReader("Readme.txt");
fr.read();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
A enhanced version might look like this.
try(new LogAndContinueExceptionHandler()){
FileReader fr = new FileReader("Readme.txt");
fr.read();
}
LogAndContinueExceptionHandler looks like this.
private static interface ExceptionHandler {
public void uncaughtException(Runnable source, Throwable e);
}
public class LogAndContinueExceptionHandler implements ExceptionHandler{
@Override
public void uncaughtException(Runnable source, final Throwable e) {
Logger.getLogger("ErrorLogger").log(Level.SEVERE, e.getMessage(), e);
}
}
If all you are going to do is log the exception, then maybe a default implementation in Logger makes sense.
try(Logger.logALL("MyLogName")){
FileReader fr = new FileReader("Readme.txt");
fr.read();
}
And for all of you who think checked exception are the bane of all existence there is this option.
public class ToRuntime implements ExceptionHandler{
@Override
public void uncaughtException(Runnable source, final Throwable e) {
throw new RuntimeException(e);
}
}
This rethrows any exception it gets a hold of as a runtime exception. This would drive me nuts, but some people really do hate checked exceptions.

It would be nice to be able to supply different logic for different types of exceptions, just like you do in a try/catch block. Also if one could handle some logic in the reusable section and override that by implementing a catch block you could get more flexibility.

Example:

try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}

try(new ReflectionHandeler()){
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}

public class ReflectionHandeler implements ExceptionHandler{
public void uncaughtException(Runnable source, final ClassNotFoundException e) {
// do something important
}

public void uncaughtException(Runnable source, final InstantiationException e) {
// do something important
}

public void uncaughtException(Runnable source, final IllegalAccessException e) {
// do something important
}
}

ReflectionHandeler might be useful someplace else... Ok this wasn't the best example, but you get the idea. Some get caught in the handler and some get caught in the catch.

Where a pattern for handling an exception or types of exceptions is repeatable building a reusable part can help unclutter and your code and make it more maintainable. Now if the task of handling a particular type of exception changes code need only be changed in one place, not scattered throughout the code in try blocks.

It's an idea. I may try to hack the javac compiler to support something like this... not that I'm sure even where to begin.

Sunday, March 9, 2008

More First Class Methods Code

I'm still experimenting with the prototype implementation of the FCM closures proposal. Here are a few utility methods that immediately came to mind.

withLock -- This one I've seen an example of online a few times. It automatically release the lock when the block of code finishes executing.
public static void withLock(Lock lock, Runnable task) {
lock.lock();
try {
task.run();
} catch (Exception e) {
throw e;
} finally {
lock.unlock();
}
}
Example Usage:
final ReentrantLock lock = new ReentrantLock();
withLock(lock, #{
// call some important locked code
});
Now I'm not too fond of unchecked Exceptions, but rethrowing is still better then swallowing every exception that escapes the Runnable. Here is my second attempt.
private static interface ExceptionHandler {
public void uncaughtException(Runnable source, Throwable e);
}

public static void withLock(Lock lock, Runnable task, ExceptionHandler eHandel) {
lock.lock();
try {
task.run();
} catch (Exception e) {
eHandel.uncaughtException(task, e);
} finally {
lock.unlock();
}
}
Example Usage:
withLock(lock, #{
// do some code that needs to be locked.
// throw an exception to test the event handler.
throw new RuntimeException("year is even error");
}, #(Runnable source, Throwable e){
// inline implemented event handler.
e.printStackTrace();
}
);
Once side effect of this is now one might be able to write reusable exception handling code. There have been plenty of times where a method I'm executing throws an exception, but there is no real way for me to recover. All I can do is log the failure and continue on. I end up writing the same try catch block over and over. It would be nice to write something like this once and reuse it.
public class LogAndContinueExceptionHandler implements ExceptionHandler{
public void uncaughtException(Runnable source, final Throwable e) {
SwingUtilities.invokeLater(#{
Logger.getLogger("ErrorLogger").log(Level.SEVERE, e.getMessage(), e);
});
}
}
Example Usage:
withLock(lock, #{
// do some code that needs to be locked.
// throw an exception to test the event handler.
throw new RuntimeException("year is even error");

}, new LogAndContinueExceptionHandler());
I used this idea when exploring another area that might benefit from closures. The EDT thread scheduling methods.

invokeAndWait
public static void invokeAndWait(Runnable r, ExceptionHandler eHandel){
try {
SwingUtilities.invokeAndWait(r);
catch (InterruptedException e) {
eHandel.uncaughtException(e);
} catch (InvocationTargetException e) {
eHandel.uncaughtException(r, e.getCause());
}
}

public class AlertAndContinueExceptionHandler implements ExceptionHandler{
public void uncaughtException(Runnable source, final Throwable e) {
Runnable showMessageBox = #{
JOptionPane.showMessageDialog(null, e.getMessage());
};
if(SwingUtilities.isEventDispatchThread()){
showMessageBox.run();
}else{
SwingUtilities.invokeLater(showMessageBox);
}
}
}
Example Usage:
invokeAndWait(#{
JOptionPane.showMessageDialog(null, "Hello World");
}, new AlertAndContinueExceptionHandler());
simpleSwingWorker -- The simpleSwingWorker method is an attempt to apply closures to the simple case of, "do something off the EDT then do something ON the EDT".
public static void simpleWorker(final Runnable offEDT, final Runnable onEDT){
Thread bGround = new Thread(#{
offEDT.run();
SwingUtilities.invokeLater(onEDT);
});
bGround.start();
}
Example Usage:
simpleWorker(#{
System.out.println("sleep");
Thread.currentThread().sleep(1000);
System.out.println("start");
}, #{
JOptionPane.showMessageDialog(null, "Hello World");
});
I also wrote a blocking version based on invokeAndWait.
public static void simpleBlockingWorker(final Runnable offEDT, final Runnable onEDT){
Thread bGround = new Thread(#{
offEDT.run();
SwingUtilities.invokeAndWait(onEDT);
});
bGround.start();
}

Hay wait a second, invokeAndWait throws exceptions right? And yet the code as it stands compiles without issue. I think I may have found a bug in the FCM prototype.

Some may look at these examples and point out that this type of functionality may really fall into the realm of "control structures". There is some debate in the Java community as to weather the common man should be allowed to write their own control structures. Some prefer to leave this responsibility with the language designers. It is my opinion that once you make this type of code easy, then you already have allowed the common man to make their own control structures. In that case you might as well legitimize the pattern and provide as much support as it possible.

I look forward to the day when there is a Java Control Abstraction (JCA) prototype to play around with.

Wednesday, March 5, 2008

Experimenting with FCM

Stephen Colebourne has a prototype implementation of the FCM closures proposal. I took some time to download and play with the new syntax and functionality.

I tried to focus on some of the functionality FCM provides that other closure proposals do not. Namely method and field literals. I think FCM can help create flexible models for swing components. In the past I've done this using plain reflection but FCM makes things easier.

This is a screenshot of the demo application.

It displays three lists and one table all of which are backed by the same collection of SuperHero beans.

I found that I could apply FCM in one of the first few lines of my demo.
SwingUtilities.invokeLater(#startApp());
This calls my startApp() method on the event dispatch thread. I have to admit that while I'm not a fan of in-lining this was preferable to the traditional method of building a Runnable and passing that to invokeLater.

Here is a very basic ListModel that can expose any public field of an object.
   /**
* Wraps a list of elements and exposes one field to the list model
* interface
*
* @param <E>
*/
private class FCMFieldListModel<T> extends AbstractListModel {

private List<T> backingList;
private Field targetField;

public FCMFieldListModel(List<T> data, Field target) {
backingList = data;
targetField = target;
}

@Override
public Object getElementAt(int index) {
try {
return targetField.get(backingList.get(index));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}

@Override
public int getSize() {
return backingList.size();
}

}
In my case I'm building a list of superheroes and wish to expose the last name field.

FCMFieldListModel<SuperHero> lastListModel = new FCMFieldListModel<SuperHero>(heroes, SuperHero#lastName);

The last parameter is the new field literal syntax from FCM. It allows me a type safe way of specifying which field I want to expose.

To create more list models that expose other fields I just need to create another FCMFieldListModel and expose a different field.

FCMFieldListModel<SuperHero> listModel = new FCMFieldListModel<SuperHero>(heroes, SuperHero#firstName);

Now most of the time a bean will not expose a field. Instead getter/setter methods are used to expose this information. FCM has method literals as well as field literals. The code for a FCMMethodListModel is very much like FCMFieldListModel but it takes a Method reference instead of a field refrence.

/**
* Wraps a list of elements and exposes one method to the list model
* interface
*
* @param <E>
*/
private class FCMMethodListModel<E> extends AbstractListModel {

private List<E> backingList;
private Method targetMethod ;

public FCMMethodListModel(List<E> data, Method target) {
backingList = data;
targetMethod = target;
}

@Override
public Object getElementAt(int index) {
try {
Object item = backingList.get(index);
return targetMethod.invoke(item);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}

@Override
public int getSize() {
return backingList.size();
}

}
Basically this lets you tell the list model which method of your bean to call to represent your bean in the list.

Finally I used this same technique to build a table model.
FCMTableModel<SuperHero> superTableModel = new FCMTableModel<SuperHero>(heroes,
SuperHero#getFirstName(), SuperHero#getLastName(),
SuperHero#getHeroName(), SuperHero#getFirstAppearance());

The constructor takes a list of SuperHeroes and a variable list of methods to use as columns. This code is all it takes to populate the table seen in the center of the screenshot.

The first appearance column of the super hero table is a date without a day. I decided to use an anonymous inner method to implement a cellrendrer to format the date.
TableColumn dateColumn = superHeroTable.getColumn(SuperHero#getFirstAppearance().getName());

// in-line cell renderer for the date column of the superhero table
dateColumn.setCellRenderer(#(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column){
if(isSelected){
dateRenderer.setBackground(UIManager.getColor("Table.selectionBackground"));
}else{
dateRenderer.setBackground(UIManager.getColor("Table.background"));
}
dateRenderer.setText(sdfDateColumn.format((Date) value));
return dateRenderer;
});
Overall I have to say I like FCM. Even in it's incomplete state I feel it's still a step forward. The method and field literals were very convenient and useful. I can see myself creating generalized adapter classes around this functionality. As I said before I'm not a fan of in-lining code. I tend not to in-line inner classes either. But the anonymous inner method syntax seemed straight forward enough. Also I much prefer using the # syntax to pass method to invokeLater.

My examples involved a bean and it's associated methods. Yet there is no way currently to specify that a method used as a parameter come from any specific class. It certainly would be an error to pass a FCMMethodListModel System.out#println(Object). I think this is one of the items on the list of things to do for FCM but I'm not certain.

I've made the source code for this demo available on google docs. Just remember that you need the prototype FCM implementation to run it.

Finally I'd just like to thank
Stephen for all his hard work in creating this prototype. It's been fun to experiment with it.

Note:
This is demo level code. It was written to play around with FCM and a such the models are not as robust as they could be. Their job is to adapt an unchanging list of beans using FCMs method literals. I will probably revisit FCMTableModel at some point to show how it could be enhanced. As it stands now they have no support for events. Also I'm not sure a cell renderer was a good choice for an anonymous inner method example. If you read the javadoc for DefaultTableCellRenderer it talks about overriding some of the JLabel methods for performance reasons.