Skip to content
9 changes: 5 additions & 4 deletions src/main/java/chapter14/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,18 @@ class Application {

public static void main(String[] args) {
try {
Args arg = new Args("l,d*", args);
Args arg = new Args("l,p#,d*", args);
boolean logging = arg.getBoolean('l');
int port = arg.getInt('p');
String directory = arg.getString('d');
executeApplication(logging, directory);
executeApplication(logging, port, directory);
} catch (ParseException e) {
System.out.printf("Parse error: %s\n", e.getMessage());
}
}

// stub
private static void executeApplication(boolean logging, String directory) {
System.out.printf("logging: %b, directory: %s\n", logging, directory);
private static void executeApplication(boolean logging, int port, String directory) {
System.out.printf("logging: %b, port: %d, directory: %s\n", logging, port, directory);
}
}
139 changes: 100 additions & 39 deletions src/main/java/chapter14/args/Args.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@ public class Args {
private Set<Character> unexpectedArguments = new TreeSet<>();
private Map<Character, Boolean> booleanArgs = new HashMap<>();
private Map<Character, String> stringArgs = new HashMap<>();
private Map<Character, Integer> intArgs = new HashMap<>();
private Set<Character> argsFound = new HashSet<>();
private int currentArgument;
private char errorArgument = '\0';
private char errorArgumentId = '\0';
private String errorParameter = "TILT";
private ErrorCode errorCode = ErrorCode.OK;

enum ErrorCode {
OK, MISSING_STRING
OK, MISSING_STRING, MISSING_INTEGER, INVALID_INTEGER, UNEXPECTED_ARGUMENT
}

private ErrorCode errorCode = ErrorCode.OK;

public Args(String schema, String[] args) throws ParseException {
this.schema = schema;
this.args = args;
Expand All @@ -30,7 +31,10 @@ private boolean parse() throws ParseException {
if (schema.length() == 0 && args.length == 0)
return true;
parseSchema();
parseArguments();
try {
parseArguments();
} catch (ArgsException e) {
}
return valid;
}

Expand All @@ -52,6 +56,13 @@ private void parseSchemaElement(String element) throws ParseException {
parseBooleanSchemaElement(elementId);
else if (isStringSchemaElement(elementTail))
parseStringSchemaElement(elementId);
else if (isIntegerSchemaElement(elementTail))
parseIntegerSchemaElement(elementId);
else {
throw new ParseException(
String.format("Argument: %c has invalid format: %s.",
elementId, elementTail), 0);
}
}

private void validateSchemaElementId(char elementId) throws ParseException {
Expand All @@ -61,6 +72,14 @@ private void validateSchemaElementId(char elementId) throws ParseException {
}
}

private void parseBooleanSchemaElement(char elementId) {
booleanArgs.put(elementId, false);
}

private void parseIntegerSchemaElement(char elementId) {
intArgs.put(elementId, 0);
}

private void parseStringSchemaElement(char elementId) {
stringArgs.put(elementId, "");
}
Expand All @@ -73,70 +92,96 @@ private boolean isBooleanSchemaElement(String elementTail) {
return elementTail.length() == 0;
}

private void parseBooleanSchemaElement(char elementId) {
booleanArgs.put(elementId, false);
private boolean isIntegerSchemaElement(String elementTail) {
return elementTail.equals("#");
}

private boolean parseArguments() {
private boolean parseArguments() throws ArgsException {
for (currentArgument = 0; currentArgument < args.length; currentArgument++) {
String arg = args[currentArgument];
parseArgument(arg);
}
return true;
}

private void parseArgument(String arg) {
private void parseArgument(String arg) throws ArgsException {
if (arg.startsWith("-"))
parseElements(arg);
}

private void parseElements(String arg) {
private void parseElements(String arg) throws ArgsException {
for (int i = 1; i < arg.length(); i++) {
parseElement(arg.charAt(i));
}
}

private void parseElement(char argChar) {
private void parseElement(char argChar) throws ArgsException {
if (setArgument(argChar))
argsFound.add(argChar);
else {
unexpectedArguments.add(argChar);
errorCode = ErrorCode.UNEXPECTED_ARGUMENT;
valid = false;
}
}

private boolean setArgument(char argChar) {
boolean set = true;
if (isBoolean(argChar))
private boolean setArgument(char argChar) throws ArgsException {
if (isBooleanArg(argChar))
setBooleanArg(argChar, true);
else if (isString(argChar))
setStringArg(argChar, "");
else if (isStringArg(argChar))
setStringArg(argChar);
else if (isIntArg(argChar))
setIntArg(argChar);
else
set = false;
return false;

return true;
}

private boolean isIntArg(char argChar) {
return intArgs.containsKey(argChar);
}

return set;
private void setIntArg(char argChar) throws ArgsException {
currentArgument++;
String parameter = null;
try {
parameter = args[currentArgument];
intArgs.put(argChar, new Integer(parameter));
} catch (ArrayIndexOutOfBoundsException e) {
valid = false;
errorArgumentId = argChar;
errorCode = ErrorCode.MISSING_INTEGER;
throw new ArgsException();
} catch (NumberFormatException e) {
valid = false;
errorArgumentId = argChar;
errorParameter = parameter;
errorCode = ErrorCode.INVALID_INTEGER;
throw new ArgsException();
}
}

private void setStringArg(char argChar, String s) {
private void setStringArg(char argChar) {
currentArgument++;
try {
stringArgs.put(argChar, args[currentArgument]);
} catch (ArrayIndexOutOfBoundsException e) {
valid = false;
errorArgument = argChar;
errorArgumentId = argChar;
errorCode = ErrorCode.MISSING_STRING;
}
}

private boolean isString(char argChar) {
private boolean isStringArg(char argChar) {
return stringArgs.containsKey(argChar);
}

private void setBooleanArg(char argChar, boolean value) {
booleanArgs.put(argChar, value);
}

private boolean isBoolean(char argChar) {
private boolean isBooleanArg(char argChar) {
return booleanArgs.containsKey(argChar);
}

Expand All @@ -152,18 +197,23 @@ public String usage() {
}

public String errorMessage() throws Exception {
if (unexpectedArguments.size() > 0) {
return unexpectedArgumentMessage();
} else {
switch (errorCode) {
case MISSING_STRING:
return String.format("Could not find string parameter for -%c.",
errorArgument);
case OK:
throw new Exception("TILT: Should not get here.");
}
return "";
switch (errorCode) {
case OK:
throw new Exception("TILT: Should not get here.");
case UNEXPECTED_ARGUMENT:
return unexpectedArgumentMessage();
case MISSING_STRING:
return String.format("Could not find string parameter for -%c.",
errorArgumentId);
case INVALID_INTEGER:
return String.format("Argument -%c expects an integer but was '%s'.",
errorArgumentId, errorParameter);
case MISSING_INTEGER:
return String.format("Could not find integer parameter for -%c.",
errorArgumentId);
}
return "";

}

private String unexpectedArgumentMessage() {
Expand All @@ -176,27 +226,38 @@ private String unexpectedArgumentMessage() {
return message.toString();
}

public boolean getBoolean(char arg) {
return falseIfNull(booleanArgs.get(arg));
}

private boolean falseIfNull(Boolean b) {
return b == null ? false : b;
}

public String getString(char arg) {
return blankIfNull(stringArgs.get(arg));
private int zeroIfNull(Integer i) {
return i == null ? 0 : i;
}

private String blankIfNull(String s) {
return s == null ? "" : s;
}

public String getString(char arg) {
return blankIfNull(stringArgs.get(arg));
}

public int getInt(char arg) {
return zeroIfNull(intArgs.get(arg));
}

public boolean getBoolean(char arg) {
return falseIfNull(booleanArgs.get(arg));
}

public boolean has(char arg) {
return argsFound.contains(arg);
}

public boolean isValid() {
return valid;
}

private class ArgsException extends Exception {
}
}
18 changes: 15 additions & 3 deletions src/test/java/chapter14/ApplicationTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,28 @@ void stringArguments() {
assertThat(output()).contains("root");
}

@Test
void integerArguments() {
//given
String[] args = new String[]{"-p", "42"};

//when
runMain(args);

//then
assertThat(output()).contains("42");
}

@Test
void allArgumentsPresent() {
//given
String[] args = new String[]{"-l", "-d", "user"};
String[] args = new String[]{"-l", "-p", "8080", "-d", "user"};

//when
runMain(args);

//then
assertThat(output()).isEqualTo("logging: true, directory: user");
assertThat(output()).isEqualTo("logging: true, port: 8080, directory: user");
}

@Test
Expand All @@ -51,7 +63,7 @@ void noArguments() {
runMain(args);

//then
assertThat(output()).isEqualTo("logging: false, directory:");
assertThat(output()).isEqualTo("logging: false, port: 0, directory:");
}

@Override
Expand Down
Loading