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

xyz.block.ftl.deployment.JVMCodeGenerator Maven / Gradle / Ivy

There is a newer version: 0.398.1
Show newest version
package xyz.block.ftl.deployment;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;

import org.eclipse.microprofile.config.Config;

import io.quarkus.bootstrap.prebuild.CodeGenException;
import io.quarkus.deployment.CodeGenContext;
import io.quarkus.deployment.CodeGenProvider;
import xyz.block.ftl.v1.schema.Data;
import xyz.block.ftl.v1.schema.Enum;
import xyz.block.ftl.v1.schema.Module;
import xyz.block.ftl.v1.schema.Topic;
import xyz.block.ftl.v1.schema.Type;
import xyz.block.ftl.v1.schema.Verb;

public abstract class JVMCodeGenerator implements CodeGenProvider {

    public static final String PACKAGE_PREFIX = "ftl.";
    public static final String TYPE_MAPPER = "TypeAliasMapper";

    @Override
    public String providerId() {
        return "ftl-clients";
    }

    @Override
    public String inputDirectory() {
        return "ftl-module-schema";
    }

    @Override
    public boolean trigger(CodeGenContext context) throws CodeGenException {
        if (!Files.isDirectory(context.inputDir())) {
            return false;
        }
        List modules = new ArrayList<>();
        Map typeAliasMap = new HashMap<>();
        Map nativeTypeAliasMap = new HashMap<>();
        try (Stream pathStream = Files.list(context.inputDir())) {
            for (var file : pathStream.toList()) {
                String fileName = file.getFileName().toString();
                if (!fileName.endsWith(".pb")) {
                    continue;
                }
                var module = Module.parseFrom(Files.readAllBytes(file));
                for (var decl : module.getDeclsList()) {
                    String packageName = PACKAGE_PREFIX + module.getName();
                    if (decl.hasTypeAlias()) {
                        var data = decl.getTypeAlias();
                        boolean handled = false;
                        for (var md : data.getMetadataList()) {
                            if (md.hasTypeMap()) {
                                String runtime = md.getTypeMap().getRuntime();
                                if (runtime.equals("kotlin") || runtime.equals("java")) {
                                    nativeTypeAliasMap.put(new DeclRef(module.getName(), data.getName()),
                                            md.getTypeMap().getNativeName());
                                    generateTypeAliasMapper(module.getName(), data.getName(), packageName,
                                            Optional.of(md.getTypeMap().getNativeName()),
                                            context.outDir());
                                    handled = true;
                                    break;
                                }
                            }
                        }
                        if (!handled) {
                            generateTypeAliasMapper(module.getName(), data.getName(), packageName, Optional.empty(),
                                    context.outDir());
                            typeAliasMap.put(new DeclRef(module.getName(), data.getName()), data.getType());
                        }

                    }
                }
                modules.add(module);
            }
        } catch (IOException e) {
            throw new CodeGenException(e);
        }
        try {
            for (var module : modules) {
                String packageName = PACKAGE_PREFIX + module.getName();
                for (var decl : module.getDeclsList()) {
                    if (decl.hasVerb()) {
                        var verb = decl.getVerb();
                        if (!verb.getExport()) {
                            continue;
                        }
                        generateVerb(module, verb, packageName, typeAliasMap, nativeTypeAliasMap, context.outDir());
                    } else if (decl.hasData()) {
                        var data = decl.getData();
                        if (!data.getExport()) {
                            continue;
                        }
                        generateDataObject(module, data, packageName, typeAliasMap, nativeTypeAliasMap, context.outDir());

                    } else if (decl.hasEnum()) {
                        var data = decl.getEnum();
                        if (!data.getExport()) {
                            continue;
                        }
                        generateEnum(module, data, packageName, typeAliasMap, nativeTypeAliasMap, context.outDir());
                    } else if (decl.hasTopic()) {
                        var data = decl.getTopic();
                        if (!data.getExport()) {
                            continue;
                        }
                        generateTopicSubscription(module, data, packageName, typeAliasMap, nativeTypeAliasMap,
                                context.outDir());
                    }
                }
            }

        } catch (Exception e) {
            throw new CodeGenException(e);
        }
        return true;
    }

    protected abstract void generateTypeAliasMapper(String module, String name, String packageName,
            Optional nativeTypeAlias, Path outputDir) throws IOException;

    protected abstract void generateTopicSubscription(Module module, Topic data, String packageName,
            Map typeAliasMap, Map nativeTypeAliasMap, Path outputDir) throws IOException;

    protected abstract void generateEnum(Module module, Enum data, String packageName, Map typeAliasMap,
            Map nativeTypeAliasMap, Path outputDir) throws IOException;

    protected abstract void generateDataObject(Module module, Data data, String packageName, Map typeAliasMap,
            Map nativeTypeAliasMap, Path outputDir) throws IOException;

    protected abstract void generateVerb(Module module, Verb verb, String packageName, Map typeAliasMap,
            Map nativeTypeAliasMap, Path outputDir) throws IOException;

    @Override
    public boolean shouldRun(Path sourceDir, Config config) {
        return true;
    }

    public record DeclRef(String module, String name) {
    }

    protected static String className(String in) {
        return Character.toUpperCase(in.charAt(0)) + in.substring(1);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy