001 /**
002 * <copyright>
003 *
004 * Copyright (c) 2002-2009 IBM Corporation and others.
005 * All rights reserved. This program and the accompanying materials
006 * are made available under the terms of the Eclipse Public License v1.0
007 * which accompanies this distribution, and is available at
008 * http://www.eclipse.org/legal/epl-v10.html
009 *
010 * Contributors:
011 * IBM - Initial API and implementation
012 *
013 * </copyright>
014 *
015 * $Id: BasicNotifierImpl.java,v 1.7 2010/03/05 15:50:31 emerks Exp $
016 */
017 package org.eclipse.emf.common.notify.impl;
018
019
020 import java.util.Collection;
021
022 import org.eclipse.emf.common.notify.Adapter;
023 import org.eclipse.emf.common.notify.Notification;
024 import org.eclipse.emf.common.notify.Notifier;
025 import org.eclipse.emf.common.util.BasicEList;
026 import org.eclipse.emf.common.util.ECollections;
027 import org.eclipse.emf.common.util.EList;
028
029
030 /**
031 * An extensible notifier implementation.
032 */
033 public class BasicNotifierImpl implements Notifier
034 {
035 /**
036 * Creates a blank new instance.
037 */
038 public BasicNotifierImpl()
039 {
040 super();
041 }
042
043 /**
044 * An interface implemented by {@link BasicNotifierImpl#eAdapters() adapter lists}
045 * that allows {@link BasicNotifierImpl.EObservableAdapterList.Listener listeners} to observe {@link Adapter adapters} being added and removed.
046 * @since 2.6
047 */
048 public interface EObservableAdapterList
049 {
050 /**
051 * An interface implemented by clients wishing to observe {@link Adapter adapters} being added and removed from an {@link BasicNotifierImpl#eAdapters() adapter lists}.
052 * @since 2.6
053 */
054 interface Listener
055 {
056 /**
057 * Called when the given adapter is added to the given notifier.
058 * @param notifier the notifier being adapted.
059 * @param adapter the adapter being added to the notifier.
060 */
061 void added(Notifier notifier, Adapter adapter);
062
063 /**
064 * Called when the given adapter is remove from the given notifier.
065 * @param notifier the notifier that was being adapted.
066 * @param adapter the adapter being removed from the notifier.
067 */
068 void removed(Notifier notifier, Adapter adapter);
069 }
070
071 /**
072 * Adds another listener from the adapter list.
073 * @param listener the listener being added.
074 */
075 void addListener(Listener listener);
076
077 /**
078 * Remove the listener from the adapter list.
079 * @param listener the listener being removed.
080 */
081 void removeListener(Listener listener);
082 }
083
084 public static class EAdapterList<E extends Object & Adapter> extends BasicEList<E> implements EObservableAdapterList
085 {
086 private static final long serialVersionUID = 1L;
087
088 protected Notifier notifier;
089
090 protected Listener [] listeners;
091
092 public EAdapterList(Notifier notifier)
093 {
094 this.notifier = notifier;
095 }
096
097 protected boolean safe;
098
099 @Override
100 protected boolean canContainNull()
101 {
102 return false;
103 }
104
105 @Override
106 protected boolean useEquals()
107 {
108 return false;
109 }
110
111 @Override
112 protected Object [] newData(int capacity)
113 {
114 return new Adapter [capacity];
115 }
116
117 @Override
118 protected void didAdd(int index, E newObject)
119 {
120 if (listeners != null)
121 {
122 for (Listener listener : listeners)
123 {
124 listener.added(notifier, newObject);
125 }
126 }
127 newObject.setTarget(notifier);
128 }
129
130 @Override
131 protected void didRemove(int index, E oldObject)
132 {
133 if (listeners != null)
134 {
135 for (Listener listener : listeners)
136 {
137 listener.removed(notifier, oldObject);
138 }
139 }
140 E adapter = oldObject;
141 if (notifier.eDeliver())
142 {
143 Notification notification =
144 new NotificationImpl(Notification.REMOVING_ADAPTER, oldObject, null, index)
145 {
146 @Override
147 public Object getNotifier()
148 {
149 return notifier;
150 }
151 };
152 adapter.notifyChanged(notification);
153 }
154 if (adapter instanceof Adapter.Internal)
155 {
156 ((Adapter.Internal)adapter).unsetTarget(notifier);
157 }
158 else if (adapter.getTarget() == notifier)
159 {
160 adapter.setTarget(null);
161 }
162 }
163
164 @Override
165 public Object [] data()
166 {
167 safe = true;
168 if (data != null && data.length != size)
169 {
170 if (size == 0)
171 {
172 data = null;
173 }
174 else
175 {
176 Object [] oldData = data;
177 data = newData(size);
178 System.arraycopy(oldData, 0, data, 0, size);
179 }
180 }
181 return data;
182 }
183
184 protected void ensureSafety()
185 {
186 if (safe && data != null)
187 {
188 Object [] oldData = data;
189 data = newData(data.length);
190 System.arraycopy(oldData, 0, data, 0, size);
191 safe = false;
192 }
193 }
194
195 @Override
196 public boolean add(E object)
197 {
198 ensureSafety();
199 return super.add(object);
200 }
201
202 @Override
203 public void add(int index, E object)
204 {
205 ensureSafety();
206 super.add(index, object);
207 }
208
209 @Override
210 public boolean addAll(Collection<? extends E> collection)
211 {
212 ensureSafety();
213 return super.addAll(collection);
214 }
215
216 @Override
217 public boolean remove(Object object)
218 {
219 ensureSafety();
220 return super.remove(object);
221 }
222
223 @Override
224 public E remove(int index)
225 {
226 ensureSafety();
227 return super.remove(index);
228 }
229
230 @Override
231 public boolean removeAll(Collection<?> collection)
232 {
233 ensureSafety();
234 return super.removeAll(collection);
235 }
236
237 @Override
238 public void clear()
239 {
240 ensureSafety();
241 super.clear();
242 }
243
244 @Override
245 public boolean retainAll(Collection<?> collection)
246 {
247 ensureSafety();
248 return super.retainAll(collection);
249 }
250
251 @Override
252 public E set(int index, E object)
253 {
254 ensureSafety();
255 return super.set(index, object);
256 }
257
258 @Override
259 public void move(int newPosition, E object)
260 {
261 ensureSafety();
262 super.move(newPosition, object);
263 }
264
265 @Override
266 public E move(int newPosition, int oldPosition)
267 {
268 ensureSafety();
269 return super.move(newPosition, oldPosition);
270 }
271
272 public void addListener(Listener listener)
273 {
274 if (listeners == null)
275 {
276 listeners = new Listener [] { listener };
277 }
278 else
279 {
280 Listener[] newListeners = new Listener[listeners.length + 1];
281 System.arraycopy(listeners, 0, newListeners, 0, listeners.length);
282 newListeners[listeners.length] = listener;
283 listeners = newListeners;
284 }
285 }
286
287 public void removeListener(Listener listener)
288 {
289 if (listeners != null)
290 {
291 for (int i = 0; i < listeners.length; ++i)
292 {
293 if (listeners[i] == listener)
294 {
295 if (listeners.length == 1)
296 {
297 listeners = null;
298 }
299 else
300 {
301 Listener[] newListeners = new Listener[listeners.length - 1];
302 System.arraycopy(listeners, 0, newListeners, 0, i);
303 if (i != newListeners.length)
304 {
305 System.arraycopy(listeners, i + 1, newListeners, i, newListeners.length - i);
306 }
307 listeners = newListeners;
308 }
309 break;
310 }
311 }
312 }
313 }
314 }
315
316 public EList<Adapter> eAdapters()
317 {
318 return ECollections.emptyEList();
319 }
320
321 /**
322 * Returns the adapter list, even if it is <code>null</code>.
323 * @return the adapter list, even if it is <code>null</code>.
324 */
325 protected BasicEList<Adapter> eBasicAdapters()
326 {
327 return null;
328 }
329
330 /**
331 * Returns the underlying array of adapters.
332 * The length of this array reflects exactly the number of adapters
333 * where <code>null</code> represents the lack of any adapters.
334 * This array may not be modified by the caller
335 * and must be guaranteed not to be modified even if the {@link #eAdapters() list of adapters} is modified.
336 * @return the underlying array of adapters.
337 */
338 protected Adapter[] eBasicAdapterArray()
339 {
340 BasicEList<Adapter> eBasicAdapters = eBasicAdapters();
341 return eBasicAdapters == null ? null : (Adapter[])eBasicAdapters.data();
342 }
343
344 /**
345 * Returns whether there are any adapters.
346 * @return whether there are any adapters.
347 */
348 protected boolean eBasicHasAdapters()
349 {
350 BasicEList<Adapter> eBasicAdapters = eBasicAdapters();
351 return eBasicAdapters != null && eBasicAdapters.size() != 0;
352 }
353
354 /*
355 * Javadoc copied from interface.
356 */
357 public boolean eDeliver()
358 {
359 return false;
360 }
361
362 /*
363 * Javadoc copied from interface.
364 */
365 public void eSetDeliver(boolean deliver)
366 {
367 throw new UnsupportedOperationException();
368 }
369
370 /*
371 * Javadoc copied from interface.
372 */
373 public void eNotify(Notification notification)
374 {
375 Adapter[] eAdapters = eBasicAdapterArray();
376 if (eAdapters != null && eDeliver())
377 {
378 for (int i = 0, size = eAdapters.length; i < size; ++i)
379 {
380 eAdapters[i].notifyChanged(notification);
381 }
382 }
383 }
384
385 /**
386 * Returns whether {@link #eNotify eNotify} needs to be called.
387 * This may return <code>true</code> even when {@link #eDeliver eDeliver} is <code>false</code>
388 * or when {@link #eAdapters eAdapters} is empty.
389 * @return whether {@link #eNotify eNotify} needs to be called.
390 */
391 public boolean eNotificationRequired()
392 {
393 return eBasicHasAdapters() && eDeliver();
394 }
395 }