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