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

org.apache.bookkeeper.tools.cli.BookKeeperCLI Maven / Gradle / Ivy

There is a newer version: 4.17.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.bookkeeper.tools.cli;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.google.common.annotations.VisibleForTesting;
import java.net.MalformedURLException;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.bookkeeper.conf.ServerConfiguration;
import org.apache.bookkeeper.tools.cli.commands.CmdBase;
import org.apache.bookkeeper.tools.cli.commands.CmdBookie;
import org.apache.bookkeeper.tools.cli.commands.CmdClient;
import org.apache.bookkeeper.tools.cli.commands.CmdCluster;
import org.apache.bookkeeper.tools.cli.commands.CmdMetadata;
import org.apache.commons.configuration.ConfigurationException;

/**
 * BookKeeper CLI.
 */
@Slf4j
public class BookKeeperCLI {

    /**
     * Make this command map static. This provides a way to plugin different sub commands.
     */
    private static final Map commandMap;

    static {
        commandMap = new TreeMap<>();

        // build the default command map
        commandMap.put("bookie", CmdBookie.class);
        commandMap.put("client", CmdClient.class);
        commandMap.put("cluster", CmdCluster.class);
        commandMap.put("metadata", CmdMetadata.class);
    }

    static JCommander newJCommander() {
        return new JCommander();
    }

    @SuppressWarnings("unchecked")
    @VisibleForTesting
    public static Object newCommandInstance(Class cls, ServerConfiguration config) throws Exception {
        return cls.getConstructor(ServerConfiguration.class).newInstance(config);
    }

    @SuppressWarnings("unchecked")
    @VisibleForTesting
    public static Object newCommandInstance(Class cls,
                                            ServerConfiguration config,
                                            JCommander commander) throws Exception {
        return cls.getConstructor(ServerConfiguration.class, JCommander.class)
            .newInstance(config, commander);
    }

    public static void registerSubcommand(String commandName, Class commandClass) {
        synchronized (commandMap) {
            commandMap.put(commandName, commandClass);
        }
    }

    public static void unregisterSubcommand(String commandName) {
        synchronized (commandMap) {
            commandMap.remove(commandName);
        }
    }

    @Getter(AccessLevel.PACKAGE)
    static class ShellArguments {

        @Parameter(names = { "-c", "--conf" }, description = "Bookie Configuration File")
        private String configFile = null;

        @Parameter(names = { "-h", "--help" }, description = "Show this help message")
        private boolean help = false;

    }

    @Getter(value = AccessLevel.PACKAGE)
    private final ShellArguments shellArgs;
    @Getter(value = AccessLevel.PACKAGE)
    private final JCommander commander;
    private final ServerConfiguration config;

    BookKeeperCLI() throws Exception {
        this.shellArgs = new ShellArguments();
        this.commander = newJCommander();
        this.commander.setProgramName("bookkeeper-cli");
        this.commander.addObject(shellArgs);

        this.config = new ServerConfiguration();
    }

    boolean setupShell() {
        for (Entry entry : commandMap.entrySet()) {
            try {
                Object obj = newCommandInstance(entry.getValue(), config);
                log.info("Setup command {}", entry.getValue());
                this.commander.addCommand(
                    entry.getKey(),
                    obj);
            } catch (Exception e) {
                System.err.println("Fail to load sub command '" + entry.getKey() + "' : " + e.getMessage());
                e.printStackTrace();
                return false;
            }
        }
        return true;
    }

    @VisibleForTesting
    boolean runArgs(String... args) {
        return run(args);
    }

    boolean run(String[] args) {
        if (!setupShell()) {
            // fail to setup the shell, fail this command.
            return false;
        }

        if (args.length == 0) {
            commander.usage();
            return false;
        }

        int cmdPos;
        for (cmdPos = 0; cmdPos < args.length; cmdPos++) {
            if (commandMap.containsKey(args[cmdPos])) {
                break;
            }
        }

        try {
            commander.parse(Arrays.copyOfRange(args, 0, Math.min(cmdPos, args.length)));
        } catch (Exception e) {
            System.err.println(e.getMessage());
            System.err.println();
            commander.usage();
            return false;
        }

        if (shellArgs.help) {
            commander.usage();
            return false;
        }

        if (null != shellArgs.configFile) {
            try {
                config.loadConf(Paths.get(shellArgs.configFile).toUri().toURL());
            } catch (ConfigurationException | MalformedURLException e) {
                System.err.println("Failed to load configuration file '" + shellArgs.configFile + "' : "
                    + e.getMessage());
                System.err.println();
                commander.usage();
                return false;
            }
        }

        log.info("cmd pos = {}", cmdPos);

        if (cmdPos == args.length) {
            commander.usage();
            return false;
        } else {
            String cmd = args[cmdPos];
            JCommander subCmd = commander.getCommands().get(cmd);
            CmdBase subCmdObj = (CmdBase) subCmd.getObjects().get(0);
            String[] subCmdArgs = Arrays.copyOfRange(args, cmdPos + 1, args.length);

            log.info("Run sub command : {}", subCmdArgs);

            return subCmdObj.run(subCmdArgs);
        }
    }

    public static void main(String[] args) throws Exception {
        BookKeeperCLI shell = new BookKeeperCLI();

        if (shell.run(args)) {
            System.exit(0);
        } else {
            System.exit(1);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy