package org.marketcetera.photon.commons.ui.databinding;
import java.util.ArrayList;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.observable.DisposeEvent;
import org.eclipse.core.databinding.observable.IDisposeListener;
import org.eclipse.core.databinding.observable.Realm;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.marketcetera.photon.commons.Validate;
import org.marketcetera.util.misc.ClassVersion;
/* $License$ */
/**
* Utilities to proxy observables to a different realm.
*
* @author <a href="mailto:will@marketcetera.com">Will Horn</a>
* @version $Id: ProxyObservables.java 16154 2012-07-14 16:34:05Z colin $
* @since 2.0.0
*/
@ClassVersion("$Id: ProxyObservables.java 16154 2012-07-14 16:34:05Z colin $")
public class ProxyObservables {
/**
* Returns an observable list that proxies on the current realm for the list
* passed in. The original list will be returned if its realm is the current
* realm.
* <p>
* Warning! As soon as this method begins, the original list can no longer
* be disposed except on the proxy realm. If the returned proxy is disposed
* (also must be on the proxy realm), then the original list can once again
* be safely disposed in its own realm. This is an unfortunate consequence
* of the usage of a {@link DataBindingContext} which is limited in that its
* bound observables can only be disposed from its realm.
*
* @param originalList
* the list to proxy
* @return the proxy list
* @throws IllegalArgumentException
* if original is null
* @throws IllegalStateException
* if this thread has no default realm
* @throws IllegalStateException
* if the default realm is not the current realm
*/
public static IObservableList proxyList(IObservableList originalList) {
Realm realm = Realm.getDefault();
if (realm == null) {
throw new IllegalStateException(
"this method requires a default realm"); //$NON-NLS-1$
}
return proxyList(realm, originalList);
}
/**
* Returns an observable list that proxies on the given realm for the list
* passed in. The original list will be returned if its realm is the alread
* the provided realm.
* <p>
* Warning! As soon as this method begins, the original list can no longer
* be disposed except on the proxy realm. If the returned proxy is disposed
* (also must be on the proxy realm), then the original list can once again
* be safely disposed in its own realm. This is an unfortunate consequence
* of the usage of a {@link DataBindingContext} which is limited in that its
* bound observables can only be disposed from its realm.
*
* @param realm
* the realm on which to proxy
* @param originalList
* the list to proxy
* @return the proxy list
* @throws IllegalArgumentException
* if realm or original is null
* @throws IllegalStateException
* if the provided realm is not the current realm
*/
public static IObservableList proxyList(Realm realm,
final IObservableList originalList) {
Validate.notNull(realm, "realm", //$NON-NLS-1$
originalList, "originalList"); //$NON-NLS-1$
if (!realm.isCurrent()) {
throw new IllegalStateException(
"must be called from the proxy realm"); //$NON-NLS-1$
}
if (realm.equals(originalList.getRealm())) {
return originalList;
}
final WritableList list = new WritableList(realm,
new ArrayList<Object>(), originalList.getElementType());
final DataBindingContext dbc = new DataBindingContext(realm);
/*
* A dispose listener is added to the original list to clean up the
* proxy list and data binding context. But this will only work if the
* original is disposed from the proxy realm.
*/
final IDisposeListener originalDisposeListener = new IDisposeListener() {
@Override
public void handleDispose(DisposeEvent staleEvent) {
if (!list.isDisposed()) {
list.dispose();
}
}
};
originalList.addDisposeListener(originalDisposeListener);
list.addDisposeListener(new IDisposeListener() {
@Override
public void handleDispose(DisposeEvent staleEvent) {
originalList.removeDisposeListener(originalDisposeListener);
dbc.dispose();
}
});
dbc.bindList(list, originalList);
return list;
}
private ProxyObservables() {
throw new AssertionError("non-instantiable"); //$NON-NLS-1$
}
}