/** * Copyright (C) 2009-2010 Wilfred Springer * * This file is part of ICal Combinator. * * ICal Combinator is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2, or (at * your option) any later version. * * ICal Combinator is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License along with * Preon; see the file COPYING. If not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Linking this library statically or dynamically with other modules is making a * combined work based on this library. Thus, the terms and conditions of the * GNU General Public License cover the whole combination. */ package nl.flotsam.tasks; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.Queue; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.logging.Level; import java.util.logging.Logger; /** * A {@link nl.flotsam.tasks.TaskExecutor} that will buffer tasks executing in a limited-capacity queue, waiting for the * first one send in to complete before waiting for the second, etc. */ public class BufferedTaskExecutor implements TaskExecutor { /** * The size of the buffer. */ private final int capacity; /** * The object called in case task execution fails. */ private final TaskExcecutionFailureHandler handler; private final static Logger logger = Logger.getLogger(BufferedTaskExecutor.class.getName()); public BufferedTaskExecutor(int capacity, TaskExcecutionFailureHandler handler) { this.capacity = capacity; this.handler = handler; } public BufferedTaskExecutor(int capacity) { this(capacity, new TaskExcecutionFailureHandler() { @Override public boolean onException(InterruptedException e) { logger.log(Level.WARNING, "Exception while producing results.", e); return true; } @Override public boolean onException(ExecutionException e) { logger.log(Level.WARNING, "Failed to start results.", e); return true; } }); } @Override public <T> void execute(Iterable<? extends Task<? extends T>> productions, Collection<? super T> results) { Queue<Future<? extends T>> buffer = new LinkedList<Future<? extends T>>(); int i = 0; Iterator<? extends Task<? extends T>> productionIterator = productions.iterator(); while (i < capacity && productionIterator.hasNext()) { buffer.offer(productionIterator.next().start()); i++; } Future<? extends T> future = null; while ((future = buffer.poll()) != null) { try { results.add(future.get()); } catch (InterruptedException e) { if (!handler.onException(e)) break; } catch (ExecutionException e) { if (!handler.onException(e)) break; } if (productionIterator.hasNext()) { buffer.offer(productionIterator.next().start()); } } } }