How to fix right click JTree selection and JPopupMenu so your JTree feels native

April 26th, 2011 Nick Posted in java, swing No Comments »

I’ve found a way of fixing two JTree problems which have been driving me up the wall recently:

1. Right clicking tree nodes in windows should select nodes in the tree, before showing the popup menu.

2. When the popup menu is displayed under Windows look and feel, clicking away from it on another tree node dismisses the popup but does not immediately select that node.

Problem 1. is equally relevant to JTables, see the notes at the bottom of this post

These issues seem relatively minor in themselves, but taken together they are enough to make your UI seem clunky and frustrating to use, especially if the JTree is a central component. Solving both of the above problems saves mouse clicks and make the user experience more fluid. Luckily, both of the above problems can be fixed fairly easily, the first by adding some MouseListener code to manually update the selections before the popup is shown, and the second simply by setting a magic property in UIManager –

UIManager.put(“PopupMenu.consumeEventOnClose”, Boolean.FALSE);

So, without more ado, let’s look at some code to fix this..

Here is a complete example which creates a tree with a fixed popup menu. The key bits for the fix are the setting of the magic property and the method setSelectedItemsOnPopupTrigger()

import javax.swing.*;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

/**
 * A JTree with mouse listener logic to select items on right click,
 * before showing a popup
 *
 * Also sets the magic PopupMenu property to fix the windows look and
 * feel, so that clicking outside the popup will select items in the
 * tree first time, rather than even being consumed by the closing popup
 */

public class FixedPopupJTree extends JTree {

    static {
        //Set the magic property which makes the first click outside the popup
        //capable of selecting tree nodes, as well as dismissing the popup.
        UIManager.put("PopupMenu.consumeEventOnClose", Boolean.FALSE);
    }

    public FixedPopupJTree() {
        getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
        addMouseListener(new ShowPopupMouseListener());
    }

    private class ShowPopupMouseListener extends MouseAdapter {

        public void mousePressed(MouseEvent e) {
            showMenuIfPopupTrigger(e);
        }

        public void mouseClicked(MouseEvent e) {
            showMenuIfPopupTrigger(e);
        }

        public void mouseReleased(MouseEvent e) {
            showMenuIfPopupTrigger(e);
        }

        private void showMenuIfPopupTrigger(final MouseEvent e) {
            if (e.isPopupTrigger()) {
                //set the new selections before showing the popup
                setSelectedItemsOnPopupTrigger(e);

                //build an example popup menu from selections
                JPopupMenu menu = new JPopupMenu();
                for ( TreePath p : getSelectionPaths()) {
                    menu.add(new JMenuItem(p.getLastPathComponent().toString()));
                }

                //show the menu, offsetting from the mouse click slightly
                menu.show((Component)e.getSource(), e.getX() + 3, e.getY() + 3);
            }
        }

         /**
         * Fix for right click not selecting tree nodes -
         * We want to implement the following behaviour which matches windows explorer:
         * If the item under the click is not already selected, clear the current selections and select the
         * item, prior to showing the popup.
         * If the item under the click is already selected, keep the current selection(s)
         */

        private void setSelectedItemsOnPopupTrigger(MouseEvent e) {
            TreePath p = getPathForLocation(e.getX(), e.getY());
            if ( ! getSelectionModel().isPathSelected(p)) {
                getSelectionModel().setSelectionPath(p);
            }
        }
    }

}

One warning, this solution is based on the Windows look and feel, and aim to match the standard explorer tree behaviour for Windows. It may or may not be appropriate for other platforms – if you are expecting your UI to be used on other platforms, you’ll have to verify for your self whether these techniques are useful.

Here is a simple test program which demonstrates the fixed behaviour. To see what it is like when it is not fixed, comment out the lines in FixedPopupJTree which set the UIManager property, and the mouse listener line which calls setSelectedItemsOnPopupTrigger()

import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeModel;
import java.awt.*;

public class TestFixPopupTree {

    //A simple test frame to show the effect of these fixes
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                try {
                    UIManager.setLookAndFeel(WindowsLookAndFeel.class.getName());
                } catch (Exception e) {
                    e.printStackTrace();
                }

                FixedPopupJTree fixedPopupJTree = new FixedPopupJTree();

                TreeModel treeModel = createExampleTreeModel();
                fixedPopupJTree.setModel(treeModel);

                JFrame frame = new JFrame();
                frame.getContentPane().add(new JScrollPane(fixedPopupJTree));
                frame.setSize(new Dimension(300, 600));
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLocationRelativeTo(null); //centre on screen
                frame.setVisible(true);
            }
        });
    }

    private static TreeModel createExampleTreeModel() {
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
        for ( int child = 0; child <=10 ; child++) {
            root.add(new DefaultMutableTreeNode("child-" + child));
        }
        DefaultTreeModel treeModel = new DefaultTreeModel(root);
        return treeModel;
    }
}

One wonders why the above behaviour isn’t implemeted as standard in the Windows look and feel for the latest JDK (I’m using jdk 1.6.0_22 as I write this). I guess it’s a case of the Swing dev team not wanting to break backwards compatibility. Although it fixes the issues, modifying the behaviour of the ui like this would represent a singificant change to the toolkit. I’m guessing this is why Swing seems to have an increasing number of ‘magic’ properties, such as the JPopupMenu property above. Supporting the use of a new property to change the behaviour is a sure way not to break functionality for existing applications – but it does require the new property to be documented if it is going to be useful, and it requires the developers of new apps to know about the property, and set it – and sadly it seems that’s not the case. Perhaps I should put together a web page to bring together all these magic properties.

In fact, these issues are related to know bugs, but the solutions don’t appear to be documented anywhere else very clearly. The bugs I found so far are below:
Bug 4196497
Bug 6753637

Incidentally, the fix for number 1 above is equally relevant for JTables which support discontiguous selection. In this case, you just need to change the popup mouse listener to update the table selection rather than the tree selection, which you can do in the following way:

protected void setSelectedItemsOnPopupTrigger(MouseEvent e) {
    int row = table.rowAtPoint(e.getPoint());
    boolean selected = table.getSelectionModel().isSelectedIndex(row);
    if ( ! selected ) {
      table.getSelectionModel().setSelectionInterval(row, row);
    }
}

AddThis Social Bookmark Button

Intellij patch not working on Windows 7 or Vista

April 4th, 2011 Nick Posted in java 3 Comments »

Just a quick tip, since I googled it and didn’t find anything much to help!

The intellij patch never seemed to work for me, and I kept having to reinstall from scratch to get a new minor version, until I tried running Intellij with Administrator privileges
Right clicking the intellij startup shortcut and running the program as administrator seems to help – after that the patch seems to install fine, on the restart.
If you’re having similar problems, I suggest you give that a go

AddThis Social Bookmark Button

Sparse arrays within Java collections can cause memory leaks.

November 19th, 2010 Nick Posted in java 2 Comments »

Here’s one java interview question which seemes to come up a lot – when would you use an ArrayList, and when would you use a LinkedList?

Well, there are various reasons to prefer each, but one thing which probably wouldn’t leap to mind initially is memory efficiency. If you do consider memory efficiency, it might first seem that ArrayList should be more efficient – in a LinkedList, each node has to retain a pointer to the next (and previous) nodes, and this is not required when you store the data in an array.

However, things re not so simple. Firstly, there are tradeoffs made by the ArrayList implementation which tend to mean that the internal array is larger than it actually needs to be to hold the number of objects required by list.size(). If this wasn’t the case, a new larger internal array would have to be created whenever you add an item to the list, which is a very expensive operation if performed frequently. So the tradeoff is to initialize the internal array with extra empty elements. Only when these empty indexes are filled will the internal array be resized. When this occurs, the new size is generally calculated using the following formula – (oldCapacity * 3)/2 + 1 – which will most likely mean that once more there are a significant number of unused indexes. So all your ArrayList instances are probably holding on to a lot of wasted memory taken up by their sparsely populated internal arrays.

This might not seem all that significant at first glance, and it seems as if the effect of the empty indexes would be outweighed by the extra node references in a LinkedList. But there are some other more surprising drawbacks with an ArrayList:

Firstly, an ArrayList is generally created with an initial internal array length of 10. (You can change this by passing an alternative length into the constructor – but few people generally bother). Lets say in a hypothetical system, you have many lists which are empty, or have very small size. Perhaps, for example, your system has lots of observable classes (bean classes for instance), and each bean stores listener references in an ArrayList. Let’s imagine your system has ten thousand bean instances, and most beans have no listeners. Even with no listeners the ten thousand ArrayList instances would still have 100,000 empty references from their internal arrays. This is starting to look like a significant waste of memory. It’s certainly worth considering initializing your ArrayLists with a default capacity of zero.

But there is an even more significant drawback. That is, the internal array of an ArrayList never shrinks, unless you specifically request this to happen by calling the trimToSize() method. Perhaps surprisingly, this does not happen automatically if you call ArrayList clear(). This means that whenever you add a large number of items to an ArrayList, you may be losing memory forever – even if you subsequently remove the items again or clear the list. Unless you remember to call trimToSize() or the list itself becomes free for garbage collection, the empty references in the internal array will be retained for the life of the app. And how often have you seen trimToSize() called in java applications?

This is not a purely academic problem. An application I have been working on recently used ArrayList as a mechanism to buffer incoming messages for future processing. In general, a large burst of 100,000 messages was received on startup, after which the rate slowed to tens or hundreds. The initial messages would cause the ArrayList’s internal array to be sized to over 100,000 elements. Unfortunately, although this amount of buffering would never again be required, these 100,000 references effectively became leaked memory, since although ArrayList clear() was called when processing the messages, trimToSize() was never invoked. There was a separate buffer of this type for each message type, which cost several megabytes in lost memory overall. Using a LinkedList would not have caused this problem, since there is no internal array in a LinkedList implementation which can leak references.

This problem with sparse arrays is not limited to ArrayList. It is the case for Maps too, and even more worryingly so, since in many Map implementations there is not even a method to call to shrink the internal array. HashMap, for example, contains an array internally, sized to a power of two, which is expanded as required as the map grows. The internal array never shrinks if you remove items or clear the map. There is no trimToSize() method. The only way you can get around this, and free up the memory held by the map’s internal array, is to create a new Map instance (passing in any current mappings which are still required) and throw the old Map instance away. This is the approach I took with a recent performance enhancement to an application which uses IdentityHashMap heavily – and this resulted in a decrease in memory usage of over 10%, or 50MB in a 500MB application. This is a huge impact for a problem which I was largely unaware of, and has gone pretty much under the radar until now.

I think if there is one thing which could be changed in the jdk to improve this, it would be for the clear methods of collections to shrink the internal arrays back to their initial size by default.

AddThis Social Bookmark Button

New jtimeseries project on sourceforge

May 20th, 2010 Nick Posted in java, jtimeseries, web, xml No Comments »

For the last year and a half I have been hard at work at a new open source project jtimeseries.

This has finally made it onto sourceforge!

So what can you do with this jtimeseries thing?

Quite a lot, already. Let me explain how this project was conceived….

Initially, I was looking for a java based API which I could use to capture metrics for a Swing application I was working on. Rather than store the raw values I was collecting, I needed a way to capture, for example, the mean value of a certain measurement over a time period (e.g. the mean price latency over the last five minutes, or the 90th percentile heap memory). As well as capturing and storing the stats, I also needed ui visualizer components to enable viewing of the data, and wanted to also show the stats collected via an embedded web server in the application.

how about storing the data?

A logical extension once the core API was up and running was to provide a lightweight database component to persist the timeseries data on the server side, in a round robin file format (noting here that there is no java api for rddtool presently, which gave me ample license to write one myself I think!). The server can store stats from multiple sources – and you can subscribe to view the series from the ui.

collecting stats from jmx

The other really neat feature of the database, is that it can be configured to read in metrics data directly via the jmx management service of a running java app. This means that you can capture details, such as the memory and cpu load of your other java components without having to change their code and re-release them! You just need to have the jvm jmx management feature enabled, so that you can point a jconsole at the app and see values.

New release

So that’s how it all came about. We now have a stable release, 1.0.10, which you can find here

At present I am consulting for a company which now has two instances of the timeseries server, currently maintaining nearly 50,000 time series, which provide stats on the performance of dozens of our production and UAT components going back over a few months. The benefits of this are massive. It’s easy to spot performance problems before they become a major issue. Most importantly, before a release takes place, it’s easy to see from the stats whether a new component version has worse performance than its predecessor – without even having to fire up the profiler.

I’ll be adding more documentation on jtimeseries over the next couple of weeks



AddThis Social Bookmark Button

How to find the pid of a java process from code

March 3rd, 2010 Nick Posted in java No Comments »

This blog has been quiet for a while, that’s about to change, but in the meantime I came across a very interesting way to get hold of the PID for your running java process from code, which I thought I’d put up straight away.

This makes use of the Management JMX beans to find the information, but the good news is that it seems you don’t have to do anything special, such as add VM system properties, to make it work.

Not sure this will work on every OS/vm, but on the ones I have tried there’s no problem.
Seems to work on both Windows on Linux

For me, the below produces:
ProcessName=[1136@iblongsw253311]
PID=[1136]

public static void main(String[] args) {
        try {
            RuntimeMXBean mx = ManagementFactory.getRuntimeMXBean();
            String s = mx.getName();
            System.out.println("ProcessName=["+s+"]");
            String[] pidAndHost = s.split("@");
            if ( pidAndHost.length == 2) {
                int pid = Integer.valueOf(pidAndHost[0]);
                System.out.println("PID=[" + pid + "]");
            }
        }
        catch( Exception e) {
            System.out.println("Whoops, can't find a PID");
        }
    }
AddThis Social Bookmark Button

JTable setRowHeight causes slow repainting

June 6th, 2009 Nick Posted in java, swing 7 Comments »

I’ve spent way too much time in the last few months fixing and optimising table rendering performance for a high performance Java application I’m working on at the moment. The problems were particularly hard to find becuase the app supports customization of almost every aspect of JTable UI, with custom rendering for rows, columns and individual cells according to user preferences. Some users would get terrible performance on some days, which would seem to disappear the next.

Some of the issues were hardware and graphics driver related, and there have been various minor and major victories along the way (more about these later), but just yesterday I found a very significant defect in JTable.tableChanged().

The problem occurs when you call setRowHeight(int row, int height) on a JTable, to set a customised table row height. You only need to do this once, and that causes JTable to initialize its internal rowModel to maintain the custom row heights. From that point onwards, any update to the TableModel (even if it is just an update event for a single cell()) will be processed by JTable.tableChanged() in such a way that the entire table component is marked as dirty. So this forces the RepaintManager to repaint the entire table every time, even for single cell updates.

The point at which everything appears to go wrong is at JTable line 4396 (in jdk 1.6.0_14) and line 3021 (in jdk 1.5.0_17), which is part of the processing for TableModel update events

// The totalRowHeight calculated below will be incorrect if
// there are variable height rows. Repaint the visible region,
// but don't return as a revalidate may be necessary as well.
if (rowModel != null) {
    repaint();
}

Essentially, if there is an internal rowModel set up (i.e the user has configured some custom row heights), then the call to repaint() in this snippit causes the entire JTable to be marked as dirty – so the RepaintManager repaints the entire table component rather than just the cells affected by an update.

The effect of this is dramatic. When I run my test class (included below):

***** Running test for table Standard JTable under 1.5.0_19
With all rows default height total time spent repainting table 24 millis
Setting custom row height for one row
With one custom row height total time spent repainting table 5427 millis
Thats 226 times slower than it should be to paint the table!

Here is a Fix for the issue

I’m pretty surprised this issue hasn’t been fixed already, since custom row heights can’t be all that rare. I have produced a workaround by extending JTable to override the tableChanged() handling for update events. Fixing this has solved major problems for our users whose tables were configured to require custom row heights.

This works fine for for me in 1.5.*.
It will also work for jdk 1.6.* but it does not support the 1.6 table row sorting (you’d need to find a way to fire sortedTableChanged() events to the sortManager to do this when the updates are processed)

   import javax.swing.table.TableModel;
import javax.swing.event.TableModelEvent;
import javax.swing.*;
import java.awt.*;


/**
 * Extends JTable to fix the broken repainting for updates when there are custom height rows
 * See http://www.objectdefinitions.com/odblog/2009/jtable-setrowheight-causes-slow-repainting/
 *
 * This fix does not support row sorting in jdk1.6 -
 * to support that would require firing sortedTableChanged to sortManager
 */

public class FixedForRowHeightJTable extends JTable {

    public FixedForRowHeightJTable() {
    }

    public FixedForRowHeightJTable(TableModel tableModel) {
        super(tableModel);
    }

    public void tableChanged(TableModelEvent e) {
        //if just an update, and not a data or structure changed event or an insert or delete, use the fixed row update handling
        //otherwise call super.tableChanged to let the standard JTable update handling manage it
        if ( e != null &&
            e.getType() == TableModelEvent.UPDATE &&
            e.getFirstRow() != TableModelEvent.HEADER_ROW &&
            e.getLastRow() != Integer.MAX_VALUE) {

            handleRowUpdate(e);
        } else {
            super.tableChanged(e);
        }
    }

    /**
     * This borrows most of the logic from the superclass handling of update events, but changes the calculation of the height
     * for the dirty region to provide proper handling for repainting custom height rows
     */

    private void handleRowUpdate(TableModelEvent e) {
        int modelColumn = e.getColumn();
        int start = e.getFirstRow();
        int end = e.getLastRow();

        Rectangle dirtyRegion;
        if (modelColumn == TableModelEvent.ALL_COLUMNS) {
            // 1 or more rows changed
            dirtyRegion = new Rectangle(0, start * getRowHeight(),
                                        getColumnModel().getTotalColumnWidth(), 0);
        }
        else {
            // A cell or column of cells has changed.
            // Unlike the rest of the methods in the JTable, the TableModelEvent
            // uses the coordinate system of the model instead of the view.
            // This is the only place in the JTable where this "reverse mapping"
            // is used.
            int column = convertColumnIndexToView(modelColumn);
            dirtyRegion = getCellRect(start, column, false);
        }

        // Now adjust the height of the dirty region
        dirtyRegion.height = 0;
        for ( int row=start; row <= end; row ++ ) {
            dirtyRegion.height += getRowHeight(row);  //THIS IS CHANGED TO CALCULATE THE DIRTY REGION HEIGHT CORRECTLY
        }
        repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
    }

}

The following Test demonstrates the problem, and that FixedForRowHeightJTable solves it

This test pops up a JTable in a frame and then changes cell values to trigger repaints.
While doing this we replace the standard RepaintManager with a TimingRepaintManager, which keeps track of the total time spent by the Swing event thread painting the table
We first run the test for a standard JTable, then for my fixed version, with the following results:

***** Running test for table Standard JTable under 1.5.0_19
With all rows default height total time spent repainting table 24 millis
Setting custom row height for one row
With one custom row height total time spent repainting table 5427 millis

***** Running test for table FixedForRowHeight JTable under 1.5.0_19
With all rows default height total time spent repainting table 2 millis
Setting custom row height for one row
With one custom row height total time spent repainting table 25 millis

Needless to say, I’ve submitted a bug report for this one!
(although technically once might argue its an RFE, since the table still gets painted, anything which degrades performance this much is a bug in my book!)

import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.*;
import javax.swing.event.TableModelEvent;
import java.awt.*;
import java.lang.reflect.InvocationTargetException;

/**
 * Created by IntelliJ IDEA.
 * User: Nick Ebbutt
 * Date: 06-Jun-2009
 * Time: 13:34:58
 *
 * A demonstration of JTable repainting bug for custom row heights
 */

public class DemoForJTableCustomRowHeightRepaintBug {

    private static final int COL_COUNT = 40;
    private static final int ROW_COUNT = 50;
    private static TimingRepaintManager timingRepaintManager;
    private static JTable table;
    private static FixedForRowHeightJTable fixedTable;

    public static void main(String[] args) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                timingRepaintManager = new TimingRepaintManager();
                RepaintManager.setCurrentManager(timingRepaintManager);
                table = new JTable(new TestTableModel());
                fixedTable = new FixedForRowHeightJTable(new TestTableModel());
            }
        });

        runTestForTable("Standard JTable", table);
        runTestForTable("FixedForRowHeight JTable", fixedTable);
    }

    private static void runTestForTable(String description, final JTable table) throws Exception {
        System.out.println("\n***** Running test for table " + description + " under " + System.getProperty("java.version"));
        showTable(table, description);
        timingRepaintManager.resetTotalRepaintTime();
        runTableModelUpdates(table.getModel());

        System.out.println("With all rows default height total time spent repainting table " + timingRepaintManager.getTotalRepaintTime() + " millis");

        System.out.println("Setting custom row height for one row");
        setRandomRowHeight(table);

        timingRepaintManager.resetTotalRepaintTime();
        runTableModelUpdates(table.getModel());
        System.out.println("With one custom row height total time spent repainting table " + timingRepaintManager.getTotalRepaintTime() + " millis");
    }

    private static void setRandomRowHeight(final JTable table) throws InterruptedException, InvocationTargetException {
        //now just set one row to a custom height and run the repaint timing test again
        SwingUtilities.invokeAndWait(
            new Runnable() {
                public void run() {
                    table.setRowHeight(getRandomRowOrCol(ROW_COUNT), 100);
                }
            }
        );
    }

    public static void showTable(final JTable t, final String name) throws Exception {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
                JFrame f = new JFrame(name);
                f.getContentPane().add(new JScrollPane(t));
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setSize(new Dimension(1024,768));
                f.setVisible(true);
            }
        });
    }

    public static void runTableModelUpdates(final TableModel tableModel) {
        for ( int loop=0; loop < 500; loop++) {
            try {
                SwingUtilities.invokeAndWait(new Runnable() {
                    public void run() {
                        tableModel.setValueAt("Wibble", getRandomRowOrCol(ROW_COUNT), getRandomRowOrCol(COL_COUNT));
                    }
                });
                Thread.sleep(10);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    //record the total time spent repainting
    private static class TimingRepaintManager extends RepaintManager {
        private volatile long totalTime;

        public void paintDirtyRegions() {
            long startTime = System.currentTimeMillis();
            super.paintDirtyRegions();
            totalTime += System.currentTimeMillis() - startTime;
        }

        public long getTotalRepaintTime() {
            return totalTime;
        }

        public void resetTotalRepaintTime() {
            this.totalTime = 0;
        }
    }


    private static class TestTableModel extends DefaultTableModel {
        public TestTableModel() {
            setColumnCount(COL_COUNT);
            for (int row=0; row < ROW_COUNT; row++) {
                addRow(createRow(row));
            }
        }

        private Object[] createRow(int row) {
            String[] colNames = new String[COL_COUNT];
            for ( int col=0; col<COL_COUNT; col++) {
                colNames[col] = "Cell " + row + ":" + col;
            }
            return colNames;
        }
    }

    public static int getRandomRowOrCol(int maxVal) {
        return (int)(Math.random() * maxVal);
    }

    /**
     * Extends JTable to fix the broken repainting for updates when there are custom height rows
     *
     * This fix does not support row sorting in jdk1.6 -
     * to support that would require firing sortedTableChanged to sortManager
     */

    private static class FixedForRowHeightJTable extends JTable {

        public FixedForRowHeightJTable(TableModel tableModel) {
            super(tableModel);
        }

        public void tableChanged(TableModelEvent e) {

            //if just an update, and not a data or structure changed event or an insert or delete, use the fixed row update handling
            //otherwise call super.tableChanged to let the standard JTable update handling manage it
            if ( e != null &&
                e.getType() == TableModelEvent.UPDATE &&
                e.getFirstRow() != TableModelEvent.HEADER_ROW &&
                e.getLastRow() != Integer.MAX_VALUE) {

                handleRowUpdate(e);
            } else {
                super.tableChanged(e);
            }
        }

        /**
         * This borrows most of the logic from the superclass handling of update events, but changes the calculation of the height
         * for the dirty region to provide proper handling for repainting custom height rows
         */

        private void handleRowUpdate(TableModelEvent e) {
            int modelColumn = e.getColumn();
            int start = e.getFirstRow();
            int end = e.getLastRow();

            Rectangle dirtyRegion;
            if (modelColumn == TableModelEvent.ALL_COLUMNS) {
                // 1 or more rows changed
                dirtyRegion = new Rectangle(0, start * getRowHeight(),
                                            getColumnModel().getTotalColumnWidth(), 0);
            }
            else {
                // A cell or column of cells has changed.
                // Unlike the rest of the methods in the JTable, the TableModelEvent
                // uses the coordinate system of the model instead of the view.
                // This is the only place in the JTable where this "reverse mapping"
                // is used.
                int column = convertColumnIndexToView(modelColumn);
                dirtyRegion = getCellRect(start, column, false);
            }

            // Now adjust the height of the dirty region
            dirtyRegion.height = 0;
            for ( int row=start; row <= end; row ++ ) {
                dirtyRegion.height += getRowHeight(row);  //THIS IS CHANGED TO CALCULATE THE DIRTY REGION HEIGHT CORRECTLY
            }
            repaint(dirtyRegion.x, dirtyRegion.y, dirtyRegion.width, dirtyRegion.height);
        }
    }

}
AddThis Social Bookmark Button

Lower bound wildcards in java – how to apply the get and put principle

February 27th, 2009 Nick Posted in java No Comments »

I recently saw an answer to a generics question on stack overflow where an incorrect (or at least misleading) answer has been voted up to the top. Sometimes generics are just a bit unintuitive.

Here is the example in a nutshell -

   addToList(List<? super Shape> l) {
    l.add(new Object());
}

 // That should work, right? After all List<? super Shape> is defined so that it can hold
 // any objects which implement a superclass of Shape....

In fact, the code above would not compile. That’s the wrong way to interpret the lower bound wildcard. The variable l actually refers to a List which may be restricted to contain any valid superclass of Shape – and we don’t know exactly what type of List it is from the lower bound reference. It may actually be a List of Drawable (if Shape extends Drawable), in which case adding an Object to it would not be safe – since an Object is not necessarily Drawable. It may also be a List of Shape instances (since Shape is the lower bound), in which case adding an Object to it would also be invalid. That’s why the example above does not compile.

There is an important principle set out in Java Generics and Collections, called the ‘Get and Put Principle’ which helps to explain when to use lower and upper bound wildcards

Use an extends wildcard when you only get values out of a structure, use super wildcard when you only put values into a structure, and don’t use a wildcard when you both get and put.

Proper use of this rule can make your classes more flexible. Partly to make sure I’ve got this fully straightened out in my own head, I’ve put together an example which illustrates the get and put principle, and helps to explain upper and lower bound wildcards:

// Example of the Get and Put Principle

    private class Drawable {}

    private class Shape extends Drawable {}

    private class Circle extends Shape {}

    public void testPut() {
        putShapeInto(new ArrayList<Object>());
        putShapeInto(new ArrayList<Drawable>());
        putShapeInto(new ArrayList<Shape>());
    }

    //flexible - can take a List of any superclass of Shape
    public void putShapeInto(List<? super Shape> l) {
        // We don't know what the type of list l is, but we know it is Shape or a superclass of Shape
        // therefore, it is always a valid destination for Shape instances
        l.add(new Shape());

        // l.add(new Object());
        // ...will not compile. The type of l may be any valid superclass of Shape
        // e.g. It may be <Drawable>, not all Objects are Drawable

        // Shape s = l.get(0);
        // ...will not compile. l may be List<Drawable>, and not all Drawables are necessarily Shapes
    }

    public void testGet() {
        getShapeFrom(new ArrayList<Shape>());
        getShapeFrom(new ArrayList<Circle>());
    }

    //flexible - can take a List of any subclass of Shape
    public void getShapeFrom(List<? extends Shape> l) {
        //  because the upper bound of list l is Shape, l is always a valid source for Shape instances
        Shape s = l.get(0);

        //  l.add(new Shape());
        //  ...will not compile, the type of l may be List<Circle>. Shapes are not all Circles
    }

    // Can add and get, but not very flexible - the method is limited to accepting Lists of type <Shape>
    public void testPutAndGet(List<Shape> l) {
        Shape s = l.get(0);
        Drawable d = l.get(0);
        l.add(new Shape());        
        l.add(new Circle());
    }
AddThis Social Bookmark Button

Careful how you synchronize toArray()

January 21st, 2009 Nick Posted in java No Comments »

This is a fuller version of the code snippit I submitted to the interesting thread on java synchronization issues on stack overflow

In general it can be tempting to assume too much thread safety when using synchronized collection classes.
It can be easy to think they somehow grant you more protection than they actually do, and forget to hold the lock between calls.

If have seen this mistake a few times:

 List<String> l = Collections.synchronizedList(new ArrayList<String>());
 String[] s = l.toArray(new String[l.size()]);

In the second line above, the toArray and size() methods are both thread safe in their own right, but the size() is evaluated separately from the toArray(), and the lock on the List is not held between these two calls. If you run this code with another thread concurrently removing items from the list, sooner or later you will end up with a new String[] returned which is larger than required to hold all the elements in the list, and has null values in the tail, which will quite possibly result in a NullPointerException eventually.

It is easy to think that because the two method calls to the List occur in a single line of code this is somehow an atomic operation, but it is not. The best way to fix this is to hold the lock explicitly :

 List<String> l = Collections.synchronizedList(new ArrayList<String>());

 synchronized(l) {
    String[] s = l.toArray(new String[l.size()]);
 }
AddThis Social Bookmark Button

Workaround for bug id 6753651 – find path to jar in cache under webstart

October 2nd, 2008 Nick Posted in java, swing 5 Comments »

Here is a workaround for the changes in 1.5.0_16 and 1.6.0_07, which prevent you from obtaining a valid URL using Class.getResource(myClassName) under webstart.

This is related to bug id 6753651 raised here

URLs acquired in this way used to include a filesystem path to the jar file in the local webstart cache containing the resource. Some apps relied on this filesystem path.

The behaviour of Class.getResource() under webstart was changed in 1.5.0_16 and 1.6.0_07 due to a security patch.

  • In 1.5.0_16 this breaks the URL (i.e. the URL returned by url.toString() is no longer valid, the file path is removed, which breaks some apps).
  • In 1.6.0_07 the url now uses the http protocol to refer to the jar file on the server – although in this case under the covers webstart will actually use the jar in the local cache if you call URL.openConnection()

One of our apps relied on the file path information in the URL, so we were forced to find a workaround.

This workaround does not fix the broken URL – but it does at least let you use the URL to find a valid path to the jar file on the local filesystem

update Nov 28th 08 – if you want to get a valid URL you might check out David’s suggestions in the comments below this post

To use the workaround first call Class.getResource(myResource) to get a (broken) URL , and then pass that URL into getJarFilePath(URL url). You should get back the path to the jar file in the local webstart cache which contains the resource.

It should work for all JDK/webstart versions up to and including 1.5.0_16 and 1.6.0_07 (subsequent versions have not been tested)

This workaround will only work for signed apps running with all permissions, since it uses reflection to access private methods and fields in classes within webstart.jar.

This workaround is pretty horrid, it certainly feels sinful, but it is the best solution I can find at present, having to fix a mission critical application within the next 24 hours. Since it relies on private implementation details within the webstart jar it may break with future jre versions if that implementation is changed. It is not part of the public API, so changes made in subsequent jdks may break the workaround at any time.

n.b. you may need to call System.setSecurityManager(null) before you call this routine to allow the private field access to work.

     /**
     * This method will return the path to the jar file containing the resource which this URL references
     *
     * It should work with URLs returned by class.getResource() under java 1.5.0_16
     * and 1.6.0_07, as well as maintaining backwards compatibility with previous jres
     *
     * The two jre above contain security patches which make the file path of the jar
     * inaccessible under webstart. This patch works around that by using reflection to access
     * private fields in the webstart.jar where required. This will only work for signed webstart
     * apps running with all security permissions
     *
     * @param jarUrl - url which has jar as the protocol
     * @return path to Jar file for this jarURL
     */

    public static String getJarFilePath(URL jarUrl) {
        JarFile jarFile = getJarFile(jarUrl);
        return findJarPath(jarFile);
    }

    public static JarFile getJarFile(URL jarUrl) {
        try {
            JarURLConnection jarUrlConnection = (JarURLConnection)jarUrl.openConnection();

            //try the getJarFile method first.
            //Under webstart in 1.5.0_16 this is overriden to return null
            JarFile jarFile = jarUrlConnection.getJarFile();

            if ( jarFile == null) {
                jarFile = getJarFileByReflection(jarUrlConnection);
            }
            return jarFile;
        } catch (Throwable t) {
            throw new RuntimeException("Failed to get JarFile from jarUrlConnection", t);
        }
    }

    private static JarFile getJarFileByReflection(JarURLConnection jarUrlConnection) throws Exception {
        //this class only exists in webstart.jar for 1.5.0_16 and later
        Class jnlpConnectionClass = Class.forName("com.sun.jnlp.JNLPCachedJarURLConnection");
        Field jarFileField;
        try {
            jarFileField = jnlpConnectionClass.getDeclaredField("jarFile");
        } catch ( Throwable t) {
            jarFileField = jnlpConnectionClass.getDeclaredField("_jarFile");
        }
        jarUrlConnection.connect(); //this causes the connection to set the jarFile field
        jarFileField.setAccessible(true);
        return (JarFile)jarFileField.get(jarUrlConnection);
    }

    private static String findJarPath(JarFile cachedJarFile) {
        try {
            String name = cachedJarFile.getName();

            //getName is overridden to return "" under 1.6.0_7 so use reflection
            if ( name == null || name.trim().equals("")) {
                Class c = ZipFile.class;
                Field field = c.getDeclaredField("name");
                field.setAccessible(true);
                name = (String)field.get(cachedJarFile);
            }
            return name;
        } catch (Throwable t) {
            throw new RuntimeException("Failed to get find name from jarFile", t);
        }
    }
AddThis Social Bookmark Button

New Open Source SwingCommand library released

September 29th, 2008 Nick Posted in java, swing No Comments »

I finally completed open sourcing SwingCommand – an open source library which provides support for the command pattern in Swing. In addition to synchronous commands, it provides support for asynchronous commands, which hides away the gory threading details in a similar way to the SwingWorker class – but in SwingCommand the asynchronous commands are integrated into the overall framework, and there are a few extra features, such as composite command support and command execution observers, which I hope make it more flexible.

Reusable Commands

One other key difference from SwingWorker is that in SwingCommand each command instance is reusable (a command can be executed more than once). Each time you call myCommand.execute() a ‘CommandExecution’ instance, which encapsulates the state for that execution. In the SwingWorker provided as part of jdk 1.6, each SwingWorker instance is designed to be executed only once. In SwingCommand there is nothing to stop you creating a new Command instance each time if you prefer, but you also have the flexibility to create a shared Command instance up front, pass references to it around your application and execute it many times if necessary.

Why a new Command library?

There is nothing fundamentally new about using the command pattern in Swing apps, but arguably there is a need for a reusable library to address this problem in a focused manner, and provide a richer set of features than SwingWorker, without attempting to solve every other ui programming issue along the way. SwingCommand has certainly been a useful library in my projects already. It does hide away a lot of the more complex threading issues, typically produces ‘clean code’, and make it easy to build a Swing application around chunks of reusable logic wrapped as Command classes. Integration with java.util.concurrent framework makes it really easy to handle threading issues which would otherwise be complex (e.g to prevent two instances of the same asynchronous command from running simulatenously would be a one line change, by using Executors.newSingleThreadExecutor()).

A milestone

This is the first of Object Definitions’ libraries which I have open sourced. It is fair to say it has been more work than I anticipated to get it to this stage – so it is probably time to crack open a bottle of something fizzy. Once I have recovered from the hangover I’ll post more about it here. In the meantime there is a lot more information on the website and you can download swingcommand library here

AddThis Social Bookmark Button

Fix for log4j bug 45704 – Failed to load logging.xml for JRE 1.5.0_16 and Webstart

September 26th, 2008 Nick Posted in java, swing 1 Comment »

This bug affects webstart applications which use log4j and xml configuration files (e.g. log.xml rather than log4j.properties) in JDK 1.5.0_16 (and later..?)

I think this problem has been occurring since a new security patch was released by Sun, which seems to have changed the behaviour of the URL class for webstart apps.

This security patch affects jdk 1.5 from 1.5.0_16 onwards, and also affects Java SE 6 Update 7 onwards
So this problem probably also exists for log4j under webstart 1.6 update 7 +

What seems to have happened is that the patch has stopped webstart apps from being able to obtain a valid URL object using MyClass.class.getResource().

If you obtain a URL instance in this way when running under webstart from 1.5.0_16, then calling toString on the URL instance gives you a malformed URL without the jar file path information. You only get back the path of the class within the Jar file – the part which usually appears after the exclamation mark – and not the path to the jar file itself. See this thread here for an example of what this looks like

I think the path to the jar file in the webstart cache has been removed from URL.toString() due to the security issues addressed by the patch. However if you call myUrl.openConnection() on the URL instance this still works OK, due to the way URL is implemented internally.

It is very bad that the only way to solve this security issue was to break the behaviour of URL class in this way.
It will surely create no end of problems for many webstart users.

Because of this issue, log4j is currently broken for webstart apps running under the latest jre, at version 1.2.15
There is an open bug id 45704 here.

There is now also a bug raised on Sun’s site

Luckily I think I have a solution (I will confirm this next Monday) and it is a one line change to log4j
The class to change is the DOMConfigurator.

Whereas the PropertyConfigurator does url.openConnection to get a stream (so this should work), the DOMConfigurator uses url.toString() – and gets back the bad webstart URL
This can be fixed at line 762 in DOMConfigurator.java simply by replacing parser.parse(url.toString()) with parser.parse(url.openConnection().getInputStream())

I have created a patch of log4j to make this change for my clients, and this seems to fix the issue with their webstart apps. I will submit the change to the log4j team for consideration tonight

Here is a link to the patched file
DOMConfigurator.java

AddThis Social Bookmark Button

Don’t be lazy

June 18th, 2008 Nick Posted in java, rants and opinions No Comments »

I’ve seen far too many bugs lately involving lazy initialization.

In theory lazy initialization might seem a good idea. Why do extra work up front which might not be needed?

The problem is that it is simply too easy to introduce bugs when state is not completely loaded after construction. For example, a project I recently worked on made extensive use of init() methods to lazily load state on demand. The constructor would not do the initialization. Instead, each getter method would check whether initialization was complete, and if not kick off an init() process before returning data.

The reasons for this were fairly convincing. The loading of the state required a call to a database, which was slow. But the problem was that this lazy initialization pattern soon spread throughout the codebase like a rash. Soon it was rare to find a class which was guaranteed to be ready for use after construction.

Still other classes used lazy loading as a speculative performance optimization. Table models received events which invalidated their internal state. Instead of recalculating immediately, they propagated events to their listeners, delaying their own recalculation. The models would recalculate only when a client class called a method to ask for data, and forced a the model to check its state and recalculate. Again, it sounded good – why take on the overhead of immediate recalculation if your class has no active listeners?

The original coders left. The code base gradually expanded to more than a million lines of code. New programmers arrived. Predictable problems emerged.

In many cases, the new programmers would simply fail to realise that an object was not ready to use until its init method had been called. Init methods had become a part of some key abstractions – although in the vast majority of cases subclasses did not actually require any special initialization. So most objects ended up with an init method, just to cater for the few places where it was really necessary. Confusion reigned as to when and where initialization should take place.

Interfaces changed and classes needed to be modified. It was all too easy to forget to check the initialization status when adding methods to existing classes. Strange errors occurred in the table models. The data had changed some time before, but since the recalculations were delayed it was hard to work out from the logs what had actually triggered the problem. Sometimes the original coders had made mistakes and forgotten to check the initialization state for some methods. In other subclasses had overridden methods and forgotten to include the check. Problems could emerge quite unexpectedly, such as when the ordering of client class method calls changed. This often caused strange data corruption or null pointer exceptions at runtime, which brought down components.

The basic OO tenet that an object should be ready for use after construction really does make a lot of sense – try very hard to avoid lazy initialization wherever possible. It may seem clever, but it probably isn’t. If it seems that lazy initialization is the only way, reconsider every alternative design. Simplicity is key, and lazy initialization or lazy recalculation is rarely, if ever, simple. You’ll likely save yourself some headaches in the short term, and in the long term you’ll save even more for those who inherit the code once you have moved on.

AddThis Social Bookmark Button

Calculating a color gradient

May 12th, 2008 Nick Posted in java, swing No Comments »

For a recent project I needed some code to calculate a colour gradient for different points on a scatter chart. The class below performs a simple interpolation between two colours, if you feed it a value between 0 and 1.

 public class GradientCalculator {
        private Color c1;
        private Color c2;

        public GradientCalculator(Color c1, Color c2) {
            this.c1 = c1;
            this.c2 = c2;
        }

        /**
         * @param ratio - value between 0 and 1
         */

        public Color getColor(double ratio) {
            int red = (int) (c1.getRed() * (1 - ratio) + c2.getRed() * ratio);
            int green = (int) (c1.getGreen() * (1 - ratio) + c2.getGreen() * ratio);
            int blue = (int) (c1.getBlue() * (1 - ratio) + c2.getBlue() * ratio);
            int alpha  =(int) (c1.getAlpha() * (1 - ratio) + c2.getAlpha() * ratio);
            return new Color(red, green, blue, alpha);
        }
    }
AddThis Social Bookmark Button

JOptionPain – JOptionPane hidden behind always on top window crashes Swing UI

April 5th, 2008 Nick Posted in java 1 Comment »

nb. this is now bug id 6690019

There is a bug in the java bug database (6519416) related to a similar issue, but it is closed and not fixed – perhaps the reviewer didn’t realise how serious this can be. I think this needs to be looked at again, since it has caused several terminal crashes in production systems I have been working on.

The problem is to do with the use of the ‘always on top’ feature for java.awt.Window. If JFrames in the application are set to always on top, a JOptionPane can be obscured by an always on top frame, and hence be inaccessible to the user. Since the JOptionPane is modal, you can’t interact with or move the always on top frame – so there is no way to reveal the JOptionPane in order to dismiss it. The whole UI just hangs. You can’t even alt-tab to reveal the option pane. The only way out is to kill the process.

There is no problem with the always on top frame is the parent of the JOptionPane – the problem only occurs if the parent is a normal frame, or the JOptionPane has a null parent set.
The following code replicates the problem

public class TestJOptionPaneAlwaysOnTopBug
{
    public static void main(String[] args) {
        SwingUtilities.invokeLater(
                new Runnable() {
                    public void run()
                    {
                        JFrame alwaysOnTopFrame = new JFrame("Test JOptionPane");
                        alwaysOnTopFrame.setSize(600, 400);
                        centreFrame(alwaysOnTopFrame);
                        alwaysOnTopFrame.setAlwaysOnTop(true);
                        alwaysOnTopFrame.setVisible(true);

                        JFrame normalFrame = new JFrame();
                        normalFrame.setSize(800, 600);
                        centreFrame(normalFrame);
                        normalFrame.setVisible(true);

                        JOptionPane.showMessageDialog(normalFrame, "Can't you see me?");
                    }
                });
    }

    private static void centreFrame(JFrame myFrame)
    {
        Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        int x = (d.width - myFrame.getWidth()) / 2;
        int y = (d.height - myFrame.getHeight()) / 2;
        myFrame.setLocation(new Point(x, y));
    }
}

There is a workaround, described in the bug report above, which involves creating the dialog for the JOptionPane explicitly and setting it to be always on top before it is displayed. This seems to fix things, at least on the Windows platform. However, if you use the standard JOptionPane static methods to show a dialog, always on top is not set. I think it possibly should be – it seems unlikely that one would ever want to show an option pane which is not on the top. Perhaps there is a corner case here which is not obvious?

AddThis Social Bookmark Button

Doubled up

April 4th, 2008 Nick Posted in java No Comments »

Can you guess the output of the code below? And no, it isn’t a compilation failure, even I can write code which compiles (at least after enough coffee)

    public static void main(String[] args) {
        double d1 = Double.NaN;
        double d2 = Double.NaN;
        String verdict = "Not guilty";

        if ( d1 == d2 ) {
            if ( ! new Double(d1).equals(d2) ) {
                    verdict =  0 < Double.MAX_VALUE ?
                         "less than MAX_VALUE" :
                         "greater than MAX_VALUE";
            }
        } else {
            verdict = 0 > Double.MIN_VALUE ?
                    "greater than MIN_VALUE" :
                    "less than MIN_VALUE";
        }
        System.out.println(verdict);
    }



Well in fact it prints out ‘less then MIN_VALUE’, so if you got that result – well done!
There are two slightly counter intuituve aspects to this example.

Firstly Double.NaN != Double.NaN. although new Double(Double.NaN).equals(Double.NaN);

This is reasonably widely known, but also the cause of many bugs, since it is all too easy to forget the == comparator does not work in this case. To be safe you have to remember to use the isNaN() method on Double, if testing NaN conditions.

Secondly, since Double.MAX_VALUE is the maximum value a Double can take (apart from inifinity), it might be natural to think that Double.MIN_VALUE is the minimum value a Double can take. In fact, it is not – it is actually the minimum positive value a Double can take! Easy to overlook, and once again, a potential cause of many bugs.

We hit a bug with this recently when writing a max value calculator which took MIN_VALUE as its starting point, and iterated through a set of values. During the iteration, if a subsequent value was higher than the currently stored max value, its value was taken as the new max. This all worked brilliantly – until we ran the calculator against a number set consisting of just negative values, in which case the result was returned as MIN_VALUE!

Surely a better name for this constant would be MIN_POSITIVE_VALUE.




AddThis Social Bookmark Button

Structure 101 – my new favourite code quality tool

March 19th, 2008 Nick Posted in java, rants and opinions No Comments »

Jetbrains recently sent out an email about a new companion product to Intellij idea – Structure 101. Structure 101 is a tool developed by headway software, which can be used to analyse the architecture and complexity of java applications. This is a very welcome addition to the marketplace for java development tools. (I say new – in fact it seems Structure 101 has been around for a couple of years now, so clearly I’ve not been paying attention!).

Structural problems in code

I am known to be opinionated about this and friends and ex-colleagues will already be bored with me going on about it! The majority of software is not well architected and well structured internally (perhaps in part because the tools to visualise structure at a package level have not been widely available). Some apps are structurally akin to a bowl of spaghetti, with all the negative implications of tight coupling between packages and cyclic dependencies. This is bad news for reuse – if software is full of dependency cycles, classes and packages can’t easily be reused in another context without sucking in everything else too. An acyclic structure is enormously important at the package and class level – not just at the level of the release unit. After all, a release unit today may need to be split into two in the future – to enable better reuse of some of the logic it contains.

Improving structure to remove dependency cycles between packages and classes can be hard – but it is not insurmountably hard, especially if you have the right tools for the job. And it pays major dividends, resulting in far easier reuse and a more intelligible project in the long term. Changes made to projects developed with these principles in mind tend to be more deterministic in their impact, since the ripple-through effect is minimised. And the great thing is that the methods required to achieve this decoupling are well known and accepted as good programming practice in their own right – chief among these, that concrete classes should depend upon abstractions. Introducing an interface is the most common way to decouple a cyclic dependency between two classes.

Avoiding bad structure

This is where tools like Structure 101 come in. It allows you to zoom in to view dependency problems within your application, and makes it far easier to visualize the layering and package structure within your project. Not only that, but it gives a summary of complexity, highlighting classes and areas which need simplification.

This is not a radically new goal. Other tools have attempted the same thing in the past, for example ‘Pasta’ (which became OptimalAdvisor), and ‘SmallWorlds’ (which became SA4J). Both of those were promising products which were swallowed up by big companies and disappeared for a time, stagnated or became prohibitively expensive. However, there is some genuine innovation in Structure 101, over and above the others. I have found it to be effective in zooming to the areas of applications which are the most problematic. It lacks the refactoring support which OptimalAdvisor provides – but then most developers would use their IDE for refactoring in any case, so it is not clear this is a significant disadvantage.

One feature I particularly like is the ability to upload structure diagrams to a shared repository. IDE plugins are then provided which allow developers to validate their changes against a shared model – without having to purchase a license. This is a great idea, which will facilitate much wider use of the tool, and allow teams to collaborate much more easily to maintain a desired architecture. This may help to overcome the natural entropy shared by all multi-developer projects. However things are still not perfect – licenses are node locked, which means a developer may need two licenses to allow him/her to work from home and in the office.

All things considered, Structure 101 is a tool it is certainly well worth checking out – it is my new number one tool for validating the quality of code.

AddThis Social Bookmark Button

Getting proxy server details in webstart app

March 11th, 2008 Nick Posted in java 2 Comments »

I had a devil of a job finding a way to do this.

A couple of apps I have recently worked on needed to make an apache httpclient or xmlrpc connection back to the server once the webstart app started. Although webstart clearly has the proxy server info (which it must use when downloading the application jars from the server), it is not immediately apparent how to access this from the app itself. The app then fails when trying to call back to the server.

I thought the proxyHost and proxyPort system properties might contain the required information – but this is not the case. In fact this information is not available from system properties at all.

Well the trick is to get the http proxy details using the java.net.ProxySelector class.

String theURIToConnectTo="http://www.yourServerURIHere.com"

String proxyHost, proxyPort;
java.util.List<Proxy> proxies = java.net.ProxySelector.getDefault().select(new java.net.URI(theURIToConnectTo));
for ( Proxy proxy : proxies ) {

    if ( proxy.type() == Proxy.Type.HTTP ) {
        SocketAddress proxyAddress = proxy.address();
        if ( proxyAddress instanceof InetSocketAddress) {
             proxyHost = ((InetSocketAddress)proxyAddress).getHostName();
             proxyPort = String.valueOf(((InetSocketAddress)proxyAddress).getPort());
        }
        break;
    }
 }

This still won’t handle the case where the proxy server requires username and password for authentication.
I don’t have a suitably authenticating proxy to test with right now – anybody know how to handle that?




AddThis Social Bookmark Button

jmap and jstack – getting a heap dump and stack trace from a running JVM

February 21st, 2008 Nick Posted in java, unix No Comments »

The project I’m working on currently has many server side java components running on linux. One of these in particular has been experiencing severe memory leaks when running in our production environment (but not UAT, surprisingly!)

It turns out there is a tool provided with sun’s jdk 1.5 + which will allow you to get a snapshot of the heap for a running process, without you having to have started the jvm with any particular options set. This tool is called jmap

running:
jmap -histo pid
where pid is the process id on a linux box

will give you a snapshot of the heap which looks like the below:

java -histo pid

Object Histogram:

Size    Count   Class description
-------------------------------------------------------
77928   583 char[]
55696   131 byte[]
8816    29  * ObjArrayKlassKlass
8520    355 java.lang.String
8272    215 java.lang.Object[]
4080    85  java.nio.HeapByteBuffer
3984    83  java.nio.HeapCharBuffer
3608    41  java.lang.Class
2456    19  int[]
1368    57  java.util.Hashtable$Entry
1288    16  * ConstMethodKlass
1208    31  java.lang.String[]
1120    14  java.util.HashMap$Entry[]
1040    10  java.util.Hashtable$Entry[]
1008    14  java.lang.reflect.Field
960 3   * InstanceKlassKlass
etc.

The most useful thing here is probably the object class count. There is a chance this could help you identify an area of your app which is producing an unexpected number of instances of a given class. Other jmap options give you a dump file in different formats – so this is worth investigating too.

There is an equivalent tool jstack (jstack pid), which dumps stack information for each of the running threads. Probably useful for diagnosing deadlocks etc.

The nice thing about both of these tools is that you don’t need to have started the jvm with any specific options. These tools just connect and work – so you don’t need to have planned your memory leak in advance :)

They only work on unix right now, unfortunately.
There is a good article on new tools with jdk1.6 here

nb. if jstack fails you may be able to get a thread dump on unix using kill -3 {pid}
Here is another useful link for suggestions on diagnosing performance problems

And here is a good link to help diagnose java app problems in general

AddThis Social Bookmark Button

Drag and drop into empty table not working?

January 25th, 2008 Nick Posted in java, swing No Comments »

This is a known gotcha from the early days of Swing, related to bug id 4310721

The symptom is that while drag and drop works fine into tables which are populated, trying to drop into a table with no rows, or drop data beneath the populated rows, does not work. The cause of this is that the table does not automatically expand to fill the area available to it in the JScrollpane viewport.

As of jdk1.6 this is fixed on JTable itself. You just need to call myJTable.setFillsViewportHeight(true)

If you do not have the great glory of 1.6 available to you, you will have to extend JTable and override the getScrollableTracksViewportHeight() method as below:

public class TrackViewportJTable extends JTable {

    public TrackViewportJTable(TableModel tableModel, TableColumnModel tableColumnModel) {
        super(tableModel, tableColumnModel);
    }

    public TrackViewportJTable(TableModel tableModel) {
        super(tableModel);
    }

    public boolean getScrollableTracksViewportHeight() {
        // fetch the table's parent
        Container viewport = getParent();

        // if the parent is not a viewport, calling this isn't useful
        if (! (viewport instanceof JViewport)) {
            return false;
        }

        // return true if the table's preferred height is smaller
        // than the viewport height, else false
        return getPreferredSize().height < viewport.getHeight();
    }
}

The above is based on the example in Shannon Hickey’s blog.
For a more complete description of the problem, and its solution, see his blog entry here

AddThis Social Bookmark Button

Tricked by short circuit operators

January 17th, 2008 Nick Posted in java No Comments »

I am currently feeling suitably humbled, having fallen into a nasty coding trap. At least in this case it didn’t cause a major industrial disaster (please shoot me if I ever start work in the aviation industry!)

So just to make the humiliation public, the following was the cause of my disgrace – I had a test, similar to the below:

return myString != null && ! myString.equals("wibble") && ! myString.equals("squork");

So that’s all OK, isn’t it, even if it isn’t particularly nice code? – if the string is null the first test will evaluate to false, and then the short circuit operator will prevent the other two tests from being evaluated. Hence a null pointer cannot occur.

Well yes. In fact, that is correct – the above works OK. My problem was that I duplicated and changed the logic, without thinking through the consequences, and introduced an or operator into the mix:

return myString != null && myString.equals("wibble") || myString.equals("squork");

Looks similar, at a glance, and again the short circuit operator should prevent any null pointer. Or should it?

In fact in this case, no. It all goes pear shaped, and horribly so. The reason is to do with operator precedence. What actually happens is that since && has a higher precedence than ||, the way the compiler actually interprets the above is this:

return ( myString != null && myString.equals("wibble") ) || myString.equals("squork");

which, if myString is null, becomes:

return false || myString.equals("squork");

So the second of the myString.equals tests is still evaluated, and a null pointer results. Luckily these lines of code weren’t wired into flight control.

I think I had been lulled into a false sense of security by the short circuit operator construct. Well, that’s one more mistake I’ll never make again. But clearly, I needed to refresh my knowledge of the rules of operator precedence !





AddThis Social Bookmark Button