Index: lutinutil/src/java/org/codelutin/util/OptionDefinitionParserException.java diff -u lutinutil/src/java/org/codelutin/util/OptionDefinitionParserException.java:1.1 lutinutil/src/java/org/codelutin/util/OptionDefinitionParserException.java:1.2 --- lutinutil/src/java/org/codelutin/util/OptionDefinitionParserException.java:1.1 Sat Nov 17 11:07:20 2007 +++ lutinutil/src/java/org/codelutin/util/OptionDefinitionParserException.java Wed Dec 5 03:03:57 2007 @@ -17,6 +17,9 @@ *##%**/ package org.codelutin.util; +import org.codelutin.util.OptionParserUtil.*; +import java.util.ArrayList; +import java.util.List; /** * Exception soulevable uniquement par le parser de définition d'option. @@ -29,15 +32,35 @@ * @see OptionDefinitionParser */ public class OptionDefinitionParserException extends RuntimeException { // OptionDefinitionParserException - private static final long serialVersionUID = -3283937669966903905L; + final OptionParserUtil.OptionDefinitionParserContext context; + private static final long serialVersionUID = 7683172805089232103L; - public OptionDefinitionParserException(String msg) { + public OptionDefinitionParserException(String msg, OptionDefinitionParserContext context) { super(msg); + this.context = context; } - public OptionDefinitionParserException(String msg, Throwable eee) { + public OptionDefinitionParserException(String msg, Throwable eee, OptionDefinitionParserContext context) { super(msg, eee); + this.context = context; } + @Override + public String toString() { + StringBuilder builder = new StringBuilder().append(super.toString()).append("\nfrom contexts :"); + OptionDefinitionParserContext cont = context; + List l = new ArrayList(); + String prefix = ""; + while (!cont.isRoot()) { + l.add(cont); + cont = (OptionDefinitionParserContext) cont.parent; + } + l.add(cont); + for (OptionDefinitionParserContext context : l) { + builder.append('\n').append(prefix).append(context); + prefix += " "; + } + return builder.toString(); + } } // OptionDefinitionParserException \ No newline at end of file Index: lutinutil/src/java/org/codelutin/util/OptionArgumentDefinition.java diff -u lutinutil/src/java/org/codelutin/util/OptionArgumentDefinition.java:1.5 lutinutil/src/java/org/codelutin/util/OptionArgumentDefinition.java:1.6 --- lutinutil/src/java/org/codelutin/util/OptionArgumentDefinition.java:1.5 Sun Dec 2 05:12:38 2007 +++ lutinutil/src/java/org/codelutin/util/OptionArgumentDefinition.java Wed Dec 5 03:03:57 2007 @@ -12,8 +12,6 @@ */ package org.codelutin.util; -import org.codelutin.util.OptionParserAnnotationHelper.OptionArgumentA; - /** * Cette classe représente la définition d'un argument d'une option. *

@@ -63,7 +61,7 @@ this.max = max; } - public OptionArgumentDefinition(OptionArgumentA definition) { + public OptionArgumentDefinition(OptionParserAnnotationHelper.ArgumentA definition) { this.type = definition.type(); this.valueType = definition.valueType(); this.key = definition.key(); Index: lutinutil/src/java/org/codelutin/util/OptionParserUtil.java diff -u lutinutil/src/java/org/codelutin/util/OptionParserUtil.java:1.2 lutinutil/src/java/org/codelutin/util/OptionParserUtil.java:1.3 --- lutinutil/src/java/org/codelutin/util/OptionParserUtil.java:1.2 Sun Dec 2 07:13:24 2007 +++ lutinutil/src/java/org/codelutin/util/OptionParserUtil.java Wed Dec 5 03:03:57 2007 @@ -1,14 +1,15 @@ package org.codelutin.util; +import static org.codelutin.i18n.I18n._; import org.codelutin.log.LutinLog; import org.codelutin.log.LutinLogFactory; import org.codelutin.util.OptionDefinitionParser.OptionArgumentContext; import org.codelutin.util.OptionDefinitionParser.OptionContext; import org.codelutin.util.OptionDefinitionParser.OptionGroupArgumentContext; +import org.codelutin.util.OptionParserAnnotationHelper.ApplicationA; +import org.codelutin.util.OptionParserAnnotationHelper.ArgumentA; +import org.codelutin.util.OptionParserAnnotationHelper.GroupArgumentA; import org.codelutin.util.OptionParserAnnotationHelper.OptionA; -import org.codelutin.util.OptionParserAnnotationHelper.OptionArgumentA; -import org.codelutin.util.OptionParserAnnotationHelper.OptionGroupArgumentA; -import org.codelutin.util.OptionParserAnnotationHelper.OptionParserA; import java.util.ArrayList; import java.util.List; @@ -21,12 +22,19 @@ public class OptionParserUtil { - public static String toString(OptionParserA anno, String prefix) { + public static String toString(ApplicationA anno, String head, String headOptions, String headArguments, String prefix) { StringBuilder builder = new StringBuilder(); + builder.append(addTitle(head, '=', true)).append("\n\n"); + builder.append(addTitle(headOptions, '-', false)).append("\n"); for (OptionA definition : anno.options()) { builder.append(prefix).append(OptionParserUtil.toString(definition)); builder.append("\n ").append(definition.description()).append("\n\n"); } + builder.append(addTitle(headArguments, '-', false)).append("\n"); + for (ArgumentA definition : anno.arguments()) { + builder.append(prefix).append(OptionParserUtil.toString(definition)); + builder.append("\n ").append(definition.description()).append("\n\n"); + } return builder.toString(); } @@ -43,20 +51,24 @@ if (min == 0 && max == 1) { StringUtil.printCardinalite(builder, s1, min, max, isMandatory, "", "", "", ""); } else { - StringUtil.printCardinalite(builder, s1, min, max, isMandatory, "(", ")", "[", "]"); + if (min == 1 && max == 1) { + builder.append(s1).append(' ').append('{').append(min).append(',').append(max).append("}"); + } else { + StringUtil.printCardinalite(builder, s1, min, max, isMandatory, "", " ", "", " "); + } } if (anno.groups().length > 0) { - for (OptionGroupArgumentA group : anno.groups()) { + for (GroupArgumentA group : anno.groups()) { builder.append(' ').append(toString(group)); } } return builder.toString(); } - public static String toString(OptionGroupArgumentA anno) { + public static String toString(GroupArgumentA anno) { StringBuilder builder = new StringBuilder(); StringBuffer s = new StringBuffer(); - for (OptionArgumentA argument : anno.arguments()) { + for (ArgumentA argument : anno.arguments()) { s.append('|').append(toString(argument)); } String s1 = s.toString(); @@ -64,7 +76,7 @@ return builder.toString(); } - public static String toString(OptionArgumentA anno) { + public static String toString(ArgumentA anno) { StringBuilder sb = new StringBuilder(); StringBuffer s = new StringBuffer(anno.key()); switch (anno.type()) { @@ -81,6 +93,39 @@ return sb.toString(); } + protected static String addTitle(String txt, char c, boolean headAndTail) { + StringBuilder writer = new StringBuilder(); + if (headAndTail) { + for (int i = 0, j = txt.length(); i < j; i++) { + writer.append(c); + } + writer.append('\n'); + } + writer.append(txt).append('\n'); + for (int i = 0, j = txt.length(); i < j; i++) { + writer.append(c); + } + return writer.toString(); + } + + public static OptionArgumentDefinition findArgumentByTypeAndKey(OptionArgumentType type, String key, OptionArgumentDefinition... defs) { + for (OptionArgumentDefinition def : defs) { + if (def.getType() == type && def.getKey().equals(key)) { + return def; + } + } + return null; + } + + public static OptionArgumentDefinition findArgumentByTypeAndValueType(OptionArgumentType type, OptionArgumentValueType valueType, OptionArgumentDefinition... defs) { + for (OptionArgumentDefinition def : defs) { + if (def.getType() == type && def.getValueType() == valueType) { + return def; + } + } + return null; + } + /** * Un contexte abstrait pour parseur (qui peut contenir un contexte parent * et des contextes enfants). @@ -88,13 +133,15 @@ * @author chemit */ - public abstract static class ParserContext

{ + public abstract static class ParserContext

, S extends ParserContext, E extends Exception> { + + protected abstract E newError(String content, Exception e); /** logger non statique pour être dans la bonne catégorie */ protected final LutinLog log = LutinLogFactory.getLutinLog(getClass()); /** le contexte parent (peut être null) */ - protected final P parent; + protected P parent; /** la liste des contextes enfants (peut être null) */ protected final List contexts; @@ -102,22 +149,35 @@ /** flag pour marquer l'état du context */ protected boolean valid = true; + /** list of errors found while parsing */ + protected List errors; + protected ParserContext(P parent, boolean withSons) { this.parent = parent; this.contexts = withSons ? new ArrayList() : null; } + boolean isRoot() { + return parent == null; + } + + boolean hasChilds() { + return contexts != null; + } + void addSon(S context) { preAddSonHook(context); - if (valid) { - log.info("[" + getClass().getSimpleName() + " : " + context + "]"); + //TODO See if the test is ok... + if (context!=null && context.valid) { + log.debug("[" + getClass().getSimpleName() + " : (" + context.valid + ")" + context + "]"); contexts.add(context); postAddSonHook(context); } } protected void preAddSonHook(S context) { - if (contexts == null) { + if (!hasChilds()) { + //TODO Should throw runtime exception, return; } if (context == null || !context.valid) { @@ -129,7 +189,7 @@ } void clear() { - if (contexts != null) { + if (hasChilds()) { for (S context : contexts) { context.clear(); } @@ -137,12 +197,94 @@ //contexts.clear(); } + public List getErrors() { + if (errors == null) { + errors = new ArrayList(); + } + return errors; + } + public void unvalidate() { this.valid = false; - if (parent != null) { + if (!isRoot()) { parent.unvalidate(); } } + + protected int getNbErrors() { + return errors == null ? 0 : errors.size(); + } + + protected E addError(String content) { + return addError(content, null); + } + + protected E addError(String content, Exception e) { + E e1 = newError(content, e); + getErrors().add(e1); + if (!isRoot()) { + parent.addError(content, e1); + } + unvalidate(); + return e1; + } + + protected boolean checkCardinalite(int min, int max, String definition, String description) { + int s = getNbErrors(); + if (min < 0) { + addError(_("lutinutil.parser.min.can.not.be.negative", min, definition, description)); + } + if (max == 0) { + addError(_("lutinutil.parser.max.can.not.be.zero", max, definition, description)); + } + if (max < -1) { // on vérifie que la cardinalité max >-2 + addError(_("lutinutil.parser.max.too.low", max, definition, description)); + } + if (max != -1 && max < min) { // on vérifie que la cardinalité max==-1 || max >= min + addError(_("lutinutil.parser.max.lowest.than.min", max, min, definition, description)); + } + return getNbErrors() == s; + } + + } + + public abstract static class OptionDefinitionParserContext

, S extends ParserContext> extends ParserContext { + protected OptionDefinitionParserContext(P parent, boolean withSons) { + super(parent, withSons); + } + + protected OptionDefinitionParserException newError(String content, Exception e) { + OptionDefinitionParserException e1; + if (e == null) { + e1 = new OptionDefinitionParserException(content, this); + } else if (e instanceof OptionDefinitionParserException) { + // propage exception + e1 = (OptionDefinitionParserException) e; + + } else { + e1 = new OptionDefinitionParserException(content, e, this); + } + return e1; + } + } + + public abstract static class OptionParserContext

, S extends ParserContext> extends ParserContext { + protected OptionParserContext(P parent, boolean withSons) { + super(parent, withSons); + } + + protected OptionParserException newError(String content, Exception e) { + OptionParserException e1; + if (e == null) { + e1 = new OptionParserException(content, this); + } else if (e instanceof OptionParserException) { + // propage exception + e1 = (OptionParserException) e; + } else { + e1 = new OptionParserException(content, e, this); + } + return e1; + } } /** @@ -204,26 +346,35 @@ return instance; } - OptionParserA parserA; + ApplicationA parserA; OptionA[] optionAs; - OptionGroupArgumentA[] groupArgumentAs; - OptionArgumentA[] argumentAs; + GroupArgumentA[] groupArgumentAs; + ArgumentA[] argumentAs; - public OptionParserA run(OptionContext[] options) { + public ApplicationA run(OptionContext[] options, OptionArgumentContext[] arguments, Class impl) { optionAs = new OptionA[options.length]; + ArgumentA[] as = new ArgumentA[arguments.length]; + if (arguments.length > 0) { + for (int i = 0; i < arguments.length; i++) { + OptionArgumentContext argument = arguments[i]; + as[i] = OptionParserAnnotationHelper.newArgumentA( + argument.type, argument.valueType, argument.key, + argument.min, argument.max, argument.description); + } + } walk(options); - parserA = OptionParserAnnotationHelper.newOptionParserA(optionAs); + parserA = OptionParserAnnotationHelper.newApplicationA(optionAs, as,impl); return parserA; } @Override protected void enterOption(OptionContext option, int optionIndex) { - groupArgumentAs = new OptionGroupArgumentA[option.contexts.size()]; + groupArgumentAs = new GroupArgumentA[option.contexts.size()]; } @Override protected void enterGroup(OptionGroupArgumentContext group, int groupIndex) { - argumentAs = new OptionArgumentA[group.contexts.size()]; + argumentAs = new ArgumentA[group.contexts.size()]; } @Override @@ -241,17 +392,17 @@ @Override protected void exitGroup(OptionGroupArgumentContext group, int groupIndex) { - OptionGroupArgumentA groupArgumentA; - groupArgumentA = OptionParserAnnotationHelper.newOptionGroupArgumentA(group.min, + GroupArgumentA groupArgumentA; + groupArgumentA = OptionParserAnnotationHelper.newGroupArgumentA(group.min, group.max, group.pos, argumentAs); groupArgumentAs[groupIndex] = groupArgumentA; } @Override protected void exitArgument(OptionArgumentContext argument, int argumentIndex) { - OptionArgumentA argumentA = OptionParserAnnotationHelper.newOptionArgumentA( + ArgumentA argumentA = OptionParserAnnotationHelper.newArgumentA( argument.type, argument.valueType, argument.key, argument.min, - argument.max); + argument.max, argument.description); argumentAs[argumentIndex] = argumentA; } } @@ -267,40 +418,52 @@ return instance; } - OptionDefinition[] optionAs; - OptionGroupArgumentDefinition[] groupArgumentAs; - OptionArgumentDefinition[] argumentAs; + ApplicationDefinition definition; - public OptionDefinition[] run(OptionContext[] options) { - optionAs = new OptionDefinition[options.length]; + OptionDefinition[] options; + OptionGroupArgumentDefinition[] groupArguments; + OptionArgumentDefinition[] arguments; + + public ApplicationDefinition run(OptionContext[] options, OptionArgumentContext[] arguments, Class impl) { + this.options = new OptionDefinition[options.length + 1]; + OptionArgumentDefinition[] as = new OptionArgumentDefinition[arguments.length]; + if (arguments.length > 0) { + for (int i = 0; i < arguments.length; i++) { + OptionArgumentContext argument = arguments[i]; + as[i] = new OptionArgumentDefinition( + argument.type, argument.valueType, argument.key, + argument.min, argument.max); + } + } walk(options); - return optionAs; + definition = new ApplicationDefinition(as, this.options,impl); + return definition; } @Override protected void enterOption(OptionContext option, int optionIndex) { - groupArgumentAs = new OptionGroupArgumentDefinition[option.contexts.size()]; + groupArguments = new OptionGroupArgumentDefinition[option.contexts.size()]; } @Override protected void enterGroup(OptionGroupArgumentContext group, int groupIndex) { - argumentAs = new OptionArgumentDefinition[group.contexts.size()]; + arguments = new OptionArgumentDefinition[group.contexts.size()]; } @Override protected void exitOption(OptionContext option, int optionIndex) { OptionDefinition optionA = new OptionDefinition(option.key, option.description, option.min, option.max, option.alias, - option.impl, groupArgumentAs); - optionAs[optionIndex] = optionA; + option.impl, groupArguments); + options[optionIndex] = optionA; } @Override protected void exitGroup(OptionGroupArgumentContext group, int groupIndex) { OptionGroupArgumentDefinition groupArgumentA; groupArgumentA = new OptionGroupArgumentDefinition(group.min, - group.max, group.pos, argumentAs); - groupArgumentAs[groupIndex] = groupArgumentA; + group.max, group.pos, arguments); + groupArguments[groupIndex] = groupArgumentA; } @Override @@ -308,7 +471,7 @@ OptionArgumentDefinition argumentA = new OptionArgumentDefinition( argument.type, argument.valueType, argument.key, argument.min, argument.max); - argumentAs[argumentIndex] = argumentA; + arguments[argumentIndex] = argumentA; } } } Index: lutinutil/src/java/org/codelutin/util/OptionParserException.java diff -u lutinutil/src/java/org/codelutin/util/OptionParserException.java:1.1 lutinutil/src/java/org/codelutin/util/OptionParserException.java:1.2 --- lutinutil/src/java/org/codelutin/util/OptionParserException.java:1.1 Sat Nov 17 11:07:20 2007 +++ lutinutil/src/java/org/codelutin/util/OptionParserException.java Wed Dec 5 03:03:57 2007 @@ -18,6 +18,11 @@ package org.codelutin.util; +import org.codelutin.util.OptionParserUtil.OptionParserContext; + +import java.util.ArrayList; +import java.util.List; + /** * Exception soulevable uniquement par le parser d'option. * @@ -25,14 +30,35 @@ * @see OptionParser */ public class OptionParserException extends Exception { // OptionParserException - private static final long serialVersionUID = -7847751486506278509L; - public OptionParserException(String msg) { + final OptionParserUtil.OptionParserContext context; + private static final long serialVersionUID = -4760568663653584477L; + + public OptionParserException(String msg, OptionParserContext context) { super(msg); + this.context = context; } - public OptionParserException(String msg, Throwable eee) { + public OptionParserException(String msg, Throwable eee, OptionParserContext context) { super(msg, eee); + this.context = context; } + @Override + public String toString() { + StringBuilder builder = new StringBuilder().append(super.toString()).append("\nfrom contexts :"); + OptionParserContext cont = context; + List l = new ArrayList(); + String prefix = ""; + while (!cont.isRoot()) { + l.add(cont); + cont = (OptionParserContext) cont.parent; + } + l.add(cont); + for (OptionParserContext context : l) { + builder.append('\n').append(prefix).append(context); + prefix += " "; + } + return builder.toString(); + } } // OptionParserException \ No newline at end of file Index: lutinutil/src/java/org/codelutin/util/OptionArgument.java diff -u lutinutil/src/java/org/codelutin/util/OptionArgument.java:1.5 lutinutil/src/java/org/codelutin/util/OptionArgument.java:1.6 --- lutinutil/src/java/org/codelutin/util/OptionArgument.java:1.5 Thu Nov 29 22:23:01 2007 +++ lutinutil/src/java/org/codelutin/util/OptionArgument.java Wed Dec 5 03:03:57 2007 @@ -24,8 +24,7 @@ public class OptionArgument { /** la definition de l'argument */ - protected OptionArgumentDefinition definition; - + //protected OptionArgumentDefinition definition; /** l'argument de la ligne de commande qui a été consommé par cet argument */ protected String arg; @@ -38,11 +37,18 @@ */ protected int pos; - public OptionArgument(OptionArgumentDefinition definition, int pos, String arg, T value) { + protected String key; + protected OptionArgumentValueType valueType; + protected OptionArgumentType type; + + public OptionArgument(String key, OptionArgumentType type, OptionArgumentValueType valueType, int pos, String arg, T value) { + this.type = type; + this.valueType = valueType; this.arg = arg; this.value = value; this.pos = pos; - this.definition = definition; + this.key = key; + //this.definition = definition; } /** @return l'argument consommé de la ligne de commande */ @@ -66,19 +72,31 @@ return pos; } + public String getKey() { + return key; + } + @Override public String toString() { StringBuilder sb; if (pos == -1) { sb = new StringBuilder("["); - sb.append("key:").append(definition.key).append(", arg:").append(arg).append(", value:").append(value); + sb.append("key:").append(key).append(", arg:").append(arg).append(", value:").append(value); sb.append(']'); } else { sb = new StringBuilder("<"); - sb.append("key:").append(definition.key).append(", arg:").append(arg).append(", value:").append(value); + sb.append("key:").append(key).append(", arg:").append(arg).append(", value:").append(value); sb.append(", pos:").append(pos); sb.append('>'); } return sb.toString(); } + + public OptionArgumentType getType() { + return type; + } + + public OptionArgumentValueType getValueType() { + return valueType; + } } Index: lutinutil/src/java/org/codelutin/util/Option.java diff -u lutinutil/src/java/org/codelutin/util/Option.java:1.6 lutinutil/src/java/org/codelutin/util/Option.java:1.7 --- lutinutil/src/java/org/codelutin/util/Option.java:1.6 Sun Dec 2 05:14:56 2007 +++ lutinutil/src/java/org/codelutin/util/Option.java Wed Dec 5 03:03:57 2007 @@ -17,7 +17,7 @@ *@author Benjamin Poussin * * Copyright Code Lutin - *@version $Revision: 1.6 $ Mise a jour: $Date: 2007-12-02 05:14:56 $ par : $Author: tchemit $ + *@version $Revision: 1.7 $ Mise a jour: $Date: 2007-12-05 03:03:57 $ par : $Author: tchemit $ */ package org.codelutin.util; @@ -142,9 +142,9 @@ protected T filterValue(int position, OptionArgumentType type, Class clazz, String key) { for (OptionArgument argument : arguments) { if (argument.getPos() == position - && argument.definition.getType() == type - && argument.definition.getValueType().getClazz() == clazz - && (key == null || argument.definition.getKey().equals(key))) { + && argument.getType() == type + && argument.getValueType().getClazz() == clazz + && (key == null || argument.getKey().equals(key))) { return (T) argument.getValue(); } } @@ -156,9 +156,9 @@ List result = new ArrayList(); for (OptionArgument argument : arguments) { if (argument.getPos() == position - && argument.definition.getType() == type - && argument.definition.getValueType().getClazz() == clazz - && (key == null || argument.definition.getKey().equals(key))) { + && argument.getType() == type + && argument.getValueType().getClazz() == clazz + && (key == null || argument.getKey().equals(key))) { result.add((T) argument.getValue()); } } Index: lutinutil/src/java/org/codelutin/util/OptionGroupArgumentDefinition.java diff -u lutinutil/src/java/org/codelutin/util/OptionGroupArgumentDefinition.java:1.1 lutinutil/src/java/org/codelutin/util/OptionGroupArgumentDefinition.java:1.2 --- lutinutil/src/java/org/codelutin/util/OptionGroupArgumentDefinition.java:1.1 Sun Dec 2 05:11:36 2007 +++ lutinutil/src/java/org/codelutin/util/OptionGroupArgumentDefinition.java Wed Dec 5 03:03:57 2007 @@ -12,8 +12,7 @@ */ package org.codelutin.util; -import org.codelutin.util.OptionParserAnnotationHelper.OptionArgumentA; -import org.codelutin.util.OptionParserAnnotationHelper.OptionGroupArgumentA; +import org.codelutin.util.OptionParserAnnotationHelper.ArgumentA; /** * Cette classe représente la définition d'un groupe d'arguments d'une option. @@ -60,11 +59,11 @@ this.arguments = arguments; } - public OptionGroupArgumentDefinition(OptionGroupArgumentA definition) { + public OptionGroupArgumentDefinition(OptionParserAnnotationHelper.GroupArgumentA definition) { this.min = definition.min(); this.max = definition.max(); this.pos = definition.pos(); - OptionArgumentA[] argumentDefinitions = definition.arguments(); + ArgumentA[] argumentDefinitions = definition.arguments(); this.arguments = new OptionArgumentDefinition[argumentDefinitions.length]; for (int i = 0; i < argumentDefinitions.length; i++) { this.arguments[i] = new OptionArgumentDefinition(argumentDefinitions[i]); Index: lutinutil/src/java/org/codelutin/util/OptionParser.java diff -u lutinutil/src/java/org/codelutin/util/OptionParser.java:1.6 lutinutil/src/java/org/codelutin/util/OptionParser.java:1.7 --- lutinutil/src/java/org/codelutin/util/OptionParser.java:1.6 Thu Nov 29 22:25:29 2007 +++ lutinutil/src/java/org/codelutin/util/OptionParser.java Wed Dec 5 03:03:57 2007 @@ -21,20 +21,18 @@ package org.codelutin.util; import org.apache.commons.beanutils.ConvertUtils; -import org.apache.commons.logging.LogFactory; import static org.codelutin.i18n.I18n._; -import static org.codelutin.util.OptionDefinitionParser.LUTINUTIL_PARSERDEF_PRINT_DETAIL_OPTION_HEAD; -import org.codelutin.util.OptionParserAnnotationHelper.OptionDefinitionA; -import org.codelutin.util.OptionParserAnnotationHelper.OptionParserA; +import org.codelutin.log.LutinLog; +import org.codelutin.log.LutinLogFactory; +import org.codelutin.util.OptionParserAnnotationHelper.ApplicationA; +import org.codelutin.util.OptionParserAnnotationHelper.ArgumentA; +import org.codelutin.util.OptionParserAnnotationHelper.OptionA; import java.io.IOException; import java.io.Writer; import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; +import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -45,341 +43,189 @@ * Parser abstrait d'options de la ligne de commande. *

* Pour implanter le parseur il suffit de surcharger cette classe et d'y ajouter - * l'annotation {@link OptionParserAnnotationHelper.OptionParserA} au niveau de la classe, en y - * indiquant la définition du parser. + * l'annotation {@link ApplicationA} au niveau de la classe, en y indiquant + * la définition du parser. *

- * Ensuite on utilise la méthode publique statique {@link #newParser(String, ClassLoader)} - * pour obtenir une nouvelle instance de parser à partir du nom de sa classe et - * de son classLoader. + * A l'instanciation de la classe, l'annotation sera transformée en + * {@link OptionDefinition} (et ses sous-classes group, argument). *

- * Enfin sur le parseur retourné, on invoque la méthode {@link #doParse(String[])} + * Exemple d'un parseur avec une unique option pour afficher l'aide: + *


+ * @ApplicationA ( options =
+ *     @OptionA(
+ *         key="help",
+ *         alias = {"--help", "-h"},
+ *         description = "affiche l'aide"
+ *     )
+ * )
+ * public class MyParser extends OptionParser {...}
+ *

+ * Voici un exemple plus concret TODO a finir. + *

+ * On peut aussi associer à une définition d'option une implantation d'option + * (elle peut être générée automatiquement par le plugin maven-commandline-plugin). + *

+ * Pour utiliser le parseur , on invoque la méthode {@link #doParse(String[])} * pour effectuer le parsing des arguments passés. + *

+ * A noter que tous les champs de la classes doivent être préfixés par '_' pour + * assurer que des collisions ne peuvent pas arriver avec des propriétés générés + * qui elles n'acceptent pas '_' comme premier caractère d'identifiant. * - * @author chemit - * @see OptionParserAnnotationHelper.OptionParserA + * @see ApplicationA */ public abstract class OptionParser { - public static OptionParser newParser(String className, ClassLoader loader) { - - Class parserClass; - OptionParser parser; - try { - // find parser class - parserClass = Class.forName(className, true, loader); - // instanciate parser, load factory and init ParserContext - parser = (OptionParser) parserClass.newInstance(); - return parser; - } catch (ClassNotFoundException e) { - throw new IllegalArgumentException(e); - } catch (IllegalAccessException e) { - throw new IllegalArgumentException(e); - } catch (InstantiationException e) { - throw new IllegalArgumentException(e); - } - } - - protected final org.apache.commons.logging.Log log; + public static final String APPLICATION_ARGUMENTS_FIELD_NAME = "applicationArguments"; - /** le context du parseur (contenant les données temporaires du parsing). */ - protected final ParserContext context; - - /** la liste des définitions d'options connues */ - protected final Map definitions; - - /** - * la liste des options, la cle est le nom de l'option, et la valeur - * est la liste des options qui ont été lues grâce à celle-ci. - */ - protected final Map> options; - - /** - * La liste des arguments qui ne sont pas des options insérés dans leur - * ordre d'apparition dans la ligne de commande - */ - protected final List arguments; + Option applicationArguments; - protected final Map actions; + public Option getApplicationArguments() { + return applicationArguments; + } - public OptionParser() { + public void setApplicationArguments(Option applicationArguments) { + this.applicationArguments = applicationArguments; + } - // find the fullyQualifiedFactoryName via OptionParserA annotation - OptionParserA def = getClass().getAnnotation(OptionParserA.class); - if (def == null) { - //TODO i18n - throw new IllegalArgumentException("could not found annotation " + - OptionParserA.class + " in Parser " + this); - } - this.log = LogFactory.getLog(getClass()); - - this.definitions = new LinkedHashMap(); - this.arguments = new ArrayList(); - this.options = new HashMap>(); - this.actions = new HashMap(); - try { - Map map; - OptionDefinitionA defA; - OptionDefinition definition; - - map = new HashMap(); - - for (String key : def.keys()) { - String fieldName = StringUtil.convertToConstantName(key); - Field field = getClass().getField(fieldName); - defA = field.getAnnotation(OptionDefinitionA.class); - definition = new OptionDefinition(defA); - map.put(key, definition); - } - List keys1 = new ArrayList(map.keySet()); - Collections.sort(keys1); - for (String key : keys1) { - this.definitions.put(key, map.get(key)); - } - keys1.clear(); - map.clear(); - // create parser context - context = new ParserContext(this.definitions); + /** logger non statique pour épouser la catégorie de l'implantation */ + protected final LutinLog log = LutinLogFactory.getLutinLog(getClass()); - } catch (NoSuchFieldException e) { - throw new IllegalArgumentException(e); - } - } + /** l'annotation de définition du parseur */ + protected final ApplicationA _anno; - /** - * Register an action associated to an Option. - * - * @param optionKey option key - * @param action action to realise for the option - */ - public void registerAction(String optionKey, OptionAction action) { - if (!definitions.containsKey(optionKey)) { - throw new IllegalArgumentException("could not found this option " + optionKey); - } - if (actions.containsKey(optionKey)) { - throw new IllegalArgumentException("already action registred for this option " + optionKey); - } - actions.put(optionKey, action); - } + /** la liste des définitions d'options connues */ + protected final Map _odefinitions; - /** - * Launch parsing of some arguments. - * - * @param args arguments to parse - * @throws OptionParserException if any problem while parsing - */ - public void doParse(String... args) throws OptionParserException { - if (args.length > 0) { - // detect OptionContexts - prepareContexts(args); - } + /** la liste des définitions d'arguments connus */ + protected final Map _adefinitions; - // check coherence on detected OptionContexts TODO Finish me - checkPostParsing(); + /** le dictionnaire des definitions d'options indexées par leurs alias */ + protected final Map _indexAlias; - if (context.optionContexts != null) { - for (OptionContext optionContext : context.optionContexts) { - // instanciate option from his context - instanciateOption(optionContext); - } - } - //TODO Report errors from context before clear context + protected Class _argImpl; - context.clear(); - } + /** le dictionnaire d'actions associées aux options */ + protected final Map _actions; - public boolean isEnabled(String key) { - List

- * Prépare avec les contexts d'options. - * - * @param args la liste des arguments à scanner - */ - protected void prepareContexts(String... args) { + this._odefinitions = new LinkedHashMap(); + this._adefinitions = new LinkedHashMap(); + this._indexAlias = new TreeMap(); - OptionContext optionContext = null; - - for (int i = 0; i < args.length; i++) { - String argument = args[i]; - if (argument.startsWith("-")) { - // alias detected - OptionDefinition newOption = context.indexAlias.get(argument); - if (newOption == null) { - // unknown argument - arguments.add(argument); - continue; + if (anno.options().length > 0) { + // parser have some available options + for (OptionA optionA : anno.options()) { + // build each definition from his associated OptionA + OptionDefinition definition = new OptionDefinition(optionA); + _odefinitions.put(optionA.key(), definition); + _acceptedOptions.put(optionA.key(), new ArrayList

- * Le context a été vérifié auparavant et on sait que l'option et ses - * arguments sont valides. - *

+ * Launch parsing of some arguments. * - * @param optionContext le contexte d'une option parsée + * @param args arguments to parse + * @throws OptionParserException if any problem while parsing + * @throws java.io.IOException if io problems with writers */ - protected void instanciateOption(OptionContext optionContext) { - - int position = 0; - - List arguments = new ArrayList(); - - for (OptionArgumentContext argumentContext : optionContext.argumentsFound) { - - // get argument from command line - String argument = argumentContext.getArgument(); + public void doParse(String... args) throws OptionParserException, IOException { + cleanResult(); + ParserContext2 context = new ParserContext2(); - // get argument definition - OptionArgumentDefinition argumentDefinition = argumentContext.getDefinition(); - // extract value as String for the argument type - String valueStr = argumentDefinition.getType().extractArgumentValue(argument); + if (args.length == 0) { + _errors = new OptionParserException[0]; + return; + } - // convert to matching type from argument definition value type - Object value = ConvertUtils.convert(valueStr, argumentDefinition.getValueType().getClazz()); + // detect application arguments (before first alias) + context.detectApplicationArguments(args.length, args); - // add argument to option - OptionArgument optionArgument; + // detect options + context.detectOptions(args); - // get real position for this argument (-1 for an optional one) - int realPosition = argumentContext.definition.isMandatory() ? position : OptionArgumentDefinition.OPTIONAL_POSITION; + // transfert errors from parser context + _errors = context.getErrors().toArray(new OptionParserException[context.getNbErrors()]); - // instanciate concrete argument - optionArgument = new OptionArgument( - argumentContext.definition, - realPosition, - argumentContext.argument, - value - ); + context.clear(); - arguments.add(optionArgument); + } - if (argumentDefinition.isMandatory()) { - // increments next mandatory position - position++; - } + private void cleanResult() { + for (Map.Entry> stringListEntry : _acceptedArguments.entrySet()) { + stringListEntry.getValue().clear(); } - - // finally instanciate option and store it - String key = optionContext.definition.getName(); - Option option = optionContext.newOption(arguments); - List