TSK-1390: Add SPI to allow task processing before creation
This commit is contained in:
parent
32a1db98bd
commit
198572b6b1
|
|
@ -5,6 +5,7 @@ import org.apache.ibatis.session.SqlSession;
|
||||||
|
|
||||||
import pro.taskana.common.api.TaskanaEngine;
|
import pro.taskana.common.api.TaskanaEngine;
|
||||||
import pro.taskana.spi.history.internal.HistoryEventManager;
|
import pro.taskana.spi.history.internal.HistoryEventManager;
|
||||||
|
import pro.taskana.spi.taskpreprocessing.internal.CreateTaskPreprocessorManager;
|
||||||
import pro.taskana.task.internal.TaskRoutingManager;
|
import pro.taskana.task.internal.TaskRoutingManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -76,6 +77,13 @@ public interface InternalTaskanaEngine {
|
||||||
*/
|
*/
|
||||||
TaskRoutingManager getTaskRoutingManager();
|
TaskRoutingManager getTaskRoutingManager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve CreateTaskPreprocessorManager.
|
||||||
|
*
|
||||||
|
* @return the CreateTaskPreprocessorManager instance.
|
||||||
|
*/
|
||||||
|
CreateTaskPreprocessorManager getCreateTaskPreprocessorManager();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is supposed to skip further permission checks if we are already in a secured
|
* This method is supposed to skip further permission checks if we are already in a secured
|
||||||
* environment. With great power comes great responsibility.
|
* environment. With great power comes great responsibility.
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ import pro.taskana.monitor.api.MonitorService;
|
||||||
import pro.taskana.monitor.internal.MonitorMapper;
|
import pro.taskana.monitor.internal.MonitorMapper;
|
||||||
import pro.taskana.monitor.internal.MonitorServiceImpl;
|
import pro.taskana.monitor.internal.MonitorServiceImpl;
|
||||||
import pro.taskana.spi.history.internal.HistoryEventManager;
|
import pro.taskana.spi.history.internal.HistoryEventManager;
|
||||||
|
import pro.taskana.spi.taskpreprocessing.internal.CreateTaskPreprocessorManager;
|
||||||
import pro.taskana.task.api.TaskService;
|
import pro.taskana.task.api.TaskService;
|
||||||
import pro.taskana.task.internal.AttachmentMapper;
|
import pro.taskana.task.internal.AttachmentMapper;
|
||||||
import pro.taskana.task.internal.ObjectReferenceMapper;
|
import pro.taskana.task.internal.ObjectReferenceMapper;
|
||||||
|
|
@ -71,8 +72,8 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
private static final String DEFAULT = "default";
|
private static final String DEFAULT = "default";
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(TaskanaEngineImpl.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(TaskanaEngineImpl.class);
|
||||||
private static final SessionStack SESSION_STACK = new SessionStack();
|
private static final SessionStack SESSION_STACK = new SessionStack();
|
||||||
private HistoryEventManager historyEventManager;
|
|
||||||
private final TaskRoutingManager taskRoutingManager;
|
private final TaskRoutingManager taskRoutingManager;
|
||||||
|
private final CreateTaskPreprocessorManager createTaskPreprocessorManager;
|
||||||
private final InternalTaskanaEngineImpl internalTaskanaEngineImpl;
|
private final InternalTaskanaEngineImpl internalTaskanaEngineImpl;
|
||||||
private final WorkingDaysToDaysConverter workingDaysToDaysConverter;
|
private final WorkingDaysToDaysConverter workingDaysToDaysConverter;
|
||||||
protected TaskanaEngineConfiguration taskanaEngineConfiguration;
|
protected TaskanaEngineConfiguration taskanaEngineConfiguration;
|
||||||
|
|
@ -80,6 +81,7 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
protected SqlSessionManager sessionManager;
|
protected SqlSessionManager sessionManager;
|
||||||
protected ConnectionManagementMode mode = ConnectionManagementMode.PARTICIPATE;
|
protected ConnectionManagementMode mode = ConnectionManagementMode.PARTICIPATE;
|
||||||
protected Connection connection = null;
|
protected Connection connection = null;
|
||||||
|
private HistoryEventManager historyEventManager;
|
||||||
|
|
||||||
protected TaskanaEngineImpl(TaskanaEngineConfiguration taskanaEngineConfiguration) {
|
protected TaskanaEngineImpl(TaskanaEngineConfiguration taskanaEngineConfiguration) {
|
||||||
this.taskanaEngineConfiguration = taskanaEngineConfiguration;
|
this.taskanaEngineConfiguration = taskanaEngineConfiguration;
|
||||||
|
|
@ -87,6 +89,7 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
this.sessionManager = createSqlSessionManager();
|
this.sessionManager = createSqlSessionManager();
|
||||||
historyEventManager = HistoryEventManager.getInstance(this);
|
historyEventManager = HistoryEventManager.getInstance(this);
|
||||||
taskRoutingManager = TaskRoutingManager.getInstance(this);
|
taskRoutingManager = TaskRoutingManager.getInstance(this);
|
||||||
|
createTaskPreprocessorManager = CreateTaskPreprocessorManager.getInstance();
|
||||||
this.internalTaskanaEngineImpl = new InternalTaskanaEngineImpl();
|
this.internalTaskanaEngineImpl = new InternalTaskanaEngineImpl();
|
||||||
workingDaysToDaysConverter =
|
workingDaysToDaysConverter =
|
||||||
new WorkingDaysToDaysConverter(
|
new WorkingDaysToDaysConverter(
|
||||||
|
|
@ -419,6 +422,11 @@ public class TaskanaEngineImpl implements TaskanaEngine {
|
||||||
return taskRoutingManager;
|
return taskRoutingManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CreateTaskPreprocessorManager getCreateTaskPreprocessorManager() {
|
||||||
|
return createTaskPreprocessorManager;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T runAsAdmin(Supplier<T> supplier) {
|
public <T> T runAsAdmin(Supplier<T> supplier) {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
package pro.taskana.spi.taskpreprocessing.api;
|
||||||
|
|
||||||
|
import pro.taskana.task.api.models.Task;
|
||||||
|
|
||||||
|
public interface CreateTaskPreprocessor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes a task before its creation.
|
||||||
|
*
|
||||||
|
* @param taskToProcess {@link Task} The Task to preprocess.
|
||||||
|
*/
|
||||||
|
void processTaskBeforeCreation(Task taskToProcess);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
package pro.taskana.spi.taskpreprocessing.internal;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.ServiceLoader;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import pro.taskana.spi.taskpreprocessing.api.CreateTaskPreprocessor;
|
||||||
|
import pro.taskana.task.api.models.Task;
|
||||||
|
|
||||||
|
public class CreateTaskPreprocessorManager {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(CreateTaskPreprocessorManager.class);
|
||||||
|
private static CreateTaskPreprocessorManager singleton;
|
||||||
|
private boolean enabled = false;
|
||||||
|
private ServiceLoader<CreateTaskPreprocessor> serviceLoader;
|
||||||
|
|
||||||
|
private CreateTaskPreprocessorManager() {
|
||||||
|
serviceLoader = ServiceLoader.load(CreateTaskPreprocessor.class);
|
||||||
|
for (CreateTaskPreprocessor preprocessor : serviceLoader) {
|
||||||
|
LOGGER.info(
|
||||||
|
"Registered CreateTaskPreprocessor provider: {}", preprocessor.getClass().getName());
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
if (!enabled) {
|
||||||
|
LOGGER.info("No CreateTaskPreprocessor found. Running without CreateTaskPreprocessor.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static synchronized CreateTaskPreprocessorManager getInstance() {
|
||||||
|
if (singleton == null) {
|
||||||
|
singleton = new CreateTaskPreprocessorManager();
|
||||||
|
}
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isCreateTaskPreprocessorEnabled() {
|
||||||
|
return Objects.nonNull(singleton) && singleton.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task processTaskBeforeCreation(Task taskToProcess) {
|
||||||
|
LOGGER.debug("Sending task to CreateTaskPreprocessor providers: {}", taskToProcess);
|
||||||
|
serviceLoader.forEach(
|
||||||
|
createTaskPreprocessorProvider ->
|
||||||
|
createTaskPreprocessorProvider.processTaskBeforeCreation(taskToProcess));
|
||||||
|
return taskToProcess;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -42,6 +42,7 @@ import pro.taskana.spi.history.api.events.task.TaskCreatedEvent;
|
||||||
import pro.taskana.spi.history.api.events.task.TaskTerminatedEvent;
|
import pro.taskana.spi.history.api.events.task.TaskTerminatedEvent;
|
||||||
import pro.taskana.spi.history.api.events.task.TaskUpdatedEvent;
|
import pro.taskana.spi.history.api.events.task.TaskUpdatedEvent;
|
||||||
import pro.taskana.spi.history.internal.HistoryEventManager;
|
import pro.taskana.spi.history.internal.HistoryEventManager;
|
||||||
|
import pro.taskana.spi.taskpreprocessing.internal.CreateTaskPreprocessorManager;
|
||||||
import pro.taskana.task.api.CallbackState;
|
import pro.taskana.task.api.CallbackState;
|
||||||
import pro.taskana.task.api.TaskCustomField;
|
import pro.taskana.task.api.TaskCustomField;
|
||||||
import pro.taskana.task.api.TaskQuery;
|
import pro.taskana.task.api.TaskQuery;
|
||||||
|
|
@ -108,6 +109,7 @@ public class TaskServiceImpl implements TaskService {
|
||||||
private final AttachmentHandler attachmentHandler;
|
private final AttachmentHandler attachmentHandler;
|
||||||
private final AttachmentMapper attachmentMapper;
|
private final AttachmentMapper attachmentMapper;
|
||||||
private final HistoryEventManager historyEventManager;
|
private final HistoryEventManager historyEventManager;
|
||||||
|
private final CreateTaskPreprocessorManager createTaskPreprocessorManager;
|
||||||
|
|
||||||
public TaskServiceImpl(
|
public TaskServiceImpl(
|
||||||
InternalTaskanaEngine taskanaEngine,
|
InternalTaskanaEngine taskanaEngine,
|
||||||
|
|
@ -120,6 +122,7 @@ public class TaskServiceImpl implements TaskService {
|
||||||
this.attachmentMapper = attachmentMapper;
|
this.attachmentMapper = attachmentMapper;
|
||||||
this.classificationService = taskanaEngine.getEngine().getClassificationService();
|
this.classificationService = taskanaEngine.getEngine().getClassificationService();
|
||||||
this.historyEventManager = taskanaEngine.getHistoryEventManager();
|
this.historyEventManager = taskanaEngine.getHistoryEventManager();
|
||||||
|
this.createTaskPreprocessorManager = taskanaEngine.getCreateTaskPreprocessorManager();
|
||||||
this.taskTransferrer = new TaskTransferrer(taskanaEngine, taskMapper, this);
|
this.taskTransferrer = new TaskTransferrer(taskanaEngine, taskMapper, this);
|
||||||
this.taskCommentService = new TaskCommentServiceImpl(taskanaEngine, taskCommentMapper, this);
|
this.taskCommentService = new TaskCommentServiceImpl(taskanaEngine, taskCommentMapper, this);
|
||||||
this.serviceLevelHandler = new ServiceLevelHandler(taskanaEngine, taskMapper, attachmentMapper);
|
this.serviceLevelHandler = new ServiceLevelHandler(taskanaEngine, taskMapper, attachmentMapper);
|
||||||
|
|
@ -209,6 +212,10 @@ public class TaskServiceImpl implements TaskService {
|
||||||
workbasketService.checkAuthorization(
|
workbasketService.checkAuthorization(
|
||||||
task.getWorkbasketSummary().getId(), WorkbasketPermission.APPEND);
|
task.getWorkbasketSummary().getId(), WorkbasketPermission.APPEND);
|
||||||
|
|
||||||
|
if (CreateTaskPreprocessorManager.isCreateTaskPreprocessorEnabled()) {
|
||||||
|
task = (TaskImpl) createTaskPreprocessorManager.processTaskBeforeCreation(task);
|
||||||
|
}
|
||||||
|
|
||||||
// we do use the key and not the ID to make sure that we use the classification from the right
|
// we do use the key and not the ID to make sure that we use the classification from the right
|
||||||
// domain.
|
// domain.
|
||||||
// otherwise we would have to check the classification and its domain for validity.
|
// otherwise we would have to check the classification and its domain for validity.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
package acceptance.taskpreprocessing;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
import acceptance.AbstractAccTest;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
|
||||||
|
import pro.taskana.common.internal.security.JaasExtension;
|
||||||
|
import pro.taskana.common.internal.security.WithAccessId;
|
||||||
|
import pro.taskana.task.api.TaskCustomField;
|
||||||
|
import pro.taskana.task.api.TaskService;
|
||||||
|
import pro.taskana.task.api.models.Task;
|
||||||
|
import pro.taskana.task.internal.models.TaskImpl;
|
||||||
|
|
||||||
|
/** Acceptance test for "task preprocessing" scenario. */
|
||||||
|
@ExtendWith(JaasExtension.class)
|
||||||
|
class CreateTaskPreprocessingAccTest extends AbstractAccTest {
|
||||||
|
|
||||||
|
private final TaskService taskService = taskanaEngine.getTaskService();
|
||||||
|
|
||||||
|
@WithAccessId(user = "admin")
|
||||||
|
@Test
|
||||||
|
void should_processTaskBeforeCreation_When_CreateTaskPreprocessorEnabled() throws Exception {
|
||||||
|
|
||||||
|
TaskImpl newTaskToCreate = (TaskImpl) taskService.newTask();
|
||||||
|
|
||||||
|
newTaskToCreate.setClassificationKey("L10303");
|
||||||
|
|
||||||
|
newTaskToCreate.setPrimaryObjRef(
|
||||||
|
createObjectReference("COMPANY_A", "SYSTEM_A", "INSTANCE_A", "VNR", "1234567"));
|
||||||
|
|
||||||
|
newTaskToCreate.setWorkbasketKey("GPK_KSC");
|
||||||
|
|
||||||
|
newTaskToCreate.setDomain("DOMAIN_A");
|
||||||
|
|
||||||
|
Task createdTask = taskService.createTask(newTaskToCreate);
|
||||||
|
|
||||||
|
assertThat(createdTask.getCustomAttribute(TaskCustomField.CUSTOM_1))
|
||||||
|
.isEqualTo("preprocessedCustomField");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package acceptance.taskpreprocessing;
|
||||||
|
|
||||||
|
import pro.taskana.spi.taskpreprocessing.api.CreateTaskPreprocessor;
|
||||||
|
import pro.taskana.task.api.TaskCustomField;
|
||||||
|
import pro.taskana.task.api.models.Task;
|
||||||
|
|
||||||
|
public class TestCreateTaskPreprocessorProvider implements CreateTaskPreprocessor {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void processTaskBeforeCreation(Task taskToProcess) {
|
||||||
|
taskToProcess
|
||||||
|
.setCustomAttribute(TaskCustomField.CUSTOM_1, "preprocessedCustomField");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -45,7 +45,10 @@ class ArchitectureTest {
|
||||||
"pro.taskana.task.internal",
|
"pro.taskana.task.internal",
|
||||||
"pro.taskana.workbasket.api",
|
"pro.taskana.workbasket.api",
|
||||||
"pro.taskana.workbasket.internal",
|
"pro.taskana.workbasket.internal",
|
||||||
"pro.taskana.spi.routing.api");
|
"pro.taskana.spi.routing.api",
|
||||||
|
"pro.taskana.spi.taskpreprocessing.api",
|
||||||
|
"pro.taskana.spi.taskpreprocessing.internal"
|
||||||
|
);
|
||||||
private static JavaClasses importedClasses;
|
private static JavaClasses importedClasses;
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
acceptance.taskpreprocessing.TestCreateTaskPreprocessorProvider
|
||||||
Loading…
Reference in New Issue