View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.collections4.list;
18  
19  import java.io.IOException;
20  import java.io.ObjectInputStream;
21  import java.io.ObjectOutputStream;
22  import java.io.Serializable;
23  import java.lang.ref.WeakReference;
24  import java.util.ArrayList;
25  import java.util.Collection;
26  import java.util.ConcurrentModificationException;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.ListIterator;
30  
31  /**
32   * A {@code List} implementation with a {@code ListIterator} that
33   * allows concurrent modifications to the underlying list.
34   * <p>
35   * This implementation supports all of the optional {@link List} operations.
36   * It extends {@code AbstractLinkedList} and thus provides the
37   * stack/queue/dequeue operations available in {@link java.util.LinkedList}.
38   * </p>
39   * <p>
40   * The main feature of this class is the ability to modify the list and the
41   * iterator at the same time. Both the {@link #listIterator()} and {@link #cursor()}
42   * methods provides access to a {@code Cursor} instance which extends
43   * {@code ListIterator}. The cursor allows changes to the list concurrent
44   * with changes to the iterator. Note that the {@link #iterator()} method and
45   * sublists do <b>not</b> provide this cursor behavior.
46   * </p>
47   * <p>
48   * The {@code Cursor} class is provided partly for backwards compatibility
49   * and partly because it allows the cursor to be directly closed. Closing the
50   * cursor is optional because references are held via a {@code WeakReference}.
51   * For most purposes, simply modify the iterator and list at will, and then let
52   * the garbage collector to the rest.
53   * </p>
54   * <p>
55   * <b>Note that this implementation is not synchronized.</b>
56   * </p>
57   *
58   * @see java.util.LinkedList
59   * @since 1.0
60   */
61  public class CursorableLinkedList<E> extends AbstractLinkedList<E> implements Serializable {
62  
63      /**
64       * An extended {@code ListIterator} that allows concurrent changes to
65       * the underlying list.
66       *
67       * @param <E> the type of elements in this cursor.
68       */
69      public static class Cursor<E> extends AbstractLinkedList.LinkedListIterator<E> {
70          /** Is the cursor valid (not closed) */
71          boolean valid = true;
72          /** Is the next index valid */
73          boolean nextIndexValid = true;
74          /** Flag to indicate if the current element was removed by another object. */
75          boolean currentRemovedByAnother;
76  
77          /**
78           * Constructs a new cursor.
79           *
80           * @param parent  the parent list
81           * @param index  the index to start from
82           */
83          protected Cursor(final CursorableLinkedList<E> parent, final int index) {
84              super(parent, index);
85              valid = true;
86          }
87  
88          /**
89           * Adds an object to the list.
90           * The object added here will be the new 'previous' in the iterator.
91           *
92           * @param obj  the object to add
93           */
94          @Override
95          public void add(final E obj) {
96              // overridden, as the nodeInserted() method updates the iterator state
97              super.add(obj);
98              // matches the (next.previous == node) clause in nodeInserted()
99              // thus next gets changed - reset it again here
100             next = next.next;
101         }
102 
103         /**
104          * Override superclass modCount check, and replace it with our valid flag.
105          */
106         @Override
107         protected void checkModCount() {
108             if (!valid) {
109                 throw new ConcurrentModificationException("Cursor closed");
110             }
111         }
112 
113         // set is not overridden, as it works ok
114         // note that we want it to throw an exception if the element being
115         // set has been removed from the real list (compare this with the
116         // remove method where we silently ignore this case)
117 
118         /**
119          * Mark this cursor as no longer being needed. Any resources
120          * associated with this cursor are immediately released.
121          * In previous versions of this class, it was mandatory to close
122          * all cursor objects to avoid memory leaks. It is <i>no longer</i>
123          * necessary to call this close method; an instance of this class
124          * can now be treated exactly like a normal iterator.
125          */
126         public void close() {
127             if (valid) {
128                 ((CursorableLinkedList<E>) parent).unregisterCursor(this);
129                 valid = false;
130             }
131         }
132 
133         /**
134          * Gets the index of the next element to be returned.
135          *
136          * @return the next index
137          */
138         @Override
139         public int nextIndex() {
140             if (!nextIndexValid) {
141                 if (next == parent.header) {
142                     nextIndex = parent.size();
143                 } else {
144                     int pos = 0;
145                     Node<E> temp = parent.header.next;
146                     while (temp != next) {
147                         pos++;
148                         temp = temp.next;
149                     }
150                     nextIndex = pos;
151                 }
152                 nextIndexValid = true;
153             }
154             return nextIndex;
155         }
156 
157         /**
158          * Handle event from the list when a node has changed.
159          *
160          * @param node  the node that changed
161          */
162         protected void nodeChanged(final Node<E> node) {
163             // do nothing
164         }
165 
166         /**
167          * Handle event from the list when a node has been added.
168          *
169          * @param node  the node that was added
170          */
171         protected void nodeInserted(final Node<E> node) {
172             if (node.previous == current || next.previous == node) {
173                 next = node;
174             } else {
175                 nextIndexValid = false;
176             }
177         }
178 
179         /**
180          * Handle event from the list when a node has been removed.
181          *
182          * @param node  the node that was removed
183          */
184         protected void nodeRemoved(final Node<E> node) {
185             if (node == next && node == current) {
186                 // state where next() followed by previous()
187                 next = node.next;
188                 current = null;
189                 currentRemovedByAnother = true;
190             } else if (node == next) {
191                 // state where next() not followed by previous()
192                 // and we are matching next node
193                 next = node.next;
194                 currentRemovedByAnother = false;
195             } else if (node == current) {
196                 // state where next() not followed by previous()
197                 // and we are matching current (last returned) node
198                 current = null;
199                 currentRemovedByAnother = true;
200                 nextIndex--;
201             } else {
202                 nextIndexValid = false;
203                 currentRemovedByAnother = false;
204             }
205         }
206 
207         /**
208          * Removes the item last returned by this iterator.
209          * <p>
210          * There may have been subsequent alterations to the list
211          * since you obtained this item, however you can still remove it.
212          * You can even remove it if the item is no longer in the main list.
213          * However, you can't call this method on the same iterator more
214          * than once without calling next() or previous().
215          *
216          * @throws IllegalStateException if there is no item to remove
217          */
218         @Override
219         public void remove() {
220             // overridden, as the nodeRemoved() method updates the iterator
221             // state in the parent.removeNode() call below
222             if (current == null && currentRemovedByAnother) { // NOPMD
223                 // quietly ignore, as the last returned node was removed
224                 // by the list or some other iterator
225                 // by ignoring it, we keep this iterator independent of
226                 // other changes as much as possible
227             } else {
228                 checkModCount();
229                 parent.removeNode(getLastNodeReturned());
230             }
231             currentRemovedByAnother = false;
232         }
233     }
234 
235     /**
236      * A cursor for the sublist based on LinkedSubListIterator.
237      *
238      * @param <E> the type of elements in this cursor.
239      * @since 3.2
240      */
241     protected static class SubCursor<E> extends Cursor<E> {
242 
243         /** The parent list */
244         protected final LinkedSubList<E> sub;
245 
246         /**
247          * Constructs a new cursor.
248          *
249          * @param sub  the sub list
250          * @param index  the index to start from
251          */
252         protected SubCursor(final LinkedSubList<E> sub, final int index) {
253             super((CursorableLinkedList<E>) sub.parent, index + sub.offset);
254             this.sub = sub;
255         }
256 
257         @Override
258         public void add(final E obj) {
259             super.add(obj);
260             sub.expectedModCount = parent.modCount;
261             sub.size++;
262         }
263 
264         @Override
265         public boolean hasNext() {
266             return nextIndex() < sub.size;
267         }
268 
269         @Override
270         public boolean hasPrevious() {
271             return previousIndex() >= 0;
272         }
273 
274         @Override
275         public int nextIndex() {
276             return super.nextIndex() - sub.offset;
277         }
278 
279         @Override
280         public void remove() {
281             super.remove();
282             sub.expectedModCount = parent.modCount;
283             sub.size--;
284         }
285     }
286 
287     /** Ensure serialization compatibility */
288     private static final long serialVersionUID = 8836393098519411393L;
289 
290     /** A list of the cursor currently open on this list */
291     private transient List<WeakReference<Cursor<E>>> cursors;
292 
293     /**
294      * Constructor that creates.
295      */
296     public CursorableLinkedList() {
297         init(); // must call init() as use super();
298     }
299 
300     /**
301      * Constructor that copies the specified collection
302      *
303      * @param coll  the collection to copy
304      */
305     public CursorableLinkedList(final Collection<? extends E> coll) {
306         super(coll);
307     }
308 
309     /**
310      * Inserts a new node into the list.
311      *
312      * @param nodeToInsert  new node to insert
313      * @param insertBeforeNode  node to insert before
314      * @throws NullPointerException if either node is null
315      */
316     @Override
317     protected void addNode(final Node<E> nodeToInsert, final Node<E> insertBeforeNode) {
318         super.addNode(nodeToInsert, insertBeforeNode);
319         broadcastNodeInserted(nodeToInsert);
320     }
321 
322     /**
323      * Informs all of my registered cursors that the specified
324      * element was changed.
325      *
326      * @param node  the node that was changed
327      */
328     protected void broadcastNodeChanged(final Node<E> node) {
329         final Iterator<WeakReference<Cursor<E>>> it = cursors.iterator();
330         while (it.hasNext()) {
331             final WeakReference<Cursor<E>> ref = it.next();
332             final Cursor<E> cursor = ref.get();
333             if (cursor == null) {
334                 it.remove(); // clean up list
335             } else {
336                 cursor.nodeChanged(node);
337             }
338         }
339     }
340 
341     /**
342      * Informs all of my registered cursors that the specified
343      * element was just added to my list.
344      *
345      * @param node  the node that was changed
346      */
347     protected void broadcastNodeInserted(final Node<E> node) {
348         final Iterator<WeakReference<Cursor<E>>> it = cursors.iterator();
349         while (it.hasNext()) {
350             final WeakReference<Cursor<E>> ref = it.next();
351             final Cursor<E> cursor = ref.get();
352             if (cursor == null) {
353                 it.remove(); // clean up list
354             } else {
355                 cursor.nodeInserted(node);
356             }
357         }
358     }
359 
360     /**
361      * Informs all of my registered cursors that the specified
362      * element was just removed from my list.
363      *
364      * @param node  the node that was changed
365      */
366     protected void broadcastNodeRemoved(final Node<E> node) {
367         final Iterator<WeakReference<Cursor<E>>> it = cursors.iterator();
368         while (it.hasNext()) {
369             final WeakReference<Cursor<E>> ref = it.next();
370             final Cursor<E> cursor = ref.get();
371             if (cursor == null) {
372                 it.remove(); // clean up list
373             } else {
374                 cursor.nodeRemoved(node);
375             }
376         }
377     }
378 
379     /**
380      * Creates a list iterator for the sublist.
381      *
382      * @param subList  the sublist to get an iterator for
383      * @param fromIndex  the index to start from, relative to the sublist
384      * @return the list iterator for the sublist
385      */
386     @Override
387     protected ListIterator<E> createSubListListIterator(final LinkedSubList<E> subList, final int fromIndex) {
388         final SubCursor<E> cursor = new SubCursor<>(subList, fromIndex);
389         registerCursor(cursor);
390         return cursor;
391     }
392 
393     /**
394      * Returns a {@link Cursor} for iterating through the elements of this list.
395      * <p>
396      * A {@code Cursor} is a {@code ListIterator} with an additional
397      * {@code close()} method. Calling this method immediately discards the
398      * references to the cursor. If it is not called, then the garbage collector
399      * will still remove the reference as it is held via a {@code WeakReference}.
400      * <p>
401      * The cursor enables iteration and list changes to occur in any order without
402      * invalidating the iterator (from one thread). When elements are added to the
403      * list, an event is fired to all active cursors enabling them to adjust to the
404      * change in the list.
405      * <p>
406      * When the "current" (i.e., last returned by {@link ListIterator#next}
407      * or {@link ListIterator#previous}) element of the list is removed,
408      * the cursor automatically adjusts to the change (invalidating the
409      * last returned value such that it cannot be removed).
410      * <p>
411      * The {@link #listIterator()} method returns the same as this method, and can
412      * be cast to a {@code Cursor} if the {@code close} method is required.
413      *
414      * @return a new cursor iterator
415      */
416     public CursorableLinkedList.Cursor<E> cursor() {
417         return cursor(0);
418     }
419 
420     /**
421      * Returns a {@link Cursor} for iterating through the elements of this list
422      * starting from a specified index.
423      * <p>
424      * A {@code Cursor} is a {@code ListIterator} with an additional
425      * {@code close()} method. Calling this method immediately discards the
426      * references to the cursor. If it is not called, then the garbage collector
427      * will still remove the reference as it is held via a {@code WeakReference}.
428      * <p>
429      * The cursor enables iteration and list changes to occur in any order without
430      * invalidating the iterator (from one thread). When elements are added to the
431      * list, an event is fired to all active cursors enabling them to adjust to the
432      * change in the list.
433      * <p>
434      * When the "current" (i.e., last returned by {@link ListIterator#next}
435      * or {@link ListIterator#previous}) element of the list is removed,
436      * the cursor automatically adjusts to the change (invalidating the
437      * last returned value such that it cannot be removed).
438      * <p>
439      * The {@link #listIterator(int)} method returns the same as this method, and can
440      * be cast to a {@code Cursor} if the {@code close} method is required.
441      *
442      * @param fromIndex  the index to start from
443      * @return a new cursor iterator
444      * @throws IndexOutOfBoundsException if the index is out of range
445      *      (index &lt; 0 || index &gt; size()).
446      */
447     public CursorableLinkedList.Cursor<E> cursor(final int fromIndex) {
448         final Cursor<E> cursor = new Cursor<>(this, fromIndex);
449         registerCursor(cursor);
450         return cursor;
451     }
452 
453     /**
454      * The equivalent of a default constructor called
455      * by any constructor and by {@code readObject}.
456      */
457     @Override
458     protected void init() {
459         super.init();
460         cursors = new ArrayList<>();
461     }
462 
463     /**
464      * Returns an iterator that does <b>not</b> support concurrent modification.
465      * <p>
466      * If the underlying list is modified while iterating using this iterator
467      * a ConcurrentModificationException will occur.
468      * The cursor behavior is available via {@link #listIterator()}.
469      *
470      * @return a new iterator that does <b>not</b> support concurrent modification
471      */
472     @Override
473     public Iterator<E> iterator() {
474         return super.listIterator(0);
475     }
476 
477     /**
478      * Returns a cursor iterator that allows changes to the underlying list in parallel.
479      * <p>
480      * The cursor enables iteration and list changes to occur in any order without
481      * invalidating the iterator (from one thread). When elements are added to the
482      * list, an event is fired to all active cursors enabling them to adjust to the
483      * change in the list.
484      * <p>
485      * When the "current" (i.e., last returned by {@link ListIterator#next}
486      * or {@link ListIterator#previous}) element of the list is removed,
487      * the cursor automatically adjusts to the change (invalidating the
488      * last returned value such that it cannot be removed).
489      *
490      * @return a new cursor iterator
491      */
492     @Override
493     public ListIterator<E> listIterator() {
494         return cursor(0);
495     }
496 
497     /**
498      * Returns a cursor iterator that allows changes to the underlying list in parallel.
499      * <p>
500      * The cursor enables iteration and list changes to occur in any order without
501      * invalidating the iterator (from one thread). When elements are added to the
502      * list, an event is fired to all active cursors enabling them to adjust to the
503      * change in the list.
504      * <p>
505      * When the "current" (i.e., last returned by {@link ListIterator#next}
506      * or {@link ListIterator#previous}) element of the list is removed,
507      * the cursor automatically adjusts to the change (invalidating the
508      * last returned value such that it cannot be removed).
509      *
510      * @param fromIndex  the index to start from
511      * @return a new cursor iterator
512      */
513     @Override
514     public ListIterator<E> listIterator(final int fromIndex) {
515         return cursor(fromIndex);
516     }
517 
518     /**
519      * Deserializes the data held in this object to the stream specified.
520      *
521      * @param in  the input stream
522      * @throws IOException if an error occurs while reading from the stream
523      * @throws ClassNotFoundException if an object read from the stream can not be loaded
524      */
525     private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
526         in.defaultReadObject();
527         doReadObject(in);
528     }
529 
530     /**
531      * Registers a cursor to be notified of changes to this list.
532      *
533      * @param cursor  the cursor to register
534      */
535     protected void registerCursor(final Cursor<E> cursor) {
536         // We take this opportunity to clean the cursors list
537         // of WeakReference objects to garbage-collected cursors.
538         cursors.removeIf(ref -> ref.get() == null);
539         cursors.add(new WeakReference<>(cursor));
540     }
541 
542     /**
543      * Removes all nodes by iteration.
544      */
545     @Override
546     protected void removeAllNodes() {
547         if (!isEmpty()) {
548             // superclass implementation would break all the iterators
549             final Iterator<E> it = iterator();
550             while (it.hasNext()) {
551                 it.next();
552                 it.remove();
553             }
554         }
555     }
556 
557     /**
558      * Removes the specified node from the list.
559      *
560      * @param node  the node to remove
561      * @throws NullPointerException if {@code node} is null
562      */
563     @Override
564     protected void removeNode(final Node<E> node) {
565         super.removeNode(node);
566         broadcastNodeRemoved(node);
567     }
568 
569     /**
570      * Deregisters a cursor from the list to be notified of changes.
571      *
572      * @param cursor  the cursor to deregister
573      */
574     protected void unregisterCursor(final Cursor<E> cursor) {
575         for (final Iterator<WeakReference<Cursor<E>>> it = cursors.iterator(); it.hasNext();) {
576             final WeakReference<Cursor<E>> ref = it.next();
577             final Cursor<E> cur = ref.get();
578             if (cur == null) {
579                 // some other unrelated cursor object has been
580                 // garbage-collected; let's take the opportunity to
581                 // clean up the cursors list anyway.
582                 it.remove();
583             } else if (cur == cursor) {
584                 ref.clear();
585                 it.remove();
586                 break;
587             }
588         }
589     }
590 
591     /**
592      * Updates the node with a new value.
593      * This implementation sets the value on the node.
594      * Subclasses can override this to record the change.
595      *
596      * @param node  node to update
597      * @param value  new value of the node
598      */
599     @Override
600     protected void updateNode(final Node<E> node, final E value) {
601         super.updateNode(node, value);
602         broadcastNodeChanged(node);
603     }
604 
605     /**
606      * Serializes the data held in this object to the stream specified.
607      *
608      * @param out  the output stream
609      * @throws IOException if an error occurs while writing to the stream
610      */
611     private void writeObject(final ObjectOutputStream out) throws IOException {
612         out.defaultWriteObject();
613         doWriteObject(out);
614     }
615 
616 }