/** * Copyright (c) 2002-2006 IBM Corporation 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: * IBM - Initial API and implementation */ package org.eclipse.emf.ecore.impl; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import org.eclipse.emf.common.notify.Notification; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.BasicEMap; import org.eclipse.emf.common.util.ECollections; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.util.DelegatingEcoreEList; import org.eclipse.emf.ecore.util.DelegatingFeatureMap; import org.eclipse.emf.ecore.util.EcoreEList; import org.eclipse.emf.ecore.util.EcoreEMap; import org.eclipse.emf.ecore.util.FeatureMap; import org.eclipse.emf.ecore.util.FeatureMapUtil; /** * An implementation of '<em><b>EObject</b></em>' that delegates to a {@link org.eclipse.emf.ecore.InternalEObject.EStore store}. */ public class EStoreEObjectImpl extends EObjectImpl implements EStructuralFeature.Internal.DynamicValueHolder { /** * An internal class for holding less frequently members variables. */ protected static class EStoreEPropertiesHolderImpl implements BasicEObjectImpl.EPropertiesHolder { protected EClass eClass; protected URI eProxyURI; protected Resource.Internal eResource; protected EList<EObject> eContents; protected EList<EObject> eCrossReferences; public EClass getEClass() { return eClass; } public void setEClass(EClass eClass) { this.eClass = eClass; } public URI getEProxyURI() { return eProxyURI; } public void setEProxyURI(URI eProxyURI) { this.eProxyURI = eProxyURI; } public Resource.Internal getEResource() { return eResource; } public void setEResource(Resource.Internal eResource) { this.eResource = eResource; } public EList<EObject> getEContents() { return eContents; } public void setEContents(EList<EObject> eContents) { this.eContents = eContents; } public EList<EObject> getECrossReferences() { return eCrossReferences; } public void setECrossReferences(EList<EObject> eCrossReferences) { this.eCrossReferences = eCrossReferences; } public boolean hasSettings() { throw new UnsupportedOperationException(); } public void allocateSettings(int maximumDynamicFeatureID) { throw new UnsupportedOperationException(); } public Object dynamicGet(int dynamicFeatureID) { throw new UnsupportedOperationException(); } public void dynamicSet(int dynamicFeatureID, Object value) { throw new UnsupportedOperationException(); } public void dynamicUnset(int dynamicFeatureID) { throw new UnsupportedOperationException(); } } /** * A list that delegates to a store. * @since 2.4 */ public static class BasicEStoreEList<E> extends DelegatingEcoreEList.Dynamic<E> { private static final long serialVersionUID = 1L; public BasicEStoreEList(InternalEObject owner, EStructuralFeature eStructuralFeature) { super(owner, eStructuralFeature); } protected EStore eStore() { return owner.eStore(); } @Override public boolean isSet() { return eStore().isSet(owner, eStructuralFeature); } @Override public void unset() { if (isUnsettable() && isNotificationRequired()) { boolean oldIsSet = isSet(); eStore().unset(owner, eStructuralFeature); dispatchNotification(createNotification(Notification.UNSET, oldIsSet, false)); } else { eStore().unset(owner, eStructuralFeature); } } @Override protected List<E> delegateList() { throw new UnsupportedOperationException(); } @Override public EStructuralFeature getEStructuralFeature() { return eStructuralFeature; } @Override protected void delegateAdd(int index, Object object) { eStore().add(owner, eStructuralFeature, index, object); } @Override protected void delegateAdd(Object object) { delegateAdd(delegateSize(), object); } @Override protected List<E> delegateBasicList() { int size = delegateSize(); if (size == 0) { return ECollections.emptyEList(); } else { Object[] data = eStore().toArray(owner, eStructuralFeature); return new EcoreEList.UnmodifiableEList<E>(owner, eStructuralFeature, data.length, data); } } @Override protected void delegateClear() { eStore().clear(owner, eStructuralFeature); } @Override protected boolean delegateContains(Object object) { return eStore().contains(owner, eStructuralFeature, object); } @Override protected boolean delegateContainsAll(Collection<?> collection) { for (Object o : collection) { if (!delegateContains(o)) { return false; } } return true; } @SuppressWarnings("unchecked") @Override protected E delegateGet(int index) { return (E)eStore().get(owner, eStructuralFeature, index); } @Override protected int delegateHashCode() { return eStore().hashCode(owner, eStructuralFeature); } @Override protected int delegateIndexOf(Object object) { return eStore().indexOf(owner, eStructuralFeature, object); } @Override protected boolean delegateIsEmpty() { return eStore().isEmpty(owner, eStructuralFeature); } @Override protected Iterator<E> delegateIterator() { return iterator(); } @Override protected int delegateLastIndexOf(Object object) { return eStore().lastIndexOf(owner, eStructuralFeature, object); } @Override protected ListIterator<E> delegateListIterator() { return listIterator(); } @SuppressWarnings("unchecked") @Override protected E delegateRemove(int index) { return (E)eStore().remove(owner, eStructuralFeature, index); } @SuppressWarnings("unchecked") @Override protected E delegateSet(int index, E object) { return (E)eStore().set(owner, eStructuralFeature, index, object); } @Override protected int delegateSize() { return eStore().size(owner, eStructuralFeature); } @Override protected Object[] delegateToArray() { return eStore().toArray(owner, eStructuralFeature); } @Override protected <T> T[] delegateToArray(T[] array) { return eStore().toArray(owner, eStructuralFeature, array); } @SuppressWarnings("unchecked") @Override protected E delegateMove(int targetIndex, int sourceIndex) { return (E)eStore().move(owner, eStructuralFeature, targetIndex, sourceIndex); } @Override protected boolean delegateEquals(Object object) { if (object == this) { return true; } if (!(object instanceof List<?>)) { return false; } List<?> list = (List<?>)object; if (list.size() != delegateSize()) { return false; } for (ListIterator<?> i = list.listIterator(); i.hasNext(); ) { Object element= i.next(); if (element == null ? get(i.previousIndex()) != null : !element.equals(get(i.previousIndex()))) { return false; } } return true; } @Override protected String delegateToString() { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("["); for (int i = 0, size = size(); i < size; ) { Object value = delegateGet(i); stringBuffer.append(String.valueOf(value)); if (++i < size) { stringBuffer.append(", "); } } stringBuffer.append("]"); return stringBuffer.toString(); } } /** * A list that delegates to a store. */ public static class EStoreEList<E> extends BasicEStoreEList<E> { private static final long serialVersionUID = 1L; protected InternalEObject.EStore store; public EStoreEList(InternalEObject owner, EStructuralFeature eStructuralFeature, InternalEObject.EStore store) { super(owner, eStructuralFeature); this.store = store; } @Override protected final EStore eStore() { return store; } } /** * A feature map that delegates to a store. * @since 2.4 */ public static class BasicEStoreFeatureMap extends DelegatingFeatureMap { private static final long serialVersionUID = 1L; public BasicEStoreFeatureMap(InternalEObject owner, EStructuralFeature eStructuralFeature) { super(owner, eStructuralFeature); } protected EStore eStore() { return owner.eStore(); } @Override protected List<FeatureMap.Entry> delegateList() { throw new UnsupportedOperationException(); } @Override public EStructuralFeature getEStructuralFeature() { return eStructuralFeature; } @Override protected void delegateAdd(int index, Entry object) { eStore().add(owner, eStructuralFeature, index, object); } @Override protected void delegateAdd(Entry object) { delegateAdd(delegateSize(), object); } @Override protected List<FeatureMap.Entry> delegateBasicList() { int size = delegateSize(); if (size == 0) { return ECollections.emptyEList(); } else { Object[] data = eStore().toArray(owner, eStructuralFeature); return new EcoreEList.UnmodifiableEList<FeatureMap.Entry>(owner, eStructuralFeature, data.length, data); } } @Override protected void delegateClear() { eStore().clear(owner, eStructuralFeature); } @Override protected boolean delegateContains(Object object) { return eStore().contains(owner, eStructuralFeature, object); } @Override protected boolean delegateContainsAll(Collection<?> collection) { for (Object o : collection) { if (!delegateContains(o)) { return false; } } return true; } @Override protected Entry delegateGet(int index) { return (Entry)eStore().get(owner, eStructuralFeature, index); } @Override protected int delegateHashCode() { return eStore().hashCode(owner, eStructuralFeature); } @Override protected int delegateIndexOf(Object object) { return eStore().indexOf(owner, eStructuralFeature, object); } @Override protected boolean delegateIsEmpty() { return eStore().isEmpty(owner, eStructuralFeature); } @Override protected Iterator<FeatureMap.Entry> delegateIterator() { return iterator(); } @Override protected int delegateLastIndexOf(Object object) { return eStore().lastIndexOf(owner, eStructuralFeature, object); } @Override protected ListIterator<FeatureMap.Entry> delegateListIterator() { return listIterator(); } @Override protected Entry delegateRemove(int index) { return (Entry)eStore().remove(owner, eStructuralFeature, index); } @Override protected Entry delegateSet(int index, Entry object) { return (Entry)eStore().set(owner, eStructuralFeature, index, object); } @Override protected int delegateSize() { return eStore().size(owner, eStructuralFeature); } @Override protected Object[] delegateToArray() { return eStore().toArray(owner, eStructuralFeature); } @Override protected <T> T[] delegateToArray(T[] array) { return eStore().toArray(owner, eStructuralFeature, array); } @Override protected Entry delegateMove(int targetIndex, int sourceIndex) { return (Entry)eStore().move(owner, eStructuralFeature, targetIndex, sourceIndex); } @Override protected String delegateToString() { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append("["); for (int i = 0, size = size(); i < size; ) { Object value = delegateGet(i); stringBuffer.append(String.valueOf(value)); if (++i < size) { stringBuffer.append(", "); } } stringBuffer.append("]"); return stringBuffer.toString(); } } /** * A feature map that delegates to a store. */ public static class EStoreFeatureMap extends BasicEStoreFeatureMap { private static final long serialVersionUID = 1L; protected final InternalEObject.EStore store; public EStoreFeatureMap(InternalEObject owner, EStructuralFeature eStructuralFeature, InternalEObject.EStore store) { super(owner, eStructuralFeature); this.store = store; } @Override protected EStore eStore() { return store; } } protected static final Object [] ENO_SETTINGS = new Object [0]; protected static final InternalEObject EUNINITIALIZED_CONTAINER = new EObjectImpl(); protected Object [] eSettings; protected InternalEObject.EStore eStore; /** * Creates a store-based EObject. */ public EStoreEObjectImpl() { super(); eContainer = EUNINITIALIZED_CONTAINER; } /** * Creates a store-based EObject. */ public EStoreEObjectImpl(InternalEObject.EStore eStore) { super(); eSetStore(eStore); eContainer = EUNINITIALIZED_CONTAINER; } /** * Creates a store-based EObject. */ public EStoreEObjectImpl(EClass eClass) { super(); eSetClass(eClass); eContainer = EUNINITIALIZED_CONTAINER; } /** * Creates a store-based EObject. */ public EStoreEObjectImpl(EClass eClass, InternalEObject.EStore eStore) { super(); eSetClass(eClass); eSetStore(eStore); eContainer = EUNINITIALIZED_CONTAINER; } protected boolean eIsCaching() { return true; } public Object dynamicGet(int dynamicFeatureID) { Object result = eSettings[dynamicFeatureID]; if (result == null) { EStructuralFeature eStructuralFeature = eDynamicFeature(dynamicFeatureID); if (!eStructuralFeature.isTransient()) { if (FeatureMapUtil.isFeatureMap(eStructuralFeature)) { eSettings[dynamicFeatureID] = result = createFeatureMap(eStructuralFeature); } else if (eStructuralFeature.isMany()) { eSettings[dynamicFeatureID] = result = createList(eStructuralFeature); } else { result = eStore().get(this, eStructuralFeature, InternalEObject.EStore.NO_INDEX); if (eIsCaching()) { eSettings[dynamicFeatureID] = result; } } } } return result; } public void dynamicSet(int dynamicFeatureID, Object value) { EStructuralFeature eStructuralFeature = eDynamicFeature(dynamicFeatureID); if (eStructuralFeature.isTransient()) { eSettings[dynamicFeatureID] = value; } else { eStore().set(this, eStructuralFeature, InternalEObject.EStore.NO_INDEX, value); if (eIsCaching()) { eSettings[dynamicFeatureID] = value; } } } public void dynamicUnset(int dynamicFeatureID) { EStructuralFeature eStructuralFeature = eDynamicFeature(dynamicFeatureID); if (eStructuralFeature.isTransient()) { eSettings[dynamicFeatureID] = null; } else { eStore().unset(this, eStructuralFeature); eSettings[dynamicFeatureID] = null; } } @Override protected boolean eDynamicIsSet(int dynamicFeatureID, EStructuralFeature eFeature) { return dynamicFeatureID < 0 ? eOpenIsSet(eFeature) : eFeature.isTransient() ? eSettingDelegate(eFeature).dynamicIsSet(this, eSettings(), dynamicFeatureID) : eStore().isSet(this, eFeature); } protected EList<?> createList(final EStructuralFeature eStructuralFeature) { final EClassifier eType = eStructuralFeature.getEType(); if (eType.getInstanceClassName() == "java.util.Map$Entry") { class EStoreEcoreEMap extends EcoreEMap<Object, Object> { private static final long serialVersionUID = 1L; public EStoreEcoreEMap() { super ((EClass)eType, BasicEMap.Entry.class, null); delegateEList = new BasicEStoreEList<BasicEMap.Entry<Object, Object>>(EStoreEObjectImpl.this, eStructuralFeature) { private static final long serialVersionUID = 1L; @Override protected void didAdd(int index, BasicEMap.Entry<Object, Object> newObject) { EStoreEcoreEMap.this.doPut(newObject); } @Override protected void didSet(int index, BasicEMap.Entry<Object, Object> newObject, BasicEMap.Entry<Object, Object> oldObject) { didRemove(index, oldObject); didAdd(index, newObject); } @Override protected void didRemove(int index, BasicEMap.Entry<Object, Object> oldObject) { EStoreEcoreEMap.this.doRemove(oldObject); } @Override protected void didClear(int size, Object [] oldObjects) { EStoreEcoreEMap.this.doClear(); } @Override protected void didMove(int index, BasicEMap.Entry<Object, Object> movedObject, int oldIndex) { EStoreEcoreEMap.this.doMove(movedObject); } }; size = delegateEList.size(); } } return new EStoreEcoreEMap(); } else { return new BasicEStoreEList<Object>(this, eStructuralFeature); } } protected FeatureMap createFeatureMap(EStructuralFeature eStructuralFeature) { return new EStoreFeatureMap(this, eStructuralFeature, eStore()); } @Override public InternalEObject eInternalContainer() { if (eContainer == EUNINITIALIZED_CONTAINER) { eInitializeContainer(); } return eContainer; } @Override public int eContainerFeatureID() { if (eContainer == EUNINITIALIZED_CONTAINER) { eInitializeContainer(); } return eContainerFeatureID; } protected void eInitializeContainer() { eContainer = eStore().getContainer(this); if (eContainer != null) { EStructuralFeature eContainingFeature = eStore().getContainingFeature(this); if (eContainingFeature instanceof EReference) { EReference eContainingReference = (EReference)eContainingFeature; EReference eOpposite = eContainingReference.getEOpposite(); if (eOpposite != null) { eContainerFeatureID = eClass().getFeatureID(eOpposite); return; } } eContainerFeatureID = EOPPOSITE_FEATURE_BASE - eContainer.eClass().getFeatureID(eContainingFeature); } } @Override public InternalEObject.EStore eStore() { return eStore; } @Override public void eSetStore(InternalEObject.EStore store) { this.eStore = store; } @Override protected int eStaticFeatureCount() { return 0; } @Override public int eDerivedStructuralFeatureID(EStructuralFeature eStructuralFeature) { return eClass().getFeatureID(eStructuralFeature); } @Override protected BasicEObjectImpl.EPropertiesHolder eProperties() { if (eProperties == null) { eProperties = new EStoreEPropertiesHolderImpl(); } return eProperties; } @Override protected boolean eHasSettings() { return eSettings != null; } @Override protected EStructuralFeature.Internal.DynamicValueHolder eSettings() { if (eSettings == null) { int size = eClass().getFeatureCount() - eStaticFeatureCount(); eSettings = size == 0 ? ENO_SETTINGS : new Object [size]; } return this; } /* public String toString() { String result = super.toString(); int index = result.indexOf("EStoreEObjectImpl"); return index == -1 ? result : result.substring(0, index) + result.substring(index + 6); } */ /** * This class is for testing purposes only and will be removed. */ public static class EStoreImpl implements InternalEObject.EStore { // protected static final EStructuralFeature CONTAINING_FEATURE = new EReferenceImpl(); // protected static final EStructuralFeature CONTAINER = new EReferenceImpl(); protected Map<Entry, Object> map = new HashMap<Entry, Object>(); public static class Entry { protected EObject eObject; protected EStructuralFeature eStructuralFeature; public Entry(InternalEObject eObject, EStructuralFeature eStructuralFeature) { this.eObject = eObject; this.eStructuralFeature = eStructuralFeature; } @Override public boolean equals(Object that) { if (that instanceof Entry) { Entry entry = (Entry)that; return eObject == entry.eObject && eStructuralFeature == entry.eStructuralFeature; } else { return false; } } @Override public int hashCode() { return eObject.hashCode() ^ eStructuralFeature.hashCode(); } } protected EList<Object> getList(Entry entry) { @SuppressWarnings("unchecked") EList<Object> result = (EList<Object>)map.get(entry); if (result == null) { result = new BasicEList<Object>(); map.put(entry, result); } return result; } public Object get(InternalEObject eObject, EStructuralFeature feature, int index) { Entry entry = new Entry(eObject, feature); if (index == NO_INDEX) { return map.get(entry); } else { return getList(entry).get(index); } } public Object set(InternalEObject eObject, EStructuralFeature feature, int index, Object value) { Entry entry = new Entry(eObject, feature); if (index == NO_INDEX) { return map.put(entry, value); } else { List<Object> list = getList(entry); return list.set(index, value); } } public void add(InternalEObject eObject, EStructuralFeature feature, int index, Object value) { Entry entry = new Entry(eObject, feature); getList(entry).add(index, value); } public Object remove(InternalEObject eObject, EStructuralFeature feature, int index) { Entry entry = new Entry(eObject, feature); return getList(entry).remove(index); } public Object move(InternalEObject eObject, EStructuralFeature feature, int targetIndex, int sourceIndex) { Entry entry = new Entry(eObject, feature); return getList(entry).move(targetIndex, sourceIndex); } public void clear(InternalEObject eObject, EStructuralFeature feature) { Entry entry = new Entry(eObject, feature); map.remove(entry); //getList(entry).clear(); } public boolean isSet(InternalEObject eObject, EStructuralFeature feature) { Entry entry = new Entry(eObject, feature); return map.containsKey(entry); } public void unset(InternalEObject eObject, EStructuralFeature feature) { Entry entry = new Entry(eObject, feature); map.remove(entry); } public int size(InternalEObject eObject, EStructuralFeature feature) { Entry entry = new Entry(eObject, feature); return getList(entry).size(); } public int indexOf(InternalEObject eObject, EStructuralFeature feature, Object value) { Entry entry = new Entry(eObject, feature); return getList(entry).indexOf(value); } public int lastIndexOf(InternalEObject eObject, EStructuralFeature feature, Object value) { Entry entry = new Entry(eObject, feature); return getList(entry).lastIndexOf(value); } public Object[] toArray(InternalEObject eObject, EStructuralFeature feature) { Entry entry = new Entry(eObject, feature); return getList(entry).toArray(); } public <T> T[] toArray(InternalEObject eObject, EStructuralFeature feature, T[] array) { Entry entry = new Entry(eObject, feature); return getList(entry).toArray(array); } public boolean isEmpty(InternalEObject eObject, EStructuralFeature feature) { Entry entry = new Entry(eObject, feature); return getList(entry).isEmpty(); } public boolean contains(InternalEObject eObject, EStructuralFeature feature, Object value) { Entry entry = new Entry(eObject, feature); return getList(entry).contains(value); } public int hashCode(InternalEObject eObject, EStructuralFeature feature) { Entry entry = new Entry(eObject, feature); return getList(entry).hashCode(); } public InternalEObject getContainer(InternalEObject eObject) { return null; // Entry entry = new Entry(eObject, CONTAINER); // return (InternalEObject)map.get(entry); } public EStructuralFeature getContainingFeature(InternalEObject eObject) { // This should never be called. // throw new UnsupportedOperationException(); // Entry entry = new Entry(eObject, CONTAINING_FEATURE); // return (EStructuralFeature)map.get(entry); } public EObject create(EClass eClass) { InternalEObject result = new EStoreEObjectImpl(eClass, this); return result; } } }