summaryrefslogtreecommitdiff
path: root/BJC-Utils2/src/main/java/bjc/utils/cli/CLICommander.java
blob: cccb255b0207dac16dc20dec5f07eb95f465c653 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package bjc.utils.cli;

import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Scanner;

/**
 * Runs a CLI interface from the provided set of streams.
 *
 * @author ben
 *
 */
public class CLICommander {
	/*
	 * The streams used for input and normal/error output.
	 */
	private final InputStream	input;
	private final OutputStream	output;
	private final OutputStream	error;

	/*
	 * The command mode to start execution in.
	 */
	private CommandMode initialMode;

	/**
	 * Create a new CLI interface powered by streams.
	 *
	 * @param input
	 *                The stream to get user input from.
	 * @param output
	 *                The stream to send normal output to.
	 * @param error
	 *                The stream to send error output to.
	 */
	public CLICommander(final InputStream input, final OutputStream output, final OutputStream error) {
		if (input == null)
			throw new NullPointerException("Input stream must not be null");
		else if (output == null)
			throw new NullPointerException("Output stream must not be null");
		else if (error == null) throw new NullPointerException("Error stream must not be null");

		this.input = input;
		this.output = output;
		this.error = error;
	}

	/**
	 * Start handling commands from the given input stream.
	 */
	public void runCommands() {
		/*
		 * Setup output streams.
		 */
		final PrintStream normalOutput = new PrintStream(output);
		final PrintStream errorOutput = new PrintStream(error);

		/*
		 * Set up input streams.
		 *
		 * We're suppressing the warning because we might use the input
		 * stream multiple times.
		 */
		@SuppressWarnings("resource")
		final Scanner inputSource = new Scanner(input);

		/*
		 * The mode currently being used to handle commands.
		 *
		 * Used to preserve the initial mode.
		 */
		CommandMode currentMode = initialMode;

		/*
		 * Process commands until we're told to stop.
		 */
		while (currentMode != null) {
			/*
			 * Print out the command prompt, using a custom prompt
			 * if one is specified.
			 */
			if (currentMode.isCustomPromptEnabled()) {
				normalOutput.print(currentMode.getCustomPrompt());
			} else {
				normalOutput.print(currentMode.getName() + ">> ");
			}

			/*
			 * Read in a command.
			 */
			final String currentLine = inputSource.nextLine();

			/*
			 * Handle commands we can handle.
			 */
			if (currentMode.canHandle(currentLine)) {
				final String[] commandTokens = currentLine.split(" ");
				String[] commandArgs = null;

				final int argCount = commandTokens.length;

				/*
				 * Parse args if they are present.
				 */
				if (argCount > 1) {
					commandArgs = Arrays.copyOfRange(commandTokens, 1, argCount);
				}

				/*
				 * Process command.
				 */
				currentMode = currentMode.process(commandTokens[0], commandArgs);
			} else {
				errorOutput.print("Error: Unrecognized command " + currentLine);
			}
		}

		normalOutput.print("Exiting now.");
	}

	/**
	 * Set the initial command mode to use.
	 *
	 * @param initialMode
	 *                The initial command mode to use.
	 */
	public void setInitialCommandMode(final CommandMode initialMode) {
		if (initialMode == null) throw new NullPointerException("Initial mode must be non-zero");

		this.initialMode = initialMode;
	}
}