From 9c132de68678926cd0d0c3d3faf257cef23fc400 Mon Sep 17 00:00:00 2001 From: matzman Date: Thu, 7 May 2015 01:22:01 +0200 Subject: [PATCH] .X --- .../schema/core/configs/rulepackage.json | 4 +- src/hos_cosgi_rulesengine/CMakeLists.txt | 1 - .../hos_rulesexecution_service.h | 12 ++-- .../src/hos_rulesengine_service_impl.cpp | 36 +++++++++-- .../src/hos_rulesengine_service_impl.h | 8 ++- .../src/rulesengine/GlobalContext.cpp | 32 ---------- .../src/rulesengine/GlobalContext.h | 47 -------------- .../src/rulesengine/Rule.cpp | 27 +++++--- .../src/rulesengine/Rule.h | 24 ++++--- .../src/rulesengine/RuleCondition.cpp | 8 +-- .../src/rulesengine/RuleCondition.h | 62 ++++++++++++++++++- .../src/rulesengine/RulePackage.cpp | 43 +++++++------ .../src/rulesengine/RulePackage.h | 32 +++++++--- src/hos_cosgi_rulesengine/test/rulepkg01.json | 6 +- .../CMakeLists.txt | 5 +- .../src/bundle_activator.cpp | 1 + .../src/hos_rulesexecution_python_impl.cpp | 43 +++++++++++-- .../src/hos_rulesexecution_python_impl.h | 46 ++++++++++++-- src/hos_launch/launch/hos_cosgi.launch | 3 + 19 files changed, 279 insertions(+), 161 deletions(-) delete mode 100644 src/hos_cosgi_rulesengine/src/rulesengine/GlobalContext.cpp delete mode 100644 src/hos_cosgi_rulesengine/src/rulesengine/GlobalContext.h diff --git a/src/hos_core_types/schema/core/configs/rulepackage.json b/src/hos_core_types/schema/core/configs/rulepackage.json index 3373fb3b..9934ba65 100644 --- a/src/hos_core_types/schema/core/configs/rulepackage.json +++ b/src/hos_core_types/schema/core/configs/rulepackage.json @@ -22,7 +22,7 @@ "type": "object", "properties": { "body": { - "type": "string" + "type": "object" }, "conditions": { "type": "array", @@ -39,7 +39,7 @@ } }, "additionalProperties": false, - "required": [ "name", "conditions", "body" ] + "required": [ "conditions", "body" ] } } } diff --git a/src/hos_cosgi_rulesengine/CMakeLists.txt b/src/hos_cosgi_rulesengine/CMakeLists.txt index 587d3ede..0a86d339 100644 --- a/src/hos_cosgi_rulesengine/CMakeLists.txt +++ b/src/hos_cosgi_rulesengine/CMakeLists.txt @@ -122,7 +122,6 @@ bundle(hos_cosgi_rulesengine ${PROJECT_SOURCE_DIR}/src/bundle_activator ${PROJECT_SOURCE_DIR}/src/hos_rulesengine_service_impl ${PROJECT_SOURCE_DIR}/src/rulesengine/RulePackage - ${PROJECT_SOURCE_DIR}/src/rulesengine/GlobalContext ${PROJECT_SOURCE_DIR}/src/rulesengine/Rule ${PROJECT_SOURCE_DIR}/src/rulesengine/RuleCondition ) diff --git a/src/hos_cosgi_rulesengine/include/hos_cosgi_rulesengine/hos_rulesexecution_service.h b/src/hos_cosgi_rulesengine/include/hos_cosgi_rulesengine/hos_rulesexecution_service.h index 7d581d72..1d4a3110 100644 --- a/src/hos_cosgi_rulesengine/include/hos_cosgi_rulesengine/hos_rulesexecution_service.h +++ b/src/hos_cosgi_rulesengine/include/hos_cosgi_rulesengine/hos_rulesexecution_service.h @@ -11,16 +11,15 @@ #include #include +#include // Forward declarations -namespace XmlRpc { -class XmlRpcValue; -} namespace hos { namespace cosgi { namespace rulesengine { class RulePackage; +class Rule; } } } @@ -37,7 +36,8 @@ class GlobalExecutionContext : public COSGI_Object_Interface { class RuleBody : public COSGI_Object_Interface { - +public: + virtual void exec(GlobalExecutionContext* gContext) = 0; }; @@ -47,8 +47,8 @@ public: virtual std::string getLanguage() = 0; - virtual std::shared_ptr createGlobalExecutionContext(rulesengine::RulePackage* parent, XmlRpc::XmlRpcValue& raw) = 0; - virtual std::shared_ptr createRuleBody(rulesengine::RulePackage* parent, XmlRpc::XmlRpcValue& raw) = 0; + virtual std::shared_ptr createGlobalExecutionContext(rulesengine::RulePackage* parent, libvariant::Variant raw) = 0; + virtual std::shared_ptr createRuleBody(rulesengine::Rule* parent, GlobalExecutionContext* gContext, libvariant::Variant raw) = 0; }; diff --git a/src/hos_cosgi_rulesengine/src/hos_rulesengine_service_impl.cpp b/src/hos_cosgi_rulesengine/src/hos_rulesengine_service_impl.cpp index d4f5ed78..48a24139 100644 --- a/src/hos_cosgi_rulesengine/src/hos_rulesengine_service_impl.cpp +++ b/src/hos_cosgi_rulesengine/src/hos_rulesengine_service_impl.cpp @@ -14,6 +14,7 @@ #include #include #include "rulesengine/RulePackage.h" +#include namespace hos { @@ -49,6 +50,7 @@ void HOSRulesEngineServiceImpl::init() { nodehandle->getParam("rulesengine_prefix", ruleEnginePrefix); XmlRpc::XmlRpcValue rawValue; nodehandle->getParam(ruleEnginePrefix, rawValue); + schemaLoader.reset(new libvariant::HosSchemaLoader()); if (rawValue.getType() == XmlRpc::XmlRpcValue::TypeStruct) { for (auto pkg : rawValue) { std::string pname = pkg.first; @@ -86,13 +88,27 @@ void HOSRulesEngineServiceImpl::addRulePkg(std::string name) { ss << ruleEnginePrefix << "/" << name; XmlRpc::XmlRpcValue rawValue; nodehandle->getParam(ss.str(), rawValue); - addRulePkg(name, rawValue); + addRulePkg(name, static_cast(rawValue)); } -void HOSRulesEngineServiceImpl::addRulePkg(std::string name, XmlRpc::XmlRpcValue& rawValue) { - std::shared_ptr pkg = RulePackage::createRulePackage(*this, name, rawValue); - if (pkg) { - rulePkgs.insert({name, pkg}); +void HOSRulesEngineServiceImpl::addRulePkg(std::string name, std::string rawValue) { + ::libvariant::Variant s = schemaLoader->GetSchema(std::string("hos:schema://core/configs/rulepackage")); + ::libvariant::Variant m = ::libvariant::Deserialize(rawValue, ::libvariant::SERIALIZE_JSON); + ::libvariant::SchemaResult sr = ::libvariant::SchemaValidate(s, m, schemaLoader.get()); + if (!sr.Error()) { + std::shared_ptr pkg = RulePackage::createRulePackage(this, name, m); + if (pkg) { + if (pkg->getState() == RulePackage::State::Ok) { + rulePkgs.insert({name, pkg}); + } else if (pkg->getState() == RulePackage::State::NoExecService) { + noExecRulePkgs.insert({name, pkg}); + std::cout << "No execution service found for rule package \"" << name << "\"" << std::endl; + } else { + throw std::runtime_error("Unknown state"); + } + } + } else { + throw std::runtime_error(sr.PrettyPrintMessage()); } } @@ -107,6 +123,16 @@ void HOSRulesEngineServiceImpl::addExecutionBackend(rulesexecution::HOSRulesExec } } + +rulesexecution::HOSRulesExecutionService* HOSRulesEngineServiceImpl::getExecutionBackend(std::string language) { + auto s = execServices.find(language); + if (s != execServices.end()) { + return s->second; + } + return nullptr; +} + + } // namespace rulesengine } // namespace cosgi } // namespace hos diff --git a/src/hos_cosgi_rulesengine/src/hos_rulesengine_service_impl.h b/src/hos_cosgi_rulesengine/src/hos_rulesengine_service_impl.h index b4bd8dff..abecf2c7 100644 --- a/src/hos_cosgi_rulesengine/src/hos_rulesengine_service_impl.h +++ b/src/hos_cosgi_rulesengine/src/hos_rulesengine_service_impl.h @@ -20,6 +20,8 @@ #include #include +#include + #include #include @@ -66,12 +68,15 @@ private: std::string ruleEnginePrefix = "/hos/rules/rulesengine0"; rulePkgMap_t rulePkgs; + rulePkgMap_t noExecRulePkgs; execServiceMap_t execServices; + std::unique_ptr schemaLoader; + bool initialized = false; void addRulePkg(std::string name); - void addRulePkg(std::string name, XmlRpc::XmlRpcValue& rawValue); + void addRulePkg(std::string name, std::string rawValue); void removeRulePkg(std::string name); void init(); @@ -97,6 +102,7 @@ public: bool isInitialized() { return initialized; } void addExecutionBackend(rulesexecution::HOSRulesExecutionService* service); + rulesexecution::HOSRulesExecutionService* getExecutionBackend(std::string language); }; diff --git a/src/hos_cosgi_rulesengine/src/rulesengine/GlobalContext.cpp b/src/hos_cosgi_rulesengine/src/rulesengine/GlobalContext.cpp deleted file mode 100644 index fb63057b..00000000 --- a/src/hos_cosgi_rulesengine/src/rulesengine/GlobalContext.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * GlobalContext.cpp - * - * Created on: 29.04.2015 - * Author: matzman - */ - -#include "GlobalContext.h" -#include - -namespace hos { -namespace cosgi { -namespace rulesengine { - -GlobalContext::GlobalContext(RulePackage& parent) - : parent(parent) {} - -GlobalContext::~GlobalContext() { - // TODO Auto-generated destructor stub -} - -std::shared_ptr GlobalContext::createGlobalContext(RulePackage& parent, const XmlRpc::XmlRpcValue& raw) { - std::shared_ptr retval; - if (raw.getType() == XmlRpc::XmlRpcValue::TypeStruct) { - retval = std::make_shared(parent); - } - return retval; -} - -} /* namespace rulesengine */ -} /* namespace cosgi */ -} /* namespace hos */ diff --git a/src/hos_cosgi_rulesengine/src/rulesengine/GlobalContext.h b/src/hos_cosgi_rulesengine/src/rulesengine/GlobalContext.h deleted file mode 100644 index 56330174..00000000 --- a/src/hos_cosgi_rulesengine/src/rulesengine/GlobalContext.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * GlobalContext.h - * - * Created on: 29.04.2015 - * Author: matzman - */ - -#ifndef SRC_RULESENGINE_GLOBALCONTEXT_H_ -#define SRC_RULESENGINE_GLOBALCONTEXT_H_ - - -#include - - -// Forward declarations -namespace XmlRpc { -class XmlRpcValue; -} -namespace hos { -namespace cosgi { -namespace rulesengine { -class RulePackage; -} -} -} - - -namespace hos { -namespace cosgi { -namespace rulesengine { - -class GlobalContext { -private: - RulePackage& parent; -public: - GlobalContext(RulePackage& parent); - static std::shared_ptr createGlobalContext(RulePackage& parent, const XmlRpc::XmlRpcValue& raw); - virtual ~GlobalContext(); - - RulePackage& getParent() { return parent; } -}; - -} /* namespace rulesengine */ -} /* namespace cosgi */ -} /* namespace hos */ - -#endif /* SRC_RULESENGINE_GLOBALCONTEXT_H_ */ diff --git a/src/hos_cosgi_rulesengine/src/rulesengine/Rule.cpp b/src/hos_cosgi_rulesengine/src/rulesengine/Rule.cpp index 0c76213e..3da6bf67 100644 --- a/src/hos_cosgi_rulesengine/src/rulesengine/Rule.cpp +++ b/src/hos_cosgi_rulesengine/src/rulesengine/Rule.cpp @@ -7,6 +7,8 @@ #include "Rule.h" +#include "RuleCondition.h" +#include #include @@ -15,22 +17,23 @@ namespace cosgi { namespace rulesengine { -Rule::Rule(RulePackage& parent, std::string name) - : parent(parent), name(name) {} +Rule::Rule(RulePackage* parent, std::string name, rulesexecution::HOSRulesExecutionService* executionService) + : parent(parent), name(name), executionService(executionService) {} Rule::~Rule() {} -std::shared_ptr Rule::createRule(RulePackage& parent, std::string name, XmlRpc::XmlRpcValue& raw) { +std::shared_ptr Rule::createRule(RulePackage* parent, std::string name, rulesexecution::GlobalExecutionContext* gContext, libvariant::Variant raw, rulesexecution::HOSRulesExecutionService* executionService) { std::shared_ptr retval; - if (raw.getType() == XmlRpc::XmlRpcValue::TypeStruct) { - retval = std::make_shared(parent, name); - if (raw.hasMember("conditions") && raw["conditions"].getType() == XmlRpc::XmlRpcValue::TypeStruct) { + if (raw.IsMap()) { + retval = std::make_shared(parent, name, executionService); + if (raw.HasPath("conditions") && raw["conditions"].IsList()) { auto conditions = raw["conditions"]; - for (auto c : conditions) { - + for (auto c : conditions.AsList()) { + auto cond = RuleCondition::createRuleCondition(retval.get(), c); + retval->conditions.push_back(cond); } - if (raw.hasMember("body") && raw["body"].getType() == XmlRpc::XmlRpcValue::TypeString) { - + if (raw.HasPath("body") && raw["body"].IsMap()) { + retval->body = executionService->createRuleBody(retval.get(), gContext, raw["body"]); } else { ROS_ERROR_STREAM("Could not create rule \"" << name << "\"."); retval.reset(); @@ -43,6 +46,10 @@ std::shared_ptr Rule::createRule(RulePackage& parent, std::string name, Xm return retval; } +void Rule::exec(rulesexecution::GlobalExecutionContext* gContext) { + body->exec(gContext); +} + } /* namespace rulesengine */ } /* namespace cosgi */ diff --git a/src/hos_cosgi_rulesengine/src/rulesengine/Rule.h b/src/hos_cosgi_rulesengine/src/rulesengine/Rule.h index 527100aa..aab5dbd5 100644 --- a/src/hos_cosgi_rulesengine/src/rulesengine/Rule.h +++ b/src/hos_cosgi_rulesengine/src/rulesengine/Rule.h @@ -12,19 +12,22 @@ #include #include #include +#include // Forward declarations -namespace XmlRpc { -class XmlRpcValue; -} namespace hos { namespace cosgi { namespace rulesengine { class RulePackage; -class RuleBody; +class Rule; class RuleCondition; } +namespace rulesexecution { +class HOSRulesExecutionService; +class GlobalExecutionContext; +class RuleBody; +} } } @@ -36,16 +39,19 @@ namespace rulesengine { class Rule { private: - RulePackage& parent; + RulePackage* parent; std::string name; - std::shared_ptr body; + std::shared_ptr body; std::vector> conditions; + rulesexecution::HOSRulesExecutionService* executionService; public: - Rule(RulePackage& parent, std::string name); - static std::shared_ptr createRule(RulePackage& parent, std::string name, XmlRpc::XmlRpcValue& raw); + Rule(RulePackage* parent, std::string name, rulesexecution::HOSRulesExecutionService* executionService); + static std::shared_ptr createRule(RulePackage* parent, std::string name, rulesexecution::GlobalExecutionContext* gContext, libvariant::Variant raw, rulesexecution::HOSRulesExecutionService* executionService); virtual ~Rule(); - RulePackage& getParent() { return parent; } + RulePackage* getParent() { return parent; } + + virtual void exec(rulesexecution::GlobalExecutionContext* gContext); }; class RuleBody { diff --git a/src/hos_cosgi_rulesengine/src/rulesengine/RuleCondition.cpp b/src/hos_cosgi_rulesengine/src/rulesengine/RuleCondition.cpp index 46677864..27d72a0a 100644 --- a/src/hos_cosgi_rulesengine/src/rulesengine/RuleCondition.cpp +++ b/src/hos_cosgi_rulesengine/src/rulesengine/RuleCondition.cpp @@ -11,14 +11,12 @@ namespace hos { namespace cosgi { namespace rulesengine { -RuleCondition::RuleCondition() { - // TODO Auto-generated constructor stub +std::shared_ptr RuleCondition::createRuleCondition(Rule* parent, libvariant::Variant raw) { + std::shared_ptr retval; + return retval; } -RuleCondition::~RuleCondition() { - // TODO Auto-generated destructor stub -} } /* namespace rulesengine */ } /* namespace cosgi */ diff --git a/src/hos_cosgi_rulesengine/src/rulesengine/RuleCondition.h b/src/hos_cosgi_rulesengine/src/rulesengine/RuleCondition.h index d1d8c91a..48f00401 100644 --- a/src/hos_cosgi_rulesengine/src/rulesengine/RuleCondition.h +++ b/src/hos_cosgi_rulesengine/src/rulesengine/RuleCondition.h @@ -8,16 +8,74 @@ #ifndef SRC_RULESENGINE_RULECONDITION_H_ #define SRC_RULESENGINE_RULECONDITION_H_ +#include +#include + + +// Forward declarations +namespace hos { +namespace cosgi { +namespace rulesengine { +class Rule; +} +} +} + + namespace hos { namespace cosgi { namespace rulesengine { + + class RuleCondition { public: - RuleCondition(); - virtual ~RuleCondition(); + enum class Type : int { DeviceMsgCondition, DeviceStatusCondition, TimeEventCondition, SystemEventCondition}; +private: + Rule* parent; + const Type type; +public: + static std::shared_ptr createRuleCondition(Rule* parent, libvariant::Variant raw); +public: + RuleCondition(Rule* parent, Type type) : parent(parent), type(type) {} + virtual ~RuleCondition() {} + + const Type getType() { return type; } }; + + +class DeviceMsgCondition : public RuleCondition { +friend class RuleCondition; +public: + DeviceMsgCondition(Rule* parent) : RuleCondition(parent, Type::DeviceMsgCondition) {} +}; + + + +class DeviceStatusCondition : public RuleCondition { +friend class RuleCondition; +public: + DeviceStatusCondition(Rule* parent) : RuleCondition(parent, Type::DeviceStatusCondition) {} +}; + + + +class TimeEventCondition : public RuleCondition { +friend class RuleCondition; +public: + TimeEventCondition(Rule* parent) : RuleCondition(parent, Type::TimeEventCondition) {} +}; + + + +class SystemEventCondition : public RuleCondition { +friend class RuleCondition; +public: + SystemEventCondition(Rule* parent) : RuleCondition(parent, Type::SystemEventCondition) {} +}; + + } /* namespace rulesengine */ } /* namespace cosgi */ } /* namespace hos */ diff --git a/src/hos_cosgi_rulesengine/src/rulesengine/RulePackage.cpp b/src/hos_cosgi_rulesengine/src/rulesengine/RulePackage.cpp index f698ae7d..820565cc 100644 --- a/src/hos_cosgi_rulesengine/src/rulesengine/RulePackage.cpp +++ b/src/hos_cosgi_rulesengine/src/rulesengine/RulePackage.cpp @@ -6,45 +6,52 @@ */ #include "RulePackage.h" -#include "GlobalContext.h" #include "Rule.h" #include #include +#include +#include "../hos_rulesengine_service_impl.h" namespace hos { namespace cosgi { namespace rulesengine { -RulePackage::RulePackage(HOSRulesEngineServiceImpl& parent, std::string name) +RulePackage::RulePackage(HOSRulesEngineServiceImpl* parent, std::string name) : parent(parent), name(name) {} RulePackage::~RulePackage() { } -std::shared_ptr RulePackage::createRulePackage(HOSRulesEngineServiceImpl& parent, std::string name, XmlRpc::XmlRpcValue& raw) { +std::shared_ptr RulePackage::createRulePackage(HOSRulesEngineServiceImpl* parent, std::string name, ::libvariant::Variant raw) { std::shared_ptr retval; - if (raw.getType() == XmlRpc::XmlRpcValue::TypeStruct) { + if (raw.IsMap()) { retval = std::make_shared(parent, name); - if (raw.hasMember("language") && raw["language"].getType() == XmlRpc::XmlRpcValue::TypeString) { - retval->language = static_cast(raw["language"]); + if (raw.HasPath("language") && raw["language"].IsString()) { + retval->language = raw["language"].AsString(); } else { throw std::runtime_error("Rule package JSON is missing language parameter or parameter has wrong type."); } - if (raw.hasMember("globalcontext")) { - retval->globalContext = GlobalContext::createGlobalContext(*retval, raw["globalcontext"]); - } - if (raw.hasMember("rules") && raw["rules"].getType() == XmlRpc::XmlRpcValue::TypeStruct) { - for (auto r : raw["rules"]) { - std::shared_ptr rule = Rule::createRule(*retval, r.first, r.second); - if (rule) { - retval->rules.insert({r.first, rule}); + retval->executionService = parent->getExecutionBackend(retval->language); + if (retval->executionService) { + if (raw.HasPath("globalcontext")) { + retval->globalContext = retval->executionService->createGlobalExecutionContext(retval.get(), raw["globalcontext"]); + } + if (raw.HasPath("rules") && raw["rules"].IsMap()) { + for (auto r : raw["rules"].AsMap()) { + std::shared_ptr rule = Rule::createRule(retval.get(), r.first, retval->globalContext.get(), r.second, retval->executionService); + if (rule) { + retval->rules.insert({r.first, rule}); + } } + if (retval->rules.size() == 0) { + throw std::runtime_error("Rule package has no rules."); + } + } else { + throw std::runtime_error("Rule package JSON is missing rules parameter or parameter has wrong type."); } - if (retval->rules.size() == 0) { - throw std::runtime_error("Rule package has no rules."); - } + retval->setState(State::Ok); } else { - throw std::runtime_error("Rule package JSON is missing rules parameter or parameter has wrong type."); + retval->setState(State::NoExecService); } } else { throw std::runtime_error("Rule package JSON is not valid."); diff --git a/src/hos_cosgi_rulesengine/src/rulesengine/RulePackage.h b/src/hos_cosgi_rulesengine/src/rulesengine/RulePackage.h index a8281f94..2213e1a7 100644 --- a/src/hos_cosgi_rulesengine/src/rulesengine/RulePackage.h +++ b/src/hos_cosgi_rulesengine/src/rulesengine/RulePackage.h @@ -13,19 +13,20 @@ #include #include #include +#include +#include // Forward declarations -namespace XmlRpc { -class XmlRpcValue; -} namespace hos { namespace cosgi { namespace rulesengine { class HOSRulesEngineServiceImpl; -class GlobalContext; class Rule; } +namespace rulesexecution { +class GlobalExecutionContext; +} } } @@ -35,25 +36,38 @@ namespace cosgi { namespace rulesengine { class RulePackage { +public: + enum class State : int { Error = 0, NoExecService = 1, Ok = 2 }; + private: typedef std::map> ruleMap_t; std::string name; std::string language; + State state = State::Error; ruleMap_t rules; - std::shared_ptr globalContext; - HOSRulesEngineServiceImpl& parent; + std::shared_ptr globalContext; + HOSRulesEngineServiceImpl* parent; + rulesexecution::HOSRulesExecutionService* executionService = nullptr; + + + bool setState(State state) { + this->state = state; + return true; + } public: - RulePackage(HOSRulesEngineServiceImpl& parent, std::string name); - static std::shared_ptr createRulePackage(HOSRulesEngineServiceImpl& parent, std::string name, XmlRpc::XmlRpcValue& raw); + RulePackage(HOSRulesEngineServiceImpl* parent, std::string name); + static std::shared_ptr createRulePackage(HOSRulesEngineServiceImpl* parent, std::string name, ::libvariant::Variant raw); virtual ~RulePackage(); std::shared_ptr getRule(const std::string& name) { return rules[name]; } size_t getRules(std::vector>& rules); - HOSRulesEngineServiceImpl& getParent() { return parent; } + HOSRulesEngineServiceImpl* getParent() { return parent; } + + State getState() { return state; } }; } /* namespace rulesengine */ diff --git a/src/hos_cosgi_rulesengine/test/rulepkg01.json b/src/hos_cosgi_rulesengine/test/rulepkg01.json index b54d2d11..67a66629 100644 --- a/src/hos_cosgi_rulesengine/test/rulepkg01.json +++ b/src/hos_cosgi_rulesengine/test/rulepkg01.json @@ -1,6 +1,6 @@ { "language": "python", - "globalcontext": {}, + "globalcontext": { "code": "print \"GlobalContext: Init!\"\nvar1 = 66.6"}, "rules": { "rule01": { "conditions": [ @@ -13,7 +13,7 @@ "deviceid": "huelight1" } ], - "body": "print \"Hello World1\"" + "body": { "code": "print \"Hello World1\"" } }, "rule02": { "conditions": [ @@ -26,7 +26,7 @@ "deviceid": "huelight2" } ], - "body": "print \"Hello World2\"" + "body": { "code": "print \"Hello World2\"" } } } } \ No newline at end of file diff --git a/src/hos_cosgi_rulesexecution_python/CMakeLists.txt b/src/hos_cosgi_rulesexecution_python/CMakeLists.txt index ebdfb678..c4416ac8 100644 --- a/src/hos_cosgi_rulesexecution_python/CMakeLists.txt +++ b/src/hos_cosgi_rulesexecution_python/CMakeLists.txt @@ -24,7 +24,7 @@ find_package(catkin REQUIRED COMPONENTS find_package(APR REQUIRED) find_package(CELIX REQUIRED) -find_package(Boost REQUIRED) +find_package(Boost REQUIRED COMPONENTS python) ################################################ @@ -111,6 +111,7 @@ include_directories( ${APR_INCLUDE_DIR}/apr-1.0 include ${hos_libvariant_INCLUDE_DIRS}/hos_libvariant + /usr/include/python2.7 ) set(BUNDLE_SYMBOLICNAME "hos.hos_rulesexecution_python") @@ -125,6 +126,8 @@ bundle(hos_cosgi_rulesexecution_python target_link_libraries(hos_cosgi_rulesexecution_python ${catkin_LIBRARIES} ${APR_LIBRARIES} + ${Boost_LIBRARIES} + python2.7 ) ## Declare a cpp library diff --git a/src/hos_cosgi_rulesexecution_python/src/bundle_activator.cpp b/src/hos_cosgi_rulesexecution_python/src/bundle_activator.cpp index 1260a845..a73e7fd3 100644 --- a/src/hos_cosgi_rulesexecution_python/src/bundle_activator.cpp +++ b/src/hos_cosgi_rulesexecution_python/src/bundle_activator.cpp @@ -27,6 +27,7 @@ extern "C" { using namespace hos::cosgi::rulesengine; using namespace hos::cosgi::rulesexecution; +using namespace hos::cosgi::rulesexecution::python; using namespace hos::cosgi::devicerepository; using namespace hos::cosgi::core; using namespace hos::cosgi; diff --git a/src/hos_cosgi_rulesexecution_python/src/hos_rulesexecution_python_impl.cpp b/src/hos_cosgi_rulesexecution_python/src/hos_rulesexecution_python_impl.cpp index f06d911c..ec67e4ff 100644 --- a/src/hos_cosgi_rulesexecution_python/src/hos_rulesexecution_python_impl.cpp +++ b/src/hos_cosgi_rulesexecution_python/src/hos_rulesexecution_python_impl.cpp @@ -10,9 +10,11 @@ #include + namespace hos { namespace cosgi { namespace rulesexecution { +namespace python { void HOSRulesExecutionPythonImpl::setCoreService(core::HOSCoreService* coreService) { if (coreService && !this->coreService) { @@ -40,6 +42,12 @@ void HOSRulesExecutionPythonImpl::setRepoService(devicerepository::HOSDeviceRepo } void HOSRulesExecutionPythonImpl::init() { + Py_Initialize(); + boost::python::object main_module = boost::python::import("__main__"); + pyGlobalScope = main_module.attr("__dict__");// Load the sys module. + boost::python::object sys = boost::python::import("sys"); + std::string version = boost::python::extract(sys.attr("version")); + ROS_INFO_STREAM("RulesExecutionPythonService: Python Version: " << version); initialized = true; ROS_INFO_STREAM("RulesExecutionPythonService: Initialized and Ready."); } @@ -51,19 +59,44 @@ void HOSRulesExecutionPythonImpl::getServiceVersion(int& major, int& minor) { minor = SERVICE_VERSION_MINOR; } -std::shared_ptr HOSRulesExecutionPythonImpl::createGlobalExecutionContext(rulesengine::RulePackage* parent, XmlRpc::XmlRpcValue& raw) { - std::shared_ptr retval; - return retval; +std::shared_ptr HOSRulesExecutionPythonImpl::createGlobalExecutionContext(rulesengine::RulePackage* parent, libvariant::Variant raw) { + std::shared_ptr retval; + if (raw.HasPath("code") && raw["code"].IsString()) { + retval = std::make_shared(this->pyGlobalScope, raw["code"].AsString()); + try { + boost::python::object result = boost::python::exec(retval->getCode().c_str(), pyGlobalScope); + } catch(boost::python::error_already_set const &) { + PyErr_Print(); + throw std::runtime_error("Python error during global context creation."); + } + } + return std::static_pointer_cast(retval); } -std::shared_ptr HOSRulesExecutionPythonImpl::createRuleBody(rulesengine::RulePackage* parent, XmlRpc::XmlRpcValue& raw) { +std::shared_ptr HOSRulesExecutionPythonImpl::createRuleBody(rulesengine::Rule* parent, GlobalExecutionContext* gContext, libvariant::Variant raw) { std::shared_ptr retval; - return retval; + if (raw.HasPath("code") && raw["code"].IsString()) { + retval = std::make_shared(raw["code"].AsString(), *this); + } + return std::static_pointer_cast(retval); } +void PyRuleBody::exec(GlobalExecutionContext* gContext) { + try { + boost::python::object& gcont = service.getPyGlobalScope(); + if (gContext) { + gcont = static_cast(gContext)->getPyGlobalContext(); + } + boost::python::object result = boost::python::exec(code.c_str(), gcont); + } catch(boost::python::error_already_set const &) { + PyErr_Print(); + throw std::runtime_error("Python error during global context creation."); + } +} +} // namespace python } // namespace rulesengine } // namespace cosgi } // namespace hos diff --git a/src/hos_cosgi_rulesexecution_python/src/hos_rulesexecution_python_impl.h b/src/hos_cosgi_rulesexecution_python/src/hos_rulesexecution_python_impl.h index 41caca8d..acb4eee2 100644 --- a/src/hos_cosgi_rulesexecution_python/src/hos_rulesexecution_python_impl.h +++ b/src/hos_cosgi_rulesexecution_python/src/hos_rulesexecution_python_impl.h @@ -11,12 +11,12 @@ #include #include #include +#include +#include +#include // Forward declarations -namespace XmlRpc { -class XmlRpcValue; -} namespace hos { namespace cosgi { namespace core { @@ -26,6 +26,11 @@ namespace devicerepository { class HOSDeviceRepositoryService; class DeviceEvent; } +namespace rulesexecution { +namespace python { +class HOSRulesExecutionPythonImpl; +} +} } } @@ -33,6 +38,33 @@ class DeviceEvent; namespace hos { namespace cosgi { namespace rulesexecution { +namespace python { + + + +class PyGlobalExecutionContext : public GlobalExecutionContext { +private: + boost::python::object& gContext; + std::string code; +public: + PyGlobalExecutionContext(boost::python::object& gContext, std::string code) + : gContext(gContext), code(code) {} + std::string getCode() { return code; } + boost::python::object& getPyGlobalContext() { return gContext; } +}; + + + +class PyRuleBody : public RuleBody { +private: + std::string code; + HOSRulesExecutionPythonImpl& service; +public: + PyRuleBody(std::string code, HOSRulesExecutionPythonImpl& service) : code(code), service(service) {} + std::string getCode() { return code; } + virtual void exec(GlobalExecutionContext* gContext); +}; + class HOSRulesExecutionPythonImpl : public HOSRulesExecutionService { @@ -41,6 +73,8 @@ private: devicerepository::HOSDeviceRepositoryService* repoService = nullptr;; ros::NodeHandle* nodehandle = nullptr; + boost::python::object pyGlobalScope; + bool initialized = false; void init(); @@ -62,17 +96,19 @@ public: virtual std::string getLanguage() { return LANGUAGE; } - virtual std::shared_ptr createGlobalExecutionContext(rulesengine::RulePackage* parent, XmlRpc::XmlRpcValue& raw); - virtual std::shared_ptr createRuleBody(rulesengine::RulePackage* parent, XmlRpc::XmlRpcValue& raw); + virtual std::shared_ptr createGlobalExecutionContext(rulesengine::RulePackage* parent, libvariant::Variant raw); + virtual std::shared_ptr createRuleBody(rulesengine::Rule* parent, GlobalExecutionContext* gContext, libvariant::Variant raw); /* Internal Stuff */ bool isInitialized() { return initialized; } + boost::python::object& getPyGlobalScope() { return pyGlobalScope; } }; +} // namespace python } // namespace rulesengine } // namespace cosgi } // namespace hos diff --git a/src/hos_launch/launch/hos_cosgi.launch b/src/hos_launch/launch/hos_cosgi.launch index c5c01430..54872c9a 100644 --- a/src/hos_launch/launch/hos_cosgi.launch +++ b/src/hos_launch/launch/hos_cosgi.launch @@ -1,4 +1,7 @@ + + +