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

org.apache.nifi.toolkit.cli.CLIMain Maven / Gradle / Ivy

There is a newer version: 2.1.0
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.nifi.toolkit.cli;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.nifi.registry.client.NiFiRegistryClient;
import org.apache.nifi.toolkit.cli.api.ClientFactory;
import org.apache.nifi.toolkit.cli.api.Command;
import org.apache.nifi.toolkit.cli.api.CommandGroup;
import org.apache.nifi.toolkit.cli.api.Context;
import org.apache.nifi.toolkit.cli.api.Session;
import org.apache.nifi.toolkit.cli.impl.client.NiFiClientFactory;
import org.apache.nifi.toolkit.cli.impl.client.NiFiRegistryClientFactory;
import org.apache.nifi.toolkit.cli.impl.client.nifi.NiFiClient;
import org.apache.nifi.toolkit.cli.impl.command.CommandFactory;
import org.apache.nifi.toolkit.cli.impl.command.CommandProcessor;
import org.apache.nifi.toolkit.cli.impl.context.StandardContext;
import org.apache.nifi.toolkit.cli.impl.session.InMemorySession;
import org.apache.nifi.toolkit.cli.impl.session.PersistentSession;
import org.jline.reader.Completer;
import org.jline.reader.EndOfFileException;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;
import org.jline.reader.ParsedLine;
import org.jline.reader.UserInterruptException;
import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths;
import java.util.Map;

/**
 * Main entry point for the CLI.
 *
 * If the main method is executed with no arguments, then the interactive shell is launched.
 *
 * If the main method is executed with arguments, then a single command will be executed, and the process will exit.
 */
public class CLIMain {

    public static final String SHELL_NAME = "nifi-registry";
    public static final String PROMPT = "#> ";
    public static final String BANNER_FILE = "nifi-banner.txt";
    public static final String SESSION_PERSISTENCE_FILE = ".nifi-cli.config";

    public static void main(String[] args) throws IOException {
        if (args == null || args.length == 0) {
            runInteractiveCLI();
        } else {
            // in standalone mode we want to make sure the process exits with the correct status
            try {
                final int returnCode = runSingleCommand(args);
                System.exit(returnCode);
            } catch (Exception e) {
                // shouldn't really get here, but just in case
                e.printStackTrace();
                System.exit(-1);
            }
        }
    }

    /**
     * Runs the interactive CLI.
     *
     * @throws IOException if an error occurs
     */
    private static void runInteractiveCLI() throws IOException {
        //Logger.getLogger("org.jline").setLevel(Level.FINE);
        try (final Terminal terminal = TerminalBuilder.builder()
                .name(SHELL_NAME)
                .system(true)
                .nativeSignals(true)
                .signalHandler(Terminal.SignalHandler.SIG_IGN)
                .build();
             final PrintStream output = new PrintStream(terminal.output(), true)) {

            printHeader(BANNER_FILE, output);

            final Context context = createContext(output, true);

            final Map topLevelCommands = CommandFactory.createTopLevelCommands(context);
            final Map commandGroups = CommandFactory.createCommandGroups(context);

            final CommandProcessor commandProcessor = new CommandProcessor(topLevelCommands, commandGroups, context);
            final Completer completer = new CLICompleter(topLevelCommands.values(), commandGroups.values());

            final LineReader reader = LineReaderBuilder.builder()
                    .appName(SHELL_NAME)
                    .terminal(terminal)
                    .completer(completer)
                    .build();
            reader.setOpt(LineReader.Option.AUTO_FRESH_LINE);
            reader.unsetOpt(LineReader.Option.INSERT_TAB);

            while (true) {
                try {
                    final String line = reader.readLine(PROMPT);
                    if (StringUtils.isBlank(line)) {
                        continue;
                    }

                    final ParsedLine parsedLine = reader.getParsedLine();
                    final String[] parsedArgs = parsedLine.words().toArray(new String[parsedLine.words().size()]);
                    commandProcessor.process(parsedArgs);
                } catch (UserInterruptException e) {
                    // Ignore
                } catch (EndOfFileException e) {
                    return;
                }
            }
        }
    }

    /**
     * Handles running a single command and exiting, non-interactive mode.
     *
     * @param args the args passed in from the command line
     */
    public static int runSingleCommand(final String[] args) {
        final Context context = createContext(System.out, false);
        final Map topLevelCommands = CommandFactory.createTopLevelCommands(context);
        final Map commandGroups = CommandFactory.createCommandGroups(context);

        final CommandProcessor commandProcessor = new CommandProcessor(topLevelCommands, commandGroups, context);
        return commandProcessor.process(args);
    }

    private static Context createContext(final PrintStream output, final boolean isInteractive) {
        Session session;

        final String userHomeValue = System.getProperty("user.home");
        final File userHome = Paths.get(userHomeValue).toFile();

        if (!userHome.exists() || !userHome.canRead() || !userHome.canWrite()) {
            session = new InMemorySession();
            if (isInteractive) {
                output.println();
                output.println("Unable to create session from " + userHomeValue + ", falling back to in-memory session");
                output.println();
            }
        } else {
            final InMemorySession inMemorySession = new InMemorySession();
            final File sessionState = new File(userHome.getAbsolutePath(), SESSION_PERSISTENCE_FILE);

            try {
                if (!sessionState.exists()) {
                    sessionState.createNewFile();
                }

                final PersistentSession persistentSession = new PersistentSession(sessionState, inMemorySession);
                persistentSession.loadSession();
                session = persistentSession;

                if (isInteractive) {
                    output.println();
                    output.println("Session loaded from " + sessionState.getAbsolutePath());
                    output.println();
                }
            } catch (Exception e) {
                session = inMemorySession;

                if (isInteractive) {
                    output.println();
                    output.println("Unable to load session from " + sessionState.getAbsolutePath()
                            + ", falling back to in-memory session");
                    output.println();
                }
            }

        }

        final ClientFactory niFiClientFactory = new NiFiClientFactory();
        final ClientFactory nifiRegClientFactory = new NiFiRegistryClientFactory();

        return new StandardContext.Builder()
                .output(output)
                .session(session)
                .nifiClientFactory(niFiClientFactory)
                .nifiRegistryClientFactory(nifiRegClientFactory)
                .interactive(isInteractive)
                .build();
    }

    protected static void printHeader(final String bannerFile, final PrintStream output) throws IOException {
        try (final InputStream bannerInput = CLIMain.class.getClassLoader().getResourceAsStream(bannerFile)) {
            final String bannerContent = IOUtils.toString(bannerInput, StandardCharsets.UTF_8);
            output.println(bannerContent);
            output.println();
            output.println("Type 'help' to see a list of available commands, use tab to auto-complete.");
            output.println();
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy