org.sd.util.cmd.AbstractExecutor.java Source code

Java tutorial

Introduction

Here is the source code for org.sd.util.cmd.AbstractExecutor.java

Source

/*
Copyright 2009 Semantic Discovery, Inc. (www.semanticdiscovery.com)
    
This file is part of the Semantic Discovery Toolkit.
    
The Semantic Discovery Toolkit is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
The Semantic Discovery Toolkit 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 Lesser General Public License for more details.
    
You should have received a copy of the GNU Lesser General Public License
along with The Semantic Discovery Toolkit.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.sd.util.cmd;

import org.sd.io.FileUtil;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;

/**
 * Abstract implementation of a command executor.
 * <p>
 * @author Spence Koehler
 */
public abstract class AbstractExecutor implements CommandExecutor {

    private String commandName;
    private String description;
    private CommandLineParser parser;
    private Options _options;

    protected abstract Options buildOptions();

    protected abstract boolean execute(CommandInterpreter interpreter, CommandLine commandLine, boolean batchMode);

    protected AbstractExecutor(String commandName, String description) {
        this.commandName = commandName;
        this.description = description;
        this.parser = new PosixParser();
        this._options = null;
    }

    protected final Options getOptions() {
        if (_options == null) {
            _options = buildOptions();
        }
        return _options;
    }

    /**
     * Execute this command with the given args, returning the status of the
     * execution (true=ok, false=error).
     * <p>
     * Note that any error or response to be printed by the interpreter needs to
     * be handled here.
     * <p>
     * @param interpreter  the interpreter executing the command.
     * @param argsString   string containing arguments for the command.
     * @param batchMode    true if interpreter is operating in batchMode; false if interactive.
     *
     * @return true for successful execution (from the interpreter's standpoint); otherwise, false.
     */
    public boolean execute(CommandInterpreter interpreter, String argsString, boolean batchMode) {
        boolean result = false;
        final Options options = getOptions();
        final String[] args = parseArgsString(interpreter, argsString);

        try {
            final CommandLine commandLine = parser.parse(options, args);
            result = execute(interpreter, commandLine, batchMode);
        } catch (ParseException e) {
            interpreter.showError("BadArgs", FileUtil.getStackTrace(e), batchMode);
        } catch (Throwable t) {
            interpreter.showError("ExecutionError", FileUtil.getStackTrace(t), batchMode);
        }

        return result;
    }

    /**
     * Get the name of this command.
     */
    public String getCommandName() {
        return commandName;
    }

    /**
     * Get a short description for this command.
     */
    public String getDescription() {
        return description;
    }

    protected static String[] parseArgsString(CommandInterpreter interpreter, String argsString) {
        // split on spaces unless quoted. make variable substitutions
        final List<String> result = new ArrayList<String>();

        final int len = (argsString == null) ? 0 : argsString.length();

        if (len > 0) {
            argsString = doVariableSubstitutions(interpreter, argsString);

            final char[] chars = argsString.toCharArray();
            final StringBuilder stringBuilder = new StringBuilder();
            int index = 0;

            while (index < len) {
                // spin past any whitespace
                while (index < chars.length && chars[index] == ' ')
                    ++index;

                int endPos = index;
                int dataBegin = index;
                int dataEnd = index + 1;

                if (chars[index] == '\'') {
                    // find unescaped end single quote
                    endPos = findEndSingleQuote(chars, index + 1);
                    if (endPos > index) {
                        dataBegin++;
                        dataEnd = endPos;
                    }
                } else if (chars[index] == '"') {
                    // find unescaped end double quote
                    endPos = findEndDoubleQuote(chars, index + 1);
                    if (endPos > index) {
                        dataBegin++;
                        dataEnd = endPos;
                    }
                } else if (chars[index] == '(') {
                    // find unescaped, balanced end paren
                    endPos = findEndParen(chars, index + 1);
                    if (endPos > index) {
                        dataEnd = endPos + 1;
                    }
                } else {
                    // find end of "word"
                    endPos = findEndWord(chars, index + 1);
                    if (endPos > index) {
                        dataEnd = endPos;
                    }
                }

                for (int i = dataBegin; i < dataEnd; ++i) {
                    stringBuilder.append(chars[i]);
                }

                if (stringBuilder.length() > 0) {
                    result.add(stringBuilder.toString());
                    stringBuilder.setLength(0); // clear out for next go-round
                }

                //make sure index has been inc'd
                index = endPos + 1;
            }
        }

        return result.toArray(new String[result.size()]);
    }

    protected static String doVariableSubstitutions(CommandInterpreter interpreter, String argsString) {
        final StringBuilder result = new StringBuilder();

        final int len = argsString.length();
        int curPos = 0;

        while (curPos < len) {
            final int dollarPos = argsString.indexOf("$", curPos);
            if (dollarPos >= 0) {
                result.append(argsString.substring(curPos, dollarPos));
                curPos = dollarPos + 1;
                if (isEscaped(argsString, dollarPos, new char[] { '$', '\\' })) {
                    result.setLength(result.length() - 1); // chop off escape char
                    result.append('$');
                    continue;
                }
                final int endPos = nextSymbol(argsString, dollarPos + 1);
                if (endPos > dollarPos + 1) {
                    final String varName = argsString.substring(dollarPos + 1, endPos);
                    final String value = interpreter.getVar(varName);
                    if (value != null) {
                        result.append(value);
                    } else {
                        result.append('$').append(argsString.substring(curPos, endPos));
                    }
                    curPos = endPos;
                } else {
                    result.append('$');
                    continue;
                }
            } else {
                result.append(argsString.substring(curPos, len));
                curPos = len;
            }
        }

        return result.toString();
    }

    protected static boolean isEscaped(String string, int pos, char[] escapeChars) {
        if (pos > 0) {
            final char prevChar = string.charAt(pos - 1);
            for (char escapeChar : escapeChars) {
                if (prevChar == escapeChar)
                    return true;
            }
        }

        return false;
    }

    protected static int nextSymbol(String string, int fromPos) {
        final int len = string.length();
        while (fromPos < len && Character.isLetterOrDigit(string.charAt(fromPos)))
            ++fromPos;
        return fromPos;
    }

    protected static int findEndSingleQuote(char[] chars, int startPos) {
        while (startPos < chars.length) {
            if (chars[startPos] == '\'' && chars[startPos - 1] != '\\') {
                return startPos;
            }
            ++startPos;
        }
        return -1;
    }

    protected static int findEndDoubleQuote(char[] chars, int startPos) {
        while (startPos < chars.length) {
            if (chars[startPos] == '"' && chars[startPos - 1] != '\\') {
                return startPos;
            }
            ++startPos;
        }
        return -1;
    }

    protected static int findEndParen(char[] chars, int startPos) {
        int numParens = 1;
        while (startPos < chars.length && numParens > 0) {
            if (chars[startPos] == ')') {
                --numParens;
                if (numParens == 0)
                    return startPos;
            } else if (chars[startPos] == '(') {
                ++numParens;
            }
            ++startPos;
        }
        return -1;
    }

    protected static int findEndWord(char[] chars, int startPos) {
        while (startPos < chars.length && chars[startPos] != ' ')
            ++startPos;
        return startPos;
    }
}