-
-
Notifications
You must be signed in to change notification settings - Fork 7k
/
Copy pathMessageSiphon.java
149 lines (126 loc) · 4.99 KB
/
MessageSiphon.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-06 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app.debug;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.SocketException;
/**
* Slurps up messages from compiler.
*/
public class MessageSiphon implements Runnable {
private final Reader streamReader;
private final MessageConsumer consumer;
private Thread thread;
private boolean canRun;
// Data is processed line-by-line if possible, but if this is non-zero
// then a partial line is also processed if no line end is received
// within this many milliseconds.
private int lineTimeout;
public MessageSiphon(InputStream stream, MessageConsumer consumer) {
this(stream, consumer, 0);
}
public MessageSiphon(InputStream stream, MessageConsumer consumer, int lineTimeout) {
this.streamReader = new InputStreamReader(stream);
this.consumer = consumer;
this.canRun = true;
this.lineTimeout = lineTimeout;
thread = new Thread(this);
thread.setName("MessageSiphon");
// don't set priority too low, otherwise exceptions won't
// bubble up in time (i.e. compile errors have a weird delay)
//thread.setPriority(Thread.MIN_PRIORITY);
thread.setPriority(Thread.MAX_PRIORITY - 1);
thread.start();
}
@Override
public void run() {
try {
// process data until we hit EOF; this will happily block
// (effectively sleeping the thread) until new data comes in.
// when the program is finally done, null will come through.
//
StringBuilder currentLine = new StringBuilder();
long lineStartTime = 0;
while (canRun) {
// First, try to read as many characters as possible. Take care
// not to block when:
// 1. lineTimeout is nonzero, and
// 2. we have some characters buffered already
while (lineTimeout == 0 || currentLine.length() == 0 || streamReader.ready()) {
int c = streamReader.read();
if (c == -1)
return; // EOF
if (!canRun)
return;
// Keep track of the line start time
if (currentLine.length() == 0)
lineStartTime = System.nanoTime();
// Store the character line
currentLine.append((char)c);
if (c == '\n') {
// We read a full line, pass it on
consumer.message(currentLine.toString());
currentLine.setLength(0);
}
}
// No more characters available. Wait until lineTimeout
// milliseconds have passed since the start of the line and then
// try reading again. If the time has already passed, then just
// pass on the characters read so far.
long passed = (System.nanoTime() - lineStartTime) / 1000;
if (passed < this.lineTimeout) {
Thread.sleep(this.lineTimeout - passed);
continue;
}
consumer.message(currentLine.toString());
currentLine.setLength(0);
}
//EditorConsole.systemOut.println("messaging thread done");
} catch (NullPointerException npe) {
// Fairly common exception during shutdown
} catch (SocketException e) {
// socket has been close while we were wainting for data. nothing to see here, move along
} catch (Exception e) {
// On Linux and sometimes on Mac OS X, a "bad file descriptor"
// message comes up when closing an applet that's run externally.
// That message just gets supressed here..
String mess = e.getMessage();
if ((mess != null) &&
(mess.indexOf("Bad file descriptor") != -1)) {
//if (e.getMessage().indexOf("Bad file descriptor") == -1) {
//System.err.println("MessageSiphon err " + e);
//e.printStackTrace();
} else {
e.printStackTrace();
}
} finally {
thread = null;
}
}
// Wait until the MessageSiphon thread is complete.
public void join() throws java.lang.InterruptedException {
// Grab a temp copy in case another thread nulls the "thread"
// member variable
Thread t = thread;
if (t != null) t.join();
}
public void stop() {
this.canRun = false;
}
}