1 package com.palantir.blog.processspawner;
2
3
40
41 import java.io.BufferedReader;
42 import java.io.ByteArrayOutputStream;
43 import java.io.File;
44 import java.io.IOException;
45 import java.io.InputStream;
46 import java.io.InputStreamReader;
47 import java.io.PrintStream;
48 import java.util.List;
49 import java.util.Map;
50
51 import org.apache.log4j.LogManager;
52 import org.apache.log4j.Logger;
53
54 public class ProcessSpawner {
55
56 static final Logger log = LogManager.getLogger(ProcessSpawner.class);
57
58 ProcessBuilder pb = null;
59 OutputPiper out = null;
60 OutputPiper err = null;
61 Process p = null;
62 String[] args;
63
64
70 public ProcessSpawner(File workingDirectory, String[] cmdarray,Map<String,String> environmentToMerge) {
71 pb = new ProcessBuilder();
72 if(workingDirectory != null) {
74 pb.directory(workingDirectory);
75 }
76 pb.command(cmdarray);
77 if(log.isInfoEnabled()) {
78 StringBuilder cmdLine = new StringBuilder();
79 for(String token : cmdarray) {
80 cmdLine.append(token).append(" ");
81 }
82 log.info("Build process spawner for the following command line:");
83 log.info(cmdLine.toString());
84 }
85 Map<String,String> env = pb.environment();
87 if(environmentToMerge != null && environmentToMerge.size() > 0) {
88 env.putAll(environmentToMerge);
89 }
90
91 if(log.isDebugEnabled()) {
92 log.debug("Environment for new processses: \n");
93 for(Map.Entry<String,String> envEntry : env.entrySet()) {
94 log.debug("\t" + envEntry.getKey() + "\t=\t" + envEntry.getValue() );
95 }
96 }
97 }
98
99 @SuppressWarnings("unused")
100 private ProcessSpawner() {}
101
102 public static class OutputPiper extends Thread {
103 InputStream in;
104 PrintStream out;
105 String tag = null;
106
107 public OutputPiper(String tag, InputStream in,PrintStream out) {
108 this.in = in;
109 this.out = out;
110 this.tag = tag;
111 this.setDaemon(true);
113 this.setName("OutputPiper-" + tag);
114 out.println("Starting output piper for tag: " + tag);
115 this.start();
116 }
117
118 @Override
119 public void run() {
120 try {
121 BufferedReader reader = new BufferedReader(new InputStreamReader(in));
122 String line = null;
123 do {
124 line = reader.readLine();
125 if(line != null) {
126 out.println(tag + ": " + line);
127 }
128 }while(line != null);
129 }
130 catch (Exception e) {
131 }
133 out.println("Output piper exiting for tag: " + tag);
134 }
135
136 public static OutputPiper createOutputPiper(String tag, InputStream in, PrintStream out) {
137 OutputPiper rc = new OutputPiper(tag, in,out);
138 return rc;
139 }
140 }
141
142 public List<String> command() {
143 return pb.command();
144 }
145
146 public File directory() {
147 return pb.directory();
148 }
149
150 public ProcessBuilder directory(File directory) {
151 return pb.directory(directory);
152 }
153
154 public Map<String, String> environment() {
155 return pb.environment();
156 }
157
158 public boolean redirectErrorStream() {
159 return pb.redirectErrorStream();
160 }
161
162 public ProcessBuilder redirectErrorStream(boolean redirectErrorStream) {
163 return pb.redirectErrorStream(redirectErrorStream);
164 }
165
166 public Process start() throws IOException {
167 p = pb.start();
168 return p;
169 }
170
171
179 public Process startStdinStderrInstance(String tag) throws IOException {
180 start();
181 out = OutputPiper.createOutputPiper(tag+ "-stdout", p.getInputStream(), System.out);
182 err = OutputPiper.createOutputPiper(tag+ "-stderr", p.getErrorStream(), System.err);
183 return p;
184 }
185
186 public void waitForProcess() throws Exception {
187 if(p != null) {
188 try {
189 if(out != null) {
190 out.join();
191 }
192 if(err != null) {
193 err.join();
194 }
195 p.waitFor();
196 } catch (InterruptedException e) {
197 throw new Exception("Interrupted while waiting for process to exit",e);
198 }
199 } else {
200 throw new Exception("Process not yet started!");
201 }
202 }
203
204 public static String exec(String cmdLine) throws Exception {
205 ByteArrayOutputStream baos = new ByteArrayOutputStream();
206 PrintStream out = new PrintStream(baos);
207 String[] cmdArray = cmdLine.split("\\s+");
208 ProcessSpawner ps = new ProcessSpawner(null,cmdArray,null);
209 Process p = ps.start();
210 OutputPiper pipe = OutputPiper.createOutputPiper(null, p.getInputStream(), out);
211 pipe.join();
212 p.waitFor();
213 out.close();
214 byte[] bytes = baos.toByteArray();
215 return new String(bytes);
216 }
217}
218
219