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.qbean;
020
021import org.jpos.q2.QBeanSupport;
022import org.jpos.util.LogEvent;
023import org.jpos.util.Logger;
024
025import java.io.*;
026import java.util.ArrayList;
027import java.util.List;
028
029/**
030* QBean for starting and stopping scripts or programs.
031* <pre>
032* Example xml:
033*  &lt;exec class="org.jpos.q2.qbean.QExec"&gt;
034*    &lt;attr name="startScript"&gt;YOUR PATH TO PROGRAM&lt;/attr&gt;
035*    &lt;attr name="shutdownScript"&gt;YOUR PATH TO PROGRAM&lt;/attr&gt;
036*  &lt;/exec&gt;
037* </pre>
038* @author Alwyn Schoeman
039* @version $Revision$ $Date$
040*/
041
042public class QExec extends QBeanSupport implements QExecMBean {
043    String startScript;
044    String shutdownScript;
045
046    @Override
047    protected void startService () throws Exception {
048        exec(startScript);
049    }
050
051    @Override
052    protected void stopService () throws Exception {
053        exec(shutdownScript);
054    }
055
056    public void setStartScript (String scriptPath) {
057        startScript = scriptPath;
058    }
059
060    public String getStartScript () {
061        return startScript;
062    }
063
064    public void setShutdownScript (String scriptPath) {
065        shutdownScript = scriptPath;
066    }
067
068    public String getShutdownScript () {
069        return shutdownScript;
070    }
071
072    private void exec (String script) throws IOException, InterruptedException {
073        if (script != null) {
074            ProcessBuilder pb = new ProcessBuilder (parseCommandLine(script));
075            Process p = pb.start();
076            BufferedReader in = p.inputReader();
077            LogEvent evt = getLog().createInfo("--- " + script + " ---");
078            String line;
079            while ((line = in.readLine()) != null) {
080                evt.addMessage(line);
081            }
082            p.waitFor();
083            Logger.log(evt);
084        }
085    }
086
087    public static List<String> parseCommandLine(String commandLine) {
088        if (commandLine == null || commandLine.isEmpty())
089            throw new IllegalArgumentException("Empty command");
090        List<String> args = new ArrayList<>();
091        StringBuilder currentArg = new StringBuilder();
092        boolean inQuotes = false;
093        boolean isEscaped = false;
094
095        for (int i = 0; i < commandLine.length(); i++) {
096            char c = commandLine.charAt(i);
097
098            if (c == '\\' && !isEscaped) {
099                isEscaped = true;
100                continue;
101            }
102
103            if (c == '\"' && !isEscaped) {
104                inQuotes = !inQuotes;
105            } else {
106                if (c == ' ' && !inQuotes) {
107                    if (currentArg.length() > 0) {
108                        args.add(currentArg.toString());
109                        currentArg.setLength(0);
110                    }
111                } else {
112                    currentArg.append(c);
113                }
114            }
115
116            if (isEscaped) {
117                isEscaped = false;
118            }
119        }
120
121        if (currentArg.length() > 0) {
122            args.add(currentArg.toString());
123        }
124
125        return args;
126    }
127
128}