From: Gunnar Beutner Date: Thu, 13 Aug 2015 06:52:00 +0000 (+0200) Subject: Implement validation for modified attributes X-Git-Tag: v2.4.0~420 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=f405a26052bfa171882851b0ea69ed6ec7a0b1a4;p=icinga2 Implement validation for modified attributes --- diff --git a/lib/base/dynamicobject.cpp b/lib/base/dynamicobject.cpp index 5f09b1140..229e4e5b3 100644 --- a/lib/base/dynamicobject.cpp +++ b/lib/base/dynamicobject.cpp @@ -33,6 +33,7 @@ #include "base/workqueue.hpp" #include "base/context.hpp" #include "base/application.hpp" +#include "config/configitem.hpp" #include #include #include @@ -95,6 +96,23 @@ void DynamicObject::ClearExtension(const String& key) extensions->Remove(key); } +class ModAttrValidationUtils : public ValidationUtils +{ +public: + virtual bool ValidateName(const String& type, const String& name) const override + { + DynamicType::Ptr dtype = DynamicType::GetByName(type); + + if (!dtype) + return false; + + if (!dtype->GetObject(name)) + return false; + + return true; + } +}; + void DynamicObject::ModifyAttribute(const String& attr, const Value& value) { Dictionary::Ptr original_attributes = GetOriginalAttributes(); @@ -118,7 +136,10 @@ void DynamicObject::ModifyAttribute(const String& attr, const Value& value) } } - //TODO: validation, vars.os + ModAttrValidationUtils utils; + ValidateField(fid, value, utils); + + //TODO: vars.os SetField(fid, value); if (updated_original_attributes) diff --git a/lib/base/exception.cpp b/lib/base/exception.cpp index a079837e5..b48de54ab 100644 --- a/lib/base/exception.cpp +++ b/lib/base/exception.cpp @@ -161,18 +161,20 @@ String icinga::DiagnosticInformation(const std::exception& ex, bool verbose, Sta Dictionary::Ptr currentHint = vex->GetDebugHint(); Array::Ptr messages; - BOOST_FOREACH(const String& attr, vex->GetAttributePath()) { - Dictionary::Ptr props = currentHint->Get("properties"); + if (currentHint) { + BOOST_FOREACH(const String& attr, vex->GetAttributePath()) { + Dictionary::Ptr props = currentHint->Get("properties"); - if (!props) - break; + if (!props) + break; - currentHint = props->Get(attr); + currentHint = props->Get(attr); - if (!currentHint) - break; + if (!currentHint) + break; - messages = currentHint->Get("messages"); + messages = currentHint->Get("messages"); + } } if (messages && messages->GetLength() > 0) { diff --git a/lib/base/object.cpp b/lib/base/object.cpp index 15667f516..e341640a6 100644 --- a/lib/base/object.cpp +++ b/lib/base/object.cpp @@ -92,7 +92,12 @@ Value Object::GetField(int id) const BOOST_THROW_EXCEPTION(std::runtime_error("Invalid field ID.")); } +void Object::ValidateField(int id, const Value& value, const ValidationUtils& utils) +{ + /* Nothing to do here. */ +} + void Object::NotifyField(int id, const Value& cookie) { BOOST_THROW_EXCEPTION(std::runtime_error("Invalid field ID.")); -} \ No newline at end of file +} diff --git a/lib/base/object.hpp b/lib/base/object.hpp index d8823d173..3b8f41b1d 100644 --- a/lib/base/object.hpp +++ b/lib/base/object.hpp @@ -48,6 +48,7 @@ class Value; class Object; class Type; class String; +class ValidationUtils; extern I2_BASE_API Value Empty; @@ -100,6 +101,7 @@ public: virtual void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty); virtual Value GetField(int id) const; + virtual void ValidateField(int id, const Value& value, const ValidationUtils& utils); virtual void NotifyField(int id, const Value& cookie = Empty); #ifdef I2_DEBUG diff --git a/tools/mkclass/classcompiler.cpp b/tools/mkclass/classcompiler.cpp index 636c5fdaf..fafbcb7b0 100644 --- a/tools/mkclass/classcompiler.cpp +++ b/tools/mkclass/classcompiler.cpp @@ -596,6 +596,50 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&) m_Impl << "}" << std::endl << std::endl; + /* ValidateField */ + m_Header << "protected:" << std::endl + << "\t" << "virtual void ValidateField(int id, const Value& value, const ValidationUtils& utils);" << std::endl; + + m_Impl << "void ObjectImpl<" << klass.Name << ">::ValidateField(int id, const Value& value, const ValidationUtils& utils)" << std::endl + << "{" << std::endl; + + if (!klass.Parent.empty()) + m_Impl << "\t" << "int real_id = id - " << klass.Parent << "::TypeInstance->GetFieldCount(); " << std::endl + << "\t" << "if (real_id < 0) { " << klass.Parent << "::ValidateField(id, value, utils); return; }" << std::endl; + + m_Impl << "\t" << "switch ("; + + if (!klass.Parent.empty()) + m_Impl << "real_id"; + else + m_Impl << "id"; + + m_Impl << ") {" << std::endl; + + num = 0; + for (it = klass.Fields.begin(); it != klass.Fields.end(); it++) { + m_Impl << "\t\t" << "case " << num << ":" << std::endl + << "\t\t\t" << "Validate" << it->GetFriendlyName() << "("; + + if (it->Attributes & FAEnum) + m_Impl << "static_cast<" << it->Type.GetRealType() << ">(static_cast("; + + m_Impl << "value"; + + if (it->Attributes & FAEnum) + m_Impl << "))"; + + m_Impl << ", utils);" << std::endl + << "\t\t\t" << "break;" << std::endl; + num++; + } + + m_Impl << "\t\t" << "default:" << std::endl + << "\t\t\t" << "throw std::runtime_error(\"Invalid field ID.\");" << std::endl + << "\t" << "}" << std::endl; + + m_Impl << "}" << std::endl << std::endl; + /* NotifyField */ m_Header << "protected:" << std::endl << "\t" << "virtual void NotifyField(int id, const Value& cookie = Empty);" << std::endl;