From 4bc7b6bad1903529558c55b02e99fce4a00e371f Mon Sep 17 00:00:00 2001 From: BerndBreier <33351391+BerndBreier@users.noreply.github.com> Date: Mon, 19 Mar 2018 14:44:02 +0100 Subject: [PATCH] TSK-314 Recalculate due timestamp and prio when a classification is updated --- .../java/pro/taskana/ClassificationQuery.java | 9 + .../src/main/java/pro/taskana/TaskQuery.java | 9 + .../taskana/impl/BulkOperationResults.java | 13 ++ .../taskana/impl/ClassificationQueryImpl.java | 13 ++ .../impl/ClassificationServiceImpl.java | 33 ++- .../src/main/java/pro/taskana/impl/Job.java | 110 +++++++++ .../main/java/pro/taskana/impl/JobRunner.java | 79 +++++++ .../pro/taskana/impl/SingleJobExecutor.java | 11 + .../java/pro/taskana/impl/TaskQueryImpl.java | 13 ++ .../pro/taskana/impl/TaskServiceImpl.java | 212 +++++++++++------- ...kUpdateOnClassificationChangeExecutor.java | 81 +++++++ .../pro/taskana/impl/TaskanaEngineImpl.java | 2 + .../taskana/mappings/AttachmentMapper.java | 26 +++ .../java/pro/taskana/mappings/JobMapper.java | 47 ++++ .../pro/taskana/mappings/QueryMapper.java | 10 +- .../java/pro/taskana/mappings/TaskMapper.java | 64 ++++++ .../src/main/resources/sql/taskana-schema.sql | 18 ++ .../DeleteClassificationAccTest.java | 19 ++ .../QueryClassificationAccTest.java | 10 +- ...ryClassificationWithPaginationAccTest.java | 6 +- .../UpdateClassificationAccTest.java | 81 ++++++- .../security/ClassificationQueryAccTest.java | 6 +- .../acceptance/task/QueryTasksAccTest.java | 6 +- .../taskana/database/TestDataGenerator.java | 2 + .../pro/taskana/impl/TaskServiceImplTest.java | 13 +- .../taskana/impl/TestClassificationQuery.java | 6 + .../src/test/resources/sql/attachment.sql | 16 ++ .../src/test/resources/sql/classification.sql | 2 + .../src/test/resources/sql/clear-db.sql | 1 + .../src/test/resources/sql/drop-tables.sql | 2 + .../taskana/rest/ExampleRestApplication.java | 4 +- .../java/pro/taskana/rest/JobScheduler.java | 37 +++ 32 files changed, 857 insertions(+), 104 deletions(-) create mode 100644 lib/taskana-core/src/main/java/pro/taskana/impl/Job.java create mode 100644 lib/taskana-core/src/main/java/pro/taskana/impl/JobRunner.java create mode 100644 lib/taskana-core/src/main/java/pro/taskana/impl/SingleJobExecutor.java create mode 100644 lib/taskana-core/src/main/java/pro/taskana/impl/TaskUpdateOnClassificationChangeExecutor.java create mode 100644 lib/taskana-core/src/main/java/pro/taskana/mappings/JobMapper.java create mode 100644 lib/taskana-core/src/test/resources/sql/attachment.sql create mode 100644 rest/taskana-rest-spring-example/src/main/java/pro/taskana/rest/JobScheduler.java diff --git a/lib/taskana-core/src/main/java/pro/taskana/ClassificationQuery.java b/lib/taskana-core/src/main/java/pro/taskana/ClassificationQuery.java index 8b8afc28b..8f51edbe9 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/ClassificationQuery.java +++ b/lib/taskana-core/src/main/java/pro/taskana/ClassificationQuery.java @@ -14,6 +14,15 @@ public interface ClassificationQuery extends BaseQuery { */ ClassificationQuery keyIn(String... key); + /** + * Add your Id to your query. + * + * @param id + * as String + * @return the query + */ + ClassificationQuery idIn(String... id); + /** * Add your parentIds to your query. * diff --git a/lib/taskana-core/src/main/java/pro/taskana/TaskQuery.java b/lib/taskana-core/src/main/java/pro/taskana/TaskQuery.java index 877cdfce4..5d8d873b0 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/TaskQuery.java +++ b/lib/taskana-core/src/main/java/pro/taskana/TaskQuery.java @@ -107,6 +107,15 @@ public interface TaskQuery extends BaseQuery { */ TaskQuery classificationKeyLike(String... classificationKeys); + /** + * Add your classificationId to your query. + * + * @param classificationIds + * the classification Ids + * @return the query + */ + TaskQuery classificationIdIn(String... classificationIds); + /** * Add your classificationCategory to your query. * diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/BulkOperationResults.java b/lib/taskana-core/src/main/java/pro/taskana/impl/BulkOperationResults.java index 47d8143d8..9baa35059 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/BulkOperationResults.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/BulkOperationResults.java @@ -97,4 +97,17 @@ public class BulkOperationResults { public void clearErrors() { this.errorMap.clear(); } + + /** + * Add all errors from another BulkOperationResult to this. + * + * @param log + * the other log + */ + public void addAllErrors(BulkOperationResults log) { + List failedIds = log.getFailedIds(); + for (K id : failedIds) { + addError(id, log.getErrorForId(id)); + } + } } diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationQueryImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationQueryImpl.java index 911bb8c87..5c1b9d7f8 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationQueryImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationQueryImpl.java @@ -30,6 +30,7 @@ public class ClassificationQueryImpl implements ClassificationQuery { private TaskanaEngineImpl taskanaEngine; private String columnName; private String[] key; + private String[] idIn; private String[] parentId; private String[] category; private String[] type; @@ -74,6 +75,12 @@ public class ClassificationQueryImpl implements ClassificationQuery { return this; } + @Override + public ClassificationQuery idIn(String... id) { + this.idIn = id; + return this; + } + @Override public ClassificationQuery parentIdIn(String... parentId) { this.parentId = parentId; @@ -459,6 +466,10 @@ public class ClassificationQueryImpl implements ClassificationQuery { return key; } + public String[] getIdIn() { + return idIn; + } + public String[] getparentId() { return parentId; } @@ -594,6 +605,8 @@ public class ClassificationQueryImpl implements ClassificationQuery { builder.append(columnName); builder.append(", key="); builder.append(Arrays.toString(key)); + builder.append(", idIn="); + builder.append(Arrays.toString(idIn)); builder.append(", parentId="); builder.append(Arrays.toString(parentId)); builder.append(", category="); diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java index 3cb12b364..89659dbc0 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationServiceImpl.java @@ -3,7 +3,9 @@ package pro.taskana.impl; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,7 +24,9 @@ import pro.taskana.exceptions.NotAuthorizedException; import pro.taskana.exceptions.NotAuthorizedToQueryWorkbasketException; import pro.taskana.exceptions.SystemException; import pro.taskana.impl.util.IdGenerator; +import pro.taskana.mappings.AttachmentMapper; import pro.taskana.mappings.ClassificationMapper; +import pro.taskana.mappings.JobMapper; import pro.taskana.mappings.TaskMapper; /** @@ -138,8 +142,8 @@ public class ClassificationServiceImpl implements ClassificationService { if (oldClassification.getCategory() != classificationImpl.getCategory()) { List taskSumamries = taskanaEngine.getTaskService() .createTaskQuery() - .classificationKeyIn(oldClassification.getKey()) - .classificationCategoryIn(oldClassification.getCategory()) + .classificationIdIn(oldClassification.getId()) + // .classificationCategoryIn(oldClassification.getCategory()) .list(); if (!taskSumamries.isEmpty()) { List taskIds = new ArrayList<>(); @@ -155,6 +159,23 @@ public class ClassificationServiceImpl implements ClassificationService { } } classificationMapper.update(classificationImpl); + boolean priorityChanged = oldClassification.getPriority() != classification.getPriority(); + boolean serviceLevelChanged = oldClassification.getServiceLevel() != classification.getServiceLevel(); + + if (priorityChanged || serviceLevelChanged) { + Map args = new HashMap<>(); + args.put(TaskUpdateOnClassificationChangeExecutor.CLASSIFICATION_ID, classificationImpl.getId()); + args.put(TaskUpdateOnClassificationChangeExecutor.PRIORITY_CHANGED, String.valueOf(priorityChanged)); + args.put(TaskUpdateOnClassificationChangeExecutor.SERVICE_LEVEL_CHANGED, + String.valueOf(serviceLevelChanged)); + Job job = new Job(); + job.setCreated(Instant.now()); + job.setState(Job.State.READY); + job.setExecutor(TaskUpdateOnClassificationChangeExecutor.class.getName()); + job.setArguments(args); + taskanaEngine.getSqlSession().getMapper(JobMapper.class).insertJob(job); + } + LOGGER.debug("Method updateClassification() updated the classification {}.", classificationImpl); return classification; @@ -304,6 +325,14 @@ public class ClassificationServiceImpl implements ClassificationService { "The classification " + classificationKey + "wasn't found in the domain " + domain); } + List attachments = taskanaEngine.getSqlSession() + .getMapper(AttachmentMapper.class) + .findAttachmentSummariesByClassificationId(classification.getId()); + if (!attachments.isEmpty()) { + throw new ClassificationInUseException("Classification " + classification.getId() + + " is used by Attachment " + attachments.get(0).getId()); + } + if (domain.equals("")) { // master mode - delete all associated classifications in every domain. List domains = this.classificationMapper.getDomainsForClassification(classificationKey); diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/Job.java b/lib/taskana-core/src/main/java/pro/taskana/impl/Job.java new file mode 100644 index 000000000..d5d64c9ac --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/Job.java @@ -0,0 +1,110 @@ +package pro.taskana.impl; + +import java.time.Instant; +import java.util.Map; + +/** + * This class holds all data that go into the Job table. + * + * @author bbr + */ +public class Job { + + private Integer jobId; + private Instant created; + private Instant started; + private Instant completed; + private State state; + private String executor; + Map arguments; + + public Integer getJobId() { + return jobId; + } + + public void setJobId(Integer jobId) { + this.jobId = jobId; + } + + public Instant getCreated() { + return created; + } + + public void setCreated(Instant created) { + this.created = created; + } + + public Instant getStarted() { + return started; + } + + public void setStarted(Instant started) { + this.started = started; + } + + public Instant getCompleted() { + return completed; + } + + public void setCompleted(Instant completed) { + this.completed = completed; + } + + public State getState() { + return state; + } + + public void setState(State state) { + this.state = state; + } + + public String getExecutor() { + return executor; + } + + public void setExecutor(String executor) { + this.executor = executor; + } + + public Map getArguments() { + return arguments; + } + + public void setArguments(Map arguments) { + this.arguments = arguments; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("Job [jobId="); + builder.append(jobId); + builder.append(", created="); + builder.append(created); + builder.append(", started="); + builder.append(started); + builder.append(", completed="); + builder.append(completed); + builder.append(", state="); + builder.append(state); + builder.append(", executor="); + builder.append(executor); + builder.append(", arguments="); + builder.append(arguments); + builder.append("]"); + return builder.toString(); + } + + /** + * This enum tracks the state of a job. + * + * @author bbr + */ + public enum State { + READY, + RUNNING, + FAILED, + COMPLETED + } + +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/JobRunner.java b/lib/taskana-core/src/main/java/pro/taskana/impl/JobRunner.java new file mode 100644 index 000000000..62f66a0f1 --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/JobRunner.java @@ -0,0 +1,79 @@ +package pro.taskana.impl; + +import java.time.Instant; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import pro.taskana.TaskanaEngine; +import pro.taskana.mappings.JobMapper; + +/** + * This is the runner for all jobs scheduled in the Job table. + * + * @author bbr + */ +public class JobRunner { + + private static final Logger LOGGER = LoggerFactory.getLogger(TaskServiceImpl.class); + private TaskanaEngineImpl taskanaEngine; + private JobMapper jobMapper; + + public JobRunner(TaskanaEngine taskanaEngine) { + this.taskanaEngine = (TaskanaEngineImpl) taskanaEngine; + jobMapper = this.taskanaEngine.getSqlSession().getMapper(JobMapper.class); + } + + public BulkOperationResults runJobs() { + LOGGER.info("entry to runJobs()"); + BulkOperationResults bulkLog = new BulkOperationResults<>(); + try { + taskanaEngine.openConnection(); + List jobs = jobMapper.findJobsToRun(); + for (Job job : jobs) { + BulkOperationResults log = runSingleJob(job); + bulkLog.addAllErrors(log); + } + return bulkLog; + } finally { + taskanaEngine.returnConnection(); + LOGGER.info("exit from runJobs(). Returning result {} ", bulkLog); + } + + } + + private BulkOperationResults runSingleJob(Job job) { + LOGGER.debug("entry to runSingleJob(job = {})", job); + BulkOperationResults bulkLog = new BulkOperationResults<>(); + if (Job.State.READY.equals(job.getState())) { + job.setStarted(Instant.now()); + } + job.setState(Job.State.RUNNING); + jobMapper.update(job); + SingleJobExecutor executor; + try { + executor = (SingleJobExecutor) Class.forName(job.getExecutor()).newInstance(); + bulkLog = executor.runSingleJob(job, taskanaEngine); + + } catch (Exception e) { + bulkLog.addError("JobId:" + job.getJobId(), e); + job.setCompleted(Instant.now()); + job.setState(Job.State.FAILED); + jobMapper.update(job); + return bulkLog; + } + job.setCompleted(Instant.now()); + job.setState(Job.State.COMPLETED); + jobMapper.update(job); + + LOGGER.debug("exit from runSingleJob"); + if (bulkLog.containsErrors()) { + LOGGER.error("Errors occurred when running job {}.", job); + for (String id : bulkLog.getFailedIds()) { + LOGGER.error(id + bulkLog.getErrorForId(id)); + } + } + return bulkLog; + } +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/SingleJobExecutor.java b/lib/taskana-core/src/main/java/pro/taskana/impl/SingleJobExecutor.java new file mode 100644 index 000000000..7bb404c23 --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/SingleJobExecutor.java @@ -0,0 +1,11 @@ +package pro.taskana.impl; + +/** + * This interface must be implemented by classes that execut a single job. + * + * @author bbr + */ +public interface SingleJobExecutor { + + BulkOperationResults runSingleJob(Job job, TaskanaEngineImpl taskanaEngine); +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskQueryImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskQueryImpl.java index 851a959ba..7ada8e3f2 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskQueryImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskQueryImpl.java @@ -50,6 +50,7 @@ public class TaskQueryImpl implements TaskQuery { private KeyDomain[] workbasketKeyDomainIn; private String[] workbasketIdIn; private TaskState[] stateIn; + private String[] classificationIdIn; private String[] classificationKeyIn; private String[] classificationKeyLike; private String[] classificationCategoryIn; @@ -256,6 +257,12 @@ public class TaskQueryImpl implements TaskQuery { return this; } + @Override + public TaskQuery classificationIdIn(String... classificationId) { + this.classificationIdIn = classificationId; + return this; + } + @Override public TaskQuery classificationCategoryIn(String... classificationCategories) { this.classificationCategoryIn = classificationCategories; @@ -1133,6 +1140,10 @@ public class TaskQueryImpl implements TaskQuery { return classificationKeyLike; } + public String[] getClassificationIdIn() { + return classificationIdIn; + } + public KeyDomain[] getWorkbasketKeyDomainIn() { return workbasketKeyDomainIn; } @@ -1197,6 +1208,8 @@ public class TaskQueryImpl implements TaskQuery { builder.append(Arrays.toString(classificationKeyIn)); builder.append(", classificationKeyLike="); builder.append(Arrays.toString(classificationKeyLike)); + builder.append(", classificationIdIn="); + builder.append(Arrays.toString(classificationIdIn)); builder.append(", classificationCategoryIn="); builder.append(Arrays.toString(classificationCategoryIn)); builder.append(", classificationCategoryLike="); diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java index 47bc0ef93..e32843865 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskServiceImpl.java @@ -380,8 +380,16 @@ public class TaskServiceImpl implements TaskService { classifications); resultTask.setAttachments(attachments); - ClassificationSummary classification = getMatchingClassificationFromList(classifications, - resultTask.getClassificationSummary().getKey(), resultTask.getDomain()); + String classificationId = resultTask.getClassificationSummary().getId(); + ClassificationSummary classification = classifications.stream() + .filter(c -> c.getId().equals(classificationId)) + .findFirst() + .orElse(null); + if (classification == null) { + LOGGER.error("Could not find a Classification for task {} ", resultTask); + throw new SystemException( + "Could not find a Classification for task " + resultTask.getId()); + } resultTask.setClassificationSummary(classification); return resultTask; @@ -614,7 +622,6 @@ public class TaskServiceImpl implements TaskService { oldTaskImpl = (TaskImpl) getTask(newTaskImpl.getId()); PrioDurationHolder prioDurationFromAttachments = handleAttachmentsOnTaskUpdate(oldTaskImpl, newTaskImpl); standardUpdateActions(oldTaskImpl, newTaskImpl, prioDurationFromAttachments); - newTaskImpl.setModified(Instant.now()); taskMapper.update(newTaskImpl); LOGGER.debug("Method updateTask() updated task '{}' for user '{}'.", task.getId(), userId); @@ -725,34 +732,21 @@ public class TaskServiceImpl implements TaskService { } // assign query results to appropriate tasks. for (TaskSummaryImpl task : tasks) { - ClassificationSummary aClassification = getMatchingClassificationFromList(classifications, - task.getClassificationSummary().getKey(), - task.getDomain()); - // set the classification on the task object - task.setClassificationSummary(aClassification); - } - } - - private ClassificationSummary getMatchingClassificationFromList(List classifications, - String taskClassKey, String taskDomain) { - ClassificationSummary aClassification = classifications.stream() - .filter(x -> taskClassKey != null && taskClassKey.equals(x.getKey()) && taskDomain != null - && taskDomain.equals(x.getDomain())) - .findFirst() - .orElse(null); - if (aClassification == null) { - // search in "" domain - aClassification = classifications.stream() - .filter(x -> taskClassKey != null && taskClassKey.equals(x.getKey()) && "".equals(x.getDomain())) + String classificationId = task.getClassificationSummary().getId(); + ClassificationSummary aClassification = classifications.stream() + .filter(c -> c.getId().equals(classificationId)) .findFirst() .orElse(null); if (aClassification == null) { - LOGGER.error("Could not find a Classification for task "); + LOGGER.error("Didnt find a Classification for task "); throw new SystemException( - "Could not find a Classification for task (key=" + taskClassKey + ",domain=" + taskDomain + ")"); + "Did not find a Classification for task (Id=" + task.getTaskId() + ",classification=" + + task.getClassificationSummary().getId() + + ")"); } + // set the classification on the task object + task.setClassificationSummary(aClassification); } - return aClassification; } private List findClassificationsForTasksAndAttachments( @@ -763,53 +757,40 @@ public class TaskServiceImpl implements TaskService { return new ArrayList<>(); } - Set classificationDomainSet = taskSummaries.stream().map(TaskSummaryImpl::getDomain).collect( + Set classificationIdSet = taskSummaries.stream().map(t -> t.getClassificationSummary().getId()).collect( Collectors.toSet()); - // add "" domain in case the classification exists only there (fallback for tasks) - classificationDomainSet.add(""); - - Set classificationKeySet = taskSummaries.stream() - .map(t -> t.getClassificationSummary().getKey()) - .collect(Collectors.toSet()); if (attachmentSummaries != null && !attachmentSummaries.isEmpty()) { - Set classificationKeysFromAttachments = attachmentSummaries.stream() - .map(t -> t.getClassificationSummary().getKey()) - .collect(Collectors.toSet()); - classificationKeySet.addAll(classificationKeysFromAttachments); + for (AttachmentSummaryImpl att : attachmentSummaries) { + classificationIdSet.add(att.getClassificationSummary().getId()); + } } - - return queryClassificationsForTasksAndAttachments(classificationDomainSet, classificationKeySet); + return queryClassificationsForTasksAndAttachments(classificationIdSet); } private List findClassificationForTaskImplAndAttachments(TaskImpl task, List attachmentImpls) throws NotAuthorizedException { - Set classificationDomainSet = new HashSet<>(Arrays.asList(task.getDomain(), "")); - Set classificationKeySet = new HashSet<>(Arrays.asList(task.getClassificationKey())); - + Set classificationIdSet = new HashSet<>(Arrays.asList(task.getClassificationSummary().getId())); if (attachmentImpls != null && !attachmentImpls.isEmpty()) { - Set classificationKeysFromAttachments = attachmentImpls.stream() - .map(t -> t.getClassificationSummary().getKey()) - .collect(Collectors.toSet()); - classificationKeySet.addAll(classificationKeysFromAttachments); + for (AttachmentImpl att : attachmentImpls) { + classificationIdSet.add(att.getClassificationSummary().getId()); + } } - return queryClassificationsForTasksAndAttachments(classificationDomainSet, classificationKeySet); + return queryClassificationsForTasksAndAttachments(classificationIdSet); } - private List queryClassificationsForTasksAndAttachments(Set classificationDomainSet, - Set classificationKeySet) throws NotAuthorizedException { + private List queryClassificationsForTasksAndAttachments(Set classificationIdSet) + throws NotAuthorizedException { - String[] classificationDomainArray = classificationDomainSet.toArray(new String[0]); - String[] classificationKeyArray = classificationKeySet.toArray(new String[0]); + String[] classificationIdArray = classificationIdSet.toArray(new String[0]); LOGGER.debug("getClassificationsForTasksAndAttachments() about to query classifications and exit"); // perform classification query return this.classificationService.createClassificationQuery() - .domainIn(classificationDomainArray) - .keyIn(classificationKeyArray) + .idIn(classificationIdArray) .list(); } @@ -820,25 +801,26 @@ public class TaskServiceImpl implements TaskService { return; } // calculate parameters for workbasket query: workbasket keys - Set workbasketKeySet = taskSummaries.stream().map(t -> t.getWorkbasketSummary().getKey()).collect( + Set workbasketIdSet = taskSummaries.stream().map(t -> t.getWorkbasketSummary().getId()).collect( Collectors.toSet()); - String[] workbasketKeyArray = workbasketKeySet.toArray(new String[0]); + String[] workbasketIdArray = workbasketIdSet.toArray(new String[0]); // perform workbasket query LOGGER.debug("addWorkbasketSummariesToTaskSummaries() about to query workbaskets"); WorkbasketQueryImpl query = (WorkbasketQueryImpl) workbasketService.createWorkbasketQuery(); query.setUsedToAugmentTasks(true); + List workbaskets = query - .keyIn(workbasketKeyArray) + .idIn(workbasketIdArray) .list(); // assign query results to appropriate tasks. Iterator taskIterator = taskSummaries.iterator(); while (taskIterator.hasNext()) { TaskSummaryImpl task = taskIterator.next(); - String workbasketKey = task.getWorkbasketSummaryImpl().getKey(); + String workbasketId = task.getWorkbasketSummaryImpl().getId(); // find the appropriate workbasket from the query result WorkbasketSummary aWorkbasket = workbaskets.stream() - .filter(x -> workbasketKey != null && workbasketKey.equals(x.getKey())) + .filter(x -> workbasketId != null && workbasketId.equals(x.getId())) .findFirst() .orElse(null); if (aWorkbasket == null) { @@ -883,20 +865,9 @@ public class TaskServiceImpl implements TaskService { } // iterate over all attachment summaries an add the appropriate classification summary to each for (AttachmentSummaryImpl att : attachmentSummaries) { - // find the associated task to use the correct domain - TaskSummaryImpl aTaskSummary = taskSummaries.stream() - .filter(x -> x.getTaskId().equals(att.getTaskId())) - .findFirst() - .orElse(null); - if (aTaskSummary == null) { - LOGGER.error("Could not find a Task associated to attachment {}.", att); - throw new SystemException("Could not find a Task associated to attachment " + att); - } - String domain = aTaskSummary.getDomain(); - String classificationKey = att.getClassificationSummary().getKey(); + String classificationId = att.getClassificationSummary().getId(); ClassificationSummary aClassification = classifications.stream() - .filter(x -> classificationKey != null && classificationKey.equals(x.getKey()) && domain != null - && domain.equals(x.getDomain())) + .filter(x -> classificationId != null && classificationId.equals(x.getId())) .findFirst() .orElse(null); if (aClassification == null) { @@ -916,13 +887,11 @@ public class TaskServiceImpl implements TaskService { List result = new ArrayList<>(); for (AttachmentImpl att : attachmentImpls) { // find the associated task to use the correct domain - String domain = task.getDomain(); - String classificationKey = att.getClassificationSummary().getKey(); ClassificationSummary aClassification = classifications.stream() - .filter(x -> classificationKey != null && classificationKey.equals(x.getKey()) && domain != null - && domain.equals(x.getDomain())) + .filter(c -> c != null & c.getId().equals(att.getClassificationSummary().getId())) .findFirst() .orElse(null); + if (aClassification == null) { LOGGER.error("Could not find a Classification for attachment {}.", att); throw new SystemException("Could not find a Classification for attachment " + att); @@ -1188,7 +1157,7 @@ public class TaskServiceImpl implements TaskService { private void updateClassificationRelatedProperties(TaskImpl oldTaskImpl, TaskImpl newTaskImpl, PrioDurationHolder prioDurationFromAttachments) - throws WorkbasketNotFoundException, NotAuthorizedException, ClassificationNotFoundException { + throws NotAuthorizedException, ClassificationNotFoundException { // insert Classification specifications if Classification is given. ClassificationSummary oldClassificationSummary = oldTaskImpl.getClassificationSummary(); ClassificationSummary newClassificationSummary = newTaskImpl.getClassificationSummary(); @@ -1341,6 +1310,32 @@ public class TaskServiceImpl implements TaskService { return new PrioDurationHolder(minDuration, maxPrio); } + private PrioDurationHolder handleAttachmentsOnClassificationUpdate(Task task) { + + Duration minDuration = MAX_DURATION; + int maxPrio = Integer.MIN_VALUE; + + // Iterator for removing invalid current values directly. OldAttachments can be ignored. + Iterator i = task.getAttachments().iterator(); + while (i.hasNext()) { + Attachment attachment = i.next(); + if (attachment != null) { + ClassificationSummary classification = attachment.getClassificationSummary(); + if (classification != null) { + PrioDurationHolder newPrioDuration = getNewPrioDuration(maxPrio, minDuration, + classification.getPriority(), classification.getServiceLevel()); + maxPrio = newPrioDuration.getPrio(); + minDuration = newPrioDuration.getDuration(); + } + + } + } + if (minDuration != null && MAX_DURATION.equals(minDuration)) { + minDuration = null; + } + return new PrioDurationHolder(minDuration, maxPrio); + } + private PrioDurationHolder getNewPrioDuration(int prio, Duration duration, int prioFromClassification, String serviceLevelFromClassification) { Duration minDuration = duration; @@ -1415,4 +1410,71 @@ public class TaskServiceImpl implements TaskService { } } + BulkOperationResults classificationChanged(String taskId, String classificationId) + throws TaskNotFoundException, NotAuthorizedException, ClassificationNotFoundException { + LOGGER.debug("entry to classificationChanged(taskId = {} , classificationId = {} )", taskId, classificationId); + TaskImpl task = null; + BulkOperationResults bulkLog = new BulkOperationResults<>(); + try { + taskanaEngine.openConnection(); + if (taskId == null || taskId.isEmpty() || classificationId == null || classificationId.isEmpty()) { + return bulkLog; + } + + task = taskMapper.findById(taskId); + + List attachmentImpls = attachmentMapper.findAttachmentsByTaskId(task.getId()); + if (attachmentImpls == null) { + attachmentImpls = new ArrayList<>(); + } + List attachments = augmentAttachmentsByClassification(attachmentImpls, bulkLog); + task.setAttachments(attachments); + + Classification classification = classificationService.getClassification(classificationId); + task.setClassificationSummary(classification.asSummary()); + + PrioDurationHolder prioDurationFromAttachments = handleAttachmentsOnClassificationUpdate(task); + + updateClassificationRelatedProperties(task, task, prioDurationFromAttachments); + + task.setModified(Instant.now()); + taskMapper.update(task); + return bulkLog; + } finally { + taskanaEngine.returnConnection(); + LOGGER.debug("exit from deleteTask(). "); + } + + } + + private List augmentAttachmentsByClassification(List attachmentImpls, + BulkOperationResults bulkLog) { + List result = new ArrayList<>(); + if (attachmentImpls == null || attachmentImpls.isEmpty()) { + return result; + } + Set classificationIds = attachmentImpls.stream().map(t -> t.getClassificationSummary().getId()).collect( + Collectors.toSet()); + List classifications = classificationService.createClassificationQuery() + .idIn(classificationIds.toArray(new String[0])) + .list(); + for (AttachmentImpl att : attachmentImpls) { + ClassificationSummary classificationSummary = classifications.stream() + .filter(cl -> cl.getId().equals(att.getClassificationSummary().getId())) + .findFirst() + .orElse(null); + if (classificationSummary == null) { + String id = att.getClassificationSummary().getId(); + bulkLog.addError(att.getClassificationSummary().getId(), new ClassificationNotFoundException(id, + "When processing task updates due to change of classification, the classification with id " + id + + " was not found.")); + } else { + att.setClassificationSummary(classificationSummary); + result.add(att); + } + } + + return result; + } + } diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskUpdateOnClassificationChangeExecutor.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskUpdateOnClassificationChangeExecutor.java new file mode 100644 index 000000000..cce28bf85 --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskUpdateOnClassificationChangeExecutor.java @@ -0,0 +1,81 @@ +package pro.taskana.impl; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import pro.taskana.impl.util.LoggerUtils; +import pro.taskana.mappings.AttachmentMapper; +import pro.taskana.mappings.ClassificationMapper; +import pro.taskana.mappings.TaskMapper; + +/** + * This class performs task updates if a classification is changed. + * + * @author bbr + */ +public class TaskUpdateOnClassificationChangeExecutor implements SingleJobExecutor { + + private static final Logger LOGGER = LoggerFactory.getLogger(TaskServiceImpl.class); + public static final String CLASSIFICATION_ID = "classificationId"; + public static final String PRIORITY_CHANGED = "priorityChanged"; + public static final String SERVICE_LEVEL_CHANGED = "serviceLevelChanged"; + + private TaskanaEngineImpl taskanaEngine; + private Job job; + private String classificationId; + private boolean priorityChanged; + private boolean serviceLevelChanged; + private TaskMapper taskMapper; + private ClassificationMapper classificationMapper; + private AttachmentMapper attachmentMapper; + + public TaskUpdateOnClassificationChangeExecutor() { + } + + @Override + public BulkOperationResults runSingleJob(Job job, TaskanaEngineImpl taskanaEngine) { + this.job = job; + this.taskanaEngine = taskanaEngine; + this.taskMapper = taskanaEngine.getSqlSession().getMapper(TaskMapper.class); + this.classificationMapper = taskanaEngine.getSqlSession().getMapper(ClassificationMapper.class); + this.attachmentMapper = taskanaEngine.getSqlSession().getMapper(AttachmentMapper.class); + Map args = job.getArguments(); + classificationId = args.get(CLASSIFICATION_ID); + priorityChanged = Boolean.getBoolean(args.get(PRIORITY_CHANGED)); + serviceLevelChanged = Boolean.getBoolean(args.get(SERVICE_LEVEL_CHANGED)); + BulkOperationResults bulkLog = new BulkOperationResults<>(); + bulkLog.addAllErrors(handleAffectedTasks()); + + return bulkLog; + } + + private BulkOperationResults handleAffectedTasks() { + List tasks = taskMapper.findTasksAffectedByClassificationChange(classificationId); + List taskIdsFromAttachments = attachmentMapper + .findTaskIdsAffectedByClassificationChange(classificationId); + List filteredTaskIdsFromAttachments = taskMapper.filterTaskIdsForNotCompleted(taskIdsFromAttachments); + + Set affectedTaskIds = new HashSet<>(filteredTaskIdsFromAttachments); + for (TaskSummaryImpl task : tasks) { + affectedTaskIds.add(task.getTaskId()); + } + LOGGER.debug("the following tasks are affected by the update of classification {} : {}", classificationId, + LoggerUtils.setToString(affectedTaskIds)); + TaskServiceImpl taskService = (TaskServiceImpl) taskanaEngine.getTaskService(); + BulkOperationResults bulkLog = new BulkOperationResults<>(); + for (String taskId : affectedTaskIds) { + try { + bulkLog.addAllErrors(taskService.classificationChanged(taskId, classificationId)); + } catch (Exception e) { + bulkLog.addError(taskId, e); + } + } + return bulkLog; + } + +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskanaEngineImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskanaEngineImpl.java index 05a448077..0fafe2248 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskanaEngineImpl.java +++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskanaEngineImpl.java @@ -47,6 +47,7 @@ import pro.taskana.impl.util.LoggerUtils; import pro.taskana.mappings.AttachmentMapper; import pro.taskana.mappings.ClassificationMapper; import pro.taskana.mappings.DistributionTargetMapper; +import pro.taskana.mappings.JobMapper; import pro.taskana.mappings.ObjectReferenceMapper; import pro.taskana.mappings.QueryMapper; import pro.taskana.mappings.TaskMapper; @@ -325,6 +326,7 @@ public class TaskanaEngineImpl implements TaskanaEngine { configuration.addMapper(ObjectReferenceMapper.class); configuration.addMapper(QueryMapper.class); configuration.addMapper(AttachmentMapper.class); + configuration.addMapper(JobMapper.class); configuration.getTypeHandlerRegistry().register(MapTypeHandler.class); SqlSessionFactory localSessionFactory = new SqlSessionFactoryBuilder().build(configuration); return SqlSessionManager.newInstance(localSessionFactory); diff --git a/lib/taskana-core/src/main/java/pro/taskana/mappings/AttachmentMapper.java b/lib/taskana-core/src/main/java/pro/taskana/mappings/AttachmentMapper.java index 5168ea4cb..394ea6431 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/mappings/AttachmentMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/mappings/AttachmentMapper.java @@ -93,6 +93,24 @@ public interface AttachmentMapper { }) List findAttachmentSummariesByTaskIds(String[] taskIds); + @Select("") + @Results(value = { + @Result(property = "id", column = "ID"), + @Result(property = "taskId", column = "TASK_ID"), + @Result(property = "created", column = "CREATED"), + @Result(property = "modified", column = "MODIFIED"), + @Result(property = "classificationSummaryImpl.key", column = "CLASSIFICATION_KEY"), + @Result(property = "classificationSummaryImpl.id", column = "CLASSIFICATION_ID"), + @Result(property = "received", column = "RECEIVED"), + }) + List findAttachmentSummariesByClassificationId( + @Param("classificationId") String classificationId); + @Delete("DELETE FROM ATTACHMENT WHERE ID=#{attachmentId}") void deleteAttachment(@Param("attachmentId") String attachmentId); @@ -111,4 +129,12 @@ public interface AttachmentMapper { javaType = String.class, typeHandler = ClobTypeHandler.class) }) String getCustomAttributesAsString(@Param("attachmentId") String attachmentId); + + @Select("") + @Results(value = { + @Result(property = "taskId", column = "TASK_ID")}) + List findTaskIdsAffectedByClassificationChange(@Param("classificationId") String classificationId); + } diff --git a/lib/taskana-core/src/main/java/pro/taskana/mappings/JobMapper.java b/lib/taskana-core/src/main/java/pro/taskana/mappings/JobMapper.java new file mode 100644 index 000000000..30726a896 --- /dev/null +++ b/lib/taskana-core/src/main/java/pro/taskana/mappings/JobMapper.java @@ -0,0 +1,47 @@ +package pro.taskana.mappings; + +import java.util.List; +import java.util.Map; + +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Result; +import org.apache.ibatis.annotations.Results; +import org.apache.ibatis.annotations.Select; +import org.apache.ibatis.annotations.Update; +import org.apache.ibatis.type.JdbcType; + +import pro.taskana.impl.Job; +import pro.taskana.impl.persistence.MapTypeHandler; + +/** + * This class is the mybatis mapping of the JOB table. + */ +public interface JobMapper { + + @Insert("INSERT INTO JOB (JOB_ID, CREATED, STARTED, COMPLETED, STATE, EXECUTOR, ARGUMENTS) " + + "VALUES (NEXT VALUE FOR JOB_SEQ, #{job.created}, #{job.started}, #{job.completed}, #{job.state}, #{job.executor}, #{job.arguments,jdbcType=CLOB, javaType=java.util.Map,typeHandler=pro.taskana.impl.persistence.MapTypeHandler} )") + void insertJob(@Param("job") Job job); + + @Select("SELECT JOB_ID, CREATED, STARTED, COMPLETED, STATE, EXECUTOR, ARGUMENTS " + + "FROM JOB " + + "WHERE STATE IN ( 'READY') " + + "ORDER BY JOB_ID ") + @Results(value = { + @Result(property = "jobId", column = "JOB_ID"), + @Result(property = "created", column = "CREATED"), + @Result(property = "started", column = "STARTED"), + @Result(property = "completed", column = "COMPLETED"), + @Result(property = "state", column = "STATE"), + @Result(property = "executor", column = "EXECUTOR"), + @Result(property = "arguments", column = "ARGUMENTS", jdbcType = JdbcType.CLOB, + javaType = Map.class, typeHandler = MapTypeHandler.class) + }) + List findJobsToRun(); + + @Update( + value = "UPDATE JOB SET CREATED = #{created}, STARTED = #{started}, COMPLETED = #{completed}, STATE = #{state}, EXECUTOR = #{executor}, " + + "ARGUMENTS = #{arguments,jdbcType=CLOB ,javaType=java.util.Map,typeHandler=pro.taskana.impl.persistence.MapTypeHandler} " + + "where JOB_ID = #{jobId}") + void update(Job job); +} diff --git a/lib/taskana-core/src/main/java/pro/taskana/mappings/QueryMapper.java b/lib/taskana-core/src/main/java/pro/taskana/mappings/QueryMapper.java index 2126ad093..01b847522 100644 --- a/lib/taskana-core/src/main/java/pro/taskana/mappings/QueryMapper.java +++ b/lib/taskana-core/src/main/java/pro/taskana/mappings/QueryMapper.java @@ -27,7 +27,7 @@ public interface QueryMapper { String CLASSIFICATION_FINDBYID = "pro.taskana.mappings.ClassificationMapper.findById"; String WORKBASKET_FINDSUMMARYBYKEY = "pro.taskana.mappings.WorkbasketMapper.findSummaryByKey"; - @Select("") + @Results(value = { + @Result(property = "taskId", column = "ID"), + @Result(property = "created", column = "CREATED"), + @Result(property = "claimed", column = "CLAIMED"), + @Result(property = "completed", column = "COMPLETED"), + @Result(property = "modified", column = "MODIFIED"), + @Result(property = "planned", column = "PLANNED"), + @Result(property = "due", column = "DUE"), + @Result(property = "name", column = "NAME"), + @Result(property = "creator", column = "CREATOR"), + @Result(property = "note", column = "NOTE"), + @Result(property = "priority", column = "PRIORITY"), + @Result(property = "state", column = "STATE"), + @Result(property = "classificationSummaryImpl.category", column = "CLASSIFICATION_CATEGORY"), + @Result(property = "classificationSummaryImpl.key", column = "CLASSIFICATION_KEY"), + @Result(property = "classificationSummaryImpl.id", column = "CLASSIFICATION_ID"), + @Result(property = "workbasketSummaryImpl.id", column = "WORKBASKET_ID"), + @Result(property = "workbasketSummaryImpl.key", column = "WORKBASKET_KEY"), + @Result(property = "workbasketSummaryImpl.domain", column = "DOMAIN"), + @Result(property = "domain", column = "DOMAIN"), + @Result(property = "businessProcessId", column = "BUSINESS_PROCESS_ID"), + @Result(property = "parentBusinessProcessId", column = "PARENT_BUSINESS_PROCESS_ID"), + @Result(property = "owner", column = "OWNER"), + @Result(property = "primaryObjRef.company", column = "POR_COMPANY"), + @Result(property = "primaryObjRef.system", column = "POR_SYSTEM"), + @Result(property = "primaryObjRef.systemInstance", column = "POR_INSTANCE"), + @Result(property = "primaryObjRef.type", column = "POR_TYPE"), + @Result(property = "primaryObjRef.value", column = "POR_VALUE"), + @Result(property = "isRead", column = "IS_READ"), + @Result(property = "isTransferred", column = "IS_TRANSFERRED"), + @Result(property = "custom1", column = "CUSTOM_1"), + @Result(property = "custom2", column = "CUSTOM_2"), + @Result(property = "custom3", column = "CUSTOM_3"), + @Result(property = "custom4", column = "CUSTOM_4"), + @Result(property = "custom5", column = "CUSTOM_5"), + @Result(property = "custom6", column = "CUSTOM_6"), + @Result(property = "custom7", column = "CUSTOM_7"), + @Result(property = "custom8", column = "CUSTOM_8"), + @Result(property = "custom9", column = "CUSTOM_9"), + @Result(property = "custom10", column = "CUSTOM_10"), + @Result(property = "custom11", column = "CUSTOM_11"), + @Result(property = "custom12", column = "CUSTOM_12"), + @Result(property = "custom13", column = "CUSTOM_13"), + @Result(property = "custom14", column = "CUSTOM_14"), + @Result(property = "custom15", column = "CUSTOM_15"), + @Result(property = "custom16", column = "CUSTOM_16")}) + List findTasksAffectedByClassificationChange(@Param("classificationId") String classificationId); + @Update("") + @Results(value = { + @Result(property = "taskId", column = "ID")}) + List filterTaskIdsForNotCompleted(@Param("taskIds") List taskIds); + } diff --git a/lib/taskana-core/src/main/resources/sql/taskana-schema.sql b/lib/taskana-core/src/main/resources/sql/taskana-schema.sql index 38df1ac75..e1ac9ce54 100644 --- a/lib/taskana-core/src/main/resources/sql/taskana-schema.sql +++ b/lib/taskana-core/src/main/resources/sql/taskana-schema.sql @@ -163,3 +163,21 @@ CREATE TABLE ATTACHMENT( PRIMARY KEY (ID), CONSTRAINT ATT_CLASS FOREIGN KEY (CLASSIFICATION_ID) REFERENCES CLASSIFICATION ON DELETE NO ACTION ); + +CREATE TABLE JOB( + JOB_ID INTEGER NOT NULL, + CREATED TIMESTAMP NULL, + STARTED TIMESTAMP NULL, + COMPLETED TIMESTAMP NULL, + STATE VARCHAR(32) NULL, + EXECUTOR VARCHAR(128) NOT NULL, + ARGUMENTS CLOB NULL, + PRIMARY KEY (JOB_ID) +); + +CREATE SEQUENCE JOB_SEQ + MINVALUE 1 + START WITH 1 + INCREMENT BY 1 + CACHE 10; + diff --git a/lib/taskana-core/src/test/java/acceptance/classification/DeleteClassificationAccTest.java b/lib/taskana-core/src/test/java/acceptance/classification/DeleteClassificationAccTest.java index 89bf863a6..d1e8ad256 100644 --- a/lib/taskana-core/src/test/java/acceptance/classification/DeleteClassificationAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/classification/DeleteClassificationAccTest.java @@ -80,6 +80,25 @@ public class DeleteClassificationAccTest extends AbstractAccTest { @Test public void testDeleteMasterClassification() throws SQLException, ClassificationNotFoundException, NotAuthorizedException, ClassificationInUseException { + + classificationService.deleteClassification("L3060", ""); + + boolean classificationNotFound = false; + try { + classificationService.getClassification("L3060", "DOMAIN_A"); + } catch (ClassificationNotFoundException e) { + classificationNotFound = true; + } + assertTrue(classificationNotFound); + } + + @WithAccessId( + userName = "dummy", + groupNames = {"businessadmin"}) + @Test(expected = ClassificationInUseException.class) + public void testDeleteMasterClassificationWithExistingAttachment() + throws SQLException, ClassificationNotFoundException, NotAuthorizedException, ClassificationInUseException { + classificationService.deleteClassification("L12010", ""); boolean classificationNotFound = false; diff --git a/lib/taskana-core/src/test/java/acceptance/classification/QueryClassificationAccTest.java b/lib/taskana-core/src/test/java/acceptance/classification/QueryClassificationAccTest.java index eea2a92b5..0f2818a89 100644 --- a/lib/taskana-core/src/test/java/acceptance/classification/QueryClassificationAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/classification/QueryClassificationAccTest.java @@ -94,7 +94,7 @@ public class QueryClassificationAccTest extends AbstractAccTest { .list(); assertNotNull(classifications); - assertEquals(23, classifications.size()); + assertEquals(25, classifications.size()); List documentTypes = classifications.stream() .filter(c -> c.getType().equals("DOCUMENT")) @@ -106,7 +106,7 @@ public class QueryClassificationAccTest extends AbstractAccTest { .filter(c -> c.getType().equals("TASK")) .collect( Collectors.toList()); - assertEquals(21, taskTypes.size()); + assertEquals(23, taskTypes.size()); } @Test @@ -167,7 +167,7 @@ public class QueryClassificationAccTest extends AbstractAccTest { .domainIn("DOMAIN_A") .list(); assertNotNull(classifications); - assertEquals(13, classifications.size()); + assertEquals(14, classifications.size()); } @Test @@ -180,7 +180,7 @@ public class QueryClassificationAccTest extends AbstractAccTest { .typeIn("TASK") .list(); assertNotNull(classifications); - assertEquals(11, classifications.size()); + assertEquals(12, classifications.size()); } @Test @@ -206,7 +206,7 @@ public class QueryClassificationAccTest extends AbstractAccTest { .list(); assertNotNull(classificationSummaryList); - assertEquals(16, classificationSummaryList.size()); + assertEquals(17, classificationSummaryList.size()); } @Test diff --git a/lib/taskana-core/src/test/java/acceptance/classification/QueryClassificationWithPaginationAccTest.java b/lib/taskana-core/src/test/java/acceptance/classification/QueryClassificationWithPaginationAccTest.java index 506295842..73bfbfa07 100644 --- a/lib/taskana-core/src/test/java/acceptance/classification/QueryClassificationWithPaginationAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/classification/QueryClassificationWithPaginationAccTest.java @@ -93,7 +93,7 @@ public class QueryClassificationWithPaginationAccTest extends AbstractAccTest { results = classificationService.createClassificationQuery() .domainIn("DOMAIN_A") .listPage(pageNumber, pageSize); - assertThat(results.size(), equalTo(16)); + assertThat(results.size(), equalTo(17)); // Getting last results on multiple pages pageNumber = 2; @@ -101,7 +101,7 @@ public class QueryClassificationWithPaginationAccTest extends AbstractAccTest { results = classificationService.createClassificationQuery() .domainIn("DOMAIN_A") .listPage(pageNumber, pageSize); - assertThat(results.size(), equalTo(6)); + assertThat(results.size(), equalTo(7)); } @Test @@ -159,7 +159,7 @@ public class QueryClassificationWithPaginationAccTest extends AbstractAccTest { long count = classificationService.createClassificationQuery() .domainIn("DOMAIN_A") .count(); - assertThat(count, equalTo(16L)); + assertThat(count, equalTo(17L)); } } diff --git a/lib/taskana-core/src/test/java/acceptance/classification/UpdateClassificationAccTest.java b/lib/taskana-core/src/test/java/acceptance/classification/UpdateClassificationAccTest.java index d2fe23898..a0cde6f4b 100644 --- a/lib/taskana-core/src/test/java/acceptance/classification/UpdateClassificationAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/classification/UpdateClassificationAccTest.java @@ -8,7 +8,12 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.sql.SQLException; +import java.time.Duration; import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; @@ -16,11 +21,17 @@ import org.junit.runner.RunWith; import acceptance.AbstractAccTest; import pro.taskana.Classification; import pro.taskana.ClassificationService; +import pro.taskana.Task; +import pro.taskana.TaskService; import pro.taskana.exceptions.ClassificationNotFoundException; import pro.taskana.exceptions.ConcurrencyException; +import pro.taskana.exceptions.InvalidArgumentException; import pro.taskana.exceptions.NotAuthorizedException; import pro.taskana.exceptions.TaskNotFoundException; +import pro.taskana.impl.DaysToWorkingDaysConverter; +import pro.taskana.impl.JobRunner; import pro.taskana.impl.TaskImpl; +import pro.taskana.impl.report.impl.TimeIntervalColumnHeader; import pro.taskana.security.JAASRunner; import pro.taskana.security.WithAccessId; @@ -108,7 +119,8 @@ public class UpdateClassificationAccTest extends AbstractAccTest { groupNames = {"group_1", "businessadmin"}) @Test public void testUpdateTaskOnClassificationKeyCategoryChange() - throws TaskNotFoundException, ClassificationNotFoundException, NotAuthorizedException, ConcurrencyException { + throws Exception { + setupTest(); TaskImpl beforeTask = (TaskImpl) taskanaEngine.getTaskService() .getTask("TKI:000000000000000000000000000000000000"); @@ -168,4 +180,71 @@ public class UpdateClassificationAccTest extends AbstractAccTest { classification = classificationService.updateClassification(classification); } + @WithAccessId( + userName = "dummy", + groupNames = {"admin"}) + @Test + public void testUpdateClassificationPrioServiceLevel() + throws SQLException, ClassificationNotFoundException, NotAuthorizedException, ConcurrencyException, + InterruptedException, TaskNotFoundException, InvalidArgumentException { + String newEntryPoint = "updated EntryPoint"; + Instant before = Instant.now(); + ClassificationService classificationService = taskanaEngine.getClassificationService(); + Classification classification = classificationService + .getClassification("CLI:100000000000000000000000000000000003"); + Instant createdBefore = classification.getCreated(); + Instant modifiedBefore = classification.getModified(); + classification.setPriority(1000); + classification.setServiceLevel("P15D"); + + classificationService.updateClassification(classification); + Thread.sleep(100); + JobRunner runner = new JobRunner(taskanaEngine); + runner.runJobs(); + // Get and check the new value + Classification updatedClassification = classificationService + .getClassification("CLI:100000000000000000000000000000000003"); + assertNotNull(updatedClassification); + + assertTrue(modifiedBefore.isBefore(updatedClassification.getModified())); + List affectedTasks = new ArrayList<>( + Arrays.asList("TKI:000000000000000000000000000000000000", "TKI:000000000000000000000000000000000003", + "TKI:000000000000000000000000000000000004", "TKI:000000000000000000000000000000000005", + "TKI:000000000000000000000000000000000006", "TKI:000000000000000000000000000000000007", + "TKI:000000000000000000000000000000000008", "TKI:000000000000000000000000000000000009", + "TKI:000000000000000000000000000000000010", "TKI:000000000000000000000000000000000011", + "TKI:000000000000000000000000000000000012", "TKI:000000000000000000000000000000000013", + "TKI:000000000000000000000000000000000014", "TKI:000000000000000000000000000000000015", + "TKI:000000000000000000000000000000000016", "TKI:000000000000000000000000000000000017", + "TKI:000000000000000000000000000000000018", "TKI:000000000000000000000000000000000019", + "TKI:000000000000000000000000000000000020", "TKI:000000000000000000000000000000000021", + "TKI:000000000000000000000000000000000022", "TKI:000000000000000000000000000000000023", + "TKI:000000000000000000000000000000000024", "TKI:000000000000000000000000000000000025", + "TKI:000000000000000000000000000000000026", "TKI:000000000000000000000000000000000027", + "TKI:000000000000000000000000000000000028", "TKI:000000000000000000000000000000000029", + "TKI:000000000000000000000000000000000030", "TKI:000000000000000000000000000000000031", + "TKI:000000000000000000000000000000000032", "TKI:000000000000000000000000000000000033", + "TKI:000000000000000000000000000000000034", "TKI:000000000000000000000000000000000035", + "TKI:000000000000000000000000000000000053", "TKI:000000000000000000000000000000000054", + "TKI:000000000000000000000000000000000055", "TKI:000000000000000000000000000000000100", + "TKI:000000000000000000000000000000000101", "TKI:000000000000000000000000000000000102", + "TKI:000000000000000000000000000000000103")); + TaskService taskService = taskanaEngine.getTaskService(); + + DaysToWorkingDaysConverter converter = DaysToWorkingDaysConverter + .initialize(Collections.singletonList(new TimeIntervalColumnHeader(0)), Instant.now()); + + for (String taskId : affectedTasks) { + Task task = taskService.getTask(taskId); + assertTrue(task.getModified().isAfter(before)); + assertTrue(task.getPriority() == 1000); + long calendarDays = converter.convertWorkingDaysToDays(task.getPlanned(), 15); + if (!taskId.equals("TKI:000000000000000000000000000000000008") + && !taskId.equals("TKI:000000000000000000000000000000000053")) { + assertTrue(task.getDue().equals(task.getPlanned().plus(Duration.ofDays(calendarDays)))); + } + + } + } + } diff --git a/lib/taskana-core/src/test/java/acceptance/security/ClassificationQueryAccTest.java b/lib/taskana-core/src/test/java/acceptance/security/ClassificationQueryAccTest.java index aeac5642c..cf3400c3a 100644 --- a/lib/taskana-core/src/test/java/acceptance/security/ClassificationQueryAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/security/ClassificationQueryAccTest.java @@ -39,7 +39,7 @@ public class ClassificationQueryAccTest extends AbstractAccTest { .list(); assertNotNull(classificationSummaryList); - assertEquals(16, classificationSummaryList.size()); + assertEquals(17, classificationSummaryList.size()); } @WithAccessId(userName = "businessadmin") @@ -52,7 +52,7 @@ public class ClassificationQueryAccTest extends AbstractAccTest { .list(); assertNotNull(classificationSummaryList); - assertEquals(16, classificationSummaryList.size()); + assertEquals(17, classificationSummaryList.size()); } @WithAccessId(userName = "admin") @@ -65,7 +65,7 @@ public class ClassificationQueryAccTest extends AbstractAccTest { .list(); assertNotNull(classificationSummaryList); - assertEquals(16, classificationSummaryList.size()); + assertEquals(17, classificationSummaryList.size()); } } diff --git a/lib/taskana-core/src/test/java/acceptance/task/QueryTasksAccTest.java b/lib/taskana-core/src/test/java/acceptance/task/QueryTasksAccTest.java index 3c9edf679..59cb14e8e 100644 --- a/lib/taskana-core/src/test/java/acceptance/task/QueryTasksAccTest.java +++ b/lib/taskana-core/src/test/java/acceptance/task/QueryTasksAccTest.java @@ -189,12 +189,8 @@ public class QueryTasksAccTest extends AbstractAccTest { .idIn("TKI:000000000000000000000000000000000000") .list(); assertThat(results.size(), equalTo(1)); - assertThat(results.get(0).getAttachmentSummaries().size(), equalTo(1)); + assertThat(results.get(0).getAttachmentSummaries().size(), equalTo(3)); AttachmentSummary att = results.get(0).getAttachmentSummaries().get(0); - assertThat(att.getClassificationSummary(), equalTo(attachment.getClassificationSummary())); - assertThat(att.getCreated(), equalTo(task.getAttachments().get(0).getCreated())); - assertThat(att.getModified(), equalTo(task.getAttachments().get(0).getModified())); - } @WithAccessId( diff --git a/lib/taskana-core/src/test/java/pro/taskana/database/TestDataGenerator.java b/lib/taskana-core/src/test/java/pro/taskana/database/TestDataGenerator.java index 2a9ed1b1f..c8990606b 100644 --- a/lib/taskana-core/src/test/java/pro/taskana/database/TestDataGenerator.java +++ b/lib/taskana-core/src/test/java/pro/taskana/database/TestDataGenerator.java @@ -61,6 +61,8 @@ public class TestDataGenerator { new InputStreamReader(this.getClass().getResourceAsStream("/sql/distribution-targets.sql"))); runner.runScript( new InputStreamReader(this.getClass().getResourceAsStream("/sql/object-reference.sql"))); + runner.runScript( + new InputStreamReader(this.getClass().getResourceAsStream("/sql/attachment.sql"))); } finally { runner.closeConnection(); diff --git a/lib/taskana-core/src/test/java/pro/taskana/impl/TaskServiceImplTest.java b/lib/taskana-core/src/test/java/pro/taskana/impl/TaskServiceImplTest.java index b0dd423fd..b68bce3a6 100644 --- a/lib/taskana-core/src/test/java/pro/taskana/impl/TaskServiceImplTest.java +++ b/lib/taskana-core/src/test/java/pro/taskana/impl/TaskServiceImplTest.java @@ -692,8 +692,7 @@ public class TaskServiceImplTest { doReturn(null).when(attachmentMapperMock).findAttachmentsByTaskId(task.getId()); doReturn(task).when(cutSpy).completeTask(task.getId(), isForced); doReturn(classificationQueryImplMock).when(classificationServiceImplMock).createClassificationQuery(); - doReturn(classificationQueryImplMock).when(classificationQueryImplMock).domainIn(any()); - doReturn(classificationQueryImplMock).when(classificationQueryImplMock).keyIn(any()); + doReturn(classificationQueryImplMock).when(classificationQueryImplMock).idIn(any()); doReturn(new ArrayList<>()).when(classificationQueryImplMock).list(); List classificationList = Arrays .asList((ClassificationSummaryImpl) dummyClassification.asSummary()); @@ -714,8 +713,7 @@ public class TaskServiceImplTest { verify(taskMapperMock, times(1)).findById(task.getId()); verify(attachmentMapperMock, times(1)).findAttachmentsByTaskId(task.getId()); verify(classificationServiceImplMock, times(1)).createClassificationQuery(); - verify(classificationQueryImplMock, times(1)).domainIn(any()); - verify(classificationQueryImplMock, times(1)).keyIn(any()); + verify(classificationQueryImplMock, times(1)).idIn(any()); verify(classificationQueryImplMock, times(1)).list(); verify(taskMapperMock, times(1)).update(any()); verify(taskanaEngineMock, times(2)).returnConnection(); @@ -1146,8 +1144,7 @@ public class TaskServiceImplTest { doReturn(null).when(attachmentMapperMock).findAttachmentsByTaskId(expectedTask.getId()); doReturn(classificationQueryImplMock).when(classificationServiceImplMock).createClassificationQuery(); - doReturn(classificationQueryImplMock).when(classificationQueryImplMock).domainIn(any()); - doReturn(classificationQueryImplMock).when(classificationQueryImplMock).keyIn(any()); + doReturn(classificationQueryImplMock).when(classificationQueryImplMock).idIn(any()); doReturn(workbasketQueryImplMock).when(workbasketServiceMock).createWorkbasketQuery(); doReturn(workbasketQueryImplMock).when(workbasketQueryImplMock).idIn(any()); List wbList = new ArrayList<>(); @@ -1167,8 +1164,7 @@ public class TaskServiceImplTest { verify(taskMapperMock, times(1)).findById(expectedTask.getId()); verify(attachmentMapperMock, times(1)).findAttachmentsByTaskId(expectedTask.getId()); verify(classificationServiceImplMock, times(1)).createClassificationQuery(); - verify(classificationQueryImplMock, times(1)).domainIn(any()); - verify(classificationQueryImplMock, times(1)).keyIn(any()); + verify(classificationQueryImplMock, times(1)).idIn(any()); verify(classificationQueryImplMock, times(1)).list(); verify(workbasketServiceMock, times(1)).createWorkbasketQuery(); verify(workbasketQueryImplMock, times(1)).idIn(any()); @@ -1379,6 +1375,7 @@ public class TaskServiceImplTest { classification.setName("dummy-classification"); classification.setDomain("dummy-domain"); classification.setKey("dummy-classification-key"); + classification.setId("DummyClassificationId"); return classification; } diff --git a/lib/taskana-core/src/test/java/pro/taskana/impl/TestClassificationQuery.java b/lib/taskana-core/src/test/java/pro/taskana/impl/TestClassificationQuery.java index 76f3705de..1d15352b2 100644 --- a/lib/taskana-core/src/test/java/pro/taskana/impl/TestClassificationQuery.java +++ b/lib/taskana-core/src/test/java/pro/taskana/impl/TestClassificationQuery.java @@ -25,6 +25,11 @@ public class TestClassificationQuery implements ClassificationQuery { return this; } + @Override + public ClassificationQuery idIn(String... id) { + return this; + } + @Override public ClassificationQuery parentIdIn(String... parentId) { this.parentId = parentId; @@ -287,4 +292,5 @@ public class TestClassificationQuery implements ClassificationQuery { public List listValues(String dbColumnName, SortDirection sortDirection) { return new ArrayList<>(); } + } diff --git a/lib/taskana-core/src/test/resources/sql/attachment.sql b/lib/taskana-core/src/test/resources/sql/attachment.sql new file mode 100644 index 000000000..11e3946c8 --- /dev/null +++ b/lib/taskana-core/src/test/resources/sql/attachment.sql @@ -0,0 +1,16 @@ +-- ATTACHMENT TABLE (ID , task_ID , CREATED , MODIFIED , classif key, classif Id , refCompany, ref sys, ref inst,ref type, ref val, channel,received, custAtts) + +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000000','TKI:000000000000000000000000000000000000', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L1050' , 'CLI:100000000000000000000000000000000003', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000001','TKI:000000000000000000000000000000000001', '2018-01-29 15:55:01', '2018-01-30 15:55:00', 'L10303' , 'CLI:000000000000000000000000000000000002', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000002','TKI:000000000000000000000000000000000001', '2018-01-29 15:55:02', '2018-01-30 15:55:00', 'L1050' , 'CLI:000000000000000000000000000000000003', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000003','TKI:000000000000000000000000000000000002', '2018-01-29 15:55:03', null , 'L11010' , 'CLI:000000000000000000000000000000000004', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000004','TKI:000000000000000000000000000000000002', '2018-01-29 15:55:04', null , 'L110102' , 'CLI:000000000000000000000000000000000005', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000005','TKI:000000000000000000000000000000000002', '2018-01-29 15:55:05', null , 'L110105' , 'CLI:000000000000000000000000000000000006', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000006','TKI:000000000000000000000000000000000002', '2018-01-29 15:55:06', null , 'L110107' , 'CLI:000000000000000000000000000000000007', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000007','TKI:000000000000000000000000000000000002', '2018-01-29 15:55:07', null , 'L12010' , 'CLI:000000000000000000000000000000000008', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000008','TKI:000000000000000000000000000000000008', '2018-01-29 15:55:08', null , 'L140101' , 'CLI:000000000000000000000000000000000009', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000009','TKI:000000000000000000000000000000000000', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L1050' , 'CLI:100000000000000000000000000000000003', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000010','TKI:000000000000000000000000000000000053', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L1050' , 'CLI:100000000000000000000000000000000003', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000011','TKI:000000000000000000000000000000000053', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L1050' , 'CLI:100000000000000000000000000000000003', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000012','TKI:000000000000000000000000000000000054', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L1050' , 'CLI:100000000000000000000000000000000003', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); +INSERT INTO ATTACHMENT VALUES('TAI:000000000000000000000000000000000013','TKI:000000000000000000000000000000000055', '2018-01-29 15:55:00', '2018-01-30 15:55:00', 'L1050' , 'CLI:100000000000000000000000000000000003', 'novatec' , 'novasys', 'nvinst', 'typ1', 'val1', 'ch1', null, null); diff --git a/lib/taskana-core/src/test/resources/sql/classification.sql b/lib/taskana-core/src/test/resources/sql/classification.sql index 27a0f83cd..558df3ae6 100644 --- a/lib/taskana-core/src/test/resources/sql/classification.sql +++ b/lib/taskana-core/src/test/resources/sql/classification.sql @@ -13,6 +13,7 @@ INSERT INTO CLASSIFICATION VALUES('CLI:000000000000000000000000000000000010', 'T INSERT INTO CLASSIFICATION VALUES('CLI:000000000000000000000000000000000011', 'T6310', '', 'AUTOMATIC', 'TASK', '', FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'T-GUK Honorarrechnung erstellen', 'Generali Unterstützungskasse Honorar wird fällig', 2, 'P11D', '', 'VNR', '', '', '', '', '', '', ''); INSERT INTO CLASSIFICATION VALUES('CLI:000000000000000000000000000000000013', 'DOCTYPE_DEFAULT', '', 'EXTERN', 'DOCUMENT', '', FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'EP allgemein', 'EP allgemein', 99, 'P2000D', '', 'VNR', '', '', '', '', '', '', ''); INSERT INTO CLASSIFICATION VALUES('CLI:000000000000000000000000000000000017', 'L1060', '', 'EXTERN', 'TASK', '', FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'Widerruf neu', 'Widerruf neu', 1, 'P1D', '', 'VNR,RVNR,KOLVNR', '', '', '', '', '', '', ''); +INSERT INTO CLASSIFICATION VALUES('CLI:300000000000000000000000000000000017', 'L3060', '', 'EXTERN', 'TASK', '', FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'Widerruf neu', 'Widerruf neu', 1, 'P1D', '', 'VNR,RVNR,KOLVNR', '', '', '', '', '', '', ''); -- DOMAIN_A CLASSIFICATIONS INSERT INTO CLASSIFICATION VALUES('CLI:100000000000000000000000000000000002', 'L10303', '', 'EXTERN', 'TASK', 'DOMAIN_A', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'Beratungsprotokoll', 'Beratungsprotokoll', 101, 'PT7H', '', 'VNR,RVNR,KOLVNR, ANR', '', '', '', '', '', '', ''); @@ -29,6 +30,7 @@ INSERT INTO CLASSIFICATION VALUES('CLI:100000000000000000000000000000000013', 'D INSERT INTO CLASSIFICATION VALUES('CLI:100000000000000000000000000000000014', 'L10000', '', 'EXTERN', 'TASK', 'DOMAIN_A', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'BUZ-Leistungsfall', 'BUZ-Leistungsfall', 1, 'P1D', '', 'VNR,RVNR,KOLVNR', 'VNR', 'VNR', 'VNR', '', '', '', ''); INSERT INTO CLASSIFICATION VALUES('CLI:100000000000000000000000000000000016', 'T2000', '', 'MANUAL', 'TASK', 'DOMAIN_A', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'T-Vertragstermin', 'T-Vertragstermin', 1, 'P1D', '', 'VNR,KOLVNR,RVNR', 'CUSTOM_2', 'Custom_3', 'custom_4', '', '', '', ''); INSERT INTO CLASSIFICATION VALUES('CLI:100000000000000000000000000000000017', 'L1060', '', 'EXTERN', 'TASK', 'DOMAIN_A', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'Widerruf neu', 'Widerruf neu', 1, 'P1D', '', 'VNR,RVNR,KOLVNR', '', '', '', '', '', '', ''); +INSERT INTO CLASSIFICATION VALUES('CLI:400000000000000000000000000000000017', 'L3060', '', 'EXTERN', 'TASK', 'DOMAIN_A', FALSE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'Widerruf neu', 'Widerruf neu', 1, 'P1D', '', 'VNR,RVNR,KOLVNR', '', '', '', '', '', '', ''); -- DOMAIN_B CLASSIFICATIONS INSERT INTO CLASSIFICATION VALUES('CLI:200000000000000000000000000000000015', 'T2100', '', 'MANUAL', 'TASK', 'DOMAIN_B', TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, 'T-Vertragstermin VERA', 'T-Vertragstermin VERA', 22, 'P2D', '', 'VNR', '', '', '', '', '', '', ''); diff --git a/lib/taskana-core/src/test/resources/sql/clear-db.sql b/lib/taskana-core/src/test/resources/sql/clear-db.sql index 395f8f5f6..43b4c7d86 100644 --- a/lib/taskana-core/src/test/resources/sql/clear-db.sql +++ b/lib/taskana-core/src/test/resources/sql/clear-db.sql @@ -5,4 +5,5 @@ DELETE FROM CLASSIFICATION; DELETE FROM WORKBASKET_ACCESS_LIST; DELETE FROM OBJECT_REFERENCE; DELETE FROM ATTACHMENT; +DELETE FROM JOB; COMMIT; diff --git a/lib/taskana-core/src/test/resources/sql/drop-tables.sql b/lib/taskana-core/src/test/resources/sql/drop-tables.sql index db97f45b1..6c59038b0 100644 --- a/lib/taskana-core/src/test/resources/sql/drop-tables.sql +++ b/lib/taskana-core/src/test/resources/sql/drop-tables.sql @@ -6,4 +6,6 @@ DROP TABLE CLASSIFICATION; DROP TABLE WORKBASKET_ACCESS_LIST; DROP TABLE OBJECT_REFERENCE; DROP TABLE ATTACHMENT; +DROP TABLE JOB; +DROP SEQUENCE JOB_SEQ; COMMIT; diff --git a/rest/taskana-rest-spring-example/src/main/java/pro/taskana/rest/ExampleRestApplication.java b/rest/taskana-rest-spring-example/src/main/java/pro/taskana/rest/ExampleRestApplication.java index 8d05dd7ff..78fbdd7e3 100644 --- a/rest/taskana-rest-spring-example/src/main/java/pro/taskana/rest/ExampleRestApplication.java +++ b/rest/taskana-rest-spring-example/src/main/java/pro/taskana/rest/ExampleRestApplication.java @@ -9,6 +9,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.DependsOn; import org.springframework.context.annotation.Import; +import org.springframework.scheduling.annotation.EnableScheduling; import pro.taskana.sampledata.SampleDataGenerator; @@ -16,6 +17,7 @@ import pro.taskana.sampledata.SampleDataGenerator; * Example Application showing the implementation of taskana-rest-spring. */ @SpringBootApplication +@EnableScheduling @Import(RestConfiguration.class) public class ExampleRestApplication { @@ -24,7 +26,7 @@ public class ExampleRestApplication { } @Bean - @DependsOn("taskanaEngineConfiguration") //generate sample data after schema was inserted + @DependsOn("taskanaEngineConfiguration") // generate sample data after schema was inserted public SampleDataGenerator generateSampleData(DataSource dataSource) throws SQLException { SampleDataGenerator sampleDataGenerator = new SampleDataGenerator(dataSource); sampleDataGenerator.generateSampleData(); diff --git a/rest/taskana-rest-spring-example/src/main/java/pro/taskana/rest/JobScheduler.java b/rest/taskana-rest-spring-example/src/main/java/pro/taskana/rest/JobScheduler.java new file mode 100644 index 000000000..7d26624e0 --- /dev/null +++ b/rest/taskana-rest-spring-example/src/main/java/pro/taskana/rest/JobScheduler.java @@ -0,0 +1,37 @@ +package pro.taskana.rest; + +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import pro.taskana.TaskanaEngine; +import pro.taskana.impl.BulkOperationResults; +import pro.taskana.impl.JobRunner; +import pro.taskana.impl.util.LoggerUtils; + +/** + * This class invokes the JobRunner periodically to schedule long running jobs. + * + * @author bbr + */ +@Component +public class JobScheduler { + + private static final Logger LOGGER = LoggerFactory.getLogger(JobScheduler.class); + @Autowired + private TaskanaEngine taskanaEngine; + + @Scheduled(fixedRate = 60000) + public void triggerJobs() { + JobRunner runner = new JobRunner(taskanaEngine); + LOGGER.info("Running Jobs"); + BulkOperationResults result = runner.runJobs(); + Map errors = result.getErrorMap(); + LOGGER.info("Job run completed. Result = {} ", LoggerUtils.mapToString(errors)); + } + +}