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

live.document.mavenplugin.method.MethodWithEntityMindMapMojo Maven / Gradle / Ivy

package live.document.mavenplugin.method;

import com.credibledoc.plantuml.svggenerator.SvgGeneratorService;
import live.document.generator.BaseMethodMindMapGenerator;
import live.document.generator.model.CallNode;
import live.document.generator.utils.FileUtils;
import live.document.mavenplugin.common.AnalyzeAssistant;
import live.document.mavenplugin.common.ProjectAnalyzeResult;
import live.document.mavenplugin.style.MindMapConstants;
import live.document.scanner.DbObjectTypeEnum;
import live.document.scanner.DbOperationTypeEnum;
import live.document.scanner.MethodObject;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 分析方法的调用链中,涉及实体Entity类操作的部分。
 */
@Mojo(name = "find-all-entities-and-tables-of-method")
public class MethodWithEntityMindMapMojo extends AbstractMojo {
    @Parameter(defaultValue = "${project.basedir}", required = true)
    private File projectRoot;
    @Parameter(required = true)
    private String gitRepositoryUri;
    @Parameter
    private String[] resourceLayerPattern;
    @Parameter
    private String[] controllerPattern;
    @Parameter
    private String[] applicationLayerPattern;
    @Parameter
    private String[] applicationServicePattern;
    @Parameter
    private String[] domainLayerPattern;
    @Parameter
    private String[] domainServicePattern;
    @Parameter
    private String[] entityPattern;
    @Parameter
    private String[] infrastructureLayerPattern;
    @Parameter
    private String[] repositoryPattern;
    @Parameter
    private String[] aclLayerPattern;
    @Parameter
    private String[] aclPattern;
    @Parameter
    private String[] transactionPattern;
    @Parameter
    private String methodMindMapClassName;
    @Parameter
    private String methodMindMapMethodName;
    @Parameter
    private String[] plsqlPaths;
    @Parameter
    private String[] sqlExecuteFullMethodNames;
    @Parameter(defaultValue = "", required = true)
    private String analysisResultOutputDir;

    public static final String[] READONLY_METHOD_NAME = new String[]{"get", "toString", "is", "has", "find", "hashCode", "equals"};

    @Override
    public void execute() throws MojoExecutionException {
        try {
            if (methodMindMapClassName == null || methodMindMapClassName.trim().length() == 0) {
                throw new MojoFailureException("Please specify methodMindMapClassName");
            }

            if (methodMindMapMethodName == null || methodMindMapMethodName.trim().length() == 0) {
                throw new MojoFailureException("Please specify methodMindMapMethodName");
            }

            FileUtils fileUtils = new FileUtils();

            getLog().info("scan: " + projectRoot.getAbsolutePath());
            EntityMethodMindMap4CallTree mindmap4CallTree = new EntityMethodMindMap4CallTree();
            BaseMethodMindMapGenerator generator = new BaseMethodMindMapGenerator(mindmap4CallTree);

            Map colorMap = getColorMap();
            mindmap4CallTree.setColors(colorMap);
            mindmap4CallTree.setLogger(getLog());
            mindmap4CallTree.setDisplayClassAndMethodName(true);
            mindmap4CallTree.setTransactionPattern(transactionPattern);
            mindmap4CallTree.setGetEntityOperations(node -> getAllEntityOperations(node));

            ProjectAnalyzeResult projectResult = AnalyzeAssistant.analyze(projectRoot,
                    sqlExecuteFullMethodNames,
                    plsqlPaths,
                    analysisResultOutputDir,
                    null);
            mindmap4CallTree.setPlSqlExplained(projectResult.getPlSqlExplained());

            String mindMapText = generator.generate(
                    projectResult.getCallGraph(),
                    projectResult.getPlSqlExplained(),
                    methodMindMapClassName,
                    methodMindMapMethodName,
                    m -> true,
                    (node -> hasEntityOperation(node)));

            Path fileName = Paths.get(analysisResultOutputDir, methodMindMapClassName + "." + methodMindMapMethodName + ".all.entity.svg");
            String svg = SvgGeneratorService.getInstance().generateSvgFromPlantUml(getFullMindMap(mindMapText));
            fileUtils.writeFile(fileName, svg);
            getLog().info("File created: file://" + fileName.toString());

        } catch (Exception e) {
            getLog().error(e);
            throw new MojoExecutionException(e.getMessage());
        }
    }

    private List getAllEntityOperations(CallNode node) {
        List allEntityOperations = getAllEntityOperations(node, true);
        List results = getDistinctEntityAndOperation(allEntityOperations);

        return results;
    }

    private List getDistinctEntityAndOperation(List allEntityOperations) {
        Map map = new HashMap<>();
        for (String allEntityOperation : allEntityOperations) {
            int endIndex = allEntityOperation.indexOf(",");
            if (endIndex > 0) {
                //for class
                String entityName = allEntityOperation.substring(0, endIndex).trim();
                String operation = allEntityOperation.substring(endIndex + 1).trim();
                if ("W".equalsIgnoreCase(operation)) {
                    map.put(entityName, "W");
                } else {
                    if (! map.containsKey(entityName)) {
                        map.put(entityName, operation);
                    }
                }
            } else {
                //for db table
                int spaceIndex = allEntityOperation.indexOf(" ");
                String tableName = allEntityOperation.substring(0, spaceIndex);
                String tableOperation = allEntityOperation.substring(spaceIndex + 1);
                String existsOperation = map.get(tableName);

                if (newOperatioHasHighPriority(existsOperation, tableOperation)) {
                    map.put(tableName, tableOperation);
                }
            }
        }

        List results = map.entrySet()
                .stream()
                .map(i -> "[" + i.getKey() + ", " + i.getValue() + "]")
                .collect(Collectors.toList());
        results.sort(String::compareTo);

        return results;
    }

    private boolean newOperatioHasHighPriority(String existsOperation, String newOperation) {
        if (existsOperation == null) {
            return true;
        }

        List operations = Arrays.asList("", "[R]", "[W]", "[RW]");

        return operations.indexOf(newOperation) > operations.indexOf(existsOperation);
    }

    private List getAllEntityOperations(CallNode node, boolean isRoot) {
        List results = new ArrayList<>();
        MethodObject methodObject = node.getMethodObject();
        boolean isEntity = isEntityClass(methodObject);

        if (isEntity && isRoot) {
            return results;
        }

        if (isEntity) {
            results.add(getClassNameWithOperation(node));
            return results;
        }

        if (node.getDbOperation() != null && node.getDbOperation().getObjectType() == DbObjectTypeEnum.TABLE) {
            results.add(node.getDbOperation().toString());
        }

        for (CallNode child : node.getChildren()) {
            List allEntityOperations = getAllEntityOperations(child, false);
            results.addAll(allEntityOperations);
        }

        return results;
    }

    private String getClassNameWithOperation(CallNode node) {
        String className = getSimpleClassName(node.getMethodObject().getClassName());
        return className + (isNodeHasEntityWriteOperation(node) ? ", W" : ", R");
    }

    protected String getSimpleClassName(String className) {
        int i = className.lastIndexOf(".");
        if (i > 0) {
            return className.substring(i + 1);
        }
        return className;
    }

    private Boolean hasEntityOperation(CallNode node) {
        if (node.isLink() && node.getLinkedNode() != null) {
            return hasEntityOperation(node.getLinkedNode());
        }

        return hasEntityOperation(node, true);
    }

    private Boolean hasEntityOperation(CallNode node, boolean isRoot) {
        if (node.getDbOperation() != null) {
            return true;
        }

        MethodObject methodObject = node.getMethodObject();
        boolean isEntity = isEntityClass(methodObject);
        if (isEntity && isRoot) {
            return false;
        }

        if (isEntity) {
            return true;
        }

        for (CallNode child : node.getChildren()) {
            if (hasEntityOperation(child, false)) {
                return true;
            }
        }

        return false;
    }

    private boolean isWriteOperation(CallNode node) {
        MethodObject methodObject = node.getMethodObject();
        for (String methodName : READONLY_METHOD_NAME) {
            if (methodObject.getMethodName().startsWith(methodName)) {
                return false;
            }
        }

        return true;
    }

    private Boolean isNodeHasEntityWriteOperation(CallNode node) {
        if (node.getMethodObject() != null) {
            MethodObject methodObject = node.getMethodObject();
            if (isEntityClass(methodObject)) {
                if (isWriteOperation(node)) {
                    return true;
                }
            }
        } else if (node.getDbOperation() != null) {
            if (node.getDbOperation().getOperationType() != DbOperationTypeEnum.READ) {
                return true;
            }
        }

        for (CallNode child : node.getChildren()) {
            if (isNodeHasEntityWriteOperation(child)) {
                return true;
            }
        }

        return false;
    }

    private boolean isEntityClass(MethodObject methodObject) {
        if (methodObject == null) {
            return false;
        }
        return (methodObject.getClassName().endsWith("Entity"));
    }

    private String getFullMindMap(String mindMapText) {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(MindMapConstants.plantUmlPrefix);
        stringBuilder.append(MindMapConstants.style);
        stringBuilder.append(mindMapText);
        stringBuilder.append(MindMapConstants.plantUmlSuffix);

        return stringBuilder.toString();
    }

    private Map getColorMap() {
        Map colorMap = new HashMap<>();
        colorMap.put("resourceLayer", resourceLayerPattern);
        colorMap.put("controller", controllerPattern);
        colorMap.put("applicationLayer", applicationLayerPattern);
        colorMap.put("applicationService", applicationServicePattern);
        colorMap.put("domainLayer", domainLayerPattern);
        colorMap.put("domainService", domainServicePattern);
        colorMap.put("entity", entityPattern);
        colorMap.put("infrastructureLayer", infrastructureLayerPattern);
        colorMap.put("repository", repositoryPattern);
        colorMap.put("aclLayer", aclLayerPattern);
        colorMap.put("acl", aclPattern);

        return colorMap;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy