1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.waarp.gateway.kernel.rest;
21
22 import com.fasterxml.jackson.core.JsonProcessingException;
23 import com.fasterxml.jackson.databind.node.ObjectNode;
24 import io.netty.buffer.ByteBuf;
25 import io.netty.buffer.Unpooled;
26 import io.netty.channel.ChannelFuture;
27 import io.netty.channel.ChannelHandlerContext;
28 import io.netty.handler.codec.http.HttpHeaderNames;
29 import io.netty.handler.codec.http.HttpResponse;
30 import io.netty.handler.codec.http.HttpResponseStatus;
31 import io.netty.handler.codec.http.multipart.FileUpload;
32 import org.waarp.common.database.DbPreparedStatement;
33 import org.waarp.common.database.data.AbstractDbData;
34 import org.waarp.common.database.data.AbstractDbData.UpdatedInfo;
35 import org.waarp.common.database.exception.WaarpDatabaseException;
36 import org.waarp.common.database.exception.WaarpDatabaseNoConnectionException;
37 import org.waarp.common.database.exception.WaarpDatabaseSqlException;
38 import org.waarp.common.json.JsonHandler;
39 import org.waarp.common.logging.SysErrLogger;
40 import org.waarp.common.logging.WaarpLogger;
41 import org.waarp.common.logging.WaarpLoggerFactory;
42 import org.waarp.common.utility.WaarpStringUtils;
43 import org.waarp.gateway.kernel.exception.HttpForbiddenRequestException;
44 import org.waarp.gateway.kernel.exception.HttpIncorrectRequestException;
45 import org.waarp.gateway.kernel.exception.HttpInvalidAuthenticationException;
46 import org.waarp.gateway.kernel.exception.HttpNotFoundRequestException;
47 import org.waarp.gateway.kernel.rest.HttpRestHandler.METHOD;
48
49 import java.nio.charset.UnsupportedCharsetException;
50
51
52
53
54 public abstract class DataModelRestMethodHandler<E extends AbstractDbData>
55 extends RestMethodHandler {
56
57 public enum COMMAND_TYPE {
58 MULTIGET, GET, UPDATE, CREATE, DELETE, OPTIONS
59 }
60
61
62
63
64 private static final WaarpLogger logger =
65 WaarpLoggerFactory.getLogger(DataModelRestMethodHandler.class);
66
67 protected DataModelRestMethodHandler(final String name,
68 final RestConfiguration config,
69 final METHOD... method) {
70 super(name, name, true, config, METHOD.OPTIONS);
71 setMethods(method);
72 }
73
74 protected abstract void checkAuthorization(HttpRestHandler handler,
75 RestArgument arguments,
76 RestArgument result, METHOD method)
77 throws HttpForbiddenRequestException;
78
79
80
81
82
83 @Override
84 public final void checkHandlerSessionCorrectness(
85 final HttpRestHandler handler, final RestArgument arguments,
86 final RestArgument result) throws HttpForbiddenRequestException {
87 final METHOD method = arguments.getMethod();
88 if (!isMethodIncluded(method)) {
89 logger.warn("NotAllowed: " + method + ':' + arguments.getUri() + ':' +
90 arguments.getUriArgs());
91 throw new HttpForbiddenRequestException("Unallowed Method: " + method);
92 }
93 checkAuthorization(handler, arguments, result, method);
94 final boolean hasOneExtraPathAsId = arguments.getSubUriSize() == 1;
95 final boolean hasNoExtraPath = arguments.getSubUriSize() == 0;
96 if (hasOneExtraPathAsId) {
97 arguments.addIdToUriArgs();
98 }
99 switch (method) {
100 case DELETE:
101 case PUT:
102 if (hasOneExtraPathAsId) {
103 return;
104 }
105 break;
106 case GET:
107 case OPTIONS:
108 return;
109 case POST:
110 if (hasNoExtraPath) {
111 return;
112 }
113 break;
114 default:
115 break;
116 }
117 logger.warn("NotAllowed: " + method + ':' + hasNoExtraPath + ':' +
118 hasOneExtraPathAsId + ':' + arguments.getUri() + ':' +
119 arguments.getUriArgs());
120 throw new HttpForbiddenRequestException(
121 "Unallowed Method and arguments combinaison");
122 }
123
124 @Override
125 public final void getFileUpload(final HttpRestHandler handler,
126 final FileUpload data,
127 final RestArgument arguments,
128 final RestArgument result)
129 throws HttpIncorrectRequestException {
130 throw new HttpIncorrectRequestException("File Upload not allowed");
131 }
132
133 @Override
134 public final Object getBody(final HttpRestHandler handler, final ByteBuf body,
135 final RestArgument arguments,
136 final RestArgument result)
137 throws HttpIncorrectRequestException {
138
139 ObjectNode node = null;
140 try {
141 final String json = body.toString(WaarpStringUtils.UTF8);
142 node = JsonHandler.getFromStringExc(json);
143 } catch (final UnsupportedCharsetException e) {
144 logger.warn("Error" + " : {}", e.getMessage());
145 throw new HttpIncorrectRequestException(e);
146 } catch (final JsonProcessingException e) {
147 result.setDetail("ERROR: JSON body cannot be parsed");
148 }
149 if (node != null) {
150 arguments.getBody().setAll(node);
151 }
152 return node;
153 }
154
155 @Override
156 public final void endParsingRequest(final HttpRestHandler handler,
157 final RestArgument arguments,
158 final RestArgument result,
159 final Object body)
160 throws HttpIncorrectRequestException, HttpInvalidAuthenticationException,
161 HttpNotFoundRequestException {
162 final METHOD method = arguments.getMethod();
163 switch (method) {
164 case DELETE:
165 delete(handler, arguments, result, body);
166 return;
167 case GET:
168 final boolean hasNoExtraPath = arguments.getSubUriSize() == 0;
169 if (hasNoExtraPath) {
170 getAll(handler, arguments, result, body);
171 } else {
172 getOne(handler, arguments, result, body);
173 }
174 return;
175 case OPTIONS:
176 optionsCommand(handler, arguments, result);
177 return;
178 case POST:
179 post(handler, arguments, result, body);
180 return;
181 case PUT:
182 put(handler, arguments, result, body);
183 return;
184 default:
185 break;
186 }
187 throw new HttpIncorrectRequestException("Incorrect request: " + method);
188 }
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207 protected abstract E getItem(HttpRestHandler handler, RestArgument arguments,
208 RestArgument result, Object body)
209 throws HttpIncorrectRequestException, HttpInvalidAuthenticationException,
210 HttpNotFoundRequestException;
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226 protected abstract E createItem(HttpRestHandler handler,
227 RestArgument arguments, RestArgument result,
228 Object body)
229 throws HttpIncorrectRequestException, HttpInvalidAuthenticationException;
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244 protected abstract DbPreparedStatement getPreparedStatement(
245 HttpRestHandler handler, RestArgument arguments, RestArgument result,
246 Object body)
247 throws HttpIncorrectRequestException, HttpInvalidAuthenticationException;
248
249
250
251
252
253
254
255
256
257
258
259 protected abstract E getItemPreparedStatement(DbPreparedStatement statement)
260 throws HttpIncorrectRequestException, HttpNotFoundRequestException;
261
262
263
264
265
266 public abstract String getPrimaryPropertyName();
267
268 protected final void setOk(final HttpRestHandler handler,
269 final RestArgument result) {
270 handler.setStatus(HttpResponseStatus.OK);
271 result.setResult(HttpResponseStatus.OK);
272 }
273
274
275
276
277
278
279
280
281
282
283
284
285
286 protected final void getAll(final HttpRestHandler handler,
287 final RestArgument arguments,
288 final RestArgument result, final Object body)
289 throws HttpIncorrectRequestException, HttpInvalidAuthenticationException,
290 HttpNotFoundRequestException {
291 final long limit = arguments.getLimitFromUri();
292 final DbPreparedStatement statement =
293 getPreparedStatement(handler, arguments, result, body);
294 try {
295 result.addFilter((ObjectNode) body);
296 int count = 0;
297 try {
298 statement.executeQuery();
299 } catch (final WaarpDatabaseNoConnectionException e) {
300 throw new HttpIncorrectRequestException(e);
301 } catch (final WaarpDatabaseSqlException e) {
302 throw new HttpNotFoundRequestException(e);
303 }
304 try {
305 for (; count < limit && statement.getNext(); count++) {
306 final E item = getItemPreparedStatement(statement);
307 if (item != null) {
308 result.addResult(item.getJson());
309 }
310 }
311 } catch (final WaarpDatabaseNoConnectionException e) {
312 throw new HttpIncorrectRequestException(e);
313 } catch (final WaarpDatabaseSqlException e) {
314 throw new HttpNotFoundRequestException(e);
315 }
316 result.addCountLimit(count, limit);
317 result.setCommand(COMMAND_TYPE.MULTIGET);
318 setOk(handler, result);
319 } finally {
320 statement.realClose();
321 }
322 }
323
324
325
326
327
328
329
330
331
332
333
334
335
336 protected final void getOne(final HttpRestHandler handler,
337 final RestArgument arguments,
338 final RestArgument result, final Object body)
339 throws HttpIncorrectRequestException, HttpInvalidAuthenticationException,
340 HttpNotFoundRequestException {
341 final E item = getItem(handler, arguments, result, body);
342 result.addAnswer(item.getJson());
343 result.setCommand(COMMAND_TYPE.GET);
344 setOk(handler, result);
345 }
346
347
348
349
350
351
352
353
354
355
356
357
358
359 protected void put(final HttpRestHandler handler,
360 final RestArgument arguments, final RestArgument result,
361 final Object body)
362 throws HttpIncorrectRequestException, HttpInvalidAuthenticationException,
363 HttpNotFoundRequestException {
364 final E item = getItem(handler, arguments, result, body);
365 try {
366 item.setFromJson(arguments.getBody(), true);
367 } catch (final WaarpDatabaseSqlException e) {
368 throw new HttpIncorrectRequestException(
369 "Issue while using Json formatting", e);
370 }
371 item.changeUpdatedInfo(UpdatedInfo.TOSUBMIT);
372 try {
373 item.update();
374 } catch (final WaarpDatabaseException e) {
375 throw new HttpIncorrectRequestException(
376 "Issue while updating to database", e);
377 }
378 result.addAnswer(item.getJson());
379 result.setCommand(COMMAND_TYPE.UPDATE);
380 setOk(handler, result);
381 }
382
383
384
385
386
387
388
389
390
391
392
393
394 protected final void post(final HttpRestHandler handler,
395 final RestArgument arguments,
396 final RestArgument result, final Object body)
397 throws HttpIncorrectRequestException, HttpInvalidAuthenticationException {
398 final E item = createItem(handler, arguments, result, body);
399 item.changeUpdatedInfo(UpdatedInfo.TOSUBMIT);
400 try {
401 item.insert();
402 } catch (final WaarpDatabaseException e) {
403
404 try {
405 item.update();
406 } catch (final WaarpDatabaseException ex) {
407 throw new HttpIncorrectRequestException(
408 "Issue while inserting to database", e);
409 }
410 }
411 if (logger.isDebugEnabled()) {
412 logger.debug("Save {}", item.getJson());
413 }
414 result.addAnswer(item.getJson());
415 result.setCommand(COMMAND_TYPE.CREATE);
416 setOk(handler, result);
417 }
418
419
420
421
422
423
424
425
426
427
428
429
430
431 protected final void delete(final HttpRestHandler handler,
432 final RestArgument arguments,
433 final RestArgument result, final Object body)
434 throws HttpIncorrectRequestException, HttpInvalidAuthenticationException,
435 HttpNotFoundRequestException {
436 final E item = getItem(handler, arguments, result, body);
437 try {
438 item.delete();
439 } catch (final WaarpDatabaseException e) {
440 throw new HttpIncorrectRequestException(
441 "Issue while deleting from database", e);
442 }
443 result.addAnswer(item.getJson());
444 result.setCommand(COMMAND_TYPE.DELETE);
445 setOk(handler, result);
446 }
447
448 @Override
449 public final ChannelFuture sendResponse(final HttpRestHandler handler,
450 final ChannelHandlerContext ctx,
451 final RestArgument arguments,
452 final RestArgument result,
453 final Object body,
454 final HttpResponseStatus status) {
455 final String answer = result.toString();
456 final ByteBuf buffer =
457 Unpooled.wrappedBuffer(answer.getBytes(WaarpStringUtils.UTF8));
458 final HttpResponse response = handler.getResponse(buffer);
459 if (status == HttpResponseStatus.UNAUTHORIZED) {
460 return ctx.writeAndFlush(response);
461 }
462 response.headers().add(HttpHeaderNames.CONTENT_TYPE, "application/json");
463 response.headers().add(HttpHeaderNames.REFERER, handler.getRequest().uri());
464 logger.debug("Will write: {}", body);
465 final ChannelFuture future = ctx.writeAndFlush(response);
466 if (handler.isWillClose()) {
467 SysErrLogger.FAKE_LOGGER.syserr(
468 "Will close session in DataModelRestMethodHandler");
469 return future;
470 }
471 return null;
472 }
473 }