001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.client.entity;
029
030import java.io.File;
031import java.io.InputStream;
032import java.io.Serializable;
033import java.util.Arrays;
034import java.util.List;
035
036import org.apache.http.HttpEntity;
037import org.apache.http.NameValuePair;
038import org.apache.http.entity.AbstractHttpEntity;
039import org.apache.http.entity.BasicHttpEntity;
040import org.apache.http.entity.ByteArrayEntity;
041import org.apache.http.entity.ContentType;
042import org.apache.http.entity.FileEntity;
043import org.apache.http.entity.InputStreamEntity;
044import org.apache.http.entity.SerializableEntity;
045import org.apache.http.entity.StringEntity;
046
047/**
048 * Builder for {@link HttpEntity} instances.
049 * <p>
050 * Several setter methods of this builder are mutually exclusive. In case of multiple invocations
051 * of the following methods only the last one will have effect:
052 * </p>
053 * <ul>
054 *   <li>{@link #setText(String)}</li>
055 *   <li>{@link #setBinary(byte[])}</li>
056 *   <li>{@link #setStream(java.io.InputStream)}</li>
057 *   <li>{@link #setSerializable(java.io.Serializable)}</li>
058 *   <li>{@link #setParameters(java.util.List)}</li>
059 *   <li>{@link #setParameters(org.apache.http.NameValuePair...)}</li>
060 *   <li>{@link #setFile(java.io.File)}</li>
061 * </ul>
062 *
063 * @since 4.3
064 */
065public class EntityBuilder {
066
067    private String text;
068    private byte[] binary;
069    private InputStream stream;
070    private List<NameValuePair> parameters;
071    private Serializable serializable;
072    private File file;
073    private ContentType contentType;
074    private String contentEncoding;
075    private boolean chunked;
076    private boolean gzipCompress;
077
078    EntityBuilder() {
079        super();
080    }
081
082    public static EntityBuilder create() {
083        return new EntityBuilder();
084    }
085
086    private void clearContent() {
087        this.text = null;
088        this.binary = null;
089        this.stream = null;
090        this.parameters = null;
091        this.serializable = null;
092        this.file = null;
093    }
094
095    /**
096     * Returns entity content as a string if set using {@link #setText(String)} method.
097     */
098    public String getText() {
099        return text;
100    }
101
102    /**
103     * Sets entity content as a string. This method is mutually exclusive with
104     * {@link #setBinary(byte[])},
105     * {@link #setStream(java.io.InputStream)} ,
106     * {@link #setSerializable(java.io.Serializable)} ,
107     * {@link #setParameters(java.util.List)},
108     * {@link #setParameters(org.apache.http.NameValuePair...)}
109     * {@link #setFile(java.io.File)} methods.
110     */
111    public EntityBuilder setText(final String text) {
112        clearContent();
113        this.text = text;
114        return this;
115    }
116
117    /**
118     * Returns entity content as a byte array if set using
119     * {@link #setBinary(byte[])} method.
120     */
121    public byte[] getBinary() {
122        return binary;
123    }
124
125    /**
126     * Sets entity content as a byte array. This method is mutually exclusive with
127     * {@link #setText(String)},
128     * {@link #setStream(java.io.InputStream)} ,
129     * {@link #setSerializable(java.io.Serializable)} ,
130     * {@link #setParameters(java.util.List)},
131     * {@link #setParameters(org.apache.http.NameValuePair...)}
132     * {@link #setFile(java.io.File)} methods.
133     */
134    public EntityBuilder setBinary(final byte[] binary) {
135        clearContent();
136        this.binary = binary;
137        return this;
138    }
139
140    /**
141     * Returns entity content as a {@link InputStream} if set using
142     * {@link #setStream(java.io.InputStream)} method.
143     */
144    public InputStream getStream() {
145        return stream;
146    }
147
148    /**
149     * Sets entity content as a {@link InputStream}. This method is mutually exclusive with
150     * {@link #setText(String)},
151     * {@link #setBinary(byte[])},
152     * {@link #setSerializable(java.io.Serializable)} ,
153     * {@link #setParameters(java.util.List)},
154     * {@link #setParameters(org.apache.http.NameValuePair...)}
155     * {@link #setFile(java.io.File)} methods.
156     */
157    public EntityBuilder setStream(final InputStream stream) {
158        clearContent();
159        this.stream = stream;
160        return this;
161    }
162
163    /**
164     * Returns entity content as a parameter list if set using
165     * {@link #setParameters(java.util.List)} or
166     * {@link #setParameters(org.apache.http.NameValuePair...)} methods.
167     */
168    public List<NameValuePair> getParameters() {
169        return parameters;
170    }
171
172    /**
173     * Sets entity content as a parameter list. This method is mutually exclusive with
174     * {@link #setText(String)},
175     * {@link #setBinary(byte[])},
176     * {@link #setStream(java.io.InputStream)} ,
177     * {@link #setSerializable(java.io.Serializable)} ,
178     * {@link #setFile(java.io.File)} methods.
179     */
180    public EntityBuilder setParameters(final List<NameValuePair> parameters) {
181        clearContent();
182        this.parameters = parameters;
183        return this;
184    }
185
186    /**
187     * Sets entity content as a parameter list. This method is mutually exclusive with
188     * {@link #setText(String)},
189     * {@link #setBinary(byte[])},
190     * {@link #setStream(java.io.InputStream)} ,
191     * {@link #setSerializable(java.io.Serializable)} ,
192     * {@link #setFile(java.io.File)} methods.
193     */
194    public EntityBuilder setParameters(final NameValuePair... parameters) {
195        return setParameters(Arrays.asList(parameters));
196    }
197
198    /**
199     * Returns entity content as a {@link Serializable} if set using
200     * {@link #setSerializable(java.io.Serializable)} method.
201     */
202    public Serializable getSerializable() {
203        return serializable;
204    }
205
206    /**
207     * Sets entity content as a {@link Serializable}. This method is mutually exclusive with
208     * {@link #setText(String)},
209     * {@link #setBinary(byte[])},
210     * {@link #setStream(java.io.InputStream)} ,
211     * {@link #setParameters(java.util.List)},
212     * {@link #setParameters(org.apache.http.NameValuePair...)}
213     * {@link #setFile(java.io.File)} methods.
214     */
215    public EntityBuilder setSerializable(final Serializable serializable) {
216        clearContent();
217        this.serializable = serializable;
218        return this;
219    }
220
221    /**
222     * Returns entity content as a {@link File} if set using
223     * {@link #setFile(java.io.File)} method.
224     */
225    public File getFile() {
226        return file;
227    }
228
229    /**
230     * Sets entity content as a {@link File}. This method is mutually exclusive with
231     * {@link #setText(String)},
232     * {@link #setBinary(byte[])},
233     * {@link #setStream(java.io.InputStream)} ,
234     * {@link #setParameters(java.util.List)},
235     * {@link #setParameters(org.apache.http.NameValuePair...)}
236     * {@link #setSerializable(java.io.Serializable)} methods.
237     */
238    public EntityBuilder setFile(final File file) {
239        clearContent();
240        this.file = file;
241        return this;
242    }
243
244    /**
245     * Returns {@link ContentType} of the entity, if set.
246     */
247    public ContentType getContentType() {
248        return contentType;
249    }
250
251    /**
252     * Sets {@link ContentType} of the entity.
253     */
254    public EntityBuilder setContentType(final ContentType contentType) {
255        this.contentType = contentType;
256        return this;
257    }
258
259    /**
260     * Returns content encoding of the entity, if set.
261     */
262    public String getContentEncoding() {
263        return contentEncoding;
264    }
265
266    /**
267     * Sets content encoding of the entity.
268     */
269    public EntityBuilder setContentEncoding(final String contentEncoding) {
270        this.contentEncoding = contentEncoding;
271        return this;
272    }
273
274    /**
275     * Returns {@code true} if entity is to be chunk coded, {@code false} otherwise.
276     */
277    public boolean isChunked() {
278        return chunked;
279    }
280
281    /**
282     * Makes entity chunk coded.
283     */
284    public EntityBuilder chunked() {
285        this.chunked = true;
286        return this;
287    }
288
289    /**
290     * Returns {@code true} if entity is to be GZIP compressed, {@code false} otherwise.
291     */
292    public boolean isGzipCompress() {
293        return gzipCompress;
294    }
295
296    /**
297     * Makes entity GZIP compressed.
298     */
299    public EntityBuilder gzipCompress() {
300        this.gzipCompress = true;
301        return this;
302    }
303
304    private ContentType getContentOrDefault(final ContentType def) {
305        return this.contentType != null ? this.contentType : def;
306    }
307
308    /**
309     * Creates new instance of {@link HttpEntity} based on the current state.
310     */
311    public HttpEntity build() {
312        final AbstractHttpEntity e;
313        if (this.text != null) {
314            e = new StringEntity(this.text, getContentOrDefault(ContentType.DEFAULT_TEXT));
315        } else if (this.binary != null) {
316            e = new ByteArrayEntity(this.binary, getContentOrDefault(ContentType.DEFAULT_BINARY));
317        } else if (this.stream != null) {
318            e = new InputStreamEntity(this.stream, -1, getContentOrDefault(ContentType.DEFAULT_BINARY));
319        } else if (this.parameters != null) {
320            e = new UrlEncodedFormEntity(this.parameters,
321                    this.contentType != null ? this.contentType.getCharset() : null);
322        } else if (this.serializable != null) {
323            e = new SerializableEntity(this.serializable);
324            e.setContentType(ContentType.DEFAULT_BINARY.toString());
325        } else if (this.file != null) {
326            e = new FileEntity(this.file, getContentOrDefault(ContentType.DEFAULT_BINARY));
327        } else {
328            e = new BasicHttpEntity();
329        }
330        if (e.getContentType() != null && this.contentType != null) {
331            e.setContentType(this.contentType.toString());
332        }
333        e.setContentEncoding(this.contentEncoding);
334        e.setChunked(this.chunked);
335        if (this.gzipCompress) {
336            return new GzipCompressingEntity(e);
337        }
338        return e;
339    }
340
341}