comparison UnitTestsSources/RestApiTests.cpp @ 968:8ed284e79850

RestApiHierarchy
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 27 Jun 2014 17:48:55 +0200
parents dfc076546821
children 3dce528b0cc2
comparison
equal deleted inserted replaced
967:dfc076546821 968:8ed284e79850
192 192
193 193
194 194
195 namespace Orthanc 195 namespace Orthanc
196 { 196 {
197 class RestApiResource 197 class RestApiHierarchy
198 { 198 {
199 private: 199 private:
200 struct Handlers 200 struct Handlers
201 { 201 {
202 std::list<RestApi::GetHandler> getHandlers_; 202 typedef std::list<RestApi::GetHandler> GetHandlers;
203 std::list<RestApi::PutHandler> putHandlers_; 203 typedef std::list<RestApi::PostHandler> PostHandlers;
204 std::list<RestApi::PostHandler> postHandlers_; 204 typedef std::list<RestApi::PutHandler> PutHandlers;
205 std::list<RestApi::DeleteHandler> deleteHandlers_; 205 typedef std::list<RestApi::DeleteHandler> DeleteHandlers;
206
207 GetHandlers getHandlers_;
208 PostHandlers postHandlers_;
209 PutHandlers putHandlers_;
210 DeleteHandlers deleteHandlers_;
211
212 bool HasGet() const
213 {
214 return getHandlers_.size() > 0;
215 }
206 216
207 void Register(RestApi::GetHandler handler) 217 void Register(RestApi::GetHandler handler)
208 { 218 {
209 getHandlers_.push_back(handler); 219 getHandlers_.push_back(handler);
210 } 220 }
221 231
222 void Register(RestApi::DeleteHandler handler) 232 void Register(RestApi::DeleteHandler handler)
223 { 233 {
224 deleteHandlers_.push_back(handler); 234 deleteHandlers_.push_back(handler);
225 } 235 }
236
237 bool IsEmpty() const
238 {
239 return (getHandlers_.empty() &&
240 postHandlers_.empty() &&
241 putHandlers_.empty() &&
242 deleteHandlers_.empty());
243 }
226 }; 244 };
227 245
228 246
229 typedef std::map<std::string, RestApiResource*> Children; 247 typedef std::map<std::string, RestApiHierarchy*> Children;
230 248 typedef bool (*ResourceCallback) (Handlers&,
249 const UriComponents& uri,
250 const RestApiPath::Components& components,
251 const UriComponents& trailing,
252 void* call);
253
254 Handlers handlers_;
231 Children children_; 255 Children children_;
232 Children wildcardChildren_; 256 Children wildcardChildren_;
233 Handlers handlers_;
234 Handlers universalHandlers_; 257 Handlers universalHandlers_;
235 258
236 259
237 static RestApiResource& AddChild(Children& children, 260 static RestApiHierarchy& AddChild(Children& children,
238 const std::string& name) 261 const std::string& name)
239 { 262 {
240 Children::iterator it = children.find(name); 263 Children::iterator it = children.find(name);
241 264
242 if (it == children.end()) 265 if (it == children.end())
243 { 266 {
244 // Create new child 267 // Create new child
245 RestApiResource *child = new RestApiResource; 268 RestApiHierarchy *child = new RestApiHierarchy;
246 children[name] = child; 269 children[name] = child;
247 return *child; 270 return *child;
248 } 271 }
249 else 272 else
250 { 273 {
259 it != children.end(); it++) 282 it != children.end(); it++)
260 { 283 {
261 delete it->second; 284 delete it->second;
262 } 285 }
263 } 286 }
264
265
266 287
267 288
268 template <typename Handler> 289 template <typename Handler>
269 void RegisterInternal(const RestApiPath& path, 290 void RegisterInternal(const RestApiPath& path,
270 Handler handler, 291 Handler handler,
279 else 300 else
280 { 301 {
281 handlers_.Register(handler); 302 handlers_.Register(handler);
282 } 303 }
283 } 304 }
284 else if (path.IsWildcardLevel(level)) 305 else
285 { 306 {
286 AddChild(wildcardChildren_, path.GetWildcardName(level)); 307 RestApiHierarchy* child;
287 } 308 if (path.IsWildcardLevel(level))
309 {
310 child = &AddChild(wildcardChildren_, path.GetWildcardName(level));
311 }
312 else
313 {
314 child = &AddChild(children_, path.GetLevelName(level));
315 }
316
317 child->RegisterInternal(path, handler, level + 1);
318 }
319 }
320
321
322 bool LookupHandler(RestApiPath::Components& components,
323 const UriComponents& uri,
324 ResourceCallback callback,
325 size_t level,
326 void* call)
327 {
328 assert(uri.size() >= level);
329 UriComponents trailing;
330
331 // Look for an exact match on the resource of interest
332 if (uri.size() == level)
333 {
334 if (!handlers_.IsEmpty() &&
335 callback(handlers_, uri, components, trailing, call))
336 {
337 return true;
338 }
339 }
340
341
342 // Try and go down in the hierarchy, using an exact match for the child
343 Children::const_iterator child = children_.find(uri[level]);
344 if (child != children_.end())
345 {
346 if (child->second->LookupHandler(components, uri, callback, level + 1, call))
347 {
348 return true;
349 }
350 }
351
352
353 // Try and go down in the hierarchy, using wildcard rules for children
354 for (child = wildcardChildren_.begin();
355 child != wildcardChildren_.end(); child++)
356 {
357 RestApiPath::Components subComponents = components;
358 subComponents[child->first] = uri[level];
359
360 if (child->second->LookupHandler(components, uri, callback, level + 1, call))
361 {
362 return true;
363 }
364 }
365
366
367 // As a last resort, call the universal handlers, if any
368 if (!universalHandlers_.IsEmpty())
369 {
370 trailing.resize(uri.size() - level);
371 size_t pos = 0;
372 for (size_t i = level; i < uri.size(); i++, pos++)
373 {
374 trailing[pos] = uri[i];
375 }
376
377 assert(pos == trailing.size());
378
379 if (callback(universalHandlers_, uri, components, trailing, call))
380 {
381 return true;
382 }
383 }
384
385 return false;
386 }
387
388
389 bool GetDirectory(Json::Value& result,
390 const UriComponents& uri,
391 size_t level)
392 {
393 if (uri.size() == level)
394 {
395 if (!handlers_.HasGet() &&
396 universalHandlers_.IsEmpty() &&
397 wildcardChildren_.size() == 0)
398 {
399 result = Json::arrayValue;
400
401 for (Children::const_iterator it = children_.begin();
402 it != children_.end(); it++)
403 {
404 result.append(it->first);
405 }
406
407 return true;
408 }
409 else
410 {
411 return false;
412 }
413 }
414
415 Children::const_iterator child = children_.find(uri[level]);
416 if (child != children_.end())
417 {
418 if (child->second->GetDirectory(result, uri, level + 1))
419 {
420 return true;
421 }
422 }
423
424 for (child = wildcardChildren_.begin();
425 child != wildcardChildren_.end(); child++)
426 {
427 if (child->second->GetDirectory(result, uri, level + 1))
428 {
429 return true;
430 }
431 }
432
433 return false;
434 }
435
436
437 static bool GetCallback(Handlers& handlers,
438 const UriComponents& uri,
439 const RestApiPath::Components& components,
440 const UriComponents& trailing,
441 void* call)
442 {
443 for (Handlers::GetHandlers::iterator
444 it = handlers.getHandlers_.begin();
445 it != handlers.getHandlers_.end(); it++)
446 {
447 // TODO RETURN BOOL
448
449 (*it) (*reinterpret_cast<RestApi::GetCall*>(call));
450 return true;
451 }
452
453 return false;
454 }
455
456
457 static bool PostCallback(Handlers& handlers,
458 const UriComponents& uri,
459 const RestApiPath::Components& components,
460 const UriComponents& trailing,
461 void* call)
462 {
463 for (Handlers::PostHandlers::iterator
464 it = handlers.postHandlers_.begin();
465 it != handlers.postHandlers_.end(); it++)
466 {
467 // TODO RETURN BOOL
468
469 (*it) (*reinterpret_cast<RestApi::PostCall*>(call));
470 return true;
471 }
472
473 return false;
474 }
475
476
477 static bool PutCallback(Handlers& handlers,
478 const UriComponents& uri,
479 const RestApiPath::Components& components,
480 const UriComponents& trailing,
481 void* call)
482 {
483 for (Handlers::PutHandlers::iterator
484 it = handlers.putHandlers_.begin();
485 it != handlers.putHandlers_.end(); it++)
486 {
487 // TODO RETURN BOOL
488
489 (*it) (*reinterpret_cast<RestApi::PutCall*>(call));
490 return true;
491 }
492
493 return false;
494 }
495
496
497 static bool DeleteCallback(Handlers& handlers,
498 const UriComponents& uri,
499 const RestApiPath::Components& components,
500 const UriComponents& trailing,
501 void* call)
502 {
503 for (Handlers::DeleteHandlers::iterator
504 it = handlers.deleteHandlers_.begin();
505 it != handlers.deleteHandlers_.end(); it++)
506 {
507 // TODO RETURN BOOL
508
509 (*it) (*reinterpret_cast<RestApi::DeleteCall*>(call));
510 return true;
511 }
512
513 return false;
288 } 514 }
289 515
290 516
291 public: 517 public:
292 ~RestApiResource() 518 ~RestApiHierarchy()
293 { 519 {
294 DeleteChildren(children_); 520 DeleteChildren(children_);
295 DeleteChildren(wildcardChildren_); 521 DeleteChildren(wildcardChildren_);
296 } 522 }
297 523
298 void Register(const RestApiPath& path, 524 void Register(const RestApiPath& path,
299 RestApi::GetHandler handler) 525 RestApi::GetHandler handler)
300 { 526 {
301 RegisterInternal(path, handler, 0); 527 RegisterInternal(path, handler, 0);
302 } 528 }
529
530 void Register(const RestApiPath& path,
531 RestApi::PutHandler handler)
532 {
533 RegisterInternal(path, handler, 0);
534 }
535
536 void Register(const RestApiPath& path,
537 RestApi::PostHandler handler)
538 {
539 RegisterInternal(path, handler, 0);
540 }
541
542 void Register(const RestApiPath& path,
543 RestApi::DeleteHandler handler)
544 {
545 RegisterInternal(path, handler, 0);
546 }
547
548 void CreateSiteMap(Json::Value& target) const
549 {
550 if (children_.size() == 0)
551 {
552 std::string s = " ";
553 if (handlers_.getHandlers_.size() != 0)
554 {
555 s += "GET ";
556 }
557
558 if (handlers_.postHandlers_.size() != 0)
559 {
560 s += "POST ";
561 }
562
563 if (handlers_.putHandlers_.size() != 0)
564 {
565 s += "PUT ";
566 }
567
568 if (handlers_.deleteHandlers_.size() != 0)
569 {
570 s += "DELETE ";
571 }
572
573 target = s;
574 }
575 else
576 {
577 target = Json::objectValue;
578
579 for (Children::const_iterator it = children_.begin();
580 it != children_.end(); it++)
581 {
582 it->second->CreateSiteMap(target[it->first]);
583 }
584 }
585
586 /*for (Children::const_iterator it = wildcardChildren_.begin();
587 it != wildcardChildren_.end(); it++)
588 {
589 it->second->CreateSiteMap(target["* (" + it->first + ")"]);
590 }*/
591 }
592
593 bool GetDirectory(Json::Value& result,
594 const UriComponents& uri)
595 {
596 return GetDirectory(result, uri, 0);
597 }
598
599 bool GetDirectory(Json::Value& result,
600 const std::string& uri)
601 {
602 UriComponents c;
603 Toolbox::SplitUriComponents(c, uri);
604 return GetDirectory(result, c, 0);
605 }
606
607 bool Handle(RestApi::GetCall& call,
608 const UriComponents& uri)
609 {
610 RestApiPath::Components components;
611 return LookupHandler(components, uri, GetCallback, 0, &call);
612 }
613
614 bool Handle(RestApi::PutCall& call,
615 const UriComponents& uri)
616 {
617 RestApiPath::Components components;
618 return LookupHandler(components, uri, PutCallback, 0, &call);
619 }
620
621 bool Handle(RestApi::PostCall& call,
622 const UriComponents& uri)
623 {
624 RestApiPath::Components components;
625 return LookupHandler(components, uri, PostCallback, 0, &call);
626 }
627
628 bool Handle(RestApi::DeleteCall& call,
629 const UriComponents& uri)
630 {
631 RestApiPath::Components components;
632 return LookupHandler(components, uri, DeleteCallback, 0, &call);
633 }
634
635 bool Handle(RestApi::GetCall& call,
636 const std::string& uri)
637 {
638 UriComponents c;
639 Toolbox::SplitUriComponents(c, uri);
640 return Handle(call, c);
641 }
303 }; 642 };
304 643
305 } 644 }
306 645
307 646
308 647
309 static void Toto(RestApi::GetCall& get) 648
649 static int testValue;
650
651 template <int value>
652 static void SetValue(RestApi::GetCall& get)
310 { 653 {
654 testValue = value;
311 } 655 }
312 656
313 657
314 TEST(RestApi, RestApiResource) 658 TEST(RestApi, RestApiHierarchy)
315 { 659 {
316 RestApiResource root; 660 RestApiHierarchy root;
317 661 root.Register(RestApiPath("/hello/world/test"), SetValue<1>);
318 root.Register(RestApiPath("/hello/world/test"), Toto); 662 root.Register(RestApiPath("/hello/world/test2"), SetValue<2>);
663 root.Register(RestApiPath("/hello/{world}/test3/test4"), SetValue<3>);
664 root.Register(RestApiPath("/hello2/*"), SetValue<4>);
665
666 Json::Value m;
667 root.CreateSiteMap(m);
668 std::cout << m;
669
670 Json::Value d;
671 ASSERT_FALSE(root.GetDirectory(d, "/hello"));
672
673 ASSERT_TRUE(root.GetDirectory(d, "/hello/a"));
674 ASSERT_EQ(1u, d.size());
675 ASSERT_EQ("test3", d[0].asString());
676
677 ASSERT_TRUE(root.GetDirectory(d, "/hello/world"));
678 ASSERT_EQ(2u, d.size());
679
680 ASSERT_TRUE(root.GetDirectory(d, "/hello/a/test3"));
681 ASSERT_EQ(1u, d.size());
682 ASSERT_EQ("test4", d[0].asString());
683
684 ASSERT_FALSE(root.GetDirectory(d, "/hello/world/test"));
685 ASSERT_FALSE(root.GetDirectory(d, "/hello/world/test2"));
686 ASSERT_FALSE(root.GetDirectory(d, "/hello2"));
687
688 testValue = 0;
689 ASSERT_TRUE(root.Handle(*reinterpret_cast<RestApi::GetCall*>(NULL), "/hello/world/test"));
690 ASSERT_EQ(testValue, 1);
691 ASSERT_TRUE(root.Handle(*reinterpret_cast<RestApi::GetCall*>(NULL), "/hello/world/test2"));
692 ASSERT_EQ(testValue, 2);
693 ASSERT_TRUE(root.Handle(*reinterpret_cast<RestApi::GetCall*>(NULL), "/hello/b/test3/test4"));
694 ASSERT_EQ(testValue, 3);
695 ASSERT_FALSE(root.Handle(*reinterpret_cast<RestApi::GetCall*>(NULL), "/hello/b/test3/test"));
696 ASSERT_EQ(testValue, 3);
697 ASSERT_TRUE(root.Handle(*reinterpret_cast<RestApi::GetCall*>(NULL), "/hello2/a/b"));
698 ASSERT_EQ(testValue, 4);
319 } 699 }