package org.signalml.plugin.method.logic; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ThreadFactory; import org.apache.log4j.Logger; import org.signalml.method.ComputationException; import org.signalml.method.MethodExecutionTracker; import org.signalml.plugin.data.logic.PluginComputationMgrStepResult; import org.signalml.plugin.data.logic.PluginMgrData; import org.signalml.plugin.exception.PluginToolAbortException; import org.signalml.plugin.exception.PluginToolInterruptedException; public abstract class PluginComputationMgr<Data extends PluginMgrData, Result> { protected static final Logger log = Logger.getLogger(PluginComputationMgr.class); private class CheckedThreadFactory implements ThreadFactory { private final ThreadGroup group; public CheckedThreadFactory(ThreadGroup group) { this.group = group; } @Override public Thread newThread(Runnable r) { Thread thread = new Thread(this.group, r); thread.setDaemon(true); return thread; } } protected Data data; protected MethodExecutionTracker tracker; protected Map<IPluginComputationMgrStep, PluginComputationMgrStepResult> stepResults; private ThreadFactory threadFactory; private PluginCheckedThreadGroup threadGroup; public Result compute(Data data, MethodExecutionTracker tracker) throws ComputationException { this.data = data; this.tracker = tracker; try { return this.doCompute(); } catch (PluginToolAbortException e) { return null; } catch (PluginToolInterruptedException e) { this.handleInterrupt(); return null; } finally { tracker.setMessage(null); } } protected ThreadFactory getThreadFactory() { if (this.threadFactory == null) { this.threadFactory = new CheckedThreadFactory(this.getThreadGroup()); } return this.threadFactory; } protected PluginCheckedThreadGroup getThreadGroup() { if (this.threadGroup == null) { this.threadGroup = new PluginCheckedThreadGroup(); } return this.threadGroup; } protected Result doCompute() throws ComputationException, PluginToolInterruptedException, PluginToolAbortException { this.stepResults = new HashMap<IPluginComputationMgrStep, PluginComputationMgrStepResult>(); Collection<IPluginComputationMgrStep> steps = this.prepareStepChain(); Map<IPluginComputationMgrStep, Integer> tickMap = new HashMap<IPluginComputationMgrStep, Integer>( steps.size()); for (IPluginComputationMgrStep step : steps) { step.initialize(); tickMap.put(step, step.getStepNumberEstimate()); } this.initializeRun(tickMap); PluginComputationMgrStepResult stepResult = null; for (IPluginComputationMgrStep step : steps) { stepResult = step.run(stepResult); this.stepResults.put(step, stepResult); } return this.prepareComputationResult(); } protected abstract Collection<IPluginComputationMgrStep> prepareStepChain(); protected void initializeRun( Map<IPluginComputationMgrStep, Integer> stepTicks) { } protected abstract Result prepareComputationResult(); private void handleInterrupt() throws ComputationException { if (this.threadGroup != null) { Throwable cause = this.threadGroup.getCause(); if (cause != null) { log.error("Error in worker thread " + this.threadGroup.getCausingThread().getId()); throw new ComputationException(cause); } } } }