Java tutorial
/* * Copyright (c) 2016-2017, Joyent, Inc. 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 http://mozilla.org/MPL/2.0/. */ package com.joyent.manta.cli; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; import com.joyent.manta.client.MantaClient; import com.joyent.manta.client.MantaObject; import com.joyent.manta.client.MantaObjectResponse; import com.joyent.manta.client.crypto.SecretKeyUtils; import com.joyent.manta.config.ChainedConfigContext; import com.joyent.manta.config.ConfigContext; import com.joyent.manta.config.DefaultsConfigContext; import com.joyent.manta.config.EnvVarConfigContext; import com.joyent.manta.config.MapConfigContext; import com.joyent.manta.util.MantaUtils;; import com.joyent.manta.util.MantaVersion; import org.apache.commons.io.IOUtils; import org.slf4j.LoggerFactory; import picocli.CommandLine; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UncheckedIOException; import java.nio.file.Path; import java.nio.file.Paths; import java.security.NoSuchAlgorithmException; import java.util.List; import java.util.stream.Stream; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; @CommandLine.Command(name = "java-manta-cli", sortOptions = false, header = { "@|cyan . . |@", "@|cyan |_.-._| |@", "@|cyan ./ \\. |@", "@|cyan _.-'` `'-._ |@", "@|cyan .-' Java '-. |@", "@|cyan ,'_.._ Manta _.._', |@", "@|cyan '` `'-. .-'` `' |@", "@|cyan '. .' |@", "@|cyan \\_/|\\_/ |@", "@|cyan | |@", "@|cyan | |@", "@|cyan | |@", "" }, description = { "", "Basic manta cli commands using the java-client. Not a stable interface.", }, optionListHeading = "@|bold %nOptions|@:%n", subcommands = { MantaCLI.ConnectTest.class, MantaCLI.DumpConfig.class, MantaCLI.GenerateKey.class, MantaCLI.ListDir.class, MantaCLI.GetFile.class, MantaCLI.PutFile.class, MantaCLI.ObjectInfo.class, MantaCLI.ValidateKey.class }) // Documented through CLI annotations @SuppressWarnings({ "checkstyle:javadocmethod", "checkstyle:javadoctype", "checkstyle:javadocvariable" }) public final class MantaCLI { @CommandLine.Option(names = { "-v", "--version" }, help = true) private boolean isVersionRequested; @CommandLine.Option(names = { "-h", "--help" }, help = true) private boolean isHelpRequested; private MantaCLI() { } public static void main(final String[] args) { final CommandLine application = new CommandLine(new MantaCLI()); application.registerConverter(Path.class, Paths::get); List<CommandLine> parsedCommands = null; try { parsedCommands = application.parse(args); } catch (CommandLine.ParameterException ex) { System.err.println(ex.getMessage()); CommandLine.usage(new MantaCLI(), System.err); return; } MantaCLI cli = (MantaCLI) parsedCommands.get(0).getCommand(); if (cli.isHelpRequested) { application.usage(System.out); return; } if (cli.isVersionRequested) { System.out.println("java-manta-client: " + MantaVersion.VERSION); return; } if (parsedCommands.size() == 1) { // no subcmd given application.usage(System.err); return; } CommandLine deepest = parsedCommands.get(parsedCommands.size() - 1); MantaSubCommand subcommand = (MantaSubCommand) deepest.getCommand(); if (subcommand.isHelpRequested) { CommandLine.usage(deepest.getCommand(), System.err); return; } if (subcommand.logLevel != null) { Logger root = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME); root.setLevel(Level.valueOf(subcommand.logLevel.toString())); } subcommand.run(); } @CommandLine.Command(sortOptions = false, headerHeading = "@|bold,underline Usage:|@%n%n", synopsisHeading = "%n", descriptionHeading = "%n@|bold,underline Description:|@%n%n", parameterListHeading = "%n@|bold,underline Parameters:|@%n", optionListHeading = "%n@|bold,underline Options:|@%n") public abstract static class MantaSubCommand { public enum CommandLogLevel { TRACE, DEBUG, INFO, WARN, ERROR }; protected static final String BR = System.lineSeparator(); protected static final String INDENT = " "; @CommandLine.Option(names = { "-h", "--help" }, help = true) private boolean isHelpRequested; @CommandLine.Option(names = { "--log-level" }, description = "TRACE, DEBUG, INFO, WARN(default), ERROR") private CommandLogLevel logLevel; public abstract void run(); /** * Builds a new {@link ConfigContext} instance based on defaults and * environment variables. * * @return chained configuration context object */ protected ConfigContext buildConfig() { return new ChainedConfigContext(new DefaultsConfigContext(), new EnvVarConfigContext(), new MapConfigContext(System.getProperties())); } } @CommandLine.Command(name = "connect-test", header = "Try to connect", description = "Attempts to connect to Manta using system properties " + "and environment variables for configuration") public static class ConnectTest extends MantaSubCommand { @Override public void run() { final StringBuilder b = new StringBuilder(); b.append("Creating connection configuration").append(BR); ConfigContext config = buildConfig(); b.append(INDENT).append(ConfigContext.toString(config)).append(BR); b.append("Creating new connection object").append(BR); try (MantaClient client = new MantaClient(config)) { b.append(INDENT).append(client).append(BR); String homeDirPath = config.getMantaHomeDirectory(); b.append("Attempting HEAD request to: ").append(homeDirPath).append(BR); MantaObjectResponse response = client.head(homeDirPath); b.append(INDENT).append(response).append(BR); b.append("Request was successful"); } catch (IOException e) { throw new UncheckedIOException(e); } System.out.println(b.toString()); } } @CommandLine.Command(name = "dump-config", header = "Dumps the configuration used for configuring a Manta client.") public static class DumpConfig extends MantaSubCommand { @Override public void run() { StringBuilder b = new StringBuilder(); ConfigContext config = buildConfig(); b.append(ConfigContext.toString(config)); System.out.println(b.toString()); } } @CommandLine.Command(name = "generate-key", header = "Generate an encryption key", description = "Generates a client-side encryption key with the specified " + "cipher and bits at the specified path.") public static class GenerateKey extends MantaSubCommand { @CommandLine.Parameters(index = "0", description = "cipher to generate key for") private String cipher; @CommandLine.Parameters(index = "1", description = "number of bits of the key") private int bits; @CommandLine.Parameters(index = "2", description = "path to write the key to") private Path path; @Override public void run() { StringBuilder b = new StringBuilder(); try { b.append("Generating key").append(BR); SecretKey key = SecretKeyUtils.generate(cipher, bits); b.append(String.format("Writing [%s-%d] key to [%s]", cipher, bits, path)); SecretKeyUtils.writeKeyToPath(key, path); } catch (NoSuchAlgorithmException e) { System.err.printf("The running JVM [%s/%s] doesn't support the " + "supplied cipher name [%s]", System.getProperty("java.version"), System.getProperty("java.vendor"), cipher); System.err.println(); return; } catch (IOException e) { String msg = String.format("Unable to write key to path [%s]", path); throw new UncheckedIOException(msg, e); } System.out.println(b.toString()); } } @CommandLine.Command(name = "ls", header = "list", description = "List directry contents") public static class ListDir extends MantaSubCommand { @CommandLine.Parameters(index = "0", description = "dir to ls") private String dirPath; @Override public void run() { final StringBuilder b = new StringBuilder(); ConfigContext config = buildConfig(); try (MantaClient client = new MantaClient(config)) { final Stream<MantaObject> objs = client.listObjects(dirPath); objs.forEach(obj -> { b.append(INDENT).append(obj.getPath()).append(BR); }); } catch (IOException e) { throw new UncheckedIOException(e); } System.out.println(b.toString()); } } @CommandLine.Command(name = "get-file", header = "Performs a download of file in Manta", description = "Performs a download of file in Manta.") public static class GetFile extends MantaSubCommand { @CommandLine.Option(names = { "-o", "--output" }, description = "write output to <file> instead of stdout") private String outputFileName; @CommandLine.Option(names = { "-O", "--remote-name" }, description = "write output to a file using remote object" + "name as filename") private boolean inferOutputFileName = false; @CommandLine.Parameters(index = "0", description = "Object path in Manta to download") private String filePath; @Override public void run() { ConfigContext config = buildConfig(); try (MantaClient client = new MantaClient(config)) { OutputStream out = System.out; if (inferOutputFileName) { outputFileName = MantaUtils.lastItemInPath(filePath); } if (outputFileName != null) { out = new FileOutputStream(outputFileName); } InputStream objectStream = client.getAsInputStream(filePath); IOUtils.copyLarge(objectStream, out); objectStream.close(); out.flush(); if (outputFileName != null) { out.close(); } } catch (IOException e) { throw new UncheckedIOException(e); } } } @CommandLine.Command(name = "put-file", header = "Performs a put of a local file to Manta", description = "Performs a put of a local file to Mantan.") public static class PutFile extends MantaSubCommand { @CommandLine.Parameters(index = "0", description = "file to upload/put") private String filePath; @CommandLine.Parameters(index = "1", description = "path in Manta to upload to") private String mantaPath; @Override public void run() { final StringBuilder b = new StringBuilder(); b.append("Creating connection configuration").append(BR); ConfigContext config = buildConfig(); b.append(INDENT).append(ConfigContext.toString(config)).append(BR); b.append("Creating new connection object").append(BR); try (MantaClient client = new MantaClient(config)) { b.append(INDENT).append(client).append(BR); b.append("Attempting PUT request to: ").append(filePath).append(BR); File file = new File(filePath); MantaObjectResponse response = client.put(mantaPath, file); b.append(response.toString()); b.append("Request was successful"); } catch (IOException e) { throw new UncheckedIOException(e); } System.out.println(b.toString()); } } @CommandLine.Command(name = "object-info", header = "show HTTP headers for a Manta object", description = "show HTTP headers for a Manta object.") public static class ObjectInfo extends MantaSubCommand { @CommandLine.Parameters(index = "0", description = "path in Manta to check") private String mantaPath; @Override public void run() { ConfigContext config = buildConfig(); try (MantaClient client = new MantaClient(config)) { MantaObjectResponse response = client.head(mantaPath); System.out.println(response.toString()); } catch (IOException e) { throw new UncheckedIOException(e); } } } @CommandLine.Command(name = "validate-key", header = "Validate an encryption key", description = "Validates that the supplied key is supported by the " + "SDK's client-side encryption functionality.") public static class ValidateKey extends MantaSubCommand { @CommandLine.Parameters(index = "0", description = "cipher to validate the key against") private String cipher; @CommandLine.Parameters(index = "1", description = "path to read the key from") private Path path; @Override public void run() { StringBuilder b = new StringBuilder(); try { b.append(String.format("Loading key from path [%s]", path)).append(BR); SecretKeySpec key = SecretKeyUtils.loadKeyFromPath(path, cipher); if (key.getAlgorithm().equals(cipher)) { b.append("Cipher of key is [").append(cipher).append("] as expected").append(BR); } else { b.append("Cipher of key is [").append(key.getAlgorithm()) .append("] - it doesn't match the expected cipher of [").append(cipher).append("]") .append(BR); } b.append("Key format is [").append(key.getFormat()).append("]").append(BR); } catch (NoSuchAlgorithmException e) { System.err.printf("The running JVM [%s/%s] doesn't support the " + "supplied cipher name [%s]", System.getProperty("java.version"), System.getProperty("java.vendor"), cipher); System.err.println(); return; } catch (IOException e) { String msg = String.format("Unable to read key from path [%s]", path); throw new UncheckedIOException(msg, e); } System.out.println(b.toString()); } } }