001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.q2;
020
021import java.io.IOException;
022import java.util.ArrayList;
023import java.util.List;
024import java.util.regex.Matcher;
025import java.util.regex.Pattern;
026
027import org.jline.terminal.Terminal;
028import org.jpos.iso.ISOUtil;
029
030public class CLICommandInterface {
031    CLIContext ctx;
032    List<String> prefixes = new ArrayList<String>();
033
034    public List<String> getPrefixes() {
035        return prefixes;
036    }
037
038    public CLICommandInterface(CLIContext ctx) {
039        this.ctx = ctx;
040    }
041
042    public void addPrefix(String prefix) {
043        prefixes.add(prefix);
044    }
045
046    public void execCommand(String line) throws IOException {
047        String args[] = parseCommand(line);
048        if (args.length == 0) {
049            return;
050        }
051        String verbatimCmd = args[0];
052        String command = args[0].toUpperCase();
053        String className = command;
054
055        for (String prefix : prefixes) {
056            if (!command.contains(".")) {
057                className = prefix + command;
058            }
059            try {
060                Object cmd = getCommand(className);
061                if (cmd != null) {
062                    try {
063                        args[0] = ISOUtil.unPadLeft(line, ' '); // full line
064                        if (cmd instanceof CLISubSystem) {
065                            CLISubSystem ss = (CLISubSystem) cmd;
066                            ctx.getCLI().setPrompt(ss.getPrompt(ctx, args), ss.getCompletionPrefixes(ctx, args));
067                        }
068                        if (cmd instanceof CLICommand) {
069                            ((CLICommand) cmd).exec(ctx, args);
070                        } else if (cmd instanceof Command) {
071                            Terminal t = ctx.getReader().getTerminal();
072                            ((Command) cmd).exec (t.input(), t.output(), t.output(), args);
073                        }
074                        return;
075                    } catch (Exception ex) {
076                        ctx.printThrowable(ex);
077                    }
078                }
079            } catch (ClassNotFoundException ignored) {
080                // NOPMD
081            } catch (Exception ex) {
082                ctx.printThrowable(ex);
083                break;
084            }
085        }
086        ctx.println("Invalid command '" + verbatimCmd + "'");
087    }
088
089    private Object getCommand(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
090        final ClassLoader cl = Thread.currentThread().getContextClassLoader();
091        return cl.loadClass(className).newInstance();
092    }
093
094    public String[] parseCommand(String line) throws IOException {
095        if (line == null) {
096            return new String[0];
097        }
098
099        List<String> matchList = new ArrayList<String>();
100        Pattern regex = Pattern.compile("[^\\s\"']+|\"([^\"]*)\"|'([^']*)'");
101        Matcher regexMatcher = regex.matcher(line);
102        while (regexMatcher.find()) {
103            if (regexMatcher.group(1) != null) {
104                // Add double-quoted string without the quotes
105                matchList.add(regexMatcher.group(1));
106            } else if (regexMatcher.group(2) != null) {
107                // Add single-quoted string without the quotes
108                matchList.add(regexMatcher.group(2));
109            } else {
110                // Add unquoted word
111                matchList.add(regexMatcher.group());
112            }
113        }
114        String[] args = new String[matchList.size()];
115        matchList.toArray(args);
116        return args;
117    }
118}