Simple table summary companion

Sometimes it may seem that standard Swing JTable or its close companions like SwingX JXTable are too limited. You don’t have too many funny ways to manipulate them – they are strict rectangular grids, with every row taking fixed amount of screen space in pixels and columns taken from one and only column model. Columns cannot be spanned or split and always take a single cell in the grid.

However there’s a reason why tables are so strict in implementation – performance. Swing tables are extremely speedy when you bake them right – don’t calculate anything in getValueAt() method of table model, do not over-use bulk updates of table model and change its structure, preferring to use single-cell focused, precise updates, and don’t use expensive rendering like built-in HTML. Fixed row height allows you not to query all of the rows even if you have millions of them – you can predict and calculate table’s height and show it appropriately inside of the container (most probably a scrolling pane) just by asking model how many rows it contains.

The other thing is to keep model as simple as possible. Indeed, you basically only need to know how many rows you have and what is in the cells for each row. No one will ask you about more data if it’s not shown on the screen. This allows us to use very clean table solutions like the bean reflection one we’ve discussed and implemented earlier in the blog.

But making tables much more powerful does not need a complete re-write. Let’s consider the situation when we need a “summary” row or even a few rows below the main table. In most cases, data in a “summary” does have a relation to “main” data, but they are not the same, rather they should behave like they are in the same table. So the design question is – will you keep the summary data in the same model or in a separate model. This potentially mean keeping fields and objects with summary data in the main data collection, thus replacing clear meaning of main table objects with something else, i.e. keeping summarized string name instead of plain “name”, controlling sorting so that summary rows won’t change their positions etc. This does not lead to clean and robust code.

To keep the code as clean as possible, let’s consider we have separate models and data collections for main and summary table, and they both can be shown in the model, for example with our bean reflection model. How do we show them as “one” table without user being able to even notice that he works with two tables? The answer is to share the table column model. This will share the renderers, editors and will automatically change order of columns for a second set of columns. The only thing needed is to have the column count and their data types to correspond between two tables – otherwise the renderers or editors may fail to understand them. Everything else is a little bit of layout magic – we’ll position tables on top of each other, make sure that scroll panes work well together and share the column model.

We’ll position tables in a panel with border layout, main table is going to take most of the space in the center, and summary one will have the remainder at the bottom, both stretched horizontally to the edges of the container, as BorderLayout implies. Here is our panel class and its constructor:

public class SummaryTablePanel extends JPanel {

protected final JTable mainTable;

protected final JTable summaryTable;

protected JScrollPane mainScrollPane, summaryScrollPane;

/**
 
* Creates a summary panel which lays and connects main and summary tables.
 
* @param mainTable Main table with the data

* @param summaryTable Summary table with the summary data. 
All the headers and additional behavior will be stripped.
*/
public SummaryTablePanel(JTable mainTable, JTable summaryTable) {

setLayout(new BorderLayout());

this.mainTable = mainTable;

this.summaryTable = summaryTable;

initComponents();

}

}

Note that fields are protected, so one can override the panel and add some more enhancements and changes for the standard summary behavior. initComponents() method is used to lay out the tables, put them into the scrolling panes and make sure they behave correctly.

First two steps are putting tables into scrolling panes and sharing the column models. This step will fail if data types for columns differ for main and summary tables, so that would be a fail-fast step in our construction.

private void initComponents() {

// step 1 - add tables into their areas

mainScrollPane = new JScrollPane(mainTable);

add(mainScrollPane);

summaryScrollPane = new JScrollPane(summaryTable);

add(summaryScrollPane, "South");

// step 2 - share the column model

summaryTable.setTableHeader(null);

summaryTable.setColumnModel(mainTable.getColumnModel());

 

Tables are put into appropriate positions wrapped into scrolling panes. Note that we are disabling table header for summary table to hide it and mimic the column set as one. Then column model from the main table is shared with the summary one – this will mean reflecting changes in columns sizes, their order on screen and dragging whenever user decide to change one of these things.

The next few steps are to tweak the visual appearance of the summary table to make sure it looks exactly as continued main table:

// step 3 - remove unnecessary UI

if ( summaryTable instanceof BaseTable ) {

((BaseTable)summaryTable).setFilterHeaderEnabled(false);

}

if (summaryTable instanceof JXTable) {

((JXTable)summaryTable).setColumnControlVisible(false);

}

// step 4 - use only necessary size

summaryTable.setPreferredScrollableViewportSize(

new Dimension(summaryTable.getPreferredSize().width,

summaryTable.getRowHeight() * (summaryTable.getRowCount() == 0 ? 1 :
 summaryTable.getRowCount()) + 1));

We’re checking if the summary table is instance of our BaseTable with more features and disable filter header for it, just in case it was enabled. If table is generic SwingX JXTable, we’re hiding its column control, which may be enabled, so that the client programmer can safely create the summary panel and not think about those minor details. The very important thing is to set appropriate size for summary table inside of the scrolling pane. We cannot set the table preferred size directly since it is in the scrolling pane, instead we’re using setPreferredScrollableViewportSize() method which allows us to change the preferred size of scrolling pane viewport. If there’s any data in the summary table, we’re setting the height to be equal to optimal height to show them – considering summary table will not contain too many rows. If there’s no data, we’re just use the size for single summary row. If you want more flexible approach for your summary rows, you can override this component and do the size tweaking according to your needs.

Last thing would be having only one horizontal scroll bar for both main and summary tables so the users can get an impression of completely connected table with a separator between usual and summary rows. We most probably don’t want synchronized scrolling on vertical side – users probably will position usual data rows differently from summary rows, but horizontal scrolling, if enabled, should be connected. Again, this is something you can always add later in a similar fashion.

// step 5 - adjust and connect scroll bars from scroll panes

summaryScrollPane.setColumnHeader(null);

summaryScrollPane.setHorizontalScrollBarPolicy(
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

summaryScrollPane.getHorizontalScrollBar().setModel(
mainScrollPane.getHorizontalScrollBar().getModel());

Here, we’re disabling the horizontal scrollbar for the summary table and only leave main one (potentially, if horizontal scrolling is enabled for the main table). That’s a matter of taste and visual design – the scrolling bar thus appears between main and summary tables, strongly separating them. The other approach is to have it on summary table, at the bottom, with less separation between tables, and behaving as one, but potentially confusing to see the separation line between two. To make two scrollbars from different scrolling panes to behave as one, we’ll use the famous Swing shared model feature again – and just share the model from main scrolling pane scrollbar with the summary one.

To see everything is the action, you can download the latest source code of the tools project from http://code.google.com/p/swingtools/ and run the TableSummaryTest test class. This is a Swing FEST based test class which tests various UI aspects of our new compound component. It uses dynamic bean reflection table model to quickly construct tables. Before it runs you can make pauses a bit longer to see and touch how summary table behaves.

 

Similar approach can be used to emulate divided blocks of rows or columns visually looking as being in a single table, keeping the elegancy and accuracy of simple clean table models. Clean data models focused on specific data types can be more important to keep code understandable and robust then monstrous Excel-like table which keeps everything in one model which quickly becomes rather UI than data driven with all the consequences of having UI code creep into the business logic.

Posted in Uncategorized | 23 Comments

Ultra-powerful tables with SwingX and FilterHeader in just 20 minutes

Remember, you can find all of the articles code and tools, as well as latest additions and changes at project code site, http://code.google.com/p/swingtools/.

 

Previously we’ve created a really powerful addition to the tables – the model which automatically figures out which columns are available from the given data set, their types which will determine the rendering and editing data. The performance of that model is extremely high as well especially on very large data sets comparing to more heavyweight beans binding solutions which is always a point of interest when working with tabular data that tend to grow huge.

 

Let’s continue on user experience side. Standard JTable does not provide almost anything to make user’s life easier, comparing to its quite famous colleague, pivot table from Microsoft Excel, which allows you to do various filtering and even calculate trends and functions based on data in the table. We’ll leave functions and calculations aside, it’s too complicated and will take a lot of time, and rarely needed, most of such functions are done by the application business layer instead. If you still need something like that where logic is interleaved with presentation, you can either use JIDE’s grids implementation (though they are commercial, behave differently and cost quite a bit) or attach scripting with JDK’s built-in Javascript and use it as a macro language.

 

We’ll concentrate on simpler usability and appearance things which are still missed from standard JTable, but frequently required by users. First of all, sorting is available now in the JTable, but disabled by default. But more advanced sister of JTable, JXTable from open-source SwingX set, does enable sorting by default, so it will be a good idea to always start with JXTable. The other powerful thing from JXTable is that it allows you to hide columns and restore them back, and more than that, provides a menu to do that with a custom button located in upper right corner of the scroll pane where a JXTable is put. One of the most powerful features of SwingX table is that it allows you to do highlighting over the rows based on some criteria, including simple striping, i.e. interleaving colors between even and odd rows of the table which makes them easier to read. Let’s start:

public class BaseTable extends JXTable {

    public BaseTable() {
        // always enable column control and striping
        setColumnControlVisible(true);
        setHighlighters(HighlighterFactory.createSimpleStriping());
    }

Moving on, there is filtering built in into the standard JTable, but it’s headless (has no UI) and requires some effort to enable and write filters programmatically. Meanwhile, there are no default UI components to do the simplest filtering on the table’s data, neither in core JTable nor in JXTable. Fortunately, there’s a nice open-source solution available from Coderazzi and it’s available from the central Maven repository. It’s extremely easy to use – we just need to create a new instance of table filter header UI component and pass our table into it. Table filter will track model and data changes and update itself automatically. It makes sense to include the table filter header directly into our advanced table:

public class BaseTable extends JXTable {
    /** Filter header used in the table */
    private TableFilterHeader tableFilterHeader;
    /** Flag to enable or disable filter header */
    private boolean filterHeaderEnabled;

    public BaseTable() {
        // always enable column control and striping
        setColumnControlVisible(true);
        setHighlighters(HighlighterFactory.createSimpleStriping());
    }

    public boolean isFilterHeaderEnabled() {
        return filterHeaderEnabled;
    }

    /**
     * Enables or disables and hides filtering header
     * @param filterHeaderEnabled True to enable and attach filter header component
     */
    public void setFilterHeaderEnabled(boolean filterHeaderEnabled) {
        // if filter was off and enabled, create and attach it
        if (filterHeaderEnabled && !this.filterHeaderEnabled && tableFilterHeader == null) {
            // enable the filter header
            tableFilterHeader = new TableFilterHeader(this);
        }
        if (tableFilterHeader != null) {
            tableFilterHeader.setVisible(filterHeaderEnabled);
            tableFilterHeader.setEnabled(filterHeaderEnabled);
        }
        this.filterHeaderEnabled = filterHeaderEnabled;
    }

    /**
     * 
     * @return Filter header component used in the table or null if never used
     */
    public TableFilterHeader getTableFilterHeader() {
        return tableFilterHeader;
    }

As you can see from the code, we don’t attach the filter header directly and forever – you can disable or enable it back, or get it and manipulate it directly. There’s a reason behind that – although quick and simple filtering using the header is nice, it does involve some overhead, especially when new large bulk of data (rows) arrive. By default the filter header is disabled, but it’s easy to enable it only by setting the appropriate flag to true.

 

Another thing that is missing from the both JTable and JXTable is tooltips for the cells. As we all know, most of the time the cells are rendered by the JLabel, which hosts some form of text representation of the value in that cell. To enable tooltip, you need that label to have it installed with setToolTipText(). Override all renderers and call it explicitly? Luckily, no. There is a helper method in  JTable class which gets called every time before renderer got prepared to be painted in the cell. Since it’s a single point of access to all of the renderers installed on the table, we can override it and do a simple job of enabling tooltips there:

/**
     * Overriden to set the tooltip text for the label-based renderers.
     * @param renderer
     * @param rowIndex
     * @param vColIndex
     * @return 
     */
    @Override
    public Component prepareRenderer(TableCellRenderer renderer,
            int rowIndex, int vColIndex) {
        Component c = super.prepareRenderer(renderer, rowIndex, vColIndex);
        if (c instanceof JLabel) {
            JLabel label = (JLabel) c;
            label.setToolTipText(label.getText());
        }
        return c;
    }

Taking the demo from previous article, where we dynamically populated model with beans, let’s do the same, but use new BaseTable with advanced functionality and filter header enabled:

final BaseTable table = new BaseTable();
        table.setFilterHeaderEnabled(true);
        add(new JScrollPane(table));
        BeanPropertyTableModel<TableBean> model = new BeanPropertyTableModel<TableBean>(TableBean.class);
        model.setOrderedProperties(Arrays.asList("name","surname","date"));
        model.setData(TableBean.generateList(100));
        table.setModel(model);

 

We’ll have the following – notice that you can hide and show all columns or adjust them to their preferred width (“pack”):

Table Demo

 

 

Tooltip are available for all cells by default, without dealing with renderers individually. And filtering works like a charm (in this screen, first column shows everything starting with Z, seconds everything starting with P – both of them should be true so we have only one such a row):

Table Demo

 

Much better and more usable than the standard JTable, and still as fast as it is.

 

Posted in Uncategorized | 371 Comments

Easy high performance tables with reflection data binding

Article code can be found at project code site, http://code.google.com/p/swingtools/.

Swing’s JTable is an extremely powerful component. It allows you do to almost everything with it, include any other components, draw and edit in each cell differently etc. Its model, TableModel, is not complex, but it requires certain amount of very boring and boilerplate code to implement a table for many situations. Most of the time, you have a list of objects where a single object presents one row in a table, and columns values are mapped to properties of that object. And for every new object type and new table, you have to write your TableModel yourself, repeating these lines of code again and again:

public class SimpleTableModel extends AbstractTableModel {

    private List data = new ArrayList();

    @Override
    public int getRowCount() {
        return data.size();
    }

    @Override
    public int getColumnCount() {
        return 10;
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        switch (columnIndex) {
            case 0:
                // either toString() or a slightly different data processing
                return data.get(rowIndex).toString();
                // many more case,case,case for each column...
            default:
                return "";
        }
    }
}

In general case, you only need those three methods to have a working table, if you’re satisfied with Excel-like column titles ‘A’, ‘B’,…,’AB’ etc. Most of the time titles are needed to be implemented as well, so this means another annoying ‘switch/case’ or preparing a list of column names so that they could be obtained by the index. There are no helper methods to obtain them directly from resources and that means you need to maintain table column names both in the code and in the resource bundle.

 

For smaller tables it seems OK to use the technique above, but if you have quite a few of them, writing the same code again and again become boring and that’s a good ground for starting to use notorious ‘copy-paste’ which means a lot of subtle bugs later. For large tables the code is monotonous set of large ‘switch/case’s, ‘if’s etc., which again is extremely low-level work and a fertile soil for a lot of bugs and mistypes. The worse thing is changing such models later, when you have different column order, names, or underlying data object has been re-factored and its properties are changed. It’s quite easy to introduce bugs and forget about many small things.

 

The obvious solution would be assigning columns directly to properties of an underlying data bean. The properties themselves have type which could become a type of a column – and that means automatic selection of an appropriate renderer and editor. It’s not hard at all to build such a table model and use it later for most of your table implementations.

public class BeanPropertyTableModel<T> extends AbstractTableModel {
    // class of the data in rows
    private final Class beanClass;
    // collection of table rows
    private List<T> data = new ArrayList<T>();
    // collection of column property descriptors
    private List<PropertyDescriptor> columns = new ArrayList<PropertyDescriptor>();

    public BeanPropertyTableModel(Class beanClass) {
        if (beanClass == null) {
            throw new IllegalArgumentException("Bean class required, cannot be null");
        }
        this.beanClass = beanClass;
        populateColumns();
    }

    public List<T> getData() {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data;
        fireTableDataChanged();
    }

    @Override
    public int getRowCount() {
        return data.size();
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return columns.get(columnIndex).getPropertyType();
    }

    @Override
    public String getColumnName(int column) {
        return columns.get(column).getDisplayName();
    }

    @Override
    public int getColumnCount() {
        return columns.size();
    }

    @Override
    public Object getValueAt(int rowIndex, int columnIndex) {
        PropertyDescriptor descriptor = columns.get(columnIndex);
        T bean = data.get(rowIndex);
        return DynamicBeanUtils.getPropertyValue(
          bean, descriptor);
    }

    private void populateColumns() {
        BeanInfo info = null;
        try {
            info = Introspector.getBeanInfo(beanClass);
        } catch (IntrospectionException ex) {
            throw new RuntimeException(
              "Unable to introspect bean class", ex);
        }
        PropertyDescriptor[] pds = info.getPropertyDescriptors();
        columns.addAll(Arrays.asList(pds));
    }
}

This is again a simple table model derived from AbstractTableModel class which does some event support and stub methods for us. We have to pass a class of the bean we’re going to show in the table into the constructor as generics type erasure won’t let us know the type of T. Upon creating a model we get all properties available in the bean with the help of core JDK BeanInfo class. Every property is described by a PropertyDescriptor. Numbers of properties in the bean becomes number of columns. When passed a new list of beans into setData(), the model notifies listeners that its data has been changed.

 

The only interesting thing is how to get a property value. This is pretty easy and separated to be in own utility class as we may need it later:

public class DynamicBeanUtils {
    public static <T> T getPropertyValue(Object instance, PropertyDescriptor descriptor) {
        try {
            Method m = descriptor.getReadMethod();
            Object result = m.invoke(instance);
            return (T) result;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

There are no reasons to catch any exceptions here and they shouldn’t be thrown as bean properties are supposed to be accessible and public, so we’re converting them into unchecked ones.

This very initial and simple implementation is already able to show list of arbitrary beans with all of their properties as columns in the table. For example, if we take the following test Java bean class:

public class TableBean {
    private String name, surname;
    private Date date;
    ...
    getters/setters
}

And create a large list of its instances with randomly generated strings and data, we’ll see the following:

 

 

The only code to create this table is:

final JTable table = new JTable();
add(new JScrollPane(table));
BeanPropertyTableModel<TableBean> model = new BeanPropertyTableModel<TableBean>(TableBean.class);
model.setOrderedProperties(Arrays.asList(“name”,”surname”,”date”));
model.setData(TableBean.generateList(100));
table.setModel(model);

 

We see that date property is recognized and properly rendered thanks to its column class, and property names are used as column names. The bad thing is BeanInfo class returns property descriptor for ‘class’ property which of course exists in any Java object (there’s getClass() method) but doesn’t belong to actual properties of an object. It makes sense to add a concept of excluded properties which would allow us to exclude certain properties from showing as columns. ‘class’ property will always be excluded.

 

The other thing is the order of columns on the screen. It’s not strictly specified by the language or compiler or virtual machine, but since the very early days of Java beans and reflection it’s always been alphabetic order of their names. Order of properties in the source file is discarded when compiler does its work. Most of the time users want to see certain order of columns on screen, so another feature of bean property model should be an ability to specify order of its properties. This is just a simple list of names and it makes sense to load it from application resource file. Also, in order to specify custom rendering for certain columns and manipulate them in other way we need to know which index has the column mapped to specific property.

 

And the last important thing would be reading column names from resource bundle using some prefix and property name. Most of the time you’ll have to do that as property names rarely work well as screen names even if you split them by words using appropriate cases.

 

Having added all of that quite primitive but useful functionality into our new BeanPropertyTableModel, we end up with the following laconic API to build flexible and powerful tables with any data in a matter of seconds:

 

setResourceBundle(ResourceBundle)

setResourcePrefix(String)

addExcludedProperty(String)

setOrderedProperties(List<String>)

 

Having all the API in place and adding just one new line

model.setOrderedProperties(Arrays.asList(“name”,”surname”,”date”));

 

We can enjoy grown up table which behaves exactly just like we’d described it s model completely from scratch for a particular Java bean.

 

 

Tables often become victim of poor performance, especially for large number of columns and complex data types. What about our new property table model? Some may remember the rumors on Java reflection poor performance, and for the large, many columns and rows table we definitely will use a lot of reflection calls to access the properties. But, in recent versions of JDK reflection performs really well and won’t be an issue comparing to usual graphics/painting overhead, more than that, JDK will replace reflection calls with bytecode pretty quickly as it discovers we’re using a lot of calls to the same methods to get the properties values. You may find it interesting to see an article on reflection performance and benchmarking here: http://buzdin.blogspot.com/2011/01/is-java-reflection-really-slow.html.

Are there any similar alternatives? One of the common solutions to quickly build tables and bind them to properties is Beans Binding library, which does not allow you to quickly show all of the bean properties as our model does, but you can add column using EL language syntax and even access inner properties inside of properties.

However, some of my experiments clearly showed insufficient performances of Beans Binding for large tables, especially if tables are read only and the bean itself does not notify listeners on changes on every single property which is supposed to be extremely fast. Simple and small table model from this article perform much faster and you can visibly see the difference, especially in scrolling. The most painful part with Beans Binding is reloading the whole data list – it takes time on event dispatch thread to re-build listeners and visibly slows down your application whenever large list of rows for a table arrives.  There is no way you can make your table as fast as manually created table which gets its data from directly calling methods of objects known at compile time when you use Beans Binding, but the simple reflection model used in this article comes very close and saves tons of time especially when it comes to prototyping or hundreds of tables in the application. Use this model for the tables of any size and any frequency of updates and still have power of binding and dynamic at hand.

The code for the bean properties based table model and other useful Swing Tools can soon be found on Google Code, under SwingTools project (http://code.google.com/p/swingtools/).

 

Posted in Uncategorized | 20 Comments

Better control of what SwingWorker does for you

SwingWorker is a great tool and a part of the standard Swing in JDK now. It does crucial job for any decent Swing application – allows us to execute long running heavy tasks on a separate thread in a background and update all of our UI models and components on UI dispatch thread. Otherwise the only heart and pumping engine of Swing UI, event dispatch thread or EDT, will be busy with moving heavy stuff and poor users won’t get a change to enjoy your wonderful application, starring at frozen pressed menu items or buttons instead.

 

It’s easy to trust such a great tool and always carelessly call it’s execute() method, not worrying what’s going on behind the scenes, but this is multi-threading and you better control every aspect of it in your application. So, what’s happening when you do something like this?

SwingWorker<String, String> work = new SwingWorker<String, String>() {
        @Override
        protected String doInBackground() throws Exception {return "";
        }

        @Override
        protected void process(List<String> chunks) {}

        @Override
        protected void done() {}
    work.execute();

When you call execute(), your SwingWorker instance gets executed by itself, and uses internal Executor service, which is fixed size thread pool with 10 threads in current versions of JDK. So if you application is big, and accidentally you have more than 10 background tasks running, all of the subsequent tasks will wait for the next available thread, which may hit the user experience significantly. More than that, recently there was a bug in the JDK regarding SwingWorker not able to execute more than one task at a time.

 

So looking in the future and expecting your application to grow and even more important, willing to control multi-threading behavior which is crucial to have better user experience with Swing UI applications, it’s better to do the execution of all your background tasks yourself. We just need to create our own Executor service, somehow expose it to all UI modules making use of SwingWorker to do background tasks, and whenever needed, change its implementation or debug it if application shows unsatisfactory behavior running a lot of background tasks.

 

The easiest way would be providing a service created with a help of a factory, something similar to the following:

public interface BackgroundTaskService {
    /**
     * Executes SwingWorker task.
     * @param worker Worker to be executed.
     */
    void execute(SwingWorker<?,?> worker);
    /**
     * Executes Runnable on background thread, it's up to
     * Runnable's code to call invokeLater() to update the UI. Do
     * not update or work with UI from the Runnable.
     * 
     * @param work Code to execute on background thread.
     */
    void execute(Runnable work);
}

This interface describes the responsibilities of a service, and we can create concrete implementations, for example, based on cached thread pool which has unlimited number of threads, cached as they get created and re-used when they are freed:

public class CachedBackgroundTaskService implements BackgroundTaskService {

    private ExecutorService executorService = Executors.newCachedThreadPool();

    @Override
    public void execute(SwingWorker<?, ?> worker) {
        executorService.execute(worker);
    }

    @Override
    public void execute(Runnable work) {
        executorService.execute(work);
    }
}

We can of course create other implementations, and even test how an application would work without background tasks by creating special implementation which just calls run() method of the SwingWorker or Runnable. That would definitely demonstrate a nightmare of running complex Swing application all in one event dispatch thread.

 

The different issue is how to provide all of your UI modules with BackgroundTaskService implementation. That’s a well known pattern of Service Locator (e.g. <url> http://martinfowler.com/articles/injection.html#UsingAServiceLocator</url>). The simplest way of course is to use singleton factory, which allows you to create a shared instance of service or multiple instances if you’d like. You then have a couple of static methods to get a current instance and set a new instance if you want to replace implementation with test stub or different approach.

package com.porty.swing;

import com.porty.swing.service.BackgroundTaskService;
import com.porty.swing.service.CachedBackgroundTaskService;

/**
 * Factory which provides access to current implementation of background task service.
 * It's instance could be substituted in order to change default library implementation.
 * 
 * @author iportyankin 
 */
public class BackgroundTaskServiceFactory {
    private static BackgroundTaskServiceFactory instance;
    // we use this implementation by default
    private CachedBackgroundTaskService taskService = new CachedBackgroundTaskService();

    public static BackgroundTaskServiceFactory getInstance() {
        if ( instance == null ) {
            instance = new BackgroundTaskServiceFactory();
        }
        return instance;
    }

    public static void setInstance(BackgroundTaskServiceFactory instance) {
        BackgroundTaskServiceFactory.instance = instance;
    }

    /**
     * Obtains currently used implementation of background task service.
     * @return Background task service
     */
    public BackgroundTaskService getBackgroundTaskService() {
        return taskService;
    }
}

The other approach would be using some sort of dependency management which is a good idea in general for programming Java Swing UI to be able to alter its behavior quickly. One of the candidates could be Google Guice, easy to use and bind to different implementations.

You can ask what’s the need in that additional abstraction level of background executor if we could just share an instance of ExecutorService between all of the UI modules in the application and make sure they all use it to execute their tasks. The good thing is that we can also provide some additional functionality in the new service related only to UI applications, still keeping the execution done by powerful Java Concurrency library. Most of the time we want the progress to be shown to the user, either indeterminate or determinate, depending on how much information is available to the task. Instead of coding the sequence of showing the progress bars and guarantee to hide them when task is done or failed or cancelled we can introduce a handy calls for that and increase simplicity and elegancy when executing UI tasks.

As an example, let’s start with indeterminate progress message, non-interruptible by the user, a bit simpler than well-defined determinate progress bar, and definitely simpler than interruption-aware automated task support. Let’s add a new method into our background execution interface:

/**
     * Executes runnable showing the progress bar with the message until the task is complete.
     * @param work Work to be executed.
     * @param message Message to be shown
     * @param components Components to be disabled while task is executing
     */
    void executeIndeterminate(Runnable work, String message, Component... components);

The purpose of this method will be executing the given task in the background thread, under defined execution policy, and while the task is executed, showing the indeterminate progress message of some form, automatically hiding it when the background activity is over. This happens very frequently in Swing/any other single-threaded (or thread-confined) UI toolkit applications. Additionally, we’ll allow client programmer to disable set of components when task starts and enabled them back when it ends – pretty frequent activity as well.

Since the method itself doesn’t define how final task is executed and only builds common infrastructure, we can implement it in a base abstract class, having concrete implementations to only define how to execute tasks and re-use the complex UI-related framework from it.

First, we need to create a component which will show the indeterminate progress bar somehow. Since we don’t know which window or layout to rely on and stay generic, let’s use simplistic blocking modal dialog with an indeterminate progress bar and a label with the message. It’s part of the Swing Tools project and located in com.porty.swing.dialog package.

/**
 * Abstract implementation of the background service with some UI work prepared.
 * Has no actual execution code.
 * 
 * @author iportyankin 
 */
public abstract class AbstractBackgroundTaskService implements BackgroundTaskService {
    protected Component createProgressComponent(String message) {
        BlockingProgressDialog dialog = new BlockingProgressDialog(null, message);
        dialog.setVisible(true);
        WindowUtils.centerWindow(dialog);
        return dialog;
    }

    protected void destroyProgressComponent(Component c) {
        ((BlockingProgressDialog) c).dispose();
    }
}

These two methods are protected so you can override them and provide progress implementation more elegant and suitable for your application needs.

Then we need to wrap the background call with UI setup and tear down code and execute the final sequence. It sounds simple, i.e. create and show component before running task and dispose it after it’s done. Naive implementation could look like that:

@Override
    public void executeIndeterminate(final Runnable work, final String message, final Component... components) {
        final List<Component> uiProgressComponent = new ArrayList<Component>(1);
        // disable the components
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                if (null != components) {
                    // disable components
                    for (Component next : components) {
                        next.setEnabled(false);
                    }
                    // create a progress component
                    uiProgressComponent.add(createProgressComponent(message));
                }
            }
        });
        Runnable proxy = new Runnable() {

            @Override
            public void run() {
                try {
                    work.run();
                } finally {
                    // enable the components back
                    SwingUtilities.invokeLater(new Runnable() {

                        @Override
                        public void run() {
                            if (null != components) {
                                // disable components
                                for (Component next : components) {
                                    next.setEnabled(true);
                                }
                            }
                            // dispose progress component
                            destroyProgressComponent(uiProgressComponent.get(0));
                        }
                    });
                }
            }
        };
        // execute proxy with actual work
        execute(proxy);
    }

What we do here is schedule UI activities to be run later when all pending events are processed, including disabling the components and creating generic progress component, and then immediately run the task itself (using execute() method which will be defined by concrete execution strategy). To be able to catch end of the task, regardless of anything that happens with it, we create a proxy Runnable on top of it and use finally section to do post-mortem activities, again scheduling UI task for later, to re-enable the components and destroy progress bar component. We don’t need any sophisticated concurrency tools here since UI thread and invokeLater() guarantee that first UI task is executed before the second one, so the component will be created and available in the exchange list (we have to use final list – restriction of inner classes access to outer variables).

The beauty of the new method is extreme simplicity and handling of many activities behind the scenes for you – to execute some work with progress and disabling a button while it’s executing is one line of code:

 BackgroundTaskServiceFactory.getInstance().
getBackgroundTaskService().executeIndeterminate(worker, "Working slow...", b);

You can see some of the Swing FEST automated tests in test package for the services for standard UI.

Moving forward, it makes sense to add determinate progress with a callback which allows updating the progress, and cancellable implementation which honors the interruption policy and supplies a standard interrupt button in the UI which does it.

Remember, you can find all of the articles code and tools, as well as latest additions and changes at project code site,http://code.google.com/p/swingtools/.

Posted in Uncategorized | 27 Comments