Automatically moving spam to a junk mailbox under a Plesk 9 server

September 3rd, 2011 Nick Posted in unix | No Comments »

This is just a quick note on how I was able to get this working under plesk 9, which seems frustratingly limited in its mail filtering ability. Essentially there’s an option to automatically delete all mails identified as junk – but nothing to enable you to simply move them into a junk directory (which is useful in cases where some emails may be misidentified as spam)

Well I found a similar thread which probably worked for plesk versions < 9, but didn't quite work for me:
http://rackerhacker.com/2007/11/27/sort-e-mail-in-plesk-with-procmail/

I adapted this slightly, also using procmail as the delivery agent.
My server had a .qmail in /var/qmail/mailnames/domain/username/ with the following contents:

| true
| /usr/bin/deliverquota ./Maildir

It seems that it was using the executable ‘deliverquota’ to do the actual mail delivery (and presumably check that quotas are not exceeded for the user)
I’m not worried at all about mail quotas on my server, so I decided to replace the ‘deliverquota’ with a call to procmail

So these are the steps I took

1.
I changed the .qmail above to

| true
|preline /usr/bin/procmail -m -o .procmailrc

2.
I then added a file .procmailrc in the same directory, as described in the thread above – you have to adapt this to have your domain name and mail user name on the first line where MAILDIR is defined:

MAILDIR=/var/qmail/mailnames/YOURDOMAIN_HERE/YOURMAILUSER_HERE/Maildir
DEFAULT=${MAILDIR}/
SPAMDIR=${MAILDIR}/.Junk/
:0
* ^X-Spam-Status: Yes.*
${SPAMDIR}

3.
Lastly, you have to make sure that the ownership and permissioning for both the .qmail and .procmailrc above are correct, otherwise things just won’t work. For me, that meant changing the ownership and group to popuser and permissions to 600 with:
chown popuser:popuser .qmail .procmailrc
chmod 600 .qmail .procmailrc

That’s it! Now the junk mail (provided spamassasin is set up and working, adding it’s headers) should go to the .Junk directory for the user. I have sacrificed the disk quota functionality for this, but it seems a worthwhile exchange for me.

To test this you can send a ‘GTUBE’ test email (an email with content which tells spamassasin to treat it as spam) from another email account, just add the following as the message body

XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X

For me the mail logs on plesk server seem to be at /usr/local/psa/var/log
If the above doesn’t work, have a look in the log, it may give you some clues as to why

Hope that helps

AddThis Social Bookmark Button

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

Create Field Intention in Intellij 9 – disabled by default?

September 30th, 2010 Nick Posted in Uncategorized | No Comments »

If, like me, you are missing the ‘Create Field’ intention in Intellij 9, here is the solution. I was about to send a bug report for the missing feature, but then I realised that the create field intention had somehow become disabled in the intellij config.

It’s certainly not something I changed. Perhaps that intention setting doesn’t get handled too well when you upgrade from 8 to 9 – or perhaps it is actually disabled by default in 9.

Whatever the reason, it’s a really useful feature, especially when you are creating a new class. Instead of manually typing all the fields (and then perhaps using the create constructor refactor), this way you just write the constructor with the fields, and then place the caret in each field in turn, press [Alt] and [Enter], and let the ide do the legwork and add the fields for you.

This is what it looks like in practice:

To switch it back on, change the setting here:

AddThis Social Bookmark Button

Setting up an IMAP account with SSL does not work with Android 2.1

July 1st, 2010 Nick Posted in hardware | No Comments »

I had this problem after upgrading my Hero to Android 2.1

I previously had an imap mailbox working fine, with an SSL connection, but setting it up again under 2.1 seemed to get me nowhere.
After going to manual setup and entering the incoming server details, clicking continue would simply take me back to the same page – not to the next ‘configure outgoing mailserver’ screen.

Since HTC pushed out the over the air upgrade for the Hero in the last few days, I guess a lot of people may now be in the same boat

It turns out this is a bug – really at this point, android should be showing the ‘accept certificate’ dialog, in cases where you don’t have a signed certificate on your mailserver

The good news is – there is a workaround.

Simply put in an incorrect value for the imap server first time around
Android will tell you that it can’t connect to the server – but will still let you proceed and add an outgoing mail server etc, and finish configuring the account.

Then, when the account is configured, simply go to the account settings and enter a correct server.
This time, Android should correctly show the ‘accept certificate’ dialog, and you should be able to proceed as normal.

Thank goodness for this workaround! I was getting seriously worried my new 2.1 Hero wouldn’t work with my email server.

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

SwingCommand part 7 – Composite Commands

May 2nd, 2009 Nick Posted in Uncategorized | No Comments »

There are occasions when it is useful to group commands together and execute several in combination. SwingCommand provides a CompositeCommandTask which allows you to group commands together in a single task which executes them sequentially.

TaskListeners on the CompositeCommandTask receive progress events as each child command is processed. The example below creates a String progress value to describe the current child command being processed.

Cancelling the composite task will cause the currently processing child command to be cancelled (if it supports cancellation), and will cause the composite task to abort processing for any remaining child command tasks. The reverse is also true – if the currently processing child command’s task is cancelled, this will cause the composite task to be cancelled and abort early.

If any of the child commands fail, the composite task will also fail with a CompositeCommandTaskException, which has the child task’s exception as the cause.

Here is a simple example of a composite task:

  SwingCommand loadThreeUsersMessages = new SwingCommand() {
 
      protected Task createTask() {
 
          CompositeCommandTask compositeTask = new CompositeCommandTask() {
 
              //let's send progress as a String update to any TaskListeners
              protected String getProgress(int currentCommandId, int totalCommands, Task currentChildCommand) {
                  return "Now running number " + currentCommandId + " out of " + totalCommands + " commands";
              }
          };
 
          compositeTask.addCommand(new LoadMessagesCommand("User 1"));
          compositeTask.addCommand(new LoadMessagesCommand("User 2"));
          compositeTask.addCommand(new LoadMessagesCommand("User 3"));
          return compositeTask;
      }
  };
 
  loadThreeUsersMessages.execute();

The composite task implements the getProgress() method to generate the String used in the progress event.

AddThis Social Bookmark Button

SwingCommand part 6 – Cancellation

May 2nd, 2009 Nick Posted in Uncategorized | No Comments »

SwingCommand has support for cancellable commands. To support cancellation for a Task it is easiest if the Task extends InterruptibleTask. InterruptibleTask helps to implement the logic necessary to interrupt the background thread if cancel() is called.

When you invoke command.execute() on a SwingCommand instance, a reference to the Task which is created to handle the execution is returned from the execute() method. Getting the reference to the Task which is running can be useful – for Tasks which support the cancel operation, you may want to cancel the task by calling task.cancel()

To implement cancellation correctly, your Task must be able to respond to the interrupt request. There are two main cases to consider:

  • Interrupting a task which is blocked on IO, or on some other blocking call
  • Interrupting a task programatically by checking the isInterrupted() status periodically

Lets look at the first of these, interrupting a task which is blocking:

//interruping a background task with cancel

  SwingCommand c = new SwingCommand() {
      protected Task createTask() {

            return new InterruptibleTask() {

                public void doInBackground() throws InterruptedException {
                    Thread.sleep(10000);
                }

                public void doInEventThreadIfNotCancelled() {
                    textArea.setText("Task was not cancelled");
                }
        };
      }
  };

  //let's pop up a option pane if the task is cancelled
  c.addTaskListener(new TaskListenerAdapter() {
      public void cancelled(Task task) {
              JOptionPane.showMessageDialog(frame, "Task was Cancelled");
      }
  });


  Task t = c.execute();

  //and then a while later, from any thread...
  t.cancel();

In the example above the Task extends InterruptibleTask. During the doInBackground() handler, the background thread is blocked for a time in the call to Thread.sleep(). When task.cancel() is called by any thread, the InterruptibleTask logic will trigger thread.interrupt() on the background thread. This will result in an InterruptedException being generated by the sleep() method. Because cancel() was called, InterruptibleTask will catch the InterruptedException and the Task will finish with cancelled set to true (task.isCancelled() == true).

Note, if cancel() had not been called, the exception would have been allowed to propagate through causing TaskListeners to receive an error message, and the command would finish in the ERROR state.


What if cancel is called before or after the background processing?

If the call to task.cancel() occurs before background processing starts, the doInBackground() handler will not be called, and cancellation will always succeed. If the call to cancel() occurs after doInBackground() has returned, the call to cancel will not succeed – in this case and the task will end with isCancelled() == false.

The doInEventThreadIfNotCancelled() method is only called if the task is not cancelled. (You could alternatively override doEvenIfCancelled() if you wanted to do some post-processing in the event thread regardless of cancellation).


Interrupting a background task using custom logic

Sometimes a blocked thread will not respond automatically to thread.interrupt(). This is the case during some JDBC queries, for example. In some cases you have to implement extra logic to interrupt the task, and you can do this by overriding the doInterrupt() method. This example demonstrates how you might handle interrupting a query on a JDBC statement:

  SwingCommand c = new SwingCommand() {
      protected Task createTask() {

            return new InterruptibleTask() {

                private volatile Statement s;
                private StringBuffer text = new StringBuffer();

                public void doInBackground() throws SQLException {
                    s = connection.createStatement();
                    ResultSet r = s.executeQuery("select text from Message");
                    while(r.next()) {
                        text.append(r.getString(1)).append("\n");
                    }
                }

                protected void doInterrupt() throws SQLException {
                    Statement statement = this.s;
                    if ( s != null) {
                        s.cancel();
                    }
                }

                public void doInEventThreadIfNotCancelled() {
                    textArea.setText(text.toString());
                }
        };
      }
  };

  Task t = c.execute();

  //do something else for a while, and then call:
  t.cancel();

In the example above, the basic processing is the same, but this time we have also overridden the doInterrupt() method, to close the JDBC statement if the background query is interrupted. This should cause the statement.executeQuery() method to throw an SQLException. Because cancel() has been called, this exception will be treated as the result of a cancellation, and the task will end with isCancelled() == true.

Interrupting a task by checking isInterrupted()

There’s just one more case to demonstrate. How to handle a non-blocking cancel. This is actually quite simple – you just need to periodically check the isInterrupted() method, and return early if necessary:

SwingCommand c = new SwingCommand() {
      protected Task createTask() {
         
        return new InterruptibleTask() {

            public void doInBackground() throws InterruptedException {
                for ( int loop=0; loop < 1000000; loop ++) {
                    if ( isInterrupted() ) {
                        break;
                    }
                }
            }

            public void doInEventThreadIfNotCancelled() {
                textArea.setText("Task was not cancelled");
            }
        };
      }
  };

Here the doInBackground() handler enters a processing loop. On each iteration, it checks to see if isInterrupted() is true – this will be the case if cancel() has been called on the task. If so, it breaks the loop to end the processing early.

Note that a task is considered cancelled even if the doInBackground() does not return early, provided that when the doInBackground() method returns the background thread still has its interrupted flag set.

Whew – that’s a fair amout to absorb. But the thing to take away is that extending InterruptedTask makes handling cancel easy. There is very little boilerplate code in the examples above, and you shouldn’t need to work too hard to get this right.

AddThis Social Bookmark Button

SwingCommand part 5 – Task States and Error Handling

May 2nd, 2009 Nick Posted in Uncategorized | No Comments »

Task States

It is possible to find the current state of a Task instance directly by calling task.getExecutionState();
There are six ExecutionStates: NOT_RUN, PENDING, STARTED, SUCCESS, CANCELLED and ERROR.

A task starts in state NOT_RUN. During the call to command.execute(), the state will change to PENDING. Once task processing begins (which may be some time later if the task is queued for processing or is blocked waiting for a thread from a thread pool) the state moves to STARTED. The final state will be either SUCCESS , ERROR or CANCELLED. In the case that a Task finishes in ERROR, you can obtain the Exception that caused the error by calling task.getExecutionException()

If a SwingCommand task handler method ( doInEventThread() or doInBackground() ) throws an Exception the task is considered to have failed. Any TaskListeners will receive an error() callback, and the task will end in the ExecutionState.ERROR state.

Ending a SwingCommand Early

If an exception is thrown during doInBackground(), the doInEventThread() handler will not be called. Instead, processing is aborted before doInEventThread() is called. This makes sense, because in most cases we will not want to update the ui if, for example, a task loading data failed.

However, sometimes you will need to perform error handling in the Swing Event Thread, or perform some processing whether or not an error occurs or the task is cancelled. For example you may need to stop a progress animation. These cases are best handled by a TaskListener, in the error() method, or the finished() method respectively.

The finished() callback always occurs, no matter if the task succeeds, fails or is cancelled. The TaskListener methods also allow you to perform handling only on success (the success() callback).

  SwingCommand c = new SwingCommand() {
      protected Task createTask() {
          return new BackgroundTask() {

              public void doInBackground() throws Exception {
                  //this method throws an exception instead of returning
                  throw new Exception("woe");
              }

              public void doInEventThread() throws Exception {
                  //So we'll never get here!
              }
          };
      }
  };

     
  c.addTaskListener(new TaskListenerAdapter() {
     
      public void error(Task task, Throwable error) {
          JOptionPane.showMessageDialog(frame, "Failed to Load Messages");
      }
   
      public void finished(Task task) {
          //the task will finish in the ERROR state since doInBackground() threw an Exception
          assert(Task.ExecutionState.ERROR == task.getExecutionState());
       
          //we can get the error back by calling task.getExecutionException()
          Throwable cause = task.getExecutionException();
      }
  });

  c.execute();
AddThis Social Bookmark Button

SwingCommand part 3 – Showing Progress

May 2nd, 2009 Nick Posted in Uncategorized | No Comments »

The progress animation triggered by the TaskListener in the previous example would at least inform the user that a SwingCommand is executing. However, sometimes it may be useful for a long running command to show publish interim results, or simply post more descriptive progress updates.

To help with this, as well as allowing you to set the generic type for parameters to your SwingCommand, the SwingCommand class also allows you to specify a generic type for a progress update. The following example demonstrates perhaps a simple case, in which an Integer progress event is fired:

//Here I have updated the ClearMessagesCommand to publish progress messages as a Integer

  class ClearMessagesCommand extends SwingCommand<String,Integer> {

      public ClearMessagesCommand() {
      }

      public Task<String,Integer> createTask() {

          return new BackgroundTask<String,Integer>() {

              public void doInBackground() throws Exception {
                  fireProgress(1);

                  String userName = getParameters();
                  Statement s = connection.createStatement();
                  s.execute("delete from Message where User = " + userName);

                  fireProgress(2);
              }

              public void doInEventThread() {
                  fireProgress(3);    
              }
          };
      }
  }

  SwingCommand<String,Integer> c = new ClearMessagesCommand();
  c.execute("Nick");

  c.addTaskListener(new TaskListenerAdapter<Integer>() {
      public void progress(Task task, Integer progressDescription) {
          progressLabel.setText("stage " + String.valueOf(progressDescription));
      }
  });

You could do more sophisticated things by firing progress, and progress events make it easy to update the UI safely – remember that these messages are received on the Swing Event thread even if fired from doInBackground().

For example, you could use this mechanism to gradually populate messages into an ‘inbox’ while reading mail messages from a remote server. Or you could send an Integer progress update representing a percentage value, to update a progress bar with the current percentage of work completed by a background thread.

AddThis Social Bookmark Button

SwingCommand part 2 – TaskListeners

May 2nd, 2009 Nick Posted in Uncategorized | No Comments »

A common requirement in User Interfaces is to show an animation while a background task runs. How might this be accomplished using SwingCommand?

The following example shows how you can add a TaskListener to a command. The TaskListener will receive events as the command executes, and start and stop an animation.

TaskListeners always receive their events on the Swing Event thread, even if the Task is a BackgroundTask.

//TaskListeners always receive their events on the Swing event thread

  LoadMessagesCommand command = new LoadMessagesCommand("My User");

  TaskListener animationListener = new TaskListenerAdapter() {
      public void pending(Task task) {
          startProgressAnimation();
      }

      public void finished(Task task) {
          stopProgressAnimation();
      }
  };

  command.addTaskListener(animationListener);
  command.execute();
  }

Every time the command is executed, the SwingCommand creates a new Task instance, and the TaskListener will receive events while the Task runs.

It’s also possible to add a TaskListener to receive events for a single SwingCommand invocation, by passing it as a parameter to the execute() method:

//Let's add a listener to perform some error handling..
//this listener will not receive events on any subsequent executions:

  LoadMessagesCommand command = new LoadMessagesCommand("My User");

  command.execute(new TaskListenerAdapter() {
      public void error(Task task, Throwable error) {
          System.err.println("Oops, perhaps our database is offline");
      }
  });

The ability to add TaskListeners to SwingCommands is a key feature of SwingCommand, and it can be very convenient. For example, you could create several different commands and add a shared listener which tracks the background tasks and updates progress components on your UI. This listener will receive events on the Swing Event thread whenever one of the commands is executed, no matter which thread or which class actually executes it.

Separation of concerns

TaskListeners are a very useful mechanism. They allow you to separate the logic for handling progress animations, and error handling logic, from the main Task processing logic. You could, for example, provide a TaskListener which performs consistent error handling for all of the commands in your application. This is a good separation of concerns. Mixing that logic in with the main command processing logic tends to clutter the code up and make classes less easy to reuse – and there are certainly cases where you might want different error handling depending on the situation in which the SwingCommand is executed (e.g. if it’s executed in response to a button click in a Dialog, you may want to show an error message in the Dialog, rather than the main UI frame). To achive this, you can add some listeners to the SwingCommand, which will get notified whenever it is executed, and others context specific listeners can be passed as parameters to SwingCommand.execute().

The TaskListener interface

There are actually six listener methods in the TaskListener interface. Some of these are always invoked, others are only invoked if a Task enters a specific state (ERROR or SUCCESS) for example. To avoid having to implement all the methods, you can extend TaskListenerAdapter.

The full definition of the TaskListener interface is below:

/**
 * Implement this interface to listen to the progress of a task
 * Callbacks on this interface are guaranteed to be received on the AWT event thread,
 * even if fired by an BackgroundTask
 *
 * These callbacks provide an easy and safe way to update the UI to show the progress of a task.
 *
 * <P> - the type of Progress object that this TaskListener will receive
 */

public interface TaskListener<P> {

    /**
     * The callback to pending is triggered when command.execute() is called
     * If the Executor running the task queues the task or blocks waiting for
     * a thread, it may be some time before started() is invoked.
     */

    void pending(Task task);

    /**
     * Called when the task starts processing. For BackgroundTask this callback
     * takes place just before doInBackground is called. For SimpleTask just before doInEventThread
     */

    void started(Task task);

    /**
     * This callback may take place at any time during task execution, to indicate progress
     */

    void progress(Task task, P progress);

    /**
     * Called when the task reaches the SUCCESS end state
     * This callback takes place once a command has successfully completed (was not cancelled,
     * and did not throw an Exception resulting in a callback to error())
     */

    void success(Task task);

    /**
     * Called when the task reaches the ERROR end state
     * This callback takes place if an exception is raised during task execution, which prevents
     * successful completion
     */

    void error(Task task, Throwable error);

    /**
     * Called when the task reaches the CANCELLED end state
     * This callback takes place if the task is cancelled.
     * @param task
     */

    void cancelled(Task task);

    /**
     * This callback always takes place once the task has finished, whether or not the
     * task finishes in ERROR, SUCCESS or CANCELLED states
     */

    void finished(Task task);
}
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

Maven License Plugin – open source just got a little bit easier

January 23rd, 2009 Nick Posted in musings, random, rants and opinions | 1 Comment »

Isn’t it nice when once in a blue moon somebody comes up with an innovation which makes your life just that little bit simpler – one of those little things which you soon take for granted, but you’d miss immediately if it was not longer there. In this case, it’s the Maven 2 plugin which automatically updates your source files with the appropriate license details

Maven License Plugin

Until now this was an annoyingly manual task which was just not quite annoying or time consuming enough to merit spending time automating. It was one of those borderline annoyances which you plan to do something about, every time it bites you. However, in this case it is always the last action before cutting a release, when you’ve had a long hard day, the caffeine has worn off (and it’s a bit late for another dose, you’d never get to sleep) – you’re running on an empty tank and you’d really like to get out of the door. Over time these small tasks stack up and sap your energy.

That’s why this plugin is such a life saver. It does just what it says on the tin, took about 5 minutes to set up and get going – saving time the very first time I used it, even taking into account the minimal setup and configuration.

Every time I find a new plugin like this I’m reminded of some of the great things about maven – particularly the convention over configuration, which facilitates such easy sharing and reuse, and allows most features to ‘just work’. For sure, there is a learning curve associated with maven – but once you’re up to speed the benefit really shows.

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