1
1
package com .github .dockerjava .netty ;
2
2
3
+ import java .io .IOException ;
4
+ import java .io .UnsupportedEncodingException ;
5
+ import java .net .URLEncoder ;
6
+ import java .nio .charset .Charset ;
7
+ import java .nio .charset .UnsupportedCharsetException ;
3
8
import java .util .ArrayList ;
4
9
import java .util .Arrays ;
5
10
import java .util .List ;
6
11
import java .util .Map ;
12
+ import java .util .Set ;
7
13
14
+ import com .fasterxml .jackson .databind .ObjectMapper ;
15
+ import com .google .common .collect .ImmutableSet ;
16
+ import io .netty .handler .codec .http .HttpConstants ;
8
17
import org .apache .commons .lang .StringUtils ;
9
18
10
19
import com .google .common .collect .ImmutableList ;
11
20
import com .google .common .collect .ImmutableMap ;
12
21
13
22
/**
14
- * This class is basically a replacement of javax.ws.rs.client.WebTarget to allow simpler migration of JAX-RS code to a netty based
23
+ * This class is basically a replacement of {@link javax.ws.rs.client.WebTarget} to allow simpler migration of JAX-RS code to a netty based
15
24
* implementation.
16
25
*
17
26
* @author Marcus Linke
18
27
*/
19
28
public class WebTarget {
29
+ private static final ObjectMapper MAPPER = new ObjectMapper ();
20
30
21
31
private final ChannelProvider channelProvider ;
22
32
23
33
private final ImmutableList <String > path ;
24
34
25
35
private final ImmutableMap <String , String > queryParams ;
26
36
37
+ /**
38
+ * Multiple values for the same name param.
39
+ */
40
+ private final ImmutableMap <String , Set <String >> queryParamsSet ;
41
+
27
42
private static final String PATH_SEPARATOR = "/" ;
28
43
29
44
public WebTarget (ChannelProvider channelProvider ) {
30
- this (channelProvider , ImmutableList .<String >of (), ImmutableMap .<String , String >of ());
45
+ this (channelProvider , ImmutableList .<String >of (), ImmutableMap .<String , String >of (),
46
+ ImmutableMap .<String , Set <String >>of ());
31
47
}
32
48
33
49
private WebTarget (ChannelProvider channelProvider ,
34
50
ImmutableList <String > path ,
35
- ImmutableMap <String , String > queryParams ) {
51
+ ImmutableMap <String , String > queryParams ,
52
+ ImmutableMap <String , Set <String >> queryParamsSet ) {
36
53
this .channelProvider = channelProvider ;
37
54
this .path = path ;
38
55
this .queryParams = queryParams ;
56
+ this .queryParamsSet = queryParamsSet ;
39
57
}
40
58
41
59
public WebTarget path (String ... components ) {
@@ -45,15 +63,21 @@ public WebTarget path(String... components) {
45
63
newPath .addAll (Arrays .asList (StringUtils .split (component , PATH_SEPARATOR )));
46
64
}
47
65
48
- return new WebTarget (channelProvider , newPath .build (), queryParams );
66
+ return new WebTarget (channelProvider , newPath .build (), queryParams , queryParamsSet );
49
67
}
50
68
51
69
public InvocationBuilder request () {
52
70
String resource = PATH_SEPARATOR + StringUtils .join (path , PATH_SEPARATOR );
53
71
54
72
List <String > params = new ArrayList <>();
55
73
for (Map .Entry <String , String > entry : queryParams .entrySet ()) {
56
- params .add (entry .getKey () + "=" + entry .getValue ());
74
+ params .add (entry .getKey () + "=" + encodeComponent (entry .getValue (), HttpConstants .DEFAULT_CHARSET ));
75
+ }
76
+
77
+ for (Map .Entry <String , Set <String >> entry : queryParamsSet .entrySet ()) {
78
+ for (String entryValueValue : entry .getValue ()) {
79
+ params .add (entry .getKey () + "=" + encodeComponent (entryValueValue , HttpConstants .DEFAULT_CHARSET ));
80
+ }
57
81
}
58
82
59
83
if (!params .isEmpty ()) {
@@ -63,21 +87,58 @@ public InvocationBuilder request() {
63
87
return new InvocationBuilder (channelProvider , resource );
64
88
}
65
89
90
+ /**
91
+ * @see io.netty.handler.codec.http.QueryStringEncoder
92
+ */
93
+ private static String encodeComponent (String s , Charset charset ) {
94
+ // TODO: Optimize me.
95
+ try {
96
+ return URLEncoder .encode (s , charset .name ()).replace ("+" , "%20" );
97
+ } catch (UnsupportedEncodingException ignored ) {
98
+ throw new UnsupportedCharsetException (charset .name ());
99
+ }
100
+ }
101
+
66
102
public WebTarget resolveTemplate (String name , Object value ) {
67
103
ImmutableList .Builder <String > newPath = ImmutableList .builder ();
68
104
for (String component : path ) {
69
105
component = component .replaceAll ("\\ {" + name + "\\ }" , value .toString ());
70
106
newPath .add (component );
71
107
}
72
- return new WebTarget (channelProvider , newPath .build (), queryParams );
108
+ return new WebTarget (channelProvider , newPath .build (), queryParams , queryParamsSet );
73
109
}
74
110
75
111
public WebTarget queryParam (String name , Object value ) {
76
112
ImmutableMap .Builder <String , String > builder = ImmutableMap .<String , String >builder ().putAll (queryParams );
77
113
if (value != null ) {
78
114
builder .put (name , value .toString ());
79
115
}
80
- return new WebTarget (channelProvider , path , builder .build ());
116
+ return new WebTarget (channelProvider , path , builder .build (), queryParamsSet );
117
+ }
118
+
119
+ public WebTarget queryParamsSet (String name , Set <?> values ) {
120
+ ImmutableMap .Builder <String , Set <String >> builder = ImmutableMap .<String , Set <String >>builder ().putAll (queryParamsSet );
121
+ if (values != null ) {
122
+ ImmutableSet .Builder <String > valueBuilder = ImmutableSet .builder ();
123
+ for (Object value : values ) {
124
+ valueBuilder .add (value .toString ());
125
+ }
126
+ builder .put (name , valueBuilder .build ());
127
+ }
128
+ return new WebTarget (channelProvider , path , queryParams , builder .build ());
129
+ }
130
+
131
+ public WebTarget queryParamsJsonMap (String name , Map <String , String > values ) {
132
+ if (values != null && !values .isEmpty ()) {
133
+ try {
134
+ // when param value is JSON string
135
+ return queryParam (name , MAPPER .writeValueAsString (values ));
136
+ } catch (IOException e ) {
137
+ throw new RuntimeException (e );
138
+ }
139
+ } else {
140
+ return this ;
141
+ }
81
142
}
82
143
83
144
@ Override
@@ -97,14 +158,22 @@ public boolean equals(Object o) {
97
158
if (path != null ? !path .equals (webTarget .path ) : webTarget .path != null ) {
98
159
return false ;
99
160
}
100
- return queryParams != null ? queryParams .equals (webTarget .queryParams ) : webTarget .queryParams == null ;
161
+ if (queryParams != null ? !queryParams .equals (webTarget .queryParams ) : webTarget .queryParams != null ) {
162
+ return false ;
163
+ }
164
+ if (queryParamsSet != null ? !queryParamsSet .equals (webTarget .queryParamsSet ) : webTarget .queryParamsSet != null ) {
165
+ return false ;
166
+ }
167
+
168
+ return true ;
101
169
}
102
170
103
171
@ Override
104
172
public int hashCode () {
105
173
int result = channelProvider != null ? channelProvider .hashCode () : 0 ;
106
174
result = 31 * result + (path != null ? path .hashCode () : 0 );
107
175
result = 31 * result + (queryParams != null ? queryParams .hashCode () : 0 );
176
+ result = 31 * result + (queryParamsSet != null ? queryParamsSet .hashCode () : 0 );
108
177
return result ;
109
178
}
110
179
}
0 commit comments