use of io.lumeer.engine.api.event.UpdateLinkInstance in project engine by Lumeer.
the class TaskProcessingFacade method onUpdateLink.
public void onUpdateLink(final UpdateLinkInstance updateLinkEvent, final String skipTask) {
LinkType linkType = getLinkTypeForEvent(updateLinkEvent);
if (linkType == null) {
return;
}
FunctionTask functionTask = functionFacade.creatTaskForChangedLink(linkType, new LinkInstance(updateLinkEvent.getOriginalLinkInstance()), new LinkInstance(updateLinkEvent.getLinkInstance()));
List<RuleTask> tasks = createLinkInstanceUpdateRuleTasks(linkType, updateLinkEvent, skipTask);
RuleTask ruleTask = createOrderedRuleTask(tasks);
processTasks(functionTask, ruleTask);
}
use of io.lumeer.engine.api.event.UpdateLinkInstance in project engine by Lumeer.
the class LinkInstanceFacade method updateLinkInstanceData.
public LinkInstance updateLinkInstanceData(final String linkInstanceId, final DataDocument updateData) {
var linkTypeAndInstance = checkEditLink(linkInstanceId);
final LinkType linkType = linkTypeAndInstance.getFirst();
final LinkInstance stored = linkTypeAndInstance.getSecond();
final LinkInstance originalLinkInstance = new LinkInstance(stored);
final DataDocument data = constraintManager.encodeDataTypes(linkType, updateData);
final DataDocument oldData = linkDataDao.getData(linkType.getId(), linkInstanceId);
originalLinkInstance.setData(oldData);
final Set<String> attributesIdsToAdd = new HashSet<>(data.keySet());
attributesIdsToAdd.removeAll(oldData.keySet());
final Set<String> attributesIdsToDec = new HashSet<>(oldData.keySet());
attributesIdsToDec.removeAll(data.keySet());
linkTypeAdapter.updateLinkTypeMetadata(linkType, attributesIdsToAdd, attributesIdsToDec);
final DataDocument updatedData = linkDataDao.updateData(linkType.getId(), linkInstanceId, data);
final LinkInstance updatedLinkInstance = updateLinkInstance(stored, updatedData, originalLinkInstance);
updatedLinkInstance.setData(constraintManager.decodeDataTypes(linkType, updatedData));
return updatedLinkInstance;
}
use of io.lumeer.engine.api.event.UpdateLinkInstance in project engine by Lumeer.
the class SingleStage method commitLinkOperations.
private List<LinkInstance> commitLinkOperations(final TaskExecutor taskExecutor, final List<LinkOperation> changes, final List<LinkInstance> createdLinks, final Map<String, LinkType> linkTypeMapForCreatedLinks) {
if (changes.isEmpty() && linkTypeMapForCreatedLinks.isEmpty()) {
return List.of();
}
final FunctionFacade functionFacade = task.getFunctionFacade();
final TaskProcessingFacade taskProcessingFacade = task.getTaskProcessingFacade(taskExecutor, functionFacade);
// LinkType -> [LinkInstance]
final Map<String, List<LinkInstance>> updatedLinks = new HashMap<>();
final Map<String, LinkType> linkTypesMap = task.getDaoContextSnapshot().getLinkTypeDao().getAllLinkTypes().stream().collect(Collectors.toMap(LinkType::getId, linkType -> linkType));
Set<String> linkTypesChanged = new HashSet<>();
Map<String, LinkInstance> linksByCorrelationId = createdLinks.stream().collect(Collectors.toMap(LinkInstance::getTemplateId, Function.identity()));
// aggregate all changes to individual link instances
final Map<String, List<LinkOperation>> changesByLinkTypeId = Utils.categorize(changes.stream(), change -> change.getEntity().getId());
final Set<String> unprocessedCreatedLinks = createdLinks.stream().map(LinkInstance::getId).collect(toSet());
changesByLinkTypeId.forEach((id, changeList) -> {
unprocessedCreatedLinks.remove(id);
final LinkInstance linkInstance = changeList.get(0).getEntity();
final LinkInstance originalLinkInstance = (task instanceof RuleTask) ? ((RuleTask) task).getOldLinkInstance() : ((task instanceof FunctionTask) ? ((FunctionTask) task).getOriginalLinkInstanceOrDefault(id, changeList.get(0).getOriginalLinkInstance()) : changeList.get(0).getOriginalLinkInstance());
final LinkType linkType = linkTypesMap.get(linkInstance.getLinkTypeId());
final DataDocument aggregatedUpdate = new DataDocument();
changeList.forEach(change -> aggregatedUpdate.put(change.getAttrId(), change.getValue()));
final DataDocument newData = constraintManager.encodeDataTypes(linkType, aggregatedUpdate);
final DataDocument oldData = originalLinkInstance != null ? new DataDocument(originalLinkInstance.getData()) : new DataDocument();
Set<String> attributesIdsToAdd = new HashSet<>(newData.keySet());
attributesIdsToAdd.removeAll(oldData.keySet());
if (attributesIdsToAdd.size() > 0) {
linkType.getAttributes().stream().filter(attr -> attributesIdsToAdd.contains(attr.getId())).forEach(attr -> {
attr.setUsageCount(attr.getUsageCount() + 1);
linkTypesChanged.add(linkType.getId());
});
}
linkInstance.setUpdatedBy(task.getInitiator().getId());
linkInstance.setUpdateDate(ZonedDateTime.now());
final DataDocument beforePatch = task.getDaoContextSnapshot().getLinkDataDao().getData(linkInstance.getLinkTypeId(), linkInstance.getId());
// thanks to an auto-link rule, the link could have ceased to exist
if (task.getDaoContextSnapshot().getLinkInstanceDao().getLinkInstances(Set.of(linkInstance.getId())).size() > 0) {
DataDocument patchedData = task.getDaoContextSnapshot().getLinkDataDao().patchData(linkInstance.getLinkTypeId(), linkInstance.getId(), newData);
LinkInstance updatedLink = task.getDaoContextSnapshot().getLinkInstanceDao().updateLinkInstance(linkInstance.getId(), linkInstance);
updatedLink.setData(patchedData);
var oldDataDecoded = constraintManager.decodeDataTypes(linkType, beforePatch);
var patchedDataDecoded = constraintManager.decodeDataTypes(linkType, patchedData);
auditAdapter.registerDataChange(updatedLink.getLinkTypeId(), ResourceType.LINK, updatedLink.getId(), task.getInitiator(), automationName, null, beforePatch, oldDataDecoded, patchedData, patchedDataDecoded);
// add patched data to new links
boolean created = false;
if (StringUtils.isNotEmpty(linkInstance.getTemplateId())) {
final LinkInstance link = linksByCorrelationId.get(linkInstance.getTemplateId());
if (link != null) {
link.setData(patchedData);
created = true;
}
}
if (task instanceof RuleTask) {
if (created) {
taskProcessingFacade.onCreateLink(new CreateLinkInstance(updatedLink));
} else {
if (task.getRecursionDepth() == 0) {
// there are now 3 versions of the document:
// 1) the document before user triggered an update - original document (null when triggered by action button)
// 2) the document with the new user entered value - before patch
// 3) the document with the value computed by the rule based on the previous two - updated document
// this rule got executed because of change from 1 to 2
// for the recursive rules, we need to trigger rules for changes between 2 and 3
final UpdateLinkInstance updateLinkInstanceEvent;
final LinkInstance orig = new LinkInstance(linkInstance);
orig.setData(beforePatch);
updateLinkInstanceEvent = new UpdateLinkInstance(updatedLink, orig);
taskProcessingFacade.onUpdateLink(updateLinkInstanceEvent, ((RuleTask) task).getRule().getName());
} else {
taskExecutor.submitTask(functionFacade.creatTaskForChangedLink(linkType, originalLinkInstance, updatedLink, aggregatedUpdate.keySet()));
}
}
}
patchedData = constraintManager.decodeDataTypes(linkType, patchedData);
updatedLink.setData(patchedData);
updatedLinks.computeIfAbsent(linkInstance.getLinkTypeId(), key -> new ArrayList<>()).add(updatedLink);
}
});
unprocessedCreatedLinks.forEach(id -> {
createdLinks.stream().filter(l -> l.getId().equals(id)).findFirst().ifPresent(link -> {
taskProcessingFacade.onCreateLink(new CreateLinkInstance(link));
});
});
linkTypeMapForCreatedLinks.forEach((id, linkType) -> linkTypesChanged.add(id));
changesTracker.addLinkTypes(linkTypesChanged.stream().map(linkTypesMap::get).collect(toSet()));
changesTracker.addUpdatedLinkInstances(updatedLinks.values().stream().flatMap(java.util.Collection::stream).collect(toSet()));
changesTracker.updateLinkTypesMap(linkTypeMapForCreatedLinks);
changesTracker.updateLinkTypesMap(linkTypesMap);
linkTypesChanged.forEach(linkTypeId -> task.getDaoContextSnapshot().getLinkTypeDao().updateLinkType(linkTypeId, linkTypesMap.get(linkTypeId), null));
return updatedLinks.values().stream().flatMap(java.util.Collection::stream).collect(toList());
}
use of io.lumeer.engine.api.event.UpdateLinkInstance in project engine by Lumeer.
the class LinkInstanceFacade method patchLinkInstanceData.
public LinkInstance patchLinkInstanceData(final String linkInstanceId, final DataDocument updateData) {
var linkTypeAndInstance = checkEditLink(linkInstanceId);
final LinkType linkType = linkTypeAndInstance.getFirst();
final LinkInstance stored = linkTypeAndInstance.getSecond();
final LinkInstance originalLinkInstance = new LinkInstance(stored);
final DataDocument data = constraintManager.encodeDataTypes(linkType, updateData);
final DataDocument oldData = linkDataDao.getData(linkType.getId(), linkInstanceId);
originalLinkInstance.setData(oldData);
final Set<String> attributesIdsToAdd = new HashSet<>(data.keySet());
attributesIdsToAdd.removeAll(oldData.keySet());
linkTypeAdapter.updateLinkTypeMetadata(linkType, attributesIdsToAdd, Collections.emptySet());
final DataDocument updatedData = linkDataDao.patchData(linkType.getId(), linkInstanceId, data);
final LinkInstance updatedLinkInstance = updateLinkInstance(stored, updatedData, originalLinkInstance);
updatedLinkInstance.setData(constraintManager.decodeDataTypes(linkType, updatedData));
return updatedLinkInstance;
}
use of io.lumeer.engine.api.event.UpdateLinkInstance in project engine by Lumeer.
the class LinkInstanceFacade method fireLinkInstanceUpdate.
private void fireLinkInstanceUpdate(final LinkInstance updatedLinkInstance, final LinkInstance originalLinkInstance) {
if (updateLinkInstanceEvent != null) {
LinkInstance updatedLinkInstanceWithData = new LinkInstance(updatedLinkInstance);
updateLinkInstanceEvent.fire(new UpdateLinkInstance(updatedLinkInstanceWithData, originalLinkInstance));
}
}
Aggregations