/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.component.workflow.execution.internal;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Callable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import de.rcenvironment.core.component.execution.api.ExecutionControllerException;
import de.rcenvironment.core.component.workflow.execution.api.WorkflowExecutionContext;
import de.rcenvironment.core.component.workflow.execution.api.WorkflowExecutionUtils;
import de.rcenvironment.core.toolkitbridge.transitional.ConcurrencyUtils;
import de.rcenvironment.core.utils.common.StringUtils;
import de.rcenvironment.core.utils.common.rpc.RemoteOperationException;
import de.rcenvironment.toolkit.modules.concurrency.api.AsyncExceptionListener;
import de.rcenvironment.toolkit.modules.concurrency.api.CallablesGroup;
import de.rcenvironment.toolkit.modules.concurrency.api.TaskDescription;
/**
* Helper class to call components in parallel.
*
* @author Doreen Seider
*/
public abstract class ParallelComponentCaller {
private static final Log LOG = LogFactory.getLog(ParallelComponentCaller.class);
private final String logMessagePart;
private final Set<String> compsToConsider;
protected ParallelComponentCaller(Set<String> componentsToConsider, WorkflowExecutionContext wfExeCtx) {
this.compsToConsider = componentsToConsider;
logMessagePart = WorkflowExecutionUtils.substituteWorkflowNameAndExeId(wfExeCtx);
}
protected Throwable callParallelAndWait() {
CallablesGroup<Throwable> callablesGroup = ConcurrencyUtils.getFactory().createCallablesGroup(Throwable.class);
for (String executionId : compsToConsider) {
final String finalExecutionId = executionId;
callablesGroup.add(new Callable<Throwable>() {
@Override
@TaskDescription("Call method of workflow component")
public Throwable call() throws Exception {
try {
callSingleComponent(finalExecutionId);
} catch (RemoteOperationException | ExecutionControllerException | RuntimeException e) {
onErrorInSingleComponentCall(finalExecutionId, e);
return e;
}
return null;
}
}, StringUtils.format("Call component ('%s'): %s", finalExecutionId, getMethodToCallAsString()));
}
List<Throwable> throwables = callablesGroup.executeParallel(new AsyncExceptionListener() {
@Override
public void onAsyncException(Exception e) {
// should never happen
}
});
for (Throwable t : throwables) {
if (t != null) {
logError(t);
}
}
for (Throwable t : throwables) {
if (t != null) {
return new Throwable(StringUtils.format("Failed to %s component(s)", getMethodToCallAsString()), t);
}
}
return null;
}
protected abstract void callSingleComponent(String compExeId) throws ExecutionControllerException, RemoteOperationException;
protected abstract String getMethodToCallAsString();
protected void onErrorInSingleComponentCall(String compExeId, Throwable t) {}
protected void logError(Throwable t) {
if (t instanceof RemoteOperationException) {
LOG.error(StringUtils.format("Failed to %s component(s) of %s; cause: %s",
getMethodToCallAsString(), logMessagePart, t.toString()));
} else {
LOG.error(StringUtils.format("Failed to %s component(s) of %s", getMethodToCallAsString(), logMessagePart, t));
}
}
}