diff --git a/debian/changelog b/debian/changelog index 893fb0ab..4fa57d96 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +guh (0.1.7) utopic; urgency=medium + + * implement StateEvaluators + + -- Michael Zanetti Sun, 08 Jun 2014 23:27:31 +0200 + guh (0.1.6) utopic; urgency=medium * state changes auto generate events now diff --git a/libguh/libguh.pro b/libguh/libguh.pro index eb0a1272..8aca0cb1 100644 --- a/libguh/libguh.pro +++ b/libguh/libguh.pro @@ -26,6 +26,7 @@ SOURCES += plugin/device.cpp \ types/paramtype.cpp \ types/param.cpp \ types/paramdescriptor.cpp \ + types/statedescriptor.cpp HEADERS += plugin/device.h \ plugin/deviceclass.h \ @@ -45,5 +46,6 @@ HEADERS += plugin/device.h \ types/typeutils.h \ types/paramtype.h \ types/param.h \ - types/paramdescriptor.h + types/paramdescriptor.h \ + types/statedescriptor.h diff --git a/libguh/plugin/device.cpp b/libguh/plugin/device.cpp index 5a32224c..38421420 100644 --- a/libguh/plugin/device.cpp +++ b/libguh/plugin/device.cpp @@ -146,7 +146,6 @@ bool Device::hasState(const StateTypeId &stateTypeId) const /*! For convenience, this finds the \l{State} matching the given \a stateTypeId and returns the current valie in this Device. */ QVariant Device::stateValue(const StateTypeId &stateTypeId) const { - qDebug() << "device has states:" << m_states.count(); foreach (const State &state, m_states) { qDebug() << "checking" << stateTypeId << state.stateTypeId(); if (state.stateTypeId() == stateTypeId) { @@ -171,6 +170,16 @@ void Device::setStateValue(const StateTypeId &stateTypeId, const QVariant &value qWarning() << "failed setting state for" << m_name; } +State Device::state(const StateTypeId &stateTypeId) const +{ + for (int i = 0; i < m_states.count(); ++i) { + if (m_states.at(i).stateTypeId() == stateTypeId) { + return m_states.at(i); + } + } + return State(StateTypeId(), DeviceId()); +} + bool Device::setupComplete() const { return m_setupComplete; diff --git a/libguh/plugin/device.h b/libguh/plugin/device.h index 76181fc9..956cf003 100644 --- a/libguh/plugin/device.h +++ b/libguh/plugin/device.h @@ -45,18 +45,20 @@ public: void setName(const QString &name); QList params() const; + bool hasParam(const QString ¶mName) const; void setParams(const QList ¶ms); QVariant paramValue(const QString ¶mName) const; QList states() const; - bool hasParam(const QString ¶mName) const; + bool hasState(const StateTypeId &stateTypeId) const; void setStates(const QList &states); - bool hasState(const StateTypeId &stateTypeId) const; QVariant stateValue(const StateTypeId &stateTypeId) const; void setStateValue(const StateTypeId &stateTypeId, const QVariant &value); + State state(const StateTypeId &stateTypeId) const; + bool setupComplete() const; signals: diff --git a/libguh/types/eventdescriptor.cpp b/libguh/types/eventdescriptor.cpp index a9668c4d..d30bf66e 100644 --- a/libguh/types/eventdescriptor.cpp +++ b/libguh/types/eventdescriptor.cpp @@ -32,13 +32,19 @@ /*! Constructs an EventDescriptor describing an Event. */ -EventDescriptor::EventDescriptor(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList ¶mDescriptors): +EventDescriptor::EventDescriptor(const EventDescriptorId &id, const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList ¶mDescriptors): + m_id(id), m_eventTypeId(eventTypeId), m_deviceId(deviceId), m_paramDescriptors(paramDescriptors) { } +EventDescriptorId EventDescriptor::id() const +{ + return m_id; +} + /*! Returns the id of the \l{EventType} which describes this Event.*/ EventTypeId EventDescriptor::eventTypeId() const { @@ -98,33 +104,33 @@ bool EventDescriptor::operator ==(const Event &event) const } foreach (const ParamDescriptor ¶mDescriptor, m_paramDescriptors) { - switch (paramDescriptor.operand()) { - case ParamDescriptor::OperandTypeEquals: + switch (paramDescriptor.operatorType()) { + case ValueOperatorEquals: if (event.param(paramDescriptor.name()).value() != paramDescriptor.value()) { return false; } break; - case ParamDescriptor::OperandTypeNotEquals: + case ValueOperatorNotEquals: if (event.param(paramDescriptor.name()).value() == paramDescriptor.value()) { return false; } break; - case ParamDescriptor::OperandTypeGreater: + case ValueOperatorGreater: if (event.param(paramDescriptor.name()).value() <= paramDescriptor.value()) { return false; } break; - case ParamDescriptor::OperandTypeGreaterOrEqual: + case ValueOperatorGreaterOrEqual: if (event.param(paramDescriptor.name()).value() < paramDescriptor.value()) { return false; } break; - case ParamDescriptor::OperandTypeLess: + case ValueOperatorLess: if (event.param(paramDescriptor.name()).value() >= paramDescriptor.value()) { return false; } break; - case ParamDescriptor::OperandTypeLessOrEqual: + case ValueOperatorLessOrEqual: if (event.param(paramDescriptor.name()).value() < paramDescriptor.value()) { return false; } diff --git a/libguh/types/eventdescriptor.h b/libguh/types/eventdescriptor.h index b666a748..5a01caaa 100644 --- a/libguh/types/eventdescriptor.h +++ b/libguh/types/eventdescriptor.h @@ -30,7 +30,9 @@ class EventDescriptor { public: - EventDescriptor(const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList ¶mDescriptors = QList()); + EventDescriptor(const EventDescriptorId &id, const EventTypeId &eventTypeId, const DeviceId &deviceId, const QList ¶mDescriptors = QList()); + + EventDescriptorId id() const; EventTypeId eventTypeId() const; DeviceId deviceId() const; @@ -44,6 +46,7 @@ public: bool operator ==(const Event &event) const; private: + EventDescriptorId m_id; EventTypeId m_eventTypeId; DeviceId m_deviceId; QList m_paramDescriptors; diff --git a/libguh/types/paramdescriptor.cpp b/libguh/types/paramdescriptor.cpp index e0220514..a64f69b8 100644 --- a/libguh/types/paramdescriptor.cpp +++ b/libguh/types/paramdescriptor.cpp @@ -20,17 +20,17 @@ ParamDescriptor::ParamDescriptor(const QString &name, const QVariant &value): Param(name, value), - m_operand(OperandTypeEquals) + m_operatorType(ValueOperatorEquals) { } -ParamDescriptor::OperandType ParamDescriptor::operand() const +ValueOperator ParamDescriptor::operatorType() const { - return m_operand; + return m_operatorType; } -void ParamDescriptor::setOperand(ParamDescriptor::OperandType operand) +void ParamDescriptor::setOperatorType(ValueOperator operatorType) { - m_operand = operand; + m_operatorType = operatorType; } diff --git a/libguh/types/paramdescriptor.h b/libguh/types/paramdescriptor.h index 1891e36b..b9450449 100644 --- a/libguh/types/paramdescriptor.h +++ b/libguh/types/paramdescriptor.h @@ -20,25 +20,18 @@ #define PARAMDESCRIPTOR_H #include "param.h" +#include "typeutils.h" class ParamDescriptor : public Param { public: - enum OperandType { - OperandTypeEquals, - OperandTypeNotEquals, - OperandTypeLess, - OperandTypeGreater, - OperandTypeLessOrEqual, - OperandTypeGreaterOrEqual - }; ParamDescriptor(const QString &name, const QVariant &value = QVariant()); - OperandType operand() const; - void setOperand(OperandType operand); + ValueOperator operatorType() const; + void setOperatorType(ValueOperator operatorType); private: - OperandType m_operand; + ValueOperator m_operatorType; }; #endif // PARAMDESCRIPTOR_H diff --git a/libguh/types/statedescriptor.cpp b/libguh/types/statedescriptor.cpp new file mode 100644 index 00000000..53e6e615 --- /dev/null +++ b/libguh/types/statedescriptor.cpp @@ -0,0 +1,96 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "statedescriptor.h" + +StateDescriptor::StateDescriptor(): + m_id(StateDescriptorId::createStateDescriptorId()), + m_operatorType(ValueOperatorEquals) +{ + +} + +StateDescriptor::StateDescriptor(const StateDescriptorId &id, const StateTypeId &stateTypeId, const DeviceId &deviceId, const QVariant &stateValue, ValueOperator operatorType): + m_id(id), + m_stateTypeId(stateTypeId), + m_deviceId(deviceId), + m_stateValue(stateValue), + m_operatorType(operatorType) +{ + +} + +StateDescriptorId StateDescriptor::id() const +{ + return m_id; +} + +StateTypeId StateDescriptor::stateTypeId() const +{ + return m_stateTypeId; +} + +DeviceId StateDescriptor::deviceId() const +{ + return m_deviceId; +} + +QVariant StateDescriptor::stateValue() const +{ + return m_stateValue; +} + +ValueOperator StateDescriptor::operatorType() const +{ + return m_operatorType; +} + +bool StateDescriptor::operator ==(const StateDescriptor &other) const +{ + return m_stateTypeId == other.stateTypeId() && + m_deviceId == other.deviceId() && + m_stateValue == other.stateValue() && + m_operatorType == other.operatorType(); +} + +bool StateDescriptor::operator ==(const State &state) const +{ + if ((m_stateTypeId != state.stateTypeId()) || (m_deviceId != state.deviceId())) { + return false; + } + switch (m_operatorType) { + case ValueOperatorEquals: + return m_stateValue == state.value(); + case ValueOperatorGreater: + return m_stateValue > state.value(); + case ValueOperatorGreaterOrEqual: + return m_stateValue >= state.value(); + case ValueOperatorLess: + return m_stateValue < state.value(); + case ValueOperatorLessOrEqual: + return m_stateValue <= state.value(); + case ValueOperatorNotEquals: + return m_stateValue != state.value(); + } + return false; +} + +bool StateDescriptor::operator !=(const State &state) const +{ + return !(operator==(state)); +} diff --git a/libguh/types/statedescriptor.h b/libguh/types/statedescriptor.h new file mode 100644 index 00000000..4eb66885 --- /dev/null +++ b/libguh/types/statedescriptor.h @@ -0,0 +1,58 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef STATEDESCRIPTOR_H +#define STATEDESCRIPTOR_H + +#include "typeutils.h" +#include "paramdescriptor.h" +#include "state.h" + +#include +#include +#include + +class StateDescriptor +{ +public: + StateDescriptor(); + StateDescriptor(const StateDescriptorId &id, const StateTypeId &stateTypeId, const DeviceId &deviceId, const QVariant &stateValue, ValueOperator operatorType = ValueOperatorEquals); + + StateDescriptorId id() const; + + StateTypeId stateTypeId() const; + DeviceId deviceId() const; + QVariant stateValue() const; + ValueOperator operatorType() const; + + bool operator ==(const StateDescriptor &other) const; + + bool operator ==(const State &state) const; + bool operator !=(const State &state) const; + +private: + StateDescriptorId m_id; + StateTypeId m_stateTypeId; + DeviceId m_deviceId; + QVariant m_stateValue; + ValueOperator m_operatorType; +}; +QDebug operator<<(QDebug dbg, const StateDescriptor &eventDescriptor); +QDebug operator<<(QDebug dbg, const QList &eventDescriptors); + +#endif // STATEDESCRIPTOR_H diff --git a/libguh/typeutils.h b/libguh/typeutils.h index ed2ee8e3..4f8f6585 100644 --- a/libguh/typeutils.h +++ b/libguh/typeutils.h @@ -43,10 +43,28 @@ DECLARE_TYPE_ID(DeviceDescriptor) DECLARE_TYPE_ID(EventType) DECLARE_TYPE_ID(Event) +DECLARE_TYPE_ID(EventDescriptor) DECLARE_TYPE_ID(StateType) DECLARE_TYPE_ID(State) +DECLARE_TYPE_ID(StateDescriptor) +DECLARE_TYPE_ID(StateEvaluator) DECLARE_TYPE_ID(ActionType) DECLARE_TYPE_ID(Action) DECLARE_TYPE_ID(Plugin) +DECLARE_TYPE_ID(Rule) + +enum ValueOperator { + ValueOperatorEquals, + ValueOperatorNotEquals, + ValueOperatorLess, + ValueOperatorGreater, + ValueOperatorLessOrEqual, + ValueOperatorGreaterOrEqual +}; + +enum StateOperator { + StateOperatorAnd, + StateOperatorOr +}; #endif // TYPEUTILS_H diff --git a/server/jsonrpc/jsontypes.cpp b/server/jsonrpc/jsontypes.cpp index 6aea8a66..97474313 100644 --- a/server/jsonrpc/jsontypes.cpp +++ b/server/jsonrpc/jsontypes.cpp @@ -28,16 +28,18 @@ bool JsonTypes::s_initialized = false; QString JsonTypes::s_lastError; QVariantList JsonTypes::s_basicTypes; -QVariantList JsonTypes::s_ruleTypes; +QVariantList JsonTypes::s_stateOperatorTypes; +QVariantList JsonTypes::s_valueOperatorTypes; QVariantList JsonTypes::s_createMethodTypes; QVariantList JsonTypes::s_setupMethodTypes; -QVariantList JsonTypes::s_operandTypes; QVariantMap JsonTypes::s_paramType; QVariantMap JsonTypes::s_param; QVariantMap JsonTypes::s_paramDescriptor; QVariantMap JsonTypes::s_stateType; QVariantMap JsonTypes::s_state; +QVariantMap JsonTypes::s_stateDescriptor; +QVariantMap JsonTypes::s_stateEvaluator; QVariantMap JsonTypes::s_eventType; QVariantMap JsonTypes::s_event; QVariantMap JsonTypes::s_eventDescriptor; @@ -54,10 +56,10 @@ void JsonTypes::init() { // BasicTypes s_basicTypes << "uuid" << "string" << "integer" << "double" << "bool"; - s_ruleTypes << "RuleTypeMatchAll" << "RuleTypeMatchAny"; + s_stateOperatorTypes << "StateOperatorAnd" << "StateOperatorOr"; + s_valueOperatorTypes << "OperatorTypeEquals" << "OperatorTypeNotEquals" << "OperatorTypeLess" << "OperatorTypeGreater" << "OperatorTypeLessThan" << "OperatorTypeGreaterThan"; s_createMethodTypes << "CreateMethodUser" << "CreateMethodAuto" << "CreateMethodDiscovery"; s_setupMethodTypes << "SetupMethodJustAdd" << "SetupMethodDisplayPin" << "SetupMethodEnterPin" << "SetupMethodPushButton"; - s_operandTypes << "OperandTypeEquals" << "OperandTypeNotEquals" << "OperandTypeLess" << "OperandTypeGreater" << "OperandTypeLessThan" << "OperandTypeGreaterThan"; // ParamType s_paramType.insert("name", "string"); @@ -73,7 +75,7 @@ void JsonTypes::init() // ParamDescriptor s_paramDescriptor.insert("name", "string"); s_paramDescriptor.insert("value", basicTypesRef()); - s_paramDescriptor.insert("operand", operandTypesRef()); + s_paramDescriptor.insert("operator", valueOperatorTypesRef()); // StateType s_stateType.insert("id", "uuid"); @@ -86,6 +88,19 @@ void JsonTypes::init() s_state.insert("deviceId", "uuid"); s_state.insert("value", "variant"); + // StateDescriptor + s_stateDescriptor.insert("id", "uuid"); + s_stateDescriptor.insert("stateTypeId", "uuid"); + s_stateDescriptor.insert("deviceId", "uuid"); + s_stateDescriptor.insert("value", "variant"); + s_stateDescriptor.insert("operator", valueOperatorTypesRef()); + + // StateEvaluator + s_stateEvaluator.insert("id", "uuid"); + s_stateEvaluator.insert("o:stateDescriptor", stateDescriptorRef()); + s_stateEvaluator.insert("o:childEvaluators", QVariantList() << stateEvaluatorRef()); + s_stateEvaluator.insert("o:operator", stateOperatorTypesRef()); + // EventType s_eventType.insert("id", "uuid"); s_eventType.insert("name", "string"); @@ -146,10 +161,9 @@ void JsonTypes::init() // Rule s_rule.insert("id", "uuid"); - s_rule.insert("ruleType", ruleTypesRef()); s_rule.insert("eventDescriptors", QVariantList() << eventDescriptorRef()); s_rule.insert("actions", QVariantList() << actionRef()); - s_rule.insert("states", QVariantList() << stateRef()); + s_rule.insert("stateEvaluator", stateEvaluatorRef()); s_initialized = true; } @@ -166,8 +180,11 @@ QVariantMap JsonTypes::allTypes() allTypes.insert("ParamType", paramTypeDescription()); allTypes.insert("CreateMethodType", createMethodTypes()); allTypes.insert("SetupMethodType", setupMethodTypes()); - allTypes.insert("OperandType", operandTypes()); + allTypes.insert("ValueOperatorType", valueOperatorTypes()); + allTypes.insert("StateOperatorType", stateOperatorTypes()); allTypes.insert("StateType", stateTypeDescription()); + allTypes.insert("StateDescriptor", stateDescriptorDescription()); + allTypes.insert("StateEvaluator", stateEvaluatorDescription()); allTypes.insert("Event", eventDescription()); allTypes.insert("EventType", eventTypeDescription()); allTypes.insert("EventDescriptor", eventDescriptorDescription()); @@ -181,7 +198,6 @@ QVariantMap JsonTypes::allTypes() allTypes.insert("Device", deviceDescription()); allTypes.insert("DeviceDescriptor", deviceDescriptorDescription()); allTypes.insert("Action", actionDescription()); - allTypes.insert("RuleType", ruleTypes()); allTypes.insert("Rule", ruleDescription()); return allTypes; } @@ -221,7 +237,7 @@ QVariantMap JsonTypes::packEventDescriptor(const EventDescriptor &eventDescripto foreach (const ParamDescriptor ¶mDescriptor, eventDescriptor.paramDescriptors()) { params.append(packParamDescriptor(paramDescriptor)); } - variant.insert("params", params); + variant.insert("paramDescriptors", params); return variant; } @@ -261,6 +277,31 @@ QVariantMap JsonTypes::packStateType(const StateType &stateType) return variantMap; } +QVariantMap JsonTypes::packStateDescriptor(const StateDescriptor &stateDescriptor) +{ + QVariantMap variantMap; + variantMap.insert("id", stateDescriptor.id().toString()); + variantMap.insert("stateTypeId", stateDescriptor.stateTypeId().toString()); + variantMap.insert("deviceId", stateDescriptor.deviceId().toString()); + variantMap.insert("value", stateDescriptor.stateValue()); + variantMap.insert("operator", valueOperatorTypes().at(stateDescriptor.operatorType())); + return variantMap; +} + +QVariantMap JsonTypes::packStateEvaluator(const StateEvaluator &stateEvaluator) +{ + QVariantMap variantMap; + variantMap.insert("id", stateEvaluator.id()); + variantMap.insert("stateDescriptor", packStateDescriptor(stateEvaluator.stateDescriptor())); + QVariantList childEvaluators; + foreach (const StateEvaluator &childEvaluator, stateEvaluator.childEvaluators()) { + childEvaluators.append(packStateEvaluator(childEvaluator)); + } + variantMap.insert("childEvaluators", childEvaluators); + + return variantMap; +} + QVariantMap JsonTypes::packParam(const Param ¶m) { QVariantMap variantMap; @@ -273,7 +314,7 @@ QVariantMap JsonTypes::packParamDescriptor(const ParamDescriptor ¶mDescripto QVariantMap variantMap; variantMap.insert("name", paramDescriptor.name()); variantMap.insert("value", paramDescriptor.value()); - variantMap.insert("operand", s_operandTypes.at(paramDescriptor.operand())); + variantMap.insert("operator", s_valueOperatorTypes.at(paramDescriptor.operatorType())); return variantMap; } @@ -380,16 +421,12 @@ QVariantMap JsonTypes::packRule(const Rule &rule) } ruleMap.insert("eventDescriptors", eventDescriptorList); - ruleMap.insert("ruleType", s_ruleTypes.at(rule.ruleType())); - QVariantList actionList; foreach (const Action &action, rule.actions()) { actionList.append(JsonTypes::packAction(action)); } ruleMap.insert("actions", actionList); - - QVariantList states; - ruleMap.insert("states", states); + ruleMap.insert("stateEvaluator", JsonTypes::packStateEvaluator(rule.stateEvaluator())); return ruleMap; } @@ -412,19 +449,19 @@ QList JsonTypes::unpackParams(const QVariantList ¶mList) ParamDescriptor JsonTypes::unpackParamDescriptor(const QVariantMap ¶mMap) { ParamDescriptor param(paramMap.value("name").toString(), paramMap.value("value")); - QString operandString = paramMap.value("operand").toString(); - if (operandString == "OperandTypeEquals") { - param.setOperand(ParamDescriptor::OperandTypeEquals); - } else if (operandString == "OperandTypeNotEquals") { - param.setOperand(ParamDescriptor::OperandTypeNotEquals); - } else if (operandString == "OperandTypeLess") { - param.setOperand(ParamDescriptor::OperandTypeLess); - } else if (operandString == "OperandTypeGreater") { - param.setOperand(ParamDescriptor::OperandTypeGreater); - } else if (operandString == "OperandTypeLessOrEqual") { - param.setOperand(ParamDescriptor::OperandTypeLessOrEqual); - } else if (operandString == "OperandTypeGreaterOrEqual") { - param.setOperand(ParamDescriptor::OperandTypeGreaterOrEqual); + QString operatorString = paramMap.value("operator").toString(); + if (operatorString == "ValueOperatorEquals") { + param.setOperatorType(ValueOperatorEquals); + } else if (operatorString == "ValueOperatorNotEquals") { + param.setOperatorType(ValueOperatorNotEquals); + } else if (operatorString == "ValueOperatorLess") { + param.setOperatorType(ValueOperatorLess); + } else if (operatorString == "ValueOperatorGreater") { + param.setOperatorType(ValueOperatorGreater); + } else if (operatorString == "ValueOperatorLessOrEqual") { + param.setOperatorType(ValueOperatorLessOrEqual); + } else if (operatorString == "ValueOperatorGreaterOrEqual") { + param.setOperatorType(ValueOperatorGreaterOrEqual); } return param; } @@ -589,6 +626,18 @@ QPair JsonTypes::validateVariant(const QVariant &templateVariant, qDebug() << "state type not matching"; return result; } + } else if (refName == stateEvaluatorRef()) { + QPair result = validateMap(stateEvaluatorDescription(), variant.toMap()); + if (!result.first) { + qDebug() << "stateEvaluator type not matching"; + return result; + } + } else if (refName == stateDescriptorRef()) { + QPair result = validateMap(stateDescriptorDescription(), variant.toMap()); + if (!result.first) { + qDebug() << "stateDescriptor type not matching"; + return result; + } } else if (refName == pluginRef()) { QPair result = validateMap(pluginDescription(), variant.toMap()); if (!result.first) { @@ -601,16 +650,22 @@ QPair JsonTypes::validateVariant(const QVariant &templateVariant, qDebug() << "rule type not matching"; return result; } + } else if (refName == eventDescriptorRef()) { + QPair result = validateMap(eventDescriptorDescription(), variant.toMap()); + if (!result.first) { + qDebug() << "evendescriptor not matching"; + return result; + } } else if (refName == basicTypesRef()) { QPair result = validateBasicType(variant); if (!result.first) { qDebug() << "value not allowed in" << basicTypesRef(); return result; } - } else if (refName == ruleTypesRef()) { - QPair result = validateRuleType(variant); + } else if (refName == stateOperatorTypesRef()) { + QPair result = validateStateOperatorType(variant); if (!result.first) { - qDebug() << "value not allowed in" << ruleTypesRef(); + qDebug() << "value not allowed in" << stateOperatorTypesRef(); return result; } } else if (refName == createMethodTypesRef()) { @@ -625,10 +680,10 @@ QPair JsonTypes::validateVariant(const QVariant &templateVariant, qDebug() << "value not allowed in" << createMethodTypesRef(); return result; } - } else if (refName == operandTypesRef()) { - QPair result = validateOperandType(variant); + } else if (refName == valueOperatorTypesRef()) { + QPair result = validateValueOperatorType(variant); if (!result.first) { - qDebug() << QString("value %1 not allowed in %2").arg(variant.toString()).arg(operandTypesRef()); + qDebug() << QString("value %1 not allowed in %2").arg(variant.toString()).arg(valueOperatorTypesRef()); return result; } } else { @@ -685,9 +740,9 @@ QPair JsonTypes::validateBasicType(const QVariant &variant) return report(false, QString("Error validating basic type %1.").arg(variant.toString())); } -QPair JsonTypes::validateRuleType(const QVariant &variant) +QPair JsonTypes::validateStateOperatorType(const QVariant &variant) { - return report(s_ruleTypes.contains(variant.toString()), QString("Unknown rules type %1").arg(variant.toString())); + return report(s_stateOperatorTypes.contains(variant.toString()), QString("Unknown state operator %1").arg(variant.toString())); } QPair JsonTypes::validateCreateMethodType(const QVariant &variant) @@ -700,7 +755,7 @@ QPair JsonTypes::validateSetupMethodType(const QVariant &variant) return report(s_setupMethodTypes.contains(variant.toString()), QString("Unknwon setupMethod type %1").arg(variant.toString())); } -QPair JsonTypes::validateOperandType(const QVariant &variant) +QPair JsonTypes::validateValueOperatorType(const QVariant &variant) { - return report(s_operandTypes.contains(variant.toString()), QString("Unknown operand type %1").arg(variant.toString())); + return report(s_valueOperatorTypes.contains(variant.toString()), QString("Unknown value operator type %1").arg(variant.toString())); } diff --git a/server/jsonrpc/jsontypes.h b/server/jsonrpc/jsontypes.h index e241ec81..58c10958 100644 --- a/server/jsonrpc/jsontypes.h +++ b/server/jsonrpc/jsontypes.h @@ -65,15 +65,17 @@ public: static QVariantMap allTypes(); DECLARE_TYPE(basicTypes, "BasicType") - DECLARE_TYPE(ruleTypes, "RuleType") + DECLARE_TYPE(stateOperatorTypes, "StateOperatorType") + DECLARE_TYPE(valueOperatorTypes, "ValueOperatorType") DECLARE_TYPE(createMethodTypes, "CreateMethodType") DECLARE_TYPE(setupMethodTypes, "SetupMethodType") - DECLARE_TYPE(operandTypes, "OperandType") DECLARE_OBJECT(paramType, "ParamType") DECLARE_OBJECT(param, "Param") DECLARE_OBJECT(paramDescriptor, "ParamDescriptor") DECLARE_OBJECT(stateType, "StateType") + DECLARE_OBJECT(stateDescriptor, "StateDescriptor") DECLARE_OBJECT(state, "State") + DECLARE_OBJECT(stateEvaluator, "StateEvaluator") DECLARE_OBJECT(eventType, "EventType") DECLARE_OBJECT(event, "Event") DECLARE_OBJECT(eventDescriptor, "EventDescriptor") @@ -92,6 +94,8 @@ public: static QVariantMap packActionType(const ActionType &actionType); static QVariantMap packAction(const Action &action); static QVariantMap packStateType(const StateType &stateType); + static QVariantMap packStateDescriptor(const StateDescriptor &stateDescriptor); + static QVariantMap packStateEvaluator(const StateEvaluator &stateEvaluator); static QVariantMap packParam(const Param ¶m); static QVariantMap packParamType(const ParamType ¶mType); static QVariantMap packParamDescriptor(const ParamDescriptor ¶mDescriptor); @@ -112,10 +116,10 @@ public: static QPair validateList(const QVariantList &templateList, const QVariantList &list); static QPair validateVariant(const QVariant &templateVariant, const QVariant &variant); static QPair validateBasicType(const QVariant &variant); - static QPair validateRuleType(const QVariant &variant); + static QPair validateStateOperatorType(const QVariant &variant); static QPair validateCreateMethodType(const QVariant &variant); static QPair validateSetupMethodType(const QVariant &variant); - static QPair validateOperandType(const QVariant &variant); + static QPair validateValueOperatorType(const QVariant &variant); private: static bool s_initialized; diff --git a/server/jsonrpc/ruleshandler.cpp b/server/jsonrpc/ruleshandler.cpp index 8f5fd95c..725578a1 100644 --- a/server/jsonrpc/ruleshandler.cpp +++ b/server/jsonrpc/ruleshandler.cpp @@ -46,12 +46,15 @@ RulesHandler::RulesHandler(QObject *parent) : setParams("AddRule", params); returns.insert("success", "bool"); returns.insert("errorMessage", "string"); + returns.insert("o:ruleId", "uuid"); setReturns("AddRule", returns); params.clear(); returns.clear(); setDescription("RemoveRule", "Remove a rule"); params.insert("ruleId", "uuid"); setParams("RemoveRule", params); + returns.insert("success", "bool"); + returns.insert("errorMessage", "string"); setReturns("RemoveRule", returns); } @@ -66,7 +69,6 @@ JsonReply* RulesHandler::GetRules(const QVariantMap ¶ms) QVariantList rulesList; foreach (const Rule &rule, GuhCore::instance()->ruleEngine()->rules()) { - qDebug() << "got rule" << rule.id(); QVariantMap ruleMap = JsonTypes::packRule(rule); rulesList.append(ruleMap); } @@ -78,16 +80,15 @@ JsonReply* RulesHandler::GetRules(const QVariantMap ¶ms) JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms) { - QVariantMap eventMap = params.value("event").toMap(); + QVariantMap eventMap = params.value("eventDescriptor").toMap(); EventTypeId eventTypeId(eventMap.value("eventTypeId").toString()); DeviceId eventDeviceId(eventMap.value("deviceId").toString()); QList eventParams = JsonTypes::unpackParamDescriptors(eventMap.value("paramDescriptors").toList()); - EventDescriptor eventDescriptor(eventTypeId, eventDeviceId, eventParams); + EventDescriptor eventDescriptor(EventDescriptorId::createEventDescriptorId(), eventTypeId, eventDeviceId, eventParams); QList actions; QVariantList actionList = params.value("actions").toList(); - qDebug() << "got action list" << actionList.count(); foreach (const QVariant &actionVariant, actionList) { QVariantMap actionMap = actionVariant.toMap(); Action action(ActionTypeId(actionMap.value("actionTypeId").toString()), DeviceId(actionMap.value("deviceId").toString())); @@ -102,10 +103,12 @@ JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms) return createReply(returns); } - switch(GuhCore::instance()->ruleEngine()->addRule(eventDescriptor, actions)) { + RuleId newRuleId = RuleId::createRuleId(); + switch(GuhCore::instance()->ruleEngine()->addRule(newRuleId, eventDescriptor, actions)) { case RuleEngine::RuleErrorNoError: returns.insert("success", true); returns.insert("errorMessage", ""); + returns.insert("ruleId", newRuleId.toString()); break; case RuleEngine::RuleErrorDeviceNotFound: returns.insert("success", false); @@ -125,10 +128,11 @@ JsonReply* RulesHandler::AddRule(const QVariantMap ¶ms) JsonReply* RulesHandler::RemoveRule(const QVariantMap ¶ms) { QVariantMap returns; - QUuid ruleId = params.value("ruleId").toUuid(); + RuleId ruleId(params.value("ruleId").toString()); switch (GuhCore::instance()->ruleEngine()->removeRule(ruleId)) { case RuleEngine::RuleErrorNoError: returns.insert("success", true); + returns.insert("errorMessage", ""); break; case RuleEngine::RuleErrorRuleNotFound: returns.insert("success", false); diff --git a/server/rule.cpp b/server/rule.cpp index 1347aa10..b885f987 100644 --- a/server/rule.cpp +++ b/server/rule.cpp @@ -48,19 +48,23 @@ #include -/*! Constructs a Rule with the given \a id, \a eventDescriptor, \a states and \a actions. The ruleType will default to - \l{Rule::RuleTypeAll}.*/ -Rule::Rule(const QUuid &id, const EventDescriptor &eventDescriptor, const QList &states, const QList &actions): +/*! Constructs an empty, invalid rule. */ +Rule::Rule() +{ + +} + +/*! Constructs a Rule with the given \a id, \a eventDescriptor, \a states and \a actions.*/ +Rule::Rule(const RuleId &id, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actions): m_id(id), - m_eventDescriptors(QList() << eventDescriptor), - m_states(states), - m_actions(actions), - m_ruleType(RuleTypeAll) + m_eventDescriptors(eventDescriptorList), + m_stateEvaluator(stateEvaluator), + m_actions(actions) { } /*! Returns the id or the Rule. */ -QUuid Rule::id() const +RuleId Rule::id() const { return m_id; } @@ -71,10 +75,10 @@ QList Rule::eventDescriptors() const return m_eventDescriptors; } -/*! Returns the \l{State}{States} that need to be matching in order for this to Rule apply. */ -QList Rule::states() const +/*! Returns the \l{StateEvaluator} that needs to evaluate successfully in order for this to Rule apply. */ +StateEvaluator Rule::stateEvaluator() const { - return m_states; + return m_stateEvaluator; } /*! Returns the \l{Action}{Actions} to be executed when this Rule is matched and states match. */ @@ -82,15 +86,3 @@ QList Rule::actions() const { return m_actions; } - -/*! Returns the type of the rule. This defines how states are compared. The default is \l{Rule::RuleTypeAll}.*/ -Rule::RuleType Rule::ruleType() const -{ - return m_ruleType; -} - -/*! Set the type of the rule to \a ruleType. This defines how states are compared. The default is \l{Rule::RuleTypeAll}.*/ -void Rule::setRuleType(Rule::RuleType ruleType) -{ - m_ruleType = ruleType; -} diff --git a/server/rule.h b/server/rule.h index d5c24a8a..c40fb32d 100644 --- a/server/rule.h +++ b/server/rule.h @@ -29,28 +29,19 @@ class Rule { public: - enum RuleType { - RuleTypeAll, - RuleTypeAny - }; + Rule(); + Rule(const RuleId &id, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actions); - Rule(const QUuid &id, const EventDescriptor &eventDescriptor, const QList &states, const QList &actions); - - QUuid id() const; + RuleId id() const; QList eventDescriptors() const; - QList states() const; + StateEvaluator stateEvaluator() const; QList actions() const; - RuleType ruleType() const; - void setRuleType(RuleType ruleType); - private: - QUuid m_id; + RuleId m_id; QList m_eventDescriptors; - QList m_states; - StateEvaluator stateEvaluator; + StateEvaluator m_stateEvaluator; QList m_actions; - RuleType m_ruleType; }; #endif // RULE_H diff --git a/server/ruleengine.cpp b/server/ruleengine.cpp index 3485a099..a8f99717 100644 --- a/server/ruleengine.cpp +++ b/server/ruleengine.cpp @@ -79,32 +79,36 @@ RuleEngine::RuleEngine(QObject *parent) : settings.beginGroup(idString); - settings.beginGroup("event"); - EventTypeId eventTypeId(settings.value("eventTypeId").toString()); - DeviceId deviceId(settings.value("deviceId").toString()); - QList params; - foreach (QString groupName, settings.childGroups()) { - if (groupName.startsWith("ParamDescriptor-")) { - settings.beginGroup(groupName); - ParamDescriptor paramDescriptor(groupName.remove(QRegExp("^ParamDescriptor-")), settings.value("value")); - paramDescriptor.setOperand((ParamDescriptor::OperandType)settings.value("operand").toInt()); - params.append(paramDescriptor); + QList eventDescriptorList; + settings.beginGroup("events"); + + foreach (QString eventGroupName, settings.childGroups()) { + if (eventGroupName.startsWith("EventDescriptor-")) { + settings.beginGroup(eventGroupName); + EventDescriptorId eventDescriptorId(eventGroupName.remove(QRegExp("^EventDescriptor-"))); + EventTypeId eventTypeId(settings.value("eventTypeId").toString()); + DeviceId deviceId(settings.value("deviceId").toString()); + + QList params; + foreach (QString groupName, settings.childGroups()) { + if (groupName.startsWith("ParamDescriptor-")) { + settings.beginGroup(groupName); + ParamDescriptor paramDescriptor(groupName.remove(QRegExp("^ParamDescriptor-")), settings.value("value")); + paramDescriptor.setOperatorType((ValueOperator)settings.value("operator").toInt()); + params.append(paramDescriptor); + settings.endGroup(); + } + } + + EventDescriptor eventDescriptor(eventDescriptorId, eventTypeId, deviceId, params); + eventDescriptorList.append(eventDescriptor); settings.endGroup(); } } - EventDescriptor eventDescriptor(eventTypeId, deviceId, params); + settings.endGroup(); - settings.beginGroup("states"); - QList states; - foreach (const QString &stateTypeIdString, settings.childGroups()) { - settings.beginGroup(stateTypeIdString); - State state(StateTypeId(stateTypeIdString), DeviceId(settings.value("deviceId").toString())); - state.setValue(settings.value("value")); - settings.endGroup(); - states.append(state); - } - settings.endGroup(); + StateEvaluator stateEvaluator = StateEvaluator::loadFromSettings(settings, "stateEvaluator"); settings.beginGroup("actions"); QList actions; @@ -129,8 +133,8 @@ RuleEngine::RuleEngine(QObject *parent) : settings.endGroup(); - Rule rule = Rule(QUuid(idString), eventDescriptor, states, actions); - m_rules.append(rule); +// Rule rule = Rule(RuleId(idString), eventDescriptorList, states, actions); +// m_rules.append(rule); } } @@ -146,23 +150,8 @@ QList RuleEngine::evaluateEvent(const Event &event) for (int i = 0; i < m_rules.count(); ++i) { qDebug() << "evaluating rule" << i << m_rules.at(i).eventDescriptors(); if (containsEvent(m_rules.at(i), event)) { - bool statesMatching = true; - qDebug() << "checking states:" << m_rules.at(i).states(); - foreach (const State &state, m_rules.at(i).states()) { - Device *device = GuhCore::instance()->deviceManager()->findConfiguredDevice(state.deviceId()); - if (!device) { - qWarning() << "Device referenced in rule cannot be found"; - break; - } - if (state.value() != device->stateValue(state.stateTypeId())) { - qDebug() << "State value not matching:" << state.value() << device->stateValue(state.stateTypeId()); - statesMatching = false; - break; - } - } - - qDebug() << "states matching" << statesMatching; - if (statesMatching) { + if (m_rules.at(i).stateEvaluator().evaluate()) { + qDebug() << "states matching!"; actions.append(m_rules.at(i).actions()); } } @@ -173,60 +162,86 @@ QList RuleEngine::evaluateEvent(const Event &event) /*! Add a new \l{Rule} with the given \a event and \a actions to the engine. For convenience, this creates a Rule without any \l{State} comparison. */ -RuleEngine::RuleError RuleEngine::addRule(const EventDescriptor &eventDescriptor, const QList &actions) +RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const EventDescriptor &eventDescriptor, const QList &actions) { - return addRule(eventDescriptor, QList(), actions); + QList eventDescriptorList; + eventDescriptorList.append(eventDescriptor); + return addRule(ruleId, eventDescriptorList, StateEvaluator(StateEvaluatorId::createStateEvaluatorId()), actions); } /*! Add a new \l{Rule} with the given \a event, \a states and \a actions to the engine. */ -RuleEngine::RuleError RuleEngine::addRule(const EventDescriptor &eventDescriptor, const QList &states, const QList &actions) +RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actions) { - Device *device = GuhCore::instance()->deviceManager()->findConfiguredDevice(eventDescriptor.deviceId()); - if (!device) { - qWarning() << "Cannot create rule. No configured device for eventTypeId" << eventDescriptor.eventTypeId(); - return RuleErrorDeviceNotFound; + if (ruleId.isNull()) { + return RuleErrorInvalidRuleId; } - DeviceClass deviceClass = GuhCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId()); - qDebug() << "found deviceClass" << deviceClass.name(); + if (!findRule(ruleId).id().isNull()) { + qWarning() << "Already have a rule with this id!"; + return RuleErrorInvalidRuleId; + } + foreach (const EventDescriptor &eventDescriptor, eventDescriptorList) { + Device *device = GuhCore::instance()->deviceManager()->findConfiguredDevice(eventDescriptor.deviceId()); + if (!device) { + qWarning() << "Cannot create rule. No configured device for eventTypeId" << eventDescriptor.eventTypeId(); + return RuleErrorDeviceNotFound; + } + DeviceClass deviceClass = GuhCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId()); - bool eventTypeFound = false; - foreach (const EventType &eventType, deviceClass.eventTypes()) { - if (eventType.id() == eventDescriptor.eventTypeId()) { - eventTypeFound = true; + bool eventTypeFound = false; + foreach (const EventType &eventType, deviceClass.eventTypes()) { + if (eventType.id() == eventDescriptor.eventTypeId()) { + eventTypeFound = true; + } + } + if (!eventTypeFound) { + qWarning() << "Cannot create rule. Device " + device->name() + " has no event type:" << eventDescriptor.eventTypeId(); + return RuleErrorEventTypeNotFound; } } - if (!eventTypeFound) { - qWarning() << "Cannot create rule. Device " + device->name() + " has no event type:" << eventDescriptor.eventTypeId(); - return RuleErrorEventTypeNotFound; + + foreach (const Action &action, actions) { + Device *device = GuhCore::instance()->deviceManager()->findConfiguredDevice(action.deviceId()); + if (!device) { + qWarning() << "Cannot create rule. No configured device for actionTypeId" << action.actionTypeId(); + return RuleErrorDeviceNotFound; + } + DeviceClass deviceClass = GuhCore::instance()->deviceManager()->findDeviceClass(device->deviceClassId()); + + bool actionTypeFound = false; + foreach (const ActionType &actionType, deviceClass.actionTypes()) { + if (actionType.id() == action.actionTypeId()) { + actionTypeFound = true; + } + } + if (!actionTypeFound) { + qWarning() << "Cannot create rule. Device " + device->name() + " has no action type:" << action.actionTypeId(); + return RuleErrorActionTypeNotFound; + } } - Rule rule = Rule(QUuid::createUuid(), eventDescriptor, states, actions); + Rule rule = Rule(ruleId, eventDescriptorList, stateEvaluator, actions); m_rules.append(rule); emit ruleAdded(rule.id()); QSettings settings(m_settingsFile); settings.beginGroup(rule.id().toString()); - settings.beginGroup("event"); - settings.setValue("eventTypeId", eventDescriptor.eventTypeId()); - settings.setValue("deviceId", eventDescriptor.deviceId()); - foreach (const ParamDescriptor ¶mDescriptor, eventDescriptor.paramDescriptors()) { - settings.beginGroup("ParamDescriptor-" + paramDescriptor.name()); - settings.setValue("value", paramDescriptor.value()); - settings.setValue("operand", paramDescriptor.operand()); + settings.beginGroup("events"); + foreach (const EventDescriptor &eventDescriptor, eventDescriptorList) { + settings.beginGroup("EventDescriptor-" + eventDescriptor.id().toString()); + settings.setValue("deviceId", eventDescriptor.deviceId().toString()); + settings.setValue("eventTypeId", eventDescriptor.eventTypeId()); + + foreach (const ParamDescriptor ¶mDescriptor, eventDescriptor.paramDescriptors()) { + settings.beginGroup("ParamDescriptor-" + paramDescriptor.name()); + settings.setValue("value", paramDescriptor.value()); + settings.setValue("operator", paramDescriptor.operatorType()); + settings.endGroup(); + } settings.endGroup(); } - settings.endGroup(); - settings.beginGroup("states"); - foreach (const State &state, states) { - settings.beginGroup(state.stateTypeId().toString()); - settings.setValue("deviceId", state.deviceId()); - settings.setValue("value", state.value()); - settings.endGroup(); - } - - settings.endGroup(); + stateEvaluator.dumpToSettings(settings, "stateEvaluator"); settings.beginGroup("actions"); foreach (const Action &action, rule.actions()) { @@ -256,7 +271,7 @@ QList RuleEngine::rules() const /*! Removes the \l{Rule} with the given \a ruleId from the Engine. Returns \l{RuleEngine::RuleError} which describes whether the operation was successful or not. */ -RuleEngine::RuleError RuleEngine::removeRule(const QUuid &ruleId) +RuleEngine::RuleError RuleEngine::removeRule(const RuleId &ruleId) { for (int i = 0; i < m_rules.count(); ++i) { Rule rule = m_rules.at(i); @@ -276,6 +291,16 @@ RuleEngine::RuleError RuleEngine::removeRule(const QUuid &ruleId) return RuleErrorRuleNotFound; } +Rule RuleEngine::findRule(const RuleId &ruleId) +{ + foreach (const Rule &rule, m_rules) { + if (rule.id() == ruleId) { + return rule; + } + } + return Rule(); +} + bool RuleEngine::containsEvent(const Rule &rule, const Event &event) { foreach (const EventDescriptor &eventDescriptor, rule.eventDescriptors()) { diff --git a/server/ruleengine.h b/server/ruleengine.h index 9b9fb1a2..e5390c27 100644 --- a/server/ruleengine.h +++ b/server/ruleengine.h @@ -21,6 +21,7 @@ #include "rule.h" #include "types/event.h" +#include "stateevaluator.h" #include #include @@ -32,24 +33,28 @@ class RuleEngine : public QObject public: enum RuleError { RuleErrorNoError, + RuleErrorInvalidRuleId, RuleErrorRuleNotFound, RuleErrorDeviceNotFound, - RuleErrorEventTypeNotFound + RuleErrorEventTypeNotFound, + RuleErrorActionTypeNotFound }; explicit RuleEngine(QObject *parent = 0); QList evaluateEvent(const Event &event); - RuleError addRule(const EventDescriptor &eventDescriptor, const QList &actions); - RuleError addRule(const EventDescriptor &eventDescriptor, const QList &states, const QList &actions); + RuleError addRule(const RuleId &ruleId, const EventDescriptor &eventDescriptor, const QList &actions); + RuleError addRule(const RuleId &ruleId, const QList &eventDescriptorList, const StateEvaluator &stateEvaluator, const QList &actions); QList rules() const; - RuleError removeRule(const QUuid &ruleId); + RuleError removeRule(const RuleId &ruleId); + + Rule findRule(const RuleId &ruleId); signals: - void ruleAdded(const QUuid &ruleId); - void ruleRemoved(const QUuid &ruleId); + void ruleAdded(const RuleId &ruleId); + void ruleRemoved(const RuleId &ruleId); private: bool containsEvent(const Rule &rule, const Event &event); diff --git a/server/stateevaluator.cpp b/server/stateevaluator.cpp index 12ceecc8..3c85bbe2 100644 --- a/server/stateevaluator.cpp +++ b/server/stateevaluator.cpp @@ -17,9 +17,141 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "stateevaluator.h" +#include "guhcore.h" +#include "devicemanager.h" StateEvaluator::StateEvaluator() { + +} + +StateEvaluator::StateEvaluator(const StateEvaluatorId &id, const StateDescriptor &statedescriptor): + m_id(id), + m_stateDescriptor(statedescriptor) +{ + +} + +StateEvaluator::StateEvaluator(const StateEvaluatorId &id, QList childEvaluators, StateOperator stateOperator): + m_id(id), + m_childEvaluators(childEvaluators), + m_operatorType(stateOperator), + m_stateDescriptor() +{ +} + +StateEvaluatorId StateEvaluator::id() const +{ + return m_id; +} + +StateDescriptor StateEvaluator::stateDescriptor() const +{ + return m_stateDescriptor; +} + +QList StateEvaluator::childEvaluators() const +{ + return m_childEvaluators; +} + +void StateEvaluator::setChildEvaluators(const QList &stateEvaluators) +{ + m_childEvaluators = stateEvaluators; +} + +void StateEvaluator::appendEvaluator(const StateEvaluator &stateEvaluator) +{ + m_childEvaluators.append(stateEvaluator); +} + +StateOperator StateEvaluator::operatorType() const +{ + return m_operatorType; +} + +void StateEvaluator::setOperatorType(StateOperator operatorType) +{ + m_operatorType = operatorType; +} + +bool StateEvaluator::evaluate() const +{ + if (!m_stateDescriptor.stateTypeId().isNull() && !m_stateDescriptor.deviceId().isNull()) { + Device *device = GuhCore::instance()->deviceManager()->findConfiguredDevice(m_stateDescriptor.deviceId()); + if (!device) { + qWarning() << "Device not existing!"; + return false; + } + if (device->hasState(m_stateDescriptor.stateTypeId())) { + qWarning() << "Device found, but it does not appear to have such a state!"; + return false; + } + if (m_stateDescriptor != device->state(m_stateDescriptor.stateTypeId())) { + // state not matching + return false; + } + } + foreach (const StateEvaluator &stateEvaluator, m_childEvaluators) { + if (!stateEvaluator.evaluate()) { + return false; + } + } + return true; +} + +void StateEvaluator::dumpToSettings(QSettings &settings, const QString &groupName) const +{ + settings.beginGroup(groupName); + + settings.setValue("id", m_id.toString()); + settings.beginGroup("stateDescriptor"); + settings.setValue("stateDescriptorId", m_stateDescriptor.id().toString()); + settings.setValue("stateTypeId", m_stateDescriptor.stateTypeId().toString()); + settings.setValue("deviceId", m_stateDescriptor.deviceId().toString()); + settings.setValue("value", m_stateDescriptor.stateValue()); + settings.setValue("operator", m_stateDescriptor.operatorType()); + settings.endGroup(); + + settings.setValue("operator", m_operatorType); + + settings.beginGroup("childEvaluators"); + foreach (const StateEvaluator &evaluator, m_childEvaluators) { + evaluator.dumpToSettings(settings, "stateEvaluator-" + evaluator.id().toString()); + } + settings.endGroup(); + + settings.endGroup(); +} + +StateEvaluator StateEvaluator::loadFromSettings(QSettings &settings, const QString &groupName) +{ + settings.beginGroup(groupName); + StateEvaluatorId id(settings.value("id").toString()); + + settings.beginGroup("stateDescriptor"); + StateDescriptorId stateDescriptorId(settings.value("stateDescriptorId").toString()); + StateTypeId stateTypeId(settings.value("stateTypeId").toString()); + DeviceId deviceId(settings.value("deviceId").toString()); + QVariant stateValue = settings.value("value"); + ValueOperator valueOperator = (ValueOperator)settings.value("operator").toInt(); + StateDescriptor stateDescriptor(stateDescriptorId, stateTypeId, deviceId, stateValue, valueOperator); + settings.endGroup(); + + StateEvaluator ret(id, stateDescriptor); + + ret.setOperatorType((StateOperator)settings.value("operator").toInt()); + + settings.beginGroup("childEvaluators"); + foreach (const QString &evaluatorGroup, settings.childGroups()) { + settings.beginGroup(evaluatorGroup); + ret.appendEvaluator(StateEvaluator::loadFromSettings(settings, evaluatorGroup)); + settings.endGroup(); + } + settings.endGroup(); + + settings.endGroup(); + return ret; } diff --git a/server/stateevaluator.h b/server/stateevaluator.h index 6e6d2bc1..db8e97b6 100644 --- a/server/stateevaluator.h +++ b/server/stateevaluator.h @@ -20,31 +20,44 @@ #define STATEEVALUATOR_H #include "types/state.h" +#include "types/statedescriptor.h" -//class EvaluatorEntry -//{ -//public: -// EvaluatorEntry(); - -// QUuid stateTypeId; -// QUuid deviceId; -//// Rule::Operator operation; -// QVariant value; -//}; - -//class EvaluatorChain -//{ - -//}; +#include class StateEvaluator { public: + enum OperatorType { + OperatorTypeAnd, + OperatorTypeOr + }; StateEvaluator(); + StateEvaluator(const StateEvaluatorId &id, const StateDescriptor &statedescriptor); + StateEvaluator(const StateEvaluatorId &id, QList childEvaluators = QList(), StateOperator stateOperator = StateOperatorAnd); + + StateEvaluatorId id() const; + + StateDescriptor stateDescriptor() const; + + QList childEvaluators() const; + void setChildEvaluators(const QList &childEvaluators); + void appendEvaluator(const StateEvaluator &stateEvaluator); + + StateOperator operatorType() const; + void setOperatorType(StateOperator operatorType); + + bool evaluate() const; + + void dumpToSettings(QSettings &settings, const QString &groupName) const; + static StateEvaluator loadFromSettings(QSettings &settings, const QString &groupPrefix); private: -// EvaluatorEntry m_entry; + StateEvaluatorId m_id; + StateDescriptor m_stateDescriptor; + + QList m_childEvaluators; + StateOperator m_operatorType; }; diff --git a/tests/auto/api.json b/tests/auto/api.json index 8b6e91d2..576dde3f 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1,4 +1,4 @@ -0.1.6 +0.1.7 { "methods": { "Actions.ExecuteAction": { @@ -223,6 +223,7 @@ }, "returns": { "errorMessage": "string", + "o:ruleId": "uuid", "success": "bool" } }, @@ -242,6 +243,8 @@ "ruleId": "uuid" }, "returns": { + "errorMessage": "string", + "success": "bool" } } }, @@ -345,21 +348,13 @@ "$ref:ParamType" ] }, - "OperandType": [ - "OperandTypeEquals", - "OperandTypeNotEquals", - "OperandTypeLess", - "OperandTypeGreater", - "OperandTypeLessThan", - "OperandTypeGreaterThan" - ], "Param": { "name": "string", "value": "$ref:BasicType" }, "ParamDescriptor": { "name": "string", - "operand": "$ref:OperandType", + "operator": "$ref:ValueOperatorType", "value": "$ref:BasicType" }, "ParamType": { @@ -384,15 +379,8 @@ "$ref:EventDescriptor" ], "id": "uuid", - "ruleType": "$ref:RuleType", - "states": [ - "$ref:State" - ] + "stateEvaluator": "$ref:StateEvaluator" }, - "RuleType": [ - "RuleTypeMatchAll", - "RuleTypeMatchAny" - ], "SetupMethodType": [ "SetupMethodJustAdd", "SetupMethodDisplayPin", @@ -404,12 +392,39 @@ "stateTypeId": "uuid", "value": "variant" }, + "StateDescriptor": { + "deviceId": "uuid", + "id": "uuid", + "operator": "$ref:ValueOperatorType", + "stateTypeId": "uuid", + "value": "variant" + }, + "StateEvaluator": { + "id": "uuid", + "o:childEvaluators": [ + "$ref:StateEvaluator" + ], + "o:operator": "$ref:StateOperatorType", + "o:stateDescriptor": "$ref:StateDescriptor" + }, + "StateOperatorType": [ + "StateOperatorAnd", + "StateOperatorOr" + ], "StateType": { "defaultValue": "variant", "id": "uuid", "name": "string", "type": "$ref:BasicType" }, + "ValueOperatorType": [ + "OperatorTypeEquals", + "OperatorTypeNotEquals", + "OperatorTypeLess", + "OperatorTypeGreater", + "OperatorTypeLessThan", + "OperatorTypeGreaterThan" + ], "Vendor": { "id": "uuid", "name": "string" diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro index fc3c1f2e..5299fc13 100644 --- a/tests/auto/auto.pro +++ b/tests/auto/auto.pro @@ -1,2 +1,2 @@ TEMPLATE=subdirs -SUBDIRS=versioning devices jsonrpc events states actions +SUBDIRS=versioning devices jsonrpc events states actions rules diff --git a/tests/auto/jsonrpc/testjsonrpc.cpp b/tests/auto/jsonrpc/testjsonrpc.cpp index 7be5a306..6d19dadd 100644 --- a/tests/auto/jsonrpc/testjsonrpc.cpp +++ b/tests/auto/jsonrpc/testjsonrpc.cpp @@ -47,8 +47,6 @@ private slots: void stateChangeEmitsNotifications(); - void getRules(); - private: QStringList extractRefs(const QVariant &variant); @@ -252,12 +250,6 @@ void TestJSONRPC::stateChangeEmitsNotifications() } -void TestJSONRPC::getRules() -{ - QVariant response = injectAndWait("Rules.GetRules", QVariantMap()); - qDebug() << "got rules response" << response; -} - #include "testjsonrpc.moc" QTEST_MAIN(TestJSONRPC) diff --git a/tests/auto/rules/rules.pro b/tests/auto/rules/rules.pro new file mode 100644 index 00000000..c0b57068 --- /dev/null +++ b/tests/auto/rules/rules.pro @@ -0,0 +1,5 @@ +include(../../../guh.pri) +include(../autotests.pri) + +TARGET = rules +SOURCES += testrules.cpp diff --git a/tests/auto/rules/testrules.cpp b/tests/auto/rules/testrules.cpp new file mode 100644 index 00000000..e4709ba7 --- /dev/null +++ b/tests/auto/rules/testrules.cpp @@ -0,0 +1,151 @@ +/**************************************************************************** + * * + * This file is part of guh. * + * * + * Guh is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * Guh is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with guh. If not, see . * + * * + ***************************************************************************/ + +#include "guhtestbase.h" +#include "guhcore.h" +#include "devicemanager.h" +#include "mocktcpserver.h" + +#include +#include +#include +#include +#include +#include +#include + +class TestRules: public GuhTestBase +{ + Q_OBJECT + +private slots: + void addRules_data(); + void addRules(); + void getStateValue_data(); + void getStateValue(); +}; + +void TestRules::addRules_data() +{ + QVariantMap validAction; + validAction.insert("actionTypeId", mockActionIdNoParams); + validAction.insert("deviceId", m_mockDeviceId); + validAction.insert("params", QVariantList()); + + QVariantMap invalidAction; + invalidAction.insert("actionTypeId", ActionTypeId()); + invalidAction.insert("deviceId", m_mockDeviceId); + invalidAction.insert("params", QVariantList()); + + QVariantMap validEventDescriptor; + validEventDescriptor.insert("eventTypeId", mockEvent1Id); + validEventDescriptor.insert("deviceId", m_mockDeviceId); + validEventDescriptor.insert("paramDescriptors", QVariantList()); + + QVariantMap invalidEventDescriptor; + invalidEventDescriptor.insert("eventTypeId", mockEvent1Id); + invalidEventDescriptor.insert("deviceId", DeviceId()); + invalidEventDescriptor.insert("paramDescriptors", QVariantList()); + + QTest::addColumn("action1"); + QTest::addColumn("eventDescriptor1"); + QTest::addColumn("success"); + + QTest::newRow("valid rule") << validAction << validEventDescriptor << true; + QTest::newRow("invalid action") << invalidAction << validEventDescriptor << false; + QTest::newRow("invalid event descriptor") << validAction << invalidEventDescriptor << false; + +} + +void TestRules::addRules() +{ + QFETCH(QVariantMap, action1); + QFETCH(QVariantMap, eventDescriptor1); + QFETCH(bool, success); + + QVariantMap params; + QVariantList actions; + actions.append(action1); + params.insert("actions", actions); + params.insert("eventDescriptor", eventDescriptor1); + QVariant response = injectAndWait("Rules.AddRule", params); + + RuleId newRuleId = RuleId(response.toMap().value("params").toMap().value("ruleId").toString()); + verifySuccess(response, success); + + response = injectAndWait("Rules.GetRules"); + QVariantList rules = response.toMap().value("params").toMap().value("rules").toList(); + + if (!success) { + QVERIFY2(rules.count() == 0, "There should be no rules."); + return; + } + + QVERIFY2(rules.count() == 1, "There should be exactly one rule"); + QCOMPARE(RuleId(rules.first().toMap().value("id").toString()), newRuleId); + + QVariantList eventDescriptors = rules.first().toMap().value("eventDescriptors").toList(); + QVERIFY2(eventDescriptors.count() == 1, "There shoud be exactly one eventDescriptor"); + QVERIFY2(eventDescriptors.first().toMap() == eventDescriptor1, "Event descriptor doesn't match"); + + QVariantList replyActions = rules.first().toMap().value("actions").toList(); + QVERIFY2(actions == replyActions, "Actions don't match"); + + + params.clear(); + params.insert("ruleId", newRuleId); + response = injectAndWait("Rules.RemoveRule", params); + verifySuccess(response, true); + + response = injectAndWait("Rules.GetRules"); + rules = response.toMap().value("params").toMap().value("rules").toList(); + QVERIFY2(rules.count() == 0, "There should be no rules."); +} + +void TestRules::getStateValue_data() +{ + QList devices = GuhCore::instance()->deviceManager()->findConfiguredDevices(mockDeviceClassId); + QVERIFY2(devices.count() > 0, "There needs to be at least one configured Mock Device for this test"); + Device *device = devices.first(); + + QTest::addColumn("deviceId"); + QTest::addColumn("stateTypeId"); + QTest::addColumn("success"); + + QTest::newRow("existing state") << device->id() << mockIntStateId << true; + QTest::newRow("invalid device") << DeviceId::createDeviceId() << mockIntStateId << false; + QTest::newRow("invalid statetype") << device->id() << StateTypeId::createStateTypeId() << false; +} + +void TestRules::getStateValue() +{ + QFETCH(DeviceId, deviceId); + QFETCH(StateTypeId, stateTypeId); + QFETCH(bool, success); + + QVariantMap params; + params.insert("deviceId", deviceId.toString()); + params.insert("stateTypeId", stateTypeId.toString()); + + QVariant response = injectAndWait("Devices.GetStateValue", params); + + verifySuccess(response, success); +} + +#include "testrules.moc" +QTEST_MAIN(TestRules)