TSK-314 Recalculate due timestamp and prio when a classification is updated

This commit is contained in:
BerndBreier 2018-03-19 14:44:02 +01:00 committed by Holger Hagen
parent 439390adee
commit 4bc7b6bad1
32 changed files with 857 additions and 104 deletions

View File

@ -14,6 +14,15 @@ public interface ClassificationQuery extends BaseQuery<ClassificationSummary> {
*/
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.
*

View File

@ -107,6 +107,15 @@ public interface TaskQuery extends BaseQuery<TaskSummary> {
*/
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.
*

View File

@ -97,4 +97,17 @@ public class BulkOperationResults<K, V> {
public void clearErrors() {
this.errorMap.clear();
}
/**
* Add all errors from another BulkOperationResult to this.
*
* @param log
* the other log
*/
public void addAllErrors(BulkOperationResults<K, V> log) {
List<K> failedIds = log.getFailedIds();
for (K id : failedIds) {
addError(id, log.getErrorForId(id));
}
}
}

View File

@ -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=");

View File

@ -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<TaskSummary> taskSumamries = taskanaEngine.getTaskService()
.createTaskQuery()
.classificationKeyIn(oldClassification.getKey())
.classificationCategoryIn(oldClassification.getCategory())
.classificationIdIn(oldClassification.getId())
// .classificationCategoryIn(oldClassification.getCategory())
.list();
if (!taskSumamries.isEmpty()) {
List<String> 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<String, String> 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<AttachmentSummaryImpl> 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<String> domains = this.classificationMapper.getDomainsForClassification(classificationKey);

View File

@ -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<String, String> 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<String, String> getArguments() {
return arguments;
}
public void setArguments(Map<String, String> 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
}
}

View File

@ -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<String, Exception> runJobs() {
LOGGER.info("entry to runJobs()");
BulkOperationResults<String, Exception> bulkLog = new BulkOperationResults<>();
try {
taskanaEngine.openConnection();
List<Job> jobs = jobMapper.findJobsToRun();
for (Job job : jobs) {
BulkOperationResults<String, Exception> log = runSingleJob(job);
bulkLog.addAllErrors(log);
}
return bulkLog;
} finally {
taskanaEngine.returnConnection();
LOGGER.info("exit from runJobs(). Returning result {} ", bulkLog);
}
}
private BulkOperationResults<String, Exception> runSingleJob(Job job) {
LOGGER.debug("entry to runSingleJob(job = {})", job);
BulkOperationResults<String, Exception> 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;
}
}

View File

@ -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<String, Exception> runSingleJob(Job job, TaskanaEngineImpl taskanaEngine);
}

View File

@ -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=");

View File

@ -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<ClassificationSummary> 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<ClassificationSummary> findClassificationsForTasksAndAttachments(
@ -763,53 +757,40 @@ public class TaskServiceImpl implements TaskService {
return new ArrayList<>();
}
Set<String> classificationDomainSet = taskSummaries.stream().map(TaskSummaryImpl::getDomain).collect(
Set<String> 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<String> classificationKeySet = taskSummaries.stream()
.map(t -> t.getClassificationSummary().getKey())
.collect(Collectors.toSet());
if (attachmentSummaries != null && !attachmentSummaries.isEmpty()) {
Set<String> 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<ClassificationSummary> findClassificationForTaskImplAndAttachments(TaskImpl task,
List<AttachmentImpl> attachmentImpls) throws NotAuthorizedException {
Set<String> classificationDomainSet = new HashSet<>(Arrays.asList(task.getDomain(), ""));
Set<String> classificationKeySet = new HashSet<>(Arrays.asList(task.getClassificationKey()));
Set<String> classificationIdSet = new HashSet<>(Arrays.asList(task.getClassificationSummary().getId()));
if (attachmentImpls != null && !attachmentImpls.isEmpty()) {
Set<String> 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<ClassificationSummary> queryClassificationsForTasksAndAttachments(Set<String> classificationDomainSet,
Set<String> classificationKeySet) throws NotAuthorizedException {
private List<ClassificationSummary> queryClassificationsForTasksAndAttachments(Set<String> 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<String> workbasketKeySet = taskSummaries.stream().map(t -> t.getWorkbasketSummary().getKey()).collect(
Set<String> 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<WorkbasketSummary> workbaskets = query
.keyIn(workbasketKeyArray)
.idIn(workbasketIdArray)
.list();
// assign query results to appropriate tasks.
Iterator<TaskSummaryImpl> 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<Attachment> 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<Attachment> 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<String, Exception> classificationChanged(String taskId, String classificationId)
throws TaskNotFoundException, NotAuthorizedException, ClassificationNotFoundException {
LOGGER.debug("entry to classificationChanged(taskId = {} , classificationId = {} )", taskId, classificationId);
TaskImpl task = null;
BulkOperationResults<String, Exception> bulkLog = new BulkOperationResults<>();
try {
taskanaEngine.openConnection();
if (taskId == null || taskId.isEmpty() || classificationId == null || classificationId.isEmpty()) {
return bulkLog;
}
task = taskMapper.findById(taskId);
List<AttachmentImpl> attachmentImpls = attachmentMapper.findAttachmentsByTaskId(task.getId());
if (attachmentImpls == null) {
attachmentImpls = new ArrayList<>();
}
List<Attachment> 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<Attachment> augmentAttachmentsByClassification(List<AttachmentImpl> attachmentImpls,
BulkOperationResults<String, Exception> bulkLog) {
List<Attachment> result = new ArrayList<>();
if (attachmentImpls == null || attachmentImpls.isEmpty()) {
return result;
}
Set<String> classificationIds = attachmentImpls.stream().map(t -> t.getClassificationSummary().getId()).collect(
Collectors.toSet());
List<ClassificationSummary> 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;
}
}

View File

@ -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<String, Exception> 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<String, String> args = job.getArguments();
classificationId = args.get(CLASSIFICATION_ID);
priorityChanged = Boolean.getBoolean(args.get(PRIORITY_CHANGED));
serviceLevelChanged = Boolean.getBoolean(args.get(SERVICE_LEVEL_CHANGED));
BulkOperationResults<String, Exception> bulkLog = new BulkOperationResults<>();
bulkLog.addAllErrors(handleAffectedTasks());
return bulkLog;
}
private BulkOperationResults<String, Exception> handleAffectedTasks() {
List<TaskSummaryImpl> tasks = taskMapper.findTasksAffectedByClassificationChange(classificationId);
List<String> taskIdsFromAttachments = attachmentMapper
.findTaskIdsAffectedByClassificationChange(classificationId);
List<String> filteredTaskIdsFromAttachments = taskMapper.filterTaskIdsForNotCompleted(taskIdsFromAttachments);
Set<String> 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<String, Exception> bulkLog = new BulkOperationResults<>();
for (String taskId : affectedTaskIds) {
try {
bulkLog.addAllErrors(taskService.classificationChanged(taskId, classificationId));
} catch (Exception e) {
bulkLog.addError(taskId, e);
}
}
return bulkLog;
}
}

View File

@ -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);

View File

@ -93,6 +93,24 @@ public interface AttachmentMapper {
})
List<AttachmentSummaryImpl> findAttachmentSummariesByTaskIds(String[] taskIds);
@Select("<script>SELECT ID, TASK_ID, CREATED, MODIFIED, CLASSIFICATION_KEY, CLASSIFICATION_ID, RECEIVED "
+ "FROM ATTACHMENT "
+ "<where>"
+ "CLASSIFICATION_ID = #{classificationId}"
+ "</where>"
+ "</script>")
@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<AttachmentSummaryImpl> 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("<script> SELECT DISTINCT TASK_ID FROM ATTACHMENT WHERE CLASSIFICATION_ID = #{classificationId} "
+ "<if test=\"_databaseId == 'db2'\">with UR </if> "
+ "</script>")
@Results(value = {
@Result(property = "taskId", column = "TASK_ID")})
List<String> findTaskIdsAffectedByClassificationChange(@Param("classificationId") String classificationId);
}

View File

@ -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<Job> 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);
}

View File

@ -27,7 +27,7 @@ public interface QueryMapper {
String CLASSIFICATION_FINDBYID = "pro.taskana.mappings.ClassificationMapper.findById";
String WORKBASKET_FINDSUMMARYBYKEY = "pro.taskana.mappings.WorkbasketMapper.findSummaryByKey";
@Select("<script>SELECT t.ID, t.CREATED, t.CLAIMED, t.COMPLETED, t.MODIFIED, t.PLANNED, t.DUE, t.NAME, t.CREATOR, t.DESCRIPTION, t.NOTE, t.PRIORITY, t.STATE, t.CLASSIFICATION_KEY, t.CLASSIFICATION_CATEGORY, t.DOMAIN, t.WORKBASKET_KEY, t.BUSINESS_PROCESS_ID, t.PARENT_BUSINESS_PROCESS_ID, t.OWNER, t.POR_COMPANY, t.POR_SYSTEM, t.POR_INSTANCE, t.POR_TYPE, t.POR_VALUE, t.IS_READ, t.IS_TRANSFERRED, t.CUSTOM_1, t.CUSTOM_2, t.CUSTOM_3, t.CUSTOM_4, t.CUSTOM_5, t.CUSTOM_6, t.CUSTOM_7, t.CUSTOM_8, t.CUSTOM_9, t.CUSTOM_10 "
@Select("<script>SELECT t.ID, t.CREATED, t.CLAIMED, t.COMPLETED, t.MODIFIED, t.PLANNED, t.DUE, t.NAME, t.CREATOR, t.DESCRIPTION, t.NOTE, t.PRIORITY, t.STATE, t.CLASSIFICATION_KEY, t.CLASSIFICATION_CATEGORY, t.CLASSIFICATION_ID, t.WORKBASKET_ID, t.DOMAIN, t.WORKBASKET_KEY, t.BUSINESS_PROCESS_ID, t.PARENT_BUSINESS_PROCESS_ID, t.OWNER, t.POR_COMPANY, t.POR_SYSTEM, t.POR_INSTANCE, t.POR_TYPE, t.POR_VALUE, t.IS_READ, t.IS_TRANSFERRED, t.CUSTOM_1, t.CUSTOM_2, t.CUSTOM_3, t.CUSTOM_4, t.CUSTOM_5, t.CUSTOM_6, t.CUSTOM_7, t.CUSTOM_8, t.CUSTOM_9, t.CUSTOM_10 "
+ "FROM TASK t "
+ "<where>"
+ "<if test='taskIds != null'>AND t.ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>)</if> "
@ -49,6 +49,7 @@ public interface QueryMapper {
+ "<if test='workbasketKeyDomainIn != null'>AND (<foreach item='item' collection='workbasketKeyDomainIn' separator=' OR '>(t.WORKBASKET_KEY = #{item.key} AND t.DOMAIN = #{item.domain})</foreach>)</if> "
+ "<if test='classificationKeyIn != null'>AND t.CLASSIFICATION_KEY IN(<foreach item='item' collection='classificationKeyIn' separator=',' >#{item}</foreach>)</if> "
+ "<if test='classificationKeyLike != null'>AND (<foreach item='item' collection='classificationKeyLike' separator=' OR '>UPPER(t.CLASSIFICATION_KEY) LIKE #{item}</foreach>)</if> "
+ "<if test='classificationIdIn != null'>AND t.CLASSIFICATION_ID IN(<foreach item='item' collection='classificationIdIn' separator=',' >#{item}</foreach>)</if> "
+ "<if test='classificationCategoryIn != null'>AND t.CLASSIFICATION_CATEGORY IN(<foreach item='item' collection='classificationCategoryIn' separator=',' >#{item}</foreach>)</if> "
+ "<if test='classificationCategoryLike != null'>AND (<foreach item='item' collection='classificationCategoryLike' separator=' OR '>UPPER(t.CLASSIFICATION_CATEGORY) LIKE #{item}</foreach>)</if> "
+ "<if test='ownerIn != null'>AND t.OWNER IN(<foreach item='item' collection='ownerIn' separator=',' >#{item}</foreach>)</if> "
@ -119,7 +120,9 @@ public interface QueryMapper {
@Result(property = "state", column = "STATE"),
@Result(property = "workbasketSummaryImpl.domain", column = "DOMAIN"),
@Result(property = "workbasketSummaryImpl.key", column = "WORKBASKET_KEY"),
@Result(property = "workbasketSummaryImpl.id", column = "WORKBASKET_ID"),
@Result(property = "classificationSummaryImpl.key", column = "CLASSIFICATION_KEY"),
@Result(property = "classificationSummaryImpl.id", column = "CLASSIFICATION_ID"),
@Result(property = "classificationSummaryImpl.domain", column = "DOMAIN"),
@Result(property = "classificationSummaryImpl.category", column = "CLASSIFICATION_CATEGORY"),
@Result(property = "businessProcessId", column = "BUSINESS_PROCESS_ID"),
@ -154,6 +157,7 @@ public interface QueryMapper {
+ "FROM CLASSIFICATION "
+ "<where>"
+ "<if test='key != null'>AND KEY IN(<foreach item='item' collection='key' separator=',' >#{item}</foreach>)</if> "
+ "<if test='idIn != null'>AND ID IN(<foreach item='item' collection='idIn' separator=',' >#{item}</foreach>)</if> "
+ "<if test='parentId != null'>AND PARENT_ID IN(<foreach item='item' collection='parentId' separator=',' >#{item}</foreach>)</if> "
+ "<if test='category != null'>AND CATEGORY IN(<foreach item='item' collection='category' separator=',' >#{item}</foreach>)</if> "
+ "<if test='type != null'>AND TYPE IN(<foreach item='item' collection='type' separator=',' >#{item}</foreach>)</if> "
@ -364,6 +368,7 @@ public interface QueryMapper {
+ "<if test='workbasketKeyDomainIn != null'>AND (<foreach item='item' collection='workbasketKeyDomainIn' separator=' OR '>(t.WORKBASKET_KEY = #{item.key} AND t.DOMAIN = #{item.domain})</foreach>)</if> "
+ "<if test='classificationKeyIn != null'>AND t.CLASSIFICATION_KEY IN(<foreach item='item' collection='classificationKeyIn' separator=',' >#{item}</foreach>)</if> "
+ "<if test='classificationKeyLike != null'>AND (<foreach item='item' collection='classificationKeyLike' separator=' OR '>UPPER(t.CLASSIFICATION_KEY) LIKE #{item}</foreach>)</if> "
+ "<if test='classificationIdIn != null'>AND t.CLASSIFICATION_ID IN(<foreach item='item' collection='classificationIdIn' separator=',' >#{item}</foreach>)</if> "
+ "<if test='classificationCategoryIn != null'>AND t.CLASSIFICATION_CATEGORY IN(<foreach item='item' collection='classificationCategoryIn' separator=',' >#{item}</foreach>)</if> "
+ "<if test='classificationCategoryLike != null'>AND (<foreach item='item' collection='classificationCategoryLike' separator=' OR '>UPPER(t.CLASSIFICATION_CATEGORY) LIKE #{item}</foreach>)</if> "
+ "<if test='ownerIn != null'>AND t.OWNER IN(<foreach item='item' collection='ownerIn' separator=',' >#{item}</foreach>)</if> "
@ -425,6 +430,7 @@ public interface QueryMapper {
@Select("<script>SELECT COUNT(ID) FROM CLASSIFICATION "
+ "<where>"
+ "<if test='key != null'>AND KEY IN(<foreach item='item' collection='key' separator=',' >#{item}</foreach>)</if> "
+ "<if test='idIn != null'>AND ID IN(<foreach item='item' collection='idIn' separator=',' >#{item}</foreach>)</if> "
+ "<if test='parentId != null'>AND PARENT_ID IN(<foreach item='item' collection='parentId' separator=',' >#{item}</foreach>)</if> "
+ "<if test='category != null'>AND CATEGORY IN(<foreach item='item' collection='category' separator=',' >#{item}</foreach>)</if> "
+ "<if test='type != null'>AND TYPE IN(<foreach item='item' collection='type' separator=',' >#{item}</foreach>)</if> "
@ -577,6 +583,7 @@ public interface QueryMapper {
+ "<if test='workbasketKeyDomainIn != null'>AND (<foreach item='item' collection='workbasketKeyDomainIn' separator=' OR '>(t.WORKBASKET_KEY = #{item.key} AND t.DOMAIN = #{item.domain})</foreach>)</if> "
+ "<if test='classificationKeyIn != null'>AND t.CLASSIFICATION_KEY IN(<foreach item='item' collection='classificationKeyIn' separator=',' >#{item}</foreach>)</if> "
+ "<if test='classificationKeyLike != null'>AND (<foreach item='item' collection='classificationKeyLike' separator=' OR '>UPPER(t.CLASSIFICATION_KEY) LIKE #{item}</foreach>)</if> "
+ "<if test='classificationIdIn != null'>AND t.CLASSIFICATION_ID IN(<foreach item='item' collection='classificationIdIn' separator=',' >#{item}</foreach>)</if> "
+ "<if test='classificationCategoryIn != null'>AND t.CLASSIFICATION_CATEGORY IN(<foreach item='item' collection='classificationCategoryIn' separator=',' >#{item}</foreach>)</if> "
+ "<if test='classificationCategoryLike != null'>AND (<foreach item='item' collection='classificationCategoryLike' separator=' OR '>UPPER(t.CLASSIFICATION_CATEGORY) LIKE #{item}</foreach>)</if> "
+ "<if test='ownerIn != null'>AND t.OWNER IN(<foreach item='item' collection='ownerIn' separator=',' >#{item}</foreach>)</if> "
@ -639,6 +646,7 @@ public interface QueryMapper {
+ "FROM CLASSIFICATION"
+ "<where>"
+ "<if test='key != null'>AND KEY IN(<foreach item='item' collection='key' separator=',' >#{item}</foreach>)</if> "
+ "<if test='idIn != null'>AND ID IN(<foreach item='item' collection='idIn' separator=',' >#{item}</foreach>)</if> "
+ "<if test='parentId != null'>AND PARENT_ID IN(<foreach item='item' collection='parentId' separator=',' >#{item}</foreach>)</if> "
+ "<if test='category != null'>AND CATEGORY IN(<foreach item='item' collection='category' separator=',' >#{item}</foreach>)</if> "
+ "<if test='type != null'>AND TYPE IN(<foreach item='item' collection='type' separator=',' >#{item}</foreach>)</if> "

View File

@ -166,6 +166,61 @@ public interface TaskMapper {
List<TaskSummaryImpl> findTasksByWorkbasketIdAndState(@Param("workbasketKey") String workbasketKey,
@Param("taskState") TaskState taskState);
@Select("<script>SELECT ID, CREATED, CLAIMED, COMPLETED, MODIFIED, PLANNED, DUE, NAME, CREATOR, DESCRIPTION, PRIORITY, STATE, CLASSIFICATION_CATEGORY, CLASSIFICATION_KEY, CLASSIFICATION_ID, WORKBASKET_ID, WORKBASKET_KEY, DOMAIN, BUSINESS_PROCESS_ID, PARENT_BUSINESS_PROCESS_ID, OWNER, POR_COMPANY, POR_SYSTEM, POR_INSTANCE, POR_TYPE, POR_VALUE, IS_READ, IS_TRANSFERRED, CUSTOM_ATTRIBUTES, CUSTOM_1, CUSTOM_2, CUSTOM_3, CUSTOM_4, CUSTOM_5, CUSTOM_6, CUSTOM_7, "
+ "CUSTOM_8, CUSTOM_9, CUSTOM_10, CUSTOM_11, CUSTOM_12, CUSTOM_13, CUSTOM_14, CUSTOM_15, CUSTOM_16 "
+ "FROM TASK "
+ "WHERE CLASSIFICATION_ID = #{classificationId} "
+ "AND STATE IN ( 'READY','CLAIMED') "
+ "<if test=\"_databaseId == 'db2'\">with UR </if> "
+ "</script>")
@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<TaskSummaryImpl> findTasksAffectedByClassificationChange(@Param("classificationId") String classificationId);
@Update("<script>"
+ " UPDATE TASK SET MODIFIED = #{referencetask.modified}, STATE = #{referencetask.state}, WORKBASKET_KEY = #{referencetask.workbasketSummary.key}, WORKBASKET_ID= #{referencetask.workbasketSummary.id}, "
+ " DOMAIN = #{referencetask.domain}, OWNER = #{referencetask.owner}, IS_READ = #{referencetask.isRead}, IS_TRANSFERRED = #{referencetask.isTransferred}"
@ -221,4 +276,13 @@ public interface TaskMapper {
void updateTasks(@Param("taskIds") List<String> taskIds, @Param("task") TaskImpl task,
@Param("fields") CustomPropertySelector fields);
@Select("<script>SELECT ID, STATE FROM TASK "
+ "WHERE ID IN(<foreach item='item' collection='taskIds' separator=',' >#{item}</foreach>) "
+ "AND STATE IN ( 'READY','CLAIMED') "
+ "<if test=\"_databaseId == 'db2'\">with UR </if> "
+ "</script>")
@Results(value = {
@Result(property = "taskId", column = "ID")})
List<String> filterTaskIdsForNotCompleted(@Param("taskIds") List<String> taskIds);
}

View File

@ -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;

View File

@ -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;

View File

@ -94,7 +94,7 @@ public class QueryClassificationAccTest extends AbstractAccTest {
.list();
assertNotNull(classifications);
assertEquals(23, classifications.size());
assertEquals(25, classifications.size());
List<ClassificationSummary> 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

View File

@ -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));
}
}

View File

@ -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<String> 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))));
}
}
}
}

View File

@ -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());
}
}

View File

@ -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(

View File

@ -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();

View File

@ -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<ClassificationSummaryImpl> 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<WorkbasketSummary> 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;
}

View File

@ -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<String> listValues(String dbColumnName, SortDirection sortDirection) {
return new ArrayList<>();
}
}

View File

@ -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);

View File

@ -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', '', '', '', '', '', '', '');

View File

@ -5,4 +5,5 @@ DELETE FROM CLASSIFICATION;
DELETE FROM WORKBASKET_ACCESS_LIST;
DELETE FROM OBJECT_REFERENCE;
DELETE FROM ATTACHMENT;
DELETE FROM JOB;
COMMIT;

View File

@ -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;

View File

@ -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();

View File

@ -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<String, Exception> result = runner.runJobs();
Map<String, Exception> errors = result.getErrorMap();
LOGGER.info("Job run completed. Result = {} ", LoggerUtils.mapToString(errors));
}
}