1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.io;
20
21 import java.io.IOException;
22 import java.net.InetSocketAddress;
23 import java.nio.ByteBuffer;
24 import java.nio.channels.ClosedChannelException;
25 import java.nio.charset.Charset;
26 import java.nio.charset.StandardCharsets;
27
28 import org.eclipse.jetty.util.BufferUtil;
29 import org.eclipse.jetty.util.log.Log;
30 import org.eclipse.jetty.util.log.Logger;
31 import org.eclipse.jetty.util.thread.Scheduler;
32
33
34
35
36
37
38 public class ByteArrayEndPoint extends AbstractEndPoint
39 {
40 static final Logger LOG = Log.getLogger(ByteArrayEndPoint.class);
41 public final static InetSocketAddress NOIP=new InetSocketAddress(0);
42
43 protected ByteBuffer _in;
44 protected ByteBuffer _out;
45 protected boolean _ishut;
46 protected boolean _oshut;
47 protected boolean _closed;
48 protected boolean _growOutput;
49
50
51
52
53
54
55 public ByteArrayEndPoint()
56 {
57 this(null,0,null,null);
58 }
59
60
61
62
63
64 public ByteArrayEndPoint(byte[] input, int outputSize)
65 {
66 this(null,0,input!=null?BufferUtil.toBuffer(input):null,BufferUtil.allocate(outputSize));
67 }
68
69
70
71
72
73 public ByteArrayEndPoint(String input, int outputSize)
74 {
75 this(null,0,input!=null?BufferUtil.toBuffer(input):null,BufferUtil.allocate(outputSize));
76 }
77
78
79 public ByteArrayEndPoint(Scheduler scheduler, long idleTimeoutMs)
80 {
81 this(scheduler,idleTimeoutMs,null,null);
82 }
83
84
85 public ByteArrayEndPoint(Scheduler timer, long idleTimeoutMs, byte[] input, int outputSize)
86 {
87 this(timer,idleTimeoutMs,input!=null?BufferUtil.toBuffer(input):null,BufferUtil.allocate(outputSize));
88 }
89
90
91 public ByteArrayEndPoint(Scheduler timer, long idleTimeoutMs, String input, int outputSize)
92 {
93 this(timer,idleTimeoutMs,input!=null?BufferUtil.toBuffer(input):null,BufferUtil.allocate(outputSize));
94 }
95
96
97 public ByteArrayEndPoint(Scheduler timer, long idleTimeoutMs, ByteBuffer input, ByteBuffer output)
98 {
99 super(timer,NOIP,NOIP);
100 _in=input==null?BufferUtil.EMPTY_BUFFER:input;
101 _out=output==null?BufferUtil.allocate(1024):output;
102 setIdleTimeout(idleTimeoutMs);
103 }
104
105
106
107
108
109
110 @Override
111 protected void onIncompleteFlush()
112 {
113
114 }
115
116
117 @Override
118 protected boolean needsFill() throws IOException
119 {
120 if (_closed)
121 throw new ClosedChannelException();
122 return _in == null || BufferUtil.hasContent(_in);
123 }
124
125
126
127
128
129 public ByteBuffer getIn()
130 {
131 return _in;
132 }
133
134
135
136
137 public void setInputEOF()
138 {
139 _in = null;
140 }
141
142
143
144
145
146 public void setInput(ByteBuffer in)
147 {
148 _in = in;
149 if (in == null || BufferUtil.hasContent(in))
150 getFillInterest().fillable();
151 }
152
153
154 public void setInput(String s)
155 {
156 setInput(BufferUtil.toBuffer(s,StandardCharsets.UTF_8));
157 }
158
159
160 public void setInput(String s,Charset charset)
161 {
162 setInput(BufferUtil.toBuffer(s,charset));
163 }
164
165
166
167
168
169 public ByteBuffer getOutput()
170 {
171 return _out;
172 }
173
174
175
176
177
178 public String getOutputString()
179 {
180 return getOutputString(StandardCharsets.UTF_8);
181 }
182
183
184
185
186
187 public String getOutputString(Charset charset)
188 {
189 return BufferUtil.toString(_out,charset);
190 }
191
192
193
194
195
196 public ByteBuffer takeOutput()
197 {
198 ByteBuffer b=_out;
199 _out=BufferUtil.allocate(b.capacity());
200 getWriteFlusher().completeWrite();
201 return b;
202 }
203
204
205
206
207
208 public String takeOutputString()
209 {
210 return takeOutputString(StandardCharsets.UTF_8);
211 }
212
213
214
215
216
217 public String takeOutputString(Charset charset)
218 {
219 ByteBuffer buffer=takeOutput();
220 return BufferUtil.toString(buffer,charset);
221 }
222
223
224
225
226
227 public void setOutput(ByteBuffer out)
228 {
229 _out = out;
230 getWriteFlusher().completeWrite();
231 }
232
233
234
235
236
237 @Override
238 public boolean isOpen()
239 {
240 return !_closed;
241 }
242
243
244
245
246 @Override
247 public boolean isInputShutdown()
248 {
249 return _ishut||_closed;
250 }
251
252
253
254
255 @Override
256 public boolean isOutputShutdown()
257 {
258 return _oshut||_closed;
259 }
260
261
262 private void shutdownInput()
263 {
264 _ishut=true;
265 if (_oshut)
266 close();
267 }
268
269
270
271
272
273 @Override
274 public void shutdownOutput()
275 {
276 _oshut=true;
277 if (_ishut)
278 close();
279 }
280
281
282
283
284
285 @Override
286 public void close()
287 {
288 _closed=true;
289 }
290
291
292
293
294
295 public boolean hasMore()
296 {
297 return getOutput().position()>0;
298 }
299
300
301
302
303
304 @Override
305 public int fill(ByteBuffer buffer) throws IOException
306 {
307 if (_closed)
308 throw new EofException("CLOSED");
309 if (_in==null)
310 shutdownInput();
311 if (_ishut)
312 return -1;
313 int filled=BufferUtil.flipPutFlip(_in,buffer);
314 if (filled>0)
315 notIdle();
316 return filled;
317 }
318
319
320
321
322
323 @Override
324 public boolean flush(ByteBuffer... buffers) throws IOException
325 {
326 if (_closed)
327 throw new IOException("CLOSED");
328 if (_oshut)
329 throw new IOException("OSHUT");
330
331 boolean flushed=true;
332 boolean idle=true;
333
334 for (ByteBuffer b : buffers)
335 {
336 if (BufferUtil.hasContent(b))
337 {
338 if (_growOutput && b.remaining()>BufferUtil.space(_out))
339 {
340 BufferUtil.compact(_out);
341 if (b.remaining()>BufferUtil.space(_out))
342 {
343 ByteBuffer n = BufferUtil.allocate(_out.capacity()+b.remaining()*2);
344 BufferUtil.flipPutFlip(_out,n);
345 _out=n;
346 }
347 }
348
349 if (BufferUtil.flipPutFlip(b,_out)>0)
350 idle=false;
351
352 if (BufferUtil.hasContent(b))
353 {
354 flushed=false;
355 break;
356 }
357 }
358 }
359 if (!idle)
360 notIdle();
361 return flushed;
362 }
363
364
365
366
367
368 public void reset()
369 {
370 getFillInterest().onClose();
371 getWriteFlusher().onClose();
372 _ishut=false;
373 _oshut=false;
374 _closed=false;
375 _in=null;
376 BufferUtil.clear(_out);
377 }
378
379
380
381
382
383 @Override
384 public Object getTransport()
385 {
386 return null;
387 }
388
389
390
391
392
393 public boolean isGrowOutput()
394 {
395 return _growOutput;
396 }
397
398
399
400
401
402 public void setGrowOutput(boolean growOutput)
403 {
404 _growOutput=growOutput;
405 }
406
407
408 }