package com.itedge.infrastructure.web.controller.task.impl;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.task.Task;
import org.springframework.context.MessageSource;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import com.itedge.infrastructure.constants.InfrastructureConstants;
import com.itedge.infrastructure.domain.IProcessEntity;
import com.itedge.infrastructure.taskdata.ITaskDataEntity;
import com.itedge.infrastructure.taskdata.TaskDataUtil;
import com.itedge.infrastructure.util.ContextUtil;
import com.itedge.infrastructure.util.WebUtil;
import com.itedge.infrastructure.web.controller.task.ITaskController;
import com.itedge.infrastructure.web.dto.TaskAvailabilityResponse;
import com.itedge.infrastructure.web.taskhandler.ITaskDataHandler;
import com.itedge.infrastructure.web.taskhandler.TaskHandlerException;
/**
* Abstract base class for all task controller with {@link IProcessEntity} process object.
*
* @author jhe
*
*/
public abstract class AbstractTaskController implements ITaskController {
/**
* Message source used for translations.
*/
protected MessageSource messageSource;
/**
* Task name parameter, used in request mapping.
*/
protected static final String TASK_NAME_PARAM = "taskName";
/**
* Process id parameter.
*/
protected static final String PROC_ID = "procId";
/**
* Task history parameter.
*/
protected static final String TASK_HISTORY_PARAM = "isHistory";
/**
* Path for undefined task, controller will delegate to this view if task name is not found in taskHandlerMapping.
*/
protected static final String UNDEFINED_TASK = "undefindedTask";
/**
* Key for model attribute of message, that task was completed in meantime.
*/
protected static final String MODEL_ATTR_TASK_COMPLETED = "taskCompletedMessage";
/**
* Key for putting and retrieving task object id from session.
*/
protected static final String SESSION_ATTR_TASK_ID = "taskId";
/**
* Key for putting and retrieving process id from session.
*/
protected static final String SESSION_ATTR_PROC_ID = "linkedObjectId";
/**
* Key for putting and retrieving task data object from session.
*/
protected static final String SESSION_ATTR_TASK_DATA_OBJECT = "taskDataObject";
/**
* Map with task handler mapping, to be initialized and filled in concrete subclasses.
*/
protected Map<String,ITaskDataHandler> taskHandlerMapping = new HashMap<String,ITaskDataHandler>();
/**
* Default constructor, only argument is messageSource.
*
* @param messageSource
*/
protected AbstractTaskController(MessageSource messageSource) {
this.messageSource = messageSource;
}
/**
* Method for retrieving {@link Task} living task instances, to be overridden in concrete subclasses.
*
* @param id
* @return task instance for given task id
*/
protected abstract Task getCurrentTask(String id);
/**
* Method for retrieving {@link HistoricTaskInstance} historic task instances, to be overridden in concrete subclasses.
*
* @param id
* @return historic task instance for given task id
*/
protected abstract HistoricTaskInstance getHistoryTask(String id);
/**
* Method for retrieving linked {@link IProcessEntity} linked process objects by their procId.
*
* @param procId
* @return linked process entity instance for specified process instance id
*/
protected abstract IProcessEntity getLinkedObject(String procId);
/**
* Returns task view path.
*
* @return task view path
*/
protected abstract String getTaskViewPath();
/**
* Returns linked object view path.
*
* @return linked entity view path
*/
protected abstract String getLinkedObjectViewPath();
/**
* Returns name of linked object attribute - to be put in MVC model.
*
* @return linked entity model key
*/
protected abstract String getLinkedObjectAttrName();
@Override
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String showTask(@PathVariable("id") String id,
@RequestParam(value = TASK_HISTORY_PARAM, required = true) Boolean historyParam,
@RequestParam(value = PROC_ID, required = true) String procId, Model model,
HttpServletRequest request) throws TaskHandlerException {
Task currentTask = null;
HistoricTaskInstance historyTask = null;
IProcessEntity linkedObject = getLinkedObject(procId);
if (Boolean.FALSE.equals(historyParam)) {
request.setAttribute(TASK_HISTORY_PARAM, false);
currentTask = getCurrentTask(id);
// living task instance requested, but already completed by other actor
if (currentTask == null) {
historyTask = getHistoryTask(id);
if (historyTask != null) {
// force historic view with additional info, who and when already completed task
request.setAttribute(TASK_HISTORY_PARAM, true);
Object[] arguments = new Object[2];
arguments[0] = historyTask.getAssignee();
arguments[1] = new SimpleDateFormat(InfrastructureConstants.ISO_DATE_TIME_FORMAT)
.format(historyTask.getEndTime());
model.addAttribute(MODEL_ATTR_TASK_COMPLETED,
messageSource.getMessage(InfrastructureConstants.TASK_ALREADY_COMPLETED,
arguments, InfrastructureConstants.UNDEFINED_MESSAGE, request.getLocale()));
} else {
// there is not living, nor historic instance, task is non existing / was deleted
request.getSession()
.setAttribute(InfrastructureConstants.SESSION_ATTR_FROM_NON_EXISTING_TASK, true);
return "redirect:/" + getLinkedObjectViewPath() +
WebUtil.encodeUrlPathSegment(linkedObject.getId().toString(),
request);
}
}
} else {
request.setAttribute(TASK_HISTORY_PARAM, true);
historyTask = getHistoryTask(id);
}
String taskName = currentTask != null ? currentTask.getName() : historyTask.getName();
// taskId is the same for active or history process task
String taskId = currentTask != null ? currentTask.getId() : historyTask.getId();
if (Boolean.FALSE.equals(historyParam)) {
request.getSession().setAttribute(SESSION_ATTR_TASK_ID, taskId);
request.getSession().setAttribute(SESSION_ATTR_PROC_ID, procId);
}
String path = UNDEFINED_TASK; // unknown task type
if (taskHandlerMapping.containsKey(taskName)) {
path = taskName;
request.setAttribute(TASK_NAME_PARAM, taskName);
ITaskDataHandler<ITaskDataEntity, IProcessEntity> handler = taskHandlerMapping.get(path);
Map<String,?> data = handler.loadTaskData(taskId, linkedObject, historyParam);
model.addAllAttributes(data);
}
model.addAttribute(getLinkedObjectAttrName(), linkedObject);
return getTaskViewPath() + path;
}
@Override
@RequestMapping(params = TASK_NAME_PARAM, method = {RequestMethod.POST, RequestMethod.PUT})
public String saveTask(Model model, HttpServletRequest request) throws TaskHandlerException {
String path = request.getParameter(TASK_NAME_PARAM);
String taskId = (String) request.getSession().getAttribute(SESSION_ATTR_TASK_ID);
String procId = (String) request.getSession().getAttribute(SESSION_ATTR_PROC_ID);
IProcessEntity linkedObject = getLinkedObject(procId);
if (taskHandlerMapping.containsKey(path)) {
ITaskDataHandler<ITaskDataEntity, IProcessEntity> handler = taskHandlerMapping.get(path);
ITaskDataEntity taskData = handler.bindTaskData(request, linkedObject);
TaskDataUtil.setLastUpdate(taskData, ContextUtil.getLoggedUsername());
if (RequestMethod.PUT.name().equals(request.getMethod())) {
handler.saveTaskData(taskData);
} else if (RequestMethod.POST.name().equals(request.getMethod())) {
handler.saveTaskDataAndPushProcess(taskData, linkedObject, taskId);
}
}
return "redirect:/" + getLinkedObjectViewPath() +
WebUtil.encodeUrlPathSegment(linkedObject.getId().toString(), request);
}
@Override
@RequestMapping(value = "/lock", params = TASK_NAME_PARAM,
method = RequestMethod.POST, headers = "Accept=application/json")
public @ResponseBody TaskAvailabilityResponse lockTask(HttpServletRequest request) {
String path = request.getParameter(TASK_NAME_PARAM);
String taskId = (String) request.getSession().getAttribute(SESSION_ATTR_TASK_ID);
ITaskDataHandler<ITaskDataEntity, IProcessEntity> handler = taskHandlerMapping.get(path);
return handler.requestTaskAvailabilityAndLockTask(taskId,
request.getSession().getId(), request.getLocale());
}
@Override
@RequestMapping(value = "/requestAvailability", params = TASK_NAME_PARAM,
method = RequestMethod.GET, headers = "Accept=application/json")
public @ResponseBody TaskAvailabilityResponse requestTaskAvailability(HttpServletRequest request) {
String path = request.getParameter(TASK_NAME_PARAM);
String taskId = (String) request.getSession().getAttribute(SESSION_ATTR_TASK_ID);
ITaskDataHandler<ITaskDataEntity, IProcessEntity> handler = taskHandlerMapping.get(path);
return handler.requestTaskAvailability(taskId, request.getLocale());
}
}