Skip to content
Snippets Groups Projects
Commit 50f55a21 authored by Martin Vogel's avatar Martin Vogel
Browse files

refactor: add runnable picocli commands (planning#2217)

parent 2f90feca
No related branches found
No related tags found
No related merge requests found
Pipeline #135957 failed
Showing
with 176 additions and 99 deletions
package dev.fitko.fitconnect.cli; package dev.fitko.fitconnect.cli;
import dev.fitko.fitconnect.cli.commands.GetAllSubmissionsCommand;
import dev.fitko.fitconnect.cli.commands.GetSubmissionCommand;
import dev.fitko.fitconnect.cli.commands.KeyGenCommand;
import dev.fitko.fitconnect.cli.commands.ListCommand;
import org.fusesource.jansi.AnsiConsole; import org.fusesource.jansi.AnsiConsole;
import picocli.CommandLine; import picocli.CommandLine;
...@@ -12,7 +16,11 @@ import static java.lang.System.exit; ...@@ -12,7 +16,11 @@ import static java.lang.System.exit;
import static java.lang.System.out; import static java.lang.System.out;
@CommandLine.Command(version = "2.0.0", @CommandLine.Command(version = "2.0.0",
subcommands = {KeyGenCommand.class, ListCommand.class}, subcommands = {
KeyGenCommand.class,
ListCommand.class,
GetSubmissionCommand.class,
GetAllSubmissionsCommand.class},
mixinStandardHelpOptions = true) mixinStandardHelpOptions = true)
public class CLI implements Runnable { public class CLI implements Runnable {
private static final String LOGO = "/splash_screen_banner.txt"; private static final String LOGO = "/splash_screen_banner.txt";
...@@ -24,6 +32,7 @@ public class CLI implements Runnable { ...@@ -24,6 +32,7 @@ public class CLI implements Runnable {
int exitCode = commandLine.execute(args); int exitCode = commandLine.execute(args);
exit(exitCode); exit(exitCode);
} }
@Override @Override
public void run() { public void run() {
final CommandLine.Help.Ansi ansi = new CommandLine.Help.ColorScheme.Builder().ansi(); final CommandLine.Help.Ansi ansi = new CommandLine.Help.ColorScheme.Builder().ansi();
......
package dev.fitko.fitconnect.cli; package dev.fitko.fitconnect.cli.commands;
import dev.fitko.fitconnect.api.config.ApplicationConfig; import dev.fitko.fitconnect.api.config.ApplicationConfig;
import dev.fitko.fitconnect.client.bootstrap.ApplicationConfigLoader; import dev.fitko.fitconnect.client.bootstrap.ApplicationConfigLoader;
......
package dev.fitko.fitconnect.cli.commands;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
@Parameters(
commandNames = {CreateTestKeysCommand.CREATE_TEST_KEYS_COMMAND_NAME},
commandDescription = "Generates JWK test keys for encryption, decryption, signing and signature validation",
separators = "="
)
public class CreateTestKeysCommand {
public static final String CREATE_TEST_KEYS_COMMAND_NAME = "keygen";
@Parameter(names = {"--outDir"}, description = "Output directory folder where the generated test keys are written to", arity = 1)
public String outputDir;
@Parameter(names = {"--withConfig"}, description = "Generates config.yaml with paths of the generated keys", arity = 1)
public boolean generateConfig;
}
package dev.fitko.fitconnect.cli.commands; package dev.fitko.fitconnect.cli.commands;
import com.beust.jcommander.Parameter; import dev.fitko.fitconnect.api.config.ApplicationConfig;
import com.beust.jcommander.Parameters; import dev.fitko.fitconnect.api.domain.model.submission.SubmissionForPickup;
import dev.fitko.fitconnect.cli.util.UUIDConverter; import dev.fitko.fitconnect.client.SubscriberClient;
import dev.fitko.fitconnect.cli.util.UUIDValidator; import dev.fitko.fitconnect.client.bootstrap.ApplicationConfigLoader;
import dev.fitko.fitconnect.client.bootstrap.ClientFactory;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import picocli.CommandLine;
import java.nio.file.Path;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
@Parameters( @CommandLine.Command(name = "get", description = "Fetch a submission by id", mixinStandardHelpOptions = true)
commandNames = {GetAllSubmissionsCommand.GET_ALL_CMD_NAME}, public class GetAllSubmissionsCommand implements Runnable {
commandDescription = "Fetches all available submission for a destination",
separators = "="
)
public class GetAllSubmissionsCommand {
public static final String GET_ALL_CMD_NAME = "all"; private static final Logger LOGGER = LoggerFactory.getLogger(GetAllSubmissionsCommand.class);
@Parameter(names = { "--config" }, description = "Path to the config yaml", arity = 1) @CommandLine.Option(names = {"--config"}, description = "Path to the config yaml", required = true)
public String config; public Path configPath;
@Parameter(names = { "--destinationId" }, description = "Unique destination identifier in UUID format", converter = UUIDConverter.class, validateWith = UUIDValidator.class, arity = 1, required = true) @CommandLine.Option(names = {"-d", "--dest"}, required = true, description = "UUID of the destination")
public UUID destinationId; private UUID destinationId;
@Parameter(names = { "--target" }, description = "Target folder where attachments and data is written to", arity = 1) @CommandLine.Option(names = {"--target"}, description = "Target folder where attachments and data is written to", required = false)
public String targetFolder; public Path targetFolder;
@Override
@SneakyThrows
public void run() {
LOGGER.info("Getting all available submissions for destination {}", destinationId);
final ApplicationConfig config = ApplicationConfigLoader.loadConfigFromPath(configPath);
final SubscriberClient subscriberClient = ClientFactory.createSubscriberClient(config);
final GetSubmissionCommand getSubmissionCommand = new GetSubmissionCommand();
final Set<SubmissionForPickup> submissions = subscriberClient.getAvailableSubmissionsForDestination(destinationId);
submissions.forEach(submission -> getSubmissionCommand.getSubmission(subscriberClient, submission.getSubmissionId(), targetFolder));
}
} }
package dev.fitko.fitconnect.cli.commands;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import dev.fitko.fitconnect.cli.util.UUIDConverter;
import dev.fitko.fitconnect.cli.util.UUIDValidator;
import java.util.UUID;
@Parameters(
commandNames = {GetOneSubmissionCommand.GET_CMD_NAME},
commandDescription = "Fetches one submission by id",
separators = "="
)
public class GetOneSubmissionCommand {
public static final String GET_CMD_NAME = "get";
@Parameter(names = { "--config" }, description = "Path to the config yaml", arity = 1)
public String config;
@Parameter(names = { "--submissionId" }, description = "Unique submission identifier in UUID format", converter = UUIDConverter.class, validateWith = UUIDValidator.class, arity = 1, required = true)
public UUID submissionId;
@Parameter(names = { "--target" }, description = "Target folder where attachments and data is written to", arity = 1)
public String targetFolder;
}
package dev.fitko.fitconnect.cli.commands;
import dev.fitko.fitconnect.api.config.ApplicationConfig;
import dev.fitko.fitconnect.cli.util.SubmissionWriter;
import dev.fitko.fitconnect.client.SubscriberClient;
import dev.fitko.fitconnect.client.bootstrap.ApplicationConfigLoader;
import dev.fitko.fitconnect.client.bootstrap.ClientFactory;
import dev.fitko.fitconnect.core.utils.StopWatch;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import picocli.CommandLine;
import java.nio.file.Path;
import java.util.UUID;
@CommandLine.Command(name = "get", description = "Fetch a submission by id", mixinStandardHelpOptions = true)
public class GetSubmissionCommand implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(GetSubmissionCommand.class);
@CommandLine.Option(names = {"-c", "--config"}, required = true, description = "Path to the config yaml with subscriber clientId and clientSecret")
public Path configPath;
@CommandLine.Option(names = {"-id", "--submissionId"}, description = "Unique submission identifier in UUID format", required = true)
public UUID submissionId;
@CommandLine.Option(names = {"--target"}, description = "Target folder where attachments and data is written to", required = false)
public Path targetFolder;
@Override
public void run() {
LOGGER.info("Getting submission for id {}", submissionId);
final ApplicationConfig config = ApplicationConfigLoader.loadConfigFromPath(configPath);
final SubscriberClient subscriberClient = ClientFactory.createSubscriberClient(config);
getSubmission(subscriberClient, submissionId, targetFolder);
}
@SneakyThrows
public void getSubmission(SubscriberClient subscriberClient, UUID submissionId, Path targetFolder) {
LOGGER.info("Getting submission for id {}", submissionId);
final var startTime = StopWatch.start();
final var submission = subscriberClient.requestSubmission(submissionId);
LOGGER.info("Submission download took {}", StopWatch.stop(startTime));
if (submission == null) {
LOGGER.info("No submission found for submission id {}", submissionId);
} else {
submission.acceptSubmission();
SubmissionWriter.writeSubmissionData(submission, getTargetFolderPath(targetFolder, submissionId));
}
}
private String getTargetFolderPath(Path targetFolder, UUID submissionId) {
return targetFolder != null ? targetFolder + "/" + submissionId : submissionId.toString();
}
}
package dev.fitko.fitconnect.cli; package dev.fitko.fitconnect.cli.commands;
import dev.fitko.fitconnect.api.domain.crypto.JWKPair; import dev.fitko.fitconnect.api.domain.crypto.JWKPair;
import dev.fitko.fitconnect.tools.keygen.KeyWriter; import dev.fitko.fitconnect.tools.keygen.KeyWriter;
...@@ -10,12 +10,11 @@ import picocli.CommandLine; ...@@ -10,12 +10,11 @@ import picocli.CommandLine;
import picocli.CommandLine.Option; import picocli.CommandLine.Option;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.concurrent.Callable;
import static dev.fitko.fitconnect.tools.keygen.TestKeyBuilder.DEFAULT_KEY_SIZE; import static dev.fitko.fitconnect.tools.keygen.TestKeyBuilder.DEFAULT_KEY_SIZE;
@CommandLine.Command(name = "keygen", description = "Generate JWKs for TEST usage", mixinStandardHelpOptions = true) @CommandLine.Command(name = "keygen", description = "Generate JWKs for TEST usage", mixinStandardHelpOptions = true)
public class KeyGenCommand implements Callable<Integer> { public class KeyGenCommand implements Runnable {
private static final Logger LOGGER = LoggerFactory.getLogger(KeyGenCommand.class); private static final Logger LOGGER = LoggerFactory.getLogger(KeyGenCommand.class);
...@@ -26,8 +25,7 @@ public class KeyGenCommand implements Callable<Integer> { ...@@ -26,8 +25,7 @@ public class KeyGenCommand implements Callable<Integer> {
private boolean generateConfig; private boolean generateConfig;
@Override @Override
public Integer call() { public void run() {
LOGGER.info("Generating Test JWKs ..."); LOGGER.info("Generating Test JWKs ...");
final JWKPair encryptionKeyPair = TestKeyBuilder.generateEncryptionKeyPair(DEFAULT_KEY_SIZE); final JWKPair encryptionKeyPair = TestKeyBuilder.generateEncryptionKeyPair(DEFAULT_KEY_SIZE);
...@@ -43,6 +41,5 @@ public class KeyGenCommand implements Callable<Integer> { ...@@ -43,6 +41,5 @@ public class KeyGenCommand implements Callable<Integer> {
} }
KeyWriter.writeKeys(settingsBuilder.build()); KeyWriter.writeKeys(settingsBuilder.build());
return null;
} }
} }
package dev.fitko.fitconnect.cli.commands;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import dev.fitko.fitconnect.cli.util.UUIDConverter;
import dev.fitko.fitconnect.cli.util.UUIDValidator;
import java.util.UUID;
@Parameters(
commandNames = {ListAllSubmissionsCommand.LIST_CMD_NAME},
commandDescription = "Lists available submissions",
separators = "="
)
public class ListAllSubmissionsCommand {
public static final String LIST_CMD_NAME = "list";
@Parameter(names = { "--config" }, description = "Path to the config yaml", arity = 1)
public String config;
@Parameter(names = { "--destinationId" }, description = "Unique destination identifier in UUID format", converter = UUIDConverter.class, validateWith = UUIDValidator.class, arity = 1, required = true)
public UUID destinationId;
}
package dev.fitko.fitconnect.cli; package dev.fitko.fitconnect.cli.commands;
import dev.fitko.fitconnect.api.config.ApplicationConfig; import dev.fitko.fitconnect.api.config.ApplicationConfig;
import dev.fitko.fitconnect.api.domain.model.submission.SubmissionForPickup; import dev.fitko.fitconnect.api.domain.model.submission.SubmissionForPickup;
...@@ -21,7 +21,7 @@ public class ListCommand implements Runnable { ...@@ -21,7 +21,7 @@ public class ListCommand implements Runnable {
@CommandLine.Option(names = {"-c", "--config"}, required = true, description = "Path to the config yaml with subscriber clientId and clientSecret") @CommandLine.Option(names = {"-c", "--config"}, required = true, description = "Path to the config yaml with subscriber clientId and clientSecret")
private Path configPath; private Path configPath;
@CommandLine.Option(names = {"-d", "--dest"}, required = true, description = "UUID of the destinationId to poll") @CommandLine.Option(names = {"-d", "--dest"}, required = true, description = "UUID of the destination to poll")
private UUID destinationId; private UUID destinationId;
@Override @Override
......
package dev.fitko.fitconnect.cli.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import dev.fitko.fitconnect.api.domain.model.attachment.Attachment;
import dev.fitko.fitconnect.api.domain.model.metadata.Metadata;
import dev.fitko.fitconnect.api.domain.subscriber.ReceivedSubmission;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class SubmissionWriter {
private static final Logger LOGGER = LoggerFactory.getLogger(SubmissionWriter.class);
private static final ObjectWriter JSON_WRITER = new ObjectMapper().writerWithDefaultPrettyPrinter();
public static void writeSubmissionData(final ReceivedSubmission receivedSubmission, final String dataDirPath) throws IOException {
LOGGER.info("Creating data directory for submission in {}", dataDirPath);
Files.createDirectories(Path.of(dataDirPath));
final var fileEnding = AttachmentDataType.getFileTypeFromMimeType(receivedSubmission.getDataMimeType());
final var filePath = Path.of(dataDirPath + "/data." + fileEnding);
LOGGER.info("Writing data.{}", fileEnding);
Files.write(filePath, receivedSubmission.getDataAsString().getBytes(StandardCharsets.UTF_8));
LOGGER.info("Writing metadata.json");
final Metadata metadata = receivedSubmission.getMetadata();
Files.write(Path.of(dataDirPath, "metadata.json"), JSON_WRITER.writeValueAsString(metadata).getBytes());
final List<Attachment> attachments = receivedSubmission.getAttachments();
for (int i = 0; i < attachments.size(); i++) {
final Attachment attachment = attachments.get(i);
final String filename = getAttachmentFilename(attachment, i);
LOGGER.info("Writing attachment {}", filename);
final Path tragetPath = Path.of(dataDirPath, filename);
if (attachment.isInMemoryAttachment()) {
Files.write(tragetPath, attachment.getDataAsBytes());
} else {
try (OutputStream os = Files.newOutputStream(tragetPath)) {
attachment.getDataAsInputStream().transferTo(os);
}
}
}
}
private static String getAttachmentFilename(Attachment attachment, int i) {
if (attachment.getFileName() == null) {
if (attachment.getMimeType() != null) {
return "attachment_" + i + "." + attachment.getMimeType().split("/")[1];
}
return attachment + "_" + i;
}
return attachment.getFileName();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment