package com.wordpress.salaboy.emergencyservice.web.task; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.ui.Model; import org.yaml.snakeyaml.Yaml; import com.wordpress.salaboy.emergencyservice.web.task.exception.FormValidationException; import com.wordpress.salaboy.smarttasks.formbuilder.api.ConnectionData; import com.wordpress.salaboy.smarttasks.formbuilder.api.SmartTaskBuilder; import com.wordpress.salaboy.smarttasks.formbuilder.api.TaskOperationsDefinition; import com.wordpress.salaboy.smarttasks.formbuilder.api.exception.InvalidTaskException; import com.wordpress.salaboy.smarttasks.formbuilder.api.output.TaskForm; import com.wordpress.salaboy.smarttasks.metamodel.MetaTaskDecoratorBase; import com.wordpress.salaboy.smarttasks.metamodel.MetaTaskDecoratorService; /** * Abstract controller which has all the common mechanism for the different task * form controllers. Extending classes will reimplement the methods, also adding * mappings for urls. * * @author calcacuervo * */ public abstract class AbstractTaskFormController { public AbstractTaskFormController() { MetaTaskDecoratorService.getInstance().registerDecorator("base", new MetaTaskDecoratorBase()); } /** * Task inputs. */ protected Map<String, Object> taskInfo; /** * Task outputs. */ protected Map<String, Object> taskOutput; /** * Concrete classes will implement this method with the task type they are * intended to render. This task type will be used to select the form * configuration with smart tasks. * * @return */ protected abstract String getTaskType(); /** * {@link Yaml} instance is used the deserialize the data. */ protected Yaml yaml = new Yaml(); /** * Inyected builder. */ @Autowired protected SmartTaskBuilder helper; /** * This is the main method to show task form. It will put in the model the * task input and outputs extracted with smart tasks, and also the * operations to show buttons. This method should be overriden by concrete * controllers, which will also make additional things and configure the url * mapping. * * @param id * @param entity * @param name * @param profile * @param model * @return */ public String taskInfo(String id, String entity, String name, String profile, Model model) { try { this.getTaskForm(entity, id, profile); TaskOperationsDefinition operationsDef = helper .getTaskOperations(id); model.addAttribute("operations", operationsDef); model.addAttribute("taskInput", taskInfo); model.addAttribute("taskOutput", taskOutput); model.addAttribute("user", entity); model.addAttribute("profile", profile); model.addAttribute("name", name); model.addAttribute("id", taskInfo.get("Id")); } catch (InvalidTaskException e) { Logger.getLogger(AbstractTaskFormController.class.getName()).log( Level.SEVERE, "Task not found", e); return "redirect:/new/"; } this.addCustomFormLogic(model); return this.getViewPrefix() + "task"; } /** * Gets the task form {@link SmartTasksTaskFormBuilder}. * * @param entity * @param id * @param profile * @throws InvalidTaskException * if a task is not found */ protected void getTaskForm(String entity, String id, String profile) throws InvalidTaskException { ConnectionData connectionData = new ConnectionData(entity); helper.connect(connectionData); String taskType = this.getTaskType(); String stringTaskform = helper.getTaskForm(id, taskType, profile); TaskForm deserializedForm = (TaskForm) yaml.load(stringTaskform); taskInfo = deserializedForm.getInputs(); taskOutput = deserializedForm.getOutputs(); } /** * Executes a given action over a given task. It assumes it receives the * data (only for complete action) in the form data1=info1,data2=info2. If * the action is "complete", it transform this data string with a map, and * calls an abstract method which will transform this data with task * specific data. * * @param taskId * @param action * @param entity * @param name * @param data * @param profile * @param model * @return */ public String executeTask(String taskId, String action, String entity, String name, String data, String profile, Model model) { try { if ("complete".equalsIgnoreCase(action)) { Map<String, String> map = new HashMap<String, String>(); String[] params = data.split(","); for (int i = 0; i < params.length; i++) { String[] param = params[i].split("="); if (param.length == 2 && param[0] != null && param[1] != null) { map.put(param[0], param[1]); } } try { this.validate(map); } catch (FormValidationException ex) { ex.printStackTrace(); model.addAttribute("validationError", ex.getMessage()); return this.taskInfo(taskId, entity, name, profile, model); } Map<String, Object> taskData = this.generateOutputForForm("", map); helper.executeTaskAction(action, taskData, taskId); } else { helper.executeTaskAction(action, null, taskId); } } catch (InvalidTaskException e) { return "redirect:new"; } return this.taskInfo(taskId, entity, name, profile, model); } /** * Transform the form data in data valuable for the specific task. * * @param string * @param map * @return */ protected abstract Map<String, Object> generateOutputForForm(String string, Map<String, String> map); /** * The view prefix is used it find the .ftl to show the task form. It will * always try with <prefix>tasl.ftl * * @return */ protected abstract String getViewPrefix(); /** * Concrete classes can fill the model with some specific data for it. * * @param model */ protected abstract void addCustomFormLogic(Model model); /** * Validates a given form. * * @param formSubmittedData * @throws FormValidationException */ protected void validate(Map<String, String> formSubmittedData) throws FormValidationException { // DEFAULT DOES NOTHING } }