package org.oddjob.values; import java.util.Iterator; import java.util.LinkedList; import org.oddjob.jobs.structural.ForEachJob; /** * Provide a service that supports a blocking Iterable that can be * used as the values for a {@link ForEachJob}. * <p> * Values are placed on the queue by setting the value property. * <p> * When this service is stopped any iterators in use return false from * their hasNext method. This will cause the foreach job to complete. * * @author rob * */ public class ValueQueueService implements ValueConsumer<Object> { /** The queue. */ private final LinkedList<Object> queue = new LinkedList<Object>(); /** Has the service been started. */ private boolean started; /** The name of this service. */ private String name; /** * Start. */ public void start() { synchronized (queue) { started = true; } } /** * Stop. */ public void stop() { started = false; synchronized(queue) { queue.notifyAll(); } } /** * The implementation of the blocking iterator. */ class BlockerIterator implements Iterator<Object> { private Object next; @Override public boolean hasNext() { while (started) { synchronized (queue) { if (queue.isEmpty()) { try { queue.wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return false; } } else { next = queue.removeFirst(); return true; } } } return false; } @Override public Object next() { return next; } @Override public void remove() { throw new UnsupportedOperationException(); } } /** * Get the values. * * @return A blocking Iterable. Never null. */ public Iterable<Object> getValues() { return new Iterable<Object>() { @Override public Iterator<Object> iterator() { return new BlockerIterator(); } }; } /** * Set a value. This causes the value to be placed on the queue. * * @param object */ @Override public void setValue(Object object) { synchronized (queue) { if (!started) { throw new IllegalStateException(this + " is not started."); } queue.add(object); queue.notifyAll(); } } /** * Get the current size of the queue. * * @return The size. */ public int getSize() { synchronized (queue) { return queue.size(); } } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { if (name == null) { return getClass().getSimpleName(); } else { return name; } } }