diff --git a/resources/META-INF/EvA2.props b/resources/META-INF/EvA2.props index 24ce0e7f..33bc8a34 100644 --- a/resources/META-INF/EvA2.props +++ b/resources/META-INF/EvA2.props @@ -13,4 +13,4 @@ ModulePackage = eva2.optimization.modules ModuleFilterClass = eva2.optimization.modules.AbstractModuleAdapter # Full EvA2 version number -EvA2Version = 3.0-rc1 \ No newline at end of file +EvA2Version = 2.2.0-rc1 \ No newline at end of file diff --git a/src/eva2/cli/Main.java b/src/eva2/cli/Main.java index c515fb55..c4d1c19d 100644 --- a/src/eva2/cli/Main.java +++ b/src/eva2/cli/Main.java @@ -1,25 +1,22 @@ package eva2.cli; +import eva2.EvAInfo; import eva2.optimization.go.InterfaceOptimizationParameters; import eva2.optimization.individuals.IndividualInterface; +import eva2.optimization.modules.OptimizationParameters; import eva2.optimization.modules.Processor; import eva2.optimization.operator.terminators.InterfaceTerminator; import eva2.optimization.population.Population; import eva2.optimization.population.PopulationInterface; -import eva2.optimization.statistics.InterfaceStatistics; -import eva2.optimization.statistics.InterfaceStatisticsListener; -import eva2.optimization.statistics.InterfaceStatisticsParameters; -import eva2.optimization.statistics.InterfaceTextListener; +import eva2.optimization.statistics.*; import eva2.optimization.strategies.InterfaceOptimizer; import eva2.problems.InterfaceAdditionalPopulationInformer; import eva2.problems.InterfaceOptimizationProblem; +import eva2.util.annotation.Description; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * @@ -27,6 +24,56 @@ import java.util.Map; public class Main { public static void main(String[] args) { + if (args.length == 0 || (args.length == 1 && args[0].equals("--help"))) { + /* Show help for empty argument list or --help */ + printHelp(); + System.exit(-1); + } else if (args.length == 2 && args[0].equals("--help")) { + /* Show help for specific class */ + String className = args[1]; + try { + Class clazz = Class.forName(className); + printHelpFor(clazz); + } catch (ClassNotFoundException e) { + System.out.printf("Class %s does not exist.\n", className); + } + System.exit(-1); + } else { + executeArguments(args); + } + } + + private static void printHelp() { + System.out.printf("EvA2 version \"%s\"\n", EvAInfo.getVersion()); + System.out.println("Usage: java -cp EvA2.jar eva2.cli.Main [args...]\n"); + + printHelpFor(OptimizationParameters.class); + printHelpFor(StatisticsParameters.class); + } + + private static void printHelpFor(Class clazz) { + System.out.println(clazz.getName() + "\n"); + if (clazz.isAnnotationPresent(Description.class)) { + Description description = clazz.getAnnotation(Description.class); + System.out.println(description.value()); + } + + ParameterGenerator generator = new ParameterGenerator(clazz, false); + generator.generate(); + Map> paramList = generator.getParameterList(); + + List parameters = paramList.get(clazz.getName()); + if (parameters.size() > 0) { + System.out.println("Options:"); + + for (Parameter key : parameters) { + System.out.printf("\t--%s\t%s\n", key.getName(), key.getType().toString()); + System.out.printf("\t\t%s\n", key.getDescription()); + } + } + } + + private static void executeArguments(String[] args) { InterfaceOptimizationParameters parameters = OptimizationBuilder.parseOptimizerArguments(args); InterfaceStatisticsParameters statisticsParameters = OptimizationBuilder.parseStatisticsArguments(args); diff --git a/src/eva2/cli/ParameterGenerator.java b/src/eva2/cli/ParameterGenerator.java new file mode 100644 index 00000000..26dfbcf1 --- /dev/null +++ b/src/eva2/cli/ParameterGenerator.java @@ -0,0 +1,165 @@ +package eva2.cli; + +import eva2.optimization.modules.OptimizationParameters; +import eva2.tools.ReflectPackage; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Generates a human readable document with all command line parameters available + * for EvA2. + */ +public class ParameterGenerator { + private Class clazz; + private boolean recursive; + + /** + * Maps class name to a list of parameters + */ + private Map> parameterList; + + public ParameterGenerator(Class clazz) { + this(clazz, true); + } + + public ParameterGenerator(Class clazz, boolean recursive) { + this.clazz = clazz; + this.parameterList = new HashMap<>(); + this.recursive = recursive; + } + + + + public Map> getParameterList() { + return parameterList; + } + + public void generate() { + generateForClass(this.clazz); + } + + private void generateForClass(Class clazz) { + List parameters = new ArrayList<>(); + + this.parameterList.put(clazz.getName(), parameters); + + BeanInfo info; + try { + if (clazz.isInterface()) { + info = Introspector.getBeanInfo(clazz); + } else { + info = Introspector.getBeanInfo(clazz, Object.class); + } + + PropertyDescriptor[] properties = info.getPropertyDescriptors(); + for (PropertyDescriptor pd : properties) { + String name = pd.getName(); + Method getter = pd.getReadMethod(); + Method setter = pd.getWriteMethod(); + Class type = pd.getPropertyType(); + + // Skip if setter is hidden or getter is not available + if (setter == null || setter.isAnnotationPresent(eva2.util.annotation.Hidden.class) || getter == null) { + continue; + } + + Parameter parameter; + if (setter.isAnnotationPresent(eva2.util.annotation.Parameter.class)) { + eva2.util.annotation.Parameter param = setter.getAnnotation(eva2.util.annotation.Parameter.class); + if (!param.name().isEmpty()) { + name = param.name(); + } + parameter = new Parameter(name, param.description(), type); + } else { + parameter = new Parameter(name, "No description available", type); + } + + parameters.add(parameter); + + if (type == Object.class || !recursive) { + continue; + } + + Class[] classes = ReflectPackage.getAssignableClassesInPackage("eva2", type, true, true); + for (Class assignable : classes) { + // Recurse if not in List + if (!parameterList.containsKey(assignable.getName()) && assignable.getName().startsWith("eva2") && !assignable.getName().startsWith("eva2.gui")) { + System.out.println(type.getName() + "\t->\t" + assignable.getName()); + generateForClass(assignable); + } + } + } + } catch (IntrospectionException ex) { + // die + } + + } + + public static void main(String[] args) { + ParameterGenerator generator = new ParameterGenerator(OptimizationParameters.class); + generator.generate(); + int paramCount = 0; + Map> paramList = generator.getParameterList(); + for(String key : paramList.keySet()) { + paramCount += paramList.get(key).size(); + } + System.out.println("Total Parameter Count: " + paramCount); + System.out.println("Total Type Count: " + paramList.size()); + } +} + +class Type { + private List parameters; + private final String name; + private final String description; + + public Type(String name, String description) { + this.name = name; + this.description = description; + this.parameters = new ArrayList<>(); + } + + public List getParameters() { + return this.parameters; + } + + public String getName() { + return this.name; + } + + public String getDescription() { + return this.description; + } +} + +class Parameter { + private final String name; + private final String description; + private final Class type; + + public Parameter(String name, String description, Class type) { + this.name = name; + this.description = description; + this.type = type; + } + + public String getName() { + return this.name; + } + + public String getDescription() { + return this.description; + } + + public Class getType() { + return this.type; + } +}