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