3
import java.io.IOException;
4
import java.io.OutputStream;
5
import java.io.UnsupportedEncodingException;
8
* Filtering {@link OutputStream} that looks for {@link #MARK} in the output stream and notifies the callback.
10
* The mark itself will be removed from the stream.
12
* @author Kohsuke Kawaguchi
15
public abstract class MarkFindingOutputStream extends OutputStream {
16
private final OutputStream base;
18
public MarkFindingOutputStream(OutputStream base) {
23
* Position in {@link #MARK} if we are currently suspecting a match.
25
private int match = 0;
27
public synchronized void write(int b) throws IOException {
28
if (MBYTES[match] == b) {// another byte matched. Good. Keep going...
30
if (match == MBYTES.length) {
31
// don't send MARK to the output, but instead notify the callback
37
// only matched partially. send the partial match that we held off down the pipe
38
base.write(MBYTES, 0, match);
41
// this might match the first byte in MARK, so retry.
49
public void write(byte b[], int off, int len) throws IOException {
50
final int start = off;
51
final int end = off + len;
52
for (int i=off; i<end; ) {
53
if (MBYTES[match] == b[i]) {// another byte matched. Good. Keep going...
56
if (match == MBYTES.length) {
57
base.write(b,off,i-off-MBYTES.length); // flush the portion up to MARK
58
// don't send MARK to the output, but instead notify the callback
66
// only matched partially.
67
// if a part of the partial match spans into the previous write, we need to fake that write.
68
int extra = match-(i-start);
70
base.write(MBYTES,0,extra);
74
// this b[i] might be a fast byte in MARK, so we'll retry
83
// if we are partially matching, can't send that portion yet.
85
base.write(b, off, len-match);
88
public void flush() throws IOException {
93
public void close() throws IOException {
98
private void flushPartialMatch() throws IOException {
100
base.write(MBYTES,0,match);
105
protected abstract void onMarkFound();
107
// having a new line in the end makes it work better with line-buffering transformation
108
public static final String MARK = "[Jenkins:SYNC-MARK]\n";
109
private static final byte[] MBYTES = toUTF8(MARK);
111
private static byte[] toUTF8(String s) {
113
return s.getBytes("UTF-8");
114
} catch (UnsupportedEncodingException e) {
115
throw new AssertionError(e);