/* * Copyright (c) 2007-2016, 2018, 2019 Eike Stepper (Loehne, Germany) and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Eike Stepper - initial API and implementation * Simon McDuff - maintenance * Christian W. Damus - partial/conditional persistence of features */ package org.eclipse.emf.internal.cdo; import org.eclipse.emf.cdo.CDOLock; import org.eclipse.emf.cdo.CDOObject; import org.eclipse.emf.cdo.CDOObjectHistory; import org.eclipse.emf.cdo.CDOState; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.lock.CDOLockState; import org.eclipse.emf.cdo.common.model.CDOModelUtil; import org.eclipse.emf.cdo.common.model.EMFUtil; import org.eclipse.emf.cdo.common.revision.CDOList; import org.eclipse.emf.cdo.common.revision.CDORevision; import org.eclipse.emf.cdo.common.security.CDOPermission; import org.eclipse.emf.cdo.eresource.CDOResource; import org.eclipse.emf.cdo.eresource.impl.CDOResourceNodeImpl; import org.eclipse.emf.cdo.spi.common.model.InternalCDOClassInfo; import org.eclipse.emf.cdo.spi.common.model.InternalCDOClassInfo.PersistenceFilter; import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; import org.eclipse.emf.cdo.util.CDOUtil; import org.eclipse.emf.cdo.view.CDOView; import org.eclipse.emf.internal.cdo.bundle.OM; import org.eclipse.emf.internal.cdo.messages.Messages; import org.eclipse.emf.internal.cdo.object.CDOLockImpl; import org.eclipse.emf.internal.cdo.view.CDOStateMachine; import org.eclipse.net4j.util.ObjectUtil; import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; import org.eclipse.net4j.util.om.OMPlatform; import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.emf.common.notify.Adapter; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.notify.NotificationChain; import org.eclipse.emf.common.notify.Notifier; import org.eclipse.emf.common.notify.impl.BasicNotifierImpl.EObservableAdapterList.Listener; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.BasicEMap; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.EMap; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.EStructuralFeature.Internal.DynamicValueHolder; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.impl.BasicEObjectImpl; import org.eclipse.emf.ecore.impl.ENotificationImpl; import org.eclipse.emf.ecore.impl.EStoreEObjectImpl; import org.eclipse.emf.ecore.impl.EStoreEObjectImpl.BasicEStoreFeatureMap; import org.eclipse.emf.ecore.impl.MinimalEStoreEObjectImpl; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.Resource.Internal; import org.eclipse.emf.ecore.util.EcoreEMap; import org.eclipse.emf.ecore.util.FeatureMap; import org.eclipse.emf.ecore.util.FeatureMapUtil; import org.eclipse.emf.ecore.util.InternalEList; import org.eclipse.emf.spi.cdo.CDOStore; import org.eclipse.emf.spi.cdo.FSMUtil; import org.eclipse.emf.spi.cdo.InternalCDOLoadable; import org.eclipse.emf.spi.cdo.InternalCDOObject; import org.eclipse.emf.spi.cdo.InternalCDOView; import org.eclipse.emf.spi.cdo.InternalCDOView.ViewAndState; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; /** * The base class of all native {@link CDOObject objects}. * * @author Eike Stepper */ public class CDOObjectImpl extends MinimalEStoreEObjectImpl implements InternalCDOObject { private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_OBJECT, CDOObjectImpl.class); private static final EObservableAdapterList.Listener ADAPTERS_LISTENER = new EObservableAdapterList.Listener() { @Override public void added(Notifier notifier, Adapter adapter) { CDOObjectImpl object = (CDOObjectImpl)notifier; object.eAdapterAdded(adapter); } @Override public void removed(Notifier notifier, Adapter adapter) { CDOObjectImpl object = (CDOObjectImpl)notifier; object.eAdapterRemoved(adapter); } }; private static final EObservableAdapterList.Listener[] ADAPTERS_LISTENERS = { ADAPTERS_LISTENER }; private static final boolean EMF_TO_STRING = OMPlatform.INSTANCE.isProperty("org.eclipse.emf.internal.cdo.CDOObjectImpl.emfToString"); private static final boolean OPTIMIZE_UNORDERED_LISTS = OMPlatform.INSTANCE.isProperty("org.eclipse.emf.internal.cdo.CDOObjectImpl.optimizeUnorderedLists"); /** * Optimized storage of {@link CDOObject#cdoView()} and {@link CDOObject#cdoState()}. * * @see ViewAndState */ private ViewAndState viewAndState = ViewAndState.TRANSIENT; /** * Optimized storage of {@link CDOObject#cdoID()} and {@link CDOObject#cdoRevision()}. * The idea is that, if a revision is set, the object's ID is equal to the {@link CDORevision revision's} ID. * The same is true for the classInfo field. */ private InternalCDORevision revision; /** * Don't use the optional slot in MinimalEObject because a CDOObject always needs eSettings to store: *
* Feature values are actually stored in {@link CDOObjectImpl#eSettings}. * * @author Simon McDuff * @since 2.0 */ private static final class TransientStore implements InternalEObject.EStore { public static TransientStore INSTANCE = new TransientStore(); private TransientStore() { } private Object getValue(InternalEObject eObject, int transientIndex) { Object[] settings = getSettings(eObject); return settings[transientIndex]; } private EList getValueAsList(InternalEObject eObject, int transientIndex) { Object[] settings = getSettings(eObject); @SuppressWarnings("unchecked") EList result = (EList)settings[transientIndex]; if (result == null) { result = new BasicEList(); settings[transientIndex] = result; } return result; } private Object setValue(InternalEObject eObject, int transientIndex, Object newValue) { Object[] settings = getSettings(eObject); Object oldValue = settings[transientIndex]; settings[transientIndex] = newValue; return oldValue; } private Object[] getSettings(InternalEObject eObject) { CDOObjectImpl object = (CDOObjectImpl)eObject; object.eSettings(); // Ensure that the array is created return object.eSettings; } private int getTransientFeatureIndex(InternalEObject eObject, EStructuralFeature feature) { CDOObjectImpl object = (CDOObjectImpl)eObject; InternalCDOClassInfo classInfo = object.cdoClassInfo(); return classInfo.getTransientFeatureIndex(feature); } @Override public Object get(InternalEObject eObject, EStructuralFeature feature, int index) { int transientIndex = getTransientFeatureIndex(eObject, feature); if (index != NO_INDEX) { return getValueAsList(eObject, transientIndex).get(index); } return getValue(eObject, transientIndex); } @Override public Object set(InternalEObject eObject, EStructuralFeature feature, int index, Object value) { int transientIndex = getTransientFeatureIndex(eObject, feature); if (index != NO_INDEX) { return getValueAsList(eObject, transientIndex).set(index, value); } return setValue(eObject, transientIndex, value); } @Override public void add(InternalEObject eObject, EStructuralFeature feature, int index, Object value) { int transientIndex = getTransientFeatureIndex(eObject, feature); getValueAsList(eObject, transientIndex).add(index, value); } @Override public Object remove(InternalEObject eObject, EStructuralFeature feature, int index) { int transientIndex = getTransientFeatureIndex(eObject, feature); return getValueAsList(eObject, transientIndex).remove(index); } @Override public Object move(InternalEObject eObject, EStructuralFeature feature, int targetIndex, int sourceIndex) { int transientIndex = getTransientFeatureIndex(eObject, feature); return getValueAsList(eObject, transientIndex).move(targetIndex, sourceIndex); } @Override public void clear(InternalEObject eObject, EStructuralFeature feature) { int transientIndex = getTransientFeatureIndex(eObject, feature); if (feature.isMany()) { getValueAsList(eObject, transientIndex).clear(); } setValue(eObject, transientIndex, null); } @Override public int size(InternalEObject eObject, EStructuralFeature feature) { int transientIndex = getTransientFeatureIndex(eObject, feature); return getValueAsList(eObject, transientIndex).size(); } @Override public int indexOf(InternalEObject eObject, EStructuralFeature feature, Object value) { int transientIndex = getTransientFeatureIndex(eObject, feature); return getValueAsList(eObject, transientIndex).indexOf(value); } @Override public int lastIndexOf(InternalEObject eObject, EStructuralFeature feature, Object value) { int transientIndex = getTransientFeatureIndex(eObject, feature); return getValueAsList(eObject, transientIndex).lastIndexOf(value); } @Override public Object[] toArray(InternalEObject eObject, EStructuralFeature feature) { int transientIndex = getTransientFeatureIndex(eObject, feature); return getValueAsList(eObject, transientIndex).toArray(); } @Override public T[] toArray(InternalEObject eObject, EStructuralFeature feature, T[] array) { int transientIndex = getTransientFeatureIndex(eObject, feature); return getValueAsList(eObject, transientIndex).toArray(array); } @Override public boolean isEmpty(InternalEObject eObject, EStructuralFeature feature) { int transientIndex = getTransientFeatureIndex(eObject, feature); return getValueAsList(eObject, transientIndex).isEmpty(); } @Override public boolean contains(InternalEObject eObject, EStructuralFeature feature, Object value) { int transientIndex = getTransientFeatureIndex(eObject, feature); return getValueAsList(eObject, transientIndex).contains(value); } @Override public int hashCode(InternalEObject eObject, EStructuralFeature feature) { int transientIndex = getTransientFeatureIndex(eObject, feature); return getValueAsList(eObject, transientIndex).hashCode(); } @Override public InternalEObject getContainer(InternalEObject eObject) { return null; } @Override public EStructuralFeature getContainingFeature(InternalEObject eObject) { throw new UnsupportedOperationException("Should never be called"); } @Override public EObject create(EClass eClass) { throw new UnsupportedOperationException("Should never be called"); } @Override public boolean isSet(InternalEObject eObject, EStructuralFeature feature) { if (!feature.isUnsettable()) { if (feature.isMany()) { @SuppressWarnings("unchecked") List list = (InternalEList)eObject.eGet(feature, false); return list != null && !list.isEmpty(); } return !ObjectUtil.equals(eObject.eGet(feature, false), feature.getDefaultValue()); } Object[] settings = ((CDOObjectImpl)eObject).eSettings; if (settings == null) { return false; } int transientIndex = getTransientFeatureIndex(eObject, feature); return settings[transientIndex] != null; } @Override public void unset(InternalEObject eObject, EStructuralFeature feature) { CDOObjectImpl cdoObject = (CDOObjectImpl)eObject; if (feature.isMany()) { // Object object = get(eObject, feature, NO_INDEX); Object object = cdoObject.eGet(feature, false); if (object instanceof List>) { List> list = (List>)object; list.clear(); } } else { Object[] settings = cdoObject.eSettings; if (settings == null) { // Is already unset return; } int transientIndex = getTransientFeatureIndex(eObject, feature); settings[transientIndex] = null; } } } /** * For internal use only. * * @author Eike Stepper * @since 4.1 */ private final class CDOStoreEcoreEMap extends EcoreEMap implements InternalCDOLoadable { private static final long serialVersionUID = 1L; public CDOStoreEcoreEMap(EStructuralFeature eStructuralFeature) { super((EClass)eStructuralFeature.getEType(), BasicEMap.Entry.class, null); delegateEList = new EStoreEObjectImpl.BasicEStoreEList>(CDOObjectImpl.this, eStructuralFeature) { private static final long serialVersionUID = 1L; // { // ensureEntryDataExists(); // } @Override public void unset() { super.unset(); doClear(); } @Override protected void didAdd(int index, BasicEMap.Entry newObject) { CDOStoreEcoreEMap.this.doPut(newObject); } @Override protected void didSet(int index, BasicEMap.Entry newObject, BasicEMap.Entry oldObject) { didRemove(index, oldObject); didAdd(index, newObject); } @Override protected void didRemove(int index, BasicEMap.Entry oldObject) { CDOStoreEcoreEMap.this.doRemove(oldObject); } @Override protected void didClear(int size, Object[] oldObjects) { CDOStoreEcoreEMap.this.doClear(); // ensureEntryDataExists(); } @Override protected void didMove(int index, BasicEMap.Entry movedObject, int oldIndex) { CDOStoreEcoreEMap.this.doMove(movedObject); } }; size = delegateEList.size(); } private void checkListForReading() { if (!FSMUtil.isTransient(CDOObjectImpl.this)) { CDOStateMachine.INSTANCE.read(CDOObjectImpl.this); } } /** * Ensures that the entry data is created and is populated with contents of the delegate list. */ @Override protected synchronized void ensureEntryDataExists() { checkListForReading(); super.ensureEntryDataExists(); } @Override public NotificationChain basicRemove(Object object, NotificationChain notifications) { InternalCDOView view = viewAndState.view; if (view == null) { return super.basicRemove(object, notifications); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.basicRemove(object, notifications); } finally { view.lockView(); } } } @Override public NotificationChain basicAdd(Map.Entry object, NotificationChain notifications) { InternalCDOView view = viewAndState.view; if (view == null) { return super.basicAdd(object, notifications); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.basicAdd(object, notifications); } finally { view.lockView(); } } } @Override public void addUnique(Map.Entry object) { InternalCDOView view = viewAndState.view; if (view == null) { super.addUnique(object); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.addUnique(object); } finally { view.lockView(); } } } @Override public void addUnique(int index, Map.Entry object) { InternalCDOView view = viewAndState.view; if (view == null) { super.addUnique(index, object); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.addUnique(index, object); } finally { view.lockView(); } } } @Override public boolean addAllUnique(Collection extends Map.Entry> collection) { InternalCDOView view = viewAndState.view; if (view == null) { return super.addAllUnique(collection); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.addAllUnique(collection); } finally { view.lockView(); } } } @Override public boolean addAllUnique(int index, Collection extends Map.Entry> collection) { InternalCDOView view = viewAndState.view; if (view == null) { return super.addAllUnique(index, collection); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.addAllUnique(index, collection); } finally { view.lockView(); } } } @Override public Map.Entry setUnique(int index, Map.Entry object) { InternalCDOView view = viewAndState.view; if (view == null) { return super.setUnique(index, object); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.setUnique(index, object); } finally { view.lockView(); } } } @Override public void set(Object value) { InternalCDOView view = viewAndState.view; if (view == null) { super.set(value); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.set(value); } finally { view.lockView(); } } } @Override public void unset() { InternalCDOView view = viewAndState.view; if (view == null) { super.unset(); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.unset(); } finally { view.lockView(); } } } @Override public Object put(Object key, Object value) { InternalCDOView view = viewAndState.view; if (view == null) { return super.put(key, value); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.put(key, value); } finally { view.lockView(); } } } @Override public Object removeKey(Object key) { InternalCDOView view = viewAndState.view; if (view == null) { return super.removeKey(key); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.removeKey(key); } finally { view.lockView(); } } } @Override public void putAll(Map extends Object, ? extends Object> map) { InternalCDOView view = viewAndState.view; if (view == null) { super.putAll(map); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.putAll(map); } finally { view.lockView(); } } } @Override public void putAll(EMap extends Object, ? extends Object> map) { InternalCDOView view = viewAndState.view; if (view == null) { super.putAll(map); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.putAll(map); } finally { view.lockView(); } } } @Override public Map.Entry set(int index, Map.Entry object) { InternalCDOView view = viewAndState.view; if (view == null) { return super.set(index, object); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.set(index, object); } finally { view.lockView(); } } } @Override public boolean add(Map.Entry object) { InternalCDOView view = viewAndState.view; if (view == null) { return super.add(object); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.add(object); } finally { view.lockView(); } } } @Override public void add(int index, Map.Entry object) { InternalCDOView view = viewAndState.view; if (view == null) { super.add(index, object); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.add(index, object); } finally { view.lockView(); } } } @Override public boolean addAll(Collection extends Map.Entry> collection) { InternalCDOView view = viewAndState.view; if (view == null) { return super.addAll(collection); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.addAll(collection); } finally { view.lockView(); } } } @Override public boolean addAll(int index, Collection extends Map.Entry> collection) { InternalCDOView view = viewAndState.view; if (view == null) { return super.addAll(index, collection); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.addAll(index, collection); } finally { view.lockView(); } } } @Override public boolean remove(Object object) { InternalCDOView view = viewAndState.view; if (view == null) { return super.remove(object); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.remove(object); } finally { view.lockView(); } } } @Override public boolean removeAll(Collection> collection) { InternalCDOView view = viewAndState.view; if (view == null) { return super.removeAll(collection); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.removeAll(collection); } finally { view.lockView(); } } } @Override public Map.Entry remove(int index) { InternalCDOView view = viewAndState.view; if (view == null) { return super.remove(index); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.remove(index); } finally { view.lockView(); } } } @Override public boolean retainAll(Collection> collection) { InternalCDOView view = viewAndState.view; if (view == null) { return super.retainAll(collection); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.retainAll(collection); } finally { view.lockView(); } } } @Override public void clear() { InternalCDOView view = viewAndState.view; if (view == null) { super.clear(); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.clear(); } finally { view.lockView(); } } } @Override public void move(int index, Map.Entry object) { InternalCDOView view = viewAndState.view; if (view == null) { super.move(index, object); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.move(index, object); } finally { view.lockView(); } } } @Override public Map.Entry move(int targetIndex, int sourceIndex) { InternalCDOView view = viewAndState.view; if (view == null) { return super.move(targetIndex, sourceIndex); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.move(targetIndex, sourceIndex); } finally { view.lockView(); } } } @Override public int size() { checkListForReading(); return size; } @Override public boolean isEmpty() { checkListForReading(); return size == 0; } @Override public boolean contains(Object object) { checkListForReading(); return super.contains(object); } @Override public boolean containsAll(Collection> collection) { checkListForReading(); return super.containsAll(collection); } @Override public boolean containsKey(Object key) { checkListForReading(); return super.containsKey(key); } @Override public boolean containsValue(Object value) { checkListForReading(); return super.containsValue(value); } @Override public void cdoInternalPreLoad() { } @Override public void cdoInternalPostLoad() { entryData = null; size = delegateEList.size(); } } /** * @author Eike Stepper */ private class CDOStoreEList extends EStoreEObjectImpl.BasicEStoreEList { private static final long serialVersionUID = 1L; private CDOStoreEList(InternalEObject owner, EStructuralFeature eStructuralFeature) { super(owner, eStructuralFeature); } @Override public void unset() { InternalCDOView view = viewAndState.view; if (view == null) { super.unset(); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.unset(); } finally { view.lockView(); } } } @Override public NotificationChain inverseAdd(Object object, NotificationChain notifications) { InternalCDOView view = viewAndState.view; if (view == null) { return super.inverseAdd(object, notifications); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.inverseAdd(object, notifications); } finally { view.lockView(); } } } @Override public NotificationChain inverseRemove(Object object, NotificationChain notifications) { InternalCDOView view = viewAndState.view; if (view == null) { return super.inverseRemove(object, notifications); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.inverseRemove(object, notifications); } finally { view.lockView(); } } } @Override public void set(Object newValue) { InternalCDOView view = viewAndState.view; if (view == null) { super.set(newValue); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.set(newValue); } finally { view.lockView(); } } } @Override public void addUnique(Object object) { InternalCDOView view = viewAndState.view; if (view == null) { super.addUnique(object); return; } Object viewMonitor = view.getViewMonitor(); synchronized (viewMonitor) { view.lockView(); try { super.addUnique(object); } finally { view.lockView(); } } } @Override public void addUnique(int index, Object object) { InternalCDOView view = viewAndState.view; if (view == null) { super.addUnique(index, object); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.addUnique(index, object); } finally { view.lockView(); } } } @Override public boolean addAllUnique(Collection extends Object> collection) { InternalCDOView view = viewAndState.view; if (view == null) { return super.addAllUnique(collection); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.addAllUnique(collection); } finally { view.lockView(); } } } @Override public boolean addAllUnique(int index, Collection extends Object> collection) { InternalCDOView view = viewAndState.view; if (view == null) { return super.addAllUnique(index, collection); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.addAllUnique(index, collection); } finally { view.lockView(); } } } @Override public boolean addAllUnique(Object[] objects, int start, int end) { InternalCDOView view = viewAndState.view; if (view == null) { return super.addAllUnique(objects, start, end); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.addAllUnique(objects, start, end); } finally { view.lockView(); } } } @Override public boolean addAllUnique(int index, Object[] objects, int start, int end) { InternalCDOView view = viewAndState.view; if (view == null) { return super.addAllUnique(index, objects, start, end); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.addAllUnique(index, objects, start, end); } finally { view.lockView(); } } } @Override public NotificationChain basicAdd(Object object, NotificationChain notifications) { InternalCDOView view = viewAndState.view; if (view == null) { return super.basicAdd(object, notifications); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.basicAdd(object, notifications); } finally { view.lockView(); } } } @Override public Object remove(int index) { InternalCDOView view = viewAndState.view; if (view == null) { return super.remove(index); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.remove(index); } finally { view.lockView(); } } } @Override public boolean removeAll(Collection> collection) { InternalCDOView view = viewAndState.view; if (view == null) { return super.removeAll(collection); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.removeAll(collection); } finally { view.lockView(); } } } @Override public NotificationChain basicRemove(Object object, NotificationChain notifications) { InternalCDOView view = viewAndState.view; if (view == null) { return super.basicRemove(object, notifications); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.basicRemove(object, notifications); } finally { view.lockView(); } } } @Override public void clear() { InternalCDOView view = viewAndState.view; if (view == null) { super.clear(); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.clear(); } finally { view.lockView(); } } } @Override public Object setUnique(int index, Object object) { InternalCDOView view = viewAndState.view; if (view == null) { return super.setUnique(index, object); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.setUnique(index, object); } finally { view.lockView(); } } } @Override public NotificationChain basicSet(int index, Object object, NotificationChain notifications) { InternalCDOView view = viewAndState.view; if (view == null) { return super.basicSet(index, object, notifications); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.basicSet(index, object, notifications); } finally { view.lockView(); } } } @Override public Object move(int targetIndex, int sourceIndex) { InternalCDOView view = viewAndState.view; if (view == null) { return super.move(targetIndex, sourceIndex); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.move(targetIndex, sourceIndex); } finally { view.lockView(); } } } @Override public boolean remove(Object object) { InternalCDOView view = viewAndState.view; if (view == null) { return super.remove(object); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.remove(object); } finally { view.lockView(); } } } @Override public boolean retainAll(Collection> collection) { InternalCDOView view = viewAndState.view; if (view == null) { return super.retainAll(collection); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.retainAll(collection); } finally { view.lockView(); } } } @Override public Object set(int index, Object object) { InternalCDOView view = viewAndState.view; if (view == null) { return super.set(index, object); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.set(index, object); } finally { view.lockView(); } } } @Override public boolean add(Object object) { InternalCDOView view = viewAndState.view; if (view == null) { return super.add(object); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.add(object); } finally { view.lockView(); } } } @Override public void add(int index, Object object) { InternalCDOView view = viewAndState.view; if (view == null) { super.add(index, object); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.add(index, object); } finally { view.lockView(); } } } @Override public boolean addAll(Collection extends Object> collection) { InternalCDOView view = viewAndState.view; if (view == null) { return super.addAll(collection); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.addAll(collection); } finally { view.lockView(); } } } @Override public boolean addAll(int index, Collection extends Object> collection) { InternalCDOView view = viewAndState.view; if (view == null) { return super.addAll(index, collection); } synchronized (view.getViewMonitor()) { view.lockView(); try { return super.addAll(index, collection); } finally { view.lockView(); } } } @Override public void move(int index, Object object) { InternalCDOView view = viewAndState.view; if (view == null) { super.move(index, object); return; } synchronized (view.getViewMonitor()) { view.lockView(); try { super.move(index, object); } finally { view.lockView(); } } } } /** * For internal use only. * * @author Andras Peteri * @since 4.1 */ private final class CDOStoreUnorderedEList extends CDOStoreEList { private static final long serialVersionUID = 1L; public CDOStoreUnorderedEList(EStructuralFeature feature) { super(CDOObjectImpl.this, feature); } @Override public E remove(int index) { InternalCDOView view = viewAndState.view; if (view == null) { return internalRemove(index); } synchronized (view.getViewMonitor()) { view.lockView(); try { return internalRemove(index); } finally { view.lockView(); } } } private E internalRemove(int index) { boolean oldObjectIsLast = index == size() - 1; @SuppressWarnings("unchecked") E oldObject = (E)super.remove(index); if (!oldObjectIsLast) { move(index, size() - 1); } return oldObject; } } /** * For internal use only. * * @author Eike Stepper */ private final class CDOStoreFeatureMap extends BasicEStoreFeatureMap { private static final long serialVersionUID = 1L; public CDOStoreFeatureMap(EStructuralFeature eStructuralFeature) { super(CDOObjectImpl.this, eStructuralFeature); } } }