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 package org.apache.hc.core5.http.impl.nio;
29
30 import java.io.IOException;
31 import java.nio.ByteBuffer;
32 import java.nio.channels.WritableByteChannel;
33 import java.util.List;
34
35 import org.apache.hc.core5.http.Header;
36 import org.apache.hc.core5.http.impl.BasicHttpTransportMetrics;
37 import org.apache.hc.core5.http.nio.ContentEncoder;
38 import org.apache.hc.core5.http.nio.SessionOutputBuffer;
39 import org.apache.hc.core5.util.Args;
40 import org.apache.hc.core5.util.Asserts;
41
42
43
44
45
46
47
48 public abstract class AbstractContentEncoder implements ContentEncoder {
49
50 final WritableByteChannel channel;
51 final SessionOutputBuffer buffer;
52 final BasicHttpTransportMetrics metrics;
53
54 boolean completed;
55
56
57
58
59
60
61
62
63
64 public AbstractContentEncoder(
65 final WritableByteChannel channel,
66 final SessionOutputBuffer buffer,
67 final BasicHttpTransportMetrics metrics) {
68 super();
69 Args.notNull(channel, "Channel");
70 Args.notNull(buffer, "Session input buffer");
71 Args.notNull(metrics, "Transport metrics");
72 this.buffer = buffer;
73 this.channel = channel;
74 this.metrics = metrics;
75 }
76
77 protected WritableByteChannel channel() {
78 return this.channel;
79 }
80
81 protected SessionOutputBuffer buffer() {
82 return this.buffer;
83 }
84
85 protected BasicHttpTransportMetrics metrics() {
86 return this.metrics;
87 }
88
89 @Override
90 public boolean isCompleted() {
91 return this.completed;
92 }
93
94 @Override
95 public void complete(final List<? extends Header> trailers) throws IOException {
96 this.completed = true;
97 }
98
99 public final void complete() throws IOException {
100 complete(null);
101 }
102
103 protected void assertNotCompleted() {
104 Asserts.check(!this.completed, "Encoding process already completed");
105 }
106
107
108
109
110
111
112
113
114 protected int flushToChannel() throws IOException {
115 if (!this.buffer.hasData()) {
116 return 0;
117 }
118 final int bytesWritten = this.buffer.flush(this.channel);
119 if (bytesWritten > 0) {
120 this.metrics.incrementBytesTransferred(bytesWritten);
121 }
122 return bytesWritten;
123 }
124
125
126
127
128
129
130
131
132 protected int writeToChannel(final ByteBuffer src) throws IOException {
133 if (!src.hasRemaining()) {
134 return 0;
135 }
136 final int bytesWritten = this.channel.write(src);
137 if (bytesWritten > 0) {
138 this.metrics.incrementBytesTransferred(bytesWritten);
139 }
140 return bytesWritten;
141 }
142
143
144
145
146
147
148
149
150
151
152 protected int writeToChannel(final ByteBuffer src, final int limit) throws IOException {
153 return doWriteChunk(src, limit, true);
154 }
155
156
157
158
159
160
161
162
163
164
165 protected int writeToBuffer(final ByteBuffer src, final int limit) throws IOException {
166 return doWriteChunk(src, limit, false);
167 }
168
169 private int doWriteChunk(
170 final ByteBuffer src, final int chunk, final boolean direct) throws IOException {
171 final int bytesWritten;
172 if (src.remaining() > chunk) {
173 final int oldLimit = src.limit();
174 final int newLimit = oldLimit - (src.remaining() - chunk);
175 src.limit(newLimit);
176 bytesWritten = doWriteChunk(src, direct);
177 src.limit(oldLimit);
178 } else {
179 bytesWritten = doWriteChunk(src, direct);
180 }
181 return bytesWritten;
182 }
183
184 private int doWriteChunk(final ByteBuffer src, final boolean direct) throws IOException {
185 if (direct) {
186 final int bytesWritten = this.channel.write(src);
187 if (bytesWritten > 0) {
188 this.metrics.incrementBytesTransferred(bytesWritten);
189 }
190 return bytesWritten;
191 }
192 final int chunk = src.remaining();
193 this.buffer.write(src);
194 return chunk;
195 }
196
197 }