View Javadoc
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.core5.http.nio.support;
29  
30  import java.net.URI;
31  import java.net.URISyntaxException;
32  import java.nio.charset.Charset;
33  import java.util.ArrayList;
34  import java.util.Iterator;
35  import java.util.LinkedList;
36  import java.util.List;
37  
38  import org.apache.hc.core5.http.ContentType;
39  import org.apache.hc.core5.http.Header;
40  import org.apache.hc.core5.http.HttpRequest;
41  import org.apache.hc.core5.http.Method;
42  import org.apache.hc.core5.http.NameValuePair;
43  import org.apache.hc.core5.http.ProtocolVersion;
44  import org.apache.hc.core5.http.message.BasicHeader;
45  import org.apache.hc.core5.http.message.BasicHttpRequest;
46  import org.apache.hc.core5.http.message.BasicNameValuePair;
47  import org.apache.hc.core5.http.message.HeaderGroup;
48  import org.apache.hc.core5.http.nio.AsyncEntityProducer;
49  import org.apache.hc.core5.http.nio.AsyncRequestProducer;
50  import org.apache.hc.core5.http.nio.entity.BasicAsyncEntityProducer;
51  import org.apache.hc.core5.http.nio.entity.StringAsyncEntityProducer;
52  import org.apache.hc.core5.net.URIBuilder;
53  import org.apache.hc.core5.net.URLEncodedUtils;
54  import org.apache.hc.core5.util.Args;
55  
56  /**
57   * Builder for {@link AsyncRequestProducer} instances.
58   * <p>
59   * Please note that this class treats parameters differently depending on composition
60   * of the request: if the request has a content entity explicitly set with
61   * {@link #setEntity(AsyncEntityProducer)} or it is not an entity enclosing method
62   * (such as POST or PUT), parameters will be added to the query component of the request URI.
63   * Otherwise, parameters will be added as a URL encoded entity.
64   * </p>
65   *
66   * @since 5.0
67   */
68  public class AsyncRequestBuilder {
69  
70      private String method;
71      private URI uri;
72      private Charset charset;
73      private ProtocolVersion version;
74      private HeaderGroup headerGroup;
75      private AsyncEntityProducer entityProducer;
76      private List<NameValuePair> parameters;
77  
78      AsyncRequestBuilder() {
79      }
80  
81      AsyncRequestBuilder(final String method) {
82          super();
83          this.method = method;
84      }
85  
86      AsyncRequestBuilder(final Method method) {
87          this(method.name());
88      }
89  
90      AsyncRequestBuilder(final String method, final URI uri) {
91          super();
92          this.method = method;
93          this.uri = uri;
94      }
95  
96      AsyncRequestBuilder(final Method method, final URI uri) {
97          this(method.name(), uri);
98      }
99  
100     AsyncRequestBuilder(final Method method, final String uri) {
101         this(method.name(), uri != null ? URI.create(uri) : null);
102     }
103 
104     AsyncRequestBuilder(final String method, final String uri) {
105         this(method, uri != null ? URI.create(uri) : null);
106     }
107 
108     public static AsyncRequestBuilder create(final String method) {
109         Args.notBlank(method, "HTTP method");
110         return new AsyncRequestBuilder(method);
111     }
112 
113     public static AsyncRequestBuilder get() {
114         return new AsyncRequestBuilder(Method.GET);
115     }
116 
117     public static AsyncRequestBuilder get(final URI uri) {
118         return new AsyncRequestBuilder(Method.GET, uri);
119     }
120 
121     public static AsyncRequestBuilder get(final String uri) {
122         return new AsyncRequestBuilder(Method.GET, uri);
123     }
124 
125     public static AsyncRequestBuilder head() {
126         return new AsyncRequestBuilder(Method.HEAD);
127     }
128 
129     public static AsyncRequestBuilder head(final URI uri) {
130         return new AsyncRequestBuilder(Method.HEAD, uri);
131     }
132 
133     public static AsyncRequestBuilder head(final String uri) {
134         return new AsyncRequestBuilder(Method.HEAD, uri);
135     }
136 
137     public static AsyncRequestBuilder patch() {
138         return new AsyncRequestBuilder(Method.PATCH);
139     }
140 
141     public static AsyncRequestBuilder patch(final URI uri) {
142         return new AsyncRequestBuilder(Method.PATCH, uri);
143     }
144 
145     public static AsyncRequestBuilder patch(final String uri) {
146         return new AsyncRequestBuilder(Method.PATCH, uri);
147     }
148 
149     public static AsyncRequestBuilder post() {
150         return new AsyncRequestBuilder(Method.POST);
151     }
152 
153     public static AsyncRequestBuilder post(final URI uri) {
154         return new AsyncRequestBuilder(Method.POST, uri);
155     }
156 
157     public static AsyncRequestBuilder post(final String uri) {
158         return new AsyncRequestBuilder(Method.POST, uri);
159     }
160 
161     public static AsyncRequestBuilder put() {
162         return new AsyncRequestBuilder(Method.PUT);
163     }
164 
165     public static AsyncRequestBuilder put(final URI uri) {
166         return new AsyncRequestBuilder(Method.PUT, uri);
167     }
168 
169     public static AsyncRequestBuilder put(final String uri) {
170         return new AsyncRequestBuilder(Method.PUT, uri);
171     }
172 
173     public static AsyncRequestBuilder delete() {
174         return new AsyncRequestBuilder(Method.DELETE);
175     }
176 
177     public static AsyncRequestBuilder delete(final URI uri) {
178         return new AsyncRequestBuilder(Method.DELETE, uri);
179     }
180 
181     public static AsyncRequestBuilder delete(final String uri) {
182         return new AsyncRequestBuilder(Method.DELETE, uri);
183     }
184 
185     public static AsyncRequestBuilder trace() {
186         return new AsyncRequestBuilder(Method.TRACE);
187     }
188 
189     public static AsyncRequestBuilder trace(final URI uri) {
190         return new AsyncRequestBuilder(Method.TRACE, uri);
191     }
192 
193     public static AsyncRequestBuilder trace(final String uri) {
194         return new AsyncRequestBuilder(Method.TRACE, uri);
195     }
196 
197     public static AsyncRequestBuilder options() {
198         return new AsyncRequestBuilder(Method.OPTIONS);
199     }
200 
201     public static AsyncRequestBuilder options(final URI uri) {
202         return new AsyncRequestBuilder(Method.OPTIONS, uri);
203     }
204 
205     public static AsyncRequestBuilder options(final String uri) {
206         return new AsyncRequestBuilder(Method.OPTIONS, uri);
207     }
208 
209     public AsyncRequestBuilder setCharset(final Charset charset) {
210         this.charset = charset;
211         return this;
212     }
213 
214     public Charset getCharset() {
215         return charset;
216     }
217 
218     public String getMethod() {
219         return method;
220     }
221 
222     public URI getUri() {
223         return uri;
224     }
225 
226     public AsyncRequestBuilder setUri(final URI uri) {
227         this.uri = uri;
228         return this;
229     }
230 
231     public AsyncRequestBuilder setUri(final String uri) {
232         this.uri = uri != null ? URI.create(uri) : null;
233         return this;
234     }
235 
236     public ProtocolVersion getVersion() {
237         return version;
238     }
239 
240     public AsyncRequestBuilder setVersion(final ProtocolVersion version) {
241         this.version = version;
242         return this;
243     }
244 
245     public Header[] getHeaders(final String name) {
246         return headerGroup != null ? headerGroup.getHeaders(name) : null;
247     }
248 
249     public AsyncRequestBuilder setHeaders(final Header... headers) {
250         if (headerGroup == null) {
251             headerGroup = new HeaderGroup();
252         }
253         headerGroup.setHeaders(headers);
254         return this;
255     }
256 
257     public Header getFirstHeader(final String name) {
258         return headerGroup != null ? headerGroup.getFirstHeader(name) : null;
259     }
260 
261     public Header getLastHeader(final String name) {
262         return headerGroup != null ? headerGroup.getLastHeader(name) : null;
263     }
264 
265     public AsyncRequestBuilder addHeader(final Header header) {
266         if (headerGroup == null) {
267             headerGroup = new HeaderGroup();
268         }
269         headerGroup.addHeader(header);
270         return this;
271     }
272 
273     public AsyncRequestBuilder addHeader(final String name, final String value) {
274         if (headerGroup == null) {
275             headerGroup = new HeaderGroup();
276         }
277         this.headerGroup.addHeader(new BasicHeader(name, value));
278         return this;
279     }
280 
281     public AsyncRequestBuilder removeHeader(final Header header) {
282         if (headerGroup == null) {
283             headerGroup = new HeaderGroup();
284         }
285         headerGroup.removeHeader(header);
286         return this;
287     }
288 
289     public AsyncRequestBuilder removeHeaders(final String name) {
290         if (name == null || headerGroup == null) {
291             return this;
292         }
293         for (final Iterator<Header> i = headerGroup.headerIterator(); i.hasNext(); ) {
294             final Header header = i.next();
295             if (name.equalsIgnoreCase(header.getName())) {
296                 i.remove();
297             }
298         }
299         return this;
300     }
301 
302     public AsyncRequestBuilder setHeader(final Header header) {
303         if (headerGroup == null) {
304             headerGroup = new HeaderGroup();
305         }
306         this.headerGroup.setHeader(header);
307         return this;
308     }
309 
310     public AsyncRequestBuilder setHeader(final String name, final String value) {
311         if (headerGroup == null) {
312             headerGroup = new HeaderGroup();
313         }
314         this.headerGroup.setHeader(new BasicHeader(name, value));
315         return this;
316     }
317 
318     public List<NameValuePair> getParameters() {
319         return parameters != null ? new ArrayList<>(parameters) : new ArrayList<NameValuePair>();
320     }
321 
322     public AsyncRequestBuilder addParameter(final NameValuePair nvp) {
323         Args.notNull(nvp, "Name value pair");
324         if (parameters == null) {
325             parameters = new LinkedList<>();
326         }
327         parameters.add(nvp);
328         return this;
329     }
330 
331     public AsyncRequestBuilder addParameter(final String name, final String value) {
332         return addParameter(new BasicNameValuePair(name, value));
333     }
334 
335     public AsyncRequestBuilder addParameters(final NameValuePair... nvps) {
336         for (final NameValuePair nvp: nvps) {
337             addParameter(nvp);
338         }
339         return this;
340     }
341 
342     public AsyncEntityProducer getEntity() {
343         return entityProducer;
344     }
345 
346     public AsyncRequestBuilder setEntity(final AsyncEntityProducer entityProducer) {
347         this.entityProducer = entityProducer;
348         return this;
349     }
350 
351     public AsyncRequestBuilder setEntity(final String content, final ContentType contentType) {
352         this.entityProducer = new BasicAsyncEntityProducer(content, contentType);
353         return this;
354     }
355 
356     public AsyncRequestBuilder setEntity(final String content) {
357         this.entityProducer = new BasicAsyncEntityProducer(content);
358         return this;
359     }
360 
361     public AsyncRequestBuilder setEntity(final byte[] content, final ContentType contentType) {
362         this.entityProducer = new BasicAsyncEntityProducer(content, contentType);
363         return this;
364     }
365 
366     public AsyncRequestProducer build() {
367         URI uriCopy = uri != null ? uri : URI.create("/");
368         AsyncEntityProducer entityProducerCopy = entityProducer;
369         if (parameters != null && !parameters.isEmpty()) {
370             if (entityProducerCopy == null && (Method.POST.isSame(method) || Method.PUT.isSame(method))) {
371                 final String content = URLEncodedUtils.format(
372                         parameters,
373                         charset != null ? charset : ContentType.APPLICATION_FORM_URLENCODED.getCharset());
374                 entityProducerCopy = new StringAsyncEntityProducer(
375                         content,
376                         ContentType.APPLICATION_FORM_URLENCODED);
377             } else {
378                 try {
379                     uriCopy = new URIBuilder(uriCopy)
380                       .setCharset(this.charset)
381                       .addParameters(parameters)
382                       .build();
383                 } catch (final URISyntaxException ex) {
384                     // should never happen
385                 }
386             }
387         }
388 
389         if (entityProducerCopy != null && Method.TRACE.isSame(method)) {
390             throw new IllegalStateException(Method.TRACE + " requests may not include an entity.");
391         }
392 
393         final HttpRequest request = new BasicHttpRequest(method, uriCopy);
394         if (this.headerGroup != null) {
395             request.setHeaders(this.headerGroup.getHeaders());
396         }
397         if (version != null) {
398             request.setVersion(version);
399         }
400         return new BasicRequestProducer(request, entityProducerCopy);
401     }
402 
403     @Override
404     public String toString() {
405         final StringBuilder builder = new StringBuilder();
406         builder.append("AsyncRequestBuilder [method=");
407         builder.append(method);
408         builder.append(", charset=");
409         builder.append(charset);
410         builder.append(", version=");
411         builder.append(version);
412         builder.append(", uri=");
413         builder.append(uri);
414         builder.append(", headerGroup=");
415         builder.append(headerGroup);
416         builder.append(", entity=");
417         builder.append(entityProducer != null ? entityProducer.getClass() : null);
418         builder.append(", parameters=");
419         builder.append(parameters);
420         builder.append("]");
421         return builder.toString();
422     }
423 
424 }