Skip to content

Commit 00b4af1

Browse files
author
River
committed
Update
1 parent f1233f1 commit 00b4af1

File tree

1 file changed

+308
-0
lines changed

1 file changed

+308
-0
lines changed
Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
package com.hipipal.sl4alib;
2+
3+
import com.googlecode.android_scripting.Log;
4+
5+
import java.io.File;
6+
import java.io.FileOutputStream;
7+
import java.io.IOException;
8+
import java.io.InputStream;
9+
10+
/**
11+
* A <code>StreamGobbler</code> is an InputStream that uses an internal worker thread to constantly consume input from
12+
* another InputStream. It uses a buffer to store the consumed data. The buffer size is automatically adjusted, if
13+
* needed.
14+
* <p>
15+
* This class is sometimes very convenient - if you wrap a session's STDOUT and STDERR InputStreams with instances of
16+
* this class, then you don't have to bother about the shared window of STDOUT and STDERR in the low level SSH-2
17+
* protocol, since all arriving data will be immediatelly consumed by the worker threads. Also, as a side effect, the
18+
* streams will be buffered (e.g., single byte read() operations are faster).
19+
* <p>
20+
* Other SSH for Java libraries include this functionality by default in their STDOUT and STDERR InputStream
21+
* implementations, however, please be aware that this approach has also a downside:
22+
* <p>
23+
* If you do not call the StreamGobbler's <code>read()</code> method often enough and the peer is constantly sending
24+
* huge amounts of data, then you will sooner or later encounter a low memory situation due to the aggregated data
25+
* (well, it also depends on the Java heap size). Joe Average will like this class anyway - a paranoid programmer would
26+
* never use such an approach.
27+
* <p>
28+
* The term "StreamGobbler" was taken from an article called "When Runtime.exec() won't", see
29+
* http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html.
30+
*
31+
* @author Christian Plattner, plattner@trilead.com
32+
* @version $Id: StreamGobbler.java,v 1.1 2007/10/15 12:49:56 cplattne Exp $
33+
*/
34+
35+
public class StreamGobbler extends InputStream {
36+
class GobblerThread extends Thread {
37+
/*
38+
@Override
39+
public void run() {
40+
41+
while (true) {
42+
try {
43+
byte[] saveBuffer = null;
44+
45+
int avail = is.read(buffer, write_pos, buffer.length - write_pos);
46+
synchronized (synchronizer) {
47+
if (avail <= 0) {
48+
isEOF = true;
49+
synchronizer.notifyAll();
50+
break;
51+
}
52+
write_pos += avail;
53+
54+
int space_available = buffer.length - write_pos;
55+
Log.e("space_available:" + buffer.length + "-" + write_pos);
56+
57+
if (space_available == 0) {
58+
if (read_pos > 0) {
59+
saveBuffer = new byte[read_pos];
60+
System.arraycopy(buffer, 0, saveBuffer, 0, read_pos);
61+
System.arraycopy(buffer, read_pos, buffer, 0, buffer.length - read_pos);
62+
write_pos -= read_pos;
63+
read_pos = 0;
64+
65+
Log.e("read_pos > 0:" + buffer);
66+
67+
}
68+
else {
69+
write_pos = 0;
70+
saveBuffer = buffer;
71+
72+
Log.e("read_pos <=0 :" + buffer);
73+
74+
}
75+
}
76+
77+
synchronizer.notifyAll();
78+
}
79+
writeToFile(saveBuffer);
80+
81+
}
82+
catch (IOException e) {
83+
synchronized (synchronizer) {
84+
exception = e;
85+
synchronizer.notifyAll();
86+
break;
87+
}
88+
}
89+
}
90+
}*/
91+
92+
public void run() {
93+
byte[] buff = new byte[8192];
94+
95+
while (true) {
96+
try {
97+
int avail = is.read(buff);
98+
99+
synchronized (synchronizer) {
100+
if (avail <= 0) {
101+
isEOF = true;
102+
synchronizer.notifyAll();
103+
break;
104+
}
105+
106+
int space_available = buffer.length - write_pos;
107+
108+
if (space_available < avail) {
109+
110+
int unread_size = write_pos - read_pos;
111+
int need_space = unread_size + avail;
112+
113+
byte[] new_buffer = buffer;
114+
115+
if (need_space > buffer.length) {
116+
int inc = need_space / 3;
117+
inc = (inc < 256) ? 256 : inc;
118+
inc = (inc > 8192) ? 8192 : inc;
119+
new_buffer = new byte[need_space + inc];
120+
}
121+
122+
if (unread_size > 0)
123+
System.arraycopy(buffer, read_pos, new_buffer, 0, unread_size);
124+
125+
buffer = new_buffer;
126+
127+
read_pos = 0;
128+
write_pos = unread_size;
129+
}
130+
131+
byte[] s_buffer = new byte[avail];
132+
System.arraycopy(buff, 0, s_buffer, 0, avail);
133+
System.arraycopy(buff, 0, buffer, write_pos, avail);
134+
write_pos += avail;
135+
136+
synchronizer.notifyAll();
137+
writeToFile(s_buffer);
138+
// Log.e("OUTPUT:"+String.valueOf(s_buffer));
139+
}
140+
141+
}
142+
catch (IOException e) {
143+
synchronized (synchronizer) {
144+
exception = e;
145+
synchronizer.notifyAll();
146+
break;
147+
}
148+
}
149+
}
150+
}
151+
}
152+
153+
private InputStream is;
154+
155+
private GobblerThread t;
156+
157+
private Object synchronizer = new Object();
158+
159+
private boolean isEOF = false;
160+
161+
private boolean isClosed = false;
162+
163+
private IOException exception = null;
164+
165+
private byte[] buffer;
166+
167+
private int read_pos = 0;
168+
169+
private int write_pos = 0;
170+
171+
private final FileOutputStream mLogStream;
172+
173+
private final int mBufferSize;
174+
175+
public StreamGobbler(InputStream is, File log, int buffer_size) {
176+
this.is = is;
177+
mBufferSize = buffer_size;
178+
FileOutputStream out = null;
179+
try {
180+
out = new FileOutputStream(log, false);
181+
}
182+
catch (IOException e) {
183+
Log.e(e);
184+
}
185+
mLogStream = out;
186+
buffer = new byte[mBufferSize];
187+
t = new GobblerThread();
188+
t.setDaemon(true);
189+
t.start();
190+
}
191+
192+
public void writeToFile(byte[] buffer) {
193+
194+
if (mLogStream != null && buffer != null) {
195+
try {
196+
mLogStream.write(buffer);
197+
}
198+
catch (IOException e) {
199+
Log.e(e);
200+
}
201+
}
202+
}
203+
204+
@Override
205+
public int read() throws IOException {
206+
synchronized (synchronizer) {
207+
if (isClosed) {
208+
throw new IOException("This StreamGobbler is closed.");
209+
}
210+
211+
while (read_pos == write_pos) {
212+
if (exception != null) {
213+
throw exception;
214+
}
215+
216+
if (isEOF) {
217+
return -1;
218+
}
219+
220+
try {
221+
synchronizer.wait();
222+
}
223+
catch (InterruptedException e) {
224+
}
225+
}
226+
227+
int b = buffer[read_pos++] & 0xff;
228+
229+
return b;
230+
}
231+
}
232+
233+
@Override
234+
public int available() throws IOException {
235+
synchronized (synchronizer) {
236+
if (isClosed) {
237+
throw new IOException("This StreamGobbler is closed.");
238+
}
239+
240+
return write_pos - read_pos;
241+
}
242+
}
243+
244+
@Override
245+
public int read(byte[] b) throws IOException {
246+
return read(b, 0, b.length);
247+
}
248+
249+
@Override
250+
public void close() throws IOException {
251+
synchronized (synchronizer) {
252+
if (isClosed) {
253+
return;
254+
}
255+
isClosed = true;
256+
isEOF = true;
257+
synchronizer.notifyAll();
258+
is.close();
259+
}
260+
}
261+
262+
@Override
263+
public int read(byte[] b, int off, int len) throws IOException {
264+
if (b == null) {
265+
throw new NullPointerException();
266+
}
267+
268+
if ((off < 0) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0) || (off > b.length)) {
269+
throw new IndexOutOfBoundsException();
270+
}
271+
272+
if (len == 0) {
273+
return 0;
274+
}
275+
276+
synchronized (synchronizer) {
277+
if (isClosed) {
278+
throw new IOException("This StreamGobbler is closed.");
279+
}
280+
281+
while (read_pos == write_pos) {
282+
if (exception != null) {
283+
throw exception;
284+
}
285+
286+
if (isEOF) {
287+
return -1;
288+
}
289+
290+
try {
291+
synchronizer.wait();
292+
}
293+
catch (InterruptedException e) {
294+
}
295+
}
296+
297+
int avail = write_pos - read_pos;
298+
299+
avail = (avail > len) ? len : avail;
300+
301+
System.arraycopy(buffer, read_pos, b, off, avail);
302+
303+
read_pos += avail;
304+
305+
return avail;
306+
}
307+
}
308+
}

0 commit comments

Comments
 (0)