I have written a CLIInterface in java that takes the necessary flags from the user as a String[].
Here is some sample code:
public static void call(String[] args)
{
try
{
Map<String, Object> cliOptions = new HashMap<>();
for (int i = 0; i < args.length; ++i) {
// override the db directory
if (args[i].equals("--help")) {
printHelp();
System.exit(1);
}
..........
}
I know that you can invoke the method in the command line using something like this:
java -Dexec.mainClass=org.bitcoinj.examples.ForwardingService -Dexec.args=""
but I want to be able to use it like a CLI and have something like this:
ethj --help whereby --help would be args[0] and then from there I could handle it in the call method.
How would one go about doing this?
the easiest way is to write a starter script ethj for your operation system passing the arguments to the java executable.
btw:
you don't need the -Dexec.args="" form, just list the parameters after the main class name...
Related
I want to run a Java program using NodeJS child process.
const util = require('util');
const exec = util.promisify(require('child_process').exec);
let dir = `${__dirname}/runtime/java/main`;
await exec(`javac Test.java`, {cwd: dir});
const { stdout, stderr } = await exec(`java Test`, {cwd: dir});
My Java code is taking multiple scanner run time arguments dynamically:
import java.util.Scanner;
class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter number of test cases");
int count = scanner.nextInt();
for(int i=0; i<count; i++){
String testCaseDescription = scanner.nextLine();
System.out.println("Test case " + i + " is "+testCaseDescription);
}
}
}
How do I pass dynamic run-time parameters to the child process?
As per the documentation of child_process.exec(), the first parameter given to the function is "the command to run, with space-separated arguments".
So, we need to get the command line arguments given to your Node.js script and pass them along to exec().
In Node.js, we can get these arguments via the process.argv property (more about it here).
process.argv is an array, and you will want to exclude the first element (which is the path of the Node.js runtime executing your file) as well as the second element (which is the path to your Node.js script).
You can use the slice() method to get only the portion of the array you want.
Then, you will want to transform the array (minus the first two elements) in a space-separated string.
You can do this by using the join() method.
The final result would look like this:
const util = require('util');
const exec = util.promisify(require('child_process').exec);
async function run() {
const dir = `${__dirname}/runtime/java/main`;
await exec(`javac Test.java`, {cwd: dir});
// Transforming the CLI arguments into a comma-separated string
const cliArguments = process.argv.slice(2).join(' ');
// Executing and passing the CLI arguments
const { stdout, stderr } = await exec(`java Test ${cliArguments}`, {cwd: dir});
}
run();
Let's say I'm writing a bot for a chat (discord, telegram, whatever). The bot can handle chat commands (e.g. !join tells it to join a voice channel on the server).
So somewhere in my code I'd have to parse the command, and I'll have something like
String userMessage = getTheMessageTextSomehow();
// Do something with the message.
I'd like to have a Command class for every one of my commands, and every command would implement a execute() method.
My question is: what's the best practice to create those command objects?
The easiest way would be to have a large CommandFactory or whatever class somwhere, that would be like
if(message.equals(JOIN_MESSAGE) {
return new JoinCommand();
}
if(message.equals(LEAVE_MESSAGE){
return new LeaveCommand();
}
//etc...
That looks like a bad practice and code smell to me.
Is there a better way to do it?
You might want to rely on a Map of Commands.
I'll make it clear that for this usecase, using the Function or Supplier, or whatever standard functional interface is not idiomatic at all. Avoid it.
We can start by building a Command interface
interface Command {
Result execute();
}
Or if you need to accept an argument
interface Command {
Result execute(final Input input);
}
Which will have the required implementations
class JoinCommand implements Command { ... }
class LeaveCommand implements Command { ... }
class NoopCommand implements Command { ... }
And so on.
You'll now need to store those definitions in a key (the command) - value (the implementation) data structure. A Map is perfect for that.
As your command definition will be a String, then
static final Map<String, Command> COMMANDS = new HashMap<>(8);
static {
COMMANDS.put("join", new JoinCommand());
COMMANDS.put("leave", new LeaveCommand());
// And so on
}
The usage is pretty simple
final String userMessage = getTheMessageTextSomehow();
final String commandStr = extractCommand(userMessage);
final Command command = COMMANDS.getOrDefault(commandStr, NOOP_COMMAND);
command.execute();
Or if you'll have to accept an argument
command.execute(yourInput);
You'll also notice I used NOOP_COMMAND, that's just a no-op implementation for Command to avoid dealing with null. It might be, or it might be not, appropriate.
If you're on Java 9+, the Map could also be created using
Map.of(
"join", new JoinCommand(),
"leave", new LeaveCommand(),
// And so on.
)
Usually, it is implemented via mapping. It would be much clearer and readable to implement this with simple Map.
For example:
Map<String, Command> strategies = new HashMap<String, Command>(){{
put(JOIN_MESSAGE, new JoinCommand());
put(LEAVE_MESSAGE, new LeaveCommand());
}};
And its usage:
Command command = strategies.get(messageType);
Moreover, you can define creation strategies (factories) since Java 8 if you need to construct commands depending on some parameters.
Map<String, Function<String, Command>> strategies = new HashMap<String, Command>(){{
put(JOIN_MESSAGE, param -> new JoinCommand(param)); // or JoinCommand::new
put(LEAVE_MESSAGE, param -> new LeaveCommand(param)); // or LeaveCommand::new
}};
And its usage:
Command command = strategies.get(messageType);
command.process(param);
Hello You try Switch Case statement for it, it's easy to understand and in future if you have any changes then it's easy to update the code.
switch(message)
{
case JOIN_MESSAGE:
return new JoinCommand();
break;
case LEAVE_MESSAGE:
return new LeaveCommand();
break;
}
I have a project in RAD. Package is inputFileEdit, and the java class I need is InputFileTest.java.
package inputFileEdit;
public class InputFileTest {
public static void main(String[] args) {
String var1 = args[0];
String var2 = args[1].toLowerCase();
// do stuff with args
}
}
I want to create a new package / java program that can call or instantiate the class InputFileTest above, with arguments, multiple times in parallel. I'm basically going to be bringing back a String list, looping through that list to create parallel threads, each row on the list calling InputFileTest.
Question 1) What's the best way to call InputFileTest? I'm using RAD and I created a new Project, a package called CallerPackage, and a Caller.java inside that package? I also including a "Jar" of the whole InputFileEdit project under /lib via Java Build Path -> Libraries -> Add External Jars. I don't know how to call the class with parameters (I tried something like InputFileEdit ifeObj = new InputFileEdit("parm 1", "parm 2"); or InputFileEdit ifeObj = new InputFileEdit("parm 1 parm 2");) but neither worked so then I tried to just call the jar like Process p = Runtime.getRuntime().exec("java -jar /lib/InputFileEdit.jar parm1 parm2"); or since I want the actual Class InputFileTest, Process p = Runtime.getRuntime().exec(new String[]{"java","-cp","/lib/InputFileEdit.jar", "InputFileTest", "parm1","parm1"});:
package CallerPackage;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
//import inputFileEdit.*;
public class Caller {
static int i = 0;
public static void main(String args[]) throws IOException, InterruptedException {
try {
System.out.println("Calling jar");
Process p = Runtime.getRuntime().exec("java -jar /lib/InputFileEdit.jar parm1 parm2");
BufferedInputStream errStrm = new BufferedInputStream(p.getErrorStream());
// get the error stream of the process and print it
for (int i = 0; i < errStrm.available(); i++) {
System.out.println("" + errStrm.read());
}
System.out.println("Called jar");
p.destroy();
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
but this doesn't seem to work either or print out anything helpful. Any ideas of the best way to go about this? I'm only trying to get 1 call to work for now before I loop through my list and call them in parallel. Eventually it'll be calling the jar/class looping through a string arraylist.
you should be able to call the main method in InputFileTest the same way you would call any other static method: InputFileTest.main(args);
However, generally directly calling main is frowned upon. If you are able, I would advise you to take the code in InputFileTest's main, and put it into another, more descriptively named method, something like processFiles.
I have pw_check.java and I need to run it with an argument first and then run it without argument in terminal.
java pw_check -g
java pw_check
But in second command, without argument, the system is throwing exception. How could I handle it to feed my requirement.
Check the code pw_check.java.
Probably there is something like
public static void main(String[] args) {
// Code accessing args[0]
}
This will cause an error if you don't have a parameter.
Modify with a code similar to the following:
public static void main(String[] args) {
String arg = DEFAULT_ARG;
if (args.length == 1) {
arg = args[0];
}
... // Code using arg DEFAULT or passed value
}
I want to make a simple interative shell based on the console where I can write commands like login, help, et cetera.
I first thought of using Enums, but then I didn't know how to implement them neatly without a load of if-else statements, so I decided to go with an array-approach and came up with this:
public class Parser {
private static String[] opts = new String[] {"opt0", "opt1", "opt2", "opt3" ... }
public void parse(String text) {
for(int i = 0; i < opts.length; i++) {
if(text.matches(opts[i]) {
switch(i) {
case 0:
// Do something
case 1:
// Do something-something
case 2:
// Do something else
}
return;
}
}
}
}
But I ended up seeing that this was probably the most rudimentary way of doing something like this, and that there would be problems if I wanted to change the order of the options. How could I make a simpler parser? This way it would work, but it would also have said problems. The use of the program is purely educational, not intended for any serious thing.
A simple approach is to have a HashMap with the key equal to the command text and the value is an instance of class that handle this command. Assuming that the command handler class does not take arguments (but you can easily extend this) you can just use a Runnable instance.
Example code:
Runnable helpHandler = new Runnable() {
public void run(){
// handle the command
}
}
// Define all your command handlers
HashMap<String, Runnable> commandsMap = new HashMap<>(); // Java 7 syntax
commandsMap.put("help",helpHandler);
// Add all your command handlers instances
String cmd; // read the user input
Runnable handler;
if((handler = commandsMap.get(cmd)) != null) {
handler.run();
}
You can easily extend this approach to accept argument by implementing your own interface and subclass it. It is good to use variable arguments if you know the data type e.g. void execute(String ... args)
One solution that comes to mind is actually using Design patterns. You could use the input from the user, as the discriminator for a Factory class.
This factory class will generate an object, with an "execute" method, based on the input. This is called a Command object.
Then you can simply call the method of the object returned from the factory.
No need for a switch statement. If the object is null, then you know the user entered an invalid option, and it abstracts the decision logic away from your input parser.
Hopefully this will help :)