I am developing my own shell(command prompt). [When
a user enters a built-in command, the shell is required to search and execute the respective code accordingly.]
I have created my code using command split, and command parameters in order to store my commands. but one thing I'm confused about is that making a command that is not in the list.
I think of using if statement to print invalid comment (for example)
if (command!="exit")||(command!="about")||(command!="date")||(command!="time")||(command!="hist")||(command!="notepad")
||(command!="")||(command!="hist -h")||(command!="hist -l")||(command!="c"){
System.out.println("invalid command");
}
but this statement is way too much if there are tons of command line.. so is there an easy way of implementing it !?
If this java and all commands are Strings and input command is also a String you can simplify what you are trying to do by creating a list of valid commands and do a contains check.
List<String> validCommands = Arrays.asList("exit", "about", "date");
if (!validCommands.contains(command)) {
System.out.println("invalid command");
}
That being said there are better ways to maintain a list of valid command outside java program such as properties file and load list of valid commands from that file. This will make your program more maintainable.
Use a Map<String, Command>, to keep track of the available commands. If the command is not in the map then it's invalid. For example:
public class Shell {
private final Map<String, Command> supportedCommands;
public Shell(Map<String, Command> supportedCommands) {
this.supportedCommands = supportedCommands;
}
public void execute(String command, String[] args) {
Command c = supportedCommands.get(command);
if (c == null) {
System.out.println("invalid command");
} else {
c.execute(args);
}
}
public interface Command {
public void execute(String[] args);
}
}
Related
I am designing a controller using the command pattern.
The controller has a while loop inside that is scanning for user input. If user input matches a specific String, then a command class is executed. Here is a code snippit:
public Controller(Readable in, Appendable out) {
this.out = out;
this.scan = new Scanner(in);
this.commandMap = this.generateCommands();
}
public void go(Model m) {
while (scan.hasNext()) {
String input = scan.next();
Command command = this.commandMap.get(input);
command.do(m);
}
}
I usually use return to stop the application. However, when I use return inside one of the Command classes, the application keeps running. I think it just goes back to this upper loop.
By the way, all my commands are public void.
Is there a way to exit/close the application from within the command classes? Like a "super" return? Or do I need to no longer make them void and if/else the return in the controller.
EDIT: system.exit(0) doesn't seem like the right solution for me because it doesn't preserve the appendable log? My JUnit tests no longer print out everything I have appended once system.exit(0) is called.
Use this to terminate the entire program:
System.exit(0);
I have some example code where a process builder is used and given two commands to execute, but I can't fully understand what each line of code is doing.
Also the commands don't seem to be actually executing.
Code:
public static void main(String[] args) {
ArrayList<String> commands = new ArrayList(); // commands in a processbuilder is an Arraylist of of strings
commands.add("myfile.pdf"); // supposed to open the file?
commands.add("bash\", \"-c\", \"ls"); // supposed to use ls command in terminal
execute(commands); // should execute the two commands above
System.out.println("executed commands"); // only thing that actually happens
}
public static void execute(ArrayList<String> command) {
try {
ProcessBuilder builder = new ProcessBuilder(command); // a new builder which takes a command passed into the method
Map<String, String> environ = builder.environment(); // ???
Process p = builder.start(); // p is never used?
} catch (Exception e) {
e.printStackTrace();
}
}
I get no errors or warnings.
Tried reading the API on the processbuilder but I didn't really understand it
ProcessBuilder helps to start external processes.
First, the command line parts (executable, parameters) are taken as a list of String, which is very comfortable. ("command" is rather misleading here, since it consists of executable and parameters).
Second, you can edit the environment of the new process (environment variables like "$HOME", "$PATH", etc.).
Your p can be used, for example to check, if the process has finished yet or to retrieve the input/output of the new process. Since you only start the process (fire-and-forget), you don't need it here.
You may also use Runtime.exec(...) to start an external process, which is the historical way to do so, but I think it's more comfortable to use ProcessBuilder.
I have this input stream that checks if I have a certain CAD file open or not. I am doing this by using an input stream to run a tasklist command with the name I want to check. I currently have a boolean that returns true if the specific CAD file isn't open. If the CAD file is open, it returns false. However, I want it to be able to loop this until the CAD file is open because as of right now I have to keep running it in order for it to work. I also need to be able to check this boolean from a separate class. I have it in my main right now so i could test it. My code looks like this...
public class AutoCadCheck {
public static void main(String[] argv) throws Exception {
String notOpen = "INFO: No tasks are running which match the specified criteria";
StringBuilder textBuilder = new StringBuilder();
String command = "tasklist /fi \"windowtitle eq Autodesk AutoCAD 2017 - [123-4567.dwg]";
int i;
InputStream myStream = Runtime.getRuntime().exec(command).getInputStream();
while ((i = myStream.read()) != -1) {
textBuilder.append((char) i);
}
String output = textBuilder.toString();
boolean logical = output.contains(notOpen);
if (logical) {
System.out.println("DWG Not Open");
} else {
System.out.print(output);
}
myStream.close();
}
}
My other class is going to have an 'if statement' that checks whether my boolean "logical" is false, and if so, print something. I have tried every possible method I could think of, but I cannot get it to function the way I want it to. Every other thing I found involving looping an inputstream didn't really apply to my situation. So hopefully someone can help me out in achieving what I want to do.
I would start by moving everything out of main and into a different class. This will make retrieving values and calling specific functions easier. Then create an object of that class in main. Once that is done, I'd create a get method for the boolean variable. Now to focus on the loop. Once the object is created in main, create a conditional loop inside of main which calls the function you need until a different condition is met. This condition might be met once the file is open. After the condition is met, it exits to another loop that relies on another conditional, such as user input.
public class AutoCadCheck {
public static void main(String[] argv) throws Exception {
AutoCadFile file = new AutoCadFile();
//loop 1
//Some conditional so the program will
//continue to run after the file has been found.
// while(){
//loop 2
//check to see if the file is open or not
//while(logical){
//}
//}
}
}
Other class
import java.io.IOException;
import java.io.InputStream;
public class AutoCadFile {
private String notOpen;
private StringBuilder textBuilder;
private String command;
private int i;
private InputStream myStream;
private String output;
private boolean logical;
public AutoCadFile() {
notOpen = "INFO: No tasks are running which match the specified criteria";
textBuilder = new StringBuilder();
command = "tasklist /fi \"windowtitle eq Autodesk AutoCAD 2017 - [123-4567.dwg]";
output = textBuilder.toString();
logical = output.contains(notOpen);
try {
myStream = Runtime.getRuntime().exec(command).getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
}
public void checkForFileOpen() {
try {
while ((i = myStream.read()) != -1) {
textBuilder.append((char) i);
}
if (logical) {
System.out.println("DWG Not Open");
} else {
System.out.print(output);
}
myStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public boolean getFileBoolean() {
return logical;
}
}
My other class is going to have an if statement that checks whether my boolean logical is false ...
Well, logical is a local variable within a method. So no code in another class is going to be able to see it.
There are two common approaches to this kind of thing:
Make the variable (i.e. logical) a field of the relevant class. (Preferably NOT a static field because that leads to other problems.)
Put your code into a method that returns the value you are assigning to logical as a result.
From a design perspective the second approach is preferable ... because it reduces coupling relative to the first. But if your application is tiny, that hardly matters.
I can see a couple of other significant problems with your code.
When you use exec(String), you are relying on the exec method to split the command string into a command name and arguments. Unfortunately, exec does not understand the (OS / shell / whatever specific) rules for quoting, etcetera in commands. So it will make a mess of your quoted string. You need to do the splitting yourself; i.e something like this:
String[] command = new String{} {
"tasklist",
"/fi",
"windowtitle eq Autodesk AutoCAD 2017 - [123-4567.dwg]"
};
Your code potentially leaks an input stream. You should use a "try with resource" to avoid that; e.g.
try (InputStream myStream = Runtime.getRuntime().exec(command).getInputStream()) {
// do stuff
} // the stream is closed automatically ... always
Edit for clarity:
I'm wondering if there is a more efficient way to:
store possible commands (like having some sort of data structure full of valid commands)
check the user-entered command against the stored commands and, if they line up, execute the related methods
I'm finding this question difficult to word, so if any clarification is needed, please let me know.
I'm trying to make a command line calendar, and currently it takes in a lot of commands and arguments separated by "|" like so:
calendar|add|"EventNameString"|"EventDescriptionString"|"EventDate"
help
calendar|print
calendar|remove|"EventNameString"|"EventDate"
I then split the input based on the "|"s. What I'm wondering is what is the best way to interpret successful commands. Currently I am using a bunch of if statements. For example, using the first sample input above, it would check to see if the first argument matches "calendar" and if so, it would check to see if the second command is "add", "print", etc.
I was thinking that there may be some way to store a list of acceptable commands in some sort of data structure and then use the data structure to optimally check if the input matches a valid command (and execute the command if so).
Here is the code for my interpreting of the commands. I can show or explain more if needed:
public StatusMessage parseCommand(String command) {
String[] command_args = command.split("\\|");
if(command_args.length == 0)
return noInputFailure;
if(command_args[0].toLowerCase().equals("help")) {
System.out.println("USAGE");
System.out.println("App: calendar");
System.out.println("");
}
else if(command_args[0].toLowerCase().equals("calendar")) {
String input_arg1 = command_args[1].toLowerCase();
if(input_arg1.equals("add")) {
DateFormat date_format = new SimpleDateFormat("mm/dd/yyyy");
Date date = null;
try {
date = (Date)date_format.parse(command_args[4]);
} catch (ParseException e) {
return dateFormatFailure;
}
calendar.addEvent(command_args[2], command_args[3], date);
return genericSuccess;
}
if(input_arg1.equals("print")) {
calendar.print();
return genericSuccess;
}
}
return genericFailure;
}
So i'm trying to make a text game in java for a project and i have a problem in the main loop.I have the available commands in a hashmap named commands in the class CommandWords and i want to check if the user input exists in the hashmap and if it does to execute the associated object.But i can't exactly find a way.Here is my code.I understand it's probably an if but i don't know how to check.
public void play()
{
System.out.println("Welcome to the world of JZork " +player.name);
printWelcome();
boolean finished = false;
while (! finished) {
Command command = parser.getCommand();
if(command == null) {
System.out.println("I don't understand...");
}
}
}
It is possible to do it the way you said, but you would need to learn to use Java reflection. This isn't THAT hard, but you aren't going to like it.
if (command.equals("quit")) {
quit();
}
else if (command.equals("whatever")) {
whatever();
}
This isn't that elegant, but it's easy to implement.