package de.hub.emffrag.fragmentation; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.EReference; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.InternalEObject; import org.eclipse.emf.ecore.util.EcoreEList; import de.hub.emffrag.EmfFragActivator; import de.hub.emffrag.datastore.IDataMap; import de.hub.emffrag.datastore.IDataStore; import de.hub.emffrag.datastore.LongKeyType; public class FValueSetList extends EcoreEList.Dynamic<FInternalObjectImpl> { private static final long serialVersionUID = 1L; private final IDataMap<Long> index; private final AbstractValueSetSemantics<Long> semantics; private final String id; public FValueSetList(int kind, Class<?> dataClass, InternalEObject owner, EStructuralFeature feature) { super(kind, dataClass, owner, feature); FInternalObjectImpl object = (FInternalObjectImpl) owner; FragmentedModel model = object.getFragmentation(); if (model == null) { model = EmfFragActivator.instance.defaultModel; } if (model == null) { throw new NotInAFragmentedModelException( "Operation on indexed value sets can only be performed for objects contained in a fragmented model."); } IDataStore dataStore = model.getDataStore(); this.id = createPrefix(object, feature); index = dataStore.getMap(id.getBytes(), LongKeyType.instance); if (((EReference) feature).isContainment()) { semantics = new IndexedContainmentValueSetSemantics<Long>(model, index, object, feature); } else { semantics = new IndexedValueSetSemantics<Long>(model, index); } } static String createPrefix(FInternalObjectImpl object, EStructuralFeature feature) { String id = EmfFragActivator.instance.idSemantics.getPrefixID(object); int featureId = feature.getFeatureID(); if (((EReference) feature).isContainment()) { return FragmentedModel.INDEX_FEATURES_PREFIX + "_" + id + "_" + featureId; } else { return FragmentedModel.INDEX_FEATURES_PREFIX + "-" + id + "_" + featureId; } } @Override protected Object[] newData(int capacity) { return null; } @Override protected FInternalObjectImpl assign(int index, FInternalObjectImpl object) { throw new UnsupportedOperationException(); } @Override public Object[] data() { return null; } @Override public void setData(int size, Object[] data) { } @Override public FInternalObjectImpl basicGet(int index) { return primitiveGet(index); } @Override protected FInternalObjectImpl primitiveGet(int index) { return get(index); } @Override public void addUnique(FInternalObjectImpl object) { size = (int) (long) index.last(); super.addUnique(object); } @Override public void addUnique(int index, FInternalObjectImpl object) { int indexIndex = ReflectiveMetaModelRegistry.instance.getInverseReferenceIndex((EReference)eStructuralFeature); EList<Long> indexes = object.getIndexes(); if (indexes.size() > indexIndex) { Long beforeIndex = indexes.get(indexIndex); object.indexBeforeAdd = beforeIndex == null ? -1 : beforeIndex; object.addValueSetId = id; } super.addUnique(index, object); object.indexBeforeAdd = -1; object.addValueSetId = null; } @Override public boolean addAllUnique(Collection<? extends FInternalObjectImpl> collection) { throw new UnsupportedOperationException(); } @Override public boolean addAllUnique(int index, Collection<? extends FInternalObjectImpl> collection) { throw new UnsupportedOperationException(); } @Override public boolean addAllUnique(Object[] objects, int start, int end) { throw new UnsupportedOperationException(); } @Override public boolean addAllUnique(int index, Object[] objects, int start, int end) { throw new UnsupportedOperationException(); } @Override public void shrink() { throw new UnsupportedOperationException(); } @Override public void grow(int minimumCapacity) { // throw new UnsupportedOperationException(); } @Override public Object clone() { throw new UnsupportedOperationException(); } @Override public boolean add(FInternalObjectImpl e) { Long key = index.add(); performAdd(key, e); return true; } @Override public void doAddUnique(int index, FInternalObjectImpl element) { Long last = this.index.last(); if ((last == null && index == 0) || (last + 1 == index)) { performAdd((long) index, element); } else { EmfFragActivator.instance.warning("Can only add to the end of an indexed value set. Add the value to the end instead."); add(element); } } private void performAdd(long key, FInternalObjectImpl object) { semantics.setValueForKey(key, object); EReference reference = (EReference) eStructuralFeature; int index = ReflectiveMetaModelRegistry.instance.getInverseReferenceIndex(reference); EList<Long> indexes = object.getIndexes(); if (indexes.size() > index && indexes.get(index) != null && indexes.get(index).intValue() != -1 && object.indexBeforeAdd == -1) { EmfFragActivator.instance .warning("An object was added to an indexed value set, but seems to be already part of another indexed value set for the same feature." + "This is not really supported. Some operations of the original value set will not work properly." + "The effected feature is " + eStructuralFeature.getName() + " of class " + eStructuralFeature.getEContainingClass().getName() + "."); } for (int i = indexes.size(); i <= index; i++) { indexes.add(Long.valueOf(-1)); } indexes.set(index, key); } @Override public boolean addAll(Collection<? extends FInternalObjectImpl> c) { boolean result = true; for (FInternalObjectImpl e : c) { result &= add(e); } return result; } @Override public boolean addAll(int index, Collection<? extends FInternalObjectImpl> c) { throw new UnsupportedOperationException("This method is not supported for indexed value sets."); } @Override public void clear() { throw new UnsupportedOperationException("This method is not supported for indexed value sets."); } @Override public boolean contains(Object o) { int indexIndex = ReflectiveMetaModelRegistry.instance.getInverseReferenceIndex((EReference) eStructuralFeature); if (o instanceof FInternalObject) { Long index = ((FInternalObject) o).getIndexes().get(indexIndex); if (index != null) { return o == performGet(index.longValue()); } else { return false; } } else { return false; } } @Override public boolean containsAll(Collection<?> c) { boolean result = true; for (Object o : c) { result &= contains(o); } return result; } @Override public FInternalObjectImpl get(int index) { FInternalObjectImpl result = performGet((long) index); if (result == null) { throw new IndexOutOfBoundsException(); } return result; } private FInternalObjectImpl performGet(long index) { return semantics.getValueForExactKey((long) index); } @Override public int indexOf(Object o) { if (o instanceof FInternalObjectImpl) { FInternalObjectImpl fInternalObject = (FInternalObjectImpl) o; if (fInternalObject.indexBeforeAdd != -1 && id.equals(fInternalObject.addValueSetId)) { return (int)fInternalObject.indexBeforeAdd; } else { int indexIndex = ReflectiveMetaModelRegistry.instance.getInverseReferenceIndex((EReference) eStructuralFeature); Long index = fInternalObject.getIndexes().get(indexIndex); if (index == null) { return -1; } else { if (performGet(index.longValue()) == o) { return index.intValue(); } else { return -1; } } } } else { return -1; } } @Override public boolean isEmpty() { return index.last() == null; } @Override public Iterator<FInternalObjectImpl> iterator() { return semantics.iterator(0l, index.last()); } @Override public int lastIndexOf(Object o) { return indexOf(o); } @Override public ListIterator<FInternalObjectImpl> listIterator() { return semantics.iterator(0l, index.last()); } @Override public ListIterator<FInternalObjectImpl> listIterator(int index) { return semantics.iterator((long) index, this.index.last()); } @Override public FInternalObjectImpl doRemove(int index) { FInternalObjectImpl value = get(index); semantics.removeValueForKey((long) index, value); if (id.equals(value.addValueSetId)) { int indexIndex = ReflectiveMetaModelRegistry.instance.getInverseReferenceIndex((EReference) eStructuralFeature); EList<Long> indexes = value.getIndexes(); indexes.set(indexIndex, Long.valueOf(-1)); } return value; } @Override public boolean remove(Object o) { if (o instanceof FInternalObjectImpl) { int indexIndex = ReflectiveMetaModelRegistry.instance.getInverseReferenceIndex((EReference) eStructuralFeature); EList<Long> indexes = ((FInternalObject) o).getIndexes(); if (indexes.size() <= indexIndex) { return false; } else { Long index = indexes.get(indexIndex); if (index == null) { return false; } else { return remove(index.intValue()) != null; } } } else { return false; } } @Override public boolean removeAll(Collection<?> c) { boolean result = true; for (Object o : c) { result &= remove(o); } return result; } @Override public boolean retainAll(Collection<?> c) { throw new UnsupportedOperationException("This method is not supported for indexed value sets."); } @Override public FInternalObjectImpl doSetUnique(int index, FInternalObjectImpl element) { FInternalObjectImpl result = get(index); semantics.setValueForKey((long) index, element); return result; } @Override public int size() { Long last = index.last(); return last == null ? 0 : (int) (last + 1); } @Override public List<FInternalObjectImpl> subList(int fromIndex, int toIndex) { // TODO throw new UnsupportedOperationException("This method is not supported for indexed value sets."); } @Override public Object[] toArray() { throw new UnsupportedOperationException("This method is not supported for indexed value sets."); } @Override public <T> T[] toArray(T[] a) { throw new UnsupportedOperationException("This method is not supported for indexed value sets."); } @Override public void move(int newPosition, FInternalObjectImpl object) { throw new UnsupportedOperationException("This method is not supported for indexed value sets."); } @Override public FInternalObjectImpl move(int newPosition, int oldPosition) { throw new UnsupportedOperationException("This method is not supported for indexed value sets."); } @Override public Iterator<FInternalObjectImpl> basicIterator() { super.basicIterator(); return iterator(); } }