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 package org.apache.http.client.utils;
28
29 import java.net.URI;
30 import java.net.URISyntaxException;
31 import java.nio.charset.Charset;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Collections;
35 import java.util.Iterator;
36 import java.util.List;
37
38 import org.apache.http.Consts;
39 import org.apache.http.NameValuePair;
40 import org.apache.http.conn.util.InetAddressUtils;
41 import org.apache.http.message.BasicNameValuePair;
42 import org.apache.http.util.TextUtils;
43
44
45
46
47
48
49 public class URIBuilder {
50
51 private String scheme;
52 private String encodedSchemeSpecificPart;
53 private String encodedAuthority;
54 private String userInfo;
55 private String encodedUserInfo;
56 private String host;
57 private int port;
58 private String encodedPath;
59 private List<String> pathSegments;
60 private String encodedQuery;
61 private List<NameValuePair> queryParams;
62 private String query;
63 private Charset charset;
64 private String fragment;
65 private String encodedFragment;
66
67
68
69
70 public URIBuilder() {
71 super();
72 this.port = -1;
73 }
74
75
76
77
78
79
80
81 public URIBuilder(final String string) throws URISyntaxException {
82 this(new URI(string), null);
83 }
84
85
86
87
88
89 public URIBuilder(final URI uri) {
90 this(uri, null);
91 }
92
93
94
95
96
97
98
99 public URIBuilder(final String string, final Charset charset) throws URISyntaxException {
100 this(new URI(string), charset);
101 }
102
103
104
105
106
107 public URIBuilder(final URI uri, final Charset charset) {
108 super();
109 setCharset(charset);
110 digestURI(uri);
111 }
112
113
114
115
116 public URIBuilder setCharset(final Charset charset) {
117 this.charset = charset;
118 return this;
119 }
120
121
122
123
124 public Charset getCharset() {
125 return charset;
126 }
127
128 private List <NameValuePair> parseQuery(final String query, final Charset charset) {
129 if (query != null && !query.isEmpty()) {
130 return URLEncodedUtils.parse(query, charset);
131 }
132 return null;
133 }
134
135 private List <String> parsePath(final String path, final Charset charset) {
136 if (path != null && !path.isEmpty()) {
137 return URLEncodedUtils.parsePathSegments(path, charset);
138 }
139 return null;
140 }
141
142
143
144
145 public URI build() throws URISyntaxException {
146 return new URI(buildString());
147 }
148
149 private String buildString() {
150 final StringBuilder sb = new StringBuilder();
151 if (this.scheme != null) {
152 sb.append(this.scheme).append(':');
153 }
154 if (this.encodedSchemeSpecificPart != null) {
155 sb.append(this.encodedSchemeSpecificPart);
156 } else {
157 if (this.encodedAuthority != null) {
158 sb.append("//").append(this.encodedAuthority);
159 } else if (this.host != null) {
160 sb.append("//");
161 if (this.encodedUserInfo != null) {
162 sb.append(this.encodedUserInfo).append("@");
163 } else if (this.userInfo != null) {
164 sb.append(encodeUserInfo(this.userInfo)).append("@");
165 }
166 if (InetAddressUtils.isIPv6Address(this.host)) {
167 sb.append("[").append(this.host).append("]");
168 } else {
169 sb.append(this.host);
170 }
171 if (this.port >= 0) {
172 sb.append(":").append(this.port);
173 }
174 }
175 if (this.encodedPath != null) {
176 sb.append(normalizePath(this.encodedPath, sb.length() == 0));
177 } else if (this.pathSegments != null) {
178 sb.append(encodePath(this.pathSegments));
179 }
180 if (this.encodedQuery != null) {
181 sb.append("?").append(this.encodedQuery);
182 } else if (this.queryParams != null && !this.queryParams.isEmpty()) {
183 sb.append("?").append(encodeUrlForm(this.queryParams));
184 } else if (this.query != null) {
185 sb.append("?").append(encodeUric(this.query));
186 }
187 }
188 if (this.encodedFragment != null) {
189 sb.append("#").append(this.encodedFragment);
190 } else if (this.fragment != null) {
191 sb.append("#").append(encodeUric(this.fragment));
192 }
193 return sb.toString();
194 }
195
196 private static String normalizePath(final String path, final boolean relative) {
197 String s = path;
198 if (TextUtils.isBlank(s)) {
199 return "";
200 }
201 if (!relative && !s.startsWith("/")) {
202 s = "/" + s;
203 }
204 return s;
205 }
206
207 private void digestURI(final URI uri) {
208 this.scheme = uri.getScheme();
209 this.encodedSchemeSpecificPart = uri.getRawSchemeSpecificPart();
210 this.encodedAuthority = uri.getRawAuthority();
211 this.host = uri.getHost();
212 this.port = uri.getPort();
213 this.encodedUserInfo = uri.getRawUserInfo();
214 this.userInfo = uri.getUserInfo();
215 this.encodedPath = uri.getRawPath();
216 this.pathSegments = parsePath(uri.getRawPath(), this.charset != null ? this.charset : Consts.UTF_8);
217 this.encodedQuery = uri.getRawQuery();
218 this.queryParams = parseQuery(uri.getRawQuery(), this.charset != null ? this.charset : Consts.UTF_8);
219 this.encodedFragment = uri.getRawFragment();
220 this.fragment = uri.getFragment();
221 }
222
223 private String encodeUserInfo(final String userInfo) {
224 return URLEncodedUtils.encUserInfo(userInfo, this.charset != null ? this.charset : Consts.UTF_8);
225 }
226
227 private String encodePath(final List<String> pathSegments) {
228 return URLEncodedUtils.formatSegments(pathSegments, this.charset != null ? this.charset : Consts.UTF_8);
229 }
230
231 private String encodeUrlForm(final List<NameValuePair> params) {
232 return URLEncodedUtils.format(params, this.charset != null ? this.charset : Consts.UTF_8);
233 }
234
235 private String encodeUric(final String fragment) {
236 return URLEncodedUtils.encUric(fragment, this.charset != null ? this.charset : Consts.UTF_8);
237 }
238
239
240
241
242 public URIBuilder setScheme(final String scheme) {
243 this.scheme = scheme;
244 return this;
245 }
246
247
248
249
250
251 public URIBuilder setUserInfo(final String userInfo) {
252 this.userInfo = userInfo;
253 this.encodedSchemeSpecificPart = null;
254 this.encodedAuthority = null;
255 this.encodedUserInfo = null;
256 return this;
257 }
258
259
260
261
262
263 public URIBuilder setUserInfo(final String username, final String password) {
264 return setUserInfo(username + ':' + password);
265 }
266
267
268
269
270 public URIBuilder setHost(final String host) {
271 this.host = host;
272 this.encodedSchemeSpecificPart = null;
273 this.encodedAuthority = null;
274 return this;
275 }
276
277
278
279
280 public URIBuilder setPort(final int port) {
281 this.port = port < 0 ? -1 : port;
282 this.encodedSchemeSpecificPart = null;
283 this.encodedAuthority = null;
284 return this;
285 }
286
287
288
289
290
291
292 public URIBuilder setPath(final String path) {
293 return setPathSegments(path != null ? URLEncodedUtils.splitPathSegments(path) : null);
294 }
295
296
297
298
299
300
301
302
303 public URIBuilder setPathSegments(final String... pathSegments) {
304 this.pathSegments = pathSegments.length > 0 ? Arrays.asList(pathSegments) : null;
305 this.encodedSchemeSpecificPart = null;
306 this.encodedPath = null;
307 return this;
308 }
309
310
311
312
313
314
315
316
317 public URIBuilder setPathSegments(final List<String> pathSegments) {
318 this.pathSegments = pathSegments != null && pathSegments.size() > 0 ? new ArrayList<String>(pathSegments) : null;
319 this.encodedSchemeSpecificPart = null;
320 this.encodedPath = null;
321 return this;
322 }
323
324
325
326
327 public URIBuilder removeQuery() {
328 this.queryParams = null;
329 this.query = null;
330 this.encodedQuery = null;
331 this.encodedSchemeSpecificPart = null;
332 return this;
333 }
334
335
336
337
338
339
340
341
342
343
344 @Deprecated
345 public URIBuilder setQuery(final String query) {
346 this.queryParams = parseQuery(query, this.charset != null ? this.charset : Consts.UTF_8);
347 this.query = null;
348 this.encodedQuery = null;
349 this.encodedSchemeSpecificPart = null;
350 return this;
351 }
352
353
354
355
356
357
358
359
360
361
362
363 public URIBuilder setParameters(final List <NameValuePair> nvps) {
364 if (this.queryParams == null) {
365 this.queryParams = new ArrayList<NameValuePair>();
366 } else {
367 this.queryParams.clear();
368 }
369 this.queryParams.addAll(nvps);
370 this.encodedQuery = null;
371 this.encodedSchemeSpecificPart = null;
372 this.query = null;
373 return this;
374 }
375
376
377
378
379
380
381
382
383
384
385
386 public URIBuilder addParameters(final List <NameValuePair> nvps) {
387 if (this.queryParams == null) {
388 this.queryParams = new ArrayList<NameValuePair>();
389 }
390 this.queryParams.addAll(nvps);
391 this.encodedQuery = null;
392 this.encodedSchemeSpecificPart = null;
393 this.query = null;
394 return this;
395 }
396
397
398
399
400
401
402
403
404
405
406
407 public URIBuilder setParameters(final NameValuePair... nvps) {
408 if (this.queryParams == null) {
409 this.queryParams = new ArrayList<NameValuePair>();
410 } else {
411 this.queryParams.clear();
412 }
413 Collections.addAll(this.queryParams, nvps);
414 this.encodedQuery = null;
415 this.encodedSchemeSpecificPart = null;
416 this.query = null;
417 return this;
418 }
419
420
421
422
423
424
425
426
427
428 public URIBuilder addParameter(final String param, final String value) {
429 if (this.queryParams == null) {
430 this.queryParams = new ArrayList<NameValuePair>();
431 }
432 this.queryParams.add(new BasicNameValuePair(param, value));
433 this.encodedQuery = null;
434 this.encodedSchemeSpecificPart = null;
435 this.query = null;
436 return this;
437 }
438
439
440
441
442
443
444
445
446
447 public URIBuilder setParameter(final String param, final String value) {
448 if (this.queryParams == null) {
449 this.queryParams = new ArrayList<NameValuePair>();
450 }
451 if (!this.queryParams.isEmpty()) {
452 for (final Iterator<NameValuePair> it = this.queryParams.iterator(); it.hasNext(); ) {
453 final NameValuePair nvp = it.next();
454 if (nvp.getName().equals(param)) {
455 it.remove();
456 }
457 }
458 }
459 this.queryParams.add(new BasicNameValuePair(param, value));
460 this.encodedQuery = null;
461 this.encodedSchemeSpecificPart = null;
462 this.query = null;
463 return this;
464 }
465
466
467
468
469
470
471 public URIBuilder clearParameters() {
472 this.queryParams = null;
473 this.encodedQuery = null;
474 this.encodedSchemeSpecificPart = null;
475 return this;
476 }
477
478
479
480
481
482
483
484
485
486
487
488 public URIBuilder setCustomQuery(final String query) {
489 this.query = query;
490 this.encodedQuery = null;
491 this.encodedSchemeSpecificPart = null;
492 this.queryParams = null;
493 return this;
494 }
495
496
497
498
499
500 public URIBuilder setFragment(final String fragment) {
501 this.fragment = fragment;
502 this.encodedFragment = null;
503 return this;
504 }
505
506
507
508
509 public boolean isAbsolute() {
510 return this.scheme != null;
511 }
512
513
514
515
516 public boolean isOpaque() {
517 return this.pathSegments == null && this.encodedPath == null;
518 }
519
520 public String getScheme() {
521 return this.scheme;
522 }
523
524 public String getUserInfo() {
525 return this.userInfo;
526 }
527
528 public String getHost() {
529 return this.host;
530 }
531
532 public int getPort() {
533 return this.port;
534 }
535
536
537
538
539 public boolean isPathEmpty() {
540 return (this.pathSegments == null || this.pathSegments.isEmpty()) &&
541 (this.encodedPath == null || this.encodedPath.isEmpty());
542 }
543
544
545
546
547 public List<String> getPathSegments() {
548 return this.pathSegments != null ? new ArrayList<String>(this.pathSegments) : new ArrayList<String>();
549 }
550
551 public String getPath() {
552 if (this.pathSegments == null) {
553 return null;
554 }
555 final StringBuilder result = new StringBuilder();
556 for (final String segment : this.pathSegments) {
557 result.append('/').append(segment);
558 }
559 return result.toString();
560 }
561
562
563
564
565 public boolean isQueryEmpty() {
566 return (this.queryParams == null || this.queryParams.isEmpty()) && this.encodedQuery == null;
567 }
568
569 public List<NameValuePair> getQueryParams() {
570 return this.queryParams != null ? new ArrayList<NameValuePair>(this.queryParams) : new ArrayList<NameValuePair>();
571 }
572
573 public String getFragment() {
574 return this.fragment;
575 }
576
577 @Override
578 public String toString() {
579 return buildString();
580 }
581
582 }