All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.jpa.jpql.utility.iterator.CloneListIterator Maven / Gradle / Ivy

There is a newer version: 5.0.0-B02
Show newest version
/*******************************************************************************
 * Copyright (c) 2006, 2014 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
 *
 ******************************************************************************/
package org.eclipse.persistence.jpa.jpql.utility.iterator;

import java.io.Serializable;
import java.util.List;
import java.util.ListIterator;
import org.eclipse.persistence.jpa.jpql.utility.CollectionTools;

/**
 * A CloneListIterator iterates over a copy of a list,
 * allowing for concurrent access to the original list.
 * 

* The original list passed to the CloneListIterator's * constructor should be synchronized; otherwise you run the risk of * a corrupted list (e.g. {@link java.util.Vector}. *

* By default, a CloneListIterator does not support the * modification operations; this is because it does not have * access to the original list. But if the CloneListIterator * is supplied with a {@link Mutator} it will delegate the * modification operations to the {@link Mutator}. * Alternatively, a subclass can override the modification methods. * * @param the type of elements returned by the iterator * * @see LiveCloneListIterable * @see SnapshotCloneListIterable */ public class CloneListIterator implements ListIterator { private int cursor; private final ListIterator listIterator; private final Mutator mutator; private State state; /** * Construct a list iterator on a copy of the specified array. * The modification methods will not be supported, * unless a subclass overrides them. */ public CloneListIterator(E[] array) { this(array, Mutator.ReadOnly.instance()); } /** * Construct a list iterator on a copy of the specified array. * Use the specified list mutator to modify the original list. */ public CloneListIterator(E[] array, Mutator mutator) { this(mutator, array.clone()); } /** * 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.ReadOnly.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) { this(mutator, list.toArray()); } /** * Internal constructor used by subclasses. * Swap order of arguments to prevent collision with other constructor. * The passed in array will *not* be cloned. */ protected CloneListIterator(Mutator mutator, Object... array) { super(); // build a copy of the list and keep it in sync with original (if the mutator allows changes) // that way the nested list iterator will maintain some of our state this.listIterator = CollectionTools.list(array).listIterator(); this.mutator = mutator; this.cursor = 0; this.state = State.UNKNOWN; } public void add(E o) { // allow the nested iterator to throw an exception before we modify the original list this.listIterator.add(o); this.add(this.cursor, o); this.cursor++; } /** * Add the specified element to the original list. *

* This method can be overridden by a subclass as an * alternative to building a {@link Mutator}. */ protected void add(int index, E o) { this.mutator.add(index, o); } public boolean hasNext() { return this.listIterator.hasNext(); } public boolean hasPrevious() { return this.listIterator.hasPrevious(); } /** * The list passed in during construction held elements of type E, * so this cast is not a problem. We need this cast because * all the elements of the original collection were copied into * an object array (Object[]). */ @SuppressWarnings("unchecked") protected E nestedNext() { return (E) this.listIterator.next(); } /** * The list passed in during construction held elements of type E, * so this cast is not a problem. We need this cast because * all the elements of the original collection were copied into * an object array (Object[]). */ @SuppressWarnings("unchecked") protected E nestedPrevious() { return (E) this.listIterator.previous(); } public E next() { // allow the nested iterator to throw an exception before we modify the index E next = this.nestedNext(); this.cursor++; this.state = State.NEXT; return next; } public int nextIndex() { return this.listIterator.nextIndex(); } public E previous() { // allow the nested iterator to throw an exception before we modify the index E previous = this.nestedPrevious(); this.cursor--; this.state = State.PREVIOUS; return previous; } public int previousIndex() { return this.listIterator.previousIndex(); } public void remove() { // allow the nested iterator to throw an exception before we modify the original list this.listIterator.remove(); if (this.state == State.PREVIOUS) { this.remove(this.cursor); } else { this.cursor--; this.remove(this.cursor); } } /** * Remove the specified element from the original list. *

* This method can be overridden by a subclass as an * alternative to building a {@link Mutator}. */ protected void remove(int index) { this.mutator.remove(index); } public void set(E o) { // allow the nested iterator to throw an exception before we modify the original list this.listIterator.set(o); if (this.state == State.PREVIOUS) { this.set(this.cursor, o); } else { this.set(this.cursor - 1, o); } } /** * Set the specified element in the original list. *

* This method can be overridden by a subclass as an * alternative to building a {@link Mutator}. */ protected void set(int index, E o) { this.mutator.set(index, o); } /** * Used by {@link CloneListIterator} 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, T 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, T o); final class ReadOnly implements Mutator, Serializable { @SuppressWarnings("rawtypes") public static final Mutator INSTANCE = new ReadOnly(); private static final long serialVersionUID = 1L; // ensure single instance private ReadOnly() { super(); } @SuppressWarnings("unchecked") public static Mutator instance() { return INSTANCE; } // add is not supported public void add(int index, Object o) { throw new UnsupportedOperationException(); } private Object readResolve() { // replace this object with the singleton return INSTANCE; } // remove is not supported public void remove(int index) { throw new UnsupportedOperationException(); } // set is not supported public void set(int index, Object o) { throw new UnsupportedOperationException(); } } } private enum State { NEXT, PREVIOUS, UNKNOWN } }