package aQute.remote.agent;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
/**
* Handles the redirection of the output. Any text written to this PrintStream
* is send to the supervisor. We are a bit careful here that we're breaking
* recursive calls that can happen when there is shit happening deep down below.
*/
public class RedirectOutput extends PrintStream {
static Timer timer = new Timer();
private final List<AgentServer> agents;
private final PrintStream out;
private StringBuilder sb = new StringBuilder();
private boolean err;
private static ThreadLocal<Boolean> onStack = new ThreadLocal<Boolean>();
private TimerTask active;
private String lastOutput = "";
/**
* If we do not have an original, we create a null stream because the
* PrintStream requires this.
*/
static class NullOutputStream extends OutputStream {
@Override
public void write(int arg0) throws IOException {}
}
public RedirectOutput(List<AgentServer> agents, PrintStream out, boolean err) {
super(out == null ? out = nullOutputStream() : out);
this.agents = agents;
this.out = out;
this.err = err;
}
private static PrintStream nullOutputStream() {
return new PrintStream(new NullOutputStream());
}
public void write(int b) {
this.write(new byte[] {
(byte) b
}, 0, 1);
}
public void write(byte b[]) {
write(b, 0, b.length);
}
public void write(byte b[], int off, int len) {
if ((off | len | (b.length - (len + off)) | (off + len)) < 0)
throw new IndexOutOfBoundsException();
out.write(b, off, len);
if (onStack.get() == null) {
onStack.set(true);
try {
sb.append(new String(b, off, len)); // default encoding!
flushConditional();
} catch (Exception e) {
// e.printStackTrace();
} finally {
onStack.remove();
}
} else {
out.println("[recursive output] " + new String(b, off, len));
}
}
private void flushConditional() {
synchronized (this) {
if (active != null)
return;
active = new TimerTask() {
@Override
public void run() {
synchronized (RedirectOutput.this) {
active = null;
}
flush();
}
};
timer.schedule(active, 300);
}
}
public void flush() {
final String output;
synchronized (this) {
if (sb.length() == 0)
return;
output = sb.toString();
sb = new StringBuilder();
}
setLastOutput(output);
for (AgentServer agent : agents) {
if (agent.quit)
continue;
try {
if (err)
agent.getSupervisor().stderr(output);
else
agent.getSupervisor().stdout(output);
} catch (InterruptedException ie) {
return;
} catch (Exception ie) {
try {
agent.close();
} catch (IOException e) {
// e.printStackTrace();
}
}
}
super.flush();
}
public void close() {
super.close();
}
public PrintStream getOut() {
return out;
}
public String getLastOutput() {
return lastOutput;
}
private void setLastOutput(String out) {
if (!"".equals(out) && out != null) {
out = out.replaceAll("^>.*$", "");
if (!"".equals(out) && !out.startsWith("true")) {
lastOutput = out;
}
}
}
}