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

io.vlingo.maven.codegen.ProtocolScanner Maven / Gradle / Ivy

// Copyright © 2012-2020 VLINGO LABS. All rights reserved.
//
// This Source Code Form is subject to the terms of the
// Mozilla Public License, v. 2.0. If a copy of the MPL
// was not distributed with this file, You can obtain
// one at https://mozilla.org/MPL/2.0/.

package io.vlingo.maven.codegen;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*;
import java.util.stream.Stream;

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

/**
 * Iterates over a source directory with Java classes and finds out which interfaces are meant to be Proxy interfaces.
 * It tries to detect cases where .actorFor is used to instantiate actors and resolves imports to detect the full qualified
 * name of the proxy class.
 *
 * @since 1.0.0
 */
public class ProtocolScanner {
    private final File directory;

    public ProtocolScanner(final File directory) {
        this.directory = directory;
    }

    /**
     * @return the list of all interfaces and proxies that need to be loaded during runtime
     */
    public Set scan() {
        return scanDirectory(directory).collect(toSet());
    }

    private Stream scanDirectory(File directory) {
        final File[] values = directory.listFiles();
        if (values == null) {
            return Stream.empty();
        }

        return Stream.of(values).flatMap(file -> {
            if (file.isDirectory()) {
                return scanDirectory(file);
            } else {
                return scanFile(file);
            }
        });
    }

    private Stream scanFile(File file) {
        if (!file.getName().endsWith(".java")) {
            return Stream.empty();
        }

        String javaCode = load(file);
        String packageName = packageName(javaCode);
        Map imports = importsOf(javaCode);
        Set proxies = usagesAsProxies(javaCode);

        return proxies.stream()
                .map(protocol -> imports.getOrDefault(protocol, fromPackageName(packageName, protocol)))
                .flatMap(protocol -> Stream.of(protocol, protocol + "__Proxy"));
    }

    private String packageName(String javaCode) {
        return extractFromWrappingTokens(javaCode, "package", ";");
    }

    private Map importsOf(String javaCode) {
        return Arrays.stream(javaCode.split("\n"))
                .map(String::trim)
                .filter(line -> line.startsWith("import") && line.endsWith(";"))
                .map(line -> extractFromWrappingTokens(javaCode, "import", ";"))
                .collect(groupingBy(javaImport -> javaImport.substring(javaImport.lastIndexOf(".") + 1)))
                .entrySet()
                .stream()
                .collect(toMap(e -> e.getKey(), e -> e.getValue().get(0)));
    }

    private Set usagesAsProxies(String javaCode) {
        return Arrays.stream(javaCode.split("\n"))
                .map(String::trim)
                .filter(line -> line.contains(".actorFor"))
                .map(line -> extractFromWrappingTokens(javaCode, ".actorFor(", ".class"))
                .collect(toSet());
    }

    private String load(File file) {
        try {
            return new String(Files.readAllBytes(file.toPath()));
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    private String extractFromWrappingTokens(String javaCode, String startToken, String endToken) {
        int packageStart = javaCode.indexOf(startToken);
        if (packageStart == -1) {
            return "";
        }

        packageStart += startToken.length();
        int packageEnd = javaCode.indexOf(endToken, packageStart);
        if (packageEnd == -1) {
            return "";
        }

        return javaCode.substring(packageStart, packageEnd).trim();
    }

    private String fromPackageName(String packageName, String proxy) {
        if (packageName.equals("")) {
            return proxy;
        } else {
            return packageName + "." + proxy;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy