/** * */ package ma.car.tishadow.bundle.update.tasks; import java.text.MessageFormat; import java.util.ArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import ma.car.tishadow.bundle.update.RequestProxy; import ma.car.tishadow.bundle.update.TishadowBundleUpdateModule; import ma.car.tishadow.bundle.update.util.TiAppUtil; import org.appcelerator.kroll.common.Log; /** * @author wei.ding */ public class ParallelTask extends ArrayList<Task> implements Task { private static final long serialVersionUID = TishadowBundleUpdateModule.BACKWARD_COMPATIBLE_UID; private static final AtomicInteger PARALLEL_TASK_IDENTIFIER = new AtomicInteger(1); private final String name; private final int identifier; public ParallelTask() { this((String) null); } /** * Add a list of tasks into current task, which can be executed in parallel. * @param tasks */ public ParallelTask(Task... tasks) { this((String) null, tasks); } /** * Add a list of tasks into current task, which can be executed in parallel. * @param tasks */ public ParallelTask(String name, Task... tasks) { this.name = name == null ? this.getClass().getName() : name; this.identifier = PARALLEL_TASK_IDENTIFIER.getAndIncrement(); for (Task task : tasks) { this.add(task); } } /* * (non-Javadoc) * @see ma.car.tishadow.bundle.update.tasks.Task#execute() */ @Override public boolean execute(final RequestProxy context) { if (this.size() == 0) { Log.i(getTag(), MessageFormat.format("No tasks in current parallel task ''{0}'', marked it as executed successfully.", this.getName())); return true; } Log.i(getTag(), "Starting parallel task '" + this.getName() + "'..."); final CountDownLatch latch = new CountDownLatch(this.size()); final AtomicBoolean expectedResult = new AtomicBoolean(true); for (final Task task : this) { executeAsyn(context, latch, expectedResult, task); } try { latch.await(); if (expectedResult.get()) { Log.i(getTag(), "Parallel task '" + this.getName() + "' executed successfully."); } return expectedResult.get(); } catch (InterruptedException e) { Log.e(getTag(), "Task '" + this.getName() + "' has been interrupted."); } return false; } private void executeAsyn(final RequestProxy context, final CountDownLatch latch, final AtomicBoolean expectedResult, final Task task) { TiAppUtil.THREAD_POOL.execute(new Runnable() { @Override public void run() { boolean result = task.execute(context); if (!result) { if (expectedResult.compareAndSet(true, false)) { String message = "ParallelTask ''{0}'' executed completely because fail to execute ''{1}''."; Log.i(getTag(), MessageFormat.format(message, ParallelTask.this.getName(), task.getClass().getName())); } else { Log.i(getTag(), "The result of ParallelTask '" + ParallelTask.this.getName() + "' has been set to false."); } } Log.i(getTag(), "Task '" + task.getClass().getName() + "' executed successfully."); latch.countDown(); } }); } private String getTag() { String simpleName = this.getClass().getSimpleName(); return ("".equals(simpleName) ? "ParallelTask" : simpleName) + "-" + this.identifier; } /** * @return the name */ private String getName() { return name; } }