| /** |
| * Copyright (c) 2003-2009 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v2.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v20.html |
| * |
| * Contributors: |
| * IBM - Initial API and implementation |
| */ |
| package org.eclipse.emf.ecore.util; |
| |
| |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.ListIterator; |
| |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.notify.NotificationChain; |
| import org.eclipse.emf.common.notify.impl.NotificationImpl; |
| import org.eclipse.emf.common.util.AbstractEList; |
| import org.eclipse.emf.common.util.BasicEList; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.ecore.EDataType; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EReference; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.emf.ecore.ETypedElement; |
| import org.eclipse.emf.ecore.InternalEObject; |
| import org.eclipse.emf.ecore.impl.ENotificationImpl; |
| |
| |
| public class BasicFeatureMap |
| extends EDataTypeEList<FeatureMap.Entry> |
| implements FeatureMap.Internal, FeatureMap.Internal.Wrapper |
| { |
| private static final long serialVersionUID = 1L; |
| |
| protected Wrapper wrapper = this; |
| protected final FeatureMapUtil.Validator featureMapValidator; |
| |
| public BasicFeatureMap(InternalEObject owner, int featureID) |
| { |
| super(Entry.Internal.class, owner, featureID); |
| |
| featureMapValidator = FeatureMapUtil.getValidator(owner.eClass(), getEStructuralFeature()); |
| } |
| |
| public BasicFeatureMap(InternalEObject owner, int featureID, EStructuralFeature eStructuralFeature) |
| { |
| super(Entry.Internal.class, owner, featureID); |
| |
| featureMapValidator = FeatureMapUtil.getValidator(owner.eClass(), eStructuralFeature); |
| } |
| |
| public Wrapper getWrapper() |
| { |
| return wrapper; |
| } |
| |
| public void setWrapper(Wrapper wrapper) |
| { |
| this.wrapper = wrapper; |
| } |
| |
| public FeatureMap featureMap() |
| { |
| return this; |
| } |
| |
| @Override |
| protected Object [] newData(int capacity) |
| { |
| return new FeatureMap.Entry.Internal [capacity]; |
| } |
| |
| @Override |
| protected Entry validate(int index, Entry object) |
| { |
| if (modCount == 0) return object; |
| |
| Entry result = super.validate(index, object); |
| EStructuralFeature eStructuralFeature = object.getEStructuralFeature(); |
| if (!eStructuralFeature.isChangeable() || !featureMapValidator.isValid(eStructuralFeature)) |
| { |
| throw |
| new RuntimeException |
| ("Invalid entry feature '" + eStructuralFeature.getEContainingClass().getName() + "." + eStructuralFeature.getName() + "'"); |
| } |
| return result; |
| } |
| |
| protected FeatureMap.Entry createEntry(EStructuralFeature eStructuralFeature, Object value) |
| { |
| return FeatureMapUtil.createEntry(eStructuralFeature, value); |
| } |
| |
| protected FeatureMap.Entry.Internal createRawEntry(EStructuralFeature eStructuralFeature, Object value) |
| { |
| return FeatureMapUtil.createRawEntry(eStructuralFeature, value); |
| } |
| |
| protected NotificationImpl createNotification |
| (int eventType, EStructuralFeature feature, Object oldObject, Object newObject, int index, boolean wasSet) |
| { |
| return new FeatureMapUtil.FeatureENotificationImpl(owner, eventType, feature, oldObject, newObject, index, wasSet); |
| } |
| |
| protected boolean isMany(EStructuralFeature feature) |
| { |
| return FeatureMapUtil.isMany(owner, feature); |
| } |
| |
| @Override |
| protected boolean hasInverse() |
| { |
| return true; |
| } |
| |
| @Override |
| protected boolean hasShadow() |
| { |
| return true; |
| } |
| |
| protected int entryIndex(EStructuralFeature feature, int index) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| int count = 0; |
| int result = size; |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (index == count) |
| { |
| return i; |
| } |
| ++count; |
| result = i + 1; |
| } |
| } |
| |
| if (index == count) |
| { |
| return result; |
| } |
| else |
| { |
| throw new IndexOutOfBoundsException("index=" + index + ", size=" + count); |
| } |
| } |
| |
| protected boolean isResolveProxies(EStructuralFeature feature) |
| { |
| return feature instanceof EReference && ((EReference)feature).isResolveProxies(); |
| } |
| |
| public Object resolveProxy(EStructuralFeature feature, int entryIndex, int index, Object object) |
| { |
| EObject resolved = resolveProxy((EObject)object); |
| if (resolved != object) |
| { |
| Entry oldObject = (Entry)data[entryIndex]; |
| Entry entry = createEntry(feature, resolved); |
| assign(entryIndex, validate(entryIndex, entry)); |
| didSet(entryIndex, entry, oldObject); |
| |
| if (isNotificationRequired()) |
| { |
| NotificationImpl notifications = |
| createNotification |
| (Notification.RESOLVE, |
| entry.getEStructuralFeature(), |
| object, |
| resolved, |
| index, |
| false); |
| |
| notifications.add(createNotification(Notification.RESOLVE, oldObject, entry, index, false)); |
| notifications.dispatch(); |
| } |
| |
| return resolved; |
| } |
| |
| return object; |
| } |
| |
| @Override |
| protected EObject resolveProxy(EObject eObject) |
| { |
| return owner.eResolveProxy((InternalEObject)eObject); |
| } |
| |
| public int getModCount() |
| { |
| return modCount; |
| } |
| |
| public EStructuralFeature getEStructuralFeature(int index) |
| { |
| return get(index).getEStructuralFeature(); |
| } |
| |
| public Object getValue(int index) |
| { |
| return get(index).getValue(); |
| } |
| |
| public Object setValue(int index, Object value) |
| { |
| return set(index, createEntry(getEStructuralFeature(index), value)).getValue(); |
| } |
| |
| @Override |
| public NotificationChain shadowAdd(Entry object, NotificationChain notifications) |
| { |
| return shadowAdd((FeatureMap.Entry.Internal)object, notifications); |
| } |
| |
| public NotificationChain shadowAdd(FeatureMap.Entry.Internal entry, NotificationChain notifications) |
| { |
| EStructuralFeature feature = entry.getEStructuralFeature(); |
| Object value = entry.getValue(); |
| // EATM must fix isSet bits. |
| NotificationImpl notification = |
| feature.isMany() ? |
| createNotification |
| (Notification.ADD, |
| feature, |
| null, |
| value, |
| indexOf(feature, value), |
| true) : |
| createNotification |
| (Notification.SET, |
| feature, |
| feature.getDefaultValue(), |
| value, |
| Notification.NO_INDEX, |
| true); |
| |
| if (notifications != null) |
| { |
| notifications.add(notification); |
| } |
| else |
| { |
| notifications = notification; |
| } |
| return notifications; |
| } |
| |
| @Override |
| public NotificationChain inverseAdd(Entry object, NotificationChain notifications) |
| { |
| return inverseAdd((FeatureMap.Entry.Internal)object, notifications); |
| } |
| |
| public NotificationChain inverseAdd(FeatureMap.Entry.Internal entry, NotificationChain notifications) |
| { |
| return entry.inverseAdd(owner, featureID, notifications); |
| } |
| |
| @Override |
| public NotificationChain shadowRemove(Entry object, NotificationChain notifications) |
| { |
| return shadowRemove((FeatureMap.Entry.Internal)object, notifications); |
| } |
| |
| public NotificationChain shadowRemove(FeatureMap.Entry.Internal entry, NotificationChain notifications) |
| { |
| EStructuralFeature feature = entry.getEStructuralFeature(); |
| Object value = entry.getValue(); |
| NotificationImpl notification = |
| feature.isMany() ? |
| createNotification |
| (Notification.REMOVE, |
| feature, |
| value, |
| null, |
| indexOf(feature, value), |
| true) : |
| createNotification |
| (feature.isUnsettable() ? Notification.UNSET : Notification.SET, |
| feature, |
| value, |
| feature.getDefaultValue(), |
| Notification.NO_INDEX, |
| true); |
| |
| if (notifications != null) |
| { |
| notifications.add(notification); |
| } |
| else |
| { |
| notifications = notification; |
| } |
| |
| return notifications; |
| } |
| |
| @Override |
| public NotificationChain inverseRemove(Entry object, NotificationChain notifications) |
| { |
| return inverseRemove((FeatureMap.Entry.Internal)object, notifications); |
| } |
| |
| public NotificationChain inverseRemove(FeatureMap.Entry.Internal entry, NotificationChain notifications) |
| { |
| return entry.inverseRemove(owner, featureID, notifications); |
| } |
| |
| @Override |
| public NotificationChain shadowSet(Entry oldObject, Entry newObject, NotificationChain notifications) |
| { |
| if (isNotificationRequired()) |
| { |
| EStructuralFeature feature = oldObject.getEStructuralFeature(); |
| Object oldValue = oldObject.getValue(); |
| Object newValue = newObject.getValue(); |
| NotificationImpl notification = |
| createNotification |
| (Notification.SET, |
| feature, |
| oldValue, |
| newValue, |
| feature.isMany() ? indexOf(feature, newValue) : Notification.NO_INDEX, |
| true); |
| |
| if (notifications != null) |
| { |
| notifications.add(notification); |
| } |
| else |
| { |
| notifications = notification; |
| } |
| } |
| return notifications; |
| } |
| |
| public NotificationChain inverseTouch(Object object, NotificationChain notifications) |
| { |
| if (isNotificationRequired()) |
| { |
| Entry entry = (Entry)object; |
| EStructuralFeature feature = entry.getEStructuralFeature(); |
| Object value = entry.getValue(); |
| NotificationImpl notification = |
| createNotification |
| (Notification.SET, |
| feature, |
| value, |
| value, |
| feature.isMany() ? indexOf(feature, value) : Notification.NO_INDEX, |
| true); |
| |
| if (notifications != null) |
| { |
| notifications.add(notification); |
| } |
| else |
| { |
| notifications = notification; |
| } |
| } |
| |
| return notifications; |
| } |
| |
| @Override |
| public Entry move(int targetIndex, int sourceIndex) |
| { |
| if (!isNotificationRequired()) |
| { |
| return doMove(targetIndex, sourceIndex); |
| } |
| else if (targetIndex != sourceIndex) |
| { |
| Entry [] entries = (Entry[])data; |
| Entry sourceEntry = entries[sourceIndex]; |
| EStructuralFeature feature = sourceEntry.getEStructuralFeature(); |
| if (isMany(feature)) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| int featureTargetIndex = -1; |
| int featureSourceIndex = -1; |
| int count = 0; |
| for (int i = 0, maxIndex= targetIndex > sourceIndex ? targetIndex : sourceIndex; i <= maxIndex; ++i) |
| { |
| if (i == sourceIndex) |
| { |
| featureSourceIndex = count++; |
| } |
| else |
| { |
| Entry entry = entries[i]; |
| boolean isValid = validator.isValid(entry.getEStructuralFeature()); |
| if (i == targetIndex) |
| { |
| featureTargetIndex = i == maxIndex && !isValid ? count-1 : count; |
| } |
| |
| if (isValid) |
| { |
| ++count; |
| } |
| } |
| } |
| |
| Entry result = super.move(targetIndex, sourceIndex); |
| |
| if (featureSourceIndex != featureTargetIndex) |
| { |
| dispatchNotification |
| (new ENotificationImpl |
| (owner, |
| Notification.MOVE, |
| feature, |
| featureSourceIndex, |
| sourceEntry.getValue(), |
| featureTargetIndex)); |
| } |
| return result; |
| } |
| } |
| return super.move(targetIndex, sourceIndex); |
| } |
| |
| @Override |
| public Entry set(int index, Entry object) |
| { |
| Entry entry = object; |
| EStructuralFeature entryFeature = entry.getEStructuralFeature(); |
| if (isMany(entryFeature)) |
| { |
| if (entryFeature.isUnique()) |
| { |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry otherEntry = entries[i]; |
| if (otherEntry.equals(entry) && i != index) |
| { |
| throw new IllegalArgumentException("The 'no duplicates' constraint is violated"); |
| } |
| } |
| } |
| } |
| else |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), entryFeature); |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry otherEntry = entries[i]; |
| if (validator.isValid(otherEntry.getEStructuralFeature()) && i != index) |
| { |
| throw new IllegalArgumentException("The multiplicity constraint is violated"); |
| } |
| } |
| } |
| |
| return doSet(index, object); |
| } |
| |
| public Entry doSet(int index, Entry object) |
| { |
| return super.set(index, object); |
| } |
| |
| @Override |
| public boolean add(Entry object) |
| { |
| Entry entry = object; |
| EStructuralFeature entryFeature = entry.getEStructuralFeature(); |
| if (isMany(entryFeature)) |
| { |
| if (entryFeature.isUnique() && contains(entryFeature, entry.getValue())) |
| { |
| return false; |
| } |
| } |
| else |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), entryFeature); |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry otherEntry = entries[i]; |
| if (validator.isValid(otherEntry.getEStructuralFeature())) |
| { |
| if (otherEntry.equals(entry)) |
| { |
| return false; |
| } |
| else |
| { |
| doSet(i, object); |
| return true; |
| } |
| } |
| } |
| } |
| |
| return doAdd(object); |
| } |
| |
| protected boolean doAdd(Entry object) |
| { |
| return super.add(object); |
| } |
| |
| @Override |
| public void add(int index, Entry object) |
| { |
| Entry entry = object; |
| EStructuralFeature entryFeature = entry.getEStructuralFeature(); |
| if (isMany(entryFeature)) |
| { |
| if (entryFeature.isUnique()) |
| { |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry otherEntry = entries[i]; |
| if (otherEntry.equals(entry) && i != index) |
| { |
| throw new IllegalArgumentException("The 'no duplicates' constraint is violated"); |
| } |
| } |
| } |
| } |
| else |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), entryFeature); |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry otherEntry = entries[i]; |
| if (validator.isValid(otherEntry.getEStructuralFeature())) |
| { |
| throw new IllegalArgumentException("The multiplicity constraint is violated"); |
| } |
| } |
| } |
| |
| doAdd(index, object); |
| } |
| |
| public void doAdd(int index, Entry object) |
| { |
| super.add(index, object); |
| } |
| |
| @Override |
| public boolean addAll(Collection<? extends Entry> collection) |
| { |
| Collection<Entry> uniqueCollection = new BasicEList<Entry>(collection.size()); |
| for (Entry entry : collection) |
| { |
| EStructuralFeature entryFeature = entry.getEStructuralFeature(); |
| if (isMany(entryFeature)) |
| { |
| if (!entryFeature.isUnique() || !contains(entryFeature, entry.getValue()) && !uniqueCollection.contains(entry)) |
| { |
| uniqueCollection.add(entry); |
| } |
| } |
| else |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), entryFeature); |
| Entry [] entries = (Entry[])data; |
| boolean include = true; |
| for (int j = 0; j < size; ++j) |
| { |
| Entry otherEntry = entries[j]; |
| if (validator.isValid(otherEntry.getEStructuralFeature())) |
| { |
| doSet(j, entry); |
| include = false; |
| break; |
| } |
| } |
| if (include) |
| { |
| uniqueCollection.add(entry); |
| } |
| } |
| } |
| |
| return doAddAll(uniqueCollection); |
| } |
| |
| public boolean doAddAll(Collection<? extends Entry> collection) |
| { |
| return super.addAll(collection); |
| } |
| |
| @Override |
| public boolean addAll(int index, Collection<? extends Entry> collection) |
| { |
| Collection<Entry> uniqueCollection = new BasicEList<Entry>(collection.size()); |
| for (Entry entry : collection) |
| { |
| EStructuralFeature entryFeature = entry.getEStructuralFeature(); |
| if (isMany(entryFeature)) |
| { |
| if (!entryFeature.isUnique() || !contains(entryFeature, entry.getValue()) && !uniqueCollection.contains(entry)) |
| { |
| uniqueCollection.add(entry); |
| } |
| } |
| else |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), entryFeature); |
| Entry [] entries = (Entry[])data; |
| boolean include = true; |
| for (int j = 0; j < size; ++j) |
| { |
| Entry otherEntry = entries[j]; |
| if (validator.isValid(otherEntry.getEStructuralFeature())) |
| { |
| doSet(j, entry); |
| include = false; |
| break; |
| } |
| } |
| if (include) |
| { |
| uniqueCollection.add(entry); |
| } |
| } |
| } |
| |
| return doAddAll(index, uniqueCollection); |
| } |
| |
| public boolean doAddAll(int index, Collection<? extends Entry> collection) |
| { |
| return super.addAll(index, collection); |
| } |
| |
| public int size(EStructuralFeature feature) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| int result = 0; |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| ++result; |
| } |
| } |
| return result; |
| } |
| |
| public boolean isEmpty(EStructuralFeature feature) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| public boolean contains(EStructuralFeature feature, Object object) |
| { |
| return contains(feature, object, isResolveProxies(feature)); |
| } |
| |
| public boolean basicContains(EStructuralFeature feature, Object object) |
| { |
| return contains(feature, object, false); |
| } |
| |
| protected boolean contains(EStructuralFeature feature, Object object, boolean resolve) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| if (FeatureMapUtil.isFeatureMap(feature)) |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature()) && entry.equals(object)) |
| { |
| return true; |
| } |
| } |
| } |
| else if (object != null) |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature()) && object.equals(entry.getValue())) |
| { |
| return true; |
| } |
| } |
| if (resolve) |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature()) && object == resolveProxy((EObject)entry.getValue())) |
| { |
| return true; |
| } |
| } |
| } |
| } |
| else |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature()) && entry.getValue() == null) |
| { |
| return false; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| public boolean containsAll(EStructuralFeature feature, Collection<?> collection) |
| { |
| for (Iterator<?> i = collection.iterator(); i.hasNext(); ) |
| { |
| if (!contains(feature, i.next())) |
| { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| public boolean basicContainsAll(EStructuralFeature feature, Collection<?> collection) |
| { |
| for (Iterator<?> i = collection.iterator(); i.hasNext(); ) |
| { |
| if (!basicContains(feature, i.next())) |
| { |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| public int indexOf(EStructuralFeature feature, Object object) |
| { |
| return indexOf(feature, object, isResolveProxies(feature)); |
| } |
| |
| public int basicIndexOf(EStructuralFeature feature, Object object) |
| { |
| return indexOf(feature, object, false); |
| } |
| |
| protected int indexOf(EStructuralFeature feature, Object object, boolean resolve) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| int result = 0; |
| Entry [] entries = (Entry[])data; |
| if (FeatureMapUtil.isFeatureMap(feature)) |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (entry.equals(object)) |
| { |
| return result; |
| } |
| ++result; |
| } |
| } |
| } |
| else if (object != null) |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (object.equals(entry.getValue())) |
| { |
| return result; |
| } |
| ++result; |
| } |
| } |
| if (resolve) |
| { |
| result = 0; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (object == resolveProxy((EObject)entry.getValue())) |
| { |
| return result; |
| } |
| ++result; |
| } |
| } |
| } |
| } |
| else |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (entry.getValue() == null) |
| { |
| return result; |
| } |
| ++result; |
| } |
| } |
| } |
| |
| return -1; |
| } |
| |
| public int lastIndexOf(EStructuralFeature feature, Object object) |
| { |
| return lastIndexOf(feature, object, isResolveProxies(feature)); |
| } |
| |
| public int basicLastIndexOf(EStructuralFeature feature, Object object) |
| { |
| return lastIndexOf(feature, object, false); |
| } |
| |
| protected int lastIndexOf(EStructuralFeature feature, Object object, boolean resolve) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| int result = -1; |
| int count = 0; |
| Entry [] entries = (Entry[])data; |
| if (FeatureMapUtil.isFeatureMap(feature)) |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (entry.equals(object)) |
| { |
| result = count; |
| } |
| ++count; |
| } |
| } |
| } |
| else if (object != null) |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (object.equals(entry.getValue())) |
| { |
| result = count; |
| } |
| ++count; |
| } |
| } |
| if (resolve) |
| { |
| result = -1; |
| count = 0; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (object == resolveProxy((EObject)entry.getValue())) |
| { |
| result = count; |
| } |
| ++count; |
| } |
| } |
| } |
| } |
| else |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (entry.getValue() == null) |
| { |
| result = count; |
| } |
| ++count; |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| public Iterator<Object> iterator(EStructuralFeature feature) |
| { |
| return |
| feature instanceof EReference && ((EReference)feature).isResolveProxies() ? |
| new ResolvingFeatureEIterator<Object>(feature, this) : |
| new FeatureEIterator<Object>(feature, this); |
| } |
| |
| public ListIterator<Object> listIterator(EStructuralFeature feature) |
| { |
| return |
| feature instanceof EReference && ((EReference)feature).isResolveProxies() ? |
| new ResolvingFeatureEIterator<Object>(feature, this) : |
| new FeatureEIterator<Object>(feature, this); |
| } |
| |
| public ListIterator<Object> listIterator(EStructuralFeature feature, int index) |
| { |
| ListIterator<Object> result = |
| feature instanceof EReference && ((EReference)feature).isResolveProxies() ? |
| new ResolvingFeatureEIterator<Object>(feature, this) : |
| new FeatureEIterator<Object>(feature, this); |
| for (int i = 0; i < index; ++i) |
| { |
| result.next(); |
| } |
| return result; |
| } |
| |
| public ValueListIterator<Object> valueListIterator() |
| { |
| return new ValueListIteratorImpl<Object>(); |
| } |
| |
| public ValueListIterator<Object> valueListIterator(int index) |
| { |
| return new ValueListIteratorImpl<Object>(index); |
| } |
| |
| protected class ValueListIteratorImpl<E1> extends AbstractEList<FeatureMap.Entry>.EListIterator<E1> implements ValueListIterator<E1> |
| { |
| public ValueListIteratorImpl() |
| { |
| super(); |
| } |
| |
| public ValueListIteratorImpl(int index) |
| { |
| super(index); |
| } |
| |
| public EStructuralFeature feature() |
| { |
| if (lastCursor == -1) |
| { |
| throw new IllegalStateException(); |
| } |
| return getEStructuralFeature(lastCursor); |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| public E1 next() |
| { |
| return (E1)doNext().getValue(); |
| } |
| |
| @SuppressWarnings("unchecked") |
| @Override |
| public E1 previous() |
| { |
| return (E1)doPrevious().getValue(); |
| } |
| |
| @Override |
| public void add(E1 value) |
| { |
| doAdd(FeatureMapUtil.createEntry(feature(), value)); |
| } |
| |
| public void add(EStructuralFeature eStructuralFeature, Object value) |
| { |
| doAdd(FeatureMapUtil.createEntry(eStructuralFeature, value)); |
| } |
| } |
| |
| /* |
| public List subList(EStructuralFeature feature, int from, int to) |
| { |
| return null; |
| } |
| */ |
| |
| @SuppressWarnings("unchecked") |
| public <T> EList<T> list(EStructuralFeature feature) |
| { |
| return |
| FeatureMapUtil.isFeatureMap(feature) ? |
| (EList<T>)new FeatureMapUtil.FeatureFeatureMap(feature, this): |
| new FeatureMapUtil.FeatureEList<T>(feature, this); |
| } |
| |
| public EStructuralFeature.Setting setting(EStructuralFeature feature) |
| { |
| return |
| isMany(feature) ? |
| (EStructuralFeature.Setting)list(feature) : |
| (EStructuralFeature.Setting)new FeatureMapUtil.FeatureValue(feature, this); |
| } |
| |
| public List<Object> basicList(final EStructuralFeature feature) |
| { |
| return new FeatureMapUtil.FeatureEList.Basic<Object>(feature, this); |
| } |
| |
| public Iterator<Object> basicIterator(EStructuralFeature feature) |
| { |
| return new FeatureEIterator<Object>(feature, this); |
| } |
| |
| public ListIterator<Object> basicListIterator(EStructuralFeature feature) |
| { |
| return new FeatureEIterator<Object>(feature, this); |
| } |
| |
| public ListIterator<Object> basicListIterator(EStructuralFeature feature, int index) |
| { |
| ListIterator<Object> result = new FeatureEIterator<Object>(feature, this); |
| for (int i = 0; i < index; ++i) |
| { |
| result.next(); |
| } |
| return result; |
| } |
| |
| public Object[] toArray(EStructuralFeature feature) |
| { |
| return toArray(feature, isResolveProxies(feature)); |
| } |
| |
| public Object[] basicToArray(EStructuralFeature feature) |
| { |
| return toArray(feature, false); |
| } |
| |
| protected Object[] toArray(EStructuralFeature feature, boolean resolve) |
| { |
| List<Object> result = new BasicEList<Object>(); |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| if (FeatureMapUtil.isFeatureMap(feature)) |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| result.add(entry); |
| } |
| } |
| } |
| else |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| Object value = entry.getValue(); |
| result.add(resolve ? resolveProxy(feature, i, result.size(), value) : value); |
| } |
| } |
| } |
| return result.toArray(); |
| } |
| |
| public <T> T[] toArray(EStructuralFeature feature, T [] array) |
| { |
| return toArray(feature, array, isResolveProxies(feature)); |
| } |
| |
| public <T> T[] basicToArray(EStructuralFeature feature, T [] array) |
| { |
| return toArray(feature, array, false); |
| } |
| |
| protected <T> T[] toArray(EStructuralFeature feature, T [] array, boolean resolve) |
| { |
| List<Object> result = new BasicEList<Object>(); |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| if (FeatureMapUtil.isFeatureMap(feature)) |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| result.add(entry); |
| } |
| } |
| } |
| else |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| Object value = entry.getValue(); |
| result.add(resolve ? resolveProxy(feature, i, result.size(), value) : value); |
| } |
| } |
| } |
| return result.toArray(array); |
| } |
| |
| public void set(EStructuralFeature feature, Object object) |
| { |
| if (isMany(feature)) |
| { |
| List<Object> list = list(feature); |
| list.clear(); |
| list.addAll((Collection<?>)object); |
| } |
| else |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| EStructuralFeature entryFeature = entry.getEStructuralFeature(); |
| if (validator.isValid(entryFeature)) |
| { |
| if (entryFeature == XMLTypeFeatures.TEXT || entryFeature == XMLTypeFeatures.CDATA) |
| { |
| boolean shouldUnset = shouldUnset(feature, object); |
| int index = i; |
| if (shouldUnset) |
| { |
| remove(i); |
| } |
| else |
| { |
| ++i; |
| } |
| while (i < size) |
| { |
| entry = entries[i]; |
| entryFeature = entry.getEStructuralFeature(); |
| if (entryFeature == XMLTypeFeatures.TEXT || entryFeature == XMLTypeFeatures.CDATA) |
| { |
| remove(i); |
| } |
| else |
| { |
| ++i; |
| } |
| } |
| if (!shouldUnset) |
| { |
| doSet(index, createEntry(feature, object)); |
| } |
| } |
| else if (shouldUnset(feature, object)) |
| { |
| remove(i); |
| } |
| else |
| { |
| doSet(i, FeatureMapUtil.isFeatureMap(feature) ? (Entry)object : (Entry)createEntry(feature, object)); |
| } |
| return; |
| } |
| } |
| |
| if (!shouldUnset(feature, object)) |
| { |
| doAdd(FeatureMapUtil.isFeatureMap(feature) ? (Entry)object : createEntry(feature, object)); |
| } |
| } |
| } |
| |
| protected boolean shouldUnset(EStructuralFeature feature, Object value) |
| { |
| // If the feature is unsettable, then regardless of the value, we should not be unsetting the feature. |
| // |
| if (feature.isUnsettable()) |
| { |
| return false; |
| } |
| // If it's not an open content element, unset the feature if the value is the same as the default value. |
| // |
| else if (feature.getUpperBound() != ETypedElement.UNSPECIFIED_MULTIPLICITY) |
| { |
| Object defaultValue = feature.getDefaultValue(); |
| return defaultValue == null ? value == null : defaultValue.equals(value); |
| } |
| // If this is a feature of the document root itself, unset if the value is null. |
| // If it was a nillable element, it would have been unsettable. |
| // |
| else if (feature.getEContainingClass() == owner.eClass()) |
| { |
| return value == null; |
| } |
| // Otherwise, return false. |
| // |
| else |
| { |
| return false; |
| } |
| } |
| |
| public void add(int index, EStructuralFeature feature, Object object) |
| { |
| boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature); |
| if (isMany(feature)) |
| { |
| if (feature.isUnique() && contains(feature, object)) |
| { |
| throw new IllegalArgumentException("The 'no duplicates' constraint is violated"); |
| } |
| } |
| else |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (isFeatureMap ? entry.equals(object) : object == null ? entry.getValue() == null : object.equals(entry.getValue())) |
| { |
| throw new IllegalArgumentException("The 'no duplicates' constraint is violated"); |
| } |
| } |
| } |
| } |
| |
| doAdd(index, isFeatureMap ? (Entry)object : createEntry(feature, object)); |
| } |
| |
| public boolean add(EStructuralFeature feature, Object object) |
| { |
| boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature); |
| if (isMany(feature)) |
| { |
| if (feature.isUnique() && contains(feature, object)) |
| { |
| return false; |
| } |
| } |
| else |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (isFeatureMap ? entry.equals(object) : object == null ? entry.getValue() == null : object.equals(entry.getValue())) |
| { |
| return false; |
| } |
| else |
| { |
| doSet(i, isFeatureMap ? (Entry)object : createEntry(feature, object)); |
| return true; |
| } |
| } |
| } |
| } |
| |
| return doAdd(isFeatureMap ? (Entry)object : createEntry(feature, object)); |
| } |
| |
| public void add(EStructuralFeature feature, int index, Object object) |
| { |
| boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature); |
| if (isMany(feature)) |
| { |
| if (feature.isUnique() && contains(feature, object)) |
| { |
| throw new IllegalArgumentException("The 'no duplicates' constraint is violated"); |
| } |
| } |
| else |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| throw new IllegalArgumentException("The multiplicity constraint is violated"); |
| } |
| } |
| } |
| |
| doAdd(entryIndex(feature, index), isFeatureMap ? (Entry)object : createEntry(feature, object)); |
| } |
| |
| public boolean addAll(int index, EStructuralFeature feature, Collection<?> collection) |
| { |
| if (collection.isEmpty()) |
| { |
| return false; |
| } |
| boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature); |
| @SuppressWarnings("unchecked") Collection<Entry> entryCollection = |
| isFeatureMap ? |
| (Collection<Entry>)collection : |
| new BasicEList<Entry>(collection.size()); |
| if (isMany(feature)) |
| { |
| if (feature.isUnique()) |
| { |
| for (Object object : collection) |
| { |
| if (!contains(feature, object)) |
| { |
| Entry entry = createEntry(feature, object); |
| if (!entryCollection.contains(entry)) |
| { |
| entryCollection.add(entry); |
| } |
| } |
| } |
| } |
| else if (!isFeatureMap) |
| { |
| for (Object object : collection) |
| { |
| Entry entry = createEntry(feature, object); |
| entryCollection.add(entry); |
| } |
| } |
| } |
| else |
| { |
| if (collection.size() > 1) |
| { |
| throw new IllegalArgumentException("The multiplicity constraint is violated"); |
| } |
| |
| if (isFeatureMap) |
| { |
| if (contains(feature, collection.iterator().next())) |
| { |
| return false; |
| } |
| } |
| else |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (collection.contains(entry.getValue())) |
| { |
| return false; |
| } |
| else |
| { |
| throw new IllegalArgumentException("The multiplicity constraint is violated"); |
| } |
| } |
| } |
| Entry entry = createEntry(feature, collection.iterator().next()); |
| entryCollection.add(entry); |
| } |
| } |
| |
| return doAddAll(index, entryCollection); |
| } |
| |
| public boolean addAll(EStructuralFeature feature, Collection<?> collection) |
| { |
| if (collection.isEmpty()) |
| { |
| return false; |
| } |
| boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature); |
| @SuppressWarnings("unchecked") Collection<Entry> entryCollection = |
| isFeatureMap ? |
| (Collection<Entry>)collection : |
| new BasicEList<Entry>(collection.size()); |
| if (isMany(feature)) |
| { |
| if (feature.isUnique()) |
| { |
| for (Object object : collection) |
| { |
| if (!contains(feature, object)) |
| { |
| Entry entry = createEntry(feature, object); |
| if (!entryCollection.contains(entry)) |
| { |
| entryCollection.add(entry); |
| } |
| } |
| } |
| } |
| else if (!isFeatureMap) |
| { |
| for (Object object : collection) |
| { |
| Entry entry = createEntry(feature, object); |
| entryCollection.add(entry); |
| } |
| } |
| } |
| else |
| { |
| if (collection.size() > 1) |
| { |
| throw new IllegalArgumentException("The multiplicity constraint is violated"); |
| } |
| |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (collection.contains(isFeatureMap ? entry : entry.getValue())) |
| { |
| return false; |
| } |
| else |
| { |
| for (Object object : collection) |
| { |
| doSet(i, isFeatureMap ? (Entry)object : createEntry(feature, object)); |
| } |
| return true; |
| } |
| } |
| } |
| if (!isFeatureMap) |
| { |
| Entry entry = createEntry(feature, collection.iterator().next()); |
| entryCollection.add(entry); |
| } |
| } |
| |
| return doAddAll(entryCollection); |
| } |
| |
| public boolean addAll(EStructuralFeature feature, int index, Collection<?> collection) |
| { |
| if (collection.isEmpty()) |
| { |
| return false; |
| } |
| boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature); |
| @SuppressWarnings("unchecked") Collection<Entry> entryCollection = |
| isFeatureMap ? |
| (Collection<Entry>)collection : |
| new BasicEList<Entry>(collection.size()); |
| if (isMany(feature)) |
| { |
| if (feature.isUnique()) |
| { |
| for (Object object : collection) |
| { |
| if (!contains(feature, object)) |
| { |
| Entry entry = createEntry(feature, object); |
| entryCollection.add(entry); |
| } |
| } |
| } |
| else if (!isFeatureMap) |
| { |
| for (Object object : collection) |
| { |
| Entry entry = createEntry(feature, object); |
| entryCollection.add(entry); |
| } |
| } |
| } |
| else |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| throw new IllegalArgumentException("The multiplicity constraint is violated"); |
| } |
| } |
| |
| if (collection.size() > 1) |
| { |
| throw new IllegalArgumentException("The multiplicity constraint is violated"); |
| } |
| |
| if (!isFeatureMap) |
| { |
| Entry entry = createEntry(feature, collection.iterator().next()); |
| entryCollection.add(entry); |
| } |
| } |
| |
| return doAddAll(entryIndex(feature, index), entryCollection); |
| } |
| |
| public void addUnique(EStructuralFeature feature, Object object) |
| { |
| modCount = -1; |
| addUnique(createRawEntry(feature, object)); |
| } |
| |
| public void addUnique(EStructuralFeature feature, int index, Object object) |
| { |
| modCount = -1; |
| addUnique(entryIndex(feature, index), createRawEntry(feature, object)); |
| } |
| |
| @Override |
| public void addUnique(Entry object) |
| { |
| // Validate now since the call we make after will skip validating. |
| ++modCount; |
| validate(size, object); |
| |
| addUnique((FeatureMap.Entry.Internal)object); |
| } |
| |
| public void addUnique(Entry.Internal entry) |
| { |
| modCount = -1; |
| if (isNotificationRequired()) |
| { |
| int index = size; |
| boolean oldIsSet = isSet(); |
| doAddUnique(entry); |
| NotificationImpl notification = createNotification(Notification.ADD, null, entry, index, oldIsSet); |
| if (hasInverse()) |
| { |
| NotificationChain notifications = inverseAdd(entry, null); |
| notifications = shadowAdd(entry, notifications); |
| |
| if (notifications == null) |
| { |
| dispatchNotification(notification); |
| } |
| else |
| { |
| notifications.add(notification); |
| notifications.dispatch(); |
| } |
| } |
| else |
| { |
| dispatchNotification(notification); |
| } |
| } |
| else |
| { |
| doAddUnique(entry); |
| NotificationChain notifications = inverseAdd(entry, null); |
| if (notifications != null) notifications.dispatch(); |
| } |
| } |
| |
| @Override |
| public boolean addAllUnique(Collection<? extends Entry> collection) |
| { |
| modCount = -1; |
| return super.addAllUnique(collection); |
| } |
| |
| public boolean addAllUnique(FeatureMap.Entry.Internal [] entries, int start, int end) |
| { |
| return addAllUnique(size, entries, start, end); |
| } |
| |
| public boolean addAllUnique(int index, FeatureMap.Entry.Internal [] entries, int start, int end) |
| { |
| modCount = -1; |
| |
| int collectionSize = end - start; |
| if (collectionSize == 0) |
| { |
| return false; |
| } |
| else |
| { |
| if (isNotificationRequired()) |
| { |
| boolean oldIsSet = isSet(); |
| doAddAllUnique(index, entries, start, end); |
| NotificationImpl notification; |
| if (collectionSize == 0) |
| { |
| notification = createNotification(Notification.ADD, null, entries[0], index, oldIsSet); |
| } |
| else |
| { |
| if (start != 0 || end != entries.length) |
| { |
| Object [] actualObjects = new Object [collectionSize]; |
| for (int i = 0, j = start; j < end; ++i, ++j) |
| { |
| actualObjects[i] = entries[j]; |
| } |
| notification = createNotification(Notification.ADD_MANY, null, actualObjects, index, oldIsSet); |
| } |
| else |
| { |
| notification = createNotification(Notification.ADD_MANY, null, entries, index, oldIsSet); |
| } |
| } |
| NotificationChain notifications = null; |
| for (int i = start; i < end; ++i) |
| { |
| FeatureMap.Entry.Internal value = entries[i]; |
| notifications = inverseAdd(value, notifications); |
| notifications = shadowAdd(value, notifications); |
| } |
| if (notifications == null) |
| { |
| dispatchNotification(notification); |
| } |
| else |
| { |
| notifications.add(notification); |
| notifications.dispatch(); |
| } |
| } |
| else |
| { |
| doAddAllUnique(index, entries, start, end); |
| NotificationChain notifications = null; |
| for (int i = start; i < end; ++i) |
| { |
| notifications = inverseAdd(entries[i], notifications); |
| } |
| if (notifications != null) notifications.dispatch(); |
| } |
| |
| return true; |
| } |
| } |
| |
| public NotificationChain basicAdd(EStructuralFeature feature, Object object, NotificationChain notifications) |
| { |
| if (object == null) |
| { |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (entry.getEStructuralFeature() == feature) |
| { |
| return super.basicRemove(entry, notifications); |
| } |
| } |
| } |
| |
| Entry entry = FeatureMapUtil.isFeatureMap(feature) ? (Entry)object : createEntry(feature, object); |
| |
| if (isNotificationRequired()) |
| { |
| boolean oldIsSet = !isEmpty(feature); |
| notifications = basicAdd(entry, notifications); |
| NotificationImpl notification = |
| feature.isMany() ? |
| createNotification |
| (Notification.ADD, |
| feature, |
| null, |
| object, |
| indexOf(feature, object), |
| oldIsSet) : |
| createNotification |
| (Notification.SET, |
| feature, |
| feature.getDefaultValue(), |
| object, |
| Notification.NO_INDEX, |
| oldIsSet); |
| |
| if (notifications != null) |
| { |
| notifications.add(notification); |
| } |
| else |
| { |
| notifications = notification; |
| } |
| } |
| else |
| { |
| notifications = basicAdd(entry, notifications); |
| } |
| return notifications; |
| } |
| |
| public boolean remove(EStructuralFeature feature, Object object) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| if (FeatureMapUtil.isFeatureMap(feature)) |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (entry.equals(object)) |
| { |
| remove(i); |
| return true; |
| } |
| } |
| } |
| } |
| else if (object != null) |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (object.equals(entry.getValue())) |
| { |
| remove(i); |
| return true; |
| } |
| } |
| } |
| } |
| else |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (entry.getValue() == null) |
| { |
| remove(i); |
| return true; |
| } |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| public Object remove(EStructuralFeature feature, int index) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| int count = 0; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (count == index) |
| { |
| remove(i); |
| return FeatureMapUtil.isFeatureMap(feature) ? entry : entry.getValue(); |
| } |
| ++count; |
| } |
| } |
| |
| throw new IndexOutOfBoundsException("index=" + index + ", size=" + count); |
| } |
| |
| public boolean removeAll(EStructuralFeature feature, Collection<?> collection) |
| { |
| if (FeatureMapUtil.isFeatureMap(feature)) |
| { |
| return removeAll(collection); |
| } |
| else |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| List<Entry> entryCollection = new BasicEList<Entry>(collection.size()); |
| Entry [] entries = (Entry[])data; |
| for (int i = size; --i >= 0; ) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (collection.contains(entry.getValue())) |
| { |
| entryCollection.add(entry); |
| } |
| } |
| } |
| |
| return removeAll(entryCollection); |
| } |
| } |
| |
| public NotificationChain basicRemove(EStructuralFeature feature, Object object, NotificationChain notifications) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| int count = 0; |
| Entry [] entries = (Entry[])data; |
| Entry match = null; |
| if (FeatureMapUtil.isFeatureMap(feature)) |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (entry.equals(object)) |
| { |
| match = entry; |
| break; |
| } |
| ++count; |
| } |
| } |
| } |
| else if (object != null) |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (object.equals(entry.getValue())) |
| { |
| match = entry; |
| break; |
| } |
| ++count; |
| } |
| } |
| } |
| else |
| { |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (entry.getValue() == null) |
| { |
| match = entry; |
| break; |
| } |
| ++count; |
| } |
| } |
| } |
| |
| if (match != null) |
| { |
| if (isNotificationRequired()) |
| { |
| NotificationImpl notification = |
| feature.isMany() ? |
| createNotification |
| (Notification.REMOVE, |
| feature, |
| object, |
| null, |
| count, |
| true) : |
| createNotification |
| (feature.isUnsettable() ? Notification.UNSET : Notification.SET, |
| feature, |
| object, |
| feature.getDefaultValue(), |
| Notification.NO_INDEX, |
| true); |
| |
| if (notifications != null) |
| { |
| notifications.add(notification); |
| } |
| else |
| { |
| notifications = notification; |
| } |
| } |
| notifications = basicRemove(match, notifications); |
| } |
| |
| return notifications; |
| } |
| |
| public boolean retainAll(EStructuralFeature feature, Collection<?> collection) |
| { |
| boolean isFeatureMap = FeatureMapUtil.isFeatureMap(feature); |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| List<Entry> entryCollection = new BasicEList<Entry>(collection.size()); |
| Entry [] entries = (Entry[])data; |
| for (int i = size; --i >= 0; ) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (!collection.contains(isFeatureMap ? entry : entry.getValue())) |
| { |
| entryCollection.add(entry); |
| } |
| } |
| } |
| |
| return removeAll(entryCollection); |
| } |
| |
| public void clear(EStructuralFeature feature) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| List<Entry> entryCollection = new BasicEList<Entry>(); |
| Entry [] entries = (Entry[])data; |
| for (int i = size; --i >= 0; ) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| entryCollection.add(entry); |
| } |
| } |
| |
| if (!removeAll(entryCollection) && owner.eNotificationRequired()) |
| { |
| dispatchNotification |
| (feature.isMany() ? |
| createNotification |
| (Notification.REMOVE_MANY, |
| feature, |
| Collections.EMPTY_LIST, |
| null, |
| Notification.NO_INDEX, |
| false) : |
| createNotification |
| (feature.isUnsettable() ? Notification.UNSET : Notification.SET, |
| feature, |
| null, |
| null, |
| Notification.NO_INDEX, |
| false)); |
| } |
| } |
| |
| public void move(EStructuralFeature feature, int index, Object object) |
| { |
| move(feature, index, indexOf(feature, object)); |
| } |
| |
| public Object move(EStructuralFeature feature, int targetIndex, int sourceIndex) |
| { |
| if (isMany(feature)) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| Object result = null; |
| int entryTargetIndex = -1; |
| int entrySourceIndex = -1; |
| int count = 0; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (count == targetIndex) |
| { |
| entryTargetIndex = i; |
| } |
| if (count == sourceIndex) |
| { |
| entrySourceIndex = i; |
| result = entry.getValue(); |
| } |
| ++count; |
| } |
| } |
| if (entryTargetIndex == -1) |
| { |
| throw new IndexOutOfBoundsException("targetIndex=" + targetIndex + ", size=" + count); |
| } |
| if (entrySourceIndex == -1) |
| { |
| throw new IndexOutOfBoundsException("sourceIndex=" + sourceIndex + ", size=" + count); |
| } |
| |
| super.move(entryTargetIndex, entrySourceIndex); |
| |
| if (isNotificationRequired()) |
| { |
| dispatchNotification |
| (createNotification |
| (Notification.MOVE, |
| feature, |
| sourceIndex, |
| result, |
| targetIndex, |
| true)); |
| } |
| |
| return result; |
| } |
| else |
| { |
| throw new IllegalArgumentException("The feature must be many-valued to support move"); |
| } |
| } |
| |
| public Object get(EStructuralFeature feature, boolean resolve) |
| { |
| Entry [] entries = (Entry[])data; |
| if (isMany(feature)) |
| { |
| return list(feature); |
| } |
| else |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| int count = 0; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| EStructuralFeature entryFeature = entry.getEStructuralFeature(); |
| if (validator.isValid(entryFeature)) |
| { |
| if (FeatureMapUtil.isFeatureMap(feature)) |
| { |
| return entry; |
| } |
| else if (entryFeature == XMLTypeFeatures.TEXT || entryFeature == XMLTypeFeatures.CDATA) |
| { |
| StringBuilder result = new StringBuilder(entry.getValue().toString()); |
| while (++i < size) |
| { |
| entry = entries[i]; |
| entryFeature = entry.getEStructuralFeature(); |
| if (entryFeature == XMLTypeFeatures.TEXT || entryFeature == XMLTypeFeatures.CDATA) |
| { |
| result.append(entry.getValue().toString()); |
| } |
| } |
| return EcoreUtil.createFromString((EDataType)feature.getEType(), result.toString()); |
| } |
| else |
| { |
| Object value = entry.getValue(); |
| if (value != null && resolve && isResolveProxies(feature)) |
| { |
| value = resolveProxy(feature, i, count, value); |
| } |
| return value; |
| } |
| } |
| ++count; |
| } |
| |
| return feature.getDefaultValue(); |
| } |
| } |
| |
| public Object get(EStructuralFeature feature, int index, boolean resolve) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| if (isMany(feature)) |
| { |
| int count = 0; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (count == index) |
| { |
| if (FeatureMapUtil.isFeatureMap(feature)) |
| { |
| return entry; |
| } |
| else |
| { |
| Object value = entry.getValue(); |
| if (value != null && resolve && isResolveProxies(feature)) |
| { |
| value = resolveProxy(feature, i, count, value); |
| } |
| return value; |
| } |
| } |
| ++count; |
| } |
| } |
| throw new IndexOutOfBoundsException("index=" + index + ", size=" + count); |
| } |
| else |
| { |
| int count = 0; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (FeatureMapUtil.isFeatureMap(feature)) |
| { |
| return entry; |
| } |
| else |
| { |
| Object value = entry.getValue(); |
| if (value != null && resolve && isResolveProxies(feature)) |
| { |
| value = resolveProxy(feature, i, count, value); |
| } |
| return value; |
| } |
| } |
| ++count; |
| } |
| |
| return feature.getDefaultValue(); |
| } |
| } |
| |
| public Object set(EStructuralFeature feature, int index, Object object) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| if (isMany(feature)) |
| { |
| if (feature.isUnique()) |
| { |
| int currentIndex = indexOf(feature, object); |
| if (currentIndex >=0 && currentIndex != index) |
| { |
| throw new IllegalArgumentException("The 'no duplicates' constraint is violated"); |
| } |
| } |
| |
| int count = 0; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (count == index) |
| { |
| return doSet(i, FeatureMapUtil.isFeatureMap(feature) ? (Entry)object : createEntry(feature, object)); |
| } |
| ++count; |
| } |
| } |
| throw new IndexOutOfBoundsException("index=" + index + ", size=" + count); |
| } |
| else |
| { |
| // Index should be -1. |
| |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| return FeatureMapUtil.isFeatureMap(feature) ? entry : entry.getValue(); |
| } |
| } |
| |
| return null; |
| } |
| } |
| |
| public Object setUnique(EStructuralFeature feature, int index, Object object) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| Entry [] entries = (Entry[])data; |
| if (isMany(feature)) |
| { |
| int count = 0; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (count == index) |
| { |
| return setUnique(i, FeatureMapUtil.isFeatureMap(feature) ? (Entry)object : createEntry(feature, object)); |
| } |
| ++count; |
| } |
| } |
| throw new IndexOutOfBoundsException("index=" + index + ", size=" + count); |
| } |
| else |
| { |
| // Index should be -1. |
| |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| return setUnique(i, FeatureMapUtil.isFeatureMap(feature) ? (Entry)object : createEntry(feature, object)); |
| } |
| } |
| |
| return feature.getDefaultValue(); |
| } |
| } |
| |
| public boolean isSet(EStructuralFeature feature) |
| { |
| return !isEmpty(feature); |
| } |
| |
| public void unset(EStructuralFeature feature) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| List<Entry> removals = null; |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| if (removals == null) |
| { |
| removals = new BasicEList<Entry>(); |
| } |
| removals.add(entry); |
| } |
| } |
| |
| if (removals != null) |
| { |
| removeAll(removals); |
| } |
| } |
| |
| @Override |
| public NotificationChain basicRemove(Object object, NotificationChain notifications) |
| { |
| // This may be called directly on an EObject for the case of a containment. |
| // |
| if (object instanceof FeatureMap.Entry) |
| { |
| return super.basicRemove(object, notifications); |
| } |
| else |
| { |
| Entry match = null; |
| EStructuralFeature feature = null; |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < size; ++i) |
| { |
| Entry entry = entries[i]; |
| if (object.equals(entry.getValue())) |
| { |
| feature = entry.getEStructuralFeature(); |
| if (feature instanceof EReference && ((EReference)feature).isContainment()) |
| { |
| match = entry; |
| break; |
| } |
| } |
| } |
| |
| if (match != null) |
| { |
| if (isNotificationRequired()) |
| { |
| NotificationImpl notification = |
| feature.isMany() ? |
| createNotification |
| (Notification.REMOVE, |
| feature, |
| object, |
| null, |
| indexOf(feature, object), |
| true) : |
| createNotification |
| (feature.isUnsettable() ? Notification.UNSET : Notification.SET, |
| feature, |
| object, |
| feature.getDefaultValue(), |
| Notification.NO_INDEX, |
| true); |
| |
| if (notifications != null) |
| { |
| notifications.add(notification); |
| } |
| else |
| { |
| notifications = notification; |
| } |
| } |
| notifications = basicRemove(match, notifications); |
| } |
| |
| return notifications; |
| } |
| } |
| |
| /** |
| * ------------------------------------------- |
| */ |
| public static class FeatureEIterator<E> extends FeatureMapUtil.BasicFeatureEIterator<E> |
| { |
| public FeatureEIterator(EStructuralFeature eStructuralFeature, FeatureMap.Internal featureMap) |
| { |
| super(eStructuralFeature, featureMap); |
| } |
| |
| @Override |
| protected boolean scanNext() |
| { |
| int size = featureMap.size(); |
| Entry [] entries = (Entry [])((BasicEList<?>)featureMap).data(); |
| while (entryCursor < size) |
| { |
| Entry entry = entries[entryCursor]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| preparedResult = extractValue(entry); |
| prepared = 2; |
| return true; |
| } |
| ++entryCursor; |
| } |
| |
| prepared = 1; |
| lastCursor = -1; |
| return false; |
| } |
| |
| @Override |
| protected boolean scanPrevious() |
| { |
| Entry [] entries = (Entry [])((BasicEList<?>)featureMap).data(); |
| while (--entryCursor >= 0) |
| { |
| Entry entry = entries[entryCursor]; |
| if (validator.isValid(entry.getEStructuralFeature())) |
| { |
| preparedResult = extractValue(entry); |
| prepared = -2; |
| return true; |
| } |
| } |
| |
| prepared = -1; |
| lastCursor = -1; |
| return false; |
| } |
| } |
| |
| /** |
| * ------------------------------------------- |
| */ |
| public static class ResolvingFeatureEIterator<E> extends FeatureEIterator<E> |
| { |
| public ResolvingFeatureEIterator(EStructuralFeature eStructuralFeature, FeatureMap.Internal featureMap) |
| { |
| super(eStructuralFeature, featureMap); |
| } |
| |
| @Override |
| protected boolean resolve() |
| { |
| return true; |
| } |
| } |
| |
| /** |
| * Temporary for testing purposes only. |
| */ |
| public static class FeatureMapEObjectImpl extends org.eclipse.emf.ecore.impl.EObjectImpl |
| { |
| protected BasicFeatureMap featureMap = new BasicFeatureMap(this, -1); |
| |
| public FeatureMapEObjectImpl() |
| { |
| super(); |
| } |
| |
| @Override |
| public Object eDynamicGet(EStructuralFeature eFeature, boolean resolve) |
| { |
| if (eFeature instanceof EReference && ((EReference)eFeature).isContainer()) |
| { |
| return eSettingDelegate(eFeature).dynamicGet(this, null, -1, true, true); |
| } |
| else |
| { |
| return featureMap.setting(eFeature).get(resolve); |
| } |
| } |
| |
| @Override |
| public void eDynamicSet(EStructuralFeature eFeature, Object newValue) |
| { |
| if (eFeature instanceof EReference && ((EReference)eFeature).isContainer()) |
| { |
| eSettingDelegate(eFeature).dynamicSet(this, null, -1, newValue); |
| } |
| else |
| { |
| if (!eFeature.isUnsettable()) |
| { |
| Object defaultValue = eFeature.getDefaultValue(); |
| if (defaultValue == null ? newValue == null : defaultValue.equals(newValue)) |
| { |
| featureMap.setting(eFeature).unset(); |
| return; |
| } |
| } |
| featureMap.setting(eFeature).set(newValue); |
| } |
| } |
| |
| @Override |
| public void eDynamicUnset(EStructuralFeature eFeature) |
| { |
| if (eFeature instanceof EReference && ((EReference)eFeature).isContainer()) |
| { |
| eSettingDelegate(eFeature).dynamicUnset(this, null, -1); |
| } |
| else |
| { |
| featureMap.setting(eFeature).unset(); |
| } |
| } |
| |
| @Override |
| public boolean eDynamicIsSet(EStructuralFeature eFeature) |
| { |
| if (eFeature instanceof EReference && ((EReference)eFeature).isContainer()) |
| { |
| return eSettingDelegate(eFeature).dynamicIsSet(this, null, -1); |
| } |
| else |
| { |
| return featureMap.setting(eFeature).isSet(); |
| } |
| } |
| |
| @Override |
| public NotificationChain eDynamicInverseAdd(InternalEObject otherEnd, int featureID, Class<?> inverseClass, NotificationChain notifications) |
| { |
| EStructuralFeature.Internal feature = (EStructuralFeature.Internal)eClass().getEStructuralFeature(featureID); |
| if (feature.isMany()) |
| { |
| return featureMap.basicAdd(feature, otherEnd, notifications); |
| } |
| else if (feature instanceof EReference && ((EReference)feature).isContainer()) |
| { |
| return eSettingDelegate(feature).dynamicInverseAdd(this, null, -1, otherEnd, notifications); |
| } |
| else |
| { |
| InternalEObject oldValue = (InternalEObject)eDynamicGet(feature, false); |
| if (oldValue != null) |
| { |
| notifications = oldValue.eInverseRemove |
| (this, oldValue.eClass().getFeatureID(((EReference)feature).getEOpposite()), null, notifications); |
| notifications = featureMap.basicRemove(feature, oldValue, notifications); |
| } |
| |
| return featureMap.basicAdd(feature, otherEnd, notifications); |
| } |
| } |
| |
| @Override |
| public NotificationChain eDynamicInverseRemove(InternalEObject otherEnd, int featureID, Class<?> inverseClass, NotificationChain notifications) |
| { |
| EStructuralFeature.Internal feature = (EStructuralFeature.Internal)eClass().getEStructuralFeature(featureID); |
| if (feature instanceof EReference && ((EReference)feature).isContainer()) |
| { |
| return eSettingDelegate(feature).dynamicInverseRemove(this, null, -1, otherEnd, notifications); |
| } |
| else |
| { |
| return featureMap.basicRemove(feature, otherEnd, notifications); |
| } |
| } |
| |
| public FeatureMap featureMap() |
| { |
| return featureMap; |
| } |
| |
| @Override |
| public void eNotify(Notification notification) |
| { |
| if (notification.getFeatureID(null) != -1) |
| { |
| super.eNotify(notification); |
| } |
| } |
| |
| @Override |
| public String toString() |
| { |
| String result = super.toString(); |
| result = "org.eclipse.emf.ecore.impl.EObjectImpl" + result.substring(result.indexOf("@")); |
| return result; |
| } |
| } |
| |
| @Override |
| public void set(Object newValue) |
| { |
| super.set(newValue instanceof FeatureMap ? newValue : ((FeatureMap.Internal.Wrapper)newValue).featureMap()); |
| } |
| |
| @Override |
| protected Entry resolve(int index, Entry entry) |
| { |
| EStructuralFeature feature = entry.getEStructuralFeature(); |
| if (isResolveProxies(feature)) |
| { |
| InternalEObject object = (InternalEObject)entry.getValue(); |
| EObject resolved = resolveProxy(object); |
| if (resolved != object) |
| { |
| Entry newEntry = createEntry(feature, resolved); |
| assign(index, validate(index, newEntry)); |
| didSet(index, newEntry, entry); |
| |
| NotificationChain notifications = null; |
| |
| // Produce a proxy resolve notification for the reference feature of the owner, if there is one. |
| // |
| if (isNotificationRequired()) |
| { |
| EStructuralFeature affiliatedFeature = ExtendedMetaData.INSTANCE.getAffiliation(owner.eClass(), feature); |
| if (affiliatedFeature != getEStructuralFeature()) |
| { |
| FeatureMapUtil.Validator validator = FeatureMapUtil.getValidator(owner.eClass(), feature); |
| int featureIndex = 0; |
| Entry [] entries = (Entry[])data; |
| for (int i = 0; i < index; ++i) |
| { |
| Entry affliatedEntry = entries[i]; |
| if (validator.isValid(affliatedEntry.getEStructuralFeature())) |
| { |
| ++featureIndex; |
| } |
| } |
| |
| notifications = |
| createNotification |
| (Notification.RESOLVE, |
| affiliatedFeature, |
| object, |
| resolved, |
| featureIndex, |
| false); |
| |
| notifications.add(createNotification(Notification.RESOLVE, entry, newEntry, index, false)); |
| } |
| } |
| |
| EReference reference = (EReference)feature; |
| EReference opposite = reference.getEOpposite(); |
| if (opposite != null) |
| { |
| notifications = object.eInverseRemove(owner, object.eClass().getFeatureID(opposite), null, notifications); |
| notifications = ((InternalEObject)resolved).eInverseAdd(owner, resolved.eClass().getFeatureID(opposite), null, notifications); |
| } |
| else if (reference.isContainment()) |
| { |
| int inverseFeatureID = InternalEObject.EOPPOSITE_FEATURE_BASE - owner.eClass().getFeatureID(reference); |
| notifications = object.eInverseRemove(owner, inverseFeatureID, null, null); |
| if (((InternalEObject)resolved).eInternalContainer() == null) |
| { |
| notifications = ((InternalEObject)resolved).eInverseAdd(owner, inverseFeatureID, null, notifications); |
| } |
| } |
| if (notifications != null) |
| { |
| notifications.dispatch(); |
| } |
| |
| return newEntry; |
| } |
| } |
| return entry; |
| } |
| } |