package net.spy.concurrent;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import net.spy.SpyObject;
/**
* Map a collection of objects with a given transformer.
*/
public class Mapper<F, T> extends SpyObject {
private final ExecutorService executor;
/**
* Construct a Mapper backed by an in-place executor.
*/
public Mapper() {
this(new DummyExecutor());
}
/**
* Construct a Mapper backed by the given executor service.
*/
public Mapper(ExecutorService x) {
super();
executor=x;
}
/**
* Transform the given collection using the given transformer.
*
* @param trans the transformer
* @param in the collection to transform
* @return a list of transformed values in the same order in which they
* were iterated by the given collection
* @throws InterruptedException if we're interrupted while processing
*/
public List<T> transform(Transformer<F,T> trans,
Collection<? extends F> in) throws InterruptedException {
List<T> rv=new ArrayList<T>(in.size());
List<Future<T>> fs=executor.invokeAll(
new TransformingCollection<F,T>(trans, in));
for(Future<T> f : fs) {
try {
rv.add(f.get());
} catch (ExecutionException e) {
throw new RuntimeException("Error processing get", e);
}
}
return rv;
}
static class DummyExecutor extends AbstractExecutorService {
private boolean isShutdown=false;
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
return false;
}
public boolean isShutdown() {
return isShutdown;
}
public boolean isTerminated() {
return isShutdown;
}
public void shutdown() {
isShutdown=true;
}
public List<Runnable> shutdownNow() {
return Collections.emptyList();
}
public void execute(Runnable command) {
assert !isShutdown : "I'm already shutdown";
command.run();
}
}
private static class TransformingCollection<F,T>
extends AbstractCollection<Callable<T>> {
final Collection<? extends F> backingCollection;
final Transformer<F, T> transformer;
public TransformingCollection(Transformer<F,T> trans,
Collection<? extends F> in) {
transformer=trans;
backingCollection=in;
}
@Override
public Iterator<Callable<T>> iterator() {
return new Titerator();
}
@Override
public int size() {
return backingCollection.size();
}
class Titerator implements Iterator<Callable<T>> {
final Iterator<? extends F> backingIterator=
backingCollection.iterator();
public boolean hasNext() {
return backingIterator.hasNext();
}
public Callable<T> next() {
return new Callable<T>() {
public T call() throws Exception {
return transformer.transform(backingIterator.next());
}
};
}
public void remove() {
throw new UnsupportedOperationException();
}
}
}
}