RoundRobinQueue.java
- package gov.usgs.earthquake.util;
- import java.util.ArrayList;
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.NoSuchElementException;
- import java.util.Queue;
- /**
- * An abstract base class for round-robin queueing.
- *
- * Sub classes should implement the {@link #getQueueId(Object)} to control how
- * objects are added to queues.
- *
- * @param <T>
- * type of object being queued.
- */
- public class RoundRobinQueue<T> implements Queue<T> {
- /**
- * Map of queues, keyed by queue id (as determined by
- * {@link #getQueueId(Object)}).
- */
- private final HashMap<String, LinkedList<T>> queueMap = new HashMap<String, LinkedList<T>>();
- /**
- * List of queues, same as in map, in round-robin order.
- */
- private final LinkedList<LinkedList<T>> queueList = new LinkedList<LinkedList<T>>();
- /** Default constructor. */
- public RoundRobinQueue() {
- }
- /**
- * This method determines which queue an object uses.
- *
- * @param object
- * the object being added.
- * @return id of the queue where object should be added.
- */
- protected String getQueueId(T object) {
- return object.toString();
- }
- /** ===================== BLOCKING QUEUE METHODS ======================= **/
- /**
- * Add an item to the queue.
- *
- * @param e
- * item to add
- * @return true if added.
- */
- @Override
- public boolean add(T e) {
- // find queue
- String queueId = getQueueId(e);
- LinkedList<T> queue = queueMap.get(queueId);
- if (queue == null) {
- // create queue
- queue = new LinkedList<T>();
- queueMap.put(queueId, queue);
- queueList.add(queue);
- }
- // add to queue
- return queue.add(e);
- }
- /**
- * Add an item to the queue, if possible.
- *
- * @param e
- * item to add
- * @return true if added, false otherwise.
- */
- @Override
- public boolean offer(T e) {
- try {
- // this could in theory throw an unchecked exception
- return this.add(e);
- } catch (Exception ex) {
- return false;
- }
- }
- /**
- * Retrieves and removes the head of this queue.
- *
- * @return first element in queue.
- * @throws NoSuchElementException
- * if queue is empty.
- */
- @Override
- public T remove() {
- if (queueList.size() == 0) {
- throw new NoSuchElementException();
- }
- T next = null;
- // find queue
- LinkedList<T> nextQueue = queueList.removeFirst();
- // take first item
- next = nextQueue.removeFirst();
- // reschedule queue
- if (nextQueue.size() == 0) {
- // queue is empty, remove
- String queueId = getQueueId(next);
- queueMap.remove(queueId);
- } else {
- // move to end of round robin list
- queueList.add(nextQueue);
- }
- return next;
- }
- /**
- * Retrieves, but does not remove, the head of this queue. This method
- * differs from the {@link #peek()} method only in that it throws an
- * exception if this queue is empty.
- *
- * @return the head of this queue.
- * @throws NoSuchElementException
- * if this queue is empty.
- */
- @Override
- public T element() {
- if (queueList.size() == 0) {
- throw new NoSuchElementException();
- }
- LinkedList<T> nextQueue = queueList.getFirst();
- return nextQueue.getFirst();
- }
- /**
- * Retrieves and removes the head of this queue.
- *
- * @return the head of this queue, or null if this queue is empty.
- */
- @Override
- public T poll() {
- try {
- return remove();
- } catch (NoSuchElementException nsee) {
- return null;
- }
- }
- /**
- * Retrieves, but does not remove, the head of this queue, returning null if
- * this queue is empty.
- *
- * @return the head of this queue, or null if this queue is empty.
- */
- @Override
- public T peek() {
- try {
- return element();
- } catch (NoSuchElementException nsee) {
- return null;
- }
- }
- /** ======================= COLLECTION METHODS ========================= **/
- @Override
- public boolean addAll(Collection<? extends T> c) {
- Iterator<? extends T> iter = c.iterator();
- boolean added = false;
- while (iter.hasNext()) {
- added = add(iter.next()) || added;
- }
- return added;
- }
- @Override
- public void clear() {
- queueList.clear();
- queueMap.clear();
- }
- @Override
- public boolean containsAll(Collection<?> c) {
- Iterator<?> iter = c.iterator();
- while (iter.hasNext()) {
- if (!contains(iter.next())) {
- return false;
- }
- }
- return true;
- }
- @Override
- public boolean isEmpty() {
- return queueList.isEmpty();
- }
- @Override
- public boolean removeAll(Collection<?> c) {
- Iterator<?> iter = c.iterator();
- boolean removed = false;
- while (iter.hasNext()) {
- removed = remove(iter.next()) || removed;
- }
- return removed;
- }
- @Override
- public int size() {
- int size = 0;
- Iterator<LinkedList<T>> iter = queueList.iterator();
- while (iter.hasNext()) {
- size = size + iter.next().size();
- }
- return size;
- }
- @Override
- public boolean contains(Object o) {
- try {
- @SuppressWarnings("unchecked")
- String queueId = getQueueId((T) o);
- LinkedList<T> queue = queueMap.get(queueId);
- return queue.contains(o);
- } catch (Exception e) {
- return false;
- }
- }
- @Override
- public boolean remove(Object o) {
- try {
- @SuppressWarnings("unchecked")
- String queueId = getQueueId((T) o);
- LinkedList<T> queue = queueMap.get(queueId);
- boolean removed = queue.remove(o);
- if (queue.isEmpty()) {
- queueMap.remove(queueId);
- queueList.remove(queue);
- }
- return removed;
- } catch (Exception e) {
- return false;
- }
- }
- /** ==================== HORRIBLY INEFFICIENT =========================== */
- /**
- * Deep copy of another RoundRobinQueue.
- *
- * This method is used for semi-destructive iteration methods.
- *
- * NOTE: this assumes {@link #getQueueId(Object)} behaves the same for this
- * and that.
- *
- * @param that a RoundRobinQueue to make a deep copy of
- */
- public RoundRobinQueue(final RoundRobinQueue<T> that) {
- Iterator<LinkedList<T>> iter = that.queueList.iterator();
- while (iter.hasNext()) {
- // copy list
- LinkedList<T> copy = new LinkedList<T>(iter.next());
- // add to round robin list
- this.queueList.add(copy);
- // add to map
- String queueId = that.getQueueId(copy.get(0));
- this.queueMap.put(queueId, copy);
- }
- }
- /**
- * Flatten queue to a list.
- *
- * Creates a copy (see {@link #RoundRobinQueue(RoundRobinQueue)}, then
- * builds list by polling until it is empty.
- *
- * @return list of all items currently in queue.
- */
- public List<T> toList() {
- ArrayList<T> list = new ArrayList<T>(this.size());
- RoundRobinQueue<T> copy = new RoundRobinQueue<T>(this);
- while (true) {
- T next = copy.poll();
- if (next == null) {
- // done
- break;
- }
- list.add(next);
- }
- return list;
- }
- @Override
- public Iterator<T> iterator() {
- return this.toList().iterator();
- }
- @Override
- public Object[] toArray() {
- return this.toList().toArray();
- }
- @Override
- public <T2> T2[] toArray(T2[] array) {
- return this.toList().toArray(array);
- }
- @Override
- public boolean retainAll(Collection<?> c) {
- List<T> toremove = this.toList();
- toremove.removeAll(c);
- return this.removeAll(toremove);
- }
- }