Search in sources :

Example 1 with TaskExecutor

use of io.lumeer.core.task.TaskExecutor in project engine by Lumeer.

the class SingleStage method commitOperations.

public ChangesTracker commitOperations() {
    if (operations.isEmpty()) {
        return new ChangesTracker();
    }
    @SuppressWarnings("rawtypes") final List<Operation> invalidOperations = operations.stream().filter(operation -> !operation.isComplete()).collect(toList());
    if (invalidOperations.size() > 0) {
        final StringBuilder sb = new StringBuilder();
        invalidOperations.forEach(operation -> sb.append("Invalid update request: ").append(operation.toString()).append("\n"));
        throw new IllegalArgumentException(sb.toString());
    }
    // first create all new documents
    final List<Document> createdDocuments = createDocuments(operations.stream().filter(operation -> operation instanceof DocumentCreationOperation && operation.isComplete()).map(operation -> (DocumentCreationOperation) operation).collect(toList()));
    final Map<String, List<Document>> toBeRemovedDocumentsByCollection = Utils.categorize(operations.stream().filter(operation -> operation instanceof DocumentRemovalOperation && operation.isComplete()).map(operation -> ((DocumentRemovalOperation) operation).getEntity()), Document::getCollectionId);
    // get data structures for efficient manipulation with the new documents
    final Map<String, List<Document>> documentsByCollection = DocumentUtils.getDocumentsByCollection(createdDocuments);
    final List<String> usedCollections = new ArrayList<>(documentsByCollection.keySet());
    usedCollections.addAll(toBeRemovedDocumentsByCollection.keySet());
    final Map<String, Collection> collectionsMap = task.getDaoContextSnapshot().getCollectionDao().getCollectionsByIds(usedCollections).stream().collect(Collectors.toMap(Collection::getId, Function.identity()));
    final Map<String, String> correlationIdsToIds = createdDocuments.stream().collect(Collectors.toMap(doc -> doc.createIfAbsentMetaData().getString(Document.META_CORRELATION_ID), Document::getId));
    // report new empty documents, later updates are sent separately
    changesTracker.addCreatedDocuments(createdDocuments);
    changesTracker.addCollections(collectionsMap.values().stream().filter(c -> documentsByCollection.containsKey(c.getId())).collect(toSet()));
    // map the newly create document IDs to all other changes so that we use the correct document in updates etc.
    operations.stream().filter(operation -> operation instanceof DocumentOperation).forEach(operation -> {
        final Document doc = (Document) operation.getEntity();
        if (StringUtils.isEmpty(doc.getId()) && StringUtils.isNotEmpty(doc.createIfAbsentMetaData().getString(Document.META_CORRELATION_ID))) {
            doc.setId(correlationIdsToIds.get(doc.getMetaData().getString(Document.META_CORRELATION_ID)));
        }
    });
    operations.stream().filter(operation -> operation instanceof LinkCreationOperation).forEach(operation -> {
        final LinkInstance link = ((LinkCreationOperation) operation).getEntity();
        if (StringUtils.isEmpty(link.getId()) && StringUtils.isNotEmpty(link.getTemplateId())) {
            link.setDocumentIds(List.of(correlationIdsToIds.containsKey(link.getDocumentIds().get(0)) ? correlationIdsToIds.get(link.getDocumentIds().get(0)) : link.getDocumentIds().get(0), correlationIdsToIds.containsKey(link.getDocumentIds().get(1)) ? correlationIdsToIds.get(link.getDocumentIds().get(1)) : link.getDocumentIds().get(1)));
        }
    });
    // commit document changes
    final List<Document> changedDocuments = commitDocumentOperations(operations.stream().filter(operation -> operation instanceof DocumentOperation && operation.isComplete()).map(operation -> (DocumentOperation) operation).collect(toList()), createdDocuments, collectionsMap);
    // remove documents
    final List<Document> removedDocuments = removeDocuments(operations.stream().filter(operation -> operation instanceof DocumentRemovalOperation).map(operation -> (DocumentRemovalOperation) operation).collect(toList()));
    changesTracker.addRemovedDocuments(removedDocuments);
    // remove created documents that were deleted later
    final Set<Document> unusedCreatedDocuments = new HashSet<>(changesTracker.getRemovedDocuments());
    unusedCreatedDocuments.retainAll(changesTracker.getCreatedDocuments());
    changesTracker.getCreatedDocuments().removeAll(unusedCreatedDocuments);
    // create new links
    final List<LinkCreationOperation> linkCreationOperations = operations.stream().filter(operation -> operation instanceof LinkCreationOperation && operation.isComplete()).map(operation -> (LinkCreationOperation) operation).collect(toList());
    final List<LinkInstance> createdLinks = createLinks(linkCreationOperations);
    final Map<String, List<LinkInstance>> linksByType = LinkTypeUtils.getLinksByType(createdLinks);
    final Map<String, LinkType> linkTypesMap = task.getDaoContextSnapshot().getLinkTypeDao().getLinkTypesByIds(linksByType.keySet()).stream().collect(Collectors.toMap(LinkType::getId, Function.identity()));
    final Map<String, String> linkCorrelationIdsToIds = createdLinks.stream().collect(Collectors.toMap(LinkInstance::getTemplateId, LinkInstance::getId));
    // report new empty links, later updates are sent separately
    changesTracker.addCreatedLinkInstances(createdLinks);
    changesTracker.addLinkTypes(linkTypesMap.values().stream().filter(c -> linksByType.containsKey(c.getId())).collect(toSet()));
    // map the newly create link IDs to all other changes so that we use the correct document in updates etc.
    operations.stream().filter(operation -> operation instanceof LinkOperation).forEach(operation -> {
        final LinkInstance link = (LinkInstance) operation.getEntity();
        if (StringUtils.isEmpty(link.getId()) && StringUtils.isNotEmpty(link.getTemplateId())) {
            link.setId(linkCorrelationIdsToIds.get(link.getTemplateId()));
        }
    });
    // commit link changes
    final List<LinkInstance> changedLinkInstances = commitLinkOperations(taskExecutor, operations.stream().filter(operation -> operation instanceof LinkOperation && operation.isComplete()).map(operation -> (LinkOperation) operation).collect(toList()), createdLinks, linkTypesMap);
    // report user messages, print, navigate, and send email requests for rules triggered via an Action button
    final String correlationId = task.getAppId() != null ? task.getAppId().getValue() : null;
    if (StringUtils.isNotEmpty(correlationId)) {
        final List<UserMessageRequest> userMessageRequests = operations.stream().filter(operation -> operation instanceof UserMessageOperation).map(operation -> ((UserMessageOperation) operation).getEntity()).collect(toList());
        changesTracker.addUserMessageRequests(userMessageRequests);
        List<GenericPrintRequest> printRequests = operations.stream().filter(operation -> operation instanceof PrintAttributeOperation).map(operation -> ((PrintAttributeOperation) operation).getEntity()).collect(toList());
        changesTracker.addPrintRequests(printRequests);
        printRequests = operations.stream().filter(operation -> operation instanceof PrintTextOperation).map(operation -> ((PrintTextOperation) operation).getEntity()).collect(toList());
        changesTracker.addPrintRequests(printRequests);
        final List<NavigationRequest> navigationRequests = operations.stream().filter(operation -> operation instanceof NavigationOperation).map(operation -> ((NavigationOperation) operation).getEntity()).collect(toList());
        changesTracker.addNavigationRequests(navigationRequests);
        final List<SendEmailRequest> sendEmailRequests = operations.stream().filter(operation -> operation instanceof SendEmailOperation).map(operation -> ((SendEmailOperation) operation).getEntity()).collect(toList());
        changesTracker.addSendEmailRequests(sendEmailRequests);
    }
    // propagate changes in existing documents and links that has been loaded prior to calling this rule
    task.propagateChanges(changedDocuments, changedLinkInstances);
    return changesTracker;
}
Also used : TaskExecutor(io.lumeer.core.task.TaskExecutor) PrintTextOperation(io.lumeer.core.task.executor.operation.PrintTextOperation) ZonedDateTime(java.time.ZonedDateTime) Operation(io.lumeer.core.task.executor.operation.Operation) StringUtils(org.apache.commons.lang3.StringUtils) CreateLinkInstance(io.lumeer.engine.api.event.CreateLinkInstance) UserMessageOperation(io.lumeer.core.task.executor.operation.UserMessageOperation) GenericPrintRequest(io.lumeer.core.task.executor.request.GenericPrintRequest) ResourceType(io.lumeer.api.model.ResourceType) Map(java.util.Map) FunctionTask(io.lumeer.core.task.FunctionTask) FunctionFacade(io.lumeer.core.facade.FunctionFacade) DocumentOperation(io.lumeer.core.task.executor.operation.DocumentOperation) DataDocument(io.lumeer.engine.api.data.DataDocument) Document(io.lumeer.api.model.Document) CreateDocument(io.lumeer.engine.api.event.CreateDocument) Set(java.util.Set) Collectors(java.util.stream.Collectors) LinkInstance(io.lumeer.api.model.LinkInstance) PurposeChangeProcessor(io.lumeer.core.facade.detector.PurposeChangeProcessor) LinkType(io.lumeer.api.model.LinkType) PrintAttributeOperation(io.lumeer.core.task.executor.operation.PrintAttributeOperation) List(java.util.List) SendEmailOperation(io.lumeer.core.task.executor.operation.SendEmailOperation) Optional(java.util.Optional) Utils(io.lumeer.core.util.Utils) ChangesTracker(io.lumeer.core.task.executor.ChangesTracker) LinkOperation(io.lumeer.core.task.executor.operation.LinkOperation) DocumentCreationOperation(io.lumeer.core.task.executor.operation.DocumentCreationOperation) SendEmailRequest(io.lumeer.core.task.executor.request.SendEmailRequest) HashMap(java.util.HashMap) Function(java.util.function.Function) ArrayList(java.util.ArrayList) NavigationOperation(io.lumeer.core.task.executor.operation.NavigationOperation) HashSet(java.util.HashSet) TaskProcessingFacade(io.lumeer.core.facade.TaskProcessingFacade) LinkCreationOperation(io.lumeer.core.task.executor.operation.LinkCreationOperation) DocumentRemovalOperation(io.lumeer.core.task.executor.operation.DocumentRemovalOperation) LinkTypeUtils(io.lumeer.core.util.LinkTypeUtils) CollectionPurposeType(io.lumeer.api.model.CollectionPurposeType) UserMessageRequest(io.lumeer.core.task.executor.request.UserMessageRequest) NavigationRequest(io.lumeer.core.task.executor.request.NavigationRequest) LinkTypeAdapter(io.lumeer.core.adapter.LinkTypeAdapter) DocumentUtils(io.lumeer.core.util.DocumentUtils) UpdateLinkInstance(io.lumeer.engine.api.event.UpdateLinkInstance) RuleTask(io.lumeer.core.task.RuleTask) OperationExecutor(io.lumeer.core.task.executor.operation.OperationExecutor) UpdateDocument(io.lumeer.engine.api.event.UpdateDocument) AutoLinkBatchTask(io.lumeer.core.task.AutoLinkBatchTask) Collection(io.lumeer.api.model.Collection) ArrayList(java.util.ArrayList) PrintAttributeOperation(io.lumeer.core.task.executor.operation.PrintAttributeOperation) PrintTextOperation(io.lumeer.core.task.executor.operation.PrintTextOperation) Operation(io.lumeer.core.task.executor.operation.Operation) UserMessageOperation(io.lumeer.core.task.executor.operation.UserMessageOperation) DocumentOperation(io.lumeer.core.task.executor.operation.DocumentOperation) PrintAttributeOperation(io.lumeer.core.task.executor.operation.PrintAttributeOperation) SendEmailOperation(io.lumeer.core.task.executor.operation.SendEmailOperation) LinkOperation(io.lumeer.core.task.executor.operation.LinkOperation) DocumentCreationOperation(io.lumeer.core.task.executor.operation.DocumentCreationOperation) NavigationOperation(io.lumeer.core.task.executor.operation.NavigationOperation) LinkCreationOperation(io.lumeer.core.task.executor.operation.LinkCreationOperation) DocumentRemovalOperation(io.lumeer.core.task.executor.operation.DocumentRemovalOperation) DataDocument(io.lumeer.engine.api.data.DataDocument) Document(io.lumeer.api.model.Document) CreateDocument(io.lumeer.engine.api.event.CreateDocument) UpdateDocument(io.lumeer.engine.api.event.UpdateDocument) DocumentCreationOperation(io.lumeer.core.task.executor.operation.DocumentCreationOperation) DocumentRemovalOperation(io.lumeer.core.task.executor.operation.DocumentRemovalOperation) SendEmailOperation(io.lumeer.core.task.executor.operation.SendEmailOperation) List(java.util.List) ArrayList(java.util.ArrayList) GenericPrintRequest(io.lumeer.core.task.executor.request.GenericPrintRequest) HashSet(java.util.HashSet) PrintTextOperation(io.lumeer.core.task.executor.operation.PrintTextOperation) SendEmailRequest(io.lumeer.core.task.executor.request.SendEmailRequest) DocumentOperation(io.lumeer.core.task.executor.operation.DocumentOperation) NavigationRequest(io.lumeer.core.task.executor.request.NavigationRequest) UserMessageOperation(io.lumeer.core.task.executor.operation.UserMessageOperation) CreateLinkInstance(io.lumeer.engine.api.event.CreateLinkInstance) LinkInstance(io.lumeer.api.model.LinkInstance) UpdateLinkInstance(io.lumeer.engine.api.event.UpdateLinkInstance) LinkOperation(io.lumeer.core.task.executor.operation.LinkOperation) LinkCreationOperation(io.lumeer.core.task.executor.operation.LinkCreationOperation) NavigationOperation(io.lumeer.core.task.executor.operation.NavigationOperation) ChangesTracker(io.lumeer.core.task.executor.ChangesTracker) Collection(io.lumeer.api.model.Collection) LinkType(io.lumeer.api.model.LinkType) UserMessageRequest(io.lumeer.core.task.executor.request.UserMessageRequest)

Example 2 with TaskExecutor

use of io.lumeer.core.task.TaskExecutor in project engine by Lumeer.

the class AutoLinkRuleTaskExecutor method addLinks.

private void addLinks(final TaskExecutor taskExecutor, final List<LinkInstance> links, final DocumentMatcher matcher) {
    final String thisCollection = matcher.getThisCollection().getId();
    if (thisCollection.equals(matcher.getThatCollection().getId())) {
        return;
    }
    final String thisDocumentId = matcher.getThisDocument().getId();
    final Set<String> alreadyLinkedDocumentIds = links.stream().map(link -> {
        final var res = new ArrayList<>(link.getDocumentIds());
        res.remove(thisDocumentId);
        return res.get(0);
    }).collect(toSet());
    final Tuple<List<Document>, List<LinkInstance>> newLinks = matcher.filterForCreation();
    final Set<String> targetDocuments = newLinks.getFirst().stream().map(Document::getId).filter(id -> !alreadyLinkedDocumentIds.contains(id)).collect(toSet());
    if (targetDocuments.size() > 0) {
        final List<LinkInstance> linkInstances = targetDocuments.stream().filter(documentId -> !documentId.equals(matcher.getNewDocument().getId())).map(documentId -> {
            var l = new LinkInstance(rule.getLinkType(), Arrays.asList(matcher.getNewDocument().getId(), documentId));
            l.setCreatedBy(ruleTask.getInitiator().getId());
            l.setCreationDate(ZonedDateTime.now());
            return l;
        }).collect(toList());
        if (!linkInstances.isEmpty()) {
            ruleTask.getDaoContextSnapshot().getLinkInstanceDao().createLinkInstances(linkInstances);
            changesTracker.updateLinkTypesMap(Map.of(matcher.getLinkType().getId(), matcher.getLinkType()));
            changesTracker.addCreatedLinkInstances(linkInstances);
            linkInstances.forEach(link -> {
                var decodedCreatedData = constraintManager.decodeDataTypes(matcher.getLinkType(), link.getData());
                auditAdapter.registerCreate(link.getLinkTypeId(), ResourceType.LINK, link.getId(), ruleTask.getInitiator(), ruleName, null, decodedCreatedData);
            });
            final FunctionFacade functionFacade = ruleTask.getFunctionFacade();
            linkInstances.forEach(linkInstance -> {
                taskExecutor.submitTask(functionFacade.createTaskForCreatedLinks(matcher.getLinkType(), Collections.singletonList(linkInstance)));
            });
        }
    }
}
Also used : Tuple(io.lumeer.core.util.Tuple) DocumentMatcher(io.lumeer.core.task.executor.matcher.DocumentMatcher) Arrays(java.util.Arrays) TaskExecutor(io.lumeer.core.task.TaskExecutor) ZonedDateTime(java.time.ZonedDateTime) Document(io.lumeer.api.model.Document) Set(java.util.Set) AutoLinkRule(io.lumeer.api.model.rule.AutoLinkRule) Logger(java.util.logging.Logger) AuditAdapter(io.lumeer.core.adapter.AuditAdapter) StringUtils(org.apache.commons.lang3.StringUtils) LinkInstance(io.lumeer.api.model.LinkInstance) ArrayList(java.util.ArrayList) Level(java.util.logging.Level) Collectors.toList(java.util.stream.Collectors.toList) DefaultConfigurationProducer(io.lumeer.core.facade.configuration.DefaultConfigurationProducer) List(java.util.List) ResourceType(io.lumeer.api.model.ResourceType) RuleTask(io.lumeer.core.task.RuleTask) Map(java.util.Map) Collections(java.util.Collections) Collectors.toSet(java.util.stream.Collectors.toSet) ConstraintManager(io.lumeer.core.constraint.ConstraintManager) FunctionFacade(io.lumeer.core.facade.FunctionFacade) ArrayList(java.util.ArrayList) Collectors.toList(java.util.stream.Collectors.toList) List(java.util.List) LinkInstance(io.lumeer.api.model.LinkInstance) Document(io.lumeer.api.model.Document) FunctionFacade(io.lumeer.core.facade.FunctionFacade)

Example 3 with TaskExecutor

use of io.lumeer.core.task.TaskExecutor 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());
}
Also used : TaskExecutor(io.lumeer.core.task.TaskExecutor) PrintTextOperation(io.lumeer.core.task.executor.operation.PrintTextOperation) ZonedDateTime(java.time.ZonedDateTime) Operation(io.lumeer.core.task.executor.operation.Operation) StringUtils(org.apache.commons.lang3.StringUtils) CreateLinkInstance(io.lumeer.engine.api.event.CreateLinkInstance) UserMessageOperation(io.lumeer.core.task.executor.operation.UserMessageOperation) GenericPrintRequest(io.lumeer.core.task.executor.request.GenericPrintRequest) ResourceType(io.lumeer.api.model.ResourceType) Map(java.util.Map) FunctionTask(io.lumeer.core.task.FunctionTask) FunctionFacade(io.lumeer.core.facade.FunctionFacade) DocumentOperation(io.lumeer.core.task.executor.operation.DocumentOperation) DataDocument(io.lumeer.engine.api.data.DataDocument) Document(io.lumeer.api.model.Document) CreateDocument(io.lumeer.engine.api.event.CreateDocument) Set(java.util.Set) Collectors(java.util.stream.Collectors) LinkInstance(io.lumeer.api.model.LinkInstance) PurposeChangeProcessor(io.lumeer.core.facade.detector.PurposeChangeProcessor) LinkType(io.lumeer.api.model.LinkType) PrintAttributeOperation(io.lumeer.core.task.executor.operation.PrintAttributeOperation) List(java.util.List) SendEmailOperation(io.lumeer.core.task.executor.operation.SendEmailOperation) Optional(java.util.Optional) Utils(io.lumeer.core.util.Utils) ChangesTracker(io.lumeer.core.task.executor.ChangesTracker) LinkOperation(io.lumeer.core.task.executor.operation.LinkOperation) DocumentCreationOperation(io.lumeer.core.task.executor.operation.DocumentCreationOperation) SendEmailRequest(io.lumeer.core.task.executor.request.SendEmailRequest) HashMap(java.util.HashMap) Function(java.util.function.Function) ArrayList(java.util.ArrayList) NavigationOperation(io.lumeer.core.task.executor.operation.NavigationOperation) HashSet(java.util.HashSet) TaskProcessingFacade(io.lumeer.core.facade.TaskProcessingFacade) LinkCreationOperation(io.lumeer.core.task.executor.operation.LinkCreationOperation) DocumentRemovalOperation(io.lumeer.core.task.executor.operation.DocumentRemovalOperation) LinkTypeUtils(io.lumeer.core.util.LinkTypeUtils) CollectionPurposeType(io.lumeer.api.model.CollectionPurposeType) UserMessageRequest(io.lumeer.core.task.executor.request.UserMessageRequest) NavigationRequest(io.lumeer.core.task.executor.request.NavigationRequest) LinkTypeAdapter(io.lumeer.core.adapter.LinkTypeAdapter) DocumentUtils(io.lumeer.core.util.DocumentUtils) UpdateLinkInstance(io.lumeer.engine.api.event.UpdateLinkInstance) RuleTask(io.lumeer.core.task.RuleTask) OperationExecutor(io.lumeer.core.task.executor.operation.OperationExecutor) UpdateDocument(io.lumeer.engine.api.event.UpdateDocument) AutoLinkBatchTask(io.lumeer.core.task.AutoLinkBatchTask) Collection(io.lumeer.api.model.Collection) DataDocument(io.lumeer.engine.api.data.DataDocument) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) UpdateLinkInstance(io.lumeer.engine.api.event.UpdateLinkInstance) List(java.util.List) ArrayList(java.util.ArrayList) RuleTask(io.lumeer.core.task.RuleTask) FunctionFacade(io.lumeer.core.facade.FunctionFacade) TaskProcessingFacade(io.lumeer.core.facade.TaskProcessingFacade) HashSet(java.util.HashSet) FunctionTask(io.lumeer.core.task.FunctionTask) CreateLinkInstance(io.lumeer.engine.api.event.CreateLinkInstance) LinkInstance(io.lumeer.api.model.LinkInstance) UpdateLinkInstance(io.lumeer.engine.api.event.UpdateLinkInstance) CreateLinkInstance(io.lumeer.engine.api.event.CreateLinkInstance) Collection(io.lumeer.api.model.Collection) LinkType(io.lumeer.api.model.LinkType)

Example 4 with TaskExecutor

use of io.lumeer.core.task.TaskExecutor in project engine by Lumeer.

the class SingleStage method commitDocumentOperations.

private List<Document> commitDocumentOperations(final List<DocumentOperation> operations, final List<Document> createdDocuments, final Map<String, Collection> collectionsMapForCreatedDocuments) {
    if (operations.isEmpty() && collectionsMapForCreatedDocuments.isEmpty()) {
        return List.of();
    }
    final FunctionFacade functionFacade = task.getFunctionFacade();
    final TaskProcessingFacade taskProcessingFacade = task.getTaskProcessingFacade(taskExecutor, functionFacade);
    final PurposeChangeProcessor purposeChangeProcessor = task.getPurposeChangeProcessor();
    // Collection -> [Document]
    final Map<String, List<Document>> updatedDocuments = new HashMap<>();
    Map<String, Set<String>> documentIdsByCollection = operations.stream().map(Operation::getEntity).collect(Collectors.groupingBy(Document::getCollectionId, mapping(Document::getId, toSet())));
    final Map<String, Collection> collectionsMap = task.getDaoContextSnapshot().getCollectionDao().getCollectionsByIds(documentIdsByCollection.keySet()).stream().collect(Collectors.toMap(Collection::getId, coll -> coll));
    final Set<String> collectionsChanged = new HashSet<>();
    Map<String, Document> documentsByCorrelationId = createdDocuments.stream().collect(Collectors.toMap(doc -> doc.createIfAbsentMetaData().getString(Document.META_CORRELATION_ID), Function.identity()));
    // aggregate all operations to individual documents
    final Map<String, List<DocumentOperation>> changesByDocumentId = Utils.categorize(operations.stream(), change -> change.getEntity().getId());
    final Set<String> unprocessedCreatedDocuments = createdDocuments.stream().map(Document::getId).collect(toSet());
    createdDocuments.forEach(document -> {
        final Collection collection = collectionsMap.get(document.getCollectionId());
        final DataDocument newDataDecoded = constraintManager.encodeDataTypes(collection, document.getData());
        auditAdapter.registerCreate(collection.getId(), ResourceType.DOCUMENT, document.getId(), task.getInitiator(), automationName, null, newDataDecoded);
    });
    changesByDocumentId.forEach((id, changeList) -> {
        unprocessedCreatedDocuments.remove(id);
        final Document document = changeList.get(0).getEntity();
        final Document originalDocument = (task instanceof RuleTask) ? ((RuleTask) task).getOldDocument() : ((task instanceof FunctionTask) ? ((FunctionTask) task).getOriginalDocumentOrDefault(id, changeList.get(0).getOriginalDocument()) : changeList.get(0).getOriginalDocument());
        final Collection collection = collectionsMap.get(document.getCollectionId());
        final DataDocument aggregatedUpdate = new DataDocument();
        changeList.forEach(change -> aggregatedUpdate.put(change.getAttrId(), change.getValue()));
        final DataDocument newData = constraintManager.encodeDataTypes(collection, aggregatedUpdate);
        final DataDocument oldData = originalDocument != null ? new DataDocument(originalDocument.getData()) : new DataDocument();
        Set<String> attributesIdsToAdd = new HashSet<>(newData.keySet());
        attributesIdsToAdd.removeAll(oldData.keySet());
        if (attributesIdsToAdd.size() > 0) {
            collection.getAttributes().stream().filter(attr -> attributesIdsToAdd.contains(attr.getId())).forEach(attr -> {
                attr.setUsageCount(attr.getUsageCount() + 1);
                collection.setLastTimeUsed(ZonedDateTime.now());
                collectionsChanged.add(collection.getId());
            });
        }
        document.setUpdatedBy(task.getInitiator().getId());
        document.setUpdateDate(ZonedDateTime.now());
        final DataDocument beforePatch = task.getDaoContextSnapshot().getDataDao().getData(document.getCollectionId(), document.getId());
        DataDocument patchedData = task.getDaoContextSnapshot().getDataDao().patchData(document.getCollectionId(), document.getId(), newData);
        Document updatedDocument = task.getDaoContextSnapshot().getDocumentDao().updateDocument(document.getId(), document);
        updatedDocument.setData(patchedData);
        // notify delayed actions about data change
        if (collection.getPurposeType() == CollectionPurposeType.Tasks) {
            final Document original;
            if (originalDocument == null) {
                // when triggered by an action button, let's use the document from db
                original = new Document(document);
                original.setData(beforePatch);
            } else {
                original = originalDocument;
            }
            purposeChangeProcessor.processChanges(new UpdateDocument(updatedDocument, original), collection);
        }
        var oldDataDecoded = constraintManager.decodeDataTypes(collection, beforePatch);
        var patchedDataDecoded = constraintManager.decodeDataTypes(collection, patchedData);
        auditAdapter.registerDataChange(updatedDocument.getCollectionId(), ResourceType.DOCUMENT, updatedDocument.getId(), task.getInitiator(), automationName, null, beforePatch, oldDataDecoded, patchedData, patchedDataDecoded);
        // add patched data to new documents
        boolean created = false;
        if (StringUtils.isNotEmpty(document.createIfAbsentMetaData().getString(Document.META_CORRELATION_ID))) {
            final Document doc = documentsByCorrelationId.get(document.getMetaData().getString(Document.META_CORRELATION_ID));
            if (doc != null) {
                doc.setData(patchedData);
                created = true;
            }
        }
        if (task instanceof RuleTask) {
            if (created) {
                taskProcessingFacade.onCreateDocument(new CreateDocument(updatedDocument));
            } 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 UpdateDocument updateDocumentEvent;
                    final Document orig = new Document(document);
                    orig.setData(beforePatch);
                    updateDocumentEvent = new UpdateDocument(updatedDocument, orig);
                    taskProcessingFacade.onDocumentUpdate(updateDocumentEvent, ((RuleTask) task).getRule().getName());
                } else {
                    taskExecutor.submitTask(functionFacade.createTaskForUpdateDocument(collection, originalDocument, updatedDocument, aggregatedUpdate.keySet()));
                }
            }
        }
        patchedData = constraintManager.decodeDataTypes(collection, patchedData);
        updatedDocument.setData(patchedData);
        updatedDocuments.computeIfAbsent(document.getCollectionId(), key -> new ArrayList<>()).add(updatedDocument);
    });
    unprocessedCreatedDocuments.forEach(id -> {
        createdDocuments.stream().filter(d -> d.getId().equals(id)).findFirst().ifPresent(document -> {
            taskProcessingFacade.onCreateDocument(new CreateDocument(document));
        });
    });
    changesTracker.addCollections(collectionsChanged.stream().map(collectionsMap::get).collect(toSet()));
    changesTracker.addUpdatedDocuments(updatedDocuments.values().stream().flatMap(java.util.Collection::stream).collect(toSet()));
    changesTracker.updateCollectionsMap(collectionsMapForCreatedDocuments);
    changesTracker.updateCollectionsMap(collectionsMap);
    collectionsChanged.forEach(collectionId -> task.getDaoContextSnapshot().getCollectionDao().updateCollection(collectionId, collectionsMap.get(collectionId), null, false));
    return updatedDocuments.values().stream().flatMap(java.util.Collection::stream).collect(toList());
}
Also used : TaskExecutor(io.lumeer.core.task.TaskExecutor) PrintTextOperation(io.lumeer.core.task.executor.operation.PrintTextOperation) ZonedDateTime(java.time.ZonedDateTime) Operation(io.lumeer.core.task.executor.operation.Operation) StringUtils(org.apache.commons.lang3.StringUtils) CreateLinkInstance(io.lumeer.engine.api.event.CreateLinkInstance) UserMessageOperation(io.lumeer.core.task.executor.operation.UserMessageOperation) GenericPrintRequest(io.lumeer.core.task.executor.request.GenericPrintRequest) ResourceType(io.lumeer.api.model.ResourceType) Map(java.util.Map) FunctionTask(io.lumeer.core.task.FunctionTask) FunctionFacade(io.lumeer.core.facade.FunctionFacade) DocumentOperation(io.lumeer.core.task.executor.operation.DocumentOperation) DataDocument(io.lumeer.engine.api.data.DataDocument) Document(io.lumeer.api.model.Document) CreateDocument(io.lumeer.engine.api.event.CreateDocument) Set(java.util.Set) Collectors(java.util.stream.Collectors) LinkInstance(io.lumeer.api.model.LinkInstance) PurposeChangeProcessor(io.lumeer.core.facade.detector.PurposeChangeProcessor) LinkType(io.lumeer.api.model.LinkType) PrintAttributeOperation(io.lumeer.core.task.executor.operation.PrintAttributeOperation) List(java.util.List) SendEmailOperation(io.lumeer.core.task.executor.operation.SendEmailOperation) Optional(java.util.Optional) Utils(io.lumeer.core.util.Utils) ChangesTracker(io.lumeer.core.task.executor.ChangesTracker) LinkOperation(io.lumeer.core.task.executor.operation.LinkOperation) DocumentCreationOperation(io.lumeer.core.task.executor.operation.DocumentCreationOperation) SendEmailRequest(io.lumeer.core.task.executor.request.SendEmailRequest) HashMap(java.util.HashMap) Function(java.util.function.Function) ArrayList(java.util.ArrayList) NavigationOperation(io.lumeer.core.task.executor.operation.NavigationOperation) HashSet(java.util.HashSet) TaskProcessingFacade(io.lumeer.core.facade.TaskProcessingFacade) LinkCreationOperation(io.lumeer.core.task.executor.operation.LinkCreationOperation) DocumentRemovalOperation(io.lumeer.core.task.executor.operation.DocumentRemovalOperation) LinkTypeUtils(io.lumeer.core.util.LinkTypeUtils) CollectionPurposeType(io.lumeer.api.model.CollectionPurposeType) UserMessageRequest(io.lumeer.core.task.executor.request.UserMessageRequest) NavigationRequest(io.lumeer.core.task.executor.request.NavigationRequest) LinkTypeAdapter(io.lumeer.core.adapter.LinkTypeAdapter) DocumentUtils(io.lumeer.core.util.DocumentUtils) UpdateLinkInstance(io.lumeer.engine.api.event.UpdateLinkInstance) RuleTask(io.lumeer.core.task.RuleTask) OperationExecutor(io.lumeer.core.task.executor.operation.OperationExecutor) UpdateDocument(io.lumeer.engine.api.event.UpdateDocument) AutoLinkBatchTask(io.lumeer.core.task.AutoLinkBatchTask) Collection(io.lumeer.api.model.Collection) DataDocument(io.lumeer.engine.api.data.DataDocument) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) DataDocument(io.lumeer.engine.api.data.DataDocument) Document(io.lumeer.api.model.Document) CreateDocument(io.lumeer.engine.api.event.CreateDocument) UpdateDocument(io.lumeer.engine.api.event.UpdateDocument) List(java.util.List) ArrayList(java.util.ArrayList) RuleTask(io.lumeer.core.task.RuleTask) FunctionFacade(io.lumeer.core.facade.FunctionFacade) TaskProcessingFacade(io.lumeer.core.facade.TaskProcessingFacade) HashSet(java.util.HashSet) UpdateDocument(io.lumeer.engine.api.event.UpdateDocument) FunctionTask(io.lumeer.core.task.FunctionTask) CreateDocument(io.lumeer.engine.api.event.CreateDocument) Collection(io.lumeer.api.model.Collection) PurposeChangeProcessor(io.lumeer.core.facade.detector.PurposeChangeProcessor)

Aggregations

Document (io.lumeer.api.model.Document)4 LinkInstance (io.lumeer.api.model.LinkInstance)4 ResourceType (io.lumeer.api.model.ResourceType)4 FunctionFacade (io.lumeer.core.facade.FunctionFacade)4 RuleTask (io.lumeer.core.task.RuleTask)4 TaskExecutor (io.lumeer.core.task.TaskExecutor)4 ZonedDateTime (java.time.ZonedDateTime)4 Collection (io.lumeer.api.model.Collection)3 CollectionPurposeType (io.lumeer.api.model.CollectionPurposeType)3 LinkType (io.lumeer.api.model.LinkType)3 LinkTypeAdapter (io.lumeer.core.adapter.LinkTypeAdapter)3 TaskProcessingFacade (io.lumeer.core.facade.TaskProcessingFacade)3 PurposeChangeProcessor (io.lumeer.core.facade.detector.PurposeChangeProcessor)3 AutoLinkBatchTask (io.lumeer.core.task.AutoLinkBatchTask)3 FunctionTask (io.lumeer.core.task.FunctionTask)3 ChangesTracker (io.lumeer.core.task.executor.ChangesTracker)3 DocumentCreationOperation (io.lumeer.core.task.executor.operation.DocumentCreationOperation)3 DocumentOperation (io.lumeer.core.task.executor.operation.DocumentOperation)3 DocumentRemovalOperation (io.lumeer.core.task.executor.operation.DocumentRemovalOperation)3 LinkCreationOperation (io.lumeer.core.task.executor.operation.LinkCreationOperation)3