/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.toolkit.modules.concurrency.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import de.rcenvironment.toolkit.modules.concurrency.api.AsyncExceptionListener;
import de.rcenvironment.toolkit.modules.concurrency.api.AsyncTaskService;
import de.rcenvironment.toolkit.modules.concurrency.api.CallablesGroup;
import de.rcenvironment.toolkit.modules.concurrency.api.ThreadGuard;
/**
* Default implementation of {@link CallablesGroup}.
*
* @param <T> the result type of method call of the {@link Callable}s
*
* @author Robert Mischke
*/
public class CallablesGroupImpl<T> implements CallablesGroup<T> {
// frequently instantiated, so use a static logger to avoid overhead
private static final Log sharedLog = LogFactory.getLog(CallablesGroupImpl.class);
private List<Callable<T>> tasks = new ArrayList<Callable<T>>();
private Map<Callable<T>, String> taskIds = new HashMap<>();
private final AsyncTaskService asyncTaskService;
public CallablesGroupImpl(AsyncTaskService asyncTaskService) {
this.asyncTaskService = asyncTaskService;
}
@Override
public void add(Callable<T> task) {
tasks.add(task);
}
@Override
public void add(Callable<T> task, String taskId) {
add(task);
String previousValue = taskIds.put(task, taskId);
if (previousValue != null) {
sharedLog.warn("Add the same task instance again, but with a different task id; the new id (" + taskId
+ ") takes precedence over the old id (" + previousValue + ")");
}
}
@Override
public List<T> executeParallel(AsyncExceptionListener exceptionListener) {
// this should usually not be called from the GUI thread
ThreadGuard.checkForForbiddenThread();
List<Future<T>> futures = new ArrayList<Future<T>>();
for (Callable<T> task : tasks) {
futures.add(asyncTaskService.submit(task, taskIds.get(task)));
}
List<T> results = new ArrayList<T>();
// note: this approach matches the order of results to the order of added tasks
for (Future<T> future : futures) {
try {
results.add(future.get());
} catch (InterruptedException e) {
results.add(null);
if (exceptionListener != null) {
exceptionListener.onAsyncException(e);
}
} catch (ExecutionException e) {
results.add(null);
if (exceptionListener != null) {
exceptionListener.onAsyncException(e);
}
}
}
return results;
}
}