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

com.github.imrafaelmerino.kafkacli.KafkaCLI Maven / Gradle / Ivy

package com.github.imrafaelmerino.kafkacli;

import fun.gen.Gen;
import jio.ExceptionFun;
import jio.IO;
import jio.cli.Command;
import jio.cli.Console;
import jio.cli.GenerateCommand;
import jsonvalues.JsObj;
import jsonvalues.JsObjPair;
import jsonvalues.JsPath;
import jsonvalues.spec.JsObjSpecParser;
import org.apache.avro.Schema.Parser;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.github.imrafaelmerino.kafkacli.ConfigurationFields.*;

public class KafkaCLI {


    final Map> generators;

    public KafkaCLI(final Map> generators) {
        this.generators = generators;
    }

    private static void validateSerializer(String keySerializerField,
                                           JsObj producerProps,
                                           String producerName
                                          ) {
        String keySerializer = producerProps.getStr(keySerializerField);
        String validSerializer = "jsonvalues.spec.serializers.confluent.ConfluentSerializer";
        if (!validSerializer.equals(keySerializer)) {
            JsPath path =
                    JsPath.fromKey(KAFKA)
                          .key(PRODUCERS)
                          .key(producerName)
                          .key(PRODUCER_PROPS)
                          .key(keySerializerField);
            throw new IllegalArgumentException("The property %s must be set to %s".formatted(path,
                                                                                             validSerializer));
        }
    }

    private static JsObj parseConf(final String[] args) throws IOException {
        JsObjSpecParser parser = JsObjSpecParser.of(ConfigurationSpec.global);
        if (args.length == 0) {
            throw new IllegalArgumentException("Pass in the configuration file");
        }
        var path = Path.of(args[0]);
        if (!path.toFile()
                 .exists()) {
            throw new IllegalArgumentException("File %s not found".formatted(path));
        }
        return parser.parse(Files.readAllBytes(path));
    }


    public IO executeCommand(JsObj conf, String command) {
        return createConsole(conf).executeCommand(conf, command);
    }


    public void start(String[] args) {
        JsObj conf;
        try {
            conf = parseConf(args);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }

        Console cli = createConsole(conf);

        cli.eval(conf);

    }

    private Console createConsole(JsObj conf) {
        validate(conf);

        List myCommands = new ArrayList<>();

        KafkaProducers producers = new KafkaProducers();
        KafkaConsumers consumers = new KafkaConsumers();

        AvroSchemas avroSchemas = new AvroSchemas(conf);

        myCommands.add(new ProducerPublishCommand(generators,
                                                  producers,
                                                  avroSchemas));
        myCommands.add(new PublishFileCommand(generators,
                                              producers,
                                              avroSchemas));
        myCommands.add(new ProducerStartCommand(producers));
        myCommands.add(new ConsumerAsyncCommitCommand(consumers));
        myCommands.add(new ProducerStopCommand(producers));
        myCommands.add(new ConsumerStopCommand(consumers));
        myCommands.add(new ConsumerStartCommand(consumers));
        myCommands.add(new ConsumerListCommand(consumers));
        myCommands.add(new ProducerListCommand(producers));
        myCommands.add(new ChannelListCommand(producers));

        for (var genName : generators.keySet()) {
            myCommands.add(new GenerateCommand(genName,
                                               "Data Generator",
                                               generators.get(genName)
                                                         .map(Object::toString)));
        }
        Console cli = new Console(myCommands);
        return cli;
    }

    private void validate(final JsObj conf) {
        JsObj channels = conf.getObj(ConfigurationFields.CHANNELS);
        for (JsObjPair pair : channels) {
            String channelName = pair.key();
            JsObj channelConf = pair.value()
                                    .toJsObj();
            String producerName = channelConf.getStr(ConfigurationFields.PRODUCER);
            if (!ConfigurationQueries.getProducers(conf)
                                     .contains(producerName)) {
                throw new IllegalArgumentException("The producer `%s` associated to the channel `%s` has not been defined in %s".formatted(producerName,
                                                                                                                                           channelName,
                                                                                                                                           "/kafka/producers"));

            }
            String keyGen = channelConf.getStr(KEY_GEN);
            if (keyGen != null && !generators.containsKey(keyGen)) {
                throw new IllegalArgumentException(("The generator `%s` associated to the key of the channel `%s` has not been "
                                                    + "created.").formatted(keyGen,
                                                                            channelName));
            }

            String valueGen = channelConf.getStr(VALUE_GEN);
            if (valueGen != null && !generators.containsKey(valueGen)) {
                throw new IllegalArgumentException(("The generator `%s` associated to the value of the channel `%s` has not "
                                                    + "been created.").formatted(valueGen,
                                                                                 channelName));
            }

            String keySchema = channelConf.getStr(KEY_SCHEMA);
            if (keySchema != null) {
                try {
                    new Parser().parse(keySchema);
                } catch (Exception e) {
                    throw new IllegalArgumentException("The AVRO schema associated to the key of the channel `%s` is not valid: %s".formatted(channelName,
                                                                                                                                              ExceptionFun.findUltimateCause(e)
                                                                                                                                                          .toString()));
                }
            }
            String valueSchema = channelConf.getStr(VALUE_SCHEMA);
            if (valueSchema != null) {
                try {
                    new Parser().parse(valueSchema);
                } catch (Exception e) {
                    throw new IllegalArgumentException("The AVRO schema associated to the value of the channel `%s` is not valid: %s"
                                                               .formatted(channelName,
                                                                          ExceptionFun.findUltimateCause(e)
                                                                                      .toString()));
                }
            }

            //validate key and value serializer of producer
            JsObj producerProps = ConfigurationQueries.getProducerProps(conf,
                                                                        producerName);

            if (keySchema != null) {
                validateSerializer("key.serializer",
                                   producerProps,
                                   producerName);
            }

            if (valueSchema != null) {
                validateSerializer("value.serializer",
                                   producerProps,
                                   producerName);
            }

        }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy