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    }