Add common exception handling 64/155764/7
authorJaemin Ryu <jm77.ryu@samsung.com>
Mon, 16 Oct 2017 05:55:25 +0000 (14:55 +0900)
committerJaemin Ryu <jm77.ryu@samsung.com>
Fri, 24 Nov 2017 00:47:08 +0000 (09:47 +0900)
Change-Id: I4a444fc90086fedc82fdf3afb34eba1d440ccdd0
Signed-off-by: Jaemin Ryu <jm77.ryu@samsung.com>
include/klay/exception.h
include/klay/rmi/client.h
include/klay/rmi/message.h
src/CMakeLists.txt
src/exception.cpp [new file with mode: 0644]
src/rmi/client.cpp
src/rmi/connection.cpp
src/rmi/message.cpp
src/rmi/service.cpp

index 734019a253b29f0518ac4d4eb216aca7b7e2b43d..81eee69ac040ecf93bec3829971e4f98de79f283 100644 (file)
@@ -28,6 +28,46 @@ public:
                std::runtime_error(error)
        {
        }
+
+       virtual ~Exception() {}
+       virtual const char *name() const;
+       virtual const char *className() const;
 };
+
+#define EXCEPTION_DEFINE(CLS)             \
+       class CLS : public Exception {        \
+       public:                               \
+               CLS(const std::string& error);    \
+               ~CLS() {}                         \
+               const char *className() const;    \
+               const char *name() const;         \
+       };
+
+
+#define EXCEPTION_IMPLEMENT(CLS, NAME)    \
+       CLS::CLS(const std::string& error) :  \
+               Exception(error)                  \
+       {                                     \
+       }                                     \
+       const char *CLS::className() const    \
+       {                                     \
+               return STRINGIFY(CLS);            \
+       }                                     \
+       const char *CLS::name() const         \
+       {                                     \
+               return NAME;                      \
+       }
+
+EXCEPTION_DEFINE(AssertionViolationException)
+EXCEPTION_DEFINE(NullPointerException)
+EXCEPTION_DEFINE(InvalidArgumentException)
+EXCEPTION_DEFINE(NotImplementedException)
+EXCEPTION_DEFINE(RangeException)
+EXCEPTION_DEFINE(NotFoundException)
+EXCEPTION_DEFINE(UnsupportedException)
+EXCEPTION_DEFINE(TimeoutException)
+EXCEPTION_DEFINE(NoPermissionException)
+EXCEPTION_DEFINE(OutOfMemoryException)
+EXCEPTION_DEFINE(IOException)
 } // namespace runtime
 #endif //__RUNTIME_EXCEPTION_H__
index dfb43a67566795fcb7640a4fbb374e2628b6a1db..d0c81e60873e11685f93c1ad4fc27b33496f9758 100644 (file)
 
 namespace rmi {
 
-class Client {
+template <typename ExceptionModel>
+class RemoteAccessClient {
 public:
-       Client(const std::string& address);
-       virtual ~Client();
+       RemoteAccessClient(const std::string& address);
+       virtual ~RemoteAccessClient();
 
-       Client(const Client&) = delete;
-       Client& operator=(const Client&) = delete;
+       RemoteAccessClient(const RemoteAccessClient&) = delete;
+       RemoteAccessClient& operator=(const RemoteAccessClient&) = delete;
 
        void connect();
        void disconnect();
@@ -58,8 +59,70 @@ private:
        std::thread dispatcher;
 };
 
-template<typename... Args>
-int Client::subscribe(const std::string& provider, const std::string& name,
+template <typename ExceptionModel>
+RemoteAccessClient<ExceptionModel>::RemoteAccessClient(const std::string& path) :
+       address(path)
+{
+}
+
+template <typename ExceptionModel>
+RemoteAccessClient<ExceptionModel>::~RemoteAccessClient()
+{
+       try {
+               disconnect();
+       } catch (runtime::Exception& e) {}
+}
+
+template <typename ExceptionModel>
+void RemoteAccessClient<ExceptionModel>::connect()
+{
+       connection = std::make_shared<Connection>(Socket::connect(address));
+
+       dispatcher = std::thread([this] { mainloop.run(); });
+}
+
+template <typename ExceptionModel>
+int RemoteAccessClient<ExceptionModel>::unsubscribe(const std::string& provider, int id)
+{
+       // file descriptor(id) is automatically closed when mainloop callback is destroyed.
+       mainloop.removeEventSource(id);
+       return 0;
+}
+
+template <typename ExceptionModel>
+int RemoteAccessClient<ExceptionModel>::subscribe(const std::string& provider, const std::string& name)
+{
+       Message request = connection->createMessage(Message::MethodCall, provider);
+       request.packParameters(name);
+       connection->send(request);
+
+       runtime::FileDescriptor response;
+       Message reply = connection->dispatch();
+       if (reply.isError()) {
+               std::string klass;
+               reply.disclose(klass);
+
+               ExceptionModel exception;
+               exception.raise(reply.target(), klass);
+       }
+
+       reply.disclose(response);
+
+       return response.fileDescriptor;
+}
+
+template <typename ExceptionModel>
+void RemoteAccessClient<ExceptionModel>::disconnect()
+{
+       mainloop.stop();
+       if (dispatcher.joinable()) {
+               dispatcher.join();
+       }
+}
+
+template <typename ExceptionModel>
+template <typename... Args>
+int RemoteAccessClient<ExceptionModel>::subscribe(const std::string& provider, const std::string& name,
                                          const typename MethodHandler<void, Args...>::type& handler)
 {
        int id = subscribe(provider, name);
@@ -91,8 +154,9 @@ int Client::subscribe(const std::string& provider, const std::string& name,
        return id;
 }
 
-template<typename Type, typename... Args>
-Type Client::methodCall(const std::string& method, Args&&... args)
+template <typename ExceptionModel>
+template <typename Type, typename... Args>
+Type RemoteAccessClient<ExceptionModel>::methodCall(const std::string& method, Args&&... args)
 {
        Message request = connection->createMessage(Message::MethodCall, method);
        request.packParameters(std::forward<Args>(args)...);
@@ -100,10 +164,24 @@ Type Client::methodCall(const std::string& method, Args&&... args)
 
        Type response;
        Message reply = connection->dispatch();
+       if (reply.isError()) {
+               std::string klass;
+               reply.disclose(klass);
+               ExceptionModel exception;
+               exception.raise(reply.target(), klass);
+       }
+
        reply.disclose<Type>(response);
 
        return response;
 }
 
+class DefaultExceptionModel {
+public:
+       void raise(const std::string& target, const std::string& except);
+};
+
+using Client = RemoteAccessClient<DefaultExceptionModel>;
+
 } // namespace rmi
 #endif //__RMI_CLIENT_H__
index 3d366713a755fb20fcd864b5914ef26b11f4c24a..7ac0208d33da1d025d2ab67fd3049bff27abc9f4 100644 (file)
@@ -51,7 +51,7 @@ public:
 
        // [TBD] Take arguments
        Message createReplyMessage() const;
-       Message createErrorMessage(const std::string& message) const;
+       Message createErrorMessage(const std::string& target, const std::string& message) const;
 
        unsigned int id() const
        {
index 832c6bafb4ae473d9e3750b95fb7150ead90fd9f..2b3c4d92e8f2ecacfa03e47423469470992cf8a8 100755 (executable)
@@ -17,6 +17,7 @@ SET(LIB_VERSION "${VERSION}")
 SET(LIB_SOVERSION "0")
 
 SET (KLAY_SOURCES              ${KLAY_SRC}/error.cpp
+                                               ${KLAY_SRC}/exception.cpp
                                                ${KLAY_SRC}/cgroup.cpp
                                                ${KLAY_SRC}/process.cpp
                                                ${KLAY_SRC}/eventfd.cpp
diff --git a/src/exception.cpp b/src/exception.cpp
new file mode 100644 (file)
index 0000000..e7cd928
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *  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 <klay/exception.h>
+#include <klay/preprocessor.h>
+
+namespace runtime {
+
+const char *Exception::name() const
+{
+       return "Exception";
+}
+
+const char *Exception::className() const
+{
+       return name();
+}
+
+EXCEPTION_IMPLEMENT(AssertionViolationException, "Assertion violation")
+EXCEPTION_IMPLEMENT(NullPointerException, "Null pointer")
+EXCEPTION_IMPLEMENT(InvalidArgumentException, "Invalid argument")
+EXCEPTION_IMPLEMENT(NotImplementedException, "Not implemented")
+EXCEPTION_IMPLEMENT(RangeException, "Out og range")
+EXCEPTION_IMPLEMENT(NotFoundException, "Not found")
+EXCEPTION_IMPLEMENT(UnsupportedException, "Unsupported")
+EXCEPTION_IMPLEMENT(TimeoutException, "Timeout")
+EXCEPTION_IMPLEMENT(NoPermissionException, "No permission")
+EXCEPTION_IMPLEMENT(OutOfMemoryException, "Out of memory")
+EXCEPTION_IMPLEMENT(IOException, "I/O error")
+} // namespace runtime
index d6e7bfa4d4d8eb9376dea747f0871bac6ea12b66..c4e7f0377b3e1eb0725e251b092bc75e43a7eb3e 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include <klay/exception.h>
 #include <klay/rmi/client.h>
 
 namespace rmi {
 
-Client::Client(const std::string& path) :
-       address(path)
+void DefaultExceptionModel::raise(const std::string& target, const std::string& msg)
 {
-}
-
-Client::~Client()
-{
-       try {
-               disconnect();
-       } catch (runtime::Exception& e) {}
-}
-
-void Client::connect()
-{
-       connection = std::make_shared<Connection>(Socket::connect(address));
-
-       dispatcher = std::thread([this] { mainloop.run(); });
-}
-
-int Client::unsubscribe(const std::string& provider, int id)
-{
-       // file descriptor(id) is automatically closed when mainloop callback is destroyed.
-       mainloop.removeEventSource(id);
-       return 0;
-}
-
-int Client::subscribe(const std::string& provider, const std::string& name)
-{
-       Message request = connection->createMessage(Message::MethodCall, provider);
-       request.packParameters(name);
-       connection->send(request);
-
-       runtime::FileDescriptor response;
-       Message reply = connection->dispatch();
-       reply.disclose(response);
-
-       return response.fileDescriptor;
-}
-
-void Client::disconnect()
-{
-       mainloop.stop();
-       if (dispatcher.joinable()) {
-               dispatcher.join();
-       }
+       if (target == "InvalidArgumentException")
+               throw runtime::InvalidArgumentException(msg);
+       else if (target == "NotImplementedException")
+               throw runtime::InvalidArgumentException(msg);
+       else if (target == "RangeException")
+               throw runtime::RangeException(msg);
+       else if (target == "NotFoundException")
+               throw runtime::NotFoundException(msg);
+       else if (target == "UnsupportedException")
+               throw runtime::UnsupportedException(msg);
+       else if (target == "NoPermissionException")
+               throw runtime::NoPermissionException(msg);
+       else if (target == "IOException")
+               throw runtime::IOException(msg);
+       else if (target == "OutOfMemoryException")
+               throw runtime::OutOfMemoryException(msg);
+       else
+               throw runtime::Exception(msg);
 }
 
 } // namespace rmi
index 4190115675b8dfe2e40858a993df53904a8b504e..1ecd54a8bb0c720068e64a3d160f97c33e8a8eb6 100644 (file)
@@ -46,12 +46,6 @@ Message Connection::dispatch() const
        std::lock_guard<std::mutex> lock(receiveMutex);
 
        message.decode(socket);
-       if (message.isError()) {
-               std::string exception;
-               message.disclose(exception);
-
-               throw runtime::Exception(exception);
-       }
 
        return message;
 }
index cd1a01935fad324a3bea3590b6694684304a71a4..9dcaa282831f20d20ab100ca4a3154d784c6c3ac 100644 (file)
@@ -81,9 +81,9 @@ Message Message::createReplyMessage() const
        return Message(id(), Reply, target());
 }
 
-Message Message::createErrorMessage(const std::string& message) const
+Message Message::createErrorMessage(const std::string& target, const std::string& message) const
 {
-       Message error(id(), Error, target());
+       Message error(id(), Error, target);
        error.enclose(message);
 
        return error;
index c6b9188ae8b910e05ef694b2f009167ab21c3365..66bcc61da81a84bc2025e7b8e65dcdc817b50d3d 100644 (file)
@@ -197,20 +197,25 @@ void Service::onMessageProcess(const std::shared_ptr<Connection>& connection)
        // we should increase the reference count of the shared_ptr by capturing it as value
        auto process = [&, connection](Message& request) {
                try {
+                       if (!methodRegistry.count(request.target()))
+                               throw runtime::NotFoundException("Method not found");
+
                        std::shared_ptr<MethodContext> methodContext = methodRegistry.at(request.target());
 
                        processingContext = ProcessingContext(connection);
                        bool allowed = onPrivilegeCheck(processingContext.credentials, methodContext->privilege);
                        onAuditTrail(processingContext.credentials, request.target(), allowed);
                        if (!allowed) {
-                               throw runtime::Exception("Permission denied");
+                               throw runtime::NoPermissionException("Permission denied");
                        }
 
                        connection->send(methodContext->dispatcher(request));
+               } catch (runtime::Exception& e) {
+                       connection->send(request.createErrorMessage(e.className(), e.what()));
                } catch (std::exception& e) {
                        try {
                                // Forward the exception to the peer
-                               connection->send(request.createErrorMessage(e.what()));
+                               connection->send(request.createErrorMessage("Exception", e.what()));
                        } catch (std::exception& ex) {
                                // The connection is abnormally closed by the peer.
                                ERROR(KSINK, ex.what());