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

com.centurylink.mdw.cli.Hierarchy Maven / Gradle / Ivy

There is a newer version: 6.1.39
Show newest version
package com.centurylink.mdw.cli;

import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.centurylink.mdw.model.workflow.Linked;
import com.centurylink.mdw.model.workflow.Process;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

@Parameters(commandNames="hierarchy", commandDescription="Process definition hierarchy", separators="=")
public class Hierarchy extends Setup {

    @Parameter(names="--process", description="Process for which heirarchy will be shown.", required=true)
    private String process;
    public String getProcess() {
        return process;
    }
    public void setProcess(String proc) {
        this.process = proc;
    }

    @Parameter(names="--max-depth", description="Maximum child depth (to avoid StackOverflowErrors)")
    private int maxDepth = 100;
    public int getMaxDepth() { return maxDepth; }
    public void setMaxDepth(int maxDepth) { this.maxDepth = maxDepth; }

    @Parameter(names="--downward", description="Only search downward from process")
    private boolean downward;
    public boolean isDownward() { return downward; }
    public void setDownward(boolean downward) { this.downward = downward; }


    private List> topLevelCallers = new ArrayList<>();
    public List> getTopLevelCallers() { return topLevelCallers; }

    private List processes;
    private Process start;

    Hierarchy() {

    }

    public Hierarchy(String process) {
        this.process = process;
    }

    public Hierarchy(Process process, List processes) {
        this.start = process;
        this.processes = processes;
    }

    @Override
    public Operation run(ProgressMonitor... monitors) throws IOException {
        for (ProgressMonitor monitor : monitors)
            monitor.progress(0);


        if (start == null) {
            if (!process.endsWith(".proc"))
                process += ".proc";
            start = loadProcess(getPackageName(process), getAssetFile(process), true);
        }

        for (ProgressMonitor monitor : monitors)
            monitor.progress(10);

        if (processes == null)
            loadProcesses(monitors);
        if (downward) {
            topLevelCallers.add(new Linked<>(start));
        }
        else {
            addTopLevelCallers(start);
        }

        for (int i = 0; i < topLevelCallers.size(); i++) {
            Linked topLevelCaller = topLevelCallers.get(i);
            addCalledHierarchy(topLevelCaller, 0);
            int prog = 85 + ((int)Math.floor((i * 10)/topLevelCallers.size()));
            for (ProgressMonitor monitor : monitors)
                monitor.progress(prog);
        }

        // weed out paths that don't contain starting process
        for (Linked topLevelCaller : topLevelCallers) {
            topLevelCaller.prune(start);
        }

        for (ProgressMonitor monitor : monitors)
            monitor.progress(100);

        if (isCommandLine()) {
            // print output
            getOut().println();
            print(topLevelCallers, 0);
        }

        return this;
    }

    private void print(List> callers, int depth) {
        for (Linked caller : callers) {
            print(caller, depth);
        }
    }

    private void print(Linked caller, int depth) {
        getOut().println(caller.toString(depth));
        print(caller.getChildren(), depth + 1);
    }

    public List findCallingProcesses(Process subproc) {
        List callers = new ArrayList<>();
        for (Process process : processes) {
            if (process.invokesSubprocess(subproc) && !callers.contains(process)) {
                callers.add(process);
            }
        }
        return callers;
    }

    public List findCalledProcesses(Process mainproc) {
        return mainproc.findInvoked(processes);
    }

    private Process loadProcess(String pkg, File procFile, boolean deep) throws IOException {
        Properties versionProps = getPackageVersions().get(pkg);
        Process process;
        if (deep) {
            process = new Process(new JSONObject(new String(Files.readAllBytes(procFile.toPath()))));
        }
        else {
            process = new Process();
        }
        int lastDot = procFile.getName().lastIndexOf('.');
        String assetPath = pkg + "/" + procFile.getName();
        process.setName(procFile.getName().substring(0, lastDot));
        process.setPackageName(pkg);
        String verProp = versionProps == null ? null : versionProps.getProperty(procFile.getName());
        process.setVersion(verProp == null ? 0 : Integer.parseInt(verProp.split(" ")[0]));
        process.setId(getAssetId(assetPath, process.getVersion()));
        return process;
    }

    /**
     * Only loads current processes (not archived) that contain subprocs.
     * Starts at 10%, uses 80% monitor progress.
     */
    private void loadProcesses(ProgressMonitor... monitors) throws IOException {
        if (processes == null) {
            processes = new ArrayList<>();
            Map> pkgProcFiles = findAllAssets("proc");
            for (String pkg : pkgProcFiles.keySet()) {
                List procFiles = pkgProcFiles.get(pkg);
                for (int i = 0; i < procFiles.size(); i++) {
                    processes.add(loadProcess(pkg, procFiles.get(i), true));
                    int prog = 10 + ((int)Math.floor((i * 80)/procFiles.size()));
                    for (ProgressMonitor monitor : monitors)
                        monitor.progress(prog);
                }
            }
        }
    }

    private Map packageVersions;
    private Map getPackageVersions() throws IOException {
        if (packageVersions == null)
            packageVersions = getVersionProps(getAssetPackageDirs());
        return packageVersions;
    }

    private void addTopLevelCallers(Process called) {
        List immediateCallers = findCallingProcesses(called);
        if (immediateCallers.isEmpty()) {
            topLevelCallers.add(new Linked<>(called));
        }
        else {
            for (Process caller : immediateCallers) {
                addTopLevelCallers(caller);
            }
        }
    }

    /**
     * Find subflow graph for caller.
     * @param caller - top level starting flow
     */
    private void addCalledHierarchy(Linked caller, int depth) throws IOException {
        depth++;
        Process callerProcess = caller.get();
        for (Process calledProcess : findCalledProcesses(callerProcess)) {
            Linked child = new Linked<>(calledProcess);
            child.setParent(caller);
            caller.getChildren().add(child);
            if (!child.checkCircular()) {
                if (depth > maxDepth) {
                    String message = "Allowable --max-depth (" + maxDepth + ") exceeded.";
                    getOut().println("\n" + message);
                    print(child.getCallChain(), 0);
                    throw new IOException(message + "  See tree output.");
                }
                else {
                    addCalledHierarchy(child, depth);
                }
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy