.
This commit is contained in:
@@ -120,11 +120,14 @@ set(BUNDLE_NAME "hos_ruleengine")
|
||||
|
||||
bundle(hos_cosgi_ruleengine
|
||||
SOURCES
|
||||
${PROJECT_SOURCE_DIR}/src/bundle_activator
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/ruleengine_serviceimpl
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rule/RulePackage
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rule/Rule
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rule/RuleConditionImpl
|
||||
${PROJECT_SOURCE_DIR}/src/BundleActivator
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/RuleEngineServiceImpl
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/RulePackageImpl
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/RuleImpl
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/LogicalOrCondition
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/LogicalAndCondition
|
||||
${PROJECT_SOURCE_DIR}/src/hos/cosgi/service/ruleengine/rules/conditions/DeviceMsgCondition
|
||||
)
|
||||
target_link_libraries(hos_cosgi_ruleengine
|
||||
${catkin_LIBRARIES}
|
||||
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
|
||||
// forward declarations
|
||||
namespace libvariant { class Variant; }
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
|
||||
|
||||
// forward declarations
|
||||
namespace rules {
|
||||
class RulePackage;
|
||||
class Rule;
|
||||
namespace conditions { class RuleCondition; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public abstract COSGI interface of a rule condition factory.
|
||||
*/
|
||||
class RuleConditionFactory
|
||||
: public virtual interface::Object {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Creates and returns a condition from the given json config.
|
||||
*
|
||||
* \param[in] parent parent rule
|
||||
* \param[in] json config
|
||||
* \return new rule condition
|
||||
*/
|
||||
virtual std::shared_ptr<rules::conditions::RuleCondition> createCondition(rules::Rule* parent, const libvariant::Variant& raw) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of the rule engine service.
|
||||
*/
|
||||
class RuleEngineService
|
||||
: public virtual interface::Service {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* The service name.
|
||||
*/
|
||||
static constexpr const char* SERVICE_NAME = "hos_ruleengine_service";
|
||||
|
||||
/**
|
||||
* Returns the rulepackage with the given name.
|
||||
*
|
||||
* \param[in] name name
|
||||
* \return weak reference to rule package (an expired reference is returned if the wanted rule package does not exists).
|
||||
*/
|
||||
virtual std::weak_ptr<rules::RulePackage> getRulePackage(const std::string& name) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns a vector containing all known rulepackages.
|
||||
*
|
||||
* \return vector of weak references.
|
||||
*/
|
||||
virtual std::vector<std::weak_ptr<rules::RulePackage>> getRulePackages() noexcept = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of known rule packages.
|
||||
*
|
||||
* \return rule package count.
|
||||
*/
|
||||
virtual size_t getRulePackageCount() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Registers a rule condition factory under the given type identifier.
|
||||
*
|
||||
* \param[in] type condition type identifier.
|
||||
* \param[in] factory rule condition factory.
|
||||
*/
|
||||
virtual void registerRuleConditionFactory(const std::string& type, std::shared_ptr<RuleConditionFactory> factory) noexcept = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace ruleengine
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
|
||||
-94
@@ -1,94 +0,0 @@
|
||||
/*
|
||||
* Rule.h
|
||||
*
|
||||
* Created on: 29.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULE_H_
|
||||
#define SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULE_H_
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <Variant/Variant.h>
|
||||
#include "RuleCondition.h"
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace devicerepository {
|
||||
class Device;
|
||||
class DeviceEvent;
|
||||
class DeviceRepositoryService;
|
||||
}
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
class RulePackage;
|
||||
}
|
||||
}
|
||||
namespace scripting {
|
||||
class ScriptingService;
|
||||
class GlobalScriptContext;
|
||||
class Script;
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace utils {
|
||||
class SchemaLoader;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
|
||||
using namespace ::libvariant;
|
||||
|
||||
class Rule {
|
||||
private:
|
||||
std::shared_ptr<scripting::Script> script;
|
||||
std::shared_ptr<scripting::Script> exitScript;
|
||||
std::shared_ptr<RuleCondition> condition;
|
||||
bool enabled = false;
|
||||
bool currentState = false;
|
||||
|
||||
public:
|
||||
RulePackage* const parent;
|
||||
const std::string name;
|
||||
|
||||
Rule(RulePackage* parent, const std::string name);
|
||||
static std::shared_ptr<Rule> createRule(RulePackage* parent, const std::string name, Variant raw);
|
||||
|
||||
bool getCurrentState() { return currentState; }
|
||||
bool evaluate();
|
||||
void execute(Variant lContext = Variant());
|
||||
void executeExitScript(Variant lContext = Variant());
|
||||
|
||||
bool isEnabled() { return enabled; }
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
void conditionStateChanged(bool newState, RuleCondition::Category category, Variant lcontext = Variant());
|
||||
|
||||
std::shared_ptr<RuleCondition> createRuleCondition(Variant raw);
|
||||
|
||||
utils::SchemaLoader* getHOSSchemaLoader();
|
||||
devicerepository::DeviceRepositoryService* getDeviceRepository();
|
||||
};
|
||||
|
||||
|
||||
} /* namespace rule */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
|
||||
#endif /* SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULE_H_ */
|
||||
-105
@@ -1,105 +0,0 @@
|
||||
/*
|
||||
* RuleCondition.h
|
||||
*
|
||||
* Created on: 29.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITION_H_
|
||||
#define SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITION_H_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
|
||||
class Rule;
|
||||
class RuleCompositeCondition;
|
||||
|
||||
using namespace ::libvariant;
|
||||
|
||||
|
||||
class RuleCondition {
|
||||
public:
|
||||
enum class Category : int { Event, State, Mixed };
|
||||
|
||||
protected:
|
||||
bool currentState = false;
|
||||
Category category;
|
||||
RuleCompositeCondition* compositeParent = nullptr;
|
||||
bool enabled = false;
|
||||
|
||||
void notifyStateChangeToParent(bool newState, Category category, Variant lcontext = Variant());
|
||||
|
||||
public:
|
||||
Rule* const parent;
|
||||
const std::string type;
|
||||
|
||||
RuleCondition(Rule* parent, Category category, const std::string type) :
|
||||
parent(parent), category(category), type(type) {}
|
||||
virtual ~RuleCondition() {}
|
||||
void setCompositeParent(RuleCompositeCondition* compositeParent) {
|
||||
this->compositeParent = compositeParent;
|
||||
}
|
||||
|
||||
virtual Category getCategory() { return category; }
|
||||
|
||||
bool getCurrentState() { return currentState; }
|
||||
virtual bool evaluate() { return currentState; }
|
||||
|
||||
bool isEnabled() { return enabled; }
|
||||
virtual void enable() { enabled = true; }
|
||||
virtual void disable() { enabled = false; }
|
||||
};
|
||||
|
||||
|
||||
class RuleCompositeCondition : public RuleCondition {
|
||||
protected:
|
||||
std::vector<std::shared_ptr<RuleCondition>> children;
|
||||
public:
|
||||
RuleCompositeCondition(Rule* parent, Category category, std::string type) :
|
||||
RuleCondition(parent, category, type) {}
|
||||
|
||||
virtual void childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext = Variant()) = 0;
|
||||
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) {
|
||||
if (child) {
|
||||
child->setCompositeParent(this);
|
||||
children.push_back(child);
|
||||
}
|
||||
};
|
||||
|
||||
virtual void enable() {
|
||||
if (!enabled) {
|
||||
for (auto c : children) {
|
||||
c->enable();
|
||||
}
|
||||
enabled = true;
|
||||
}
|
||||
}
|
||||
virtual void disable() {
|
||||
if (enabled) {
|
||||
for (auto c : children) {
|
||||
c->disable();
|
||||
}
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
} /* namespace rule */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
#endif /* SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITION_H_ */
|
||||
-49
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* hos_ruleengine_service.h
|
||||
*
|
||||
* Created on: 26.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_HOS_COSGI_RULEENGINE_HOS_COSGI_SERVICE_RULEENGINE_RULEENGINE_SERVICE_H_
|
||||
#define INCLUDE_HOS_COSGI_RULEENGINE_HOS_COSGI_SERVICE_RULEENGINE_RULEENGINE_SERVICE_H_
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <memory>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
|
||||
namespace rule {
|
||||
class RuleCondition;
|
||||
class Rule;
|
||||
}
|
||||
|
||||
class RuleConditionFactory : public virtual interface::Object {
|
||||
public:
|
||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, ::libvariant::Variant raw) = 0;
|
||||
};
|
||||
|
||||
|
||||
class RuleEngineService : public virtual interface::Service {
|
||||
public:
|
||||
static constexpr const char* SERVICE_NAME = "hos_ruleengine_service";
|
||||
|
||||
virtual void registerRuleConditionFactory(std::string type, std::shared_ptr<RuleConditionFactory> factory) = 0;
|
||||
};
|
||||
|
||||
|
||||
} // namespace ruleengine
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_HOS_COSGI_RULEENGINE_HOS_COSGI_SERVICE_RULEENGINE_RULEENGINE_SERVICE_H_ */
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
|
||||
|
||||
// forward declarations
|
||||
namespace devicerepository { class DeviceRepositoryService; }
|
||||
|
||||
|
||||
// main namespace
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace conditions {
|
||||
class RuleCondition;
|
||||
enum class ConditionTriggerType : int;
|
||||
}
|
||||
class RulePackage;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of a rule.
|
||||
*/
|
||||
class Rule
|
||||
: public virtual interface::Object {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Returns a reference to the parent rule package.
|
||||
*
|
||||
* \return rule package.
|
||||
*/
|
||||
virtual RulePackage* getParent() noexcept = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the rule.
|
||||
*
|
||||
* \return name.
|
||||
*/
|
||||
virtual const std::string& getName() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns whether the rule is currently active.
|
||||
*
|
||||
* Only conditions of trigger type "state" can activate a rule.
|
||||
*
|
||||
* \return whether rule is active.
|
||||
*/
|
||||
virtual bool isActive() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Evaluates the conditions of the rule and may execute associated scripts.
|
||||
*
|
||||
* Only active conditions of trigger type "state" can return true here.
|
||||
*
|
||||
* May return exceptions derived from std::exception.
|
||||
*
|
||||
* \return evaluation result.
|
||||
*/
|
||||
virtual bool evaluate() = 0;
|
||||
|
||||
/**
|
||||
* Executes the associated script.
|
||||
*
|
||||
* May return exceptions derived from std::exception.
|
||||
*
|
||||
* \param[in] local context.
|
||||
*/
|
||||
virtual void executeScript(const libvariant::Variant& lContext = libvariant::Variant()) = 0;
|
||||
|
||||
/**
|
||||
* Executes the associated exit script.
|
||||
*
|
||||
* May return exceptions derived from std::exception.
|
||||
*
|
||||
* \param[in] local context.
|
||||
*/
|
||||
virtual void executeExitScript(const libvariant::Variant& lContext = libvariant::Variant()) = 0;
|
||||
|
||||
/**
|
||||
* Returns whether this rule is enabled.
|
||||
*
|
||||
* \return enabled
|
||||
*/
|
||||
virtual bool isEnabled() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Enable/Disable this rule package.
|
||||
*
|
||||
* \param[in] enabled.
|
||||
*/
|
||||
virtual void setEnabled(bool enabled) noexcept = 0;
|
||||
|
||||
|
||||
/* Interface for third-party conditions. */
|
||||
|
||||
/**
|
||||
* Creates and returns a new condition based on the given json config.
|
||||
*
|
||||
* \param[in] json config.
|
||||
* \return new rule condition.
|
||||
*/
|
||||
virtual std::shared_ptr<conditions::RuleCondition> createRuleCondition(const libvariant::Variant& raw) = 0;
|
||||
|
||||
/**
|
||||
* Indicates that one of the conditions of the rule changed state.
|
||||
*
|
||||
* \param[in] newState new state.
|
||||
* \param[in] trigger trigger type.
|
||||
* \param[in] lcontext local context that should be passed to script.
|
||||
*/
|
||||
virtual void conditionStateChanged(bool newState, const conditions::ConditionTriggerType& trigger,
|
||||
const libvariant::Variant& lcontext = libvariant::Variant()) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns a reference to the device repository service.
|
||||
*
|
||||
* \return device repository service.
|
||||
*/
|
||||
virtual devicerepository::DeviceRepositoryService* getDeviceRepository() noexcept = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace hos { namespace cosgi { namespace service {
|
||||
namespace scripting { class ScriptingService; }
|
||||
namespace scripting { class GlobalScriptContext; }
|
||||
} } }
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
|
||||
|
||||
// Forward declarations
|
||||
class RuleEngineService;
|
||||
|
||||
|
||||
// main namespace
|
||||
namespace rules {
|
||||
|
||||
|
||||
// Forward declarations
|
||||
class Rule;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of a rule package.
|
||||
*/
|
||||
class RulePackage
|
||||
: public virtual interface::Object {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Returns a reference to the rule engine service.
|
||||
*
|
||||
* \return rule engine service.
|
||||
*/
|
||||
virtual service::ruleengine::RuleEngineService* getParent() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the name of the rule package.
|
||||
*
|
||||
* \return name.
|
||||
*/
|
||||
virtual const std::string& getName() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns an identifier indicating the scripting language.
|
||||
*
|
||||
* \return scripting language identifier.
|
||||
*/
|
||||
virtual const std::string& getLanguage() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the rule with the given name.
|
||||
*
|
||||
* \param[in] name rule name.
|
||||
* \return weak reference to rule (expired reference in case of rule not found).
|
||||
*/
|
||||
virtual std::weak_ptr<Rule> getRule(const std::string& name) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns all rules contained within the rule package
|
||||
*
|
||||
* \return vector of weak references.
|
||||
*/
|
||||
virtual std::vector<std::weak_ptr<Rule>> getRules() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the number of contained rules.
|
||||
*
|
||||
* \return rule count.
|
||||
*/
|
||||
virtual size_t getRuleCount() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns whether this rule package is enabled.
|
||||
*
|
||||
* \return enabled
|
||||
*/
|
||||
virtual bool isEnabled() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Enable/Disable this rule package.
|
||||
*
|
||||
* \param[in] enabled.
|
||||
*/
|
||||
virtual void setEnabled(bool enabled) noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns a reference to the associated scripting service.
|
||||
*
|
||||
* \return scripting service.
|
||||
*/
|
||||
virtual service::scripting::ScriptingService* getScriptingService() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns a reference to the associated global script context.
|
||||
*
|
||||
* \return global script context.
|
||||
*/
|
||||
virtual std::weak_ptr<scripting::GlobalScriptContext> getGlobalScriptContext() noexcept = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <hos/cosgi/service/Interface.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
|
||||
|
||||
// forward declarations
|
||||
class Rule;
|
||||
|
||||
|
||||
// main namespace
|
||||
namespace conditions {
|
||||
|
||||
|
||||
// forward declarations
|
||||
class RuleCompositeCondition;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Condition trigger type.
|
||||
*
|
||||
* Conditions can have two different trigger types:
|
||||
* - Event trigger: Conditions are triggered by events happening.
|
||||
* - State trigger: Condition are triggered by device state.
|
||||
*
|
||||
* "Both" indicates that an condition has both trigger types.
|
||||
**/
|
||||
enum class ConditionTriggerType : int {
|
||||
Event = 1,
|
||||
State = 2,
|
||||
Both = 3
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of a rule condition.
|
||||
*/
|
||||
class RuleCondition
|
||||
: public virtual interface::Object {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Returns the type of the condition.
|
||||
*
|
||||
* \return condition type.
|
||||
*/
|
||||
virtual const std::string& getType() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the trigger type of the condition.
|
||||
*
|
||||
* \return trigger type.
|
||||
*/
|
||||
virtual ConditionTriggerType getTriggerType() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns the current state of the condition.
|
||||
*
|
||||
* This function returns a cached value.
|
||||
*
|
||||
* \return current state.
|
||||
*/
|
||||
virtual bool getCurrentState() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Evaluates the condition and returns the result.
|
||||
*
|
||||
* \return evaluation result.
|
||||
*/
|
||||
virtual bool evaluate() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns a reference to the parent rule.
|
||||
*
|
||||
* \return parent rule.
|
||||
*/
|
||||
virtual rules::Rule* getParent() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Returns whether this rule condition is enabled.
|
||||
*
|
||||
* \return enabled.
|
||||
*/
|
||||
virtual bool isEnabled() noexcept = 0;
|
||||
|
||||
/**
|
||||
* Enable/Disable this rule condition.
|
||||
*
|
||||
* \param[in] enabled.
|
||||
*/
|
||||
virtual void setEnabled(bool enabled) noexcept = 0;
|
||||
|
||||
|
||||
/* Interface for third-party conditions. */
|
||||
|
||||
/**
|
||||
* Sets the composite condition this condition is contained within.
|
||||
*
|
||||
* \param[in] parent composite condition.
|
||||
*/
|
||||
virtual void setCompositeParent(RuleCompositeCondition* compositeParent) noexcept = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Public COSGI interface of a composite condition.
|
||||
*/
|
||||
class RuleCompositeCondition
|
||||
: public virtual RuleCondition {
|
||||
|
||||
public:
|
||||
|
||||
/* Interface for third-party conditions. */
|
||||
|
||||
/**
|
||||
* Indicates that a contained condition has changed its state.
|
||||
*
|
||||
* \param[in] child condition whose state has changed.
|
||||
* \param[in] newState new state.
|
||||
* \param[in] trigger trigger type.
|
||||
* \param[in] lcontext local context that should be passed to the script.
|
||||
*/
|
||||
virtual void childStateChanged( RuleCondition* child,
|
||||
bool newState,
|
||||
ConditionTriggerType trigger,
|
||||
const libvariant::Variant& lcontext = libvariant::Variant() ) noexcept = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Adds a new condition.
|
||||
*
|
||||
* \param[in] child child condition.
|
||||
*/
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) = 0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+123
@@ -0,0 +1,123 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "RuleCondition.h"
|
||||
|
||||
|
||||
|
||||
// main namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Base class for condition implementations.
|
||||
*/
|
||||
class RuleConditionImpl
|
||||
: public virtual RuleCondition {
|
||||
|
||||
protected:
|
||||
|
||||
rules::Rule* parent;
|
||||
ConditionTriggerType triggerType;
|
||||
std::string type;
|
||||
|
||||
bool currentState = false;
|
||||
RuleCompositeCondition* compositeParent = nullptr;
|
||||
bool enabled = false;
|
||||
|
||||
void notifyStateChangeToParent(bool newState, ConditionTriggerType category, const libvariant::Variant& lcontext = libvariant::Variant());
|
||||
|
||||
public:
|
||||
|
||||
RuleConditionImpl(rules::Rule* parent, ConditionTriggerType triggerType, const std::string& type) :
|
||||
parent(parent), triggerType(triggerType), type(type) {}
|
||||
|
||||
virtual rules::Rule* getParent() noexcept override {
|
||||
return parent;
|
||||
}
|
||||
|
||||
virtual void setCompositeParent(RuleCompositeCondition* compositeParent) noexcept override {
|
||||
this->compositeParent = compositeParent;
|
||||
}
|
||||
|
||||
virtual const std::string& getType() noexcept override {
|
||||
return type;
|
||||
}
|
||||
|
||||
virtual ConditionTriggerType getTriggerType() noexcept override {
|
||||
return triggerType;
|
||||
}
|
||||
|
||||
virtual bool getCurrentState() noexcept override {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
virtual bool evaluate() noexcept override {
|
||||
return currentState;
|
||||
}
|
||||
|
||||
virtual bool isEnabled() noexcept override {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
virtual void setEnabled(bool enabled) noexcept override {
|
||||
this->enabled;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Base class for composite condition implementations.
|
||||
*/
|
||||
class RuleCompositeConditionImpl
|
||||
: public virtual RuleCompositeCondition,
|
||||
public RuleConditionImpl {
|
||||
|
||||
protected:
|
||||
std::vector<std::shared_ptr<RuleCondition>> children;
|
||||
|
||||
public:
|
||||
|
||||
RuleCompositeConditionImpl(Rule* parent, ConditionTriggerType category, std::string type) :
|
||||
RuleConditionImpl(parent, category, type) {}
|
||||
|
||||
virtual void childStateChanged( RuleCondition* child,
|
||||
bool newState,
|
||||
ConditionTriggerType category,
|
||||
const libvariant::Variant& lcontext = libvariant::Variant() ) noexcept override = 0;
|
||||
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override {
|
||||
if (child) {
|
||||
child->setCompositeParent(this);
|
||||
children.push_back(child);
|
||||
}
|
||||
};
|
||||
|
||||
virtual void setEnabled(bool enabled) noexcept override {
|
||||
if (this->enabled != enabled) {
|
||||
for (auto c : children) {
|
||||
c->setEnabled(enabled);
|
||||
}
|
||||
this->enabled = enabled;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ extern "C" {
|
||||
}
|
||||
|
||||
#include <hos/cosgi/service/core/CoreService.h>
|
||||
#include "hos/cosgi/service/ruleengine/ruleengine_serviceimpl.h"
|
||||
#include "hos/cosgi/service/ruleengine/RuleEngineServiceImpl.h"
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
+29
-14
@@ -5,7 +5,6 @@
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#include "ruleengine_serviceimpl.h"
|
||||
#include <ros/ros.h>
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
@@ -16,8 +15,12 @@
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
#include "rule/RulePackage.h"
|
||||
#include "rule/RuleConditionImpl.h"
|
||||
#include "RuleEngineServiceImpl.h"
|
||||
|
||||
#include "rules/conditions/LogicalAndCondition.h"
|
||||
#include "rules/conditions/LogicalOrCondition.h"
|
||||
#include "rules/conditions/DeviceMsgCondition.h"
|
||||
#include "rules/RulePackageImpl.h"
|
||||
|
||||
|
||||
namespace hos {
|
||||
@@ -62,11 +65,11 @@ void RuleEngineServiceImpl::init() {
|
||||
XmlRpc::XmlRpcValue rawValue;
|
||||
nodehandle->getParam(ruleEnginePrefix, rawValue);
|
||||
schemaLoader.reset(new utils::SchemaLoader());
|
||||
registerRuleConditionFactory("logical_or", std::make_shared<rule::LogicalOrConditionFactory>());
|
||||
registerRuleConditionFactory("logical_and", std::make_shared<rule::LogicalAndConditionFactory>());
|
||||
registerRuleConditionFactory("devicestatusmsg", std::make_shared<rule::DeviceStatusMsgConditionFactory>());
|
||||
registerRuleConditionFactory("devicecommandmsg", std::make_shared<rule::DeviceCommandMsgConditionFactory>());
|
||||
registerRuleConditionFactory("devicestatechange", std::make_shared<rule::DeviceStateChangeConditionFactory>());
|
||||
registerRuleConditionFactory("logical_or", std::make_shared<rules::conditions::LogicalOrConditionFactory>());
|
||||
registerRuleConditionFactory("logical_and", std::make_shared<rules::conditions::LogicalAndConditionFactory>());
|
||||
registerRuleConditionFactory("devicestatusmsg", std::make_shared<rules::conditions::DeviceStatusMsgConditionFactory>());
|
||||
registerRuleConditionFactory("devicecommandmsg", std::make_shared<rules::conditions::DeviceCommandMsgConditionFactory>());
|
||||
registerRuleConditionFactory("devicestatechange", std::make_shared<rules::conditions::DeviceStateChangeConditionFactory>());
|
||||
if (rawValue.getType() == XmlRpc::XmlRpcValue::TypeStruct) {
|
||||
for (auto pkg : rawValue) {
|
||||
std::string pname = pkg.first;
|
||||
@@ -96,11 +99,11 @@ void RuleEngineServiceImpl::addRulePkg(std::string name, std::string rawValue) {
|
||||
Variant m = Deserialize(rawValue, SERIALIZE_JSON);
|
||||
SchemaResult sr = SchemaValidate(s, m, schemaLoader.get());
|
||||
if (!sr.Error()) {
|
||||
std::shared_ptr<rule::RulePackage> pkg = rule::RulePackage::createRulePackage(this, name, m);
|
||||
std::shared_ptr<rules::RulePackageImpl> pkg = rules::RulePackageImpl::createRulePackage(this, name, m);
|
||||
if (pkg) {
|
||||
if (pkg->getScriptingService()) {
|
||||
rulePkgs.insert({name, pkg});
|
||||
pkg->enable();
|
||||
pkg->setEnabled(true);
|
||||
} else {
|
||||
noExecRulePkgs.insert({name, pkg});
|
||||
std::cout << "No execution service found for rule package \"" << name << "\"" << std::endl;
|
||||
@@ -142,17 +145,17 @@ scripting::ScriptingService* RuleEngineServiceImpl::getExecutionBackend(std::str
|
||||
}
|
||||
|
||||
|
||||
void RuleEngineServiceImpl::registerRuleConditionFactory(std::string type, std::shared_ptr<RuleConditionFactory> factory) {
|
||||
void RuleEngineServiceImpl::registerRuleConditionFactory(const std::string& type, std::shared_ptr<RuleConditionFactory> factory) noexcept {
|
||||
condFactories.insert({type, factory});
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<rule::RulePackage> RuleEngineServiceImpl::getRulePackage(const std::string& name) {
|
||||
std::shared_ptr<rule::RulePackage> retval;
|
||||
std::weak_ptr<rules::RulePackage> RuleEngineServiceImpl::getRulePackage(const std::string& name) noexcept {
|
||||
std::weak_ptr<rules::RulePackage> retval;
|
||||
try {
|
||||
retval = rulePkgs.at(name);
|
||||
} catch(...) {}
|
||||
if (!retval) {
|
||||
if (retval.expired()) {
|
||||
try {
|
||||
retval = noExecRulePkgs.at(name);
|
||||
} catch(...) {}
|
||||
@@ -160,6 +163,18 @@ std::shared_ptr<rule::RulePackage> RuleEngineServiceImpl::getRulePackage(const s
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::weak_ptr<rules::RulePackage>> RuleEngineServiceImpl::getRulePackages() noexcept {
|
||||
|
||||
}
|
||||
|
||||
|
||||
size_t RuleEngineServiceImpl::getRulePackageCount() noexcept {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace ruleengine
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
+33
-24
@@ -1,12 +1,7 @@
|
||||
/*
|
||||
* hos_ruleengine_service_impl.h
|
||||
*
|
||||
* Created on: 26.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_HOS_COSGI_RULEENGINE_HOS_RULEENGINE_SERVICE_IMPL_H_
|
||||
#define INCLUDE_HOS_COSGI_RULEENGINE_HOS_RULEENGINE_SERVICE_IMPL_H_
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
@@ -15,10 +10,10 @@
|
||||
#include <hos_core_msgs/DeviceStatusUpdate.h>
|
||||
#include <hos_core_msgs/HosStatusUpdate.h>
|
||||
#include <hos/utils/SchemaLoader.h>
|
||||
#include <hos/cosgi/service/ruleengine/ruleengine_service.h>
|
||||
#include <hos/cosgi/service/scripting/scripting_service.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <hos/cosgi/service/Implementation.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||
#include <ros/ros.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -45,18 +40,19 @@ namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
|
||||
class RulePackage;
|
||||
namespace rules {
|
||||
class RulePackageImpl;
|
||||
}
|
||||
|
||||
|
||||
class RuleEngineServiceImpl;
|
||||
|
||||
class RuleEngineServiceImpl :
|
||||
public virtual RuleEngineService,
|
||||
public virtual implementation::Service<RuleEngineServiceImpl> {
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, std::shared_ptr<rule::RulePackage>> rulePkgMap_t;
|
||||
typedef std::map<std::string, std::shared_ptr<rules::RulePackageImpl>> rulePkgMap_t;
|
||||
typedef std::map<std::string, scripting::ScriptingService*> execServiceMap_t;
|
||||
typedef std::map<std::string, std::shared_ptr<RuleConditionFactory>> condFactoryMap_t;
|
||||
|
||||
@@ -82,39 +78,52 @@ private:
|
||||
void init();
|
||||
|
||||
public:
|
||||
|
||||
/* Initialization */
|
||||
|
||||
void setCoreService(service::core::CoreService* coreService);
|
||||
|
||||
void setRepoService(devicerepository::DeviceRepositoryService* repoService);
|
||||
|
||||
|
||||
/* Public Service Implementations */
|
||||
|
||||
virtual void registerRuleConditionFactory(std::string type, std::shared_ptr<RuleConditionFactory> factory) override;
|
||||
virtual void registerRuleConditionFactory(const std::string& type, std::shared_ptr<RuleConditionFactory> factory) noexcept override;
|
||||
|
||||
virtual std::weak_ptr<rules::RulePackage> getRulePackage(const std::string& name) noexcept override;
|
||||
|
||||
virtual std::vector<std::weak_ptr<rules::RulePackage>> getRulePackages() noexcept override;
|
||||
|
||||
|
||||
virtual size_t getRulePackageCount() noexcept override;
|
||||
|
||||
|
||||
/* Internal Stuff */
|
||||
|
||||
bool isInitialized() { return initialized; }
|
||||
|
||||
void addExecutionBackend(scripting::ScriptingService* service);
|
||||
|
||||
scripting::ScriptingService* getExecutionBackend(std::string language);
|
||||
|
||||
std::shared_ptr<RuleConditionFactory> getRuleConditionFactory(std::string type) { return condFactories[type]; }
|
||||
std::shared_ptr<RuleConditionFactory> getRuleConditionFactory(std::string type) {
|
||||
return condFactories[type];
|
||||
}
|
||||
|
||||
utils::SchemaLoader* getHOSSchemaLoader() { return schemaLoader.get(); }
|
||||
utils::SchemaLoader* getHOSSchemaLoader() {
|
||||
return schemaLoader.get();
|
||||
}
|
||||
|
||||
devicerepository::DeviceRepositoryService* getDeviceRepository() { return repoService; }
|
||||
devicerepository::DeviceRepositoryService* getDeviceRepository() {
|
||||
return repoService;
|
||||
}
|
||||
|
||||
std::shared_ptr<rule::RulePackage> getRulePackage(const std::string& name);
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace ruleengine
|
||||
} // namespace service
|
||||
} // namespace cosgi
|
||||
} // namespace hos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* INCLUDE_HOS_COSGI_RULEENGINE_HOS_RULEENGINE_SERVICE_IMPL_H_ */
|
||||
@@ -1,432 +0,0 @@
|
||||
/*
|
||||
* RuleCondition.cpp
|
||||
*
|
||||
* Created on: 29.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#include "RuleConditionImpl.h"
|
||||
#include <hos/cosgi/service/ruleengine/rule/Rule.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <ros/ros.h>
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
|
||||
|
||||
std::shared_ptr<rule::RuleCondition> LogicalOrConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
||||
std::shared_ptr<rule::LogicalOrCondition> retval;
|
||||
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
||||
retval = std::make_shared<rule::LogicalOrCondition>(parent);
|
||||
for (auto c : raw["conditions"].AsList()) {
|
||||
auto cond = parent->createRuleCondition(c);
|
||||
if (cond) {
|
||||
retval->addChild(cond);
|
||||
} else {
|
||||
throw std::runtime_error("Could not create condition.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property condition or is not a list.");
|
||||
}
|
||||
return std::static_pointer_cast<rule::RuleCondition>(retval);
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<rule::RuleCondition> LogicalAndConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
||||
std::shared_ptr<rule::LogicalAndCondition> retval;
|
||||
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
||||
retval = std::make_shared<rule::LogicalAndCondition>(parent);
|
||||
for (auto c : raw["conditions"].AsList()) {
|
||||
auto cond = parent->createRuleCondition(c);
|
||||
if (cond) {
|
||||
retval->addChild(cond);
|
||||
} else {
|
||||
throw std::runtime_error("Could not create condition.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property condition or is not a list.");
|
||||
}
|
||||
return std::static_pointer_cast<rule::RuleCondition>(retval);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void RuleCondition::notifyStateChangeToParent(bool newState, Category category, Variant lcontext) {
|
||||
if (compositeParent) {
|
||||
compositeParent->childStateChanged(this, newState, category, lcontext);
|
||||
} else {
|
||||
parent->conditionStateChanged(newState, category, lcontext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LogicalOrCondition::addChild(std::shared_ptr<RuleCondition> child) {
|
||||
if (child->getCategory() == Category::Event) {
|
||||
eventChildrenCount++;
|
||||
} else if (child->getCategory() == Category::State) {
|
||||
stateChildrenCount++;
|
||||
} else {
|
||||
mixedChildrenCount++;
|
||||
}
|
||||
if (mixedChildrenCount > 0 || (eventChildrenCount > 0 && stateChildrenCount > 0)) {
|
||||
category = Category::Mixed;
|
||||
} else if (eventChildrenCount > 0 && stateChildrenCount == 0) {
|
||||
category = Category::Event;
|
||||
} else {
|
||||
category = Category::State;
|
||||
}
|
||||
RuleCompositeCondition::addChild(child);
|
||||
}
|
||||
|
||||
|
||||
void LogicalOrCondition::childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext) {
|
||||
if (newState && category == Category::Event && !currentState) {
|
||||
notifyStateChangeToParent(true, category, lcontext);
|
||||
} else if (category == Category::State) {
|
||||
if (newState) {
|
||||
trueChildrenCount++;
|
||||
if (!currentState) {
|
||||
currentState = true;
|
||||
notifyStateChangeToParent(true, category, lcontext);
|
||||
}
|
||||
} else {
|
||||
trueChildrenCount--;
|
||||
if (currentState && trueChildrenCount <= 0) {
|
||||
currentState = false;
|
||||
notifyStateChangeToParent(false, category, lcontext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LogicalOrCondition::evaluate() {
|
||||
// Event conditions always evaluate to false
|
||||
if (category == Category::Event) {
|
||||
return false;
|
||||
}
|
||||
trueChildrenCount = 0;
|
||||
for (auto c : children) {
|
||||
if (c->evaluate()) {
|
||||
trueChildrenCount++;
|
||||
}
|
||||
}
|
||||
currentState = trueChildrenCount > 0;
|
||||
return currentState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LogicalAndCondition::addChild(std::shared_ptr<RuleCondition> child) {
|
||||
if (child->getCategory() == Category::Event) {
|
||||
if (eventChildrenCount > 0) {
|
||||
throw new std::runtime_error("Cannot have an and condition with more than two event conditions.");
|
||||
}
|
||||
eventChildrenCount++;
|
||||
} else if (child->getCategory() == Category::State) {
|
||||
stateChildrenCount++;
|
||||
} else {
|
||||
mixedChildrenCount++;
|
||||
}
|
||||
if (mixedChildrenCount > 0 || (eventChildrenCount > 0 && stateChildrenCount > 0)) {
|
||||
category = Category::Mixed;
|
||||
} else if (eventChildrenCount > 0 && stateChildrenCount == 0) {
|
||||
category = Category::Event;
|
||||
} else {
|
||||
category = Category::State;
|
||||
}
|
||||
RuleCompositeCondition::addChild(child);
|
||||
}
|
||||
|
||||
void LogicalAndCondition::childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext) {
|
||||
if (newState && category == Category::Event && !currentState && trueChildrenCount >= children.size()-1) {
|
||||
notifyStateChangeToParent(true, category);
|
||||
} else if (category == Category::State) {
|
||||
if (newState) {
|
||||
trueChildrenCount++;
|
||||
if (!currentState && trueChildrenCount >= children.size()) {
|
||||
currentState = true;
|
||||
notifyStateChangeToParent(true, category, lcontext);
|
||||
}
|
||||
} else {
|
||||
trueChildrenCount--;
|
||||
if (currentState) {
|
||||
currentState = false;
|
||||
notifyStateChangeToParent(false, category, lcontext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool LogicalAndCondition::evaluate() {
|
||||
// Event conditions always evaluate to false
|
||||
if (category == Category::Event) {
|
||||
return false;
|
||||
}
|
||||
trueChildrenCount = 0;
|
||||
for (auto c : children) {
|
||||
if (c->evaluate()) {
|
||||
trueChildrenCount++;
|
||||
}
|
||||
}
|
||||
currentState = trueChildrenCount == children.size();
|
||||
return currentState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DeviceMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (key) {
|
||||
case devicerepository::DeviceEvent::EventType::DEVICE_ADDED:
|
||||
if (!device && this->deviceID.compare(e->device->getDeviceID()) == 0) {
|
||||
ROS_INFO_STREAM("Rule " << parent->name << ": Device " << deviceID << " appeared.");
|
||||
device = e->device;
|
||||
parent->getDeviceRepository()->deleteObserver(devicerepository::DeviceEvent::EventType::DEVICE_ADDED, this);
|
||||
_registerAsListener();
|
||||
}
|
||||
break;
|
||||
case devicerepository::DeviceEvent::EventType::DEVICE_REMOVED:
|
||||
if (device && device->getDeviceID().compare(e->device->getDeviceID()) == 0) {
|
||||
ROS_ERROR_STREAM("Rule " << parent->name << ": Device " << deviceID << " disappeared.");
|
||||
device->deleteObserver(this);
|
||||
device = nullptr;
|
||||
parent->getDeviceRepository()->addObserver(devicerepository::DeviceEvent::EventType::DEVICE_ADDED, this);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceMsgCondition::enable() {
|
||||
auto repoService = parent->getDeviceRepository();
|
||||
auto device = repoService->getDevice(deviceID);
|
||||
if (!device.expired()) {
|
||||
this->device = device.lock().get();
|
||||
_registerAsListener();
|
||||
} else {
|
||||
ROS_ERROR_STREAM("Rule " << parent->name << ": Could not find device " << deviceID);
|
||||
parent->getDeviceRepository()->addObserver(devicerepository::DeviceEvent::EventType::DEVICE_ADDED, this);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceMsgCondition::disable() {
|
||||
if (device) {
|
||||
device->deleteObserver(this);
|
||||
device = nullptr;
|
||||
}
|
||||
parent->getDeviceRepository()->deleteObserver(this);
|
||||
}
|
||||
|
||||
void DeviceMsgCondition::_registerAsListener() {
|
||||
if (device) {
|
||||
for (auto k : _listenerKeys) {
|
||||
device->addObserver(k, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::shared_ptr<rule::RuleCondition> DeviceStatusMsgConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
||||
std::shared_ptr<rule::DeviceStatusMsgCondition> retval;
|
||||
std::string deviceID;
|
||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||
deviceID = raw["deviceid"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||
}
|
||||
std::string msgPointer;
|
||||
if (raw.HasPath("msgpointer")) {
|
||||
if (raw["msgpointer"].IsString()) {
|
||||
msgPointer = raw["msgpointer"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||
}
|
||||
}
|
||||
Variant msgValue;
|
||||
if (raw.HasPath("msgvalue")) {
|
||||
msgValue = raw["msgvalue"];
|
||||
}
|
||||
retval = std::make_shared<rule::DeviceStatusMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void DeviceStatusMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (e->eventType) {
|
||||
case devicerepository::DeviceEvent::EventType::STATUS_UPDATE_RECEIVED:
|
||||
if (device && device == e->device) {
|
||||
auto e2 = static_cast<const devicerepository::DeviceStatusMsgEvent*>(e);
|
||||
bool notify = true;
|
||||
Variant value;
|
||||
if (msgPointer.empty()) {
|
||||
value = e2->statusMsg;
|
||||
} else if (e2->statusMsg.HasPath(msgPointer)) {
|
||||
value = e2->statusMsg.GetPath(msgPointer);
|
||||
} else {
|
||||
notify = false;
|
||||
}
|
||||
if (notify && !msgValue.IsNull()) {
|
||||
if (msgValue != value) {
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
Variant lcontext;
|
||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||
lcontext["event_type"] = Variant("statusmsg");
|
||||
lcontext["event_msg"] = e2->statusMsg;
|
||||
notifyStateChangeToParent(true, Category::Event, lcontext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<rule::RuleCondition> DeviceCommandMsgConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
||||
std::shared_ptr<rule::DeviceCommandMsgCondition> retval;
|
||||
std::string deviceID;
|
||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||
deviceID = raw["deviceid"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||
}
|
||||
std::string msgPointer;
|
||||
if (raw.HasPath("msgpointer")) {
|
||||
if (raw["msgpointer"].IsString()) {
|
||||
msgPointer = raw["msgpointer"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||
}
|
||||
}
|
||||
Variant msgValue;
|
||||
if (raw.HasPath("msgvalue")) {
|
||||
msgValue = raw["msgvalue"];
|
||||
}
|
||||
retval = std::make_shared<rule::DeviceCommandMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void DeviceCommandMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (e->eventType) {
|
||||
case devicerepository::DeviceEvent::EventType::COMMAND_RECEIVED:
|
||||
if (device && device == e->device) {
|
||||
auto e2 = static_cast<const devicerepository::DeviceCmdMsgEvent*>(e);
|
||||
bool notify = true;
|
||||
Variant value;
|
||||
if (msgPointer.empty()) {
|
||||
value = e2->cmdMsg;
|
||||
} else if (e2->cmdMsg.HasPath(msgPointer)) {
|
||||
value = e2->cmdMsg.GetPath(msgPointer);
|
||||
} else {
|
||||
notify = false;
|
||||
}
|
||||
if (notify && !msgValue.IsNull()) {
|
||||
if (msgValue != value) {
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
Variant lcontext;
|
||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||
lcontext["event_type"] = Variant("commandmsg");
|
||||
lcontext["event_msg"] = e2->cmdMsg;
|
||||
notifyStateChangeToParent(true, Category::Event, lcontext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<rule::RuleCondition> DeviceStateChangeConditionFactory::createCondition(rule::Rule* parent, Variant raw) {
|
||||
std::shared_ptr<rule::DeviceStateChangeCondition> retval;
|
||||
std::string deviceID;
|
||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||
deviceID = raw["deviceid"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||
}
|
||||
std::string statePointer;
|
||||
if (raw.HasPath("msgpointer")) {
|
||||
if (raw["msgpointer"].IsString()) {
|
||||
statePointer = raw["msgpointer"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||
}
|
||||
}
|
||||
Variant fromValue;
|
||||
if (raw.HasPath("fromvalue")) {
|
||||
fromValue = raw["fromvalue"];
|
||||
}
|
||||
Variant toValue;
|
||||
if (raw.HasPath("tovalue")) {
|
||||
toValue = raw["tovalue"];
|
||||
}
|
||||
retval = std::make_shared<DeviceStateChangeCondition>(parent, deviceID, statePointer, fromValue, toValue);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void DeviceStateChangeCondition::notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (e->eventType) {
|
||||
case devicerepository::DeviceEvent::EventType::STATE_CHANGED:
|
||||
if (device && device == e->device) {
|
||||
auto e2 = static_cast<const devicerepository::DeviceStatusMsgEvent*>(e);
|
||||
bool notify = true;
|
||||
Variant current, last;
|
||||
if (msgPointer.empty()) {
|
||||
current = device->getCurrentState();
|
||||
last = device->getLastState();
|
||||
} else if (device->getCurrentState().HasPath(msgPointer) && device->getLastState().HasPath(msgPointer)) {
|
||||
current = device->getCurrentState().GetPath(msgPointer);
|
||||
last = device->getLastState().GetPath(msgPointer);
|
||||
} else {
|
||||
notify = false;
|
||||
}
|
||||
if (notify) {
|
||||
if (current == last) {
|
||||
notify = false;
|
||||
} else if (!fromValue.IsNull() && fromValue != last) {
|
||||
notify = false;
|
||||
} else if (!msgValue.IsNull() && msgValue != current) {
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
Variant lcontext;
|
||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||
lcontext["event_type"] = Variant("statechange");
|
||||
lcontext["event_msg"] = e2->statusMsg;
|
||||
notifyStateChangeToParent(true, Category::Event, lcontext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} /* namespace rule */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
@@ -1,142 +0,0 @@
|
||||
/*
|
||||
* RuleConditionImpl.h
|
||||
*
|
||||
* Created on: 11.05.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITIONIMPL_H_
|
||||
#define SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITIONIMPL_H_
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rule/RuleCondition.h>
|
||||
#include <hos/cosgi/service/ruleengine/ruleengine_service.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <set>
|
||||
|
||||
|
||||
// Service Namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
|
||||
using namespace ::libvariant;
|
||||
|
||||
|
||||
class LogicalOrCondition : public RuleCompositeCondition {
|
||||
protected:
|
||||
unsigned eventChildrenCount = 0;
|
||||
unsigned stateChildrenCount = 0;
|
||||
unsigned mixedChildrenCount = 0;
|
||||
unsigned trueChildrenCount = 0;
|
||||
public:
|
||||
LogicalOrCondition(Rule* parent) :
|
||||
RuleCompositeCondition(parent, Category::Mixed, "logical_or") {}
|
||||
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
||||
virtual void childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext = Variant()) override;
|
||||
virtual bool evaluate() override;
|
||||
};
|
||||
|
||||
class LogicalOrConditionFactory : public virtual RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, ::libvariant::Variant raw) override;
|
||||
};
|
||||
|
||||
|
||||
class LogicalAndCondition : public RuleCompositeCondition {
|
||||
protected:
|
||||
unsigned eventChildrenCount = 0;
|
||||
unsigned stateChildrenCount = 0;
|
||||
unsigned mixedChildrenCount = 0;
|
||||
unsigned trueChildrenCount = 0;
|
||||
public:
|
||||
LogicalAndCondition(Rule* parent) :
|
||||
RuleCompositeCondition(parent, Category::Mixed, "logical_and") {}
|
||||
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
||||
virtual void childStateChanged(RuleCondition* child, bool newState, Category category, Variant lcontext = Variant()) override;
|
||||
virtual bool evaluate() override;
|
||||
};
|
||||
|
||||
class LogicalAndConditionFactory : public virtual RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, ::libvariant::Variant raw) override;
|
||||
};
|
||||
|
||||
|
||||
class DeviceMsgCondition : public RuleCondition, public virtual interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent> {
|
||||
protected:
|
||||
const std::string deviceID;
|
||||
devicerepository::Device* device = nullptr;
|
||||
const std::string msgPointer;
|
||||
const Variant msgValue;
|
||||
std::set<devicerepository::DeviceEvent::EventType> _listenerKeys;
|
||||
|
||||
virtual void _registerAsListener();
|
||||
|
||||
public:
|
||||
DeviceMsgCondition(Rule* parent, Category category, std::string type, const std::string deviceID, const std::string msgPointer, const Variant msgValue, std::set<devicerepository::DeviceEvent::EventType> _listenerKeys) :
|
||||
RuleCondition(parent, category, type), deviceID(deviceID), msgPointer(msgPointer), msgValue(msgValue), _listenerKeys(_listenerKeys) {}
|
||||
|
||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
||||
virtual void enable() override;
|
||||
virtual void disable() override;
|
||||
};
|
||||
|
||||
|
||||
class DeviceStatusMsgCondition : public DeviceMsgCondition {
|
||||
public:
|
||||
DeviceStatusMsgCondition(Rule* parent, const std::string deviceID, const std::string msgPointer, const Variant msgValue) :
|
||||
DeviceMsgCondition(parent, Category::Event, "devicestatusmsg", deviceID, msgPointer, msgValue, {devicerepository::DeviceEvent::EventType::STATUS_UPDATE_RECEIVED}) {}
|
||||
|
||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
||||
};
|
||||
|
||||
class DeviceStatusMsgConditionFactory : public virtual RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, Variant raw) override;
|
||||
};
|
||||
|
||||
|
||||
class DeviceCommandMsgCondition : public DeviceMsgCondition {
|
||||
public:
|
||||
DeviceCommandMsgCondition(Rule* parent, const std::string deviceID, const std::string msgPointer, const Variant msgValue) :
|
||||
DeviceMsgCondition(parent, Category::Event, "devicecommandmsg", deviceID, msgPointer, msgValue, {devicerepository::DeviceEvent::EventType::COMMAND_RECEIVED}) {}
|
||||
|
||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
||||
};
|
||||
|
||||
class DeviceCommandMsgConditionFactory : public virtual RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, ::libvariant::Variant raw) override;
|
||||
};
|
||||
|
||||
|
||||
class DeviceStateChangeCondition : public DeviceMsgCondition {
|
||||
protected:
|
||||
const Variant fromValue;
|
||||
public:
|
||||
DeviceStateChangeCondition(Rule* parent, const std::string deviceID, const std::string statePointer, const Variant fromValue, const Variant toValue) :
|
||||
DeviceMsgCondition(parent, Category::Event, "devicestatechange", deviceID, statePointer, toValue, {devicerepository::DeviceEvent::EventType::STATE_CHANGED}), fromValue(fromValue) {}
|
||||
|
||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEvent::EventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEvent::EventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
||||
};
|
||||
|
||||
class DeviceStateChangeConditionFactory : public virtual RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<rule::RuleCondition> createCondition(rule::Rule* parent, Variant raw) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
} /* namespace rule */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
|
||||
#endif /* SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULECONDITIONIMPL_H_ */
|
||||
@@ -1,85 +0,0 @@
|
||||
/*
|
||||
* RulePackage.h
|
||||
*
|
||||
* Created on: 29.04.2015
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#ifndef SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULEPACKAGE_H_
|
||||
#define SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULEPACKAGE_H_
|
||||
|
||||
|
||||
#include <hos/cosgi/service/scripting/scripting_service.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
class RuleEngineServiceImpl;
|
||||
class RuleConditionFactory;
|
||||
namespace rule {
|
||||
class Rule;
|
||||
}
|
||||
}
|
||||
namespace scripting {
|
||||
class GlobalScriptContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
|
||||
using namespace ::libvariant;
|
||||
|
||||
class RulePackage {
|
||||
private:
|
||||
typedef std::map<std::string, std::shared_ptr<Rule>> ruleMap_t;
|
||||
|
||||
service::scripting::ScriptingService* executionService = nullptr;
|
||||
std::shared_ptr<scripting::GlobalScriptContext> globalContext;
|
||||
ruleMap_t rules;
|
||||
Variant rawValue;
|
||||
bool enabled = false;
|
||||
|
||||
|
||||
public:
|
||||
service::ruleengine::RuleEngineServiceImpl* const parent;
|
||||
const std::string name;
|
||||
const std::string language;
|
||||
|
||||
static std::shared_ptr<RulePackage> createRulePackage(service::ruleengine::RuleEngineServiceImpl* parent, std::string name, Variant raw);
|
||||
RulePackage(service::ruleengine::RuleEngineServiceImpl* parent, const std::string name, const std::string language, Variant raw);
|
||||
virtual ~RulePackage();
|
||||
|
||||
std::shared_ptr<Rule> getRule(const std::string& name);
|
||||
size_t getRules(std::vector<std::shared_ptr<Rule>>& rules);
|
||||
|
||||
bool isEnabled() { return enabled; }
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
service::scripting::ScriptingService* getScriptingService() { return executionService; }
|
||||
std::shared_ptr<scripting::GlobalScriptContext> getGlobalScriptContext() { return globalContext; }
|
||||
std::shared_ptr<service::ruleengine::RuleConditionFactory> getConditionFactory(std::string type);
|
||||
};
|
||||
|
||||
} /* namespace rule */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
#endif /* SRC_HOS_COSGI_SERVICE_RULEENGINE_RULE_RULEPACKAGE_H_ */
|
||||
+36
-48
@@ -6,39 +6,36 @@
|
||||
*/
|
||||
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rule/Rule.h>
|
||||
#include "../rules/RuleImpl.h"
|
||||
|
||||
#include <hos/cosgi/service/scripting/scripting_service.h>
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rule/RuleCondition.h>
|
||||
#include <ros/ros.h>
|
||||
#include "RulePackage.h"
|
||||
#include <hos/cosgi/service/ruleengine/ruleengine_service.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleCondition.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||
#include <hos/utils/SchemaLoader.h>
|
||||
#include "../ruleengine_serviceimpl.h"
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
#include "../rules/RulePackageImpl.h"
|
||||
|
||||
#include "../RuleEngineServiceImpl.h"
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
namespace rules {
|
||||
|
||||
|
||||
Rule::Rule(RulePackage* parent, std::string name)
|
||||
RuleImpl::RuleImpl(RulePackageImpl* parent, std::string name)
|
||||
: parent(parent), name(name) {}
|
||||
|
||||
|
||||
utils::SchemaLoader* Rule::getHOSSchemaLoader() {
|
||||
return parent->parent->getHOSSchemaLoader();
|
||||
}
|
||||
|
||||
std::shared_ptr<RuleCondition> Rule::createRuleCondition(Variant condition) {
|
||||
std::shared_ptr<RuleCondition> retval;
|
||||
std::shared_ptr<conditions::RuleCondition> RuleImpl::createRuleCondition(const Variant& condition) {
|
||||
std::shared_ptr<conditions::RuleCondition> retval;
|
||||
if (condition.IsMap() && condition.HasPath("type") && condition["type"].IsString()) {
|
||||
if (condition.HasPath("$schema")) {
|
||||
SchemaResult sr = SchemaValidate(Variant(), condition, getHOSSchemaLoader());
|
||||
SchemaResult sr = SchemaValidate(Variant(), condition, parent->parent->getHOSSchemaLoader());
|
||||
if (sr.Error()) {
|
||||
throw std::runtime_error(sr.PrettyPrintMessage());
|
||||
}
|
||||
@@ -60,13 +57,13 @@ std::shared_ptr<RuleCondition> Rule::createRuleCondition(Variant condition) {
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::shared_ptr<Rule> Rule::createRule(RulePackage* parent, std::string name, Variant raw) {
|
||||
std::shared_ptr<Rule> retval;
|
||||
if (parent->getRule(name)) {
|
||||
std::shared_ptr<RuleImpl> RuleImpl::createRule(RulePackageImpl* parent, std::string name, Variant raw) {
|
||||
std::shared_ptr<RuleImpl> retval;
|
||||
if (!parent->getRule(name).expired()) {
|
||||
throw std::runtime_error("Rule with the same name already exists.");
|
||||
}
|
||||
if (raw.IsMap()) {
|
||||
retval = std::make_shared<Rule>(parent, name);
|
||||
retval = std::make_shared<RuleImpl>(parent, name);
|
||||
if (raw.HasPath("condition") && raw["condition"].IsMap()) {
|
||||
auto condition = raw["condition"];
|
||||
auto cond = retval->createRuleCondition(condition);
|
||||
@@ -78,7 +75,7 @@ std::shared_ptr<Rule> Rule::createRule(RulePackage* parent, std::string name, Va
|
||||
auto scriptFactory = parent->getScriptingService();
|
||||
//ToDo: Create Condition
|
||||
if (raw.HasPath("script") && raw["script"].IsMap()) {
|
||||
auto script = scriptFactory->createScript(parent->getGlobalScriptContext().get(), raw["script"]);
|
||||
auto script = scriptFactory->createScript(raw["script"]);
|
||||
if (script) {
|
||||
retval->script = script;
|
||||
} else {
|
||||
@@ -88,7 +85,7 @@ std::shared_ptr<Rule> Rule::createRule(RulePackage* parent, std::string name, Va
|
||||
throw std::runtime_error("Malformed JSON: missing property script or is not an object.");
|
||||
}
|
||||
if (raw.HasPath("exitscript") && raw["exitscript"].IsMap()) {
|
||||
auto script = scriptFactory->createScript(parent->getGlobalScriptContext().get(), raw["exitscript"]);
|
||||
auto script = scriptFactory->createScript(raw["exitscript"]);
|
||||
if (script) {
|
||||
retval->exitScript = script;
|
||||
} else {
|
||||
@@ -105,43 +102,34 @@ std::shared_ptr<Rule> Rule::createRule(RulePackage* parent, std::string name, Va
|
||||
}
|
||||
|
||||
|
||||
devicerepository::DeviceRepositoryService* Rule::getDeviceRepository() {
|
||||
devicerepository::DeviceRepositoryService* RuleImpl::getDeviceRepository() noexcept {
|
||||
return parent->parent->getDeviceRepository();
|
||||
}
|
||||
|
||||
void Rule::enable() {
|
||||
if (!enabled) {
|
||||
void RuleImpl::setEnabled(bool enabled) noexcept {
|
||||
if (this->enabled != enabled) {
|
||||
if (condition) {
|
||||
condition->enable();
|
||||
condition->setEnabled(enabled);
|
||||
}
|
||||
enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
void Rule::disable() {
|
||||
if (enabled) {
|
||||
if (condition) {
|
||||
condition->disable();
|
||||
}
|
||||
enabled = false;
|
||||
this->enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Rule::execute(Variant lContext) {
|
||||
void RuleImpl::executeScript(const libvariant::Variant& lContext) {
|
||||
if (enabled && script) {
|
||||
try {
|
||||
script->exec(parent->getGlobalScriptContext().get(), lContext);
|
||||
script->execute(parent->getGlobalScriptContext().lock(), lContext);
|
||||
} catch(std::exception& e) {
|
||||
ROS_ERROR_STREAM(e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Rule::executeExitScript(Variant lContext) {
|
||||
void RuleImpl::executeExitScript(const libvariant::Variant& lContext) {
|
||||
if (enabled && exitScript) {
|
||||
try {
|
||||
exitScript->exec(parent->getGlobalScriptContext().get(), lContext);
|
||||
exitScript->execute(parent->getGlobalScriptContext().lock(), lContext);
|
||||
} catch(std::exception& e) {
|
||||
ROS_ERROR_STREAM(e.what());
|
||||
}
|
||||
@@ -149,13 +137,13 @@ void Rule::executeExitScript(Variant lContext) {
|
||||
}
|
||||
|
||||
|
||||
bool Rule::evaluate() {
|
||||
bool RuleImpl::evaluate() {
|
||||
if (condition) {
|
||||
bool retval = condition->evaluate();
|
||||
if (retval != currentState) {
|
||||
currentState = retval;
|
||||
if (retval) {
|
||||
execute();
|
||||
executeScript();
|
||||
} else {
|
||||
executeExitScript();
|
||||
}
|
||||
@@ -168,13 +156,13 @@ bool Rule::evaluate() {
|
||||
}
|
||||
|
||||
|
||||
void Rule::conditionStateChanged(bool newState, RuleCondition::Category category, Variant lcontext) {
|
||||
if (newState && !currentState && category == RuleCondition::Category::Event) {
|
||||
execute(lcontext);
|
||||
} else if (category == RuleCondition::Category::State && newState != currentState) {
|
||||
void RuleImpl::conditionStateChanged(bool newState, const conditions::ConditionTriggerType& category, const Variant& lcontext) noexcept {
|
||||
if (newState && !currentState && category == conditions::ConditionTriggerType::Event) {
|
||||
executeScript(lcontext);
|
||||
} else if (category == conditions::ConditionTriggerType::State && newState != currentState) {
|
||||
currentState = newState;
|
||||
if (newState) {
|
||||
execute(lcontext);
|
||||
executeScript(lcontext);
|
||||
} else {
|
||||
executeExitScript(lcontext);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleCondition.h>
|
||||
#include <hos/cosgi/service/ruleengine/rules/Rule.h>
|
||||
#include <hos/cosgi/service/ruleengine/rules/RulePackage.h>
|
||||
|
||||
#include "RulePackageImpl.h"
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace devicerepository {
|
||||
class Device;
|
||||
class DeviceEvent;
|
||||
class DeviceRepositoryService;
|
||||
}
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
class RulePackageImpl;
|
||||
}
|
||||
}
|
||||
namespace scripting {
|
||||
class ScriptingService;
|
||||
class GlobalScriptContext;
|
||||
class Script;
|
||||
}
|
||||
}
|
||||
}
|
||||
namespace utils {
|
||||
class SchemaLoader;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
|
||||
using namespace ::libvariant;
|
||||
|
||||
class RuleImpl : public virtual Rule {
|
||||
private:
|
||||
std::shared_ptr<scripting::Script> script;
|
||||
std::shared_ptr<scripting::Script> exitScript;
|
||||
std::shared_ptr<conditions::RuleCondition> condition;
|
||||
bool enabled = false;
|
||||
bool currentState = false;
|
||||
|
||||
public:
|
||||
RulePackageImpl* const parent;
|
||||
const std::string name;
|
||||
|
||||
RuleImpl(RulePackageImpl* parent, const std::string name);
|
||||
static std::shared_ptr<RuleImpl> createRule(RulePackageImpl* parent, const std::string name, Variant raw);
|
||||
|
||||
virtual RulePackage* getParent() noexcept {
|
||||
return dynamic_cast<RulePackage*>(parent);
|
||||
}
|
||||
|
||||
virtual const std::string& getName() noexcept {
|
||||
return name;
|
||||
}
|
||||
|
||||
virtual bool isActive() noexcept override {
|
||||
return currentState;
|
||||
}
|
||||
virtual bool evaluate() override;
|
||||
virtual void executeScript(const libvariant::Variant& lContext = libvariant::Variant()) override;
|
||||
virtual void executeExitScript(const libvariant::Variant& lContext = libvariant::Variant()) override;
|
||||
|
||||
virtual bool isEnabled() noexcept override {
|
||||
return enabled;
|
||||
}
|
||||
virtual void setEnabled(bool enabled) noexcept override;
|
||||
|
||||
void conditionStateChanged(bool newState, const conditions::ConditionTriggerType& category, const Variant& lcontext = Variant()) noexcept override;
|
||||
|
||||
std::shared_ptr<conditions::RuleCondition> createRuleCondition(const Variant& raw) override;
|
||||
devicerepository::DeviceRepositoryService* getDeviceRepository() noexcept override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+22
-32
@@ -5,29 +5,29 @@
|
||||
* Author: matzman
|
||||
*/
|
||||
|
||||
#include "RulePackage.h"
|
||||
#include "RuleImpl.h"
|
||||
|
||||
#include <ros/ros.h>
|
||||
#include <exception>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
#include "../ruleengine_serviceimpl.h"
|
||||
#include <hos/cosgi/service/ruleengine/rule/Rule.h>
|
||||
#include "../RuleEngineServiceImpl.h"
|
||||
#include "RulePackageImpl.h"
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rule {
|
||||
namespace rules {
|
||||
|
||||
RulePackage::RulePackage(service::ruleengine::RuleEngineServiceImpl* parent, const std::string name, const std::string language, const Variant raw)
|
||||
RulePackageImpl::RulePackageImpl(service::ruleengine::RuleEngineServiceImpl* parent, const std::string name, const std::string language, const Variant raw)
|
||||
: parent(parent), name(name), language(language), rawValue(raw) {}
|
||||
|
||||
RulePackage::~RulePackage() {}
|
||||
RulePackageImpl::~RulePackageImpl() {}
|
||||
|
||||
std::shared_ptr<RulePackage> RulePackage::createRulePackage(service::ruleengine::RuleEngineServiceImpl* parent, std::string name, Variant raw) {
|
||||
std::shared_ptr<RulePackage> retval;
|
||||
if (parent->getRulePackage(name)) {
|
||||
std::shared_ptr<RulePackageImpl> RulePackageImpl::createRulePackage(service::ruleengine::RuleEngineServiceImpl* parent, std::string name, Variant raw) {
|
||||
std::shared_ptr<RulePackageImpl> retval;
|
||||
if (!parent->getRulePackage(name).expired()) {
|
||||
std::stringstream ss;
|
||||
ss << "Could not create package " << name << ": There already exists a rule package with the same name.";
|
||||
throw std::runtime_error(ss.str());
|
||||
@@ -39,7 +39,7 @@ std::shared_ptr<RulePackage> RulePackage::createRulePackage(service::ruleengine:
|
||||
} else {
|
||||
throw std::runtime_error("Rule package JSON is missing language parameter or parameter has wrong type.");
|
||||
}
|
||||
retval = std::make_shared<RulePackage>(parent, name, language, raw);
|
||||
retval = std::make_shared<RulePackageImpl>(parent, name, language, raw);
|
||||
retval->executionService = parent->getExecutionBackend(retval->language);
|
||||
if (retval->executionService) {
|
||||
if (raw.HasPath("globalcontext")) {
|
||||
@@ -48,7 +48,7 @@ std::shared_ptr<RulePackage> RulePackage::createRulePackage(service::ruleengine:
|
||||
if (raw.HasPath("rules") && raw["rules"].IsMap()) {
|
||||
for (auto r : raw["rules"].AsMap()) {
|
||||
try {
|
||||
std::shared_ptr<Rule> rule = Rule::createRule(retval.get(), r.first, r.second);
|
||||
std::shared_ptr<RuleImpl> rule = RuleImpl::createRule(retval.get(), r.first, r.second);
|
||||
if (rule) {
|
||||
retval->rules.insert({r.first, rule});
|
||||
}
|
||||
@@ -70,49 +70,39 @@ std::shared_ptr<RulePackage> RulePackage::createRulePackage(service::ruleengine:
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<Rule> RulePackage::getRule(const std::string& name) {
|
||||
std::shared_ptr<Rule> retval;
|
||||
std::weak_ptr<Rule> RulePackageImpl::getRule(const std::string& name) noexcept {
|
||||
std::weak_ptr<Rule> retval;
|
||||
try {
|
||||
retval = rules.at(name);
|
||||
} catch (...) {}
|
||||
return retval;
|
||||
}
|
||||
|
||||
size_t RulePackage::getRules(std::vector<std::shared_ptr<Rule>>& rules) {
|
||||
size_t retval = 0;
|
||||
std::vector<std::weak_ptr<Rule>> RulePackageImpl::getRules() noexcept {
|
||||
std::vector<std::weak_ptr<Rule>> retval;
|
||||
for (auto item : this->rules) {
|
||||
rules.push_back(item.second);
|
||||
retval++;
|
||||
retval.push_back(dynamic_pointer_cast<Rule>(item.second));
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
std::shared_ptr<RuleConditionFactory> RulePackage::getConditionFactory(std::string type) {
|
||||
std::shared_ptr<RuleConditionFactory> RulePackageImpl::getConditionFactory(std::string type) {
|
||||
return parent->getRuleConditionFactory(type);
|
||||
}
|
||||
|
||||
|
||||
void RulePackage::enable() {
|
||||
if (!enabled) {
|
||||
void RulePackageImpl::setEnabled(bool enabled) noexcept {
|
||||
if (this->enabled != enabled) {
|
||||
for (auto r : rules) {
|
||||
r.second->enable();
|
||||
r.second->setEnabled(enabled);
|
||||
}
|
||||
enabled = true;
|
||||
this->enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void RulePackage::disable() {
|
||||
if (enabled) {
|
||||
for (auto r : rules) {
|
||||
r.second->enable();
|
||||
}
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} /* namespace rule */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
@@ -0,0 +1,97 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rules/RulePackage.h>
|
||||
#include <hos/cosgi/service/scripting/ScriptingService.h>
|
||||
#include "../RuleEngineServiceImpl.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <Variant/Variant.h>
|
||||
|
||||
|
||||
// Forward declarations
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
class RuleEngineServiceImpl;
|
||||
class RuleConditionFactory;
|
||||
namespace rules {
|
||||
class RuleImpl;
|
||||
}
|
||||
}
|
||||
namespace scripting {
|
||||
class GlobalScriptContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
|
||||
using namespace ::libvariant;
|
||||
|
||||
class RulePackageImpl
|
||||
: public virtual RulePackage {
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<std::string, std::shared_ptr<RuleImpl>> ruleMap_t;
|
||||
|
||||
service::scripting::ScriptingService* executionService = nullptr;
|
||||
std::shared_ptr<scripting::GlobalScriptContext> globalContext;
|
||||
ruleMap_t rules;
|
||||
Variant rawValue;
|
||||
bool enabled = false;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
static std::shared_ptr<RulePackageImpl> createRulePackage(service::ruleengine::RuleEngineServiceImpl* parent, std::string name, Variant raw);
|
||||
RulePackageImpl(service::ruleengine::RuleEngineServiceImpl* parent, const std::string name, const std::string language, Variant raw);
|
||||
virtual ~RulePackageImpl();
|
||||
|
||||
service::ruleengine::RuleEngineServiceImpl* const parent;
|
||||
const std::string name;
|
||||
const std::string language;
|
||||
|
||||
virtual service::ruleengine::RuleEngineService* getParent() noexcept override {
|
||||
return dynamic_cast<service::ruleengine::RuleEngineService*>(parent);
|
||||
}
|
||||
|
||||
virtual const std::string& getName() noexcept override {
|
||||
return name;
|
||||
};
|
||||
virtual const std::string& getLanguage() noexcept override {
|
||||
return language;
|
||||
}
|
||||
|
||||
virtual std::weak_ptr<Rule> getRule(const std::string& name) noexcept override;
|
||||
virtual std::vector<std::weak_ptr<Rule>> getRules() noexcept override;
|
||||
virtual size_t getRuleCount() noexcept override { return rules.size(); }
|
||||
|
||||
virtual bool isEnabled() noexcept override {
|
||||
return enabled;
|
||||
}
|
||||
virtual void setEnabled(bool enabled) noexcept override;
|
||||
|
||||
virtual service::scripting::ScriptingService* getScriptingService() noexcept override { return executionService; }
|
||||
virtual std::weak_ptr<scripting::GlobalScriptContext> getGlobalScriptContext() noexcept override { return globalContext; }
|
||||
std::shared_ptr<service::ruleengine::RuleConditionFactory> getConditionFactory(std::string type);
|
||||
};
|
||||
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
|
||||
|
||||
#include "DeviceMsgCondition.h"
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include "../RuleImpl.h"
|
||||
#include <ros/ros.h>
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
|
||||
|
||||
|
||||
void DeviceMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (key) {
|
||||
case devicerepository::DeviceEventType::DEVICE_ADDED:
|
||||
if (!device && this->deviceID.compare(e->device->getDeviceID()) == 0) {
|
||||
ROS_INFO_STREAM("Rule " << parent->getName() << ": Device " << deviceID << " appeared.");
|
||||
device = e->device;
|
||||
parent->getDeviceRepository()->deleteObserver(devicerepository::DeviceEventType::DEVICE_ADDED, this);
|
||||
_registerAsListener();
|
||||
}
|
||||
break;
|
||||
case devicerepository::DeviceEventType::DEVICE_REMOVED:
|
||||
if (device && device->getDeviceID().compare(e->device->getDeviceID()) == 0) {
|
||||
ROS_ERROR_STREAM("Rule " << parent->getName() << ": Device " << deviceID << " disappeared.");
|
||||
device->deleteObserver(this);
|
||||
device = nullptr;
|
||||
parent->getDeviceRepository()->addObserver(devicerepository::DeviceEventType::DEVICE_ADDED, this);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceMsgCondition::setEnabled(bool enabled) noexcept {
|
||||
if (this->enabled != enabled) {
|
||||
if (enabled) {
|
||||
auto repoService = parent->getDeviceRepository();
|
||||
auto device = repoService->getDevice(deviceID);
|
||||
if (!device.expired()) {
|
||||
this->device = device.lock().get();
|
||||
_registerAsListener();
|
||||
} else {
|
||||
ROS_ERROR_STREAM("Rule " << parent->getName() << ": Could not find device " << deviceID);
|
||||
parent->getDeviceRepository()->addObserver(devicerepository::DeviceEventType::DEVICE_ADDED, this);
|
||||
}
|
||||
} else {
|
||||
if (device) {
|
||||
device->deleteObserver(this);
|
||||
device = nullptr;
|
||||
}
|
||||
parent->getDeviceRepository()->deleteObserver(this);
|
||||
}
|
||||
this->enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceMsgCondition::_registerAsListener() {
|
||||
if (device) {
|
||||
for (auto k : _listenerKeys) {
|
||||
device->addObserver(k, this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
std::shared_ptr<RuleCondition> DeviceStatusMsgConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||
std::shared_ptr<DeviceStatusMsgCondition> retval;
|
||||
std::string deviceID;
|
||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||
deviceID = raw["deviceid"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||
}
|
||||
std::string msgPointer;
|
||||
if (raw.HasPath("msgpointer")) {
|
||||
if (raw["msgpointer"].IsString()) {
|
||||
msgPointer = raw["msgpointer"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||
}
|
||||
}
|
||||
Variant msgValue;
|
||||
if (raw.HasPath("msgvalue")) {
|
||||
msgValue = raw["msgvalue"];
|
||||
}
|
||||
retval = std::make_shared<DeviceStatusMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void DeviceStatusMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (e->eventType) {
|
||||
case devicerepository::DeviceEventType::STATUS_UPDATE_RECEIVED:
|
||||
if (device && device == e->device) {
|
||||
auto e2 = static_cast<const devicerepository::DeviceStatusMsgEvent*>(e);
|
||||
bool notify = true;
|
||||
Variant value;
|
||||
if (msgPointer.empty()) {
|
||||
value = e2->statusMsg;
|
||||
} else if (e2->statusMsg.HasPath(msgPointer)) {
|
||||
value = e2->statusMsg.GetPath(msgPointer);
|
||||
} else {
|
||||
notify = false;
|
||||
}
|
||||
if (notify && !msgValue.IsNull()) {
|
||||
if (msgValue != value) {
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
Variant lcontext;
|
||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||
lcontext["event_type"] = Variant("statusmsg");
|
||||
lcontext["event_msg"] = e2->statusMsg;
|
||||
notifyStateChangeToParent(true, ConditionTriggerType::Event, lcontext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<RuleCondition> DeviceCommandMsgConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||
std::shared_ptr<DeviceCommandMsgCondition> retval;
|
||||
std::string deviceID;
|
||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||
deviceID = raw["deviceid"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||
}
|
||||
std::string msgPointer;
|
||||
if (raw.HasPath("msgpointer")) {
|
||||
if (raw["msgpointer"].IsString()) {
|
||||
msgPointer = raw["msgpointer"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||
}
|
||||
}
|
||||
Variant msgValue;
|
||||
if (raw.HasPath("msgvalue")) {
|
||||
msgValue = raw["msgvalue"];
|
||||
}
|
||||
retval = std::make_shared<DeviceCommandMsgCondition>(parent, deviceID, msgPointer, msgValue);
|
||||
return retval;
|
||||
}
|
||||
|
||||
void DeviceCommandMsgCondition::notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (e->eventType) {
|
||||
case devicerepository::DeviceEventType::COMMAND_RECEIVED:
|
||||
if (device && device == e->device) {
|
||||
auto e2 = static_cast<const devicerepository::DeviceCmdMsgEvent*>(e);
|
||||
bool notify = true;
|
||||
Variant value;
|
||||
if (msgPointer.empty()) {
|
||||
value = e2->cmdMsg;
|
||||
} else if (e2->cmdMsg.HasPath(msgPointer)) {
|
||||
value = e2->cmdMsg.GetPath(msgPointer);
|
||||
} else {
|
||||
notify = false;
|
||||
}
|
||||
if (notify && !msgValue.IsNull()) {
|
||||
if (msgValue != value) {
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
Variant lcontext;
|
||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||
lcontext["event_type"] = Variant("commandmsg");
|
||||
lcontext["event_msg"] = e2->cmdMsg;
|
||||
notifyStateChangeToParent(true, ConditionTriggerType::Event, lcontext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::shared_ptr<RuleCondition> DeviceStateChangeConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||
std::shared_ptr<DeviceStateChangeCondition> retval;
|
||||
std::string deviceID;
|
||||
if (raw.HasPath("deviceid") && raw["deviceid"].IsString()) {
|
||||
deviceID = raw["deviceid"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property deviceid or is not an string.");
|
||||
}
|
||||
std::string statePointer;
|
||||
if (raw.HasPath("msgpointer")) {
|
||||
if (raw["msgpointer"].IsString()) {
|
||||
statePointer = raw["msgpointer"].AsString();
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: property msgpointer is not an string.");
|
||||
}
|
||||
}
|
||||
Variant fromValue;
|
||||
if (raw.HasPath("fromvalue")) {
|
||||
fromValue = raw["fromvalue"];
|
||||
}
|
||||
Variant toValue;
|
||||
if (raw.HasPath("tovalue")) {
|
||||
toValue = raw["tovalue"];
|
||||
}
|
||||
retval = std::make_shared<DeviceStateChangeCondition>(parent, deviceID, statePointer, fromValue, toValue);
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
void DeviceStateChangeCondition::notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept {
|
||||
switch (e->eventType) {
|
||||
case devicerepository::DeviceEventType::STATE_CHANGED:
|
||||
if (device && device == e->device) {
|
||||
auto e2 = static_cast<const devicerepository::DeviceStatusMsgEvent*>(e);
|
||||
bool notify = true;
|
||||
Variant current, last;
|
||||
if (msgPointer.empty()) {
|
||||
current = device->getCurrentState();
|
||||
last = device->getLastState();
|
||||
} else if (device->getCurrentState().HasPath(msgPointer) && device->getLastState().HasPath(msgPointer)) {
|
||||
current = device->getCurrentState().GetPath(msgPointer);
|
||||
last = device->getLastState().GetPath(msgPointer);
|
||||
} else {
|
||||
notify = false;
|
||||
}
|
||||
if (notify) {
|
||||
if (current == last) {
|
||||
notify = false;
|
||||
} else if (!fromValue.IsNull() && fromValue != last) {
|
||||
notify = false;
|
||||
} else if (!msgValue.IsNull() && msgValue != current) {
|
||||
notify = false;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
Variant lcontext;
|
||||
lcontext["event_deviceid"] = Variant(e->device->getDeviceID());
|
||||
lcontext["event_type"] = Variant("statechange");
|
||||
lcontext["event_msg"] = e2->statusMsg;
|
||||
notifyStateChangeToParent(true, ConditionTriggerType::Event, lcontext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
DeviceMsgCondition::notificationReceived(o, key, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
#include <hos/cosgi/service/devicerepository/DeviceRepositoryService.h>
|
||||
#include <set>
|
||||
|
||||
|
||||
// main Namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
|
||||
using namespace libvariant;
|
||||
|
||||
|
||||
|
||||
class DeviceMsgCondition
|
||||
: public RuleConditionImpl,
|
||||
public virtual interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent> {
|
||||
|
||||
protected:
|
||||
const std::string deviceID;
|
||||
devicerepository::Device* device = nullptr;
|
||||
const std::string msgPointer;
|
||||
const Variant msgValue;
|
||||
std::set<devicerepository::DeviceEventType> _listenerKeys;
|
||||
|
||||
virtual void _registerAsListener();
|
||||
|
||||
public:
|
||||
DeviceMsgCondition( Rule* parent,
|
||||
ConditionTriggerType category,
|
||||
const std::string& type,
|
||||
const std::string& deviceID,
|
||||
const std::string& msgPointer,
|
||||
const Variant& msgValue,
|
||||
const std::set<devicerepository::DeviceEventType> _listenerKeys )
|
||||
: RuleConditionImpl(parent, category, type), deviceID(deviceID),
|
||||
msgPointer(msgPointer), msgValue(msgValue), _listenerKeys(_listenerKeys) {}
|
||||
|
||||
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
||||
devicerepository::DeviceEvent>::observable_type* o,
|
||||
const devicerepository::DeviceEventType& key,
|
||||
const devicerepository::DeviceEvent* e) noexcept override;
|
||||
|
||||
virtual void setEnabled(bool enabled) noexcept override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class DeviceStatusMsgCondition
|
||||
: public DeviceMsgCondition {
|
||||
|
||||
public:
|
||||
DeviceStatusMsgCondition( Rule* parent,
|
||||
const std::string& deviceID,
|
||||
const std::string& msgPointer,
|
||||
const Variant& msgValue)
|
||||
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicestatusmsg", deviceID,
|
||||
msgPointer, msgValue, {devicerepository::DeviceEventType::STATUS_UPDATE_RECEIVED}) {}
|
||||
|
||||
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
||||
devicerepository::DeviceEvent>::observable_type* o,
|
||||
const devicerepository::DeviceEventType& key,
|
||||
const devicerepository::DeviceEvent* e ) noexcept override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class DeviceStatusMsgConditionFactory
|
||||
: public RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class DeviceCommandMsgCondition
|
||||
: public DeviceMsgCondition {
|
||||
|
||||
public:
|
||||
DeviceCommandMsgCondition(Rule* parent, const std::string deviceID, const std::string msgPointer, const Variant msgValue)
|
||||
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicecommandmsg", deviceID,
|
||||
msgPointer, msgValue, {devicerepository::DeviceEventType::COMMAND_RECEIVED}) {}
|
||||
|
||||
virtual void notificationReceived( interface::Observer<devicerepository::DeviceEventType,
|
||||
devicerepository::DeviceEvent>::observable_type* o,
|
||||
const devicerepository::DeviceEventType& key,
|
||||
const devicerepository::DeviceEvent* e ) noexcept override;
|
||||
};
|
||||
|
||||
|
||||
class DeviceCommandMsgConditionFactory
|
||||
: public RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class DeviceStateChangeCondition
|
||||
: public DeviceMsgCondition {
|
||||
|
||||
protected:
|
||||
const Variant fromValue;
|
||||
|
||||
public:
|
||||
DeviceStateChangeCondition( Rule* parent,
|
||||
const std::string deviceID,
|
||||
const std::string statePointer,
|
||||
const Variant fromValue,
|
||||
const Variant toValue )
|
||||
: DeviceMsgCondition(parent, ConditionTriggerType::Event, "devicestatechange", deviceID, statePointer,
|
||||
toValue, {devicerepository::DeviceEventType::STATE_CHANGED}), fromValue(fromValue) {}
|
||||
|
||||
virtual void notificationReceived(interface::Observer<devicerepository::DeviceEventType, devicerepository::DeviceEvent>::observable_type* o, const devicerepository::DeviceEventType& key, const devicerepository::DeviceEvent* e) noexcept override;
|
||||
};
|
||||
|
||||
|
||||
class DeviceStateChangeConditionFactory
|
||||
: public RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
+104
@@ -0,0 +1,104 @@
|
||||
|
||||
#include "LogicalAndCondition.h"
|
||||
#include <hos/cosgi/service/ruleengine/rules/Rule.h>
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
|
||||
|
||||
std::shared_ptr<RuleCondition> LogicalAndConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||
std::shared_ptr<LogicalAndCondition> retval;
|
||||
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
||||
retval = std::make_shared<LogicalAndCondition>(parent);
|
||||
for (auto c : raw["conditions"].AsList()) {
|
||||
auto cond = parent->createRuleCondition(c);
|
||||
if (cond) {
|
||||
retval->addChild(cond);
|
||||
} else {
|
||||
throw std::runtime_error("Could not create condition.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property condition or is not a list.");
|
||||
}
|
||||
return std::static_pointer_cast<RuleConditionImpl>(retval);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LogicalAndCondition::addChild(std::shared_ptr<RuleCondition> child) {
|
||||
if (child->getTriggerType() == ConditionTriggerType::Event) {
|
||||
if (eventChildrenCount > 0) {
|
||||
throw new std::runtime_error("Cannot have an and condition with more than two event conditions.");
|
||||
}
|
||||
eventChildrenCount++;
|
||||
} else if (child->getTriggerType() == ConditionTriggerType::State) {
|
||||
stateChildrenCount++;
|
||||
} else {
|
||||
mixedChildrenCount++;
|
||||
}
|
||||
if (mixedChildrenCount > 0 || (eventChildrenCount > 0 && stateChildrenCount > 0)) {
|
||||
triggerType = ConditionTriggerType::Both;
|
||||
} else if (eventChildrenCount > 0 && stateChildrenCount == 0) {
|
||||
triggerType = ConditionTriggerType::Event;
|
||||
} else {
|
||||
triggerType = ConditionTriggerType::State;
|
||||
}
|
||||
RuleCompositeConditionImpl::addChild(child);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LogicalAndCondition::childStateChanged(RuleCondition* child, bool newState, ConditionTriggerType category, const Variant& lcontext) noexcept {
|
||||
if (newState && category == ConditionTriggerType::Event && !currentState && trueChildrenCount >= children.size()-1) {
|
||||
notifyStateChangeToParent(true, category);
|
||||
} else if (category == ConditionTriggerType::State) {
|
||||
if (newState) {
|
||||
trueChildrenCount++;
|
||||
if (!currentState && trueChildrenCount >= children.size()) {
|
||||
currentState = true;
|
||||
notifyStateChangeToParent(true, category, lcontext);
|
||||
}
|
||||
} else {
|
||||
trueChildrenCount--;
|
||||
if (currentState) {
|
||||
currentState = false;
|
||||
notifyStateChangeToParent(false, category, lcontext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool LogicalAndCondition::evaluate() noexcept {
|
||||
// Event conditions always evaluate to false
|
||||
if (triggerType == ConditionTriggerType::Event) {
|
||||
return false;
|
||||
}
|
||||
trueChildrenCount = 0;
|
||||
for (auto c : children) {
|
||||
if (c->evaluate()) {
|
||||
trueChildrenCount++;
|
||||
}
|
||||
}
|
||||
currentState = trueChildrenCount == children.size();
|
||||
return currentState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
|
||||
|
||||
// Service Namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
using namespace libvariant;
|
||||
|
||||
|
||||
|
||||
class LogicalAndCondition
|
||||
: public RuleCompositeConditionImpl {
|
||||
|
||||
protected:
|
||||
unsigned eventChildrenCount = 0;
|
||||
unsigned stateChildrenCount = 0;
|
||||
unsigned mixedChildrenCount = 0;
|
||||
unsigned trueChildrenCount = 0;
|
||||
|
||||
public:
|
||||
LogicalAndCondition(Rule* parent) :
|
||||
RuleCompositeConditionImpl(parent, ConditionTriggerType::Both, "logical_and") {}
|
||||
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
||||
|
||||
virtual void childStateChanged(RuleCondition* child, bool newState, ConditionTriggerType category,
|
||||
const Variant& lcontext = Variant()) noexcept override;
|
||||
|
||||
virtual bool evaluate() noexcept override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LogicalAndConditionFactory
|
||||
: public RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
|
||||
#include "LogicalOrCondition.h"
|
||||
#include <hos/cosgi/service/ruleengine/rules/Rule.h>
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
|
||||
|
||||
std::shared_ptr<RuleCondition> LogicalOrConditionFactory::createCondition(rules::Rule* parent, const Variant& raw) {
|
||||
std::shared_ptr<LogicalOrCondition> retval;
|
||||
if (raw.HasPath("conditions") && raw["conditions"].IsList() && raw["conditions"].Size() > 0) {
|
||||
retval = std::make_shared<LogicalOrCondition>(parent);
|
||||
for (auto c : raw["conditions"].AsList()) {
|
||||
auto cond = parent->createRuleCondition(c);
|
||||
if (cond) {
|
||||
retval->addChild(cond);
|
||||
} else {
|
||||
throw std::runtime_error("Could not create condition.");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw std::runtime_error("Malformed JSON: missing property condition or is not a list.");
|
||||
}
|
||||
return std::static_pointer_cast<RuleConditionImpl>(retval);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LogicalOrCondition::addChild(std::shared_ptr<RuleCondition> child) {
|
||||
if (child->getTriggerType() == ConditionTriggerType::Event) {
|
||||
eventChildrenCount++;
|
||||
} else if (child->getTriggerType() == ConditionTriggerType::State) {
|
||||
stateChildrenCount++;
|
||||
} else {
|
||||
mixedChildrenCount++;
|
||||
}
|
||||
if (mixedChildrenCount > 0 || (eventChildrenCount > 0 && stateChildrenCount > 0)) {
|
||||
triggerType = ConditionTriggerType::Both;
|
||||
} else if (eventChildrenCount > 0 && stateChildrenCount == 0) {
|
||||
triggerType = ConditionTriggerType::Event;
|
||||
} else {
|
||||
triggerType = ConditionTriggerType::State;
|
||||
}
|
||||
RuleCompositeConditionImpl::addChild(child);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void LogicalOrCondition::childStateChanged(RuleCondition* child, bool newState,
|
||||
ConditionTriggerType category, const Variant& lcontext) noexcept {
|
||||
if (newState && category == ConditionTriggerType::Event && !currentState) {
|
||||
notifyStateChangeToParent(true, category, lcontext);
|
||||
} else if (category == ConditionTriggerType::State) {
|
||||
if (newState) {
|
||||
trueChildrenCount++;
|
||||
if (!currentState) {
|
||||
currentState = true;
|
||||
notifyStateChangeToParent(true, category, lcontext);
|
||||
}
|
||||
} else {
|
||||
trueChildrenCount--;
|
||||
if (currentState && trueChildrenCount <= 0) {
|
||||
currentState = false;
|
||||
notifyStateChangeToParent(false, category, lcontext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool LogicalOrCondition::evaluate() noexcept {
|
||||
// Event conditions always evaluate to false
|
||||
if (triggerType == ConditionTriggerType::Event) {
|
||||
return false;
|
||||
}
|
||||
trueChildrenCount = 0;
|
||||
for (auto c : children) {
|
||||
if (c->evaluate()) {
|
||||
trueChildrenCount++;
|
||||
}
|
||||
}
|
||||
currentState = trueChildrenCount > 0;
|
||||
return currentState;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl.h>
|
||||
#include <hos/cosgi/service/ruleengine/RuleEngineService.h>
|
||||
|
||||
|
||||
// Service Namespace
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
using namespace libvariant;
|
||||
|
||||
|
||||
|
||||
class LogicalOrCondition
|
||||
: public RuleCompositeConditionImpl {
|
||||
|
||||
protected:
|
||||
unsigned eventChildrenCount = 0;
|
||||
unsigned stateChildrenCount = 0;
|
||||
unsigned mixedChildrenCount = 0;
|
||||
unsigned trueChildrenCount = 0;
|
||||
|
||||
public:
|
||||
LogicalOrCondition(Rule* parent) :
|
||||
RuleCompositeConditionImpl(parent, ConditionTriggerType::Both, "logical_or") {}
|
||||
|
||||
virtual void addChild(std::shared_ptr<RuleCondition> child) override;
|
||||
virtual void childStateChanged(RuleCondition* child, bool newState, ConditionTriggerType category,
|
||||
const libvariant::Variant& lcontext = libvariant::Variant()) noexcept override;
|
||||
virtual bool evaluate() noexcept override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
class LogicalOrConditionFactory
|
||||
: public RuleConditionFactory {
|
||||
public:
|
||||
virtual std::shared_ptr<RuleCondition> createCondition(rules::Rule* parent, const Variant& raw) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
|
||||
#include <hos/cosgi/service/ruleengine/rules/conditions/RuleConditionImpl.h>
|
||||
#include "../RuleImpl.h"
|
||||
|
||||
|
||||
|
||||
namespace hos {
|
||||
namespace cosgi {
|
||||
namespace service {
|
||||
namespace ruleengine {
|
||||
namespace rules {
|
||||
namespace conditions {
|
||||
|
||||
|
||||
|
||||
void RuleConditionImpl::notifyStateChangeToParent(bool newState, ConditionTriggerType category, const libvariant::Variant& lcontext) {
|
||||
if (compositeParent) {
|
||||
compositeParent->childStateChanged(this, newState, category, lcontext);
|
||||
} else {
|
||||
parent->conditionStateChanged(newState, category, lcontext);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} /* namespace conditions */
|
||||
} /* namespace rules */
|
||||
} /* namespace ruleengine */
|
||||
} /* namespace service */
|
||||
} /* namespace cosgi */
|
||||
} /* namespace hos */
|
||||
|
||||
Reference in New Issue
Block a user