/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.tools.workbench.utility.iterators; import java.util.List; import java.util.ListIterator; import org.eclipse.persistence.tools.workbench.utility.ClassTools; import org.eclipse.persistence.tools.workbench.utility.CollectionTools; /** * A <code>CloneListIterator</code> iterates over a copy of a list, * allowing for concurrent access to the original list. * <p> * The original list passed to the <code>CloneListIterator</code>'s * constructor should be synchronized; otherwise you run the risk of * a corrupted list. * <p> * By default, a <code>CloneListIterator</code> does not support the * modification operations; this is because it does not have * access to the original list. But if the <code>CloneListIterator</code> * is supplied with a <code>Mutator</code> it will delegate the * modification operations to the <code>Mutator</code>. * Alternatively, a subclass can override the modification methods. */ public class CloneListIterator implements ListIterator { private ListIterator nestedListIterator; private int cursor; private String state; private Mutator mutator; private static final String UNKNOWN = "unknown"; private static final String PREVIOUS = "previous"; private static final String NEXT = "next"; // ********** constructors ********** /** * Construct a list iterator on a copy of the specified list. * The modification methods will not be supported, * unless a subclass overrides them. */ public CloneListIterator(List list) { this(list, Mutator.READ_ONLY_INSTANCE); } /** * Construct a list iterator on a copy of the specified list. * Use the specified list mutator to modify the original list. */ public CloneListIterator(List list, Mutator mutator) { super(); this.nestedListIterator = CollectionTools.list(list.toArray()).listIterator(); this.mutator = mutator; this.cursor = 0; this.state = UNKNOWN; } // ********** ListIterator implementation ********** /** * @see java.util.ListIterator#hasNext() */ public boolean hasNext() { return this.nestedListIterator.hasNext(); } /** * @see java.util.ListIterator#next() */ public Object next() { // allow the nested iterator to throw an exception before we modify the index Object next = this.nestedListIterator.next(); this.cursor++; this.state = NEXT; return next; } /** * @see java.util.ListIterator#remove() */ public void remove() { // allow the nested iterator to throw an exception before we modify the original list this.nestedListIterator.remove(); if (this.state == PREVIOUS) { this.remove(this.cursor); } else { this.cursor--; this.remove(this.cursor); } } /** * @see java.util.ListIterator#nextIndex() */ public int nextIndex() { return this.nestedListIterator.nextIndex(); } /** * @see java.util.ListIterator#previousIndex() */ public int previousIndex() { return this.nestedListIterator.previousIndex(); } /** * @see java.util.ListIterator#hasPrevious() */ public boolean hasPrevious() { return this.nestedListIterator.hasPrevious(); } /** * @see java.util.ListIterator#previous() */ public Object previous() { // allow the nested iterator to throw an exception before we modify the index Object previous = this.nestedListIterator.previous(); this.cursor--; this.state = PREVIOUS; return previous; } /** * @see java.util.ListIterator#add(java.lang.Object) */ public void add(Object o) { // allow the nested iterator to throw an exception before we modify the original list this.nestedListIterator.add(o); this.add(this.cursor, o); this.cursor++; } /** * @see java.util.ListIterator#set(java.lang.Object) */ public void set(Object o) { // allow the nested iterator to throw an exception before we modify the original list this.nestedListIterator.set(o); if (this.state == PREVIOUS) { this.set(this.cursor, o); } else { this.set(this.cursor - 1, o); } } // ********** internal methods ********** /** * Add the specified element to the original list. * <p> * This method can be overridden by a subclass as an * alternative to building a <code>Mutator</code>. */ protected void add(int index, Object o) { this.mutator.add(index, o); } /** * Remove the specified element from the original list. * <p> * This method can be overridden by a subclass as an * alternative to building a <code>Mutator</code>. */ protected void remove(int index) { this.mutator.remove(index); } /** * Set the specified element in the original list. * <p> * This method can be overridden by a subclass as an * alternative to building a <code>Mutator</code>. */ protected void set(int index, Object o) { this.mutator.set(index, o); } /** * @see java.lang.Object#toString() */ public String toString() { return ClassTools.shortClassNameForObject(this); } //********** member interface ********** /** * Used by <code>CloneListIterator</code> to remove * elements from the original list; since the list iterator * does not have direct access to the original list. */ public interface Mutator { /** * Add the specified object to the original list. */ void add(int index, Object o); /** * Remove the specified object from the original list. */ void remove(int index); /** * Set the specified object in the original list. */ void set(int index, Object o); Mutator READ_ONLY_INSTANCE = new Mutator() { public void add(int index, Object o) { throw new UnsupportedOperationException(); } public void remove(int index) { throw new UnsupportedOperationException(); } public void set(int index, Object o) { throw new UnsupportedOperationException(); } public String toString() { return "ReadOnlyListMutator"; } }; } }