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

io.automatiko.engine.codegen.process.ProcessCodegen Maven / Gradle / Ivy

The newest version!

package io.automatiko.engine.codegen.process;

import static io.automatiko.engine.api.io.ResourceType.determineResourceType;
import static io.automatiko.engine.codegen.ApplicationGenerator.log;
import static io.automatiko.engine.services.utils.IoUtils.readBytesFromInputStream;

import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;

import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;

import io.automatiko.engine.api.Functions;
import io.automatiko.engine.api.definition.process.Process;
import io.automatiko.engine.api.definition.process.WorkflowProcess;
import io.automatiko.engine.api.io.Resource;
import io.automatiko.engine.api.io.ResourceType;
import io.automatiko.engine.codegen.AbstractGenerator;
import io.automatiko.engine.codegen.ApplicationGenerator;
import io.automatiko.engine.codegen.ApplicationSection;
import io.automatiko.engine.codegen.CodegenUtils;
import io.automatiko.engine.codegen.ConfigGenerator;
import io.automatiko.engine.codegen.DefaultResourceGeneratorFactory;
import io.automatiko.engine.codegen.GeneratedFile;
import io.automatiko.engine.codegen.GeneratedFile.Type;
import io.automatiko.engine.codegen.ResourceGeneratorFactory;
import io.automatiko.engine.codegen.di.DependencyInjectionAnnotator;
import io.automatiko.engine.codegen.process.config.ProcessConfigGenerator;
import io.automatiko.engine.services.execution.BaseFunctions;
import io.automatiko.engine.services.io.ByteArrayResource;
import io.automatiko.engine.services.io.FileSystemResource;
import io.automatiko.engine.services.io.InternalResource;
import io.automatiko.engine.services.utils.StringUtils;
import io.automatiko.engine.workflow.bpmn2.xml.BPMNDISemanticModule;
import io.automatiko.engine.workflow.bpmn2.xml.BPMNExtensionsSemanticModule;
import io.automatiko.engine.workflow.bpmn2.xml.BPMNSemanticModule;
import io.automatiko.engine.workflow.compiler.canonical.ModelMetaData;
import io.automatiko.engine.workflow.compiler.canonical.OpenAPIMetaData;
import io.automatiko.engine.workflow.compiler.canonical.ProcessMetaData;
import io.automatiko.engine.workflow.compiler.canonical.ProcessToExecModelGenerator;
import io.automatiko.engine.workflow.compiler.canonical.TriggerMetaData;
import io.automatiko.engine.workflow.compiler.canonical.UserTaskModelMetaData;
import io.automatiko.engine.workflow.compiler.xml.SemanticModules;
import io.automatiko.engine.workflow.compiler.xml.XmlProcessReader;
import io.automatiko.engine.workflow.process.core.node.SubProcessNode;
import io.automatiko.engine.workflow.serverless.parser.ServerlessWorkflowParser;

/**
 * Entry point to process code generation
 */
public class ProcessCodegen extends AbstractGenerator {

    private static final Logger LOGGER = LoggerFactory.getLogger(ProcessCodegen.class);

    private static final SemanticModules BPMN_SEMANTIC_MODULES = new SemanticModules();
    public static final Set SUPPORTED_BPMN_EXTENSIONS = Collections
            .unmodifiableSet(new HashSet<>(Arrays.asList(".bpmn", ".bpmn2")));
    private static final String YAML_PARSER = "yml";
    private static final String JSON_PARSER = "json";
    public static final Map SUPPORTED_SW_EXTENSIONS;

    static {
        BPMN_SEMANTIC_MODULES.addSemanticModule(new BPMNSemanticModule());
        BPMN_SEMANTIC_MODULES.addSemanticModule(new BPMNExtensionsSemanticModule());
        BPMN_SEMANTIC_MODULES.addSemanticModule(new BPMNDISemanticModule());

        Map extMap = new HashMap<>();
        extMap.put(".sw.yml", YAML_PARSER);
        extMap.put(".sw.yaml", YAML_PARSER);
        extMap.put(".sw.json", JSON_PARSER);
        SUPPORTED_SW_EXTENSIONS = Collections.unmodifiableMap(extMap);
    }

    private ClassLoader contextClassLoader;
    private ResourceGeneratorFactory resourceGeneratorFactory;

    public static ProcessCodegen ofJar(Path... jarPaths) {
        return ofJar(Collections.emptyList(), Collections.emptyList(), jarPaths);
    }

    public static ProcessCodegen ofJar(List inprocesses, List dependencies, Path... jarPaths) {
        List processes = new ArrayList<>(inprocesses);

        for (Path jarPath : jarPaths) {
            try (ZipFile zipFile = new ZipFile(jarPath.toFile())) {
                Enumeration entries = zipFile.entries();
                while (entries.hasMoreElements()) {
                    ZipEntry entry = entries.nextElement();
                    ResourceType resourceType = determineResourceType(entry.getName());
                    if (SUPPORTED_BPMN_EXTENSIONS.stream().anyMatch(entry.getName()::endsWith)) {
                        InternalResource resource = new ByteArrayResource(
                                readBytesFromInputStream(zipFile.getInputStream(entry)));
                        resource.setResourceType(resourceType);
                        resource.setSourcePath(entry.getName());
                        processes.addAll(parseProcessFile(resource));
                    } else if (SUPPORTED_SW_EXTENSIONS.keySet().stream().anyMatch(entry.getName()::endsWith)) {
                        InternalResource resource = new ByteArrayResource(
                                readBytesFromInputStream(zipFile.getInputStream(entry)));
                        resource.setResourceType(resourceType);
                        resource.setSourcePath(entry.getName());

                        SUPPORTED_SW_EXTENSIONS.entrySet().stream()
                                .filter(e -> entry.getName().endsWith(e.getKey()))
                                .forEach(e -> processes.add(parseWorkflowFile(resource, e.getValue())));

                    }
                }
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }

        for (String dependency : dependencies) {
            try (ZipFile zipFile = new ZipFile(dependency)) {
                Enumeration entries = zipFile.entries();
                while (entries.hasMoreElements()) {
                    ZipEntry entry = entries.nextElement();
                    ResourceType resourceType = determineResourceType(entry.getName());
                    if (SUPPORTED_BPMN_EXTENSIONS.stream().anyMatch(entry.getName()::endsWith)) {
                        InternalResource resource = new ByteArrayResource(
                                readBytesFromInputStream(zipFile.getInputStream(entry)));
                        resource.setResourceType(resourceType);
                        resource.setSourcePath(entry.getName());
                        processes.addAll(parseProcessFile(resource));
                    }
                }
            } catch (IOException e) {

            }
        }

        return ofProcesses(processes);
    }

    public static ProcessCodegen ofPath(Path... paths) throws IOException {

        return ofPath(Collections.emptyList(), Collections.emptyList(), paths);
    }

    public static ProcessCodegen ofPath(List inprocesses, List dependencies, Path... paths)
            throws IOException {

        List allProcesses = new ArrayList<>(inprocesses);

        for (String dependency : dependencies) {
            File file = new File(dependency);

            if (file.isDirectory()) {

                try (Stream filesStream = Files.walk(file.toPath())) {
                    List files = filesStream
                            .filter(p -> SUPPORTED_BPMN_EXTENSIONS.stream().anyMatch(p.toString()::endsWith)
                                    || SUPPORTED_SW_EXTENSIONS.keySet().stream().anyMatch(p.toString()::endsWith))
                            .map(Path::toFile).collect(Collectors.toList());
                    allProcesses.addAll(parseProcesses(files, true));
                }
            } else {

                try (ZipFile zipFile = new ZipFile(dependency)) {
                    Enumeration entries = zipFile.entries();
                    while (entries.hasMoreElements()) {
                        ZipEntry entry = entries.nextElement();
                        ResourceType resourceType = determineResourceType(entry.getName());
                        if (SUPPORTED_BPMN_EXTENSIONS.stream().anyMatch(entry.getName()::endsWith)) {
                            InternalResource resource = new ByteArrayResource(
                                    readBytesFromInputStream(zipFile.getInputStream(entry)));
                            resource.setResourceType(resourceType);
                            resource.setSourcePath(entry.getName());
                            allProcesses.addAll(parseProcessFile(resource));
                        }
                    }
                } catch (IOException e) {

                }
            }
        }

        for (Path path : paths) {
            Path srcPath = Paths.get(path.toString());
            try (Stream filesStream = Files.walk(srcPath)) {
                List files = filesStream
                        .filter(p -> SUPPORTED_BPMN_EXTENSIONS.stream().anyMatch(p.toString()::endsWith)
                                || SUPPORTED_SW_EXTENSIONS.keySet().stream().anyMatch(p.toString()::endsWith))
                        .map(Path::toFile).collect(Collectors.toList());
                allProcesses.addAll(parseProcesses(files, false));
            }
        }
        return ofProcesses(allProcesses);
    }

    public static ProcessCodegen ofFiles(Collection processFiles) {
        List allProcesses = parseProcesses(processFiles, false);
        return ofProcesses(allProcesses);
    }

    public static ProcessCodegen ofFilesAndProcesses(Collection processFiles, List processes) {
        List allProcesses = parseProcesses(processFiles, false);
        allProcesses.addAll(processes);
        return ofProcesses(allProcesses);
    }

    public static ProcessCodegen ofProcesses(List processes) {
        return new ProcessCodegen(processes);
    }

    static List parseProcesses(Collection processFiles, boolean fromDeps) {
        List processes = new ArrayList<>();
        for (File processSourceFile : processFiles) {
            if (!fromDeps && processSourceFile.getAbsolutePath().contains("target" + File.separator + "classes")) {
                // exclude any resources files that come from target folder especially in dev mode which can cause overrides
                continue;
            }
            try {
                FileSystemResource r = new FileSystemResource(processSourceFile);
                if (SUPPORTED_BPMN_EXTENSIONS.stream().anyMatch(processSourceFile.getPath()::endsWith)) {
                    processes.addAll(parseProcessFile(r));
                } else {
                    SUPPORTED_SW_EXTENSIONS.entrySet().stream()
                            .filter(e -> processSourceFile.getPath().endsWith(e.getKey()))
                            .forEach(e -> processes.add(parseWorkflowFile(r, e.getValue())));
                }
                if (processes.isEmpty()) {
                    throw new IllegalArgumentException(
                            "Unable to process file with unsupported extension: " + processSourceFile);
                }
            } catch (RuntimeException e) {
                throw new ProcessCodegenException(processSourceFile.getAbsolutePath(), e);
            }
        }
        return processes;
    }

    private static Process parseWorkflowFile(Resource r, String parser) {
        try {
            ServerlessWorkflowParser workflowParser = new ServerlessWorkflowParser();
            Process p = workflowParser.parse(r.getReader());
            ((WorkflowProcess) p).getMetaData().put("IsServerlessWorkflow", true);
            p.setResource(r);
            return p;
        } catch (IOException e) {
            throw new ProcessParsingException("Could not parse file " + r.getSourcePath(), e);
        }
    }

    private static Collection parseProcessFile(Resource r) {
        try {
            XmlProcessReader xmlReader = new XmlProcessReader(BPMN_SEMANTIC_MODULES,
                    Thread.currentThread().getContextClassLoader());
            Collection parsed = xmlReader.read(r.getReader());
            parsed.forEach(p -> p.setResource(r));
            return parsed;
        } catch (SAXException | IOException e) {
            throw new ProcessParsingException("Could not parse file " + r.getSourcePath(), e);
        }
    }

    private String applicationCanonicalName;
    private DependencyInjectionAnnotator annotator;

    private ProcessesContainerGenerator moduleGenerator;

    private final Map processes;
    private final List generatedFiles = new ArrayList<>();

    private boolean persistence;

    public ProcessCodegen(Collection processes) {
        this.processes = new HashMap<>();
        for (Process process : processes) {
            String version = "";
            if (process.getVersion() != null) {
                version = "_" + process.getVersion();
            }
            this.processes.put(process.getId() + version, (WorkflowProcess) process);
        }

        // set default package name
        setPackageName(ApplicationGenerator.DEFAULT_PACKAGE_NAME);
        contextClassLoader = Thread.currentThread().getContextClassLoader();

        resourceGeneratorFactory = new DefaultResourceGeneratorFactory();
    }

    public static String defaultWorkItemHandlerConfigClass(String packageName) {
        return packageName + ".WorkItemHandlerConfig";
    }

    public static String defaultProcessListenerConfigClass(String packageName) {
        return packageName + ".ProcessEventListenerConfig";
    }

    public void setPackageName(String packageName) {
        this.moduleGenerator = new ProcessesContainerGenerator(packageName);
        this.applicationCanonicalName = packageName + ".Application";
    }

    public void setDependencyInjection(DependencyInjectionAnnotator annotator) {
        this.annotator = annotator;
        this.moduleGenerator.withDependencyInjection(annotator);
    }

    public ProcessesContainerGenerator moduleGenerator() {
        return moduleGenerator;
    }

    public ProcessCodegen withPersistence(boolean persistence) {
        this.persistence = persistence;
        return this;
    }

    public ProcessCodegen withClassLoader(ClassLoader projectClassLoader) {
        this.contextClassLoader = projectClassLoader;
        return this;
    }

    public List generate() {
        if (processes.isEmpty()) {
            return Collections.emptyList();
        }

        List ps = new ArrayList<>();
        List pis = new ArrayList<>();
        List processExecutableModelGenerators = new ArrayList<>();
        List rgs = new ArrayList<>(); // REST resources
        List grapggs = new ArrayList<>(); // GraphQL resources
        List fgs = new ArrayList<>(); // Function resources
        List ffgs = new ArrayList<>(); // Function flow resources
        List mdegs = new ArrayList<>(); // message data events
        Set megs = new LinkedHashSet<>(); // message endpoints/consumers
        List mpgs = new ArrayList<>(); // message producers
        Set opgs = new LinkedHashSet<>(); // OpenAPI clients

        List publicProcesses = new ArrayList<>();

        Map processIdToModel = new HashMap<>();

        Map processIdToModelGenerator = new HashMap<>();
        Map processIdToInputModelGenerator = new HashMap<>();
        Map processIdToOutputModelGenerator = new HashMap<>();

        Map> processIdToUserTaskModel = new HashMap<>();
        Map processIdToMetadata = new HashMap<>();

        String workflowType = Process.WORKFLOW_TYPE;
        if (isFunctionFlowProject()) {
            workflowType = Process.FUNCTION_FLOW_TYPE;
        } else if (isFunctionProject()) {
            workflowType = Process.FUNCTION_TYPE;
        }

        // then we can instantiate the exec model generator
        // with the data classes that we have already resolved
        ProcessToExecModelGenerator execModelGenerator = new ProcessToExecModelGenerator(contextClassLoader, workflowType);

        // first we generate all the data classes from variable declarations
        for (Entry entry : processes.entrySet()) {
            ModelClassGenerator mcg = new ModelClassGenerator(execModelGenerator, context(), entry.getValue());
            processIdToModelGenerator.put(entry.getKey(), mcg);
            processIdToModel.put(entry.getKey(), mcg.generate());

            InputModelClassGenerator imcg = new InputModelClassGenerator(context(), entry.getValue(), workflowType);
            processIdToInputModelGenerator.put(entry.getKey(), imcg);

            OutputModelClassGenerator omcg = new OutputModelClassGenerator(context(), entry.getValue(), workflowType);
            processIdToOutputModelGenerator.put(entry.getKey(), omcg);

            context.addGenerator("ModelClassGenerator", entry.getKey(), mcg);
            context.addGenerator("InputModelClassGenerator", entry.getKey(), imcg);
            context.addGenerator("OutputModelClassGenerator", entry.getKey(), omcg);
        }

        // then we generate user task inputs and outputs if any
        for (Entry entry : processes.entrySet()) {
            UserTasksModelClassGenerator utcg = new UserTasksModelClassGenerator(entry.getValue(), context);
            processIdToUserTaskModel.put(entry.getKey(), utcg.generate());
        }

        List functions = context.getBuildContext().classThatImplement(Functions.class.getCanonicalName());

        // collect all process descriptors (exec model)
        for (Entry entry : processes.entrySet()) {

            entry.getValue().getNodesRecursively().stream().filter(node -> node instanceof SubProcessNode).forEach(sp -> {
                String processId = ((SubProcessNode) sp).getProcessId();
                if (((SubProcessNode) sp).getProcessVersion() != null) {
                    processId += "_" + ((SubProcessNode) sp).getProcessVersion();
                }

                WorkflowProcess sprocess = processes.get(processId);

                ((SubProcessNode) sp).setMetaData("serverless", ProcessToExecModelGenerator.isServerlessWorkflow(sprocess));
            });

            ProcessExecutableModelGenerator execModelGen = new ProcessExecutableModelGenerator(entry.getValue(),
                    execModelGenerator);
            String packageName = entry.getValue().getPackageName();
            String id = entry.getKey();

            // add extra meta data to indicate if user task mgmt is available
            if (context.getBuildContext().isUserTaskMgmtSupported()) {
                entry.getValue().getMetaData().put("UserTaskMgmt", "true");
            }
            entry.getValue().getMetaData().put("referencePrefix",
                    context.getApplicationProperty("quarkus.automatiko.resource-path-prefix").orElse(""));

            Set classImports = ((io.automatiko.engine.workflow.process.core.WorkflowProcess) entry.getValue())
                    .getImports();
            if (classImports != null) {
                classImports = new HashSet<>();
                ((io.automatiko.engine.workflow.process.core.WorkflowProcess) entry.getValue()).setImports(classImports);
            }
            classImports.add(BaseFunctions.class.getCanonicalName());
            classImports.addAll(functions);

            try {
                ProcessMetaData generate = execModelGen.generate();
                processIdToMetadata.put(id, generate);
                processExecutableModelGenerators.add(execModelGen);

                context.addProcess(id, generate);
            } catch (RuntimeException e) {
                LOGGER.error(e.getMessage());
                throw new ProcessCodegenException(id, packageName, e);
            }
        }

        // generate Process, ProcessInstance classes and the REST resource
        for (ProcessExecutableModelGenerator execModelGen : processExecutableModelGenerators) {
            String classPrefix = StringUtils.capitalize(execModelGen.extractedProcessId());
            WorkflowProcess workFlowProcess = execModelGen.process();
            ModelClassGenerator modelClassGenerator = processIdToModelGenerator.get(execModelGen.getProcessId());

            ProcessGenerator p = new ProcessGenerator(context, workFlowProcess, execModelGen, classPrefix,
                    modelClassGenerator.className(), applicationCanonicalName,
                    processIdToUserTaskModel.get(execModelGen.getProcessId()), processIdToMetadata)
                            .withDependencyInjection(annotator)
                            .withPersistence(persistence);

            ProcessInstanceGenerator pi = new ProcessInstanceGenerator(workflowType, context(), execModelGen,
                    workFlowProcess.getPackageName(),
                    classPrefix, modelClassGenerator.generate());

            ProcessMetaData metaData = processIdToMetadata.get(execModelGen.getProcessId());
            if (isFunctionFlowProject()) {
                ffgs.add(new FunctionFlowGenerator(context(), workFlowProcess, modelClassGenerator.className(),
                        execModelGen.className(),
                        applicationCanonicalName).withDependencyInjection(annotator).withSignals(metaData.getSignals(),
                                metaData.getSignalNodes()).withTriggers(metaData.getTriggers()));

                if (metaData.getTriggers() != null) {

                    for (TriggerMetaData trigger : metaData.getTriggers()) {

                        if (trigger.getType().equals(TriggerMetaData.TriggerType.ProduceMessage)) {

                            MessageDataEventGenerator msgDataEventGenerator = new MessageDataEventGenerator(workFlowProcess,
                                    trigger).withDependencyInjection(annotator);
                            mdegs.add(msgDataEventGenerator);

                            mpgs.add(new MessageProducerGenerator(workflowType, context(), workFlowProcess,
                                    modelClassGenerator.className(), execModelGen.className(),
                                    msgDataEventGenerator.className(), trigger).withDependencyInjection(annotator));
                        }
                    }
                }
            } else if (isFunctionProject()) {
                fgs.add(new FunctionGenerator(context(), workFlowProcess, modelClassGenerator.className(),
                        execModelGen.className(),
                        applicationCanonicalName).withDependencyInjection(annotator));
            } else if (isServiceProject()) {
                if (isPublic(workFlowProcess)) {

                    // Creating and adding the ResourceGenerator
                    resourceGeneratorFactory
                            .create(context(), workFlowProcess, modelClassGenerator.className(), execModelGen.className(),
                                    applicationCanonicalName)
                            .map(r -> r.withDependencyInjection(annotator).withParentProcess(null).withPersistence(persistence)
                                    .withUserTasks(processIdToUserTaskModel.get(execModelGen.getProcessId()))
                                    .withPathPrefix("{id}").withSignals(metaData.getSignals(),
                                            metaData.getSignalNodes())
                                    .withTriggers(metaData.isStartable(), metaData.isDynamic())
                                    .withSubProcesses(populateSubprocesses(workFlowProcess,
                                            processIdToMetadata.get(execModelGen.getProcessId()), processIdToMetadata,
                                            processIdToModelGenerator, processExecutableModelGenerators,
                                            processIdToUserTaskModel)))
                            .ifPresent(rgs::add);

                    if (context.getBuildContext().isGraphQLSupported()) {
                        GraphQLResourceGenerator graphqlGenerator = new GraphQLResourceGenerator(context(), workFlowProcess,
                                modelClassGenerator.className(), execModelGen.className(),
                                applicationCanonicalName);

                        graphqlGenerator.withDependencyInjection(annotator).withParentProcess(null).withPersistence(persistence)
                                .withUserTasks(processIdToUserTaskModel.get(execModelGen.getProcessId()))
                                .withPathPrefix(CodegenUtils.version(workFlowProcess.getVersion()))
                                .withSignals(metaData.getSignals(),
                                        metaData.getSignalNodes())
                                .withTriggers(metaData.isStartable(), metaData.isDynamic())
                                .withSubProcesses(populateSubprocessesGraphQL(workFlowProcess,
                                        processIdToMetadata.get(execModelGen.getProcessId()), processIdToMetadata,
                                        processIdToModelGenerator, processExecutableModelGenerators,
                                        processIdToUserTaskModel));

                        grapggs.add(graphqlGenerator);
                    }
                }
                if (metaData.getTriggers() != null) {

                    for (TriggerMetaData trigger : metaData.getTriggers()) {

                        // generate message consumers for processes with message events
                        if (isPublic(workFlowProcess)
                                && trigger.getType().equals(TriggerMetaData.TriggerType.ConsumeMessage)) {

                            MessageDataEventGenerator msgDataEventGenerator = new MessageDataEventGenerator(workFlowProcess,
                                    trigger).withDependencyInjection(annotator);
                            mdegs.add(msgDataEventGenerator);

                            megs.add(new MessageConsumerGenerator(context(), workFlowProcess,
                                    modelClassGenerator.className(), execModelGen.className(), applicationCanonicalName,
                                    msgDataEventGenerator.className(), trigger).withDependencyInjection(annotator)
                                            .withPersistence(persistence));
                        } else if (trigger.getType().equals(TriggerMetaData.TriggerType.ProduceMessage)) {

                            MessageDataEventGenerator msgDataEventGenerator = new MessageDataEventGenerator(workFlowProcess,
                                    trigger).withDependencyInjection(annotator);
                            mdegs.add(msgDataEventGenerator);

                            mpgs.add(new MessageProducerGenerator(workflowType, context(), workFlowProcess,
                                    modelClassGenerator.className(), execModelGen.className(),
                                    msgDataEventGenerator.className(), trigger).withDependencyInjection(annotator));
                        }
                    }
                }
            }

            if (metaData.getOpenAPIs() != null) {

                for (OpenAPIMetaData api : metaData.getOpenAPIs()) {
                    OpenAPIClientGenerator oagenerator = new OpenAPIClientGenerator(context, workFlowProcess, api)
                            .withDependencyInjection(annotator);

                    opgs.add(oagenerator);
                }
            }
            moduleGenerator.addProcess(p);

            ps.add(p);
            pis.add(pi);
        }

        for (ModelClassGenerator modelClassGenerator : processIdToModelGenerator.values()) {
            ModelMetaData mmd = modelClassGenerator.generate();

            storeFile(Type.MODEL, modelClassGenerator.generatedFilePath(), mmd.generate(
                    annotator != null ? new String[] { "io.quarkus.runtime.annotations.RegisterForReflection" }
                            : new String[0]));
        }

        for (InputModelClassGenerator modelClassGenerator : processIdToInputModelGenerator.values()) {
            ModelMetaData mmd = modelClassGenerator.generate();
            storeFile(Type.MODEL, modelClassGenerator.generatedFilePath(), mmd.generate(
                    annotator != null ? new String[] { "io.quarkus.runtime.annotations.RegisterForReflection" }
                            : new String[0]));
        }

        for (OutputModelClassGenerator modelClassGenerator : processIdToOutputModelGenerator.values()) {
            ModelMetaData mmd = modelClassGenerator.generate();
            storeFile(Type.MODEL, modelClassGenerator.generatedFilePath(), mmd.generate(
                    annotator != null ? new String[] { "io.quarkus.runtime.annotations.RegisterForReflection" }
                            : new String[0]));
        }

        for (List utmd : processIdToUserTaskModel.values()) {

            for (UserTaskModelMetaData ut : utmd) {
                storeFile(Type.MODEL, UserTasksModelClassGenerator.generatedFilePath(ut.getInputModelClassName()),
                        ut.generateInput());

                storeFile(Type.MODEL, UserTasksModelClassGenerator.generatedFilePath(ut.getOutputModelClassName()),
                        ut.generateOutput());
            }
        }

        for (AbstractResourceGenerator resourceGenerator : rgs) {
            storeFile(Type.REST, resourceGenerator.generatedFilePath(), resourceGenerator.generate());
        }

        for (AbstractResourceGenerator resourceGenerator : grapggs) {
            storeFile(Type.GRAPHQL, resourceGenerator.generatedFilePath(), resourceGenerator.generate());
        }

        for (FunctionGenerator functionGenerator : fgs) {
            storeFile(Type.FUNCTION, functionGenerator.generatedFilePath(), functionGenerator.generate());
        }

        for (FunctionFlowGenerator functionFlowGenerator : ffgs) {
            storeFile(Type.FUNCTION_FLOW, functionFlowGenerator.generatedFilePath(), functionFlowGenerator.generate());
        }

        for (MessageDataEventGenerator messageDataEventGenerator : mdegs) {
            storeFile(Type.CLASS, messageDataEventGenerator.generatedFilePath(), messageDataEventGenerator.generate());
        }

        for (MessageConsumerGenerator messageConsumerGenerator : megs) {
            storeFile(Type.MESSAGE_CONSUMER, messageConsumerGenerator.generatedFilePath(),
                    messageConsumerGenerator.generate());
        }

        for (MessageProducerGenerator messageProducerGenerator : mpgs) {
            storeFile(Type.MESSAGE_PRODUCER, messageProducerGenerator.generatedFilePath(),
                    messageProducerGenerator.generate());
        }

        for (OpenAPIClientGenerator openApiClientGenerator : opgs) {
            openApiClientGenerator.generate();

            Map contents = openApiClientGenerator.generatedClasses();

            for (Entry entry : contents.entrySet()) {

                storeFile(Type.CLASS, entry.getKey().replace('.', '/') + ".java", entry.getValue());
            }
        }

        for (ProcessGenerator p : ps) {
            storeFile(Type.PROCESS, p.generatedFilePath(), p.generate());

            p.getAdditionalClasses().forEach(cp -> {
                String packageName = cp.getPackageDeclaration().map(pd -> pd.getName().toString()).orElse("");
                String clazzName = cp.findFirst(ClassOrInterfaceDeclaration.class).map(cls -> cls.getName().toString())
                        .get();
                String path = (packageName + "." + clazzName).replace('.', '/') + ".java";
                storeFile(Type.CLASS, path, cp.toString());
            });
        }

        for (ProcessInstanceGenerator pi : pis) {
            storeFile(Type.PROCESS_INSTANCE, pi.generatedFilePath(), pi.generate());
        }

        for (ProcessExecutableModelGenerator processGenerator : processExecutableModelGenerators) {
            if (processGenerator.isPublic()) {
                publicProcesses.add(processGenerator.extractedProcessId());
            }
        }

        return generatedFiles;
    }

    @Override
    public void updateConfig(ConfigGenerator cfg) {
        if (!processes.isEmpty()) {
            cfg.withProcessConfig(new ProcessConfigGenerator());
        }
    }

    private void storeFile(Type type, String path, String source) {
        if (source != null) {
            generatedFiles.add(new GeneratedFile(type, path, log(source).getBytes(StandardCharsets.UTF_8)));
        }
    }

    public List getGeneratedFiles() {
        return generatedFiles;
    }

    @Override
    public ApplicationSection section() {
        return moduleGenerator;
    }

    protected boolean isPublic(WorkflowProcess process) {
        return WorkflowProcess.PUBLIC_VISIBILITY.equalsIgnoreCase(process.getVisibility());
    }

    protected List populateSubprocesses(WorkflowProcess parentProcess,
            ProcessMetaData metaData, Map processIdToMetadata,
            Map processIdToModelGenerator,
            List processExecutableModelGenerators,
            Map> processIdToUserTaskModel) {
        List subprocesses = new ArrayList();

        for (Entry entry : metaData.getSubProcesses().entrySet()) {

            ProcessExecutableModelGenerator execModelGen = processExecutableModelGenerators.stream()
                    .filter(p -> p.getProcessId().equals(entry.getValue())).findFirst().orElse(null);

            if (execModelGen != null) {
                WorkflowProcess workFlowProcess = execModelGen.process();
                ModelClassGenerator modelClassGenerator = processIdToModelGenerator.get(entry.getValue());

                Optional.of(new SubprocessResourceGenerator(context(), workFlowProcess, modelClassGenerator.className(),
                        execModelGen.className(), applicationCanonicalName))
                        .map(r -> r.withDependencyInjection(annotator).withParentProcess(parentProcess)
                                .withUserTasks(processIdToUserTaskModel.get(execModelGen.getProcessId()))
                                .withSignals(processIdToMetadata.get(execModelGen.getProcessId()).getSignals(),
                                        metaData.getSignalNodes())
                                .withTriggers(processIdToMetadata.get(execModelGen.getProcessId()).isStartable(),
                                        processIdToMetadata.get(execModelGen.getProcessId()).isDynamic())
                                .withSubProcesses(populateSubprocesses(workFlowProcess,
                                        processIdToMetadata.get(execModelGen.getProcessId()), processIdToMetadata,
                                        processIdToModelGenerator, processExecutableModelGenerators,
                                        processIdToUserTaskModel)))
                        .ifPresent(subprocesses::add);
            }
        }

        return subprocesses;
    }

    protected List populateSubprocessesGraphQL(WorkflowProcess parentProcess,
            ProcessMetaData metaData, Map processIdToMetadata,
            Map processIdToModelGenerator,
            List processExecutableModelGenerators,
            Map> processIdToUserTaskModel) {
        List subprocesses = new ArrayList();

        for (Entry entry : metaData.getSubProcesses().entrySet()) {

            ProcessExecutableModelGenerator execModelGen = processExecutableModelGenerators.stream()
                    .filter(p -> p.getProcessId().equals(entry.getValue())).findFirst().orElse(null);

            if (execModelGen != null) {
                WorkflowProcess workFlowProcess = execModelGen.process();
                ModelClassGenerator modelClassGenerator = processIdToModelGenerator.get(entry.getValue());

                Optional.of(new SubprocessGraphQLResourceGenerator(context(), workFlowProcess, modelClassGenerator.className(),
                        execModelGen.className(), applicationCanonicalName))
                        .map(r -> r.withDependencyInjection(annotator).withParentProcess(parentProcess)
                                .withUserTasks(processIdToUserTaskModel.get(execModelGen.getProcessId()))
                                .withSignals(processIdToMetadata.get(execModelGen.getProcessId()).getSignals(),
                                        metaData.getSignalNodes())
                                .withTriggers(processIdToMetadata.get(execModelGen.getProcessId()).isStartable(),
                                        processIdToMetadata.get(execModelGen.getProcessId()).isDynamic())
                                .withSubProcesses(populateSubprocessesGraphQL(workFlowProcess,
                                        processIdToMetadata.get(execModelGen.getProcessId()), processIdToMetadata,
                                        processIdToModelGenerator, processExecutableModelGenerators,
                                        processIdToUserTaskModel)))
                        .ifPresent(subprocesses::add);
            }
        }

        return subprocesses;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy