1
17 package org.apache.tomcat.util.net;
18
19 import java.io.IOException;
20 import java.nio.ByteBuffer;
21 import java.util.ArrayList;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.concurrent.LinkedBlockingDeque;
25
26 import org.apache.tomcat.util.buf.ByteBufferHolder;
27
28
36 public class WriteBuffer {
37
38 private final int bufferSize;
39
40 private final LinkedBlockingDeque<ByteBufferHolder> buffers = new LinkedBlockingDeque<>();
41
42 public WriteBuffer(int bufferSize) {
43 this.bufferSize = bufferSize;
44 }
45
46 void clear() {
47 buffers.clear();
48 }
49
50 void add(byte[] buf, int offset, int length) {
51 ByteBufferHolder holder = getByteBufferHolder(length);
52 holder.getBuf().put(buf, offset, length);
53 }
54
55
56 public void add(ByteBuffer from) {
57 ByteBufferHolder holder = getByteBufferHolder(from.remaining());
58 holder.getBuf().put(from);
59 }
60
61
62 private ByteBufferHolder getByteBufferHolder(int capacity) {
63 ByteBufferHolder holder = buffers.peekLast();
64 if (holder == null || holder.isFlipped() || holder.getBuf().remaining() < capacity) {
65 ByteBuffer buffer = ByteBuffer.allocate(Math.max(bufferSize, capacity));
66 holder = new ByteBufferHolder(buffer, false);
67 buffers.add(holder);
68 }
69 return holder;
70 }
71
72
73 public boolean isEmpty() {
74 return buffers.isEmpty();
75 }
76
77
78
88 ByteBuffer[] toArray(ByteBuffer... prefixes) {
89 List<ByteBuffer> result = new ArrayList<>();
90 for (ByteBuffer prefix : prefixes) {
91 if (prefix.hasRemaining()) {
92 result.add(prefix);
93 }
94 }
95 for (ByteBufferHolder buffer : buffers) {
96 buffer.flip();
97 result.add(buffer.getBuf());
98 }
99 buffers.clear();
100 return result.toArray(new ByteBuffer[result.size()]);
101 }
102
103
104 boolean write(SocketWrapperBase<?> socketWrapper, boolean blocking) throws IOException {
105 Iterator<ByteBufferHolder> bufIter = buffers.iterator();
106 boolean dataLeft = false;
107 while (!dataLeft && bufIter.hasNext()) {
108 ByteBufferHolder buffer = bufIter.next();
109 buffer.flip();
110 if (blocking) {
111 socketWrapper.writeBlocking(buffer.getBuf());
112 } else {
113 socketWrapper.writeNonBlockingInternal(buffer.getBuf());
114 }
115 if (buffer.getBuf().remaining() == 0) {
116 bufIter.remove();
117 } else {
118 dataLeft = true;
119 }
120 }
121 return dataLeft;
122 }
123
124
125 public boolean write(Sink sink, boolean blocking) throws IOException {
126 Iterator<ByteBufferHolder> bufIter = buffers.iterator();
127 boolean dataLeft = false;
128 while (!dataLeft && bufIter.hasNext()) {
129 ByteBufferHolder buffer = bufIter.next();
130 buffer.flip();
131 dataLeft = sink.writeFromBuffer(buffer.getBuf(), blocking);
132 if (!dataLeft) {
133 bufIter.remove();
134 }
135 }
136 return dataLeft;
137 }
138
139
140
144 public interface Sink {
145 boolean writeFromBuffer(ByteBuffer buffer, boolean block) throws IOException;
146 }
147 }
148