package com.circlegate.liban.task; import android.os.Bundle; import com.circlegate.liban.task.TaskInterfaces.ITask; import com.circlegate.liban.task.TaskInterfaces.ITaskContext; import com.circlegate.liban.task.TaskInterfaces.ITaskExecutor; import com.circlegate.liban.task.TaskInterfaces.ITaskParam; import com.circlegate.liban.task.TaskInterfaces.ITaskProgressListener; import com.circlegate.liban.task.TaskInterfaces.ITaskResultListener; import com.circlegate.liban.utils.EqualsUtils; import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; public class TaskExecutor implements ITaskExecutor { private static final int CORE_POOL_SIZE = 5; private static final int MAXIMUM_POOL_SIZE = 128; private static final int KEEP_ALIVE = 1; private final ThreadFactory threadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); public Thread newThread(Runnable r) { return new Thread(r, "Thread #" + mCount.getAndIncrement()); } }; private final BlockingQueue<Runnable> poolWorkQueue = new LinkedBlockingQueue<>(10); public final Executor threadPoolExecutor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, poolWorkQueue, threadFactory); private final HashMap<SerialExecutorKey, TaskSerialExecutor> serialExecutors = new HashMap<>(); private final ITaskContext context; public TaskExecutor(ITaskContext context) { this.context = context; } @Override public void executeTask(String id, ITaskParam param, Bundle bundle, boolean canCacheReferenceToParamResult, ITaskResultListener listener, ITaskProgressListener optProgressListener) { SerialExecutorKey key = new SerialExecutorKey(param.getSerialExecutionKey(context), param.isExecutionInParallelForbidden(context) ? null : listener); TaskSerialExecutor executor = serialExecutors.get(key); if (executor == null) { executor = new TaskSerialExecutor(this.context, this.threadPoolExecutor); serialExecutors.put(key, executor); } executor.executeTask(id, param, bundle, canCacheReferenceToParamResult, listener, optProgressListener); } @Override public boolean containsTask(String id, ITaskResultListener listener) { return getTask(id, listener) != null; } @Override public boolean containsAnyTaskByResultHandler(ITaskResultListener listener) { for (TaskSerialExecutor s : serialExecutors.values()) { if (s.containsAnyTaskByResultHandler(listener)) return true; } return false; } @Override public ITask getTask(String id, ITaskResultListener listener) { for (TaskSerialExecutor s : serialExecutors.values()) { ITask task = s.getTask(id, listener); if (task != null) return task; } return null; } @Override public boolean cancelTask(String id, ITaskResultListener listener) { for (TaskSerialExecutor s : serialExecutors.values()) { if (s.cancelTask(id, listener)) return true; } return false; } @Override public void cancelTasksByResultHandler(ITaskResultListener listener) { for (TaskSerialExecutor s : serialExecutors.values()) { s.cancelTasksByResultHandler(listener); } for (Iterator<Entry<SerialExecutorKey, TaskSerialExecutor>> iter = serialExecutors.entrySet().iterator(); iter.hasNext();) { TaskSerialExecutor s = iter.next().getValue(); s.cancelTasksByResultHandler(listener); if (s.getTasksCount() == 0) { iter.remove(); } } } @Override public boolean addSkipCount(String id, ITaskResultListener listener, int skipCount) { for (TaskSerialExecutor s : serialExecutors.values()) { if (s.addSkipCount(id, listener, skipCount)) return true; } return false; } private static class SerialExecutorKey { public final String serialExecutionKey; public final ITaskResultListener optListener; // muze byt null - pokud dany task ma byt spousten seriove pres vsechny listenery public SerialExecutorKey(String serialExecutionKey, ITaskResultListener optListener) { this.serialExecutionKey = serialExecutionKey; this.optListener = optListener; } @Override public int hashCode() { int _hash = 17; _hash = _hash * 29 + EqualsUtils.hashCodeCheckNull(serialExecutionKey); _hash = _hash * 29 + EqualsUtils.hashCodeCheckNull(optListener); return _hash; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (!(o instanceof SerialExecutorKey)) { return false; } SerialExecutorKey lhs = (SerialExecutorKey) o; return lhs != null && EqualsUtils.equalsCheckNull(serialExecutionKey, lhs.serialExecutionKey) && EqualsUtils.equalsCheckNull(optListener, lhs.optListener); } } }