Jump to: navigation, search

JFace Data Binding/Realm

JFace Data Binding
Home
How to Contribute
FAQ
Snippets
Concepts
Binding
Converter
Observable
Realm

Realm is the core concept of JFace Data Binding in regards to synchronization. A realm can be thought of as a special thread, or a lock, that serializes access to a set of observables in that realm. Each observable belongs to a Realm. It can only be accessed from that realm, and it will always fire change events on that realm. One important example of a realm is the SWT UI thread. Like for the SWT UI thread, you can execute code within a realm by using Realm.asyncExec(); in fact, the SWT realm implementation just delegates to Display.asyncExec(). This means that while the data binding framework can be used in a multi-threaded environment, each observable is essentially single-threaded. Java bean observables implement this contract on the observable side, but don't require it on the Java beans side: Even if a bean fires a PropertyChangeEvent on a different thread, the change events originating from the observable will happen within its realm. To bridge between observables in different realms, use a data binding context - you can bind two observables even if they belong to different realms and the bindings take care of this for you by using Realm.asyncExec() where necessary.

Unit Testing

When writing unit tests for observables or bindings it is difficult to set the default Realm without wrapping the test code in a Runnable and invoking Realm.runWithDefault(Realm realm, Runnable runnable). The following implementation can be used as a stub Realm for unit testing purposes and fits into the setUp() and tearDown() testing paradigm.

/**
 * Simple realm implementation that will set itself as default when constructed. Invoke
 * {@link #dispose()} to remove the realm from being the default. Does not support asyncExec(...).
 */
public class DefaultRealm extends Realm {
    private Realm previousRealm;

    public DefaultRealm() {
        previousRealm = super.setDefault(this);
    }

    /**
     * @return always returns true
     */
    public boolean isCurrent() {
        return true;
    }

    protected void syncExec(Runnable runnable) {
        runnable.run();
    }

    /**
     * @throws UnsupportedOperationException
     */
    public void asyncExec(Runnable runnable) {
        throw new UnsupportedOperationException("asyncExec is unsupported");
    }

    /**
     * Removes the realm from being the current and sets the previous realm to the default.
     */
    public void dispose() {
        if (getDefault() == this) {
            setDefault(previousRealm);
        }
    }
}
public class SampleTestCase extends TestCase {
    private DefaultRealm realm;
    
    /**
     * Creates a new default realm for every test.
     */
    protected void setUp() throws Exception {
        super.setUp();
        realm = new DefaultRealm();
    }
    
    /**
     * Removes the default realm.
     */
    protected void tearDown() throws Exception {
        super.tearDown();
        realm.dispose();
    }
}