1 /*
2 * ====================================================================
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 * ====================================================================
20 *
21 * This software consists of voluntary contributions made by many
22 * individuals on behalf of the Apache Software Foundation. For more
23 * information on the Apache Software Foundation, please see
24 * <http://www.apache.org/>.
25 *
26 */
27
28 package org.apache.hc.client5.http.entity;
29
30 import java.io.File;
31 import java.io.InputStream;
32 import java.io.Serializable;
33 import java.util.Arrays;
34 import java.util.List;
35
36 import org.apache.hc.core5.http.ContentType;
37 import org.apache.hc.core5.http.HttpEntity;
38 import org.apache.hc.core5.http.NameValuePair;
39 import org.apache.hc.core5.http.io.entity.AbstractHttpEntity;
40 import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
41 import org.apache.hc.core5.http.io.entity.FileEntity;
42 import org.apache.hc.core5.http.io.entity.InputStreamEntity;
43 import org.apache.hc.core5.http.io.entity.SerializableEntity;
44 import org.apache.hc.core5.http.io.entity.StringEntity;
45
46 /**
47 * Builder for {@link HttpEntity} instances.
48 * <p>
49 * Several setter methods of this builder are mutually exclusive. In case of multiple invocations
50 * of the following methods only the last one will have effect:
51 * </p>
52 * <ul>
53 * <li>{@link #setText(String)}</li>
54 * <li>{@link #setBinary(byte[])}</li>
55 * <li>{@link #setStream(java.io.InputStream)}</li>
56 * <li>{@link #setSerializable(java.io.Serializable)}</li>
57 * <li>{@link #setParameters(java.util.List)}</li>
58 * <li>{@link #setParameters(NameValuePair...)}</li>
59 * <li>{@link #setFile(java.io.File)}</li>
60 * </ul>
61 *
62 * @since 4.3
63 */
64 public class EntityBuilder {
65
66 private String text;
67 private byte[] binary;
68 private InputStream stream;
69 private List<NameValuePair> parameters;
70 private Serializable serializable;
71 private File file;
72 private ContentType contentType;
73 private String contentEncoding;
74 private boolean chunked;
75 private boolean gzipCompressed;
76
77 EntityBuilder() {
78 super();
79 }
80
81 public static EntityBuilder create() {
82 return new EntityBuilder();
83 }
84
85 private void clearContent() {
86 this.text = null;
87 this.binary = null;
88 this.stream = null;
89 this.parameters = null;
90 this.serializable = null;
91 this.file = null;
92 }
93
94 /**
95 * Gets the entity content as a string if set using {@link #setText(String)}.
96 *
97 * @return the entity content as a string, may be null.
98 */
99 public String getText() {
100 return text;
101 }
102
103 /**
104 * Sets entity content as a string. This method is mutually exclusive with
105 * {@link #setBinary(byte[])},
106 * {@link #setStream(java.io.InputStream)},
107 * {@link #setSerializable(java.io.Serializable)},
108 * {@link #setParameters(java.util.List)},
109 * {@link #setParameters(NameValuePair...)}
110 * {@link #setFile(java.io.File)} methods.
111 *
112 * @param text entity content as a string.
113 * @return this
114 */
115 public EntityBuilder setText(final String text) {
116 clearContent();
117 this.text = text;
118 return this;
119 }
120
121 /**
122 * Gets entity content as a byte array if set using
123 * {@link #setBinary(byte[])}.
124 *
125 * @return entity content as a byte array.
126 */
127 public byte[] getBinary() {
128 return binary;
129 }
130
131 /**
132 * Sets entity content as a byte array. This method is mutually exclusive with
133 * {@link #setText(String)},
134 * {@link #setStream(java.io.InputStream)},
135 * {@link #setSerializable(java.io.Serializable)},
136 * {@link #setParameters(java.util.List)},
137 * {@link #setParameters(NameValuePair...)}
138 * {@link #setFile(java.io.File)}.
139 *
140 * @param binary The new entity content as a byte array.
141 * @return this
142 */
143 public EntityBuilder setBinary(final byte[] binary) {
144 clearContent();
145 this.binary = binary;
146 return this;
147 }
148
149 /**
150 * Gets entity content as an {@link InputStream} if set using
151 * {@link #setStream(java.io.InputStream)} method.
152 *
153 * @return entity content as an {@link InputStream}
154 */
155 public InputStream getStream() {
156 return stream;
157 }
158
159 /**
160 * Sets entity content as an {@link InputStream}. This method is mutually exclusive with
161 * {@link #setText(String)},
162 * {@link #setBinary(byte[])},
163 * {@link #setSerializable(java.io.Serializable)},
164 * {@link #setParameters(java.util.List)},
165 * {@link #setParameters(NameValuePair...)}
166 * {@link #setFile(java.io.File)}.
167 *
168 * @param stream The new entity content as an InputStream.
169 * @return this
170 */
171 public EntityBuilder setStream(final InputStream stream) {
172 clearContent();
173 this.stream = stream;
174 return this;
175 }
176
177 /**
178 * Gets entity content as a parameter list if set using
179 * {@link #setParameters(java.util.List)} or
180 * {@link #setParameters(NameValuePair...)}.
181 *
182 * @return entity content as a parameter list.
183 */
184 public List<NameValuePair> getParameters() {
185 return parameters;
186 }
187
188 /**
189 * Sets entity content as a parameter list. This method is mutually exclusive with
190 * {@link #setText(String)},
191 * {@link #setBinary(byte[])},
192 * {@link #setStream(java.io.InputStream)},
193 * {@link #setSerializable(java.io.Serializable)},
194 * {@link #setFile(java.io.File)}.
195 *
196 * @param parameters entity content as a parameter list.
197 * @return this
198 */
199 public EntityBuilder setParameters(final List<NameValuePair> parameters) {
200 clearContent();
201 this.parameters = parameters;
202 return this;
203 }
204
205 /**
206 * Sets entity content as a parameter list. This method is mutually exclusive with
207 * {@link #setText(String)},
208 * {@link #setBinary(byte[])},
209 * {@link #setStream(java.io.InputStream)},
210 * {@link #setSerializable(java.io.Serializable)},
211 * {@link #setFile(java.io.File)}.
212 *
213 * @param parameters entity content as a parameter list.
214 * @return this
215 */
216 public EntityBuilder setParameters(final NameValuePair... parameters) {
217 return setParameters(Arrays.asList(parameters));
218 }
219
220 /**
221 * Gets entity content as a {@link Serializable} if set using
222 * {@link #setSerializable(java.io.Serializable)} method.
223 *
224 * @return entity content as a {@link Serializable}.
225 */
226 public Serializable getSerializable() {
227 return serializable;
228 }
229
230 /**
231 * Sets entity content as a {@link Serializable}. This method is mutually exclusive with
232 * {@link #setText(String)},
233 * {@link #setBinary(byte[])},
234 * {@link #setStream(java.io.InputStream)},
235 * {@link #setParameters(java.util.List)},
236 * {@link #setParameters(NameValuePair...)}
237 * {@link #setFile(java.io.File)}.
238 *
239 * @param serializable entity content as a {@link Serializable}.
240 * @return this
241 */
242 public EntityBuilder setSerializable(final Serializable serializable) {
243 clearContent();
244 this.serializable = serializable;
245 return this;
246 }
247
248 /**
249 * Gets the entity content as a {@link File} if set using
250 * {@link #setFile(java.io.File)}.
251 *
252 * @return Gets the entity content as a {@link File}.
253 */
254 public File getFile() {
255 return file;
256 }
257
258 /**
259 * Sets entity content as a {@link File}. This method is mutually exclusive with
260 * {@link #setText(String)},
261 * {@link #setBinary(byte[])},
262 * {@link #setStream(java.io.InputStream)},
263 * {@link #setParameters(java.util.List)},
264 * {@link #setParameters(NameValuePair...)}
265 * {@link #setSerializable(java.io.Serializable)}.
266 *
267 * @param file entity content as a {@link File}.
268 * @return this
269 */
270 public EntityBuilder setFile(final File file) {
271 clearContent();
272 this.file = file;
273 return this;
274 }
275
276 /**
277 * Gets the {@link ContentType} of the entity, may be null.
278 *
279 * @return the {@link ContentType} of the entity, may be null.
280 */
281 public ContentType getContentType() {
282 return contentType;
283 }
284
285 /**
286 * Sets the {@link ContentType} of the entity.
287 *
288 * @param contentType the {@link ContentType} of the entity, may be null.
289 * @return this
290 */
291 public EntityBuilder setContentType(final ContentType contentType) {
292 this.contentType = contentType;
293 return this;
294 }
295
296 /**
297 * Gets the content encoding of the entity, may be null.
298 *
299 * @return the content encoding of the entity, may be null.
300 */
301 public String getContentEncoding() {
302 return contentEncoding;
303 }
304
305 /**
306 * Sets the content encoding of the entity.
307 *
308 * @param contentEncoding the content encoding of the entity, may be null.
309 * @return this
310 */
311 public EntityBuilder setContentEncoding(final String contentEncoding) {
312 this.contentEncoding = contentEncoding;
313 return this;
314 }
315
316 /**
317 * Tests if the entity is to be chunk coded ({@code true}), or not ({@code false}).
318 *
319 * @return {@code true} if entity is to be chunk coded, {@code false} otherwise.
320 */
321 public boolean isChunked() {
322 return chunked;
323 }
324
325 /**
326 * Sets entities to be chunked.
327 * @return this
328 */
329 public EntityBuilder chunked() {
330 this.chunked = true;
331 return this;
332 }
333
334 /**
335 * Tests if entities are to be GZIP compressed ({@code true}), or not ({@code false}).
336 *
337 * @return {@code true} if entity is to be GZIP compressed, {@code false} otherwise.
338 */
339 public boolean isGzipCompressed() {
340 return gzipCompressed;
341 }
342
343 /**
344 * Sets entities to be GZIP compressed.
345 *
346 * @return this
347 */
348 public EntityBuilder gzipCompressed() {
349 this.gzipCompressed = true;
350 return this;
351 }
352
353 private ContentType getContentOrDefault(final ContentType def) {
354 return this.contentType != null ? this.contentType : def;
355 }
356
357 /**
358 * Builds a new instance of {@link HttpEntity} based on the current state.
359 *
360 * @return a new instance.
361 */
362 public HttpEntity build() {
363 final AbstractHttpEntity e;
364 if (this.text != null) {
365 e = new StringEntity(this.text, getContentOrDefault(ContentType.DEFAULT_TEXT), this.contentEncoding,
366 this.chunked);
367 } else if (this.binary != null) {
368 e = new ByteArrayEntity(this.binary, getContentOrDefault(ContentType.DEFAULT_BINARY),
369 this.contentEncoding, this.chunked);
370 } else if (this.stream != null) {
371 e = new InputStreamEntity(this.stream, -1, getContentOrDefault(ContentType.DEFAULT_BINARY),
372 this.contentEncoding);
373 } else if (this.parameters != null) {
374 e = new UrlEncodedFormEntity(this.parameters,
375 this.contentType != null ? this.contentType.getCharset() : null);
376 } else if (this.serializable != null) {
377 e = new SerializableEntity(this.serializable, ContentType.DEFAULT_BINARY, this.contentEncoding);
378 } else if (this.file != null) {
379 e = new FileEntity(this.file, getContentOrDefault(ContentType.DEFAULT_BINARY), this.contentEncoding);
380 } else {
381 throw new IllegalStateException("No entity set");
382 }
383 if (this.gzipCompressed) {
384 return new GzipCompressingEntity(e);
385 }
386 return e;
387 }
388
389 }