Add Redis Sentinel based database discovery
[ric-plt/sdl.git] / src / errorqueries.cpp
1 /*
2    Copyright (c) 2018-2019 Nokia.
3
4    Licensed under the Apache License, Version 2.0 (the "License");
5    you may not use this file except in compliance with the License.
6    You may obtain a copy of the License at
7
8        http://www.apache.org/licenses/LICENSE-2.0
9
10    Unless required by applicable law or agreed to in writing, software
11    distributed under the License is distributed on an "AS IS" BASIS,
12    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    See the License for the specific language governing permissions and
14    limitations under the License.
15 */
16
17 #include <sstream>
18 #include "config.h"
19 #include <sdl/errorqueries.hpp>
20 #include "private/createlogger.hpp"
21 #include "private/error.hpp"
22
23 using namespace shareddatalayer;
24
25 namespace
26 {
27     class SharedDataLayerErrorCategory : public std::error_category
28     {
29     public:
30       SharedDataLayerErrorCategory() = default;
31       const char* name() const noexcept override;
32       std::string message(int condition) const override;
33       bool equivalent(const std::error_code& ec, int condition) const noexcept override;
34     };
35
36     const char* SharedDataLayerErrorCategory::name() const noexcept
37     {
38         return "shareddatalayer-errorcodes";
39     }
40
41     std::string SharedDataLayerErrorCategory::message(int condition) const
42     {
43         switch (static_cast<shareddatalayer::Error>(condition))
44         {
45             case shareddatalayer::Error::SUCCESS:
46                 return std::error_code().message();
47             case shareddatalayer::Error::NOT_CONNECTED:
48                 return "shareddatalayer not connected to backend data storage";
49             case shareddatalayer::Error::OPERATION_INTERRUPTED:
50                 return "shareddatalayer sent the request to backend data storage but did not receive reply";
51             case shareddatalayer::Error::BACKEND_FAILURE:
52                 return "backend data storage failed to process the request";
53             case shareddatalayer::Error::REJECTED_BY_BACKEND:
54                 return "backend data storage rejected the request";
55             case shareddatalayer::Error::REJECTED_BY_SDL:
56                 return "SDL rejected the request";
57             default:
58                 return "description missing for SharedDataLayerErrorCategory error: " + std::to_string(condition);
59         }
60     }
61
62     const std::error_category& getSharedDataLayerErrorCategory() noexcept
63     {
64         static const SharedDataLayerErrorCategory theSharedDataLayerErrorCategory;
65         return theSharedDataLayerErrorCategory;
66     }
67
68
69     bool SharedDataLayerErrorCategory::equivalent(const std::error_code& ec, int condition) const noexcept
70     {
71         /* Reasoning for possibly not self-evident mappings:
72             - InternalError::BACKEND_NOT_READY is mapped to shareddatalayer::Error::NOT_CONNECTED
73               even though we are connected to backend in that situation. Client handling for InternalError::BACKEND_NOT_READY
74               situation is identical than handling for other shareddatalayer::Error::NOT_CONNECTED client error cases.
75               To have minimal amount of  client error codes we map it to that.
76             - InternalError::SDL_ERROR_CODE_LOGIC_ERROR is mapped to shareddatalayer::Error::BACKEND_FAILURE.
77               That internal failure should never happen. If it does happen, we cannot know here which kind of error
78               has really happened. Thus we map to the most severe client error code (other places will write logs about this).
79          */
80         switch (static_cast<shareddatalayer::Error>(condition))
81         {
82             case shareddatalayer::Error::SUCCESS:
83                 return ec == InternalError::SUCCESS ||
84                        ec == std::error_code();
85             case shareddatalayer::Error::NOT_CONNECTED:
86                 return ec == InternalError::SDL_NOT_CONNECTED_TO_BACKEND ||
87                        ec == InternalError::BACKEND_NOT_READY ||
88                        ec == InternalError::SDL_NOT_READY;
89             case shareddatalayer::Error::OPERATION_INTERRUPTED:
90                 return ec == InternalError::BACKEND_CONNECTION_LOST;
91             case shareddatalayer::Error::BACKEND_FAILURE:
92                 return ec == InternalError::BACKEND_ERROR ||
93                        ec == InternalError::SDL_ERROR_CODE_LOGIC_ERROR;
94             case shareddatalayer::Error::REJECTED_BY_BACKEND:
95                 return ec == InternalError::BACKEND_REJECTED_REQUEST;
96             case shareddatalayer::Error::REJECTED_BY_SDL:
97                 return ec == InternalError::SDL_RECEIVED_INVALID_PARAMETER;
98             default:
99                 /* Since clients can compare shareddatalayer::Error conditions against any std::error_code based ec, this error log
100                  * can occur without fault in SDL implementation. If error log appears:
101                  *  - First check is the problematic ec set in SDL implementation
102                  *      - If yes, do needed updates to SDL (update error mappings for given ec or change SDL to set some error_code)
103                  *      - If no, ask client to check why they are comparing non-SDL originated error_code against shareddatalayer::Error
104                  */
105                 std::ostringstream msg;
106                 msg << "SharedDataLayerErrorCategory::equivalent no mapping for error: " << ec.category().name()
107                     << ec.value();
108                 logErrorOnce(msg.str());
109                 return false;
110         }
111     }
112 }
113
114 namespace shareddatalayer
115 {
116     std::error_condition make_error_condition(shareddatalayer::Error errorCode)
117     {
118       return {static_cast<int>(errorCode), getSharedDataLayerErrorCategory()};
119     }
120 }