more work on rules

disallow removing a device if a rule still refers to it unless
parameters contain information on what to do with those rules.
This commit is contained in:
Michael Zanetti 2014-06-22 21:46:31 +02:00
parent cd67ab567b
commit be90f47f63
14 changed files with 311 additions and 49 deletions

View File

@ -78,9 +78,37 @@ QList<DeviceClass> GuhCore::supportedDevices(const VendorId &vendorId) const
return m_deviceManager->supportedDevices(vendorId); return m_deviceManager->supportedDevices(vendorId);
} }
QPair<DeviceManager::DeviceError, QString> GuhCore::removeConfiguredDevice(const DeviceId &deviceId) QPair<DeviceManager::DeviceError, QString> GuhCore::removeConfiguredDevice(const DeviceId &deviceId, const QHash<RuleId, RuleEngine::RemovePolicy> &removePolicyList)
{ {
// TODO: make sure we don't remove a device and keep stale rules around... QHash<RuleId, RuleEngine::RemovePolicy> toBeChanged;
QList<RuleId> unhandledRules;
foreach (const RuleId &ruleId, m_ruleEngine->findRules(deviceId)) {
bool found = false;
foreach (const RuleId &policyRuleId, removePolicyList.keys()) {
if (ruleId == policyRuleId) {
found = true;
toBeChanged.insert(ruleId, removePolicyList.value(ruleId));
break;
}
}
if (!found) {
unhandledRules.append(ruleId);
}
}
if (!unhandledRules.isEmpty()) {
return qMakePair<DeviceManager::DeviceError, QString>(DeviceManager::DeviceErrorMissingParameter, "There are unhandled rules which depend on this device.");
}
// Update the rules...
foreach (const RuleId &ruleId, toBeChanged.keys()) {
if (toBeChanged.value(ruleId) == RuleEngine::RemovePolicyCascade) {
m_ruleEngine->removeRule(ruleId);
} else if (toBeChanged.value(ruleId) == RuleEngine::RemovePolicyUpdate){
m_ruleEngine->removeDeviceFromRule(ruleId, deviceId);
}
}
return m_deviceManager->removeConfiguredDevice(deviceId); return m_deviceManager->removeConfiguredDevice(deviceId);
} }
@ -144,6 +172,16 @@ QList<Rule> GuhCore::rules() const
return m_ruleEngine->rules(); return m_ruleEngine->rules();
} }
QList<RuleId> GuhCore::ruleIds() const
{
return m_ruleEngine->ruleIds();
}
Rule GuhCore::findRule(const RuleId &ruleId)
{
return m_ruleEngine->findRule(ruleId);
}
RuleEngine::RuleError GuhCore::addRule(const RuleId &id, const QList<EventDescriptor> &eventDescriptorList, const QList<Action> &actionList) RuleEngine::RuleError GuhCore::addRule(const RuleId &id, const QList<EventDescriptor> &eventDescriptorList, const QList<Action> &actionList)
{ {
return m_ruleEngine->addRule(id, eventDescriptorList, actionList); return m_ruleEngine->addRule(id, eventDescriptorList, actionList);
@ -154,6 +192,11 @@ RuleEngine::RuleError GuhCore::removeRule(const RuleId &id)
return m_ruleEngine->removeRule(id); return m_ruleEngine->removeRule(id);
} }
QList<RuleId> GuhCore::findRules(const DeviceId &deviceId)
{
return m_ruleEngine->findRules(deviceId);
}
/*! Returns a pointer to the \l{DeviceManager} instance owned by GuhCore.*/ /*! Returns a pointer to the \l{DeviceManager} instance owned by GuhCore.*/
DeviceManager *GuhCore::deviceManager() const DeviceManager *GuhCore::deviceManager() const
{ {

View File

@ -55,7 +55,7 @@ public:
QList<Device*> configuredDevices() const; QList<Device*> configuredDevices() const;
Device *findConfiguredDevice(const DeviceId &deviceId) const; Device *findConfiguredDevice(const DeviceId &deviceId) const;
QList<Device*> findConfiguredDevices(const DeviceClassId &deviceClassId) const; QList<Device*> findConfiguredDevices(const DeviceClassId &deviceClassId) const;
QPair<DeviceManager::DeviceError, QString> removeConfiguredDevice(const DeviceId &deviceId); QPair<DeviceManager::DeviceError, QString> removeConfiguredDevice(const DeviceId &deviceId, const QHash<RuleId, RuleEngine::RemovePolicy> &removePolicyList);
QPair<DeviceManager::DeviceError, QString> pairDevice(const DeviceClassId &deviceClassId, const DeviceDescriptorId &deviceDescriptorId); QPair<DeviceManager::DeviceError, QString> pairDevice(const DeviceClassId &deviceClassId, const DeviceDescriptorId &deviceDescriptorId);
QPair<DeviceManager::DeviceError, QString> pairDevice(const DeviceClassId &deviceClassId, const QList<Param> &params); QPair<DeviceManager::DeviceError, QString> pairDevice(const DeviceClassId &deviceClassId, const QList<Param> &params);
@ -64,8 +64,11 @@ public:
QPair<DeviceManager::DeviceError, QString> executeAction(const Action &action); QPair<DeviceManager::DeviceError, QString> executeAction(const Action &action);
QList<Rule> rules() const; QList<Rule> rules() const;
QList<RuleId> ruleIds() const;
Rule findRule(const RuleId &ruleId);
RuleEngine::RuleError addRule(const RuleId &id, const QList<EventDescriptor> &eventDescriptorList, const QList<Action> &actionList); RuleEngine::RuleError addRule(const RuleId &id, const QList<EventDescriptor> &eventDescriptorList, const QList<Action> &actionList);
RuleEngine::RuleError removeRule(const RuleId &id); RuleEngine::RuleError removeRule(const RuleId &id);
QList<RuleId> findRules(const DeviceId &deviceId);
signals: signals:
void eventTriggered(const Event &event); void eventTriggered(const Event &event);

View File

@ -147,6 +147,12 @@ DeviceHandler::DeviceHandler(QObject *parent) :
params.clear(); returns.clear(); params.clear(); returns.clear();
setDescription("RemoveConfiguredDevice", "Remove a device from the system."); setDescription("RemoveConfiguredDevice", "Remove a device from the system.");
params.insert("deviceId", "uuid"); params.insert("deviceId", "uuid");
QVariantList removePolicyList;
QVariantMap policy;
policy.insert("ruleId", "uuid");
policy.insert("policy", JsonTypes::removePolicyTypesRef());
removePolicyList.append(policy);
params.insert("o:removePolicyList", removePolicyList);
setParams("RemoveConfiguredDevice", params); setParams("RemoveConfiguredDevice", params);
returns.insert("success", "bool"); returns.insert("success", "bool");
returns.insert("errorMessage", "string"); returns.insert("errorMessage", "string");
@ -480,8 +486,16 @@ JsonReply* DeviceHandler::GetConfiguredDevices(const QVariantMap &params) const
JsonReply* DeviceHandler::RemoveConfiguredDevice(const QVariantMap &params) JsonReply* DeviceHandler::RemoveConfiguredDevice(const QVariantMap &params)
{ {
DeviceId deviceId = DeviceId(params.value("deviceId").toString());
QHash<RuleId, RuleEngine::RemovePolicy> removePolicyList;
foreach (const QVariant &variant, params.value("removePolicyList").toList()) {
RuleId ruleId = RuleId(variant.toMap().value("ruleId").toString());
RuleEngine::RemovePolicy policy = variant.toMap().value("policy").toString() == "RemovePolicyCascade" ? RuleEngine::RemovePolicyCascade : RuleEngine::RemovePolicyUpdate;
removePolicyList.insert(ruleId, policy);
}
QVariantMap returns; QVariantMap returns;
QPair<DeviceManager::DeviceError, QString> status = GuhCore::instance()->removeConfiguredDevice(DeviceId(params.value("deviceId").toString())); QPair<DeviceManager::DeviceError, QString> status = GuhCore::instance()->removeConfiguredDevice(deviceId, removePolicyList);
switch(status.first) { switch(status.first) {
case DeviceManager::DeviceErrorNoError: case DeviceManager::DeviceErrorNoError:
returns.insert("success", true); returns.insert("success", true);
@ -491,6 +505,10 @@ JsonReply* DeviceHandler::RemoveConfiguredDevice(const QVariantMap &params)
returns.insert("success", false); returns.insert("success", false);
returns.insert("errorMessage", QString("No such device: %1").arg(status.second)); returns.insert("errorMessage", QString("No such device: %1").arg(status.second));
break; break;
case DeviceManager::DeviceErrorMissingParameter:
returns.insert("success", false);
returns.insert("errorMessage", QString("Missing Parameter: %1").arg(status.second));
break;
default: default:
returns.insert("success", false); returns.insert("success", false);
returns.insert("errorMessage", "Unknown error."); returns.insert("errorMessage", "Unknown error.");

View File

@ -42,7 +42,7 @@
#include <QJsonDocument> #include <QJsonDocument>
#include <QStringList> #include <QStringList>
#define JSON_PROTOCOL_VERSION 2 #define JSON_PROTOCOL_VERSION 3
JsonRPCServer::JsonRPCServer(QObject *parent): JsonRPCServer::JsonRPCServer(QObject *parent):
JsonHandler(parent), JsonHandler(parent),

View File

@ -32,6 +32,7 @@ QVariantList JsonTypes::s_stateOperatorTypes;
QVariantList JsonTypes::s_valueOperatorTypes; QVariantList JsonTypes::s_valueOperatorTypes;
QVariantList JsonTypes::s_createMethodTypes; QVariantList JsonTypes::s_createMethodTypes;
QVariantList JsonTypes::s_setupMethodTypes; QVariantList JsonTypes::s_setupMethodTypes;
QVariantList JsonTypes::s_removePolicyTypes;
QVariantMap JsonTypes::s_paramType; QVariantMap JsonTypes::s_paramType;
QVariantMap JsonTypes::s_param; QVariantMap JsonTypes::s_param;
@ -60,6 +61,7 @@ void JsonTypes::init()
s_valueOperatorTypes << "OperatorTypeEquals" << "OperatorTypeNotEquals" << "OperatorTypeLess" << "OperatorTypeGreater" << "OperatorTypeLessThan" << "OperatorTypeGreaterThan"; s_valueOperatorTypes << "OperatorTypeEquals" << "OperatorTypeNotEquals" << "OperatorTypeLess" << "OperatorTypeGreater" << "OperatorTypeLessThan" << "OperatorTypeGreaterThan";
s_createMethodTypes << "CreateMethodUser" << "CreateMethodAuto" << "CreateMethodDiscovery"; s_createMethodTypes << "CreateMethodUser" << "CreateMethodAuto" << "CreateMethodDiscovery";
s_setupMethodTypes << "SetupMethodJustAdd" << "SetupMethodDisplayPin" << "SetupMethodEnterPin" << "SetupMethodPushButton"; s_setupMethodTypes << "SetupMethodJustAdd" << "SetupMethodDisplayPin" << "SetupMethodEnterPin" << "SetupMethodPushButton";
s_removePolicyTypes << "RemovePolicyCascade" << "RemovePolicyUpdate";
// ParamType // ParamType
s_paramType.insert("name", "string"); s_paramType.insert("name", "string");
@ -180,6 +182,7 @@ QVariantMap JsonTypes::allTypes()
allTypes.insert("SetupMethodType", setupMethodTypes()); allTypes.insert("SetupMethodType", setupMethodTypes());
allTypes.insert("ValueOperatorType", valueOperatorTypes()); allTypes.insert("ValueOperatorType", valueOperatorTypes());
allTypes.insert("StateOperatorType", stateOperatorTypes()); allTypes.insert("StateOperatorType", stateOperatorTypes());
allTypes.insert("RemovePolicyType", removePolicyTypes());
allTypes.insert("StateType", stateTypeDescription()); allTypes.insert("StateType", stateTypeDescription());
allTypes.insert("StateDescriptor", stateDescriptorDescription()); allTypes.insert("StateDescriptor", stateDescriptorDescription());
allTypes.insert("StateEvaluator", stateEvaluatorDescription()); allTypes.insert("StateEvaluator", stateEvaluatorDescription());

View File

@ -69,6 +69,7 @@ public:
DECLARE_TYPE(valueOperatorTypes, "ValueOperatorType") DECLARE_TYPE(valueOperatorTypes, "ValueOperatorType")
DECLARE_TYPE(createMethodTypes, "CreateMethodType") DECLARE_TYPE(createMethodTypes, "CreateMethodType")
DECLARE_TYPE(setupMethodTypes, "SetupMethodType") DECLARE_TYPE(setupMethodTypes, "SetupMethodType")
DECLARE_TYPE(removePolicyTypes, "RemovePolicyType")
DECLARE_OBJECT(paramType, "ParamType") DECLARE_OBJECT(paramType, "ParamType")
DECLARE_OBJECT(param, "Param") DECLARE_OBJECT(param, "Param")
DECLARE_OBJECT(paramDescriptor, "ParamDescriptor") DECLARE_OBJECT(paramDescriptor, "ParamDescriptor")

View File

@ -32,11 +32,16 @@ RulesHandler::RulesHandler(QObject *parent) :
params.clear(); returns.clear(); params.clear(); returns.clear();
setDescription("GetRules", "Get all configured rules"); setDescription("GetRules", "Get all configured rules");
setParams("GetRules", params); setParams("GetRules", params);
QVariantList rules; returns.insert("ruleIds", QVariantList() << "uuid");
rules.append(JsonTypes::ruleRef());
returns.insert("rules", rules);
setReturns("GetRules", returns); setReturns("GetRules", returns);
params.clear(); returns.clear();
setDescription("GetRuleDetails", "Get details for the rule identified by ruleId");
params.insert("ruleId", "uuid");
setParams("GetRuleDetails", params);
returns.insert("rule", JsonTypes::ruleRef());
setReturns("GetRuleDetails", returns);
params.clear(); returns.clear(); params.clear(); returns.clear();
setDescription("AddRule", "Add a rule."); setDescription("AddRule", "Add a rule.");
params.insert("o:eventDescriptor", JsonTypes::eventDescriptorRef()); params.insert("o:eventDescriptor", JsonTypes::eventDescriptorRef());
@ -58,6 +63,13 @@ RulesHandler::RulesHandler(QObject *parent) :
returns.insert("success", "bool"); returns.insert("success", "bool");
returns.insert("errorMessage", "string"); returns.insert("errorMessage", "string");
setReturns("RemoveRule", returns); setReturns("RemoveRule", returns);
params.clear(); returns.clear();
setDescription("FindRules", "Find a list of rules containing any of the given parameters.");
params.insert("deviceId", "uuid");
setParams("FindRules", params);
returns.insert("ruleIds", QVariantList() << "uuid");
setReturns("FindRules", returns);
} }
QString RulesHandler::name() const QString RulesHandler::name() const
@ -70,16 +82,26 @@ JsonReply* RulesHandler::GetRules(const QVariantMap &params)
Q_UNUSED(params) Q_UNUSED(params)
QVariantList rulesList; QVariantList rulesList;
foreach (const Rule &rule, GuhCore::instance()->rules()) { foreach (const RuleId &ruleId, GuhCore::instance()->ruleIds()) {
QVariantMap ruleMap = JsonTypes::packRule(rule); rulesList.append(ruleId);
rulesList.append(ruleMap);
} }
QVariantMap returns; QVariantMap returns;
returns.insert("rules", rulesList); returns.insert("ruleIds", rulesList);
return createReply(returns); return createReply(returns);
} }
JsonReply *RulesHandler::GetRuleDetails(const QVariantMap &params)
{
RuleId ruleId = RuleId(params.value("ruleId").toString());
Rule rule = GuhCore::instance()->findRule(ruleId);
QVariantMap ruleData;
if (!rule.id().isNull()) {
ruleData.insert("rule", JsonTypes::packRule(rule));
}
return createReply(ruleData);
}
JsonReply* RulesHandler::AddRule(const QVariantMap &params) JsonReply* RulesHandler::AddRule(const QVariantMap &params)
{ {
if (params.contains("eventDescriptor") && params.contains("eventDescriptorList")) { if (params.contains("eventDescriptor") && params.contains("eventDescriptorList")) {
@ -157,3 +179,18 @@ JsonReply* RulesHandler::RemoveRule(const QVariantMap &params)
} }
return createReply(returns); return createReply(returns);
} }
JsonReply *RulesHandler::FindRules(const QVariantMap &params)
{
DeviceId deviceId = DeviceId(params.value("deviceId").toString());
QList<RuleId> rules = GuhCore::instance()->findRules(deviceId);
QVariantList rulesList;
foreach (const RuleId &ruleId, rules) {
rulesList.append(ruleId);
}
QVariantMap returns;
returns.insert("ruleIds", rulesList);
return createReply(returns);
}

View File

@ -30,9 +30,11 @@ public:
QString name() const override; QString name() const override;
Q_INVOKABLE JsonReply* GetRules(const QVariantMap &params); Q_INVOKABLE JsonReply* GetRules(const QVariantMap &params);
Q_INVOKABLE JsonReply* GetRuleDetails(const QVariantMap &params);
Q_INVOKABLE JsonReply* AddRule(const QVariantMap &params); Q_INVOKABLE JsonReply* AddRule(const QVariantMap &params);
Q_INVOKABLE JsonReply* RemoveRule(const QVariantMap &params); Q_INVOKABLE JsonReply* RemoveRule(const QVariantMap &params);
Q_INVOKABLE JsonReply* FindRules(const QVariantMap &params);
}; };

View File

@ -133,7 +133,7 @@ RuleEngine::RuleEngine(QObject *parent) :
settings.endGroup(); settings.endGroup();
Rule rule = Rule(RuleId(idString), eventDescriptorList, stateEvaluator, actions); Rule rule = Rule(RuleId(idString), eventDescriptorList, stateEvaluator, actions);
m_rules.append(rule); appendRule(rule);
} }
} }
@ -149,12 +149,12 @@ QList<Action> RuleEngine::evaluateEvent(const Event &event)
qDebug() << "got event:" << event << device->name(); qDebug() << "got event:" << event << device->name();
QList<Action> actions; QList<Action> actions;
for (int i = 0; i < m_rules.count(); ++i) { foreach (const RuleId &id, m_ruleIds) {
qDebug() << "evaluating rule" << i << m_rules.at(i).eventDescriptors(); Rule rule = m_rules.value(id);
if (containsEvent(m_rules.at(i), event)) { if (containsEvent(rule, event)) {
if (m_rules.at(i).stateEvaluator().evaluate()) { if (rule.stateEvaluator().evaluate()) {
qDebug() << "states matching!"; qDebug() << "states matching!";
actions.append(m_rules.at(i).actions()); actions.append(rule.actions());
} }
} }
} }
@ -220,7 +220,7 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QList<Even
} }
Rule rule = Rule(ruleId, eventDescriptorList, stateEvaluator, actions); Rule rule = Rule(ruleId, eventDescriptorList, stateEvaluator, actions);
m_rules.append(rule); appendRule(rule);
emit ruleAdded(rule.id()); emit ruleAdded(rule.id());
QSettings settings(m_settingsFile); QSettings settings(m_settingsFile);
@ -263,10 +263,18 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QList<Even
return RuleErrorNoError; return RuleErrorNoError;
} }
/*! Returns a list of all \l{Rule}{Rules} loaded in this Engine.*/ /*! Returns a list of all \l{Rule}{Rules} loaded in this Engine.
Be aware that this does not necessarily reflect the order of the rules in the engine.
Use ruleIds() if you need the correct order.
*/
QList<Rule> RuleEngine::rules() const QList<Rule> RuleEngine::rules() const
{ {
return m_rules; return m_rules.values();
}
QList<RuleId> RuleEngine::ruleIds() const
{
return m_ruleIds;
} }
/*! Removes the \l{Rule} with the given \a ruleId from the Engine. /*! Removes the \l{Rule} with the given \a ruleId from the Engine.
@ -274,22 +282,22 @@ QList<Rule> RuleEngine::rules() const
was successful or not. */ was successful or not. */
RuleEngine::RuleError RuleEngine::removeRule(const RuleId &ruleId) RuleEngine::RuleError RuleEngine::removeRule(const RuleId &ruleId)
{ {
for (int i = 0; i < m_rules.count(); ++i) { int index = m_ruleIds.indexOf(ruleId);
Rule rule = m_rules.at(i);
if (rule.id() == ruleId) {
m_rules.takeAt(i); if (index < 0) {
return RuleErrorRuleNotFound;
QSettings settings(m_settingsFile);
settings.beginGroup(rule.id().toString());
settings.remove("");
settings.endGroup();
emit ruleRemoved(rule.id());
return RuleErrorNoError;
}
} }
return RuleErrorRuleNotFound;
m_ruleIds.takeAt(index);
m_rules.remove(ruleId);
QSettings settings(m_settingsFile);
settings.beginGroup(ruleId.toString());
settings.remove("");
settings.endGroup();
emit ruleRemoved(ruleId);
return RuleErrorNoError;
} }
Rule RuleEngine::findRule(const RuleId &ruleId) Rule RuleEngine::findRule(const RuleId &ruleId)
@ -302,6 +310,68 @@ Rule RuleEngine::findRule(const RuleId &ruleId)
return Rule(); return Rule();
} }
QList<RuleId> RuleEngine::findRules(const DeviceId &deviceId)
{
// Find all offending rules
QList<RuleId> offendingRules;
foreach (const Rule &rule, m_rules) {
bool offending = false;
foreach (const EventDescriptor &eventDescriptor, rule.eventDescriptors()) {
if (eventDescriptor.deviceId() == deviceId) {
offending = true;
break;
}
}
if (!offending && rule.stateEvaluator().containsDevice(deviceId)) {
offending = true;
}
if (!offending) {
foreach (const Action &action, rule.actions()) {
if (action.deviceId() == deviceId) {
offending = true;
break;
}
}
}
if (offending) {
offendingRules.append(rule.id());
}
}
return offendingRules;
}
void RuleEngine::removeDeviceFromRule(const RuleId &id, const DeviceId &deviceId)
{
if (!m_rules.contains(id)) {
return;
}
Rule rule = m_rules.value(id);
QList<EventDescriptor> eventDescriptors = rule.eventDescriptors();
QList<int> removeIndexes;
for (int i = 0; i < eventDescriptors.count(); i++) {
if (eventDescriptors.at(i).deviceId() == deviceId) {
removeIndexes.append(i);
}
}
while (removeIndexes.count() > 0) {
eventDescriptors.takeAt(removeIndexes.takeLast());
}
StateEvaluator stateEvalatuator = rule.stateEvaluator();
stateEvalatuator.removeDevice(deviceId);
QList<Action> actions = rule.actions();
for (int i = 0; i < actions.count(); i++) {
if (actions.at(i).deviceId() == deviceId) {
removeIndexes.append(i);
}
}
while (removeIndexes.count() > 0) {
actions.takeAt(removeIndexes.takeLast());
}
Rule newRule(id, eventDescriptors, stateEvalatuator, actions);
m_rules[id] = newRule;
}
bool RuleEngine::containsEvent(const Rule &rule, const Event &event) bool RuleEngine::containsEvent(const Rule &rule, const Event &event)
{ {
foreach (const EventDescriptor &eventDescriptor, rule.eventDescriptors()) { foreach (const EventDescriptor &eventDescriptor, rule.eventDescriptors()) {
@ -311,3 +381,9 @@ bool RuleEngine::containsEvent(const Rule &rule, const Event &event)
} }
return false; return false;
} }
void RuleEngine::appendRule(const Rule &rule)
{
m_rules.insert(rule.id(), rule);
m_ruleIds.append(rule.id());
}

View File

@ -40,6 +40,11 @@ public:
RuleErrorActionTypeNotFound RuleErrorActionTypeNotFound
}; };
enum RemovePolicy {
RemovePolicyCascade,
RemovePolicyUpdate
};
explicit RuleEngine(QObject *parent = 0); explicit RuleEngine(QObject *parent = 0);
QList<Action> evaluateEvent(const Event &event); QList<Action> evaluateEvent(const Event &event);
@ -47,10 +52,14 @@ public:
RuleError addRule(const RuleId &ruleId, const QList<EventDescriptor> &eventDescriptorList, const QList<Action> &actions); RuleError addRule(const RuleId &ruleId, const QList<EventDescriptor> &eventDescriptorList, const QList<Action> &actions);
RuleError addRule(const RuleId &ruleId, const QList<EventDescriptor> &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList<Action> &actions); RuleError addRule(const RuleId &ruleId, const QList<EventDescriptor> &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList<Action> &actions);
QList<Rule> rules() const; QList<Rule> rules() const;
QList<RuleId> ruleIds() const;
RuleError removeRule(const RuleId &ruleId); RuleError removeRule(const RuleId &ruleId);
Rule findRule(const RuleId &ruleId); Rule findRule(const RuleId &ruleId);
QList<RuleId> findRules(const DeviceId &deviceId);
void removeDeviceFromRule(const RuleId &id, const DeviceId &deviceId);
signals: signals:
void ruleAdded(const RuleId &ruleId); void ruleAdded(const RuleId &ruleId);
@ -59,10 +68,12 @@ signals:
private: private:
bool containsEvent(const Rule &rule, const Event &event); bool containsEvent(const Rule &rule, const Event &event);
void appendRule(const Rule &rule);
private: private:
QString m_settingsFile; QString m_settingsFile;
QList<Rule> m_rules; QList<RuleId> m_ruleIds; // Keeping a list of RuleIds to keep sorting order...
QHash<RuleId, Rule> m_rules; // ...but use a Hash for faster finding
}; };
#endif // RULEENGINE_H #endif // RULEENGINE_H

View File

@ -99,6 +99,29 @@ bool StateEvaluator::evaluate() const
return true; return true;
} }
bool StateEvaluator::containsDevice(const DeviceId &deviceId) const
{
if (m_stateDescriptor.deviceId() == deviceId) {
return true;
}
foreach (const StateEvaluator &childEvaluator, m_childEvaluators) {
if (childEvaluator.containsDevice(deviceId)) {
return true;
}
}
return false;
}
void StateEvaluator::removeDevice(const DeviceId &deviceId)
{
if (m_stateDescriptor.deviceId() == deviceId) {
m_stateDescriptor = StateDescriptor();
}
for (int i = 0; i < m_childEvaluators.count(); i++) {
m_childEvaluators[i].removeDevice(deviceId);
}
}
void StateEvaluator::dumpToSettings(QSettings &settings, const QString &groupName) const void StateEvaluator::dumpToSettings(QSettings &settings, const QString &groupName) const
{ {
settings.beginGroup(groupName); settings.beginGroup(groupName);

View File

@ -45,6 +45,9 @@ public:
void setOperatorType(StateOperator operatorType); void setOperatorType(StateOperator operatorType);
bool evaluate() const; bool evaluate() const;
bool containsDevice(const DeviceId &deviceId) const;
void removeDevice(const DeviceId &deviceId);
void dumpToSettings(QSettings &settings, const QString &groupName) const; void dumpToSettings(QSettings &settings, const QString &groupName) const;
static StateEvaluator loadFromSettings(QSettings &settings, const QString &groupPrefix); static StateEvaluator loadFromSettings(QSettings &settings, const QString &groupPrefix);

View File

@ -1,4 +1,4 @@
2 3
{ {
"methods": { "methods": {
"Actions.ExecuteAction": { "Actions.ExecuteAction": {
@ -194,7 +194,13 @@
"Devices.RemoveConfiguredDevice": { "Devices.RemoveConfiguredDevice": {
"description": "Remove a device from the system.", "description": "Remove a device from the system.",
"params": { "params": {
"deviceId": "uuid" "deviceId": "uuid",
"o:removePolicyList": [
{
"policy": "$ref:RemovePolicyType",
"ruleId": "uuid"
}
]
}, },
"returns": { "returns": {
"errorMessage": "string", "errorMessage": "string",
@ -261,13 +267,33 @@
"success": "bool" "success": "bool"
} }
}, },
"Rules.FindRules": {
"description": "Find a list of rules containing any of the given parameters.",
"params": {
"deviceId": "uuid"
},
"returns": {
"ruleIds": [
"uuid"
]
}
},
"Rules.GetRuleDetails": {
"description": "Get details for the rule identified by ruleId",
"params": {
"ruleId": "uuid"
},
"returns": {
"rule": "$ref:Rule"
}
},
"Rules.GetRules": { "Rules.GetRules": {
"description": "Get all configured rules", "description": "Get all configured rules",
"params": { "params": {
}, },
"returns": { "returns": {
"rules": [ "ruleIds": [
"$ref:Rule" "uuid"
] ]
} }
}, },
@ -405,6 +431,10 @@
"$ref:Param" "$ref:Param"
] ]
}, },
"RemovePolicyType": [
"RemovePolicyCascade",
"RemovePolicyUpdate"
],
"Rule": { "Rule": {
"actions": [ "actions": [
"$ref:Action" "$ref:Action"

View File

@ -142,7 +142,7 @@ void TestRules::addRemoveRules()
RuleId newRuleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString()); RuleId newRuleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString());
response = injectAndWait("Rules.GetRules"); response = injectAndWait("Rules.GetRules");
QVariantList rules = response.toMap().value("params").toMap().value("rules").toList(); QVariantList rules = response.toMap().value("params").toMap().value("ruleIds").toList();
if (!success) { if (!success) {
QVERIFY2(rules.count() == 0, "There should be no rules."); QVERIFY2(rules.count() == 0, "There should be no rules.");
@ -150,10 +150,16 @@ void TestRules::addRemoveRules()
} }
QVERIFY2(rules.count() == 1, "There should be exactly one rule"); QVERIFY2(rules.count() == 1, "There should be exactly one rule");
QCOMPARE(RuleId(rules.first().toMap().value("id").toString()), newRuleId); QCOMPARE(RuleId(rules.first().toString()), newRuleId);
params.clear();
params.insert("ruleId", newRuleId);
response = injectAndWait("Rules.GetRuleDetails", params);
// verifySuccess(response);
QVariantList eventDescriptors = rules.first().toMap().value("eventDescriptors").toList(); QVariantMap rule = response.toMap().value("params").toMap().value("rule").toMap();
QVariantList eventDescriptors = rule.value("eventDescriptors").toList();
if (!eventDescriptor.isEmpty()) { if (!eventDescriptor.isEmpty()) {
QVERIFY2(eventDescriptors.count() == 1, "There shoud be exactly one eventDescriptor"); QVERIFY2(eventDescriptors.count() == 1, "There shoud be exactly one eventDescriptor");
QVERIFY2(eventDescriptors.first().toMap() == eventDescriptor, "Event descriptor doesn't match"); QVERIFY2(eventDescriptors.first().toMap() == eventDescriptor, "Event descriptor doesn't match");
@ -172,7 +178,7 @@ void TestRules::addRemoveRules()
} }
} }
QVariantList replyActions = rules.first().toMap().value("actions").toList(); QVariantList replyActions = rule.value("actions").toList();
QVERIFY2(actions == replyActions, "Actions don't match"); QVERIFY2(actions == replyActions, "Actions don't match");
@ -251,12 +257,18 @@ void TestRules::loadStoreConfig()
response = injectAndWait("Rules.GetRules"); response = injectAndWait("Rules.GetRules");
QVariantList rules = response.toMap().value("params").toMap().value("rules").toList(); QVariantList rules = response.toMap().value("params").toMap().value("ruleIds").toList();
QVERIFY2(rules.count() == 1, "There should be exactly one rule"); QVERIFY2(rules.count() == 1, "There should be exactly one rule");
QCOMPARE(RuleId(rules.first().toMap().value("id").toString()), newRuleId); QCOMPARE(RuleId(rules.first().toString()), newRuleId);
QVariantList eventDescriptors = rules.first().toMap().value("eventDescriptors").toList(); params.clear();
params.insert("ruleId", rules.first().toString());
response = injectAndWait("Rules.GetRuleDetails", params);
QVariantMap rule = response.toMap().value("params").toMap().value("rule").toMap();
QVariantList eventDescriptors = rule.value("eventDescriptors").toList();
QVERIFY2(eventDescriptors.count() == 2, "There shoud be exactly 2 eventDescriptors"); QVERIFY2(eventDescriptors.count() == 2, "There shoud be exactly 2 eventDescriptors");
foreach (const QVariant &expectedEventDescriptorVariant, eventDescriptorList) { foreach (const QVariant &expectedEventDescriptorVariant, eventDescriptorList) {
bool found = false; bool found = false;
@ -270,7 +282,7 @@ void TestRules::loadStoreConfig()
QVERIFY2(found, "missing eventdescriptor"); QVERIFY2(found, "missing eventdescriptor");
} }
QVariantList replyActions = rules.first().toMap().value("actions").toList(); QVariantList replyActions = rule.value("actions").toList();
foreach (const QVariant &actionVariant, actions) { foreach (const QVariant &actionVariant, actions) {
bool found = false; bool found = false;
foreach (const QVariant &replyActionVariant, replyActions) { foreach (const QVariant &replyActionVariant, replyActions) {