/**
*Task management class
*/
public class TaskManager {
/**
* Log processing class
*/
private static Log logger = LogFactory.getLog(TaskManager.class);
/**
* Thread pool task execution object
*/
private ThreadPoolTaskExecutor taskExecutor;
/**
* Where to save the task results
*/
private final static String resultSavePath = Constants.getDownloadPath()
+ File.separator + Constants.get(Constants.TASK_TEMP_PATH);
/**
* The file name of the task execution result serialized into a file
*/
private static final String RESULT_FILE_NAME = "result";
/**
* The name of the directory where the files generated during task execution are saved
*/
private static final String FILES_DIR = "files";
/**
* Add the task to the thread pool
* @param task task object
* @param params parameters required to execute the task
* @param operatorId The current operator ID
* @return If the addition is successful, return the task number, if the server is busy, return null
*/
public String addTask(AbstractTask task, Map<String, Object> params, String operatorId) {
if (resultSavePath == null || resultSavePath.length() < 1) {
if (logger.isErrorEnabled()) {
logger.error("The save directory is not configured");
}
return null;
}
//If the save directory does not exist, this directory will be created automatically
File saveDir = new File (resultSavePath);
if (!saveDir.exists()) {
saveDir.mkdirs ();
if (saveDir.exists()) {
if (logger.isDebugEnabled()) {
logger.debug("Successfully created save directory");
}
} else {
if (logger.isErrorEnabled()) {
logger.error("Error in configuration directory");
return null;
}
}
}
//if the thread pool is full
if (taskExecutor.getThreadPoolExecutor().getQueue().remainingCapacity() == 0) {
return null;
}
//Set the parameters required when the task is executed
task.setParams(params);
//generate task number
String taskId = generateTaskId(operatorId);
/ / Create the file storage directory generated when the task is executed
String savePath = resultSavePath + File.separator + taskId + File.separator + FILES_DIR + File.separator;
createDir(savePath);
/ / Set the file storage directory generated when the task is executed
task.setSavePath (savePath);
//create task thread object
TaskThread t = new TaskThread(taskId, task);
//Add the task to the connection pool
taskExecutor.execute(t);
return taskId;
}
/**
* Get the result of the task execution
* @param taskId task number
* @return if the result does not exist, return null, otherwise return the result object
* @throws IOException
*/
public TaskResult getTaskResult(String taskId) throws IOException {
File resultFile = new File(resultSavePath + File.separator + taskId + File.separator + RESULT_FILE_NAME + File.separator + RESULT_FILE_NAME);
if (!resultFile.exists()) {//If the result file does not exist
return null;
}
FileInputStream fis = new FileInputStream(resultFile);
ObjectInputStream ois = new ObjectInputStream(fis);
try {
Object obj = ois.readObject();
ois.close();
fis.close();
if (obj == null) {//If the read result is empty, return null
logger.info("result File content is null!");
return null;
} else {
TaskResult result = (TaskResult) obj;
return result;
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} finally {
if (ois != null) {
ois.close();
}
if (fis != null) {
fis.close();
}
}
}
/**
* Get files generated during task execution
* @param taskId task number
* @param fileName The file name to be taken
* @return If the result does not exist, return null, otherwise return the file object
* @throws IOException
*/
public File getTaskResultFile(String taskId, String fileName) throws IOException {
File reportFile = new File(resultSavePath + File.separator + taskId + File.separator + FILES_DIR + File.separator + fileName);
if (!reportFile.exists()) {//If the file does not exist
File resultFile = new File(resultSavePath + File.separator + taskId + File.separator + RESULT_FILE_NAME + File.separator + RESULT_FILE_NAME);
FileInputStream fis = new FileInputStream(resultFile);
ObjectInputStream ois = new ObjectInputStream(fis);
try {
Object obj = ois.readObject();
ois.close();
fis.close();
if (obj == null) {//If the read result is empty, return null
logger.info("result File content is null!");
return null;
} else {
TaskResult result = (TaskResult) obj;
logger.error("task " + result.getTaskClassName() + " not generate report file!");
}
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
} finally {
if (ois != null) {
ois.close();
}
if (fis != null) {
fis.close();
}
}
return null;
}
return reportFile;
}
/**
* Create directory - supports multiple levels
* @param path the path to the directory
*/
private void createDir(String path) {
File dir = new File(path);
dir.mkdirs();
}
/**
* Generate a unique number for the task
* @param operatorId current operator
* @return returns the generated number
*/
private String generateTaskId(String operatorId) {
Date now = new Date();
SimpleDateFormat sdf = new SimpleDateFormat(Constants.YYYY_MM_DD_SSS);
if (operatorId == null || operatorId.length() < 1) {
return sdf.format(now) + Toolkit.getUuidRandomizer().generate();
} else {
return sdf.format(now) + operatorId + Toolkit.getUuidRandomizer().generate();
}
}
public void setTaskExecutor(ThreadPoolTaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
}
/**
* The task thread object that encapsulates the task
* @author oscar.xie
*
*/
private class TaskThread implements Runnable {
/**
* Task number - assigned by task manager
*/
private String taskId;
/**
* task object
*/
private AbstractTask task;
public TaskThread(String taskId, AbstractTask task) {
this.taskId = taskId;
this.task = task;
}
/**
* Task execution method
*/
public void run() {
TaskResult result = task.execute();
if (result != null) {
result.setTaskClassName(task.getClass().getName());
String savePath = resultSavePath + File.separator + this.taskId + File.separator + RESULT_FILE_NAME;
createDir(savePath);
File resultFile = new File(savePath + File.separator + RESULT_FILE_NAME);
FileOutputStream fos = null;
ObjectOutputStream east = null;
try {
fos = new FileOutputStream(resultFile);
oos = new ObjectOutputStream (fos);
oos.writeObject(result);
oos.flush ();
} catch (Exception e) { //This exception generally does not occur
logger.error("write task result File failure:" + e.getMessage());
} finally {
try {
if (oos != null) {
oos.close();
}
if (fos != null) {
fos.close();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
} else {
logger.info("result is null************************************!");
}
}
}
}
</div>
<div>
<!-- Asynchronous task thread operation configuration-->
<bean id="threadPoolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="30" /> <!-- Core thread pool size -->
<property name="keepAliveSeconds" value="200" /> <!-- seconds to keep alive -->
<property name="maxPoolSize" value="35" /> <!-- Maximum thread pool size -->
<property name="queueCapacity" value="1" /> <!-- Waiting queue size -->
</bean>
<!-- Asynchronous Task Manager -->
<bean id="taskManager" class="com.sf.module.bilcommon.util.TaskManager">
<property name="taskExecutor" ref="threadPoolTaskExecutor"></property>
</bean>
/**
* Abstract task class - used for long-running business operations
* @author oscar.xie
*
*/
public abstract class AbstractTask {
/**
* Required parameters for task execution
*/
protected Map<String, Object> params;
/**
* The storage directory of files generated during task execution
*/
protected String savePath;
/**
* The task action to perform
* @return the result object of the execution
*/
public abstract TaskResult execute();
public Map<String, Object> getParams() {
return params;
}
public void setParams(Map<String, Object> params) {
this.params = params;
}
public void setSavePath(String savePath) {
this.savePath = savePath;
}
}
/**
* The result class of task execution
* @author oscar.xie
*
*/
public class TaskResult implements Serializable {
private static final long serialVersionUID = -4396986540034886297L;
/**
* Whether the task was successfully executed
*/
private Boolean success;
/**
* The result of the task execution
*/
private String result;
/**
* The class name of the task execution - used to find the processing class when an error occurs
*/
private String taskClassName;
public TaskResult () {
}
public TaskResult(Boolean success, String result) {
this.success = success;
this.result = result;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
public String getTaskClassName() {
return taskClassName;
}
public void setTaskClassName(String taskClassName) {
this.taskClassName = taskClassName;
}
}