package org.marketcetera.photon.strategy.engine.ui;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.core.databinding.observable.Observables;
import org.eclipse.core.databinding.observable.list.IObservableList;
import org.eclipse.core.databinding.observable.list.WritableList;
import org.eclipse.swt.widgets.Display;
import org.marketcetera.photon.commons.Validate;
import org.marketcetera.photon.commons.ui.DisplayThreadExecutor;
import org.marketcetera.photon.commons.ui.SWTUtils;
import org.marketcetera.photon.strategy.engine.IStrategyEngines;
import org.marketcetera.photon.strategy.engine.model.core.StrategyEngine;
import org.marketcetera.util.misc.ClassVersion;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceException;
import org.osgi.framework.ServiceRegistration;
/* $License$ */
/**
* Convenience base class for bundles that provide a {@link IStrategyEngines}
* service. The service is confined to the thread on which this object was
* constructed. The service is registered by {@link #init(BundleContext)}.
*
* @author <a href="mailto:will@marketcetera.com">Will Horn</a>
* @version $Id: AbstractStrategyEnginesSupport.java 16154 2012-07-14 16:34:05Z colin $
* @since 2.0.0
*/
@ClassVersion("$Id: AbstractStrategyEnginesSupport.java 16154 2012-07-14 16:34:05Z colin $")
public abstract class AbstractStrategyEnginesSupport {
private ExecutorService mGuiExecutor;
private WritableList mEngines;
private ServiceRegistration mRegistration;
private final AtomicBoolean mDisposed = new AtomicBoolean();
/**
* Initializes the service. Must only be called once.
*
* @param context
* the context with which to register the service
* @throws IllegalArgumentException
* if context is null
* @throws IllegalStateException
* if called from a non UI thread
*/
public final void init(BundleContext context) {
Validate.notNull(context, "context"); //$NON-NLS-1$
SWTUtils.checkThread();
mGuiExecutor = DisplayThreadExecutor.getInstance(Display.getCurrent());
mEngines = WritableList.withElementType(StrategyEngine.class);
initList(getGenericEngines());
mRegistration = context.registerService(IStrategyEngines.class
.getName(), new IStrategyEngines() {
@Override
public IObservableList getStrategyEngines() throws ServiceException {
SWTUtils.checkThread();
checkDisposed();
return Observables.unmodifiableObservableList(mEngines);
}
@Override
public StrategyEngine addEngine(final StrategyEngine engine) {
Validate.notNull(engine, "engine"); //$NON-NLS-1$
SWTUtils.checkThread();
checkDisposed();
return doAddEngine(getGenericEngines(), engine);
}
@Override
public void removeEngine(final StrategyEngine engine) {
Validate.notNull(engine, "engine"); //$NON-NLS-1$
SWTUtils.checkThread();
checkDisposed();
doRemoveEngine(getGenericEngines(), engine);
}
}, null);
}
/**
* Returns the list of engines.
*
* @return the list of engines
*/
@SuppressWarnings("unchecked")
protected final List<StrategyEngine> getGenericEngines() {
/*
* This is for convenience and safety. WritableList is not generic, but
* mEngines must only contain StrategyEngine objects.
*/
return mEngines;
}
private void checkDisposed() throws IllegalStateException {
if (mDisposed.get()) {
throw new IllegalStateException(
Messages.ABSTRACT_STRATEGY_ENGINES_SUPPORT_SERVICE_NOT_AVAILABLE
.getText());
}
}
/**
* Returns the executor that can be used to safely update the model backing
* the service.
*
* @return the executor service
*/
protected final ExecutorService getGuiExecutor() {
return mGuiExecutor;
}
/**
* Initialize the list of engines after it has been created but before the
* service has been registered.
* <p>
* Must be called from the UI thread for the model
*
* @param engines
* the list of engines
*/
protected void initList(List<StrategyEngine> engines) {
}
/**
* Adds an engine to the list of engines.
* <p>
* Must be called from the UI thread of the model.
*
* @param engines
* the list of engines
* @param engine
* the new engine to add
* @return the engine that was added, not necessarily the engine passed in
*/
protected abstract StrategyEngine doAddEngine(List<StrategyEngine> engines,
final StrategyEngine engine);
/**
* Removes an engine from the list of engines.
* <p>
* Must be called from the UI thread of the model.
*
* @param engines
* the list of engines
* @param engine
* the new engine to add
*/
protected abstract void doRemoveEngine(List<StrategyEngine> engines,
final StrategyEngine engine);
/**
* Unregisters the service and cleans up the model, after which this object
* should no longer be used.
*/
public final void dispose() {
if (mDisposed.compareAndSet(false, true)) {
mRegistration.unregister();
mEngines.dispose();
}
}
}