001 /*
002 * Copyright (c) 2006, 2007 IBM Corporation and others.
003 * All rights reserved. This program and the accompanying materials
004 * are made available under the terms of the Eclipse Public License v1.0
005 * which accompanies this distribution, and is available at
006 * http://www.eclipse.org/legal/epl-v10.html
007 *
008 * Contributors:
009 * IBM - initial API and implementation
010 *
011 * $Id: SubsetSupersetEObjectEList.java,v 1.6 2007/04/04 03:15:12 khussey Exp $
012 */
013 package org.eclipse.uml2.common.util;
014
015 import java.util.Collection;
016 import java.util.Iterator;
017
018 import org.eclipse.emf.common.notify.Notification;
019 import org.eclipse.emf.common.notify.NotificationChain;
020 import org.eclipse.emf.common.util.EList;
021 import org.eclipse.emf.ecore.EStructuralFeature;
022 import org.eclipse.emf.ecore.InternalEObject;
023 import org.eclipse.emf.ecore.resource.Resource;
024 import org.eclipse.emf.ecore.util.EObjectEList;
025
026 /**
027 * A list that enforces subset/superset consraints. Specifically, when an
028 * element is added to a subset, it is also added to the associated superset(s),
029 * if not already present; when an element is removed from a superset, it is
030 * also removed from the associated subset(s), if present.
031 *
032 * @since 1.2
033 */
034 public class SubsetSupersetEObjectEList<E>
035 extends EObjectEList<E> {
036
037 private static final long serialVersionUID = 1L;
038
039 public static class Unsettable<E>
040 extends SubsetSupersetEObjectEList<E> {
041
042 private static final long serialVersionUID = 1L;
043
044 protected boolean isSet;
045
046 public Unsettable(Class<?> dataClass, InternalEObject owner,
047 int featureID, int[] supersetFeatureIDs, int[] subsetFeatureIDs) {
048 super(dataClass, owner, featureID, supersetFeatureIDs,
049 subsetFeatureIDs);
050 }
051
052 @Override
053 protected void didChange() {
054 isSet = true;
055 }
056
057 @Override
058 public boolean isSet() {
059 return isSet;
060 }
061
062 @Override
063 public void unset() {
064 super.unset();
065
066 if (isNotificationRequired()) {
067 boolean oldIsSet = isSet;
068 isSet = false;
069
070 owner.eNotify(createNotification(Notification.UNSET, oldIsSet,
071 false));
072 } else {
073 isSet = false;
074 }
075 }
076 }
077
078 /**
079 * An array of superset feature identifiers.
080 */
081 protected final int[] supersetFeatureIDs;
082
083 /**
084 * An array of subset feature identifiers.
085 */
086 protected final int[] subsetFeatureIDs;
087
088 public SubsetSupersetEObjectEList(Class<?> dataClass,
089 InternalEObject owner, int featureID, int[] supersetFeatureIDs,
090 int[] subsetFeatureIDs) {
091 super(dataClass, owner, featureID);
092
093 this.supersetFeatureIDs = supersetFeatureIDs;
094 this.subsetFeatureIDs = subsetFeatureIDs;
095 }
096
097 /**
098 * Indicates whether subset constraints should be enforced.
099 *
100 * @return <code>true</code> if subset constraints should be enforced;
101 * <code>false</code> otherwise.
102 */
103 protected boolean enforceSubsetConstraints() {
104 Resource.Internal eInternalResource = owner.eInternalResource();
105 return eInternalResource == null || !eInternalResource.isLoading();
106 }
107
108 /**
109 * Adds the specified element to the superset(s).
110 *
111 * @param object
112 * The element to be added.
113 */
114 protected void supersetAdd(Object object) {
115
116 if (supersetFeatureIDs != null && enforceSubsetConstraints()) {
117
118 for (int i = 0; i < supersetFeatureIDs.length; i++) {
119 EStructuralFeature supersetEStructuralFeature = owner.eClass()
120 .getEStructuralFeature(supersetFeatureIDs[i]);
121
122 if (supersetEStructuralFeature.isMany()) {
123 @SuppressWarnings("unchecked")
124 EList<Object> supersetEList = (EList<Object>) owner
125 .eGet(supersetEStructuralFeature);
126
127 if (!supersetEList.contains(object)) {
128 supersetEList.add(object);
129 }
130 }
131 }
132 }
133 }
134
135 /**
136 * Indicates whether superset constraints should be enforced.
137 *
138 * @return <code>true</code> if superset constraints should be enforced;
139 * <code>false</code> otherwise.
140 */
141 protected boolean enforceSupersetConstraints() {
142 return true;
143 }
144
145 /**
146 * Removes the specified element from the subset(s).
147 *
148 * @param object
149 * The element to be removed.
150 */
151 protected void subsetRemove(Object object) {
152
153 if (subsetFeatureIDs != null && enforceSupersetConstraints()) {
154
155 for (int i = 0; i < subsetFeatureIDs.length; i++) {
156 EStructuralFeature subsetEStructuralFeature = owner.eClass()
157 .getEStructuralFeature(subsetFeatureIDs[i]);
158
159 if (subsetEStructuralFeature.isMany()) {
160 @SuppressWarnings("unchecked")
161 EList<Object> list = ((EList<Object>) owner
162 .eGet(subsetEStructuralFeature));
163 list.remove(object);
164 } else if (object.equals(owner.eGet(subsetEStructuralFeature))) {
165 owner.eSet(subsetEStructuralFeature, null);
166 }
167 }
168 }
169 }
170
171 @Override
172 public NotificationChain basicAdd(E object, NotificationChain notifications) {
173 notifications = super.basicAdd(object, notifications);
174
175 supersetAdd(object);
176
177 return notifications;
178 }
179
180 @Override
181 public NotificationChain basicSet(int index, E object,
182 NotificationChain notifications) {
183 Object oldObject = data[index];
184
185 notifications = super.basicSet(index, object, notifications);
186
187 supersetAdd(object);
188
189 if (oldObject != object) {
190 subsetRemove(oldObject);
191 }
192
193 return notifications;
194 }
195
196 @Override
197 public void add(int index, E object) {
198 super.add(index, object);
199
200 supersetAdd(object);
201 }
202
203 @Override
204 public boolean add(E object) {
205 boolean result = super.add(object);
206
207 supersetAdd(object);
208
209 return result;
210 }
211
212 @Override
213 public boolean addAll(Collection<? extends E> collection) {
214 boolean result = super.addAll(collection);
215
216 for (Iterator<? extends E> elements = collection.iterator(); elements
217 .hasNext();) {
218
219 supersetAdd(elements.next());
220 }
221
222 return result;
223 }
224
225 @Override
226 public boolean addAll(int index, Collection<? extends E> collection) {
227 boolean result = super.addAll(index, collection);
228
229 for (Iterator<? extends E> elements = collection.iterator(); elements
230 .hasNext();) {
231
232 supersetAdd(elements.next());
233 }
234
235 return result;
236 }
237
238 @Override
239 public E set(int index, E object) {
240 E result = super.set(index, object);
241
242 supersetAdd(object);
243
244 if (result != object) {
245 subsetRemove(result);
246 }
247
248 return result;
249 }
250
251 @Override
252 protected void didRemove(int index, E oldObject) {
253 super.didRemove(index, oldObject);
254
255 subsetRemove(oldObject);
256 }
257
258 }