/**
*
*/
package com.trendrr.oss.taskprocessor;
import java.util.Comparator;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.trendrr.oss.FileCache;
import com.trendrr.oss.PriorityUpdateQueue;
import com.trendrr.oss.concurrent.LazyInitObject;
import com.trendrr.oss.executionreport.ExecutionReport;
import com.trendrr.oss.executionreport.ExecutionReportIncrementor;
import com.trendrr.oss.executionreport.ExecutionSubReport;
import com.trendrr.oss.taskprocessor.Task.ASYNCH;
/**
* @author Dustin Norlander
* @created Sep 24, 2012
*
*/
public class TaskProcessor {
protected static Log log = LogFactory.getLog(TaskProcessor.class);
static class TaskProcessorThreadFactory implements ThreadFactory {
static final AtomicInteger poolNumber = new AtomicInteger(1);
final ThreadGroup group;
final AtomicInteger threadNumber = new AtomicInteger(1);
final String namePrefix;
TaskProcessorThreadFactory(String name) {
SecurityManager s = System.getSecurityManager();
group = (s != null)? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "TP-" + name +"-" +
poolNumber.getAndIncrement() +
"-thread-";
}
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(true);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
static LazyInitObject<AsynchTaskRegistery> asynchTasks = new LazyInitObject<AsynchTaskRegistery>() {
@Override
public AsynchTaskRegistery init() {
AsynchTaskRegistery reg = new AsynchTaskRegistery();
reg.start();
return reg;
}
};
protected ExecutorService threadPool = null;
protected String name;
protected TaskCallback callback;
//example threadpool, blocks when queue is full.
// ExecutorService threadPool = new ThreadPoolExecutor(
// 1, // core size
// 30, // max size
// 130, // idle timeout
// TimeUnit.SECONDS,
// new ArrayBlockingQueue<Runnable>(30), // queue with a size
// new ThreadPoolExecutor.CallerRunsPolicy() //if queue is full run in current thread.
// );
/**
* creates a new TaskProcessor with a new executorService
* ExecutorService threadPool = new ThreadPoolExecutor(
1, // core size
numThreads, // max size
130, // idle timeout
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(numThreads), // queue with a size
new ThreadPoolExecutor.CallerRunsPolicy() //if queue is full run in current thread.
);
*
* @param name
* @param callback
* @param numThreads
*/
public static TaskProcessor defaultInstance(String name, TaskCallback callback, int numThreads) {
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
numThreads, // core size
numThreads, // max size
130, // idle timeout
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(numThreads), // queue with a size
new TaskProcessorThreadFactory(name),
new ThreadPoolExecutor.CallerRunsPolicy() //if queue is full run in current thread.
);
return new TaskProcessor(name, callback, threadPool);
}
/**
* creates a new task processor.
*
*
*
*
* @param name The name of this processor. used for execution reporting.
* @param callback Methods called for every task execution. this callback is called before the callback specified in the task. can be null.
* @param executor the executor
*/
public TaskProcessor(String name, TaskCallback callback, ExecutorService executor) {
this.threadPool = executor;
this.name = name;
this.callback = callback;
}
/**
* submits a task for execution.
* @param task
*/
public void submitTask(Task task) {
if (task.getSubmitted() == null) {
task.submitted();
}
task.setProcessor(this);
//add to the executor service..
TaskFilterRunner runner = new TaskFilterRunner(task);
this.threadPool.execute(runner);
}
public void setAsynch(Task t, ASYNCH asynch, long timeout) {
asynchTasks.get().add(t, asynch, timeout);
}
/**
* submit a future, a separate thread will poll it on interval and
* call your callback when isDone is set, or cancel once the timeout has.
*
* callback is executed in one of this processors executor threads.
* @param future
* @param callback
*/
public void submitFuture(Task task, Future future, FuturePollerCallback callback, long timeout) {
FuturePollerWrapper wrapper = new FuturePollerWrapper(future, callback, timeout, task);
asynchTasks.get().addFuture(wrapper);
}
// public void resumeAsynch(String taskId) {
// asynchTasks.get().resume(taskId);
// }
public void resumeAsynch(Task task) {
asynchTasks.get().resume(task);
}
public ExecutorService getExecutor() {
return this.threadPool;
}
/**
* A unique name for this processor. only one instance per name will be allowed.
* @return
*/
public String getName() {
return this.name;
}
public void taskComplete(Task task) {
if (this.callback != null) {
this.callback.taskComplete(task);
}
if (task.getCallback() != null) {
task.getCallback().taskComplete(task);
}
}
public void taskError(Task task, Exception error) {
if (this.callback != null) {
this.callback.taskError(task, error);
}
if (task.getCallback() != null) {
task.getCallback().taskError(task, error);
}
}
/**
* gets the execution report incrementor for TaskProcessor.{this.getName}
*
* @return
*/
public ExecutionReportIncrementor getExecutionReport() {
return new ExecutionSubReport(this.getName(), ExecutionReport.instance("TaskProcessor"));
}
}