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
28
29
30 package com.jcabi.http.mock;
31
32 import com.jcabi.aspects.Immutable;
33 import com.jcabi.aspects.Loggable;
34 import com.jcabi.http.ImmutableHeader;
35 import com.jcabi.http.RequestBody;
36 import com.jcabi.immutable.Array;
37 import com.jcabi.log.Logger;
38 import java.net.HttpURLConnection;
39 import java.nio.charset.Charset;
40 import java.util.LinkedList;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.concurrent.ConcurrentHashMap;
44 import java.util.concurrent.ConcurrentMap;
45 import lombok.EqualsAndHashCode;
46
47
48
49
50
51
52 @Immutable
53 @SuppressWarnings("PMD.TooManyMethods")
54 public interface MkAnswer {
55
56
57
58
59
60 int status();
61
62
63
64
65
66 Map<String, List<String>> headers();
67
68
69
70
71
72 String body();
73
74
75
76
77
78 byte[] bodyBytes();
79
80
81
82
83
84
85 @Immutable
86 @EqualsAndHashCode(of = {"code", "hdrs", "content"})
87 @Loggable(Loggable.DEBUG)
88 final class Simple implements MkAnswer {
89
90
91
92 private static final Charset CHARSET = Charset.forName("UTF-8");
93
94
95
96
97 private final transient int code;
98
99
100
101
102 private final transient Array<Map.Entry<String, String>> hdrs;
103
104
105
106
107 @Immutable.Array
108 private final transient byte[] content;
109
110
111
112
113
114 public Simple(final String body) {
115 this(HttpURLConnection.HTTP_OK, body);
116 }
117
118
119
120
121
122
123 public Simple(final int status) {
124 this(status, "");
125 }
126
127
128
129
130
131
132 public Simple(final int status, final String body) {
133 this(
134 status, new Array<Map.Entry<String, String>>(),
135 body.getBytes(MkAnswer.Simple.CHARSET)
136 );
137 }
138
139
140
141
142
143
144
145 public Simple(final int status,
146 final Iterable<Map.Entry<String, String>> headers,
147 final byte[] body) {
148 this.code = status;
149 this.hdrs = new Array<>(headers);
150 this.content = body.clone();
151 }
152
153 @Override
154 public int status() {
155 return this.code;
156 }
157
158 @Override
159 @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
160 public Map<String, List<String>> headers() {
161 final ConcurrentMap<String, List<String>> map =
162 new ConcurrentHashMap<>(0);
163 for (final Map.Entry<String, String> header : this.hdrs) {
164 map.putIfAbsent(header.getKey(), new LinkedList<String>());
165 map.get(header.getKey()).add(header.getValue());
166 }
167 return map;
168 }
169
170 @Override
171 public String body() {
172 return new String(this.content, MkAnswer.Simple.CHARSET);
173 }
174
175 @Override
176 public byte[] bodyBytes() {
177 return this.content.clone();
178 }
179
180 @Override
181 public String toString() {
182 final StringBuilder text = new StringBuilder(0)
183 .append(this.code).append('\n');
184 for (final Map.Entry<String, String> header : this.hdrs) {
185 text.append(
186 Logger.format(
187 "%s: %s\n",
188 header.getKey(),
189 header.getValue()
190 )
191 );
192 }
193 return text.append('\n')
194 .append(new RequestBody.Printable(this.content))
195 .toString();
196 }
197
198
199
200
201
202
203
204 public MkAnswer.Simple withHeader(final String name,
205 final String value) {
206 return new MkAnswer.Simple(
207 this.code,
208 this.hdrs.with(new ImmutableHeader(name, value)),
209 this.content
210 );
211 }
212
213
214
215
216
217
218 public MkAnswer.Simple withStatus(final int status) {
219 return new MkAnswer.Simple(
220 status,
221 this.hdrs,
222 this.content
223 );
224 }
225
226
227
228
229
230
231 public MkAnswer.Simple withBody(final String body) {
232 return new MkAnswer.Simple(
233 this.code,
234 this.hdrs,
235 body.getBytes(MkAnswer.Simple.CHARSET)
236 );
237 }
238
239
240
241
242
243
244 public MkAnswer.Simple withBody(final byte[] body) {
245 return new MkAnswer.Simple(this.code, this.hdrs, body);
246 }
247 }
248
249 }