/****************************************************************************** * Copyright (c) 2006, 2010 VMware Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0 * is available at http://www.opensource.org/licenses/apache2.0.php. * You may elect to redistribute this code under either of these licenses. * * Contributors: * VMware Inc. *****************************************************************************/ package org.eclipse.gemini.blueprint.service.importer.support.internal.collection; import java.util.Collection; import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; import java.util.RandomAccess; /** * Subclass offering a List extension for a DynamicCollection. This allows not * just forward, but also backwards iteration through the * <code>ListIterator</list>. * * @author Costin Leau * */ public class DynamicList<E> extends DynamicCollection<E> implements List<E>, RandomAccess { /** * List iterator. * * @author Costin Leau * */ private class DynamicListIterator extends DynamicIterator implements ListIterator<E> { /** * Similar to {@link DynamicIterator#tailGhost} in functionality but * representing the last seen object in the head of the collection. */ protected volatile E headGhost = null; // flag used for enforcing the iterator consistency: // null - do not enforce anything // true - should not throw exception // false - should throw exception /** * Iterator variable - not thread-safe/synchronized since only one * thread should use the iterator. */ protected Boolean hasPrevious = null; /** * Boolean field used by the {@link #set(Object)} and {@link #remove()} * operation. True indicates next() was called, and false previous(). */ private boolean previousOperationCalled = true; private DynamicListIterator(int index) { super.cursor = index; } public void add(E o) { removalAllowed = false; synchronized (storage) { synchronized (lock) { DynamicList.this.add(cursor, o); } } } /** * Updates the hasPrevious field. * * Internal unprotected method to avoid nested synchronization blocks. * To execute this code, one needs the storage, iteratorsLock and * iterator lock. * * @return */ private boolean unsafeHasPrevious() { hasPrevious = (cursor - 1 >= 0 ? Boolean.TRUE : Boolean.FALSE); return hasPrevious.booleanValue(); } public boolean hasPrevious() { synchronized (lock) { headGhost = null; return unsafeHasPrevious(); } } public int nextIndex() { synchronized (lock) { return cursor; } } public E next() { previousOperationCalled = true; return super.next(); } public E previous() { try { removalAllowed = true; previousOperationCalled = false; // no enforcement if (hasPrevious == null) { synchronized (storage) { synchronized (lock) { if (unsafeHasPrevious()) return storage.get(--cursor); else throw new NoSuchElementException(); } } } // need to return an object no matter what else if (hasPrevious.booleanValue()) { synchronized (storage) { synchronized (lock) { // if there is an element available, return it if (unsafeHasPrevious()) { return storage.get(--cursor); } else { // otherwise return the last one seen return headGhost; } } } } // should throw exception no matter what else { throw new NoSuchElementException(); } } finally { // no matter what, reset hasPrevious hasPrevious = null; // remove ghost object synchronized (lock) { headGhost = null; } } } public int previousIndex() { synchronized (lock) { return (cursor - 1); } } public void set(E o) { if (!removalAllowed) throw new IllegalStateException(); synchronized (storage) { synchronized (lock) { int index = (previousOperationCalled ? cursor - 1 : cursor); if (index < 0) { index = 0; } else { int length = storage.size(); if (index > length) { index = length; } } storage.set(index, o); } } } protected int removalIndex(int cursor) { int index = (previousOperationCalled ? cursor - 1 : cursor); if (index < 0) { index = 0; } else { int length; synchronized (storage) { length = storage.size(); } if (index > length) { index = length; } } return index; } } public DynamicList() { super(); } public DynamicList(Collection<? extends E> c) { super(c); } public DynamicList(int size) { super(size); } public void add(int index, E o) { super.add(index, o); } public boolean addAll(int index, Collection<? extends E> c) { synchronized (storage) { return storage.addAll(index, c); } } public E get(int index) { synchronized (storage) { return storage.get(index); } } public int indexOf(Object o) { synchronized (storage) { return storage.indexOf(o); } } public int lastIndexOf(Object o) { synchronized (storage) { return storage.lastIndexOf(o); } } public ListIterator<E> listIterator() { DynamicListIterator iter = new DynamicListIterator(0); synchronized (iterators) { iterators.put(iter, null); } return iter; } public ListIterator<E> listIterator(int index) { return new DynamicListIterator(index); } public E remove(int index) { return super.remove(index); } public E set(int index, E o) { synchronized (storage) { return storage.set(index, o); } } // TODO: test behavior to see if the returned list properly behaves under // dynamic circumstances public List<E> subList(int fromIndex, int toIndex) { synchronized (storage) { return storage.subList(fromIndex, toIndex); } } }