| /* |
| * 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(); |
| } |
| |
| } |
| |
| } |