package org.marketcetera.photon.internal.marketdata; import java.util.ArrayList; import java.util.Iterator; import java.util.ListIterator; import java.util.concurrent.Callable; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.util.EObjectContainmentEList; import org.marketcetera.util.misc.ClassVersion; /* $License$ */ /** * Provides an <code>EList</code> implementation that provides limited concurrent-safe operations. * * <p>This collection provides concurrent-safe <code>Iterator</code> operations: * <ul> * <li>{@link #basicIterator()}</li> * <li>{@link #basicListIterator()</li> * <li>{@link #basicListIterator(int)</li> * <li>{@link #iterator()</li> * <li>{@link #listIterator()</li> * <li>{@link #listIterator(int)</li> * </ul></p> * * <p>These iterator operations provide a snapshot of the collection contents upon invocation. * It is safe to traverse these iterators regardless of modifications to the original list. * Operations conducted using the iterators, however, will not be reflected in the original list.</p> * * <p>Callers must execute operations on this list using the provided {@link #doWriteOperation(Callable)} and * {@link #doReadOperation(Callable)} methods. Note that intrinsic list operations not covered in the list above * are not guaranteed to be concurrent. Such list operations must be manually locked using one of the lock * operation methods. * * @author <a href="mailto:colin@marketcetera.com">Colin DuPlantis</a> * @version $Id: EObjectLockableCopyOnReadContainmentEList.java 16154 2012-07-14 16:34:05Z colin $ * @since 2.2.0 */ @ClassVersion("$Id: EObjectLockableCopyOnReadContainmentEList.java 16154 2012-07-14 16:34:05Z colin $") public class EObjectLockableCopyOnReadContainmentEList<E> extends EObjectContainmentEList<E> implements LockableEList<E> { /** * Create a new EObjectCopyOnReadContainmentEList instance. * * @param inDataClass a <code>Class<E></code> value * @param inOwner an <code>InternalEObject</code> value * @param inFeatureID an <code>int</code> value */ public EObjectLockableCopyOnReadContainmentEList(Class<E> inDataClass, InternalEObject inOwner, int inFeatureID) { super(inDataClass, inOwner, inFeatureID); } /* (non-Javadoc) * @see org.eclipse.emf.ecore.util.NotifyingInternalEListImpl#basicIterator() */ @Override public Iterator<E> basicIterator() { return doReadOperation(new Callable<Iterator<E>>() { @Override public Iterator<E> call() throws Exception { return new ArrayList<E>(EObjectLockableCopyOnReadContainmentEList.this).iterator(); } }); } /* (non-Javadoc) * @see org.eclipse.emf.ecore.util.NotifyingInternalEListImpl#basicListIterator() */ @Override public ListIterator<E> basicListIterator() { return doReadOperation(new Callable<ListIterator<E>>() { @Override public ListIterator<E> call() throws Exception { return new ArrayList<E>(EObjectLockableCopyOnReadContainmentEList.this).listIterator(); } }); } /* (non-Javadoc) * @see org.eclipse.emf.ecore.util.NotifyingInternalEListImpl#basicListIterator(int) */ @Override public ListIterator<E> basicListIterator(final int inIndex) { return doReadOperation(new Callable<ListIterator<E>>() { @Override public ListIterator<E> call() throws Exception { return new ArrayList<E>(EObjectLockableCopyOnReadContainmentEList.this).listIterator(inIndex); } }); } /* (non-Javadoc) * @see org.eclipse.emf.common.util.AbstractEList#iterator() */ @Override public Iterator<E> iterator() { return doReadOperation(new Callable<Iterator<E>>() { @Override public Iterator<E> call() throws Exception { return new ArrayList<E>(EObjectLockableCopyOnReadContainmentEList.this).iterator(); } }); } /* (non-Javadoc) * @see org.eclipse.emf.common.util.AbstractEList#listIterator() */ @Override public ListIterator<E> listIterator() { return doReadOperation(new Callable<ListIterator<E>>() { @Override public ListIterator<E> call() throws Exception { return new ArrayList<E>(EObjectLockableCopyOnReadContainmentEList.this).listIterator(); } }); } /* (non-Javadoc) * @see org.eclipse.emf.common.util.AbstractEList#listIterator(int) */ @Override public ListIterator<E> listIterator(final int inIndex) { return doReadOperation(new Callable<ListIterator<E>>() { @Override public ListIterator<E> call() throws Exception { return new ArrayList<E>(EObjectLockableCopyOnReadContainmentEList.this).listIterator(inIndex); } }); } /* (non-Javadoc) * @see org.marketcetera.photon.internal.marketdata.LockableEList#doReadOperation(java.util.concurrent.Callable) */ @Override public <T> T doReadOperation(Callable<T> inOperation) { Lock iteratorLock = lock.readLock(); boolean locked = false; try { iteratorLock.lockInterruptibly(); locked = true; return inOperation.call(); } catch (Exception e) { throw new RuntimeException(e); } finally { if(locked) { iteratorLock.unlock(); } } } /* (non-Javadoc) * @see org.marketcetera.photon.internal.marketdata.LockableEList#doWriteOperation(java.util.concurrent.Callable) */ @Override public <T> T doWriteOperation(Callable<T> inOperation) { Lock iteratorLock = lock.writeLock(); boolean locked = false; try { iteratorLock.lockInterruptibly(); locked = true; return inOperation.call(); } catch (Exception e) { throw new RuntimeException(e); } finally { if(locked) { iteratorLock.unlock(); } } } /** * lock used to guard access */ private final ReadWriteLock lock = new ReentrantReadWriteLock(); private static final long serialVersionUID = 1L; }