/*
* Copyright 2012 Jason Miller
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jj.configuration;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.inject.Singleton;
import jj.InitializationException;
import jj.conversion.Converters;
/**
* <p>
* Parses the command line arguments and makes them available to the rest of the system
*
* <p>
* Arguments are expected to be "name=value" pairs, although I am considering providing
* simple booleans just using presence.
*
* @author jason
*
*/
@Singleton
public class Arguments {
private static final Pattern SPLITTER = Pattern.compile("(?<=[^\\s])=(?=[^\\s])");
private final Map<String, String> arguments;
private final Converters converters;
private static <E extends Enum<E>> String from(Class<E> enumClass) {
String name = enumClass.getSimpleName();
StringBuilder out = new StringBuilder(name.length() * 2); // pretty worst case
out.append(Character.toLowerCase(name.charAt(0)));
for (int i = 1; i < name.length(); ++i) {
char c = name.charAt(i);
if (Character.isUpperCase(c)) {
out.append('-');
c = Character.toLowerCase(c);
}
out.append(c);
}
return out.toString();
}
@Inject
Arguments(final @CommandLine String[] arguments, final Converters converters) {
this.arguments = readArguments(arguments);
this.converters = converters;
}
private Map<String, String> readArguments(String[] arguments) {
HashMap<String, String> result = new HashMap<>();
LinkedHashSet<String> badArgs = new LinkedHashSet<>();
for (final String argument : arguments) {
String[] particles = SPLITTER.split(argument);
if (particles.length == 2) {
result.put(particles[0], particles[1]);
} else {
badArgs.add(argument);
}
}
if (!badArgs.isEmpty()) {
throw new InitializationException("all arguments must be name=value pairs, the following were not understood\n" + badArgs);
}
return Collections.unmodifiableMap(result);
}
public <E extends Enum<E>> E get(Class<E> enumClass) {
return converters.convert(arguments.get(from(enumClass)), enumClass);
}
public <E extends Enum<E>> E get(Class<E> enumClass, E defaultValue) {
E result = converters.convert(arguments.get(from(enumClass)), enumClass);
return result == null ? defaultValue : result;
}
/**
* <p>
* Retrieve the indicated argument, converting to the desired type using {@link Converters}
*
* @param name the name of the argument to retrieve
* @param type the desired type
* @return the argument value, if present and convertible. null otherwise
*/
public <T> T get(final String name, final Class<T> type) {
return converters.convert(arguments.get(name), type);
}
/**
* <p>
* Retrieve the indicated argument, converting to the desired type using {@link Converters}, and
* returning the given default if necessary.
*
* @param name the name of the argument to retrieve
* @param type the desired type
* @param defaultValue the desired default
* @return the argument value, if present and convertible. defaultValue otherwise
*/
public <T> T get(final String name, final Class<T> type, final T defaultValue) {
T result = get(name, type);
return arguments.containsKey(name) ? (result == null ? defaultValue : result) : defaultValue;
}
/**
* <p>
* Retrieve the raw value of the indicated argument, if present
*
* @param name the name of the argument to retrieve
* @return the raw argument value, if present. null otherwise
*/
public String get(final String name) {
return arguments.get(name);
}
@Override
public String toString() {
return arguments.toString();
}
}