You are here

Project Architecture

Project Architecture

To allow standard Swing components, such as JTable, JList and JComboBox, reading thread-safe data from the underlying DataList model, while being updated by many threads at the same time, a double-buffering technique is  implemented.

The DataList class, implementing the java.util.List interface, is actually a wrapper of two different lists: a source list and a target list, the second one being a java.util.ArrayList. All standard Swing components can randomly read underlying data models upon request of the AWT Event-dispatching thread. To allow this behaviour and avoid performance problems, the target list model always implements the java.util.ArrayList class.

Swing components read the embedded target list inside the AWT Event-Dispatching thread while any number of threads is modifying the source list cuncurrenlty. A change in the embedded source list doesn't cause an immediate synchronous update of the user interface. The synchronization is upon request of  AWT Event-dispatching thread. When and update is required by the AWT Event-Dispatching thread, an atomic, and thread-safe syncronization, takes place between the two embedded lists. To make the atomic and thread-safe synchronization as fast as possible, an event optimizing component is used, the core and the main feature of the DataList model.

Event Optimizer

When a change occurs for the first time in the DataList embedded source list, an object implementing the java.lang.Runnable interface, the EventRunner, is created and inserted into the AWT Event-Dispatching queue using the EventQueue.invokeLater(Runnable runner) method of the Swing frametwork. This component is also a listener, receiving events in real-time from the source list which implements the ActiveList interface sending events when updated.

The EventRunner collects all the events from the source list and redirect them to an ActiveListEventAssembler component packing and optimizing them in linear time: the original sequence of events is then transformed into a strongly optimized one.

When the AWT Event-Dispatching thread executes the run method of the  EventRunner component, a read and write lock is acquired on the source list and the target list is synchronized in one go with the source list using the optimized list of events.

Following a class diagram describing the connections between the described objects.

Model Adapters

A set of adapter has been implemented to make javax.swing.JList, javax.swing.JComboBox, javax.swing.JTable Swing components read the content of the common DataList model. The DataList component implements the ActiveListEvent interface and to allow more flexibility all the adapters have been build around that interface.

The list model adapter

The ListModelAdapter implements the javax.swing.ListModel interface and represents the model seen by the javax.swing.JList component. It provides an interface between an ActiveList and the javax.swing.ListModel. When updated the ActiveList fires events to the private listener ListDataListenerDispatcher which translates them into javax.swing.event.ListDataEvent understandable by the javax.swing.JList.

Because the ActiveList is a list of Java Beans, the javax.swing.JList must provide a custom javax.swing.ListCellRenderer in order to show the bean information on the GUI. The implementation BeanListCellRenderer allows to get such information usign Java Reflection.

The combobox model adapter

This adapter is very similar to the previous one. The main difference is in the ComboBoxModelAdapter logic which includes a reference to the current selected object. The default javax.swing.BasicComboBox cell renderer BeanCombpBoxCellRenderer is provided to show the information from the list Java Beans.

The table model adapter

The table model adapter is a little bit more sofisticated. The ActiveList contains Java Beans and an additional interface TableStructure is used to transform the bean information into a table row. The default implementation BeanTableStructure is provided to transform the content of a bean into a table row using Java Reflection.