1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.opencastproject.index.service.util;
23
24 import static com.entwinemedia.fn.data.json.Jsons.arr;
25 import static com.entwinemedia.fn.data.json.Jsons.f;
26 import static com.entwinemedia.fn.data.json.Jsons.obj;
27 import static com.entwinemedia.fn.data.json.Jsons.v;
28 import static java.lang.String.format;
29
30 import org.opencastproject.util.DateTimeSupport;
31 import org.opencastproject.util.data.Tuple;
32 import org.opencastproject.util.requests.SortCriterion;
33
34 import com.entwinemedia.fn.Fx;
35 import com.entwinemedia.fn.data.json.Field;
36 import com.entwinemedia.fn.data.json.JValue;
37 import com.entwinemedia.fn.data.json.SimpleSerializer;
38
39 import org.apache.commons.lang3.StringUtils;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
42
43 import java.io.BufferedOutputStream;
44 import java.io.IOException;
45 import java.io.OutputStream;
46 import java.net.URLDecoder;
47 import java.nio.charset.StandardCharsets;
48 import java.util.ArrayList;
49 import java.util.Date;
50 import java.util.HashMap;
51 import java.util.List;
52 import java.util.Map;
53 import java.util.Optional;
54 import java.util.StringTokenizer;
55
56 import javax.ws.rs.WebApplicationException;
57 import javax.ws.rs.core.MediaType;
58 import javax.ws.rs.core.Response;
59 import javax.ws.rs.core.Response.Status;
60 import javax.ws.rs.core.StreamingOutput;
61
62
63
64
65 public final class RestUtils {
66 private static final Logger logger = LoggerFactory.getLogger(RestUtils.class);
67
68 private static final SimpleSerializer serializer = new SimpleSerializer();
69
70 private RestUtils() {
71 }
72
73
74
75
76
77
78
79
80 public static Response okJson(JValue json) {
81 return Response.ok(stream(serializer.fn.toJson(json)), MediaType.APPLICATION_JSON_TYPE).build();
82 }
83
84
85
86
87
88
89
90
91 public static Response conflictJson(JValue json) {
92 return Response.status(Status.CONFLICT).entity(stream(serializer.fn.toJson(json)))
93 .type(MediaType.APPLICATION_JSON_TYPE).build();
94 }
95
96
97
98
99
100
101
102
103 public static Response notFound(String msg, Object... args) {
104 return Response.status(Status.NOT_FOUND).entity(format(msg, args)).type(MediaType.TEXT_PLAIN_TYPE).build();
105 }
106
107
108
109
110
111
112
113
114 public static Response notFoundJson(JValue json) {
115 return Response.status(Status.NOT_FOUND).entity(stream(serializer.fn.toJson(json)))
116 .type(MediaType.APPLICATION_JSON_TYPE).build();
117 }
118
119
120
121
122
123
124
125
126 public static Response serverErrorJson(JValue json) {
127 return Response.status(Status.INTERNAL_SERVER_ERROR).entity(stream(serializer.fn.toJson(json)))
128 .type(MediaType.APPLICATION_JSON_TYPE).build();
129 }
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 public static Response okJsonList(List<JValue> jsonList, int offset, int limit, long total) {
149 return okJsonList(jsonList, Optional.of(offset), Optional.of(limit), total);
150 }
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182 public static Response okJsonList(List<JValue> jsonList, Optional<Integer> optOffset, Optional<Integer> optLimit,
183 long total) {
184 if (jsonList == null)
185 throw new IllegalArgumentException("The list of value must not be null.");
186
187 ArrayList<Field> fields = new ArrayList<>();
188 fields.add(f("results", arr(jsonList)));
189 fields.add(f("count", v(jsonList.size())));
190 fields.add(f("total", v(total)));
191
192 if (optOffset.isPresent()) {
193 fields.add(f("offset", v(optOffset.get())));
194 }
195 if (optLimit.isPresent()) {
196 fields.add(f("limit", v(optLimit.get())));
197 }
198
199 return okJson(obj(fields));
200 }
201
202
203
204
205
206 public static StreamingOutput stream(final Fx<OutputStream> out) {
207 return s -> {
208 try (BufferedOutputStream bs = new BufferedOutputStream(s)) {
209 out.apply(bs);
210 }
211 };
212 }
213
214
215
216
217
218
219
220
221
222 public static ArrayList<SortCriterion> parseSortQueryParameter(String sort) throws WebApplicationException {
223 ArrayList<SortCriterion> sortOrders = new ArrayList<>();
224
225 if (StringUtils.isNotBlank(sort)) {
226 StringTokenizer tokenizer = new StringTokenizer(sort, ",");
227 while (tokenizer.hasMoreTokens()) {
228 try {
229 sortOrders.add(SortCriterion.parse(tokenizer.nextToken()));
230 } catch (IllegalArgumentException e) {
231 throw new WebApplicationException(Status.BAD_REQUEST);
232 }
233 }
234 }
235
236 return sortOrders;
237 }
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252 public static Tuple<Date, Date> getFromAndToDateRange(String fromToDateRange) {
253 String[] dates = fromToDateRange.split("/");
254 if (dates.length != 2) {
255 logger.warn("The date range '{}' is malformed", fromToDateRange);
256 throw new IllegalArgumentException("The date range string is malformed");
257 }
258
259 Date fromDate = null;
260 try {
261 fromDate = new Date(DateTimeSupport.fromUTC(dates[0]));
262 } catch (Exception e) {
263 logger.warn("Unable to parse from date parameter '{}'", dates[0]);
264 throw new IllegalArgumentException("Unable to parse from date parameter");
265 }
266
267 Date toDate = null;
268 try {
269 toDate = new Date(DateTimeSupport.fromUTC(dates[1]));
270 } catch (Exception e) {
271 logger.warn("Unable to parse to date parameter '{}'", dates[1]);
272 throw new IllegalArgumentException("Unable to parse to date parameter");
273 }
274
275 return new Tuple<Date, Date>(fromDate, toDate);
276 }
277
278
279
280
281
282
283
284
285 public static Map<String, String> parseFilter(String filter) {
286 Map<String, String> filters = new HashMap<>();
287 if (StringUtils.isNotBlank(filter)) {
288 for (String f : filter.split(",")) {
289 String[] filterTuple = f.split(":");
290 if (filterTuple.length < 2) {
291 logger.debug("No value for filter '{}' in filters list: {}", filterTuple[0], filter);
292 continue;
293 }
294
295 filters.put(filterTuple[0].trim(), URLDecoder.decode(f.substring(filterTuple[0].length() + 1).trim(),
296 StandardCharsets.UTF_8));
297 }
298 }
299 return filters;
300 }
301
302 public static String getJsonString(JValue json) throws WebApplicationException, IOException {
303 OutputStream output = new OutputStream() {
304 private StringBuilder string = new StringBuilder();
305
306 @Override
307 public void write(int b) throws IOException {
308 this.string.append((char) b);
309 }
310
311 @Override
312 public String toString() {
313 return this.string.toString();
314 }
315 };
316
317 stream(serializer.fn.toJson(json)).write(output);
318
319 return output.toString();
320 }
321
322
323
324
325
326
327
328
329 public static String getJsonStringSilent(JValue json) {
330 try {
331 return getJsonString(json);
332 } catch (Exception e) {
333 return "";
334 }
335 }
336 }