diff --git a/scm-core/src/main/java/sonia/scm/collect/IterableQueue.java b/scm-core/src/main/java/sonia/scm/collect/IterableQueue.java new file mode 100644 index 0000000000..353ccf919b --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/collect/IterableQueue.java @@ -0,0 +1,204 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.collect; + +//~--- non-JDK imports -------------------------------------------------------- + +import com.google.common.collect.Iterators; +import com.google.common.collect.Lists; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +//~--- JDK imports ------------------------------------------------------------ + +import java.util.Iterator; +import java.util.List; + +/** + * A iterable queue. The queue can have multiple consumer {@link Iterator}, + * which can iterate over all items of the queue until the end of the queue is + * reached. The end of the queue if reached, if a producer call the method + * {@link #endReached()} and the iterator has consumed all items of the backend + * list. + * + * @author Sebastian Sdorra + * + * @since 1.29 + * @param type of the queued items + */ +public final class IterableQueue implements Iterable +{ + + /** + * the logger for IterableQueue + */ + private static final Logger logger = + LoggerFactory.getLogger(IterableQueue.class); + + //~--- constructors --------------------------------------------------------- + + /** + * Constructs a new {@link IterableQueue} with the default implementation + * of the backing list. + * + */ + public IterableQueue() + { + list = Lists.newArrayList(); + } + + /** + * Constructs a new {@link IterableQueue} with the given backing list. + * + * + * @param list backend list for the queue + */ + public IterableQueue(List list) + { + this.list = list; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Mark that the end of the queue is reached and notify all consuming + * iterators. + * + * @throws IllegalStateException if the end of the queue if already reached + */ + public synchronized void endReached() + { + if (endReached) + { + throw new IllegalStateException( + "the end of the queue is already reached"); + } + endReached = true; + notifyAll(); + } + + /** + * Returns a new consuming iterator for the queue. The methods + * {@link Iterator#hasNext()} and {@link Iterator#next()} of the + * {@link Iterator} will block until the next item is pushed to the queue, if + * the queue is empty and the end is not reached. The + * {@link Iterator#remove()} method of the {@link Iterator} is not implemented + * and will throw a {@link UnsupportedOperationException}. + * + * + * @return new consuming iterator + */ + @Override + public Iterator iterator() + { + Iterator iterator; + + if (endReached) + { + logger.trace("create list iterator"); + iterator = Iterators.unmodifiableIterator(list.iterator()); + } + else + { + logger.trace("create queue iterator"); + iterator = new QueueIterator(this); + } + + return iterator; + } + + /** + * Push a new item to the queue and notify all consuming iterators. + * + * @throws IllegalStateException if the end of the queue is already reached + * @param item item to push to the queue + */ + public synchronized void push(T item) + { + if (endReached) + { + throw new IllegalStateException( + "the end of the queue is already reached"); + } + + list.add(item); + notifyAll(); + } + + /** + * Returns the current size of the queue. + * + * + * @return current size + */ + int size() + { + return list.size(); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Returns the item at the specified index in this queue. + * + * + * @param index index of the item in the queue + * + * @return item at the current index + */ + T get(int index) + { + return list.get(index); + } + + /** + * Returns true if the end of the queue is reached. + * + * + * @return true if the end is reached + */ + boolean isEndReached() + { + return endReached; + } + + //~--- fields --------------------------------------------------------------- + + /** marker for the end of the queue */ + private boolean endReached = false; + + /** backend list of the queue */ + private List list; +} diff --git a/scm-core/src/main/java/sonia/scm/collect/QueueIterator.java b/scm-core/src/main/java/sonia/scm/collect/QueueIterator.java new file mode 100644 index 0000000000..10b3bf8a78 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/collect/QueueIterator.java @@ -0,0 +1,133 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + + +package sonia.scm.collect; + +//~--- JDK imports ------------------------------------------------------------ + +import com.google.common.collect.UnmodifiableIterator; +import java.util.NoSuchElementException; +import java.util.concurrent.TimeUnit; + +/** + * Iterator for the {@link IterableQueue}. The {@link QueueIterator} should + * only be created from the {@link IterableQueue} by calling the + * {@link IterableQueue#iterator()}. + * + * @author Sebastian Sdorra + * + * @since 1.29 + * @param type of the queued items + */ +public final class QueueIterator extends UnmodifiableIterator +{ + + /** + * Constructs a new {@link QueueIterator} for the given {@link IterableQueue}. + * + * + * @param queue backend queue + */ + QueueIterator(IterableQueue queue) + { + this.queue = queue; + } + + //~--- methods -------------------------------------------------------------- + + /** + * Returns the next item in the queue. This method will block until the next + * item is pushed to the queue, if the queue is empty and the end is not + * reached. + * + * @throws NoSuchElementException if the iteration has no more elements + * + * @return the next item in the queue + */ + @Override + public T next() + { + if ( ! hasNext() ){ + throw new NoSuchElementException("no more items in the queue"); + } + return queue.get(index++); + } + + //~--- get methods ---------------------------------------------------------- + + /** + * Returns {@code true} {@code true} if the queue has more items. + * This method will block until the next item is pushed to the queue, if the + * queue is empty and the end is not + * reached. + * + * + * @return {@code true} {@code true} if the queue has more items + */ + @Override + public boolean hasNext() + { + boolean result = false; + + if (index < queue.size()) + { + result = true; + } + else if (!queue.isEndReached()) + { + synchronized (queue) + { + try + { + queue.wait(TimeUnit.SECONDS.toMillis(10)); + result = index < queue.size(); + } + catch (InterruptedException ex) + { + throw new RuntimeException(ex); + } + } + } + + return result; + } + + + //~--- fields --------------------------------------------------------------- + + /** queue for the iterator */ + private final IterableQueue queue; + + /** current index */ + private int index = 0; +} diff --git a/scm-core/src/main/java/sonia/scm/collect/package-info.java b/scm-core/src/main/java/sonia/scm/collect/package-info.java new file mode 100644 index 0000000000..3e1629f137 --- /dev/null +++ b/scm-core/src/main/java/sonia/scm/collect/package-info.java @@ -0,0 +1,34 @@ +/** + * Copyright (c) 2010, Sebastian Sdorra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of SCM-Manager; nor the names of its + * contributors may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * http://bitbucket.org/sdorra/scm-manager + * + */ + + +/** Collection classes for SCM-Manager */ +package sonia.scm.collect; \ No newline at end of file