changeset 980:f1ff2a2f06cd plugins

use RestApiHierarchy inside RestApi
author Sebastien Jodogne <s.jodogne@gmail.com>
date Mon, 30 Jun 2014 17:41:40 +0200
parents 624f44047238
children 5983e59ac670
files Core/RestApi/RestApi.cpp Core/RestApi/RestApi.h Core/RestApi/RestApiHierarchy.cpp
diffstat 3 files changed, 152 insertions(+), 219 deletions(-) [+]
line wrap: on
line diff
--- a/Core/RestApi/RestApi.cpp	Mon Jun 30 16:10:13 2014 +0200
+++ b/Core/RestApi/RestApi.cpp	Mon Jun 30 17:41:40 2014 +0200
@@ -36,63 +36,89 @@
 #include <stdlib.h>   // To define "_exit()" under Windows
 #include <glog/logging.h>
 
+#include <stdio.h>
+
 namespace Orthanc
 {
-  bool RestApi::IsGetAccepted(const UriComponents& uri)
+  namespace
   {
-    for (GetHandlers::const_iterator it = getHandlers_.begin();
-         it != getHandlers_.end(); ++it)
+    // Anonymous namespace to avoid clashes between compilation modules
+    class HttpHandlerVisitor : public RestApiHierarchy::IVisitor
     {
-      if (it->first->Match(uri))
+    private:
+      RestApi& api_;
+      HttpOutput& output_;
+      HttpMethod method_;
+      const HttpHandler::Arguments& headers_;
+      const HttpHandler::Arguments& getArguments_;
+      const std::string& postData_;
+
+    public:
+      HttpHandlerVisitor(RestApi& api,
+                         HttpOutput& output,
+                         HttpMethod method,
+                         const HttpHandler::Arguments& headers,
+                         const HttpHandler::Arguments& getArguments,
+                         const std::string& postData) :
+        api_(api),
+        output_(output),
+        method_(method),
+        headers_(headers),
+        getArguments_(getArguments),
+        postData_(postData)
       {
-        return true;
       }
-    }
+
+      virtual bool Visit(const RestApiHierarchy::Resource& resource,
+                         const UriComponents& uri,
+                         const HttpHandler::Arguments& components,
+                         const UriComponents& trailing)
+      {
+        if (resource.HasHandler(method_))
+        {
+          RestApiOutput output(output_);
+
+          switch (method_)
+          {
+            case HttpMethod_Get:
+            {
+              RestApiGetCall call(output, api_, headers_, components, trailing, uri, getArguments_);
+              resource.Handle(call);
+              return true;
+            }
 
-    return false;
+            case HttpMethod_Post:
+            {
+              RestApiPostCall call(output, api_, headers_, components, trailing, uri, postData_);
+              resource.Handle(call);
+              return true;
+            }
+
+            case HttpMethod_Delete:
+            {
+              RestApiDeleteCall call(output, api_, headers_, components, trailing, uri);
+              resource.Handle(call);
+              return true;
+            }
+
+            case HttpMethod_Put:
+            {
+              RestApiPutCall call(output, api_, headers_, components, trailing, uri, postData_);
+              resource.Handle(call);
+              return true;
+            }
+
+            default:
+              return false;
+          }
+        }
+
+        return false;
+      }
+    };
   }
 
-  bool RestApi::IsPutAccepted(const UriComponents& uri)
-  {
-    for (PutHandlers::const_iterator it = putHandlers_.begin();
-         it != putHandlers_.end(); ++it)
-    {
-      if (it->first->Match(uri))
-      {
-        return true;
-      }
-    }
 
-    return false;
-  }
-
-  bool RestApi::IsPostAccepted(const UriComponents& uri)
-  {
-    for (PostHandlers::const_iterator it = postHandlers_.begin();
-         it != postHandlers_.end(); ++it)
-    {
-      if (it->first->Match(uri))
-      {
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-  bool RestApi::IsDeleteAccepted(const UriComponents& uri)
-  {
-    for (DeleteHandlers::const_iterator it = deleteHandlers_.begin();
-         it != deleteHandlers_.end(); ++it)
-    {
-      if (it->first->Match(uri))
-      {
-        return true;
-      }
-    }
-
-    return false;
-  }
 
   static void AddMethod(std::string& target,
                         const std::string& method)
@@ -103,51 +129,33 @@
       target = method;
   }
 
-  std::string  RestApi::GetAcceptedMethods(const UriComponents& uri)
+  static std::string  MethodsToString(const std::set<HttpMethod>& methods)
   {
     std::string s;
 
-    if (IsGetAccepted(uri))
+    if (methods.find(HttpMethod_Get) != methods.end())
+    {
       AddMethod(s, "GET");
+    }
 
-    if (IsPutAccepted(uri))
-      AddMethod(s, "PUT");
+    if (methods.find(HttpMethod_Post) != methods.end())
+    {
+      AddMethod(s, "POST");
+    }
 
-    if (IsPostAccepted(uri))
-      AddMethod(s, "POST");
+    if (methods.find(HttpMethod_Put) != methods.end())
+    {
+      AddMethod(s, "PUT");
+    }
 
-    if (IsDeleteAccepted(uri))
+    if (methods.find(HttpMethod_Delete) != methods.end())
+    {
       AddMethod(s, "DELETE");
+    }
 
     return s;
   }
 
-  RestApi::~RestApi()
-  {
-    for (GetHandlers::iterator it = getHandlers_.begin(); 
-         it != getHandlers_.end(); ++it)
-    {
-      delete it->first;
-    } 
-
-    for (PutHandlers::iterator it = putHandlers_.begin(); 
-         it != putHandlers_.end(); ++it)
-    {
-      delete it->first;
-    } 
-
-    for (PostHandlers::iterator it = postHandlers_.begin(); 
-         it != postHandlers_.end(); ++it)
-    {
-      delete it->first;
-    } 
-
-    for (DeleteHandlers::iterator it = deleteHandlers_.begin(); 
-         it != deleteHandlers_.end(); ++it)
-    {
-      delete it->first;
-    } 
-  }
 
 
   bool RestApi::Handle(HttpOutput& output,
@@ -157,113 +165,60 @@
                        const Arguments& getArguments,
                        const std::string& postData)
   {
-    if (!IsGetAccepted(uri) &&
-        !IsPutAccepted(uri) &&
-        !IsPostAccepted(uri) &&
-        !IsDeleteAccepted(uri))
+    HttpHandlerVisitor visitor(*this, output, method, headers, getArguments, postData);
+
+    if (root_.LookupResource(uri, visitor))
     {
-      // This URI is not served by this handler
-      return false;
+      return true;
     }
 
-
-    bool ok = false;
-    RestApiOutput restOutput(output);
-    HttpHandler::Arguments components;
-    UriComponents trailing;
-
-    if (method == HttpMethod_Get)
-    {
-      for (GetHandlers::const_iterator it = getHandlers_.begin();
-           it != getHandlers_.end(); ++it)
-      {
-        if (it->first->Match(components, trailing, uri))
-        {
-          //LOG(INFO) << "REST GET call on: " << Toolbox::FlattenUri(uri);
-          ok = true;
-          RestApiGetCall call(restOutput, *this, headers, components, trailing, uri, getArguments);
-          it->second(call);
-        }
-      }
-    }
-    else if (method == HttpMethod_Put)
+    Json::Value directory;
+    if (root_.GetDirectory(directory, uri))
     {
-      for (PutHandlers::const_iterator it = putHandlers_.begin();
-           it != putHandlers_.end(); ++it)
-      {
-        if (it->first->Match(components, trailing, uri))
-        {
-          //LOG(INFO) << "REST PUT call on: " << Toolbox::FlattenUri(uri);
-          ok = true;
-          RestApiPutCall call(restOutput, *this, headers, components, trailing, uri, postData);
-          it->second(call);
-        }
-      }
-    }
-    else if (method == HttpMethod_Post)
-    {
-      for (PostHandlers::const_iterator it = postHandlers_.begin();
-           it != postHandlers_.end(); ++it)
-      {
-        if (it->first->Match(components, trailing, uri))
-        {
-          //LOG(INFO) << "REST POST call on: " << Toolbox::FlattenUri(uri);
-          ok = true;
-          RestApiPostCall call(restOutput, *this, headers, components, trailing, uri, postData);
-          it->second(call);
-        }
-      }
-    }
-    else if (method == HttpMethod_Delete)
-    {
-      for (DeleteHandlers::const_iterator it = deleteHandlers_.begin();
-           it != deleteHandlers_.end(); ++it)
-      {
-        if (it->first->Match(components, trailing, uri))
-        {
-          //LOG(INFO) << "REST DELETE call on: " << Toolbox::FlattenUri(uri);
-          ok = true;
-          RestApiDeleteCall call(restOutput, *this, headers, components, trailing, uri);
-          it->second(call);
-        }
-      }
+      RestApiOutput tmp(output);
+      tmp.AnswerJson(directory);
+      return true;
     }
 
-    if (!ok)
+    std::set<HttpMethod> methods;
+    root_.GetAcceptedMethods(methods, uri);
+
+    if (methods.empty())
+    {
+      return false;  // This URI is not served by this REST API
+    }
+    else
     {
       LOG(INFO) << "REST method " << EnumerationToString(method) 
                 << " not allowed on: " << Toolbox::FlattenUri(uri);
-      output.SendMethodNotAllowedError(GetAcceptedMethods(uri));
+
+      output.SendMethodNotAllowedError(MethodsToString(methods));
+
+      return true;
     }
-
-    return true;
   }
 
   void RestApi::Register(const std::string& path,
                          RestApiGetCall::Handler handler)
   {
     root_.Register(path, handler);
-    getHandlers_.push_back(std::make_pair(new RestApiPath(path), handler));
   }
 
   void RestApi::Register(const std::string& path,
                          RestApiPutCall::Handler handler)
   {
     root_.Register(path, handler);
-    putHandlers_.push_back(std::make_pair(new RestApiPath(path), handler));
   }
 
   void RestApi::Register(const std::string& path,
                          RestApiPostCall::Handler handler)
   {
     root_.Register(path, handler);
-    postHandlers_.push_back(std::make_pair(new RestApiPath(path), handler));
   }
 
   void RestApi::Register(const std::string& path,
                          RestApiDeleteCall::Handler handler)
   {
     root_.Register(path, handler);
-    deleteHandlers_.push_back(std::make_pair(new RestApiPath(path), handler));
   }
 }
--- a/Core/RestApi/RestApi.h	Mon Jun 30 16:10:13 2014 +0200
+++ b/Core/RestApi/RestApi.h	Mon Jun 30 17:41:40 2014 +0200
@@ -43,30 +43,7 @@
   private:
     RestApiHierarchy root_;
 
-    typedef std::list< std::pair<RestApiPath*, RestApiGetCall::Handler> > GetHandlers;
-    typedef std::list< std::pair<RestApiPath*, RestApiPutCall::Handler> > PutHandlers;
-    typedef std::list< std::pair<RestApiPath*, RestApiPostCall::Handler> > PostHandlers;
-    typedef std::list< std::pair<RestApiPath*, RestApiDeleteCall::Handler> > DeleteHandlers;
-
-    GetHandlers  getHandlers_;
-    PutHandlers  putHandlers_;
-    PostHandlers  postHandlers_;
-    DeleteHandlers  deleteHandlers_;
-
-    bool IsGetAccepted(const UriComponents& uri);
-    bool IsPutAccepted(const UriComponents& uri);
-    bool IsPostAccepted(const UriComponents& uri);
-    bool IsDeleteAccepted(const UriComponents& uri);
-
-    std::string  GetAcceptedMethods(const UriComponents& uri);
-
   public:
-    RestApi()
-    {
-    }
-
-    ~RestApi();
-
     virtual bool Handle(HttpOutput& output,
                         HttpMethod method,
                         const UriComponents& uri,
--- a/Core/RestApi/RestApiHierarchy.cpp	Mon Jun 30 16:10:13 2014 +0200
+++ b/Core/RestApi/RestApiHierarchy.cpp	Mon Jun 30 17:41:40 2014 +0200
@@ -203,11 +203,17 @@
                                        IVisitor& visitor,
                                        size_t level)
   {
-    assert(uri.size() >= level);
+    if (uri.size() != 0 &&
+        level > uri.size())
+    {
+      return false;
+    }
+
     UriComponents trailing;
 
     // Look for an exact match on the resource of interest
-    if (uri.size() == level)
+      if (uri.size() == 0 ||
+          level == uri.size())
     {
       if (!handlers_.IsEmpty() &&
           visitor.Visit(handlers_, uri, components, trailing))
@@ -217,28 +223,30 @@
     }
 
 
-    // Try and go down in the hierarchy, using an exact match for the child
-    Children::const_iterator child = children_.find(uri[level]);
-    if (child != children_.end())
+    if (level < uri.size())  // A recursive call is possible
     {
-      if (child->second->LookupResource(components, uri, visitor, level + 1))
+      // Try and go down in the hierarchy, using an exact match for the child
+      Children::const_iterator child = children_.find(uri[level]);
+      if (child != children_.end())
       {
-        return true;
+        if (child->second->LookupResource(components, uri, visitor, level + 1))
+        {
+          return true;
+        }
       }
-    }
-
 
-    // Try and go down in the hierarchy, using wildcard rules for children
-    for (child = wildcardChildren_.begin();
-         child != wildcardChildren_.end(); child++)
-    {
-      HttpHandler::Arguments subComponents = components;
-      subComponents[child->first] = uri[level];
+      // Try and go down in the hierarchy, using wildcard rules for children
+      for (child = wildcardChildren_.begin();
+           child != wildcardChildren_.end(); child++)
+      {
+        HttpHandler::Arguments subComponents = components;
+        subComponents[child->first] = uri[level];
 
-      if (child->second->LookupResource(components, uri, visitor, level + 1))
-      {
-        return true;
-      }        
+        if (child->second->LookupResource(subComponents, uri, visitor, level + 1))
+        {
+          return true;
+        }        
+      }
     }
 
 
@@ -354,49 +362,42 @@
 
   void RestApiHierarchy::CreateSiteMap(Json::Value& target) const
   {
-    if (children_.size() == 0)
-    {
-      /*std::string s = " ";
+    target = Json::objectValue;
+
+    /*std::string s = " ";
       if (handlers_.HasHandler(HttpMethod_Get))
       {
-        s += "GET ";
+      s += "GET ";
       }
 
       if (handlers_.HasHandler(HttpMethod_Post))
       {
-        s += "POST ";
+      s += "POST ";
       }
 
       if (handlers_.HasHandler(HttpMethod_Put))
       {
-        s += "PUT ";
+      s += "PUT ";
       }
 
       if (handlers_.HasHandler(HttpMethod_Delete))
       {
-        s += "DELETE ";
+      s += "DELETE ";
       }
 
       target = s;*/
-
-      target = Json::objectValue;
-    }
-    else
+      
+    for (Children::const_iterator it = children_.begin();
+         it != children_.end(); it++)
     {
-      target = Json::objectValue;
-      
-      for (Children::const_iterator it = children_.begin();
-           it != children_.end(); it++)
-      {
-        it->second->CreateSiteMap(target[it->first]);
-      }
+      it->second->CreateSiteMap(target[it->first]);
     }
       
-    /*for (Children::const_iterator it = wildcardChildren_.begin();
-      it != wildcardChildren_.end(); it++)
-      {
-      it->second->CreateSiteMap(target["* (" + it->first + ")"]);
-      }*/
+    for (Children::const_iterator it = wildcardChildren_.begin();
+         it != wildcardChildren_.end(); it++)
+    {
+      it->second->CreateSiteMap(target["<" + it->first + ">"]);
+    }
   }