How to add command arguments to main? Java [closed] - java

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
How can I setup my main to accept command switches?
a source port (-s source_port) and the destination hostname (-h hostname) and port (-p port) of the receiving application as well as the audit log file (-l log_file). One IDS misuse keyword (–m misuse_keyword) and a misuse threshold (-t misuse_threshold) are also specified on the command line.
Basically, I want to have -h localhost set a field named hostname = localhost and -l bob.txt set to a field named inputfile = "bob.txt". How do I do this in Java? I can do this in C and C++ but not sure how to do this in Java.
public static void main(String[] args) {
}

In java if you pass -h hostname -p port you will receive array with 4 elements {"-h", "hostname", "-p", "port"}. So you will have to manage the keys parsing manually.
Here is an example:
private static final String HOST_KEY = "-h";
private static final String PORT_KEY = "-p";
public static void main(String[] args)
{
String host = "";
String port = "";
for(int i=0; i<args.length; i+=2)
{
String key = args[i];
String value = args[i+1];
switch (key)
{
case HOST_KEY : host = value; break;
case PORT_KEY : port = value; break;
}
}
}

Do something like this in your main() method
args = new String[12];
args[0]="-s";
args[1]="source_port";// something integer value "1324"
args[2]="-h";
args[3]="hostname";
args[4]="-p";
args[5]="port";
args[6]="-l";
args[7]="log_file";
args[8]="-m";
args[9]="misuse_keyword";
args[10]="-t";
args[11]="misuse_threshold";
while storing in another variable
int source_port = Integer.parseInt(args[1]);

Just put the argument after your program name. For example
java addProgram 1 2
In your case, it should be
java YourProgramName "-s source_port_value" "-h hostname_value" "-p port_value"
These values will be received by main method in args (String array), then you can iterate the array and get the flag options and their corresponding values to proceed with your operation. I have put the double quotes to make them as a single input value. we have three arguments passing into the main method
Logic to parse the value
public static void main(String[] args){
HashMap<String,String> properties = new HashMap<String,String>();
for(int i=0;i<args.length;i++){
if(args[i].trim().startsWith("-s"))
properties.put("source_port",args[i].split(" ")[1]);
if(args[i].trim().startsWith("-h"))
properties.put("hostname",args[i].split(" ")[1]);
if(args[i].trim().startsWith("-p"))
properties.put("port",args[i].split(" ")[1]);
}
//this will give you all the property values mapped with their keys after this looping
//you can get the values from properties map from here onwards
}

Related

Pass more dynamic run time arguments to NodeJS child process

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();

How to implement this property file?

I have this piece of data (this is just one part of one line of the whole file):
000000055555444444******4444 YY
I implemented this CSV config file to be able to read each part of the data and parse it:
128-12,140-22,YY
The first pair (128-12) represent at what position in the line to start reading and then the amount of characters to read, that first pair is for the account number.
The second pair if for the card number.
And the thir parameter is for the registry name.
Anyways, what I do is String.split(","), and then assign the array[0] as the account number and so on.
But I want to change that CSV config file to a Property file, but I'm not sure of how to implement that solution, if I use a Properties file I'd have to add a bunch of if/then in order to properly map my values, here's what I'm thinking of doing:
Property cfg = new Property();
cfg.put("fieldName", "accountNumber");
cfg.put("startPosition", "128");
cfg.put("length", "12");
But I'd have to say if("fieldName".equals("accountNumber")) then assign accountNumber; is there a way to implement this in such a way that I could avoid implementing all this decisions? right now with my solution I don't have to use ifs, I only say accountNumber = array[0]; and that's it, but I don't think that's a good solution and I think that using Property would be more elegant or efficient
EDIT:
This probably needs some more clarification, this data I'm showing is part of a parsing program that I'm currently doing for a client; the data holds information for many many of their customers and I have to parse a huge mess of data that I receive from them, into something more readable in order to convert it to a PDF file, so far the program is under production but I'm trying to refactor it a little bit. All the customer's information is saved into different Registry classes, each class having it's own set of fields with unique information, lets say that this is what RegistryYY would look like:
class RegistryYY extends Registry{
String name;
String lastName;
PhysicalAddress address;
public RegistryYY(String dataFromFile) {
}
}
I want to implement the Property solution, because in that way, I could make the Property for parsing the file, or interpreting the data correctly to be owned by each Registry class, I mean, a Registry should know what data it needs from the data received from the file right?, I think that if I do it that way, I could make each Registry an Observer and they would decide if the current line read from the file belongs to them by checking the registry name stored in the current line and then they'd return an initialized Registry to the calling object which only cares about receiving and storing a Registry class.
EDIT 2:
I created this function to return the value stored in each line's position:
public static String getField(String fieldParams, String rawData){
// splits the field
String[] fields = fieldParams.split("-");
int fieldStart = Integer.parseInt(fields[0]); // get initial position of the field
int fieldLen = Integer.parseInt(fields[1]); // get length of field
// gets field value
String fieldValue = FieldParser.getStringValue(rawData, fieldStart, fieldLen);
return fieldValue;
}
Which works with the CSV file, I'd like to change the implementation to work with the Property file instead.
Is there any reason why you need to have the record layout exposed to the outside world ? does it need to be configurable ?
I think your proposed approached of using the Property file is better than your current approach of using the CSV file since it is more descriptive and meaningful. I would just add a "type" attribute to your Property definition as well to enforce your conversion i.e. for Numeric/String/Date/Boolean.
I wouldnt use an "if" statement to process your property file. You can load all the properties into an Array at the beginning and then iterate around the array for each line of your data file and process that section accordingly something like pseudo code below,
for each loop of data-file{
SomeClass myClass = myClassBuilder(data-file-line)
}
myClassBuilder SomeClass (String data-file-line){
Map<column, value> result = new HashMap<>
for each attribute of property-file-list{
switch attribute_type {
Integer:
result.put(fieldname, makeInteger(data-file-line, property_attribute)
Date:
result.put(fieldname, makeDate(data-file-line, property_attribute)
Boolean :
result.put(fieldname, makeBoolean(data-file-line, property_attribute)
String :
result.put(fieldname, makeBoolean(data-file-line, property_attribute)
------- etc
}
}
return new SomeClass(result)
}
}
If your record layout doesnt need to be configurable then you could do all the conversion inside your Java application only and not even use a Property file.
If you could get your data in XML format then you could use the JAXB framework and simply have your data definition in an XML file.
First of all, thanks to the guys who helped me, #robbie70, #RC. and #VinceEmigh.
I used YAML to parse a file called "test.yml" with the following information in it:
statement:
- fieldName: accountNumber
startPosition: 128
length: 12
- fieldName: cardNumber
startPosition: 140
length: 22
- fieldName: registryName
startPosition: 162
length: 2
This is what I made:
// Start of main
String fileValue = "0222000000002222F 00000000000111110001000000099999444444******4444 YY";
YamlReader reader = new YamlReader(new FileReader("test.yml"));
Object object = reader.read();
System.out.println(object);
Map map = (Map) object;
List list = (List) map.get("statement");
for(int i = 0; i < list.size(); i++) {
Map map2 = (Map) list.get(i);
System.out.println("Value: " + foo(map2, fileValue));
}
}
// End of main
public static String foo(Map map, String source) {
int startPos = Integer.parseInt((String) map.get("startPosition"));
int length = Integer.parseInt((String) map.get("length"));
return getField(startPos, length, source);
}
public static String getField(int start, int length, String source) {
return source.substring(start, start+length);
}
It correctly displays the output:
Value: 000000099999
Value: 444444******4444
Value: YY
I know that maybe the config file has some lists and other unnecessary values and what nots, and that maybe the program needs a little improvement, but I think that I can take it from here and implement what I had in mind.
EDIT:
I made this other one, using Apache Commons, this is what I have in the configuration property file:
#properties defining the statement file
#properties for account number
statement.accountNumber.startPosition = 128
statement.accountNumber.length = 12
statement.account.rules = ${statement.accountNumber.startPosition} ${statement.accountNumber.length}
#properties for card number
statement.cardNumber.startPosition = 140
statement.cardNumber.length = 22
statement.card.rules = ${statement.cardNumber.startPosition} ${statement.cardNumber.length}
#properties for registry name
statement.registryName.startPosition = 162
statement.registryName.length = 2
statement.registry.rules = ${statement.registryName.startPosition} ${statement.registryName.length}
And this is how I read it:
// Inside Main
String valorLeido = "0713000000007451D 00000000000111110001000000099999444444******4444 YY";
Parameters params = new Parameters();
FileBasedConfigurationBuilder<FileBasedConfiguration> builder =
new FileBasedConfigurationBuilder<FileBasedConfiguration>(PropertiesConfiguration.class)
.configure(params.properties()
.setFileName("config.properties"));
try {
Configuration config = builder.getConfiguration();
Iterator<String> keys = config.getKeys();
String account = getValue(getRules(config, "statement.account.rules"), valorLeido);
String cardNumber = getValue(getRules(config, "statement.card.rules"), valorLeido);
String registryName = getValue(getRules(config, "statement.registry.rules"), valorLeido);
} catch (org.apache.commons.configuration2.ex.ConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// End of Main
public static String getRules(Configuration config, String rules) {
return config.getString(rules);
}
public static String getValue(String rules, String source) {
String[] tokens = rules.split(" ");
int startPos = Integer.parseInt(tokens[0]);
int length = Integer.parseInt(tokens[1]);
return getField(startPos, length, source);
}
I'm not entirely sure, I think that with the YAML file it looks simpler, but I really like the control I get with the Apache Commons Config, since I can pass around the Configuration object to each registry, and the registry knows what "rules" it wants to get, let's say that the Registry class only cares about "statement.registry.rules" and that's it, with the YAML option I'm not entirely sure of how to do that yet, maybe I'll need to experiment with both options a little bit more, but I like where this is going.
PS:
That weird value I used in fileValue is what I'm dealing with, now add nearly 1,000 characters to the length of the line and you'll understand why I want to have a config file for parsing it (don't ask why....clients be crazy)

Why isn't my Arraylist class working? What am I doing wrong? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have a task to create a tracking System of incoming phone calls with an option menu. Each phone call should belong to an ArrayList that displays the user's name and phone number. My first struggle was storing both a name (string) and number (double) in an ArrayList together. After playing around, this is what I came up with- BUT my third class remove and add method doesn't work? What is it I am doing wrong? I have looked online and at examples and I don't understand why remove and add methods do not work.
My third class: Where my problem is
public class Incoming {
Scanner input = new Scanner(System.in);
ArrayList<Person> arr = new ArrayList<Person>();
Person p1 = new Person("Alex", "01010101");
Person p2 = new Person("Emily", "0123812"); // I will have 10 people
void AddCall() {
System.out.println("Who would you like to add to the call? Enter p+number");
String add = input.nextLine();
Person.add(input);
}
void RemoveCall() {
System.out.println("Which call would you like to answer? Enter p+ caller position"); //NOTE following will be removed from queue
String remove = input.nextLine();
Person.remove(input);
}
void ViewCallerList() {
System.out.println("The queue has the following callers: " + Person);
}
}
Your Person class does not have any methods named add or remove, so you can't ever call Person.add or Person.remove. Instead, you should add and remove items to/from the list itself.
Since you're reading the caller data from the command prompt, you have to figure out which person is being referred to by the text that your user types in. Assuming they type in something like "John,555-5555", you can construct a new Person object for John based on that. Using String#split, split the text based on the position of the comma, and then create a new Person instance to add to your list of callers:
public class Incoming {
Scanner input = new Scanner(System.in);
List<Person> callers = new ArrayList<Person>();
Person p1 = new Person("Alex", "01010101");
Person p2 = new Person("Emily", "0123812"); // I will have 10 people
private static Person readPerson(Scanner sc) {
String callerText = sc.nextLine();
String[] callerData = callerText.split(",");
return new Person(callerData[0], callerData[1]);
}
void addCall() {
System.out.println("Who would you like to add to the call? Enter p+number");
callers.add(readPerson(input));
}
void removeCall() {
// Complete this based on the add method above
}
// This should output the list (callers), not a single person
void viewCallerList() {
System.out.println("The queue has the following callers: " + callers);
}
}

Having issues with List in Java [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 9 years ago.
Improve this question
I have this class:
public class Attributes {
List text = new ArrayList();
List angle = new ArrayList();
public Attributes() {
}
public int getHowManyNodes() {
int howMany = 0;
howMany += text.isEmpty() ? 0 : text.size();
howMany += angle.isEmpty() ? 0 : angle.size();
return howMany;
}
}
And when I do:
Attributes attributes = new Attributes();
System.out.print(attributes.getHowManyNodes());
It gives Exception in thread "main" java.lang.NullPointerException
Weirdly tho, it only gives an error on "angle.isEmpty()" not on "text.isEmpty()"
Why does it say it is null when I initialize it with:
List angle = new ArrayList();
Edit1:
Full error:
Exception in thread "main" java.lang.NullPointerException
at projectmerger1.Attributes.getHowManyNodes(Attributes.java:55)
at projectmerger1.Project.listGameVariables(Project.java:235)
at projectmerger1.ProjectMerger1.main(ProjectMerger1.java:289)
Java Result: 1
Minor edit:
Line 55 in Attributes Class is
howMany += angle.isEmpty() ? 0 : angle.size();
Edit2:
public class Project {
Game game;
public void listGameVariables() {
System.out.print(game.attributes.getHowManyNodes());
}
}
public class Game {
Attributes attributes = new Attributes();
}
This is my whole setup.
Based on your comments (and your code) one (or both) of your List(s) must be null. I would add a null check like this
howMany += text == null ? 0 : text.size();
howMany += angle == null ? 0 : angle.size();
It's possible you have another method that is "nulling" those fields.
I've compiled and run this code, it prints out 0 with no NullPointerException. There is no way to get this error with the code you provided.
public class Attributes {
List text = new ArrayList();
List angle = new ArrayList();
public Attributes() {
}
public int getHowManyNodes() {
int howMany = 0;
howMany += text.isEmpty() ? 0 : text.size();
howMany += angle.isEmpty() ? 0 : angle.size();
return howMany;
}
public static void main(String[] args) {
Attributes attributes = new Attributes();
System.out.print(attributes.getHowManyNodes());
}
}
The only possible way that this could be happening is if:
angle is being accessed somewhere else and set to null before you call getHowManyNodes().
angle is being "shadowed" by another variable of the same name that you are not showing in your code example.
Ways to debug this:
Make your variables private and final, and see what code they break so you can see if they're being set to null elsewhere.
Put System.out.println(angle) in a block of code under your instantiation of angle, and also in your constructor.
Ways to avoid this bug in the future:
Encapsulate your variables.
Make your methods null-safe.
Set a BreakPoint in the first source code line of your getHowManyNodes() method, start your program in debug mode and try to figure out where the error comes from by using the short cut keys (Eclipse) F5 -> StepInto and F6 -> StepOver. Your source provided looks fine and shouldn't cause any problems. By debugging your application via Eclipse or any other IDE, you should easily find such errors.

What would be a safe way to split a string into multiple parts in Java?

Let me clarify the question I am asking. I have a java program I am working on that takes input from the keyboard via a readline library called JLine2. The library takes the entire line types as a command instead on breaking it up into space separated commands and arguments. What I am looking for is a safe way to break up the string that is passed as input.
I have tried using an array but since I am in the early stages of concept I don't yet know how many arguments my largest command will have so using a pre-initialized array I don't think will work. The problem I have ran into is when I check for null values in the array or when I check to see if a particular command or argument is present. Java keeps throwing an exception about the array index being out of scope or something. Because the array does not actually have a value for say array index 1 which is an argument to command in array index 0.
So what I am looking for is a way to take a string and safely split it into parts without having Java yelling at me when and array exception has occurred.
Here is the very slim code I can provide...
ConfigShell.class
package shell;
import java.io.IOException;
import configFS.ConfigFS;
import jline.console.ConsoleReader;
public class ConfigShell {
private ConfigFS config;
public ConfigShell() throws IOException {
config = new ConfigFS();
}
public void init() throws IOException {
ConsoleReader console = new ConsoleReader();
// When the program starts we want to be placed at / (root).
console.setPrompt(">> ");
// In this case an infinite loop is better than a loop based on whether line is equal to null.
// This allows line to be equal to null and still stay inside the shell.
while (true) {
String line = console.readLine();
if (line != null) {
// If pre-initialize the array I can check for null as a value for an array index.
// If I did this at time I needed the array and there were not enough index occupied the system would return an exception.
String[] cmdArgs = new String[4];
// We need to split up the incoming line because JLine2 does not do it for me.
// This allows me to evaluate the entire command piece by piece rather all at once.
cmdArgs = line.split("\\s+");
if (cmdArgs[0] != null && cmdArgs[0].equals("add")) {
if (cmdArgs[1] != null && cmdArgs[1].equals("server")) {
if (cmdArgs[2] != null) {
config.addServer(cmdArgs[2]);
System.out.println("Added server " + cmdArgs[2] + " to the configuration successfully.");
}
}
}
if (cmdArgs[0].equals("exit")) {
System.exit(0);
}
}
}
}
}
Note for testing: My Start.class main method makes a call to the init method in the above file.
You can do:
String cmdArgs = line.split("\\s+");
and then, before accessing any particular index, check the size of the array so that you do not get ArrayIndexOutOfBoundException
Something like this:
if(cmdArgs.length>=2){
//It means you have at least 2 elements
//Now its safe to access cmdArgs[0] and cmdArgs[1]
}
If all your problem is to have a storage for a variable number of strings you can use ArrayList<String> object.
You declare it like ArrayList<String> as = new ArrayList<String>();
Then when you split something from your command string you will simply use add method:
as.add(yourString);
If you need to retrieve a particular element of the ArrayList you can use its get method:
as.get(0);
You can process all elements with for each loop:
for(String str: as) {
println(str):
}
Have a look here for info and here for an example.
As I think you can use StringTokenizer class and its methods for your requirement.
see the sample code below:
if(line!=null)
{
StringTokenizer st=new StringTokenizer(line);// by default it takes space as delimiter....you can use as required as second argument in constructor...
while(st.hasMoreTokens())
{
String token1=st.nextToken();
// do your stuffs here..........
// I don't know exactly about your required logic here......
/* if(token1.equals("add"))
{
String token2=st.nextToken();
if(token2.equals("server"))
{
String token3=st.nextToken();
config.addServer(token3);
System.out.println("Added server " + token3 + " to the configuration successfully.");
}
}
*/
}// while closing...
}// outer if closing...
Or as PM 77-1 told you can use ArrayList. But as my opinion LinkedList should be a better option here.

Categories

Resources