package com.dgrid.helpers.impl; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import jsr166y.forkjoin.ForkJoinExecutor; import jsr166y.forkjoin.ForkJoinPool; import jsr166y.forkjoin.RecursiveAction; import com.dgrid.gen.Joblet; import com.dgrid.gen.JobletResult; import com.dgrid.helpers.ForkJoinHelper; import com.dgrid.service.DGridClient; @SuppressWarnings("unchecked") public class ForkJoinHelperImpl implements ForkJoinHelper { private Log log = LogFactory.getLog(getClass()); private DGridClient gridClient; public void setGridClient(DGridClient gridClient) { this.gridClient = gridClient; } public List executeConcurrently(List<Callable> tasks, int maxThreadCount) { log.trace("executeConcurrently()"); int threadCount = (maxThreadCount > tasks.size()) ? tasks.size() : maxThreadCount; ForkJoinExecutor fjPool = new ForkJoinPool(threadCount); FJAction actions = new FJAction((Callable[]) tasks .toArray(new Callable[tasks.size()])); if (log.isDebugEnabled()) { log.debug(String.format( "Calling ForkJoinPool.invoke() with %1$d tasks", tasks .size())); } fjPool.invoke(actions); List results = actions.getResults(); if (log.isDebugEnabled()) { log.debug("ForkJoinPool.invoke() returned"); log.debug(String.format("Results: %1$s", results)); } return results; } public List<JobletResult> gridExecuteConcurrently(List<Joblet> joblets, int maxThreadCount, int retries) { List<Callable> tasks = (List<Callable>) new ArrayList<Callable>(joblets .size()); for (Joblet joblet : joblets) { Callable<JobletResult> c = new GridCallable(gridClient, joblet, retries); tasks.add(c); } List results = executeConcurrently(tasks, maxThreadCount); return results; } private static class GridCallable implements Callable<JobletResult> { private DGridClient gridClient; private Joblet joblet; private int retries; private GridCallable(DGridClient gridClient, Joblet joblet, int retries) { this.gridClient = gridClient; this.joblet = joblet; this.retries = retries; } public JobletResult call() throws Exception { return gridClient.gridExecute(joblet, retries); } } private static class FJAction extends RecursiveAction { private Callable[] tasks; private List results; public FJAction(Callable[] tasks) { this.tasks = tasks; } private List getResults() { return results; } @Override protected void compute() { results = new ArrayList(tasks.length); if (tasks.length == 1) { try { results.add(computeSequentially()); } catch (Exception e) { results.add(e); } finally { } } else { FJAction[] actions = new FJAction[tasks.length]; for (int i = 0; i < actions.length; ++i) { actions[i] = new FJAction(new Callable[] { tasks[i] }); } forkJoin(actions); results = merge(actions); } } private List merge(FJAction[] actions) { List values = new ArrayList(); for (FJAction action : actions) { List results = action.getResults(); for (Object object : results) { values.add(object); } } return values; } private Object computeSequentially() throws Exception { return tasks[0].call(); } } }