3

I'm writing a JAVA-Console-Application. After the user started the jar he should get a Commandline like the Linux shell, where he can enter commands. This is something I never programmed before. Normaly im writing GUI's or I start the jar with some Arguments which are parsed.

Basicly I have 2 Questions:

  1. Is there a third-party-libary which helps reading the user-input from the command line parsing the commands and generating the prompt? To parse args passed in the main class I normally use by Apache Commons CLI. Is it use full here, too or is there a better way?
  2. Is there a best practice to provide an "infinite input"? All solutions I found are 10 or more years old like:

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    while(true){
        System.out.print("Enter String");
        String s = br.readLine();
    }
    

    Is this still best practice or is there a better way today?

centic
  • 15,565
  • 9
  • 68
  • 125
Daniel
  • 1,027
  • 1
  • 8
  • 23
  • 1
    "Questions asking us to recommend or find a book, tool, software library, tutorial or other off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, [describe the problem](http://meta.stackoverflow.com/questions/254393) and what has been done so far to solve it." – Siguza Mar 12 '16 at 00:18
  • What are your concerns with 2? One big advantage is that it doesn't rely on any external libraries... – Stefan Haustein Mar 13 '16 at 13:32

2 Answers2

5

I am using the library jline2, i.e. with this it's as simple as:

    InputStream inStream = new FileInputStream(FileDescriptor.in);
    ConsoleReader reader = new ConsoleReader("App", inStream, System.out, null);

    reader.setPrompt("> ");

    reader.addCompleter(new FileNameCompleter());
    reader.addCompleter(new StringsCompleter(Arrays.asList(new String[] {
            "cmd1",
            "exit",
            "quit",
    })));

    String line;
    PrintWriter out = new PrintWriter(reader.getOutput());

    while ((line = reader.readLine()) != null) {
        if (line.startsWith("cmd1")) {
            String[] cmd = line.split("\\s+");
            if(cmd.length < 2) {
                out.println("Invalid command");
                help(out);
            } else {
                ... do work
            }
        } else if (line.equalsIgnoreCase("quit") || line.equalsIgnoreCase("exit")) {
            break;
        } else {
            help(out);
        }
    }

    // ensure that all content is written to the screen at the end to make unit tests stable
    reader.flush();
centic
  • 15,565
  • 9
  • 68
  • 125
1

I am also in the process of building an application with a command line-like interface. The way that I designed mine was create one class called "command" which is the superclass for all commands. Make 2 abstract methods, "execute," and "getName()".

Then, override the getName() method in each command child class so that it will return the command that the user will enter as a string. (you don't have to use the getName(), any other method name will work, or you could override toString(), but this isn't ideal as it doesn't force the child class to have its own implementation)

Have another the method called "execute" take the remainder of the command entry (the parameters) and the logic for each command.

Take the user input, then you can just try to match it with the command.getName() method by iterating through a list of all commands, instead of using a huge case-switch section of code. It will get ugly otherwise.

FWIW, I have the console class as a Singleton so that it can easily be accessed from any other part of the application.

Preston Garno
  • 1,175
  • 10
  • 33