001/* 002 * Stallion Core: A Modern Web Framework 003 * 004 * Copyright (C) 2015 - 2016 Stallion Software LLC. 005 * 006 * This program is free software: you can redistribute it and/or modify it under the terms of the 007 * GNU General Public License as published by the Free Software Foundation, either version 2 of 008 * the License, or (at your option) any later version. This program is distributed in the hope that 009 * it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 010 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 011 * License for more details. You should have received a copy of the GNU General Public License 012 * along with this program. If not, see <http://www.gnu.org/licenses/gpl-2.0.html>. 013 * 014 * 015 * 016 */ 017 018package io.stallion.utils; 019 020 021 022import io.stallion.services.Log; 023import org.apache.commons.io.IOUtils; 024 025import java.io.BufferedReader; 026import java.io.File; 027import java.io.IOException; 028import java.io.InputStreamReader; 029import java.util.Map; 030import java.util.concurrent.TimeUnit; 031 032import static io.stallion.utils.Literals.*; 033 034/** 035 * A helper class for running external programs. 036 */ 037public class ProcessHelper { 038 private String[] args; 039 private String directory = null; 040 private String input; 041 private Boolean showDotsWhileWaiting = true; 042 private boolean inheritIO = true; 043 private boolean quietMode = false; 044 045 046 public static CommandResult run(String...args) { 047 return new ProcessHelper(args).run(); 048 } 049 050 051 public ProcessHelper(String...args) { 052 this.args = args; 053 } 054 055 public ProcessHelper withDirectory(String directory) { 056 this.directory = directory; 057 return this; 058 } 059 060 public CommandResult run() { 061 062 String cmdString = String.join(" ", args); 063 System.out.printf("----- Execute command: %s ----\n", cmdString); 064 ProcessBuilder pb = new ProcessBuilder(args); 065 if (!empty(directory)) { 066 pb.directory(new File(directory)); 067 } 068 Map<String, String> env = pb.environment(); 069 CommandResult commandResult = new CommandResult(); 070 Process p = null; 071 try { 072 if (showDotsWhileWaiting == null) { 073 showDotsWhileWaiting = !inheritIO; 074 } 075 076 if (inheritIO) { 077 p = pb.inheritIO().start(); 078 } else { 079 p = pb.start(); 080 } 081 082 BufferedReader err = new BufferedReader(new InputStreamReader(p.getErrorStream())); 083 BufferedReader out = new BufferedReader(new InputStreamReader(p.getInputStream())); 084 085 if (!empty(input)) { 086 Log.info("Writing input to pipe {0}", input); 087 IOUtils.write(input, p.getOutputStream(), UTF8); 088 p.getOutputStream().flush(); 089 } 090 091 while (p.isAlive()) { 092 p.waitFor(1000, TimeUnit.MILLISECONDS); 093 if (showDotsWhileWaiting == true) { 094 System.out.printf("."); 095 } 096 } 097 098 commandResult.setErr(IOUtils.toString(err)); 099 commandResult.setOut(IOUtils.toString(out)); 100 commandResult.setCode(p.exitValue()); 101 102 if (commandResult.succeeded()) { 103 info("\n---- Command execution completed ----\n"); 104 } else { 105 Log.warn("Command failed with error code: " + commandResult.getCode()); 106 } 107 108 } catch (IOException e) { 109 Log.exception(e, "Error running command: " + cmdString); 110 commandResult.setCode(999); 111 commandResult.setEx(e); 112 } catch (InterruptedException e) { 113 Log.exception(e, "Error running command: " + cmdString); 114 commandResult.setCode(998); 115 commandResult.setEx(e); 116 } 117 Log.fine("\n\n----Start shell command result----:\nCommand: {0}\nexitCode: {1}\n----------STDOUT---------\n{2}\n\n----------STDERR--------\n{3}\n\n----end shell command result----\n", 118 cmdString, 119 commandResult.getCode(), 120 commandResult.getOut(), 121 commandResult.getErr()); 122 return commandResult; 123 } 124 125 protected void info(String msg) { 126 if (quietMode == true) { 127 128 } 129 System.out.printf(msg + "\n"); 130 } 131 132 public static class CommandResult { 133 private int code; 134 private String out; 135 private String err; 136 private Throwable ex; 137 138 public boolean succeeded() { 139 return code == 0; 140 } 141 142 public int getCode() { 143 return code; 144 } 145 146 public void setCode(int code) { 147 this.code = code; 148 } 149 150 public String getOut() { 151 return out; 152 } 153 154 public void setOut(String out) { 155 this.out = out; 156 } 157 158 public String getErr() { 159 return err; 160 } 161 162 public void setErr(String err) { 163 this.err = err; 164 } 165 166 public Throwable getEx() { 167 return ex; 168 } 169 170 public void setEx(Throwable ex) { 171 this.ex = ex; 172 } 173 } 174 175 176 public String getInput() { 177 return input; 178 } 179 180 public ProcessHelper setInput(String input) { 181 this.input = input; 182 return this; 183 } 184 185 public boolean isInheritIO() { 186 return inheritIO; 187 } 188 189 public ProcessHelper setInheritIO(boolean inheritIO) { 190 this.inheritIO = inheritIO; 191 return this; 192 } 193 194 public boolean isShowDotsWhileWaiting() { 195 return showDotsWhileWaiting; 196 } 197 198 public ProcessHelper setShowDotsWhileWaiting(boolean showDotsWhileWaiting) { 199 this.showDotsWhileWaiting = showDotsWhileWaiting; 200 return this; 201 } 202}