/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.aries.blueprint.utils; import java.lang.ref.WeakReference; import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; /** * Collection that allows iterators to see addition or removals of elements while iterating. * This collection and its iterators are thread safe but all operations happen under a * synchronization lock, so the performance in heavy concurrency load is far from optimal. * If such a use is needed, a CopyOnWriteArrayList may be more suited. * * @version $Rev$, $Date$ */ public class DynamicCollection<E> extends AbstractCollection<E> { protected final Object lock = new Object(); protected final List<E> storage; protected final List<WeakReference<DynamicIterator>> iterators; public DynamicCollection() { this.storage = new ArrayList<E>(); this.iterators = new ArrayList<WeakReference<DynamicIterator>>(); } public DynamicIterator iterator() { return iterator(0); } public DynamicIterator iterator(int index) { DynamicIterator iterator = createIterator(index); synchronized (lock) { for (Iterator<WeakReference<DynamicIterator>> it = iterators.iterator(); it.hasNext();) { if (it.next().get() == null) { it.remove(); } } iterators.add(new WeakReference<DynamicIterator>(iterator)); } return iterator; } protected DynamicIterator createIterator(int index) { return new DynamicIterator(index); } public int size() { synchronized (lock) { return storage.size(); } } public boolean isEmpty() { return size() == 0; } public boolean contains(Object o) { if (o == null) { throw new NullPointerException(); } synchronized (lock) { return storage.contains(o); } } public Object[] toArray() { synchronized (lock) { return storage.toArray(); } } public <T> T[] toArray(T[] a) { synchronized (lock) { return storage.toArray(a); } } public boolean containsAll(Collection<?> c) { synchronized (lock) { return storage.containsAll(c); } } public boolean add(E o) { if (o == null) { throw new NullPointerException(); } synchronized (lock) { internalAdd(storage.size(), o); return true; } } public boolean remove(Object o) { if (o == null) { throw new NullPointerException(); } synchronized (lock) { int index = storage.indexOf(o); return remove(index) != null; } } public E get(int index) { synchronized (lock) { return storage.get(index); } } private void internalAdd(int index, E o) { if (o == null) { throw new NullPointerException(); } synchronized (lock) { storage.add(index, o); for (Iterator<WeakReference<DynamicIterator>> it = iterators.iterator(); it.hasNext();) { DynamicIterator i = it.next().get(); if (i == null) { it.remove(); } else { i.addedIndex(index); } } } } @Override public void clear() { synchronized (lock) { storage.clear(); } } public E remove(int index) { synchronized (lock) { E o = storage.remove(index); for (Iterator<WeakReference<DynamicIterator>> it = iterators.iterator(); it.hasNext();) { WeakReference<DynamicIterator> r = it.next(); DynamicIterator i = r.get(); if (i == null) { it.remove(); } else { i.removedIndex(index); } } return o; } } public E first() { synchronized (lock) { if (storage.isEmpty()) { throw new NoSuchElementException(); } else { return storage.get(0); } } } public E last() { synchronized (lock) { if (storage.isEmpty()) { throw new NoSuchElementException(); } else { return storage.get(storage.size() - 1); } } } public class DynamicIterator implements ListIterator<E> { protected int index; protected boolean hasNextCalled; protected E next; protected boolean hasPreviousCalled; protected E previous; protected E last; public DynamicIterator() { this(0); } public DynamicIterator(int index) { this.index = index; } protected void removedIndex(int index) { synchronized (lock) { if (index < this.index || (index == this.index && (hasNextCalled || hasPreviousCalled))) { this.index--; } } } protected void addedIndex(int index) { synchronized (lock) { if (index < this.index || (index == this.index && (next != null || previous != null))) { this.index++; } } } public boolean hasNext() { synchronized (lock) { hasPreviousCalled = false; hasNextCalled = true; next = index < storage.size() ? storage.get(index) : null; return next != null; } } public boolean hasPrevious() { synchronized (lock) { hasPreviousCalled = true; hasNextCalled = false; previous = index > 0 ? storage.get(index - 1) : null; return previous != null; } } public E next() { synchronized (lock) { try { if (!hasNextCalled) { hasNext(); } last = next; if (next != null) { ++index; return next; } else { throw new NoSuchElementException(); } } finally { hasPreviousCalled = false; hasNextCalled = false; next = null; previous = null; } } } public E previous() { synchronized (lock) { try { if (!hasPreviousCalled) { hasPrevious(); } last = previous; if (previous != null) { --index; return previous; } else { throw new NoSuchElementException(); } } finally { hasPreviousCalled = false; hasNextCalled = false; next = null; previous = null; } } } public int nextIndex() { synchronized (lock) { return index; } } public int previousIndex() { synchronized (lock) { return index - 1; } } public void set(E o) { throw new UnsupportedOperationException(); } public void add(E o) { throw new UnsupportedOperationException(); } public void remove() { throw new UnsupportedOperationException(); } } }