blob: 3f5f2d8fd8a9d9bc17fe41c786818d4dee6ea210 [file] [log] [blame]
/*
* 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: 896324 $, $Date: 2010-01-06 06:05:04 +0000 (Wed, 06 Jan 2010) $
*/
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();
}
}
}