All Downloads are FREE. Search and download functionalities are using the official Maven repository.

poussecafe.doc.DomainProcessStepsFactory Maven / Gradle / Ivy

The newest version!
package poussecafe.doc;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import poussecafe.discovery.DefaultProcess;
import poussecafe.doc.model.DocumentationItem;
import poussecafe.doc.model.Domain;
import poussecafe.doc.model.DomainProcessGraphNodes;
import poussecafe.doc.model.MessageListener;
import poussecafe.doc.model.MessageListenersPerEvent;
import poussecafe.doc.model.domainprocessdoc.DomainProcessGraphNode;
import poussecafe.doc.model.domainprocessdoc.DomainProcessGraphNodeName;
import poussecafe.doc.model.domainprocessdoc.ToStep;
import poussecafe.doc.model.processstepdoc.NameRequired;
import poussecafe.doc.model.processstepdoc.StepMethodSignature;
import poussecafe.source.analysis.ClassName;
import poussecafe.source.model.Documentation;

import static java.util.stream.Collectors.toList;

public class DomainProcessStepsFactory {

    public static DomainProcessGraphNodes buildDomainProcessGraphNodes(DocumentationItem domainProcessDoc, Domain domain) {
        DomainProcessGraphNodes.Builder stepsBuilder = new DomainProcessGraphNodes.Builder();

        var moduleComponentDoc = domainProcessDoc;
        var moduleDocId = moduleComponentDoc.moduleName();
        String processName = moduleComponentDoc.name();

        List listeners = domain.listeners(moduleDocId, processName);
        MessageListenersPerEvent eventToConsumingStepsMap = buildConsumingStepsPerEvent(listeners);

        Set otherProcesses = new HashSet<>();
        for(MessageListener listener : listeners) {
            var currentStepToSteps = new ArrayList();

            var toInternals = eventToConsumingStepsMap.locateToInternals(listener);
            currentStepToSteps.addAll(toDirectSteps(toInternals));

            var toExternals = locateToExternals(listener);
            stepsBuilder.merge(toExternalStepsMap(toExternals));
            currentStepToSteps.addAll(toExternals);

            var toDomainProcesses = locateToDomainProcesses(domainProcessDoc, listener, domain);
            otherProcesses.addAll(toDomainProcesses.stream().map(ToStep::name).collect(toList()));
            stepsBuilder.merge(toExternalStepsMap(toDomainProcesses));
            currentStepToSteps.addAll(toDomainProcesses);

            var processStepComponentDoc = listener.documentation();
            var currentStep = new DomainProcessGraphNode.Builder()
                    .componentDoc(processStepComponentDoc)
                    .tos(currentStepToSteps)
                    .build();
            stepsBuilder.add(currentStep);

            DomainProcessGraphNodeName currentStepName = new DomainProcessGraphNodeName(processStepComponentDoc.name());
            ToStep toCurrentStep = directStep(currentStepName);

            List fromExternals = locateFromExternals(listener);
            stepsBuilder.merge(fromExternalStepsMap(fromExternals, toCurrentStep));

            List fromDomainProcesses = fromDomainProcesses(domainProcessDoc, listener, domain);
            otherProcesses.addAll(fromDomainProcesses);
            stepsBuilder.merge(fromExternalStepsMap(fromDomainProcesses, toCurrentStep));
        }

        Map interprocessSteps = buildInterprocessSteps(moduleDocId, otherProcesses, domain);
        stepsBuilder.merge(interprocessSteps);

        return stepsBuilder.build();
    }

    private static List locateFromExternals(MessageListener processStepDoc) {
        return processStepDoc.fromExternals().stream().map(DomainProcessGraphNodeName::new).collect(toList());
    }

    private static Map fromExternalStepsMap(List fromExternals, ToStep toCurrentStep) {
        Map fromExternalSteps = new HashMap<>();
        for(DomainProcessGraphNodeName fromExternal : fromExternals) {
            var fromExternalStep = new DomainProcessGraphNode.Builder()
                    .componentDoc(new DocumentationItem.Builder()
                            .id("from" + fromExternal)
                            .name(fromExternal.stringValue())
                            .description(Documentation.empty())
                            .build())
                    .external(true)
                    .to(toCurrentStep)
                    .build();
            fromExternalSteps.put(fromExternalStep.stepName(), fromExternalStep);
        }
        return fromExternalSteps;
    }

    private static Map toExternalStepsMap(Collection externalStepsNames) {
        Map steps = new HashMap<>();
        for(ToStep externalToStep : externalStepsNames) {
            DomainProcessGraphNodeName externalStepName = externalToStep.name();
            steps.computeIfAbsent(externalStepName, key -> new DomainProcessGraphNode.Builder()
                    .componentDoc(new DocumentationItem.Builder()
                            .id("to" + externalStepName)
                            .name(externalStepName.stringValue())
                            .description(Documentation.empty())
                            .build())
                    .external(true)
                    .build());
        }
        return steps;
    }

    private static MessageListenersPerEvent buildConsumingStepsPerEvent(List processStepDocs) {
        var builder = new MessageListenersPerEvent.Builder();
        for(MessageListener processStepDoc : processStepDocs) {
            builder.withMessageListener(processStepDoc);
        }
        return builder.build();
    }

    private static List toDirectSteps(Collection tos) {
        List toSteps = new ArrayList<>();
        for(DomainProcessGraphNodeName to : tos) {
            toSteps.add(directStep(to));
        }
        return toSteps;
    }

    private static ToStep directStep(DomainProcessGraphNodeName to) {
        return new ToStep.Builder()
                .name(to)
                .directly(true)
                .build();
    }

    private static Set locateToExternals(MessageListener processStepDoc) {
        Set toExternals = new HashSet<>();
        toExternals.addAll(processStepDoc.toExternals().stream().map(DomainProcessGraphNodeName::new).map(DomainProcessStepsFactory::directStep).collect(toList()));
        for(Entry> entry : processStepDoc.toExternalsByEvent().entrySet()) {
            boolean required = entry.getKey().required();
            toExternals.addAll(entry.getValue().stream().map(name -> toStep(name, required)).collect(toList()));
        }
        return toExternals;
    }

    private static ToStep toStep(String name, boolean required) {
        return new ToStep.Builder()
                .name(new DomainProcessGraphNodeName(name))
                .directly(required)
                .build();
    }

    private static List locateToDomainProcesses(
            DocumentationItem processDoc,
            MessageListener listener,
            Domain domain) {
        Set producedEvents = listener.producedEvents();
        String domainProcessName = processDoc.name();
        String moduleDocId = processDoc.moduleName();
        Set toDomainProcesses = new HashSet<>();
        for(NameRequired producedEvent : producedEvents) {
            for(MessageListener nextListener : domain.findConsuming(moduleDocId, producedEvent.name())) {
                Set processNames = nextListener.processNames();
                for(String processName : processNames) {
                    if(!processName.equals(domainProcessName)) {
                        toDomainProcesses.add(new ToStep.Builder()
                                .name(new DomainProcessGraphNodeName(processName))
                                .directly(producedEvent.required())
                                .build());
                    }
                }
            }
        }
        return toDomainProcesses.stream().collect(toList());
    }

    private static List fromDomainProcesses(
            DocumentationItem domainProcessDoc,
            MessageListener processStepDoc,
            Domain domain) {
        Optional stepMethodSignature = processStepDoc.stepMethodSignature();
        Optional consumedEvent = Optional.empty();
        if(stepMethodSignature.isPresent()) {
            consumedEvent = stepMethodSignature.get().consumedEventName();
        }
        String domainProcessName = domainProcessDoc.name();
        Set otherDomainProcesses = new HashSet<>();
        if(consumedEvent.isPresent()) {
            String moduleDocId = domainProcessDoc.moduleName();
            List stepsProducingEvent = domain.findProducing(moduleDocId, consumedEvent.get());
            for(MessageListener stepDoc : stepsProducingEvent) {
                Set processNames = stepDoc.processNames();
                for(String processName : processNames) {
                    if(!processName.equals(domainProcessName)) {
                        otherDomainProcesses.add(processName);
                    }
                }
            }
        }
        return otherDomainProcesses.stream()
                .map(DomainProcessGraphNodeName::new)
                .collect(toList());
    }

    private static Map buildInterprocessSteps(
            String moduleName,
            Set otherProcesses,
            Domain domain) {
        Map interprocessSteps = new HashMap<>();
        List otherProcessesList = new ArrayList<>(otherProcesses);
        Map> producedEventsPerProcess = new HashMap<>();
        Map> consumedEventsPerProcess = new HashMap<>();
        for(int i = 0; i < otherProcessesList.size(); ++i) {
            var processName1 = otherProcessesList.get(i);
            var process1ClassName = processClassName(moduleName, domain, processName1);
            var producedEventsOf1 = producedEventsPerProcess.computeIfAbsent(processName1, name -> producedEventsOfProcess(moduleName, name, domain));
            var consumedEventsOf1 = consumedEventsPerProcess.computeIfAbsent(processName1, name -> consumedEventsOfProcess(moduleName, name, domain));
            for(int j = i + 1; j < otherProcessesList.size(); ++j) {
                var processName2 = otherProcessesList.get(j);
                var process2ClassName = processClassName(moduleName, domain, processName2);
                var producedEventsOf2 = producedEventsPerProcess.computeIfAbsent(processName2, name -> producedEventsOfProcess(moduleName, name, domain));
                var consumedEventsOf2 = consumedEventsPerProcess.computeIfAbsent(processName2, name -> consumedEventsOfProcess(moduleName, name, domain));

                Set producedBy1AndConsumedBy2 = intersect(producedEventsOf1, consumedEventsOf2);
                if(!producedBy1AndConsumedBy2.isEmpty()) {
                    interprocessSteps.put(processName1, new DomainProcessGraphNode.Builder()
                            .componentDoc(new DocumentationItem.Builder()
                                    .id(processName1 + "_" + processName2)
                                    .className(process1ClassName)
                                    .name(processName1.stringValue())
                                    .description(Documentation.empty())
                                    .moduleName(moduleName)
                                    .build())
                            .to(directStep(processName2))
                            .build());
                }

                Set producedBy2AndConsumedBy1 = intersect(producedEventsOf2, consumedEventsOf1);
                if(!producedBy2AndConsumedBy1.isEmpty()) {
                    interprocessSteps.put(processName2, new DomainProcessGraphNode.Builder()
                            .componentDoc(new DocumentationItem.Builder()
                                    .id(processName2 + "_" + processName1)
                                    .className(process2ClassName)
                                    .name(processName2.stringValue())
                                    .description(Documentation.empty())
                                    .moduleName(moduleName)
                                    .build())
                            .to(directStep(processName1))
                            .build());
                }
            }
        }
        return interprocessSteps;
    }

    private static Optional processClassName(String moduleName, Domain domain, DomainProcessGraphNodeName processName) {
        if(processName.stringValue().equals(DefaultProcess.class.getSimpleName())) {
            return Optional.empty();
        } else {
            return domain.module(moduleName).orElseThrow().processes().stream()
                    .filter(process -> process.name().equals(processName.stringValue()))
                    .findFirst()
                    .map(DocumentationItem::className)
                    .orElse(Optional.empty());
        }
    }

    private static Set producedEventsOfProcess(
            String moduleDocId,
            DomainProcessGraphNodeName processName,
            Domain domain) {
        Set producedEvents = new HashSet<>();
        List processStepDocs = domain.listeners(moduleDocId, processName.stringValue());
        for(MessageListener stepDoc : processStepDocs) {
            producedEvents.addAll(stepDoc.producedEvents().stream().map(NameRequired::name).collect(toList()));
        }
        return producedEvents;
    }

    private static Set consumedEventsOfProcess(String moduleDocId, DomainProcessGraphNodeName processName, Domain domain) {
        Set consumedEvents = new HashSet<>();
        List processStepDocs = domain.listeners(moduleDocId, processName.stringValue());
        for(MessageListener stepDoc : processStepDocs) {
            Optional signature = stepDoc.stepMethodSignature();
            if(signature.isPresent()) {
                Optional consumedEvent = signature.get().consumedEventName();
                if(consumedEvent.isPresent()) {
                    consumedEvents.add(consumedEvent.get());
                }
            }
        }
        return consumedEvents;
    }

    private static Set intersect(Set set1, Set set2) {
        Set intersection = new HashSet<>(set1);
        intersection.retainAll(set2);
        return intersection;
    }

    private DomainProcessStepsFactory() {

    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy