Lucene Powered Swing Data Models

by Jonathan Simon

 

What it is.

This package contains classes that help you easily integrate Lucene based searching into your Swing components. Currently there are classes to index and search JTables and JLists. This is done using model decorators rather than custom models to make it easier to search current models as well as new ones.

These models do not actually contain any data. Rather, the ListModel decorator (ListSearcher) and the TableModel decorator (TableSearcher) take a model in the constructor and delegate all calls to it (after a little alteration, but we'll get to that). That said, these are not full fledged models themselves. You still have to have another model to decorate with the searching models. If you are adding searching to a pre-existing model, you can use your pre-existing model directly. Otherwise, you can implement a model from scratch or use a pre-existing one to get started.

What it isn't.

A complete component: These are just models. They are not complete components with search fields and buttons laid out like a searchable interface. You still have to build that since the UI changes drastically between applciations.

A complete model: There are just model decorators. You can't just set the model of a JList or JTable to one of these models, and you can't add data directly to these models.

A front end for a lucene index: In other words, you can't use these classes to point a JTable directly to a Lucene index. Although that's interesting in its own right, this is not that.

Usage:

Coding to both models nearly identical. They both take the model to decorate at construction time. Here is the code from the demo to decorate a JTable model with the TableSearcher and set it as the table model.

//make a new JTable
JTable table = new JTable();
//make my base model, the model with the data
BaseTableModel tableModel = new BaseTableModel(DataStore.getRestaurants());
//decorate the tableModel with the TableSearcher 
TableSearcher searchTableModel = new TableSearcher(tableModel);
//set the TableModel in the table to the TableSearcher
table.setModel(searchTableModel);

Initially, you won't notice a difference. This is because there is no active search which displays all data from the underlying model. You search by calling the search() method passing a search string. This filters the data set down without changing the underlying data model -- one of the main reasons for decorating in the first place. Any valid Lucene search string should work (see notes for more info on this). You'll probaby have some code somewhere like this in your app to connect a text field and search button to the model.

//create components
final JTextField searchField = new JTextField();
JButton searchButton = new JButton("Go");

//make an action listener
ActionListener searchListener = new ActionListener() {
	public void actionPerformed(ActionEvent e) {
	   searchTableModel.search(searchField.getText().trim().toLowerCase());
	}
};

//register listeners
searchButton.addActionListener(searchListener);
searchField.addActionListener(searchListener);

You also might want to have a clear search button, working the same way. But to keep things simple, if you search will a null String or an empty String, the search clears and you will once again see all of your data.

Demo notes:

The list demo does real time searching. In other words, as you type, searches run and the result set updates. The table demo has a search button, and only searches when the button is clicked. They both work, I just implemented them this way to show the different UI metaphors and that they both work.

Implementation notes:

This code started as a proof of concept so it's not a fully featured model. Don't get me wrong, it fully works, but it could use some improvement that it will hopefully get over time. I just wanted to get it out there and get people using it. I'm also trying to keep everything as simple as possible. Here are some of the issues.