Swlink

Swlink provides an all purpose data and event-binding facility for Java in general and Swing in particular. Swlink, unlike other frameworks, considers the Link between two components a first class entity. Each Link binds an Activator and an Action together. Once the Activator is triggered, the Action defined for the link is performed. Swlink is available as open source for download.

Activators can be bound to arbitrary events including, of course, PropertyChangeEvents. There are two predefined target actions, PropertySyncAction and DelegateMethodAction. The first is used to synchronize component properties of any component with any other component using standard JavaBeans getter and setter methods. The second is used to invoke a delegate method in case the link is activated. For example, this can be used to invoke a specific method if a user presses a button on the gui.

Getting started

Swlink is available under an open source license. Download a Swlink binary or source code distribution. In order to build Swlink from source, you need apache-ant available from the Apache Software Foundation. For using Swlink you need to incorporate Swlink and its dependencies into your classpath. Currently this will include the following jar files For running the Swlink examples and for performing unit tests you will need the additional libraries in the lib directory of the distribution. You can run the Swlink examples from the command line using the following java command.

java -jar swlink.jar

Or you can run it directly using Java. Note that you need to set the class path accordingly.

java com.iternum.swlink.examples.Launcher

This will open a window with a selection list that contains the various examples.

Using Swlink

Documentation for Swlink is available in this document and in the Swlink JavaDoc.

Creating a Delegate

A delegate is a method that is invoked on the target of a link if the link is activated.

A common example is to invoke a specific method if a specific button is pressed. In Java there are multiple ways to achieve this. One of the most popular is shown below.
myAcceptBtn.addActionListener(
    new ActionListener() {
        public void actionPerformed(ActionEvent pEvt) {
            getController().okPressed();
        }
    }
);
This is a lot of code to create something very simplistic. In Swlink, this logic is reduced to a single line of code.

Linker.createDelegateLink(myAcceptBtn, ActionEventActivator.class, null, 
    getController(), "okPressed", false, false, false);      

Property Synchronization

One of the most common problems in gui programming is that the content of the gui needs to be synchronized with some form of model. Typical models are business models and presentation models. In business models, the gui components map directly to the actual business objects. In presentation models, the gui components map to a model representation that is more geared towards user interaction tasks and is subsequently - for example on pressing an ok button - transfered to the business object model. Fortunately, Java has the notion of JavaBeans to describe objects that enable access to their properties with getter and setter methods. Consider binding the content of the textfield myNameTf to the field called lastName in the model. Binding should occur, whenever the text field loses its focus and whenever the value in the model changes (assuming lastName is a bound property), as shown in the diagram below.

One common approach for such a synchronization is using explicit code like this.
getModel().addPropertyChangeListener(this);
...
myNameTf.addFocusListener(new FocusAdapter() {
    public void focusLost(FocusEvent evt) {
        getModel().setLastName(myNameTf.getText());
    }
});
...
...
public void propertyChange(PropertyChangeEvent pEvt) {
	if (pEvt.propertyName().equals("lastName")) {
		myNameTf.setText(getModel().getLastName());
	}
}
Again, a lot of boilerplate code for a standard task. Since Swlink supports the notion of bidirectional connections, setting up the same synchronization looks a lot tidier.
Linker.createPropertySyncLink(myNameTf, "text", FocusLostActivator.class, 
    null, getModel(), "lastName", null, null, true,false);
Of course it is also possible to synchronize two properties in two arbitrary JavaBeans. Consider two JavaBeans with properties propertyOne and propertyTwo respectively. A change in propertyOne should synchronize propertyOne with propertyTwo in its opposite and vice versa.

Swlink allows to create this Link with minimal code.
Linker.createPropertySyncLink(theBeanOne, theBeanTwo, 
            "propertyOne", "propertyTwo",true,false);

Using an EndpointProxy

By using an EndpointProxy, you can create a Link between two Objects that can change after the Link is established. This is an extremely powerful concept as it enables you to "wire" up connections even before you can supply the underlying data. A typical usage scenario for this is an editor form for list items. You can bind all the fields in the form to the proxy and at runtime supply the actual object to the proxy by calling the setValue() method of the proxy. An EndpointProxy can be used to proxy both source and target of a link. The following code snippet uses an EndpointProxy to proxy the source of a link.
TestBean theBeanOne = new TestBean();
TestBean theBeanTwo = new TestBean();
EndpointProxy theSource = new DefaultEndpointProxy(theBeanOne);
Linker.createPropertySyncLink(theSource,theBeanThree,
            "propertyTwo","propertyTwo",
            true,false);
...
// Now swap the source of the link
TestBean theBeanThree = new TestBean();
theSource.setValue(theBeanThree)

Using nested properties

Swlink supports creation of links by supplying nested properties between the target and the source provided. Effectively, Swlink will resolve the nested properties and will then create the actual connection between the resolved target and source. Consider the diagram below. You want to link propertyOne of TestBeanOne with propertyTwo of TestBeanTwo for property synchronization.

In order to do that, however, you establish a Link between propertyOne in TestBeanOne and a nested property beanTwo.propertyTwo in TestBeanThree. The code to setup such a Link is again very compact.
Linker.createPropertySyncLink(beanOne, beanThree,
          	"propertyOne", "beanTwo.propertyTwo",
            true, false);
Nested properties are especially useful if they are combined with an EndpointProxy. As a general rule, EndpointProxies are resolved before nested properties. By calling setValue() in an EndpointProxy, the links with nested properties are recreated using the newly supplied value object.

Consider a data structures that is hierachical and that is connected to several other objects on different levels of the hierachy. Now this object can be swapped in and out as a single entity during program execution. The Swlink examples contain code that demonstrates handling of structured profiles. They consist of data about a person, a home address, a delivery address and various other data.

In general, Swlink supports nested properties to the same extent that the underlying implementation of Apache BeanUtils supports them. This includes simple nested properties as outlined in this example as well as mapped and indexed properties.

Property Conversion

A common task is to convert data between the gui representation and the internal object model representation. Typical conversions deal with converting a string in the gui component into a number or a domain object as shown below.

Swlink uses Apache BeanUtils for property synchronization. So every time Swlink attempts to set a property, the BeanUtils property conversion mechanism kicks in. BeanUtils comes with several out of the box convertors that make it easy to transform Strings into basic Java data types, like number, boolean values or dates. Converters are typically registered at application startup time. There is also support for locale sensitive conversions. The example below shows a simple date conversion.
// Create a beanutils locale sensitve converter
ConvertUtils.register(new DateLocaleConverter(null, Locale.GERMANY,
            "dd.MM.yyyy"), java.util.Date.class);
Swlink builds on this mechanism to provide support for formatting conversions. Formatting conversions are typically required when you need to transform some data type into a String. Swlink provides out of the box support for the classes derived from java.text.Format. It is also easy to provide your own format classes to format domain specific objects, for example order numbers or airline codes. The example below shows to format a date accoring to a specific date format.
// Create a format converter for a date
FormatConverter formatConverter = new FormatConverter();
formatConverter.setFormat(java.util.Date.class,
  new SimpleDateFormat("dd.MM.yyyy", Locale.GERMANY));
// Register with BeanUtils
ConvertUtils.register(formatConverter, java.lang.String.class);

Swlink Architecture

The main interfaces used in Swlink are One of the major architectural goals of Swlink was to make object links independent on any assumption on the particular nature of the linked endpoints. In fact the only assumption inherent in Swlink is that they are Java objects and to a certain extent that they are JavaBeans. Unlike with other powerful frameworks for gui data binding, Swlink makes no assumptions about the nature of the model or the individual components it links together Of course the most prominent example is using Swlink to link graphical interface elements - thus the name. But you can use Swlink to link virtually all types of objects with each other as long as they are Java Beans.

Performance

Swlink makes use of Java Reflection to create connections between components. Relection is used both when a connection is established - for example when registering a property change listener - as well as at runtime, when a particular method is invoked by name. While this does have a certain performance impact, chances are that it is barely noticeable in your actual application, unless you have an application that establishes and activates connections at an extremely high rate. For example, experience has shown that this approach is usually sufficient for typical form handling purposes.

Extension Points

You will hardly ever need to create new types of Links. The main extension points of the system are to create new Activator and Action.

Activators

Create a new Activator when you need to define a new way to activate a connection. Consider to derive your new Activator from AbstractActivator and implement the abstract methods.

Actions

Create a new Action if you need to define a new action in order a link is activated. Consider to derive your new Action from AbstractAction as this provides boilerplate implementation for handling reentrancy. Before creating a new Action take some time to determine if you cannot use one of the existing Actions. Actually the existing action types should suffice most of the time.

About Swlink

Swlink has been initiated by Karl F. Banke. In 2005, he returned to do some graphical user interface programming using Java Swing after spending 5 years mainly on the Java Server Side. He was astonished to find out that there is still a lot of custom boilerplate code required to connect events with event handlers and models with their view representation. There are some decent graphical gui builders, but by and large they mostly support the creation of the application view. He recently worked with Apple's Interface Builder product, and it became quite obvious to him that the best way to tie a graphical user interface into application logic is by declaratively connecting component instances. So when you can do it graphically, why would you compromise and have your graphical tool generate tons of boilerplate code tying you into whatever tool you use?

License

Swlink is licensed under the Apache License, Version 2.0.

Legal

This website contains references to product and company names of other companies. The terms used are registered trademarks of the respective companies. Several pages on this page contain links to other sites. We are stressing that we have no influence whatsoever on such websites. Therefore we dissociate iternum from all content on pages linked from this site. We do not share nor assume the views of the creators of these sites. This statement covers all links from this page.
Copyright Karl F. Banke, 2006