Add first version
[ric-plt/sdl.git] / src / errorqueries.cpp
diff --git a/src/errorqueries.cpp b/src/errorqueries.cpp
new file mode 100644 (file)
index 0000000..55ba2c1
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+   Copyright (c) 2018-2019 Nokia.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+#include <sstream>
+#include "config.h"
+#include <sdl/errorqueries.hpp>
+#include "private/createlogger.hpp"
+#include "private/error.hpp"
+
+using namespace shareddatalayer;
+
+namespace
+{
+    class SharedDataLayerErrorCategory : public std::error_category
+    {
+    public:
+      SharedDataLayerErrorCategory() = default;
+      const char* name() const noexcept override;
+      std::string message(int condition) const override;
+      bool equivalent(const std::error_code& ec, int condition) const noexcept override;
+    };
+
+    const char* SharedDataLayerErrorCategory::name() const noexcept
+    {
+        return "shareddatalayer-errorcodes";
+    }
+
+    std::string SharedDataLayerErrorCategory::message(int condition) const
+    {
+        switch (static_cast<shareddatalayer::Error>(condition))
+        {
+            case shareddatalayer::Error::SUCCESS:
+                return std::error_code().message();
+            case shareddatalayer::Error::NOT_CONNECTED:
+                return "shareddatalayer not connected to backend data storage";
+            case shareddatalayer::Error::OPERATION_INTERRUPTED:
+                return "shareddatalayer sent the request to backend data storage but did not receive reply";
+            case shareddatalayer::Error::BACKEND_FAILURE:
+                return "backend data storage failed to process the request";
+            case shareddatalayer::Error::REJECTED_BY_BACKEND:
+                return "backend data storage rejected the request";
+            case shareddatalayer::Error::REJECTED_BY_SDL:
+                return "SDL rejected the request";
+            default:
+                return "description missing for SharedDataLayerErrorCategory error: " + std::to_string(condition);
+        }
+    }
+
+    const std::error_category& getSharedDataLayerErrorCategory() noexcept
+    {
+        static const SharedDataLayerErrorCategory theSharedDataLayerErrorCategory;
+        return theSharedDataLayerErrorCategory;
+    }
+
+
+    bool SharedDataLayerErrorCategory::equivalent(const std::error_code& ec, int condition) const noexcept
+    {
+        /* Reasoning for possibly not self-evident mappings:
+            - InternalError::BACKEND_NOT_READY is mapped to shareddatalayer::Error::NOT_CONNECTED
+              even though we are connected to backend in that situation. Client handling for InternalError::BACKEND_NOT_READY
+              situation is identical than handling for other shareddatalayer::Error::NOT_CONNECTED client error cases.
+              To have minimal amount of  client error codes we map it to that.
+            - InternalError::SDL_ERROR_CODE_LOGIC_ERROR is mapped to shareddatalayer::Error::BACKEND_FAILURE.
+              That internal failure should never happen. If it does happen, we cannot know here which kind of error
+              has really happened. Thus we map to the most severe client error code (other places will write logs about this).
+         */
+        switch (static_cast<shareddatalayer::Error>(condition))
+        {
+            case shareddatalayer::Error::SUCCESS:
+                return ec == InternalError::SUCCESS ||
+                       ec == std::error_code();
+            case shareddatalayer::Error::NOT_CONNECTED:
+                return ec == InternalError::SDL_NOT_CONNECTED_TO_BACKEND ||
+                       ec == InternalError::BACKEND_NOT_READY ||
+                       ec == InternalError::SDL_NOT_READY;
+            case shareddatalayer::Error::OPERATION_INTERRUPTED:
+                return ec == InternalError::BACKEND_CONNECTION_LOST;
+            case shareddatalayer::Error::BACKEND_FAILURE:
+                return ec == InternalError::BACKEND_ERROR ||
+                       ec == InternalError::SDL_ERROR_CODE_LOGIC_ERROR;
+            case shareddatalayer::Error::REJECTED_BY_BACKEND:
+                return ec == InternalError::BACKEND_REJECTED_REQUEST;
+            case shareddatalayer::Error::REJECTED_BY_SDL:
+                return ec == InternalError::SDL_RECEIVED_INVALID_PARAMETER;
+            default:
+                /* Since clients can compare shareddatalayer::Error conditions against any std::error_code based ec, this error log
+                 * can occur without fault in SDL implementation. If error log appears:
+                 *  - First check is the problematic ec set in SDL implementation
+                 *      - If yes, do needed updates to SDL (update error mappings for given ec or change SDL to set some error_code)
+                 *      - If no, ask client to check why they are comparing non-SDL originated error_code against shareddatalayer::Error
+                 */
+                std::ostringstream msg;
+                msg << "SharedDataLayerErrorCategory::equivalent no mapping for error: " << ec.category().name()
+                    << ec.value();
+                logErrorOnce(msg.str());
+                return false;
+        }
+    }
+}
+
+namespace shareddatalayer
+{
+    std::error_condition make_error_condition(shareddatalayer::Error errorCode)
+    {
+      return {static_cast<int>(errorCode), getSharedDataLayerErrorCategory()};
+    }
+}