serialization: extract xml-based db implementation 54/200554/3
authorAdrian Szyndela <adrian.s@samsung.com>
Mon, 25 Feb 2019 13:42:33 +0000 (14:42 +0100)
committerHyotaek Shim <hyotaek.shim@samsung.com>
Thu, 7 Mar 2019 07:37:34 +0000 (07:37 +0000)
Change-Id: I84ef422a5451192fe18762c16bc14aa7ed4b9d02

Makefile.am
src/internal/naive_policy_db.cpp
src/internal/naive_policy_db.hpp
src/internal/storage_backend_xml.cpp [new file with mode: 0644]
src/internal/storage_backend_xml.hpp [new file with mode: 0644]

index beb20b7..28d274e 100644 (file)
@@ -63,7 +63,8 @@ COMMON_SRC =\
        src/internal/tslog.cpp \
        src/internal/serializer.cpp \
        src/internal/print_content.cpp \
-       src/internal/storage_backend_serialized.cpp
+       src/internal/storage_backend_serialized.cpp \
+       src/internal/storage_backend_xml.cpp
 
 src_libdbuspolicy1_la_SOURCES =\
        $(COMMON_SRC) \
index 7ce3b4e..cf53c10 100644 (file)
@@ -5,6 +5,7 @@
 #include "print_content.hpp"
 #include "tslog.hpp"
 #include "type_list.h"
+#include "storage_backend_xml.hpp"
 
 #include <cassert>
 #include <map>
 
 namespace ldp_xml_parser {
 
-/* The following two are building blocks for PolicySet class.
- * They specify if a given PolicySet class supports user and group policies.
- */
-/****************** UserAndGroupContext ************************/
-template <typename P>
-class UserAndGroupContext {
-protected:
-       /** Map with policies for different users */
-       std::map<uid_t, P> user;
-       /** Map with policies for different groups */
-       std::map<gid_t, P> group;
-
-       template <typename T>
-       void addItemUser(uid_t uid, T &item) { user[uid].addItem(item); }
-
-       template <typename T>
-       void addItemGroup(gid_t gid, T &item) { group[gid].addItem(item); }
-
-       void printContent() const {
-               for (const auto& i : user) {
-                       std::cerr << "user: " << i.first << std::endl;
-                       i.second.printContent();
-               }
-
-               for (const auto& i : group) {
-                       std::cerr << "group: " << i.first << std::endl;
-                       i.second.printContent();
-               }
-       }
-
-       size_t getSize() const {
-               size_t size = user.size() * sizeof(typename decltype(user)::value_type);
-               for (const auto& i : user)
-                       size += i.second.getSize();
-
-               size += group.size() * sizeof(typename decltype(group)::value_type);
-               for (const auto& i : group)
-                       size += i.second.getSize();
-               return size;
-       }
-
-public:
-       const P *getPolicyUser(uid_t uid) const {
-               tslog::log("---policy_type = USER =", uid, "\n");
-
-               auto it = user.find(uid);
-               if (it == user.end()) {
-                       tslog::log_verbose("GetPolicy: Out of Range exception\n");
-                       return nullptr;
-               }
-               return &(it->second);
-       }
-
-       const P *getPolicyGroup(gid_t gid) const {
-               tslog::log("---policy_type = GROUP = ", gid, "\n");
-
-               auto it = group.find(gid);
-               if (it == group.end()) {
-                       tslog::log_verbose("GetPolicy: Out of Range exception\n");
-                       return nullptr;
-               }
-               return &(it->second);
-       }
-
-       const std::map<uid_t, P> &getPoliciesUser() const { return user; }
-       const std::map<uid_t, P> &getPoliciesGroup() const { return group; }
-};
-
-/****************** NoUserAndGroupContext ************************/
-class NoUserAndGroupContext {
-protected:
-       template <typename T>
-       void addItemUser(uid_t, T &) { assert(false); }
-
-       template <typename T>
-       void addItemGroup(gid_t, T &) { assert(false); }
-
-       void printContent() const {}
-       size_t getSize() const { return 0; }
-};
-
-template<typename P, typename UG = UserAndGroupContext<P>>
-class PolicySet : public UG {
-       /** Policies for all contexts */
-       P contextMandatory;
-       P contextDefault;
-
-       P &getPolicyContext(ContextType type) {
-               if (ContextType::MANDATORY == type)
-                       return contextMandatory;
-
-               assert(ContextType::DEFAULT == type);
-               return contextDefault;
-       }
-
-public:
-       typedef P policy_type;
-       /** Adds given item to policy
-        * \param[in] policy_type Policy type
-        * \param[in] policy_type_value Policy type value
-        * \param[in] item Item to add
-       */
-       template<typename T>
-       void addItem(const PolicyType policy_type,
-                                const PolicyTypeValue policy_type_value,
-                                T &item) {
-               switch (policy_type) {
-                       case PolicyType::CONTEXT:
-                               getPolicyContext(policy_type_value.context).addItem(item);
-                               break;
-                       case PolicyType::USER:
-                               UG::addItemUser(policy_type_value.user, item);
-                               break;
-                       case PolicyType::GROUP:
-                               UG::addItemGroup(policy_type_value.group, item);
-                               break;
-                       case PolicyType::NONE:
-                               assert(false);
-                               break;
-               }
-       }
-
-       const P &getRefPolicyContextMandatory() const { return contextMandatory; }
-       const P &getRefPolicyContextDefault() const { return contextDefault; }
-
-       const P *getPolicyContextMandatory() const {
-               tslog::log("---policy_type = CONTEXT = MANDATORY\n");
-               return &contextMandatory;
-       }
-
-       const P *getPolicyContextDefault() const {
-               tslog::log("---policy_type = CONTEXT = DEFAULT\n");
-               return &contextDefault;
-       }
-
-       void printSet() const {
-               std::cerr << "context default" << std::endl;
-               contextDefault.printContent();
-               std::cerr << "context mandatory" << std::endl;
-               contextMandatory.printContent();
-
-               UG::printContent();
-
-               std::cerr << "Memory consumption: " << getSetSize() << " B" << std::endl;
-       }
-
-       size_t getSetSize() const {
-               size_t size = sizeof(*this);
-
-               size += contextMandatory.getSize();
-               size += contextDefault.getSize();
-
-               size += UG::getSize();
-               return size;
-       }
-};
-
-/****************** NaivePolicyDbImpl ************************/
-class NaivePolicyDb::NaivePolicyDbImpl {
-public:
-       /** Set of ownership policies */
-       PolicySet<PolicyOwn> m_own_set;
-       /** Set of send policies */
-       PolicySet<PolicySend> m_send_set;
-       /** Set of receive policies */
-       PolicySet<PolicyReceive> m_receive_set;
-       /** Set of bus access policies */
-       PolicySet<PolicyAccess, NoUserAndGroupContext> m_access_set;
-
-       template <typename T>
-       struct MatchPolicy; // provide policy_type in specializations
-
-       template <typename T>
-       const typename MatchPolicy<T>::policy_set_type &getPolicySet() const;
-       template <typename T>
-       typename MatchPolicy<T>::policy_set_type &getPolicySet();
-
-       template <typename T,
-                         typename P = typename MatchPolicy<T>::policy_type,
-                         typename PS = typename MatchPolicy<T>::policy_set_type,
-                         typename ...Args>
-       DecisionItem getDecisionItem(const T &item,
-                                                                const P *(PS::*f)(Args ... args) const,
-                                                                Args ...args) const;
-};
-
-/* Tie MatchItems with proper policy sets.
- * Parameters: T - MatchItem* type
- *             field - one of m_*_set fields from NaivePolicyDb
- *
- * The below DEF_GET_POLICY_SET defines specialization for MatchPolicy<T> template,
- * and a specialization of NaivePolicyDb::getPolicySet template function
- *
- * Specialization for MatchPolicy<T> provides field 'policy_type' which specifies
- * a type of policy used within 'field' parameter, and field 'policy_set_type'
- * which specifies a type of the 'field' parameter.
- * Specialization of NaivePolicyDb::getPolicySet returns the 'field'.
- *
- * For example: DEF_GET_POLICY_SET(MatchItemOwn, m_own_set) defines equivalent to
- * MatchPolicy<MatchItemOwn> {
- *             typedef PolicyOwn policy_type;
- *             typedef PolicySet<PolicyOwn> policy_set_type;
- * }
- * PolicySet<PolicyOwn> &getPolicySet<MatchItemOwn> const;
- *
- * Thanks to this construction we do not need to manually specify PolicyOwn in functions that
- * know MatchItemOwn - it is inferred.
- *
- */
-#define DEF_GET_POLICY_SET(T, field) \
-       template <>     struct NaivePolicyDb::NaivePolicyDbImpl::MatchPolicy<T> { \
-               typedef decltype(field)::policy_type policy_type; \
-               typedef decltype(field) policy_set_type; \
-       }; \
-       template <>     struct NaivePolicyDb::NaivePolicyDbImpl::MatchPolicy<typename decltype(NaivePolicyDb::NaivePolicyDbImpl::field)::policy_type> { \
-               typedef decltype(field) policy_set_type; \
-       }; \
-       template <> \
-       auto NaivePolicyDb::NaivePolicyDbImpl::getPolicySet<T>() const -> decltype((field)) { \
-               return field; \
-       } \
-       template <> \
-       auto NaivePolicyDb::NaivePolicyDbImpl::getPolicySet<T>() -> decltype((field)) { \
-               return field; \
-       } \
-       template <> \
-       auto NaivePolicyDb::NaivePolicyDbImpl::getPolicySet<typename decltype(NaivePolicyDb::NaivePolicyDbImpl::field)::policy_type>() -> decltype((field)) { \
-               return field; \
-       }
-
-DEF_GET_POLICY_SET(MatchItemOwn, m_own_set)
-DEF_GET_POLICY_SET(MatchItemSend, m_send_set)
-DEF_GET_POLICY_SET(MatchItemReceive, m_receive_set)
-DEF_GET_POLICY_SET(MatchItemAccess, m_access_set)
-
-#undef DEF_GET_POLICY_SET
-
-template <typename T, typename P, typename PS, typename ...Args>
-DecisionItem NaivePolicyDb::NaivePolicyDbImpl::getDecisionItem(const T &item,
-                                               const P *(PS::*f)(Args ... args) const,
-                                               Args ...args) const
-{
-       const auto &policySet = getPolicySet<T>();
-       typedef typename std::remove_reference<decltype(policySet)>::type PolicySetType;
-
-       auto policy = (policySet.*f)(args...);
-       if (nullptr == policy)
-               return Decision::ANY;
-
-       tslog::log_verbose("Checking ", PolicySetType::policy_type::name, " policy for: ", item, "\n");
-
-       return policy->getDecisionItem(item);
-}
-
 void NaivePolicyDb::updateSupplementaryGroups(const VGid &groups, uid_t uid, gid_t gid) const {
        auto &vsend = getMapGroup<MatchItemSend>(uid);
        auto &vrecv = getMapGroup<MatchItemReceive>(uid);
@@ -284,9 +31,9 @@ void NaivePolicyDb::updateSupplementaryGroups(const VGid &groups, uid_t uid, gid
 
        /* insert supplementary group */
        for (const auto group : groups) {
-               if (pimpl->getPolicySet<MatchItemSend>().getPolicyGroup(group) != nullptr)
+               if (backend.existsPolicyForGroup<MatchItemSend>(group))
                        vsend.push_back(group);
-               if (pimpl->getPolicySet<MatchItemReceive>().getPolicyGroup(group) != nullptr)
+               if (backend.existsPolicyForGroup<MatchItemReceive>(group))
                        vrecv.push_back(group);
                vaccess.push_back(group);       // no filtering, it will be used once
        }
@@ -303,7 +50,7 @@ void NaivePolicyDb::updateSupplementaryGroupsOwn(const VGid &groups, uid_t uid,
                vown.push_back(gid);
        } else {
                for (const auto group : groups) {
-                       if (pimpl->getPolicySet<MatchItemOwn>().getPolicyGroup(group) != nullptr)
+                       if (backend.existsPolicyForGroup<MatchItemOwn>(group))
                                vown.push_back(group);
                }
        }
@@ -315,21 +62,12 @@ void NaivePolicyDb::addItem(const PolicyType policy_type,
                                                        const PolicyTypeValue policy_type_value,
                                                        T &item) {
        tslog::log("Add item: ", item, ", decision: ", item.getDecision(), "\n");
-       pimpl->getPolicySet<typename T::match_type>().addItem(policy_type, policy_type_value, item);
+       backend.addItem(policy_type, policy_type_value, item);
 }
 
 void NaivePolicyDb::printContent() const
 {
-       #define PRINT_SET(x) \
-       std::cerr << std::endl << "----" #x "----" << std::endl; \
-       (x).printSet();
-
-       PRINT_SET(pimpl->m_own_set)
-       PRINT_SET(pimpl->m_send_set)
-       PRINT_SET(pimpl->m_receive_set)
-       PRINT_SET(pimpl->m_access_set)
-
-       #undef PRINT_SET
+       backend.printContent();
 
        for (const auto &mapGroup : mapGroups) {
                std::cerr << std::endl << "---- mapGroup ----" << std::endl;
@@ -347,30 +85,6 @@ void NaivePolicyDb::printContent() const
        }
 }
 
-template <typename T>
-DecisionItem NaivePolicyDb::getDecisionItemContextMandatory(const T &item) const
-{
-       return pimpl->getDecisionItem<T>(item, &NaivePolicyDbImpl::MatchPolicy<T>::policy_set_type::getPolicyContextMandatory);
-}
-
-template <typename T>
-DecisionItem NaivePolicyDb::getDecisionItemContextDefault(const T &item) const
-{
-       return pimpl->getDecisionItem<T>(item, &NaivePolicyDbImpl::MatchPolicy<T>::policy_set_type::getPolicyContextDefault);
-}
-
-template <typename T>
-DecisionItem NaivePolicyDb::getDecisionItemUser(uid_t uid, const T &item) const
-{
-       return pimpl->getDecisionItem<T>(item, &NaivePolicyDbImpl::MatchPolicy<T>::policy_set_type::getPolicyUser, uid);
-}
-
-template <typename T>
-DecisionItem NaivePolicyDb::getDecisionItemGroup(gid_t gid, const T &item) const
-{
-       return pimpl->getDecisionItem<T>(item, &NaivePolicyDbImpl::MatchPolicy<T>::policy_set_type::getPolicyGroup, gid);
-}
-
 template <>
 const VGid *NaivePolicyDb::getGroups<MatchItemOwn>(uid_t uid, gid_t) const
 {
@@ -423,83 +137,52 @@ VGid &NaivePolicyDb::getMapGroup(uid_t uid) const
 }
 
 void NaivePolicyDb::clear() {
-       pimpl = std::unique_ptr<NaivePolicyDbImpl>{new NaivePolicyDbImpl};
+       backend.clear();
 }
 
 template <typename T>
 const T &NaivePolicyDb::getPolicyContextMandatory() const {
-       return pimpl->getPolicySet<T>().getRefPolicyContextMandatory();
+       return backend.getPolicyContextMandatory<T>();
 }
 
 template <typename T>
 const T &NaivePolicyDb::getPolicyContextDefault() const {
-       return pimpl->getPolicySet<T>().getRefPolicyContextDefault();
+       return backend.getPolicyContextDefault<T>();
 }
 
 template <typename T>
 const std::map<uid_t, T> &NaivePolicyDb::getPoliciesUser() const {
-       return pimpl->getPolicySet<T>().getPoliciesUser();
+       return backend.getPoliciesUser<T>();
 }
 
 template <typename T>
 const std::map<gid_t, T> &NaivePolicyDb::getPoliciesGroup() const {
-       return pimpl->getPolicySet<T>().getPoliciesGroup();
+       return backend.getPoliciesGroup<T>();
 }
 
-NaivePolicyDb::NaivePolicyDb() : pimpl{new NaivePolicyDbImpl} {
-}
-
-NaivePolicyDb::~NaivePolicyDb() = default;
-
 /* Explicit instantiation is needed for used public template methods defined in this file.
  */
 #define T_INSTANTIATION(T) \
-       template DecisionItem NaivePolicyDb::getDecisionItemContextMandatory<T>(const T &) const; \
-       template DecisionItem NaivePolicyDb::getDecisionItemContextDefault<T>(const T &) const; \
-       template const VGid *NaivePolicyDb::getGroups<T>(uid_t, gid_t) const;
-
-T_INSTANTIATION(MatchItemOwn)
-T_INSTANTIATION(MatchItemSend)
-T_INSTANTIATION(MatchItemReceive)
-T_INSTANTIATION(MatchItemAccess)
-
-#define T_INSTANTIATION2(T) \
-       template DecisionItem NaivePolicyDb::getDecisionItemUser<T>(uid_t, const T &) const; \
-       template DecisionItem NaivePolicyDb::getDecisionItemGroup<T>(gid_t, const T &) const;
-
-T_INSTANTIATION2(MatchItemOwn)
-T_INSTANTIATION2(MatchItemSend)
-T_INSTANTIATION2(MatchItemReceive)
+       template const VGid *NaivePolicyDb::getGroups<MatchItem##T>(uid_t, gid_t) const; \
+       template void NaivePolicyDb::addItem(const PolicyType policy_type, const PolicyTypeValue policy_type_value, Item##T &item); \
+       template const Policy##T &NaivePolicyDb::getPolicyContextMandatory() const; \
+       template const Policy##T &NaivePolicyDb::getPolicyContextDefault() const;
 
-#define T_INSTANTIATION3(T) \
-       template void NaivePolicyDb::addItem(const PolicyType policy_type, const PolicyTypeValue policy_type_value, T &item);
+T_INSTANTIATION(Own)
+T_INSTANTIATION(Send)
+T_INSTANTIATION(Receive)
+T_INSTANTIATION(Access)
 
-T_INSTANTIATION3(ItemOwn)
-T_INSTANTIATION3(ItemSend)
-T_INSTANTIATION3(ItemReceive)
-T_INSTANTIATION3(ItemAccess)
-
-#define T_INSTANTIATION4(T) \
-       template const T &NaivePolicyDb::getPolicyContextMandatory() const; \
-       template const T &NaivePolicyDb::getPolicyContextDefault() const;
-
-T_INSTANTIATION4(PolicyOwn)
-T_INSTANTIATION4(PolicySend)
-T_INSTANTIATION4(PolicyReceive)
-T_INSTANTIATION4(PolicyAccess)
+#undef T_INSTANTIATION
 
-#define T_INSTANTIATION5(T) \
-       template const std::map<uid_t, T> &NaivePolicyDb::getPoliciesGroup() const; \
-       template const std::map<gid_t, T> &NaivePolicyDb::getPoliciesUser() const;
+#define T_INSTANTIATION(T) \
+       template const std::map<uid_t, Policy##T> &NaivePolicyDb::getPoliciesGroup() const; \
+       template const std::map<gid_t, Policy##T> &NaivePolicyDb::getPoliciesUser() const;
 
-T_INSTANTIATION5(PolicyOwn)
-T_INSTANTIATION5(PolicySend)
-T_INSTANTIATION5(PolicyReceive)
+T_INSTANTIATION(Own)
+T_INSTANTIATION(Send)
+T_INSTANTIATION(Receive)
 
 #undef T_INSTANTIATION
-#undef T_INSTANTIATION2
-#undef T_INSTANTIATION3
-#undef T_INSTANTIATION4
-#undef T_INSTANTIATION5
 
 } // namespace ldp_xml_parser
index 7db549e..9137dfc 100644 (file)
@@ -16,6 +16,7 @@
 #ifndef _NAIVE_DB_H
 #define _NAIVE_DB_H
 
+#include "storage_backend_xml.hpp"
 #include <memory>
 #include <vector>
 #include <map>
@@ -34,9 +35,7 @@ namespace ldp_xml_parser
        /** Database class, contains policies for ownership and send/receive */
        class NaivePolicyDb {
        private:
-               class NaivePolicyDbImpl;
-
-               std::unique_ptr<NaivePolicyDbImpl> pimpl;
+               ldp_xml::StorageBackendXML backend;
 
                mutable std::map<uid_t, VGid> mapGroups[MatchItemTypes::count];
                /* A mutex for mapGroups */
@@ -47,27 +46,36 @@ namespace ldp_xml_parser
 
                void updateSupplementaryGroups(const VGid &groups, uid_t uid, gid_t gid) const;
                void updateSupplementaryGroupsOwn(const VGid &groups, uid_t uid, gid_t gid) const;
-       public:
-
-               NaivePolicyDb();
-               ~NaivePolicyDb();
 
+       public:
+               /***** Common interface for all backends ******/
                void printContent() const;
 
                template <typename T>
-               DecisionItem getDecisionItemContextMandatory(const T &item) const;
+               DecisionItem getDecisionItemContextMandatory(const T &item) const
+               { return backend.getDecisionItemContextMandatory(item); }
+
                template <typename T>
-               DecisionItem getDecisionItemContextDefault(const T &item) const;
+               DecisionItem getDecisionItemContextDefault(const T &item) const
+               { return backend.getDecisionItemContextDefault(item); }
+
                template <typename T>
-               DecisionItem getDecisionItemUser(uid_t uid, const T &item) const;
+               DecisionItem getDecisionItemUser(uid_t uid, const T &item) const
+               { return backend.getDecisionItemUser(uid, item); }
+
                template <typename T>
-               DecisionItem getDecisionItemGroup(gid_t gid, const T &item) const;
+               DecisionItem getDecisionItemGroup(gid_t gid, const T &item) const
+               { return backend.getDecisionItemGroup(gid, item); }
 
+               /******* Common interface for group maps management **********/
                template <typename T>
                const VGid *getGroups(uid_t uid, gid_t gid) const;
 
                void initializeGroups(uid_t uid, gid_t gid);
 
+               /******* Interface for read-write backends (e.g. XML-based) */
+               /* This will be probably moved from here */
+
                /** Adds item to a policy
                 * \param[in] policy_type Policy type
                 * \param[in] policy_type_value Policy type value
diff --git a/src/internal/storage_backend_xml.cpp b/src/internal/storage_backend_xml.cpp
new file mode 100644 (file)
index 0000000..5cfb9cb
--- /dev/null
@@ -0,0 +1,366 @@
+#include "storage_backend_xml.hpp"
+#include "policy_containers.hpp"
+
+using namespace ldp_xml_parser;
+
+namespace ldp_xml {
+
+/* The following two are building blocks for PolicySet class.
+ * They specify if a given PolicySet class supports user and group policies.
+ */
+/****************** UserAndGroupContext ************************/
+template <typename P>
+class UserAndGroupContext {
+protected:
+       /** Map with policies for different users */
+       std::map<uid_t, P> user;
+       /** Map with policies for different groups */
+       std::map<gid_t, P> group;
+
+       template <typename T>
+       void addItemUser(uid_t uid, T &item) { user[uid].addItem(item); }
+
+       template <typename T>
+       void addItemGroup(gid_t gid, T &item) { group[gid].addItem(item); }
+
+       void printContent() const {
+               for (const auto& i : user) {
+                       std::cerr << "user: " << i.first << std::endl;
+                       i.second.printContent();
+               }
+
+               for (const auto& i : group) {
+                       std::cerr << "group: " << i.first << std::endl;
+                       i.second.printContent();
+               }
+       }
+
+       size_t getSize() const {
+               size_t size = user.size() * sizeof(typename decltype(user)::value_type);
+               for (const auto& i : user)
+                       size += i.second.getSize();
+
+               size += group.size() * sizeof(typename decltype(group)::value_type);
+               for (const auto& i : group)
+                       size += i.second.getSize();
+               return size;
+       }
+
+public:
+       const P *getPolicyUser(uid_t uid) const {
+               tslog::log("---policy_type = USER =", uid, "\n");
+
+               auto it = user.find(uid);
+               if (it == user.end()) {
+                       tslog::log_verbose("GetPolicy: Out of Range exception\n");
+                       return nullptr;
+               }
+               return &(it->second);
+       }
+
+       const P *getPolicyGroup(gid_t gid) const {
+               tslog::log("---policy_type = GROUP = ", gid, "\n");
+
+               auto it = group.find(gid);
+               if (it == group.end()) {
+                       tslog::log_verbose("GetPolicy: Out of Range exception\n");
+                       return nullptr;
+               }
+               return &(it->second);
+       }
+
+       const std::map<uid_t, P> &getPoliciesUser() const { return user; }
+       const std::map<uid_t, P> &getPoliciesGroup() const { return group; }
+};
+
+/****************** NoUserAndGroupContext ************************/
+class NoUserAndGroupContext {
+protected:
+       template <typename T>
+       void addItemUser(uid_t, T &) { assert(false); }
+
+       template <typename T>
+       void addItemGroup(gid_t, T &) { assert(false); }
+
+       void printContent() const {}
+       size_t getSize() const { return 0; }
+};
+
+/****************** PolicySet ************************/
+template<typename P, typename UG = UserAndGroupContext<P>>
+class PolicySet : public UG {
+       /** Policies for all contexts */
+       P contextMandatory;
+       P contextDefault;
+
+       P &getPolicyContext(ContextType type) {
+               if (ContextType::MANDATORY == type)
+                       return contextMandatory;
+
+               assert(ContextType::DEFAULT == type);
+               return contextDefault;
+       }
+
+public:
+       typedef P policy_type;
+       /** Adds given item to policy
+        * \param[in] policy_type Policy type
+        * \param[in] policy_type_value Policy type value
+        * \param[in] item Item to add
+       */
+       template<typename T>
+       void addItem(const PolicyType policy_type,
+                                const PolicyTypeValue policy_type_value,
+                                T &item) {
+               switch (policy_type) {
+                       case PolicyType::CONTEXT:
+                               getPolicyContext(policy_type_value.context).addItem(item);
+                               break;
+                       case PolicyType::USER:
+                               UG::addItemUser(policy_type_value.user, item);
+                               break;
+                       case PolicyType::GROUP:
+                               UG::addItemGroup(policy_type_value.group, item);
+                               break;
+                       case PolicyType::NONE:
+                               assert(false);
+                               break;
+               }
+       }
+
+       const P &getRefPolicyContextMandatory() const { return contextMandatory; }
+       const P &getRefPolicyContextDefault() const { return contextDefault; }
+
+       const P *getPolicyContextMandatory() const {
+               tslog::log("---policy_type = CONTEXT = MANDATORY\n");
+               return &contextMandatory;
+       }
+
+       const P *getPolicyContextDefault() const {
+               tslog::log("---policy_type = CONTEXT = DEFAULT\n");
+               return &contextDefault;
+       }
+
+       void printSet() const {
+               std::cerr << "context default" << std::endl;
+               contextDefault.printContent();
+               std::cerr << "context mandatory" << std::endl;
+               contextMandatory.printContent();
+
+               UG::printContent();
+
+               std::cerr << "Memory consumption: " << getSetSize() << " B" << std::endl;
+       }
+
+       size_t getSetSize() const {
+               size_t size = sizeof(*this);
+
+               size += contextMandatory.getSize();
+               size += contextDefault.getSize();
+
+               size += UG::getSize();
+               return size;
+       }
+};
+
+/****************** StorageBackendXML ************************/
+class StorageBackendXML::StorageBackendXMLImpl {
+public:
+       /** Set of ownership policies */
+       PolicySet<PolicyOwn> m_own_set;
+       /** Set of send policies */
+       PolicySet<PolicySend> m_send_set;
+       /** Set of receive policies */
+       PolicySet<PolicyReceive> m_receive_set;
+       /** Set of bus access policies */
+       PolicySet<PolicyAccess, NoUserAndGroupContext> m_access_set;
+
+       template <typename T>
+       struct MatchPolicy; // provide policy_type in specializations
+
+       template <typename T>
+       const typename MatchPolicy<T>::policy_set_type &getPolicySet() const;
+       template <typename T>
+       typename MatchPolicy<T>::policy_set_type &getPolicySet();
+
+       template <typename T,
+                         typename P = typename MatchPolicy<T>::policy_type,
+                         typename PS = typename MatchPolicy<T>::policy_set_type,
+                         typename ...Args>
+       DecisionItem getDecisionItem(const T &item,
+                                                                const P *(PS::*f)(Args ... args) const,
+                                                                Args ...args) const;
+};
+
+/* Tie MatchItems with proper policy sets.
+ * Parameters: T - MatchItem* type
+ *             field - one of m_*_set fields from StorageBackendXMLImpl
+ *
+ * The below DEF_GET_POLICY_SET defines specialization for MatchPolicy<T> template,
+ * and a specialization of StorageBackendXMLImpl::getPolicySet template function
+ *
+ * Specialization for MatchPolicy<T> provides field 'policy_type' which specifies
+ * a type of policy used within 'field' parameter, and field 'policy_set_type'
+ * which specifies a type of the 'field' parameter.
+ * Specialization of StorageBackendXMLImpl::getPolicySet returns the 'field'.
+ *
+ * For example: DEF_GET_POLICY_SET(MatchItemOwn, m_own_set) defines equivalent to
+ * MatchPolicy<MatchItemOwn> {
+ *             typedef PolicyOwn policy_type;
+ *             typedef PolicySet<PolicyOwn> policy_set_type;
+ * }
+ * PolicySet<PolicyOwn> &getPolicySet<MatchItemOwn> const;
+ *
+ * Thanks to this construction we do not need to manually specify PolicyOwn in functions that
+ * know MatchItemOwn - it is inferred.
+ *
+ */
+#define DEF_GET_POLICY_SET(T, field) \
+       template <>     struct StorageBackendXML::StorageBackendXMLImpl::MatchPolicy<T> { \
+               typedef decltype(field)::policy_type policy_type; \
+               typedef decltype(field) policy_set_type; \
+       }; \
+       template <>     struct StorageBackendXML::StorageBackendXMLImpl::MatchPolicy<typename decltype(StorageBackendXML::StorageBackendXMLImpl::field)::policy_type> { \
+               typedef decltype(field) policy_set_type; \
+       }; \
+       template <> \
+       auto StorageBackendXML::StorageBackendXMLImpl::getPolicySet<T>() const -> decltype((field)) { \
+               return field; \
+       } \
+       template <> \
+       auto StorageBackendXML::StorageBackendXMLImpl::getPolicySet<T>() -> decltype((field)) { \
+               return field; \
+       } \
+       template <> \
+       auto StorageBackendXML::StorageBackendXMLImpl::getPolicySet<typename decltype(StorageBackendXML::StorageBackendXMLImpl::field)::policy_type>() -> decltype((field)) { \
+               return field; \
+       }
+
+DEF_GET_POLICY_SET(MatchItemOwn, m_own_set)
+DEF_GET_POLICY_SET(MatchItemSend, m_send_set)
+DEF_GET_POLICY_SET(MatchItemReceive, m_receive_set)
+DEF_GET_POLICY_SET(MatchItemAccess, m_access_set)
+
+#undef DEF_GET_POLICY_SET
+
+template <typename T, typename P, typename PS, typename ...Args>
+DecisionItem StorageBackendXML::StorageBackendXMLImpl::getDecisionItem(const T &item,
+                                               const P *(PS::*f)(Args ... args) const,
+                                               Args ...args) const
+{
+       const auto &policySet = getPolicySet<T>();
+       typedef typename std::remove_reference<decltype(policySet)>::type PolicySetType;
+
+       auto policy = (policySet.*f)(args...);
+       if (nullptr == policy)
+               return Decision::ANY;
+
+       tslog::log_verbose("Checking ", PolicySetType::policy_type::name, " policy for: ", item, "\n");
+
+       return policy->getDecisionItem(item);
+}
+
+template <typename T>
+void StorageBackendXML::addItem(const ldp_xml_parser::PolicyType policy_type,
+                                                               const ldp_xml_parser::PolicyTypeValue policy_type_value,
+                                                               T &item) {
+       pimpl->getPolicySet<typename T::match_type>().addItem(policy_type, policy_type_value, item);
+}
+
+void StorageBackendXML::clear() {
+       pimpl.reset(new StorageBackendXMLImpl);
+}
+
+void StorageBackendXML::printContent() const {
+       #define PRINT_SET(x) \
+       std::cerr << std::endl << "----" #x "----" << std::endl; \
+       (x).printSet();
+
+       PRINT_SET(pimpl->m_own_set)
+       PRINT_SET(pimpl->m_send_set)
+       PRINT_SET(pimpl->m_receive_set)
+       PRINT_SET(pimpl->m_access_set)
+
+       #undef PRINT_SET
+}
+
+template <typename T>
+const T &StorageBackendXML::getPolicyContextMandatory() const {
+       return pimpl->getPolicySet<T>().getRefPolicyContextMandatory();
+}
+
+template <typename T>
+const T &StorageBackendXML::getPolicyContextDefault() const {
+       return pimpl->getPolicySet<T>().getRefPolicyContextDefault();
+}
+
+template <typename T>
+const std::map<uid_t, T> &StorageBackendXML::getPoliciesUser() const {
+       return pimpl->getPolicySet<T>().getPoliciesUser();
+}
+
+template <typename T>
+const std::map<gid_t, T> &StorageBackendXML::getPoliciesGroup() const {
+       return pimpl->getPolicySet<T>().getPoliciesGroup();
+}
+
+template <typename T>
+bool StorageBackendXML::existsPolicyForGroup(gid_t gid) const {
+       return pimpl->getPolicySet<T>().getPolicyGroup(gid) != nullptr;
+}
+
+template <typename T>
+ldp_xml_parser::DecisionItem StorageBackendXML::getDecisionItemContextMandatory(const T &item) const {
+       return pimpl->getDecisionItem<T>(item, &StorageBackendXMLImpl::MatchPolicy<T>::policy_set_type::getPolicyContextMandatory);
+}
+
+template <typename T>
+ldp_xml_parser::DecisionItem StorageBackendXML::getDecisionItemContextDefault(const T &item) const {
+       return pimpl->getDecisionItem<T>(item, &StorageBackendXMLImpl::MatchPolicy<T>::policy_set_type::getPolicyContextDefault);
+}
+
+template <typename T>
+ldp_xml_parser::DecisionItem StorageBackendXML::getDecisionItemUser(uid_t uid, const T &item) const {
+       return pimpl->getDecisionItem<T>(item, &StorageBackendXMLImpl::MatchPolicy<T>::policy_set_type::getPolicyUser, uid);
+}
+
+template <typename T>
+ldp_xml_parser::DecisionItem StorageBackendXML::getDecisionItemGroup(gid_t gid, const T &item) const {
+       return pimpl->getDecisionItem<T>(item, &StorageBackendXMLImpl::MatchPolicy<T>::policy_set_type::getPolicyGroup, gid);
+}
+
+StorageBackendXML::StorageBackendXML() : pimpl{new StorageBackendXMLImpl} {
+}
+
+StorageBackendXML::~StorageBackendXML() = default;
+
+/* Explicit instantiation is needed for used public template methods defined in this file.
+ */
+#define T_INSTANTIATION(T) \
+       template ldp_xml_parser::DecisionItem StorageBackendXML::getDecisionItemContextMandatory(const MatchItem##T &item) const; \
+       template ldp_xml_parser::DecisionItem StorageBackendXML::getDecisionItemContextDefault(const MatchItem##T &item) const; \
+       template void StorageBackendXML::addItem(const PolicyType policy_type, const PolicyTypeValue policy_type_value, Item##T &item); \
+       template const Policy##T &StorageBackendXML::getPolicyContextMandatory() const; \
+       template const Policy##T &StorageBackendXML::getPolicyContextDefault() const;
+
+T_INSTANTIATION(Own)
+T_INSTANTIATION(Send)
+T_INSTANTIATION(Receive)
+T_INSTANTIATION(Access)
+
+#undef T_INSTANTIATION
+
+#define T_INSTANTIATION(T) \
+       template bool StorageBackendXML::existsPolicyForGroup<MatchItem##T>(gid_t gid) const; \
+       template ldp_xml_parser::DecisionItem StorageBackendXML::getDecisionItemUser(uid_t uid, const MatchItem##T &item) const; \
+       template ldp_xml_parser::DecisionItem StorageBackendXML::getDecisionItemGroup(gid_t gid, const MatchItem##T &item) const; \
+       template const std::map<gid_t, Policy##T> &StorageBackendXML::getPoliciesGroup() const; \
+       template const std::map<uid_t, Policy##T> &StorageBackendXML::getPoliciesUser() const;
+
+T_INSTANTIATION(Own)
+T_INSTANTIATION(Send)
+T_INSTANTIATION(Receive)
+
+#undef T_INSTANTIATION
+
+} // namespace ldp_xml
diff --git a/src/internal/storage_backend_xml.hpp b/src/internal/storage_backend_xml.hpp
new file mode 100644 (file)
index 0000000..dd4cffc
--- /dev/null
@@ -0,0 +1,56 @@
+#pragma once
+
+#include "policy.hpp"
+#include <sys/types.h>
+#include <map>
+#include <memory>
+
+namespace ldp_xml {
+
+class StorageBackendXML {
+       class StorageBackendXMLImpl;
+       std::unique_ptr<StorageBackendXMLImpl> pimpl;
+public:
+       StorageBackendXML();
+       ~StorageBackendXML();
+
+       // This works with T set to MatchItemOwn, MatchItemSend, MatchItemReceive or MatchItemAccess
+       template <typename T>
+       void addItem(const ldp_xml_parser::PolicyType policy_type,
+                                const ldp_xml_parser::PolicyTypeValue policy_type_value,
+                                T &item);
+
+       void clear();
+
+       void printContent() const;
+
+       // The getPolicy*() methods are intended for Serializers to get
+       // access to policy structures.
+       // Supported template parameters are: PolicyOwn, PolicySend, PolicyReceive
+       // and for PolicyAccess only getPolicyContext*()
+       template <typename T>
+       const T &getPolicyContextMandatory() const;
+       template <typename T>
+       const T &getPolicyContextDefault() const;
+       template <typename T>
+       const std::map<uid_t, T> &getPoliciesUser() const;
+       template <typename T>
+       const std::map<gid_t, T> &getPoliciesGroup() const;
+
+       // This works with T set to MatchItemOwn, MatchItemSend or MatchItemReceive
+       // This is needed for filtering mapGroups. Check NaivePolicyDb.
+       template <typename T>
+       bool existsPolicyForGroup(gid_t gid) const;
+
+       // These work with T set to MatchItemOwn, MatchItemSend, MatchItemReceive or MatchItemAccess
+       template <typename T>
+       ldp_xml_parser::DecisionItem getDecisionItemContextMandatory(const T &item) const;
+       template <typename T>
+       ldp_xml_parser::DecisionItem getDecisionItemContextDefault(const T &item) const;
+       template <typename T>
+       ldp_xml_parser::DecisionItem getDecisionItemUser(uid_t uid, const T &item) const;
+       template <typename T>
+       ldp_xml_parser::DecisionItem getDecisionItemGroup(gid_t gid, const T &item) const;
+};
+
+}