1. /*
  2. * Copyright 2002-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.collections.list;
  17. import java.io.IOException;
  18. import java.io.ObjectInputStream;
  19. import java.io.ObjectOutputStream;
  20. import java.io.Serializable;
  21. import java.lang.ref.WeakReference;
  22. import java.util.ArrayList;
  23. import java.util.Collection;
  24. import java.util.ConcurrentModificationException;
  25. import java.util.Iterator;
  26. import java.util.List;
  27. import java.util.ListIterator;
  28. /**
  29. * A <code>List</code> implementation with a <code>ListIterator</code> that
  30. * allows concurrent modifications to the underlying list.
  31. * <p>
  32. * This implementation supports all of the optional {@link List} operations.
  33. * It extends <code>AbstractLinkedList</code> and thus provides the
  34. * stack/queue/dequeue operations available in {@link java.util.LinkedList}.
  35. * <p>
  36. * The main feature of this class is the ability to modify the list and the
  37. * iterator at the same time. Both the {@link #listIterator()} and {@link #cursor()}
  38. * methods provides access to a <code>Cursor</code> instance which extends
  39. * <code>ListIterator</code>. The cursor allows changes to the list concurrent
  40. * with changes to the iterator. Note that the {@link #iterator()} method and
  41. * sublists do <b>not</b> provide this cursor behaviour.
  42. * <p>
  43. * The <code>Cursor</code> class is provided partly for backwards compatibility
  44. * and partly because it allows the cursor to be directly closed. Closing the
  45. * cursor is optional because references are held via a <code>WeakReference</code>.
  46. * For most purposes, simply modify the iterator and list at will, and then let
  47. * the garbage collector to the rest.
  48. * <p>
  49. * <b>Note that this implementation is not synchronized.</b>
  50. *
  51. * @see java.util.LinkedList
  52. * @since Commons Collections 1.0
  53. * @version $Revision: 1.5 $ $Date: 2004/02/18 01:12:26 $
  54. *
  55. * @author Rodney Waldhoff
  56. * @author Janek Bogucki
  57. * @author Simon Kitching
  58. * @author Stephen Colebourne
  59. */
  60. public class CursorableLinkedList extends AbstractLinkedList implements Serializable {
  61. /** Ensure serialization compatibility */
  62. private static final long serialVersionUID = 8836393098519411393L;
  63. /** A list of the cursor currently open on this list */
  64. protected transient List cursors = new ArrayList();
  65. //-----------------------------------------------------------------------
  66. /**
  67. * Constructor that creates.
  68. */
  69. public CursorableLinkedList() {
  70. super();
  71. init(); // must call init() as use super();
  72. }
  73. /**
  74. * Constructor that copies the specified collection
  75. *
  76. * @param coll the collection to copy
  77. */
  78. public CursorableLinkedList(Collection coll) {
  79. super(coll);
  80. }
  81. /**
  82. * The equivalent of a default constructor called
  83. * by any constructor and by <code>readObject</code>.
  84. */
  85. protected void init() {
  86. super.init();
  87. cursors = new ArrayList();
  88. }
  89. //-----------------------------------------------------------------------
  90. /**
  91. * Returns an iterator that does <b>not</b> support concurrent modification.
  92. * <p>
  93. * If the underlying list is modified while iterating using this iterator
  94. * a ConcurrentModificationException will occur.
  95. * The cursor behaviour is available via {@link #listIterator()}.
  96. *
  97. * @return a new iterator that does <b>not</b> support concurrent modification
  98. */
  99. public Iterator iterator() {
  100. return super.listIterator(0);
  101. }
  102. /**
  103. * Returns a cursor iterator that allows changes to the underlying list in parallel.
  104. * <p>
  105. * The cursor enables iteration and list changes to occur in any order without
  106. * invalidating the iterator (from one thread). When elements are added to the
  107. * list, an event is fired to all active cursors enabling them to adjust to the
  108. * change in the list.
  109. * <p>
  110. * When the "current" (i.e., last returned by {@link ListIterator#next}
  111. * or {@link ListIterator#previous}) element of the list is removed,
  112. * the cursor automatically adjusts to the change (invalidating the
  113. * last returned value such that it cannot be removed).
  114. *
  115. * @return a new cursor iterator
  116. */
  117. public ListIterator listIterator() {
  118. return cursor(0);
  119. }
  120. /**
  121. * Returns a cursor iterator that allows changes to the underlying list in parallel.
  122. * <p>
  123. * The cursor enables iteration and list changes to occur in any order without
  124. * invalidating the iterator (from one thread). When elements are added to the
  125. * list, an event is fired to all active cursors enabling them to adjust to the
  126. * change in the list.
  127. * <p>
  128. * When the "current" (i.e., last returned by {@link ListIterator#next}
  129. * or {@link ListIterator#previous}) element of the list is removed,
  130. * the cursor automatically adjusts to the change (invalidating the
  131. * last returned value such that it cannot be removed).
  132. *
  133. * @param fromIndex the index to start from
  134. * @return a new cursor iterator
  135. */
  136. public ListIterator listIterator(int fromIndex) {
  137. return cursor(fromIndex);
  138. }
  139. /**
  140. * Returns a {@link Cursor} for iterating through the elements of this list.
  141. * <p>
  142. * A <code>Cursor</code> is a <code>ListIterator</code> with an additional
  143. * <code>close()</code> method. Calling this method immediately discards the
  144. * references to the cursor. If it is not called, then the garbage collector
  145. * will still remove the reference as it is held via a <code>WeakReference</code>.
  146. * <p>
  147. * The cursor enables iteration and list changes to occur in any order without
  148. * invalidating the iterator (from one thread). When elements are added to the
  149. * list, an event is fired to all active cursors enabling them to adjust to the
  150. * change in the list.
  151. * <p>
  152. * When the "current" (i.e., last returned by {@link ListIterator#next}
  153. * or {@link ListIterator#previous}) element of the list is removed,
  154. * the cursor automatically adjusts to the change (invalidating the
  155. * last returned value such that it cannot be removed).
  156. * <p>
  157. * The {@link #listIterator()} method returns the same as this method, and can
  158. * be cast to a <code>Cursor</code> if the <code>close</code> method is required.
  159. *
  160. * @return a new cursor iterator
  161. */
  162. public CursorableLinkedList.Cursor cursor() {
  163. return cursor(0);
  164. }
  165. /**
  166. * Returns a {@link Cursor} for iterating through the elements of this list
  167. * starting from a specified index.
  168. * <p>
  169. * A <code>Cursor</code> is a <code>ListIterator</code> with an additional
  170. * <code>close()</code> method. Calling this method immediately discards the
  171. * references to the cursor. If it is not called, then the garbage collector
  172. * will still remove the reference as it is held via a <code>WeakReference</code>.
  173. * <p>
  174. * The cursor enables iteration and list changes to occur in any order without
  175. * invalidating the iterator (from one thread). When elements are added to the
  176. * list, an event is fired to all active cursors enabling them to adjust to the
  177. * change in the list.
  178. * <p>
  179. * When the "current" (i.e., last returned by {@link ListIterator#next}
  180. * or {@link ListIterator#previous}) element of the list is removed,
  181. * the cursor automatically adjusts to the change (invalidating the
  182. * last returned value such that it cannot be removed).
  183. * <p>
  184. * The {@link #listIterator(int)} method returns the same as this method, and can
  185. * be cast to a <code>Cursor</code> if the <code>close</code> method is required.
  186. *
  187. * @param fromIndex the index to start from
  188. * @return a new cursor iterator
  189. * @throws IndexOutOfBoundsException if the index is out of range
  190. * (index < 0 || index > size()).
  191. */
  192. public CursorableLinkedList.Cursor cursor(int fromIndex) {
  193. Cursor cursor = new Cursor(this, fromIndex);
  194. registerCursor(cursor);
  195. return cursor;
  196. }
  197. //-----------------------------------------------------------------------
  198. /**
  199. * Updates the node with a new value.
  200. * This implementation sets the value on the node.
  201. * Subclasses can override this to record the change.
  202. *
  203. * @param node node to update
  204. * @param value new value of the node
  205. */
  206. protected void updateNode(Node node, Object value) {
  207. super.updateNode(node, value);
  208. broadcastNodeChanged(node);
  209. }
  210. /**
  211. * Inserts a new node into the list.
  212. *
  213. * @param nodeToInsert new node to insert
  214. * @param insertBeforeNode node to insert before
  215. * @throws NullPointerException if either node is null
  216. */
  217. protected void addNode(Node nodeToInsert, Node insertBeforeNode) {
  218. super.addNode(nodeToInsert, insertBeforeNode);
  219. broadcastNodeInserted(nodeToInsert);
  220. }
  221. /**
  222. * Removes the specified node from the list.
  223. *
  224. * @param node the node to remove
  225. * @throws NullPointerException if <code>node</code> is null
  226. */
  227. protected void removeNode(Node node) {
  228. super.removeNode(node);
  229. broadcastNodeRemoved(node);
  230. }
  231. /**
  232. * Removes all nodes by iteration.
  233. */
  234. protected void removeAllNodes() {
  235. if (size() > 0) {
  236. // superclass implementation would break all the iterators
  237. Iterator it = iterator();
  238. while (it.hasNext()) {
  239. it.next();
  240. it.remove();
  241. }
  242. }
  243. }
  244. //-----------------------------------------------------------------------
  245. /**
  246. * Registers a cursor to be notified of changes to this list.
  247. *
  248. * @param cursor the cursor to register
  249. */
  250. protected void registerCursor(Cursor cursor) {
  251. // We take this opportunity to clean the cursors list
  252. // of WeakReference objects to garbage-collected cursors.
  253. for (Iterator it = cursors.iterator(); it.hasNext();) {
  254. WeakReference ref = (WeakReference) it.next();
  255. if (ref.get() == null) {
  256. it.remove();
  257. }
  258. }
  259. cursors.add(new WeakReference(cursor));
  260. }
  261. /**
  262. * Deregisters a cursor from the list to be notified of changes.
  263. *
  264. * @param cursor the cursor to deregister
  265. */
  266. protected void unregisterCursor(Cursor cursor) {
  267. for (Iterator it = cursors.iterator(); it.hasNext();) {
  268. WeakReference ref = (WeakReference) it.next();
  269. Cursor cur = (Cursor) ref.get();
  270. if (cur == null) {
  271. // some other unrelated cursor object has been
  272. // garbage-collected; let's take the opportunity to
  273. // clean up the cursors list anyway..
  274. it.remove();
  275. } else if (cur == cursor) {
  276. ref.clear();
  277. it.remove();
  278. break;
  279. }
  280. }
  281. }
  282. //-----------------------------------------------------------------------
  283. /**
  284. * Informs all of my registered cursors that the specified
  285. * element was changed.
  286. *
  287. * @param node the node that was changed
  288. */
  289. protected void broadcastNodeChanged(Node node) {
  290. Iterator it = cursors.iterator();
  291. while (it.hasNext()) {
  292. WeakReference ref = (WeakReference) it.next();
  293. Cursor cursor = (Cursor) ref.get();
  294. if (cursor == null) {
  295. it.remove(); // clean up list
  296. } else {
  297. cursor.nodeChanged(node);
  298. }
  299. }
  300. }
  301. /**
  302. * Informs all of my registered cursors that the specified
  303. * element was just removed from my list.
  304. *
  305. * @param node the node that was changed
  306. */
  307. protected void broadcastNodeRemoved(Node node) {
  308. Iterator it = cursors.iterator();
  309. while (it.hasNext()) {
  310. WeakReference ref = (WeakReference) it.next();
  311. Cursor cursor = (Cursor) ref.get();
  312. if (cursor == null) {
  313. it.remove(); // clean up list
  314. } else {
  315. cursor.nodeRemoved(node);
  316. }
  317. }
  318. }
  319. /**
  320. * Informs all of my registered cursors that the specified
  321. * element was just added to my list.
  322. *
  323. * @param node the node that was changed
  324. */
  325. protected void broadcastNodeInserted(Node node) {
  326. Iterator it = cursors.iterator();
  327. while (it.hasNext()) {
  328. WeakReference ref = (WeakReference) it.next();
  329. Cursor cursor = (Cursor) ref.get();
  330. if (cursor == null) {
  331. it.remove(); // clean up list
  332. } else {
  333. cursor.nodeInserted(node);
  334. }
  335. }
  336. }
  337. //-----------------------------------------------------------------------
  338. /**
  339. * Serializes the data held in this object to the stream specified.
  340. */
  341. private void writeObject(ObjectOutputStream out) throws IOException {
  342. out.defaultWriteObject();
  343. doWriteObject(out);
  344. }
  345. /**
  346. * Deserializes the data held in this object to the stream specified.
  347. */
  348. private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
  349. in.defaultReadObject();
  350. doReadObject(in);
  351. }
  352. //-----------------------------------------------------------------------
  353. /**
  354. * An extended <code>ListIterator</code> that allows concurrent changes to
  355. * the underlying list.
  356. */
  357. public static class Cursor extends AbstractLinkedList.LinkedListIterator {
  358. /** Is the cursor valid (not closed) */
  359. boolean valid = true;
  360. /** Is the next index valid */
  361. boolean nextIndexValid = true;
  362. /**
  363. * Constructs a new cursor.
  364. *
  365. * @param index the index to start from
  366. */
  367. protected Cursor(CursorableLinkedList parent, int index) {
  368. super(parent, index);
  369. valid = true;
  370. }
  371. /**
  372. * Adds an object to the list.
  373. * The object added here will be the new 'previous' in the iterator.
  374. *
  375. * @param obj the object to add
  376. */
  377. public void add(Object obj) {
  378. super.add(obj);
  379. // add on iterator does not return the added element
  380. next = next.next;
  381. }
  382. /**
  383. * Gets the index of the next element to be returned.
  384. *
  385. * @return the next index
  386. */
  387. public int nextIndex() {
  388. if (nextIndexValid == false) {
  389. if (next == parent.header) {
  390. nextIndex = parent.size();
  391. } else {
  392. int pos = 0;
  393. Node temp = parent.header.next;
  394. while (temp != next) {
  395. pos++;
  396. temp = temp.next;
  397. }
  398. nextIndex = pos;
  399. }
  400. nextIndexValid = true;
  401. }
  402. return nextIndex;
  403. }
  404. /**
  405. * Handle event from the list when a node has changed.
  406. *
  407. * @param node the node that changed
  408. */
  409. protected void nodeChanged(Node node) {
  410. // do nothing
  411. }
  412. /**
  413. * Handle event from the list when a node has been removed.
  414. *
  415. * @param node the node that was removed
  416. */
  417. protected void nodeRemoved(Node node) {
  418. if (node == next) {
  419. next = node.next;
  420. } else if (node == current) {
  421. current = null;
  422. nextIndex--;
  423. } else {
  424. nextIndexValid = false;
  425. }
  426. }
  427. /**
  428. * Handle event from the list when a node has been added.
  429. *
  430. * @param node the node that was added
  431. */
  432. protected void nodeInserted(Node node) {
  433. if (node.previous == current) {
  434. next = node;
  435. } else if (next.previous == node) {
  436. next = node;
  437. } else {
  438. nextIndexValid = false;
  439. }
  440. }
  441. /**
  442. * Override superclass modCount check, and replace it with our valid flag.
  443. */
  444. protected void checkModCount() {
  445. if (!valid) {
  446. throw new ConcurrentModificationException("Cursor closed");
  447. }
  448. }
  449. /**
  450. * Mark this cursor as no longer being needed. Any resources
  451. * associated with this cursor are immediately released.
  452. * In previous versions of this class, it was mandatory to close
  453. * all cursor objects to avoid memory leaks. It is <i>no longer</i>
  454. * necessary to call this close method; an instance of this class
  455. * can now be treated exactly like a normal iterator.
  456. */
  457. public void close() {
  458. if (valid) {
  459. ((CursorableLinkedList) parent).unregisterCursor(this);
  460. valid = false;
  461. }
  462. }
  463. }
  464. }