001    /*
002     * JAPI - (Yet another (hopefully) useful) Java API
003     *
004     * Copyright (C) 2006 Christian Hujer
005     *
006     * This program is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU General Public License as
008     * published by the Free Software Foundation; either version 2 of the
009     * License, or (at your option) any later version.
010     *
011     * This program is distributed in the hope that it will be useful, but
012     * WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * General Public License for more details.
015     *
016     * You should have received a copy of the GNU General Public License
017     * along with this program; if not, write to the Free Software
018     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
019     * 02111-1307, USA.
020     */
021    
022    package net.sf.japi.io.args;
023    
024    import java.lang.reflect.InvocationTargetException;
025    import java.lang.reflect.Method;
026    import java.util.ArrayList;
027    import java.util.Arrays;
028    import java.util.HashMap;
029    import java.util.Iterator;
030    import java.util.List;
031    import java.util.Map;
032    
033    /** Parser for command line arguments.
034     * @author <a href="mailto:chris@riedquat.de">Christian Hujer</a>
035     */
036    public class ArgParser {
037    
038        /** Parses arguments into an arguments container and invokes the Command's {@link Command#run(List<String>)} method.
039         * @param argsContainer object to hold parsed arguments
040         * @param args Arguments to parse
041         */
042        public static void parse(final Command argsContainer, final String... args) {
043            final List<String> argList = new ArrayList<String>(Arrays.asList(args));
044            final Class<?> argsContainerClass = argsContainer.getClass();
045            final Method[] argsContainerMethods = argsContainerClass.getMethods();
046            final Map<String, Method> argumentMethods = new HashMap<String, Method>();
047            for (final Method method : argsContainerMethods) {
048                final Option option = method.getAnnotation(Option.class);
049                if (option != null) {
050                    for (final String optionString : option.value()) {
051                        argumentMethods.put(optionString.length() > 1 ? '-' + optionString : optionString, method);
052                    }
053                }
054            }
055            for (final Iterator<String> it = argList.iterator(); it.hasNext(); ) {
056                final String arg = it.next();
057                if (arg.length() > 1 && arg.charAt(0) == '-') {
058                    it.remove();
059                    if ("--".equals(arg)) {
060                        //noinspection BreakStatement
061                        break;
062                    }
063                    if (arg.charAt(1) == '-') {
064                        if (invokeMethod(argumentMethods.get(arg.substring(1)), argsContainer)) {
065                            return;
066                        }
067                    } else {
068                        for (final String realArg : arg.substring(1).split("")) {
069                            if (invokeMethod(argumentMethods.get(arg.substring(1)), argsContainer)) {
070                                return;
071                            }
072                        }
073                    }
074                }
075                // empty arguments are intentionally not removed.
076            }
077            argsContainer.run(argList);
078        }
079    
080        /** Invoke an argument method.
081         * @param method
082         * @param argsContainer
083         * @return true if the method indicated to stop parsing the arguments
084         */
085        private static boolean invokeMethod(final Method method, final Command argsContainer) {
086            if (method == null) {
087                throw new RuntimeException("Unknown argument Exception");
088            }
089            try {
090                method.invoke(argsContainer);
091            } catch (final IllegalAccessException e) {
092                System.err.println(e);
093            } catch (final InvocationTargetException e) {
094                System.err.println(e.getCause());
095            }
096            return method.getAnnotation(StopOption.class) != null;
097        }
098    
099    } // class ArgParser