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* <exec class="org.jpos.q2.qbean.QExec"> 034* <attr name="startScript">YOUR PATH TO PROGRAM</attr> 035* <attr name="shutdownScript">YOUR PATH TO PROGRAM</attr> 036* </exec> 037* </pre> 038* @author Alwyn Schoeman 039* @version $Revision$ $Date$ 040*/ 041 042public class QExec extends QBeanSupport implements QExecMBean { 043 /** Default constructor; no instance state to initialise. */ 044 public QExec() {} 045 String startScript; 046 String shutdownScript; 047 048 @Override 049 protected void startService () throws Exception { 050 exec(startScript); 051 } 052 053 @Override 054 protected void stopService () throws Exception { 055 exec(shutdownScript); 056 } 057 058 public void setStartScript (String scriptPath) { 059 startScript = scriptPath; 060 } 061 062 public String getStartScript () { 063 return startScript; 064 } 065 066 public void setShutdownScript (String scriptPath) { 067 shutdownScript = scriptPath; 068 } 069 070 public String getShutdownScript () { 071 return shutdownScript; 072 } 073 074 private void exec (String script) throws IOException, InterruptedException { 075 if (script != null) { 076 ProcessBuilder pb = new ProcessBuilder (parseCommandLine(script)); 077 Process p = pb.start(); 078 BufferedReader in = p.inputReader(); 079 LogEvent evt = getLog().createInfo("--- " + script + " ---"); 080 String line; 081 while ((line = in.readLine()) != null) { 082 evt.addMessage(line); 083 } 084 p.waitFor(); 085 Logger.log(evt); 086 } 087 } 088 089 /** 090 * Tokenises a command line, honouring double-quoted segments and 091 * backslash-escaped characters. 092 * 093 * @param commandLine the command-line string 094 * @return the parsed argument list 095 * @throws IllegalArgumentException if {@code commandLine} is {@code null} or empty 096 */ 097 public static List<String> parseCommandLine(String commandLine) { 098 if (commandLine == null || commandLine.isEmpty()) 099 throw new IllegalArgumentException("Empty command"); 100 List<String> args = new ArrayList<>(); 101 StringBuilder currentArg = new StringBuilder(); 102 boolean inQuotes = false; 103 boolean isEscaped = false; 104 105 for (int i = 0; i < commandLine.length(); i++) { 106 char c = commandLine.charAt(i); 107 108 if (c == '\\' && !isEscaped) { 109 isEscaped = true; 110 continue; 111 } 112 113 if (c == '\"' && !isEscaped) { 114 inQuotes = !inQuotes; 115 } else { 116 if (c == ' ' && !inQuotes) { 117 if (currentArg.length() > 0) { 118 args.add(currentArg.toString()); 119 currentArg.setLength(0); 120 } 121 } else { 122 currentArg.append(c); 123 } 124 } 125 126 if (isEscaped) { 127 isEscaped = false; 128 } 129 } 130 131 if (currentArg.length() > 0) { 132 args.add(currentArg.toString()); 133 } 134 135 return args; 136 } 137 138}