Index: lutinutil/src/java/org/codelutin/option/OptionAction.java
diff -u /dev/null lutinutil/src/java/org/codelutin/option/OptionAction.java:1.1
--- /dev/null Sun Dec 30 22:50:52 2007
+++ lutinutil/src/java/org/codelutin/option/OptionAction.java Sun Dec 30 22:50:46 2007
@@ -0,0 +1,69 @@
+package org.codelutin.option;
+
+/**
+ * A simple empty action for an option.
+ *
+ * Use method {@link #doRun(Option[])} to launch action for the given options.
+ *
+ * This method offers some hooks to use for controling running :
+ *
+ * {@link #beforeAll(Option[])} : no {@link #option} is set, before any doRun.
+ *
+ * {@link #beforeRun()} : an {@link #option} has been set in action, just before {@link #run()}
+ *
+ * {@link #afterRun()} : just after {@link #run()}, the current {@link #option} is still available.
+ *
+ * {@link #afterAll(Option[])} : no more {@link #option} is set, after all doRun.
+ *
+ * @author chemit
+ */
+
+public abstract class OptionAction {
+ /**
+ * Method to implement logic of the action for the current option.
+ *
+ * This method will never by directly called, you have to use
+ * {@link #doRun(Option[])} method instead which offers some hooks to control actions.
+ *
+ * @throws Exception if any problem while action
+ */
+ protected abstract void run() throws Exception;
+
+ /** the parser used to obtain options */
+ protected P parser;
+
+ /** the current option to be used for running. */
+ protected O option;
+
+ protected OptionAction(P parser) {
+ this.parser = parser;
+ }
+
+ public void doRun(O... options) throws Exception {
+ beforeAll(options);
+ for (O option : options) {
+ this.option = option;
+ beforeRun();
+ run();
+ afterRun();
+ this.option = null;
+ }
+ afterAll(options);
+ }
+
+ protected void beforeAll(O... options) {
+ }
+
+ protected void beforeRun() {
+ }
+
+ protected void afterRun() {
+ }
+
+ protected void afterAll(O... options) {
+ }
+
+ protected P getParser() {
+ return parser;
+ }
+}
Index: lutinutil/src/java/org/codelutin/option/OptionParserContexts.java
diff -u /dev/null lutinutil/src/java/org/codelutin/option/OptionParserContexts.java:1.1
--- /dev/null Sun Dec 30 22:50:52 2007
+++ lutinutil/src/java/org/codelutin/option/OptionParserContexts.java Sun Dec 30 22:50:46 2007
@@ -0,0 +1,626 @@
+/*
+* ##% Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Code Lutin,
+* Tony Chemit
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+* ##% */
+package org.codelutin.option;
+
+import org.apache.commons.beanutils.ConvertUtils;
+import org.codelutin.option.def.ArgumentDefinition;
+import org.codelutin.option.def.ArgumentType;
+import org.codelutin.option.def.ArgumentValueType;
+import org.codelutin.option.def.GroupDefinition;
+import org.codelutin.option.def.OptionDefinition;
+import org.codelutin.util.CardinalityHelper;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * La classe contenant tous les contextes de parsing pour le parseur {@link OptionParser}
+ *
+ * @author tony
+ */
+public class OptionParserContexts {
+
+ public static ArgumentDefinition findArgumentByTypeAndKey(ArgumentType type, String key, ArgumentDefinition... defs) {
+ for (ArgumentDefinition def : defs) {
+ if (def.getType() == type && def.getKey().equals(key)) {
+ return def;
+ }
+ }
+ return null;
+ }
+
+ public static ArgumentDefinition findArgumentByTypeAndValueType(ArgumentType type, ArgumentValueType valueType, ArgumentDefinition... defs) {
+ for (ArgumentDefinition def : defs) {
+ if (def.getType() == type && def.getValueType() == valueType) {
+ return def;
+ }
+ }
+ return null;
+ }
+
+ public static List getOptionalGroups(List groups) {
+ List result = new ArrayList();
+ for (GroupDefinition group : groups) {
+ if (!group.isMandatory()) {
+ result.add(group);
+ }
+ }
+ return result;
+ }
+
+ public static GroupDefinition getNextMandatoryGroup(List groups) {
+ for (GroupDefinition group : groups) {
+ if (group.isMandatory()) {
+ return group;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * le context de base à utiliser dans le parseur d'options {@link OptionParser}
+ *
+ * @author chemit
+ */
+ abstract static class AbstractOptionParserContext
, S extends ParserUtil.AbstractParserContext> extends ParserUtil.AbstractParserContext
{
+ protected AbstractOptionParserContext(P parent, boolean withSons) {
+ super(parent, withSons);
+ }
+
+ protected abstract Object instanciate();
+
+ protected ParserException newError(String content, Exception e) {
+ ParserException e1;
+ if (e == null) {
+ e1 = new ParserException(content, this);
+ } else if (e instanceof ParserException) {
+ // propage exception
+ e1 = (ParserException) e;
+ } else {
+ e1 = new ParserException(content, e, this);
+ }
+ return e1;
+ }
+ }
+
+ /**
+ * Cette classe contient les contextes d'options détectés pendand le parsing.
+ *
+ * Elle est de visibilité package, car elle n'a pas à être utilisée ailleurs.
+ *
+ * @author chemit
+ */
+ static class ParserContext extends AbstractOptionParserContext {
+
+ /** le dictionnaire des definitions d'options indexées par leurs alias */
+ protected final Map indexAlias;
+
+ /** order on options by their names */
+ protected final List definitionsIndex;
+
+ /** les occurences des options trouvées (est mis à jour dans la méthode */
+ final int[] optionFounds;
+
+ /** les positions des args non utilisés */
+ final List unusedArguments;
+
+ /** les options disponibles pendant la détection des args */
+ final List availabledOptions;
+
+ int pos = 0;
+ private OptionParser parser;
+
+ protected ParserContext(OptionParser parser) {
+ super(null, true);
+ this.parser = parser;
+ optionFounds = new int[parser.getOptionKeys().size()];
+ unusedArguments = new ArrayList();
+ availabledOptions = new ArrayList();
+ this.definitionsIndex = new ArrayList();
+ this.indexAlias = new TreeMap();
+ for (OptionKey optionKey : parser.getOptionKeys()) {
+ OptionDefinition definition = optionKey.getDefinition();
+ availabledOptions.add(definition);
+ definitionsIndex.add(definition.getKey());
+ // keep all alias of the option
+ for (String alias : definition.getAlias()) {
+ indexAlias.put(alias, definition);
+ }
+ }
+ }
+
+ @Override
+ protected void clear() {
+ super.clear();
+ unusedArguments.clear();
+ availabledOptions.clear();
+ definitionsIndex.clear();
+ indexAlias.clear();
+ pos = 0;
+ }
+
+ /**
+ * Detecte les options et leurs arguments, à partir de la suite des
+ * arguments donnés et construit la liste des parser d'options.
+ *
+ * Détecte les contextes d'options à analyser.
+ * Une fois un contexte d'option détecté (un alias et les arguments
+ * jusqu'au prochain alias), on instancie un {@link OptionContext},
+ * et on lance la méthode
+ * {@link #addSon(org.codelutin.option.ParserUtil.AbstractParserContext)}.
+ *
+ * Cette méthode suit l'algorthime générique, on surcharge
+ * {@link #preAddSonHook(OptionContext)} , pour lancer l'analyse de
+ * l'option, et la méthode {@link #postAddSonHook(OptionContext)}
+ * pour mettre à jour la table d'occurrences des options trouvées si
+ * l'option est valide.
+ *
+ * @param args la liste des arguments à scanner
+ */
+ protected void detectOptions(String... args) {
+ int length = args.length;
+
+ List argsForOption = new ArrayList();
+ // detect all arguments before first alias
+ fillArgumentsForOption(length, argsForOption, true, args);
+
+ while (pos < length) {
+ // detect a new option with his arguments
+ // coming here means pos is exactly an index of an option's alias
+ int start = pos;
+ String alias = args[pos++];
+ // detect all arguments before next alias
+ argsForOption.clear();
+ fillArgumentsForOption(length, argsForOption, false, args);
+
+ // a fully option was detected
+ log.info(" (pos " + start + ") " + alias + " " + argsForOption);
+ // find definition from alias
+ OptionDefinition definition = indexAlias.get(alias);
+ if (definition == null) {
+ //fatal error : unknown option
+ addError(org.codelutin.i18n.I18n._("lutinutil.parser.unknown.option", alias, start));
+ continue;
+ }
+ if (!availabledOptions.contains(definition)) {
+ // fatal error : the option is not available
+ addError(org.codelutin.i18n.I18n._("lutinutil.parser.unavailable.option", alias, start));
+ continue;
+ }
+ // create a OptionContext
+ OptionContext optionContext = new OptionContext(parser, this, definition, argsForOption.toArray(new String[argsForOption.size()]), start, alias);
+ // try to add the parser
+ addSon(optionContext);
+ }
+ // check if we did not miss a mandatory option
+ for (OptionDefinition definition : availabledOptions) {
+ if (definition.isMandatory()) {
+ int optionPos = definitionsIndex.indexOf(definition.getKey());
+ if (optionFounds[optionPos] == 0) {
+ addError(org.codelutin.i18n.I18n._("lutinutil.error.parser.unfound.mandatory.option", definition));
+ }
+ }
+ }
+ // check the min property on each found option
+ for (OptionContext context : contexts) {
+ int optionPos = definitionsIndex.indexOf(context.definition.getKey());
+ int nbOccur = optionFounds[optionPos];
+ int min = context.definition.getMin();
+ if (nbOccur < min) {
+ addError(org.codelutin.i18n.I18n._("lutinutil.error.parser.too.less.option.found", context.definition, nbOccur, min));
+ }
+ }
+ }
+
+ protected Map> instanciate() {
+ Map> acceptedOptions = new LinkedHashMap>();
+ for (OptionContext context : contexts) {
+ Option option = context.instanciate();
+ OptionKey key = parser.getOptionKey(context.definition.getKey());
+ List