diff --git a/lib/base/dynamicobject.hpp b/lib/base/dynamicobject.hpp index 31e764146..9b355bf4c 100644 --- a/lib/base/dynamicobject.hpp +++ b/lib/base/dynamicobject.hpp @@ -101,7 +101,7 @@ private: DebugInfo m_DebugInfo; }; -#define DECLARE_OBJECTNAME(klass) \ +#define DECLARE_OBJECTNAME(klass) \ inline static String GetTypeName(void) \ { \ return #klass; \ diff --git a/lib/base/dynamicobject.ti b/lib/base/dynamicobject.ti index c92870d70..55aad8248 100644 --- a/lib/base/dynamicobject.ti +++ b/lib/base/dynamicobject.ti @@ -29,12 +29,14 @@ enum HAMode class NameComposer { public: - virtual String MakeName(const String& shortName, const Dictionary::Ptr& props) const = 0; + virtual String MakeName(const String& shortName, const Object::Ptr& context) const = 0; }; }}} abstract class DynamicObject { + [protected] Object::Ptr __parent (ParentScope); + [config, internal] String __name (Name); [config] String name (ShortName) { get {{{ diff --git a/lib/base/dynamictype.cpp b/lib/base/dynamictype.cpp index 024c59136..a3449ce4f 100644 --- a/lib/base/dynamictype.cpp +++ b/lib/base/dynamictype.cpp @@ -123,19 +123,6 @@ DynamicObject::Ptr DynamicType::GetObject(const String& name) const return nt->second; } -DynamicObject::Ptr DynamicType::CreateObject(const Dictionary::Ptr& serializedUpdate) -{ - ASSERT(!OwnsLock()); - - Type::Ptr type = Type::GetByName(m_Name); - - Object::Ptr object = type->Instantiate(); - - Deserialize(object, serializedUpdate, true, FAConfig); - - return static_pointer_cast(object); -} - boost::mutex& DynamicType::GetStaticMutex(void) { static boost::mutex mutex; diff --git a/lib/base/dynamictype.hpp b/lib/base/dynamictype.hpp index fd5271f59..6bac3d059 100644 --- a/lib/base/dynamictype.hpp +++ b/lib/base/dynamictype.hpp @@ -44,7 +44,6 @@ public: static DynamicType::Ptr GetByName(const String& name); - DynamicObject::Ptr CreateObject(const Dictionary::Ptr& serializedUpdate); DynamicObject::Ptr GetObject(const String& name) const; void RegisterObject(const DynamicObject::Ptr& object); diff --git a/lib/base/value.hpp b/lib/base/value.hpp index 6aa28eef4..3326421dc 100644 --- a/lib/base/value.hpp +++ b/lib/base/value.hpp @@ -97,6 +97,9 @@ public: if (IsEmpty()) return shared_ptr(); + if (!IsObject()) + BOOST_THROW_EXCEPTION(std::runtime_error("Cannot convert value to object.")); + Object::Ptr object = boost::get(m_Value); ASSERT(object); diff --git a/lib/cli/daemoncommand.cpp b/lib/cli/daemoncommand.cpp index ca4074d8b..4dd8c856a 100644 --- a/lib/cli/daemoncommand.cpp +++ b/lib/cli/daemoncommand.cpp @@ -81,6 +81,9 @@ static bool LoadConfigFiles(const boost::program_options::variables_map& vm, con { ConfigCompilerContext::GetInstance()->Reset(); + if (!objectsFile.IsEmpty()) + ConfigCompilerContext::GetInstance()->OpenObjectsFile(objectsFile); + if (vm.count("config") > 0) { BOOST_FOREACH(const String& configPath, vm["config"].as >()) { ConfigCompiler::CompileFile(configPath); @@ -109,7 +112,7 @@ static bool LoadConfigFiles(const boost::program_options::variables_map& vm, con ConfigItem::Ptr item = builder->Compile(); item->Register(); - bool result = ConfigItem::ValidateItems(objectsFile); + bool result = ConfigItem::ValidateItems(); int warnings = 0, errors = 0; @@ -149,6 +152,8 @@ static bool LoadConfigFiles(const boost::program_options::variables_map& vm, con if (!result) return false; + ConfigCompilerContext::GetInstance()->FinishObjectsFile(); + ScriptVariable::WriteVariablesFile(varsfile); return true; diff --git a/lib/config/applyrule.cpp b/lib/config/applyrule.cpp index a8f24f720..8509fd00d 100644 --- a/lib/config/applyrule.cpp +++ b/lib/config/applyrule.cpp @@ -29,7 +29,7 @@ ApplyRule::CallbackMap ApplyRule::m_Callbacks; ApplyRule::ApplyRule(const String& targetType, const String& name, const Expression::Ptr& expression, const Expression::Ptr& filter, const String& fkvar, const String& fvvar, const Expression::Ptr& fterm, - const DebugInfo& di, const Dictionary::Ptr& scope) + const DebugInfo& di, const Object::Ptr& scope) : m_TargetType(targetType), m_Name(name), m_Expression(expression), m_Filter(filter), m_FKVar(fkvar), m_FVVar(fvvar), m_FTerm(fterm), m_DebugInfo(di), m_Scope(scope) { } @@ -74,19 +74,19 @@ DebugInfo ApplyRule::GetDebugInfo(void) const return m_DebugInfo; } -Dictionary::Ptr ApplyRule::GetScope(void) const +Object::Ptr ApplyRule::GetScope(void) const { return m_Scope; } void ApplyRule::AddRule(const String& sourceType, const String& targetType, const String& name, const Expression::Ptr& expression, const Expression::Ptr& filter, const String& fkvar, - const String& fvvar, const Expression::Ptr& fterm, const DebugInfo& di, const Dictionary::Ptr& scope) + const String& fvvar, const Expression::Ptr& fterm, const DebugInfo& di, const Object::Ptr& scope) { m_Rules[sourceType].push_back(ApplyRule(targetType, name, expression, filter, fkvar, fvvar, fterm, di, scope)); } -bool ApplyRule::EvaluateFilter(const Dictionary::Ptr& scope) const +bool ApplyRule::EvaluateFilter(const Object::Ptr& scope) const { return m_Filter->Evaluate(scope); } diff --git a/lib/config/applyrule.hpp b/lib/config/applyrule.hpp index 1a5375fab..4682bfe0f 100644 --- a/lib/config/applyrule.hpp +++ b/lib/config/applyrule.hpp @@ -46,12 +46,12 @@ public: String GetFVVar(void) const; Expression::Ptr GetFTerm(void) const; DebugInfo GetDebugInfo(void) const; - Dictionary::Ptr GetScope(void) const; + Object::Ptr GetScope(void) const; - bool EvaluateFilter(const Dictionary::Ptr& scope) const; + bool EvaluateFilter(const Object::Ptr& scope) const; static void AddRule(const String& sourceType, const String& targetType, const String& name, const Expression::Ptr& expression, - const Expression::Ptr& filter, const String& fkvar, const String& fvvar, const Expression::Ptr& fterm, const DebugInfo& di, const Dictionary::Ptr& scope); + const Expression::Ptr& filter, const String& fkvar, const String& fvvar, const Expression::Ptr& fterm, const DebugInfo& di, const Object::Ptr& scope); static void EvaluateRules(bool clear); static void RegisterType(const String& sourceType, const std::vector& targetTypes, const ApplyRule::Callback& callback); @@ -68,14 +68,14 @@ private: String m_FVVar; Expression::Ptr m_FTerm; DebugInfo m_DebugInfo; - Dictionary::Ptr m_Scope; + Object::Ptr m_Scope; static CallbackMap m_Callbacks; static RuleMap m_Rules; ApplyRule(const String& targetType, const String& name, const Expression::Ptr& expression, const Expression::Ptr& filter, const String& fkvar, const String& fvvar, const Expression::Ptr& fterm, - const DebugInfo& di, const Dictionary::Ptr& scope); + const DebugInfo& di, const Object::Ptr& scope); }; } diff --git a/lib/config/configcompilercontext.cpp b/lib/config/configcompilercontext.cpp index b20684e6b..e5b95ce25 100644 --- a/lib/config/configcompilercontext.cpp +++ b/lib/config/configcompilercontext.cpp @@ -19,7 +19,10 @@ #include "config/configcompilercontext.hpp" #include "base/singleton.hpp" +#include "base/json.hpp" +#include "base/netstring.hpp" #include +#include using namespace icinga; @@ -61,3 +64,50 @@ ConfigCompilerContext *ConfigCompilerContext::GetInstance(void) return Singleton::GetInstance(); } +void ConfigCompilerContext::OpenObjectsFile(const String& filename) +{ + m_ObjectsPath = filename; + + String tempFilename = m_ObjectsPath + ".tmp"; + + std::fstream *fp = new std::fstream(); + fp->open(tempFilename.CStr(), std::ios_base::out); + + if (!*fp) + BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file")); + + m_ObjectsFP = make_shared(fp, true); +} + +void ConfigCompilerContext::WriteObject(const Dictionary::Ptr& object) +{ + if (!m_ObjectsFP) + return; + + String json = JsonEncode(object); + + { + boost::mutex::scoped_lock lock(m_Mutex); + NetString::WriteStringToStream(m_ObjectsFP, json); + } +} + +void ConfigCompilerContext::FinishObjectsFile(void) +{ + m_ObjectsFP->Close(); + + String tempFilename = m_ObjectsPath + ".tmp"; + +#ifdef _WIN32 + _unlink(m_ObjectsPath.CStr()); +#endif /* _WIN32 */ + + if (rename(tempFilename.CStr(), m_ObjectsPath.CStr()) < 0) { + BOOST_THROW_EXCEPTION(posix_error() + << boost::errinfo_api_function("rename") + << boost::errinfo_errno(errno) + << boost::errinfo_file_name(tempFilename)); + } + +} + diff --git a/lib/config/configcompilercontext.hpp b/lib/config/configcompilercontext.hpp index 2a3401e0c..84091ba2f 100644 --- a/lib/config/configcompilercontext.hpp +++ b/lib/config/configcompilercontext.hpp @@ -22,6 +22,8 @@ #include "config/i2-config.hpp" #include "base/debuginfo.hpp" +#include "base/stdiostream.hpp" +#include "base/dictionary.hpp" #include #include @@ -51,10 +53,16 @@ public: void Reset(void); + void OpenObjectsFile(const String& filename); + void WriteObject(const Dictionary::Ptr& object); + void FinishObjectsFile(void); + static ConfigCompilerContext *GetInstance(void); private: std::vector m_Messages; + String m_ObjectsPath; + StdioStream::Ptr m_ObjectsFP; mutable boost::mutex m_Mutex; }; diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index 8dbde2dcc..8199e029f 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -32,6 +32,7 @@ #include "base/exception.hpp" #include "base/stdiostream.hpp" #include "base/netstring.hpp" +#include "base/serializer.hpp" #include "base/json.hpp" #include "base/configerror.hpp" #include @@ -55,9 +56,9 @@ ConfigItem::ItemMap ConfigItem::m_Items; */ ConfigItem::ConfigItem(const String& type, const String& name, bool abstract, const Expression::Ptr& exprl, - const DebugInfo& debuginfo, const Dictionary::Ptr& scope, + const DebugInfo& debuginfo, const Object::Ptr& scope, const String& zone) - : m_Type(type), m_Name(name), m_Abstract(abstract), m_Validated(false), + : m_Type(type), m_Name(name), m_Abstract(abstract), m_ExpressionList(exprl), m_DebugInfo(debuginfo), m_Scope(scope), m_Zone(zone) { @@ -103,7 +104,7 @@ DebugInfo ConfigItem::GetDebugInfo(void) const return m_DebugInfo; } -Dictionary::Ptr ConfigItem::GetScope(void) const +Object::Ptr ConfigItem::GetScope(void) const { return m_Scope; } @@ -118,62 +119,13 @@ Expression::Ptr ConfigItem::GetExpressionList(void) const return m_ExpressionList; } -Dictionary::Ptr ConfigItem::GetProperties(void) -{ - ASSERT(!OwnsLock()); - VERIFY(!IsAbstract()); - - ObjectLock olock(this); - - if (!m_Properties) { - Dictionary::Ptr locals = make_shared(); - locals->Set("__parent", m_Scope); - locals->Set("name", m_Name); - - m_Properties = make_shared(); - m_Properties->Set("type", m_Type); - if (!m_Zone.IsEmpty()) - m_Properties->Set("zone", m_Zone); - m_Properties->Set("__parent", locals); - GetExpressionList()->Evaluate(m_Properties, &m_DebugHints); - m_Properties->Remove("__parent"); - - String name = m_Name; - - if (!m_Abstract) { - shared_ptr nc = dynamic_pointer_cast(Type::GetByName(m_Type)); - - if (nc) { - name = nc->MakeName(m_Name, m_Properties); - - if (name.IsEmpty()) - BOOST_THROW_EXCEPTION(std::runtime_error("Could not determine name for object")); - } - } - - if (name != m_Name) - m_Properties->Set("name", m_Name); - - m_Properties->Set("__name", name); - - VERIFY(m_Properties->Get("type") == GetType()); - } - - return m_Properties; -} - -const DebugHint& ConfigItem::GetDebugHints(void) const -{ - return m_DebugHints; -} - /** * Commits the configuration item by creating a DynamicObject * object. * * @returns The DynamicObject that was created/updated. */ -DynamicObject::Ptr ConfigItem::Commit(void) +DynamicObject::Ptr ConfigItem::Commit(bool discard) { ASSERT(!OwnsLock()); @@ -183,16 +135,88 @@ DynamicObject::Ptr ConfigItem::Commit(void) #endif /* _DEBUG */ /* Make sure the type is valid. */ - DynamicType::Ptr dtype = DynamicType::GetByName(GetType()); + Type::Ptr type = Type::GetByName(GetType()); - if (!dtype) - BOOST_THROW_EXCEPTION(std::runtime_error("Type '" + GetType() + "' does not exist.")); + if (!type || !Type::GetByName("DynamicObject")->IsAssignableFrom(type)) + BOOST_THROW_EXCEPTION(ConfigError("Type '" + GetType() + "' does not exist.")); if (IsAbstract()) return DynamicObject::Ptr(); - DynamicObject::Ptr dobj = dtype->CreateObject(GetProperties()); + DynamicObject::Ptr dobj = static_pointer_cast(type->Instantiate()); + dobj->SetDebugInfo(m_DebugInfo); + dobj->SetTypeName(m_Type); + dobj->SetZone(m_Zone); + + Dictionary::Ptr locals = make_shared(); + locals->Set("__parent", m_Scope); + m_Scope.reset(); + locals->Set("name", m_Name); + + dobj->SetParentScope(locals); + + DebugHint debugHints; + + try { + m_ExpressionList->Evaluate(dobj, &debugHints); + } catch (const ConfigError& ex) { + const DebugInfo *di = boost::get_error_info(ex); + ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo()); + } catch (const std::exception& ex) { + ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex)); + } + + if (discard) + m_ExpressionList.reset(); + + dobj->SetParentScope(Dictionary::Ptr()); + + String name = m_Name; + + shared_ptr nc = dynamic_pointer_cast(type); + + if (nc) { + name = nc->MakeName(m_Name, dobj); + + if (name.IsEmpty()) + BOOST_THROW_EXCEPTION(std::runtime_error("Could not determine name for object")); + } + + if (name != m_Name) + dobj->SetShortName(m_Name); + + dobj->SetName(name); + + Dictionary::Ptr attrs = Serialize(dobj, FAConfig); + + Dictionary::Ptr persistentItem = make_shared(); + + persistentItem->Set("type", GetType()); + persistentItem->Set("name", GetName()); + persistentItem->Set("properties", attrs); + persistentItem->Set("debug_hints", debugHints.ToDictionary()); + + ConfigCompilerContext::GetInstance()->WriteObject(persistentItem); + + ConfigType::Ptr ctype = ConfigType::GetByName(GetType()); + + if (!ctype) + ConfigCompilerContext::GetInstance()->AddMessage(false, "No validation type found for object '" + GetName() + "' of type '" + GetType() + "'"); + else { + TypeRuleUtilities utils; + + try { + attrs->Remove("name"); + ctype->ValidateItem(GetName(), attrs, GetDebugInfo(), &utils); + } catch (const ConfigError& ex) { + const DebugInfo *di = boost::get_error_info(ex); + ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo()); + } catch (const std::exception& ex) { + ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex)); + } + } + dobj->Register(); m_Object = dobj; @@ -207,20 +231,11 @@ void ConfigItem::Register(void) { String name = m_Name; - /* If this is a non-abstract object we need to figure out - * its real name now - or assign it a temporary name. */ - if (!m_Abstract) { - shared_ptr nc = dynamic_pointer_cast(Type::GetByName(m_Type)); + shared_ptr nc = dynamic_pointer_cast(Type::GetByName(m_Type)); - if (nc) { - name = nc->MakeName(m_Name, Dictionary::Ptr()); - - ASSERT(name.IsEmpty() || name == m_Name); - - if (name.IsEmpty()) - name = Utility::NewUniqueID(); - } - } + /* If this is a non-abstract object with a composite name we don't register it. */ + if (!m_Abstract && nc) + return; std::pair key = std::make_pair(m_Type, name); ConfigItem::Ptr self = GetSelf(); @@ -254,104 +269,17 @@ ConfigItem::Ptr ConfigItem::GetObject(const String& type, const String& name) return ConfigItem::Ptr(); } -void ConfigItem::ValidateItem(void) -{ - if (m_Validated || IsAbstract()) - return; - - ConfigType::Ptr ctype = ConfigType::GetByName(GetType()); - - if (!ctype) { - ConfigCompilerContext::GetInstance()->AddMessage(false, "No validation type found for object '" + GetName() + "' of type '" + GetType() + "'"); - - return; - } - - TypeRuleUtilities utils; - - try { - ctype->ValidateItem(GetName(), GetProperties(), GetDebugInfo(), &utils); - } catch (const ConfigError& ex) { - const DebugInfo *di = boost::get_error_info(ex); - ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo()); - } catch (const std::exception& ex) { - ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex)); - } - - m_Validated = true; -} - -void ConfigItem::WriteObjectsFile(const String& filename) -{ - Log(LogInformation, "ConfigItem") - << "Dumping config items to file '" << filename << "'"; - - String tempFilename = filename + ".tmp"; - - std::fstream fp; - fp.open(tempFilename.CStr(), std::ios_base::out); - - if (!fp) - BOOST_THROW_EXCEPTION(std::runtime_error("Could not open '" + tempFilename + "' file")); - - StdioStream::Ptr sfp = make_shared(&fp, false); - - BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) { - ConfigItem::Ptr item = kv.second; - - if (item->IsAbstract()) - continue; - - Dictionary::Ptr persistentItem = make_shared(); - - persistentItem->Set("type", item->GetType()); - persistentItem->Set("name", item->GetName()); - persistentItem->Set("properties", item->GetProperties()); - persistentItem->Set("debug_hints", item->GetDebugHints().ToDictionary()); - - String json = JsonEncode(persistentItem); - - NetString::WriteStringToStream(sfp, json); - } - - sfp->Close(); - - fp.close(); - -#ifdef _WIN32 - _unlink(filename.CStr()); -#endif /* _WIN32 */ - - if (rename(tempFilename.CStr(), filename.CStr()) < 0) { - BOOST_THROW_EXCEPTION(posix_error() - << boost::errinfo_api_function("rename") - << boost::errinfo_errno(errno) - << boost::errinfo_file_name(tempFilename)); - } -} - -bool ConfigItem::ValidateItems(const String& objectsFile) +bool ConfigItem::ValidateItems(void) { if (ConfigCompilerContext::GetInstance()->HasErrors()) return false; ParallelWorkQueue upq; - Log(LogInformation, "ConfigItem", "Validating config items (step 1)..."); - - BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) { - upq.Enqueue(boost::bind(&ConfigItem::ValidateItem, kv.second)); - } - - upq.Join(); - - if (ConfigCompilerContext::GetInstance()->HasErrors()) - return false; - Log(LogInformation, "ConfigItem", "Committing config items"); BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) { - upq.Enqueue(boost::bind(&ConfigItem::Commit, kv.second)); + upq.Enqueue(boost::bind(&ConfigItem::Commit, kv.second, false)); } upq.Join(); @@ -381,17 +309,8 @@ bool ConfigItem::ValidateItems(const String& objectsFile) Log(LogInformation, "ConfigItem", "Evaluating 'object' rules (step 2)..."); ObjectRule::EvaluateRules(true); - Log(LogInformation, "ConfigItem", "Validating config items (step 2)..."); - - BOOST_FOREACH(const ItemMap::value_type& kv, m_Items) { - upq.Enqueue(boost::bind(&ConfigItem::ValidateItem, kv.second)); - } - upq.Join(); - if (!objectsFile.IsEmpty()) - ConfigItem::WriteObjectsFile(objectsFile); - ConfigItem::DiscardItems(); ConfigType::DiscardTypes(); diff --git a/lib/config/configitem.hpp b/lib/config/configitem.hpp index a267b79d6..2c5e5ab27 100644 --- a/lib/config/configitem.hpp +++ b/lib/config/configitem.hpp @@ -39,7 +39,7 @@ public: ConfigItem(const String& type, const String& name, bool abstract, const Expression::Ptr& exprl, const DebugInfo& debuginfo, - const Dictionary::Ptr& scope, const String& zone); + const Object::Ptr& scope, const String& zone); String GetType(void) const; String GetName(void) const; @@ -48,42 +48,33 @@ public: std::vector GetParents(void) const; Expression::Ptr GetExpressionList(void) const; - Dictionary::Ptr GetProperties(void); - const DebugHint& GetDebugHints(void) const; - DynamicObject::Ptr Commit(void); + DynamicObject::Ptr Commit(bool discard = true); void Register(void); DebugInfo GetDebugInfo(void) const; - Dictionary::Ptr GetScope(void) const; + Object::Ptr GetScope(void) const; String GetZone(void) const; static ConfigItem::Ptr GetObject(const String& type, const String& name); - void ValidateItem(void); - - static bool ValidateItems(const String& objectsFile = String()); + static bool ValidateItems(void); static bool ActivateItems(void); static void DiscardItems(void); - static void WriteObjectsFile(const String& filename); - private: String m_Type; /**< The object type. */ String m_Name; /**< The name. */ bool m_Abstract; /**< Whether this is a template. */ - bool m_Validated; /** Whether this object has been validated. */ Expression::Ptr m_ExpressionList; - Dictionary::Ptr m_Properties; - DebugHint m_DebugHints; std::vector m_ParentNames; /**< The names of parent configuration items. */ DebugInfo m_DebugInfo; /**< Debug information. */ - Dictionary::Ptr m_Scope; /**< variable scope. */ + Object::Ptr m_Scope; /**< variable scope. */ String m_Zone; /**< The zone. */ DynamicObject::Ptr m_Object; diff --git a/lib/config/configitembuilder.cpp b/lib/config/configitembuilder.cpp index 16dab1194..c843c9cb6 100644 --- a/lib/config/configitembuilder.cpp +++ b/lib/config/configitembuilder.cpp @@ -54,7 +54,7 @@ void ConfigItemBuilder::SetAbstract(bool abstract) m_Abstract = abstract; } -void ConfigItemBuilder::SetScope(const Dictionary::Ptr& scope) +void ConfigItemBuilder::SetScope(const Object::Ptr& scope) { m_Scope = scope; } diff --git a/lib/config/configitembuilder.hpp b/lib/config/configitembuilder.hpp index 30b16f0c9..923ce138f 100644 --- a/lib/config/configitembuilder.hpp +++ b/lib/config/configitembuilder.hpp @@ -45,7 +45,7 @@ public: void SetType(const String& type); void SetName(const String& name); void SetAbstract(bool abstract); - void SetScope(const Dictionary::Ptr& scope); + void SetScope(const Object::Ptr& scope); void SetZone(const String& zone); void AddExpression(const Expression::Ptr& expr); @@ -58,7 +58,7 @@ private: bool m_Abstract; /**< Whether the item is abstract. */ Array::Ptr m_Expressions; /**< Expressions for this item. */ DebugInfo m_DebugInfo; /**< Debug information. */ - Dictionary::Ptr m_Scope; /**< variable scope. */ + Object::Ptr m_Scope; /**< variable scope. */ String m_Zone; /**< The zone. */ }; diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index 01f26bf35..dab19f251 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -33,6 +33,7 @@ #include "base/configerror.hpp" #include #include +#include #include using namespace icinga; @@ -45,7 +46,7 @@ Expression::Expression(OpCallback op, const Value& operand1, const Value& operan : m_Operator(op), m_Operand1(operand1), m_Operand2(operand2), m_DebugInfo(di) { } -Value Expression::Evaluate(const Dictionary::Ptr& locals, DebugHint *dhint) const +Value Expression::Evaluate(const Object::Ptr& context, DebugHint *dhint) const { try { #ifdef _DEBUG @@ -57,7 +58,7 @@ Value Expression::Evaluate(const Dictionary::Ptr& locals, DebugHint *dhint) cons } #endif /* _DEBUG */ - return m_Operator(this, locals, dhint); + return m_Operator(this, context, dhint); } catch (const std::exception& ex) { if (boost::get_error_info(ex)) throw; @@ -99,125 +100,125 @@ void Expression::Dump(std::ostream& stream, int indent) const DumpOperand(stream, m_Operand2, indent + 1); } -Value Expression::EvaluateOperand1(const Dictionary::Ptr& locals, DebugHint *dhint) const +Value Expression::EvaluateOperand1(const Object::Ptr& context, DebugHint *dhint) const { - return static_cast(m_Operand1)->Evaluate(locals, dhint); + return static_cast(m_Operand1)->Evaluate(context, dhint); } -Value Expression::EvaluateOperand2(const Dictionary::Ptr& locals, DebugHint *dhint) const +Value Expression::EvaluateOperand2(const Object::Ptr& context, DebugHint *dhint) const { - return static_cast(m_Operand2)->Evaluate(locals, dhint); + return static_cast(m_Operand2)->Evaluate(context, dhint); } -Value Expression::OpLiteral(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpLiteral(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { return expr->m_Operand1; } -Value Expression::OpVariable(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpVariable(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - Dictionary::Ptr scope = locals; + Object::Ptr scope = context; while (scope) { - if (scope->Contains(expr->m_Operand1)) - return scope->Get(expr->m_Operand1); + if (HasField(scope, expr->m_Operand1)) + return GetField(scope, expr->m_Operand1); - scope = scope->Get("__parent"); + scope = GetField(scope, "__parent"); } return ScriptVariable::Get(expr->m_Operand1); } -Value Expression::OpNegate(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpNegate(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return ~(long)expr->EvaluateOperand1(locals); + return ~(long)expr->EvaluateOperand1(context); } -Value Expression::OpLogicalNegate(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpLogicalNegate(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return !expr->EvaluateOperand1(locals).ToBool(); + return !expr->EvaluateOperand1(context).ToBool(); } -Value Expression::OpAdd(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpAdd(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) + expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) + expr->EvaluateOperand2(context); } -Value Expression::OpSubtract(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpSubtract(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) - expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) - expr->EvaluateOperand2(context); } -Value Expression::OpMultiply(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpMultiply(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) * expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) * expr->EvaluateOperand2(context); } -Value Expression::OpDivide(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpDivide(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) / expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) / expr->EvaluateOperand2(context); } -Value Expression::OpBinaryAnd(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpBinaryAnd(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) & expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) & expr->EvaluateOperand2(context); } -Value Expression::OpBinaryOr(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpBinaryOr(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) | expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) | expr->EvaluateOperand2(context); } -Value Expression::OpShiftLeft(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpShiftLeft(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) << expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) << expr->EvaluateOperand2(context); } -Value Expression::OpShiftRight(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpShiftRight(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) >> expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) >> expr->EvaluateOperand2(context); } -Value Expression::OpEqual(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpEqual(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) == expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) == expr->EvaluateOperand2(context); } -Value Expression::OpNotEqual(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpNotEqual(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) != expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) != expr->EvaluateOperand2(context); } -Value Expression::OpLessThan(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpLessThan(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) < expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) < expr->EvaluateOperand2(context); } -Value Expression::OpGreaterThan(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpGreaterThan(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) > expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) > expr->EvaluateOperand2(context); } -Value Expression::OpLessThanOrEqual(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpLessThanOrEqual(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) <= expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) <= expr->EvaluateOperand2(context); } -Value Expression::OpGreaterThanOrEqual(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpGreaterThanOrEqual(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals) >= expr->EvaluateOperand2(locals); + return expr->EvaluateOperand1(context) >= expr->EvaluateOperand2(context); } -Value Expression::OpIn(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpIn(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - Value right = expr->EvaluateOperand2(locals); + Value right = expr->EvaluateOperand2(context); if (right.IsEmpty()) return false; else if (!right.IsObjectType()) BOOST_THROW_EXCEPTION(ConfigError("Invalid right side argument for 'in' operator: " + JsonEncode(right))); - Value left = expr->EvaluateOperand1(locals); + Value left = expr->EvaluateOperand1(context); Array::Ptr arr = right; bool found = false; @@ -232,24 +233,24 @@ Value Expression::OpIn(const Expression *expr, const Dictionary::Ptr& locals, De return found; } -Value Expression::OpNotIn(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpNotIn(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return !OpIn(expr, locals, dhint); + return !OpIn(expr, context, dhint); } -Value Expression::OpLogicalAnd(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpLogicalAnd(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals).ToBool() && expr->EvaluateOperand2(locals).ToBool(); + return expr->EvaluateOperand1(context).ToBool() && expr->EvaluateOperand2(context).ToBool(); } -Value Expression::OpLogicalOr(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpLogicalOr(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - return expr->EvaluateOperand1(locals).ToBool() || expr->EvaluateOperand2(locals).ToBool(); + return expr->EvaluateOperand1(context).ToBool() || expr->EvaluateOperand2(context).ToBool(); } -Value Expression::OpFunctionCall(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpFunctionCall(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - Value funcName = expr->EvaluateOperand1(locals); + Value funcName = expr->EvaluateOperand1(context); ScriptFunction::Ptr func; @@ -261,17 +262,17 @@ Value Expression::OpFunctionCall(const Expression *expr, const Dictionary::Ptr& if (!func) BOOST_THROW_EXCEPTION(ConfigError("Function '" + funcName + "' does not exist.")); - Array::Ptr arr = expr->EvaluateOperand2(locals); + Array::Ptr arr = expr->EvaluateOperand2(context); std::vector arguments; for (Array::SizeType index = 0; index < arr->GetLength(); index++) { const Expression::Ptr& aexpr = arr->Get(index); - arguments.push_back(aexpr->Evaluate(locals)); + arguments.push_back(aexpr->Evaluate(context)); } return func->Invoke(arguments); } -Value Expression::OpArray(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpArray(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { Array::Ptr arr = expr->m_Operand1; Array::Ptr result = make_shared(); @@ -279,28 +280,28 @@ Value Expression::OpArray(const Expression *expr, const Dictionary::Ptr& locals, if (arr) { for (Array::SizeType index = 0; index < arr->GetLength(); index++) { const Expression::Ptr& aexpr = arr->Get(index); - result->Add(aexpr->Evaluate(locals)); + result->Add(aexpr->Evaluate(context)); } } return result; } -Value Expression::OpDict(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpDict(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { Array::Ptr arr = expr->m_Operand1; bool in_place = expr->m_Operand2; Dictionary::Ptr result = make_shared(); - result->Set("__parent", locals); + result->Set("__parent", context); if (arr) { for (Array::SizeType index = 0; index < arr->GetLength(); index++) { const Expression::Ptr& aexpr = arr->Get(index); - Dictionary::Ptr alocals = in_place ? locals : result; - aexpr->Evaluate(alocals, dhint); + Object::Ptr acontext = in_place ? context : result; + aexpr->Evaluate(acontext, dhint); - if (alocals->Contains("__result")) + if (HasField(acontext, "__result")) break; } } @@ -310,7 +311,7 @@ Value Expression::OpDict(const Expression *expr, const Dictionary::Ptr& locals, return xresult; } -Value Expression::OpSet(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpSet(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { Array::Ptr left = expr->m_Operand1; Array::Ptr indexer = left->Get(0); @@ -323,14 +324,14 @@ Value Expression::OpSet(const Expression *expr, const Dictionary::Ptr& locals, D for (Array::SizeType i = 0; i < indexer->GetLength(); i++) { Expression::Ptr indexExpr = indexer->Get(i); - String tempindex = indexExpr->Evaluate(locals, dhint); + String tempindex = indexExpr->Evaluate(context, dhint); if (i == indexer->GetLength() - 1) index = tempindex; if (i == 0) { - parent = locals; - object = locals->Get(tempindex); + parent = context; + object = GetField(context, tempindex); } else { parent = object; @@ -338,7 +339,7 @@ Value Expression::OpSet(const Expression *expr, const Dictionary::Ptr& locals, D Expression::Ptr eindex = make_shared(&Expression::OpLiteral, tempindex, expr->m_DebugInfo); Expression::Ptr eip = make_shared(&Expression::OpIndexer, eparent, eindex, expr->m_DebugInfo); - object = eip->Evaluate(locals, dhint); + object = eip->Evaluate(context, dhint); } if (sdhint) @@ -347,12 +348,11 @@ Value Expression::OpSet(const Expression *expr, const Dictionary::Ptr& locals, D if (i != indexer->GetLength() - 1 && object.IsEmpty()) { object = make_shared(); - Dictionary::Ptr pdict = parent; - pdict->Set(tempindex, object); + SetField(parent, tempindex, object); } } - Value right = expr->EvaluateOperand2(locals, dhint); + Value right = expr->EvaluateOperand2(context, dhint); if (csop != OpSetLiteral) { Expression::OpCallback op; @@ -379,11 +379,10 @@ Value Expression::OpSet(const Expression *expr, const Dictionary::Ptr& locals, D make_shared(&Expression::OpLiteral, right, expr->m_DebugInfo), expr->m_DebugInfo); - right = ecp->Evaluate(locals, dhint); + right = ecp->Evaluate(context, dhint); } - Dictionary::Ptr pdict = parent; - pdict->Set(index, right); + SetField(parent, index, right); if (sdhint) sdhint->AddMessage("=", expr->m_DebugInfo); @@ -391,10 +390,10 @@ Value Expression::OpSet(const Expression *expr, const Dictionary::Ptr& locals, D return right; } -Value Expression::OpIndexer(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpIndexer(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - Value value = expr->EvaluateOperand1(locals); - Value index = expr->EvaluateOperand2(locals); + Value value = expr->EvaluateOperand1(context); + Value index = expr->EvaluateOperand2(context); if (value.IsObjectType()) { Dictionary::Ptr dict = value; @@ -422,44 +421,44 @@ Value Expression::OpIndexer(const Expression *expr, const Dictionary::Ptr& local } } -Value Expression::OpImport(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpImport(const Expression *expr, const Object::Ptr& context, DebugHint *dhint) { - Value type = expr->EvaluateOperand1(locals); - Value name = expr->EvaluateOperand2(locals); + Value type = expr->EvaluateOperand1(context); + Value name = expr->EvaluateOperand2(context); ConfigItem::Ptr item = ConfigItem::GetObject(type, name); if (!item) BOOST_THROW_EXCEPTION(ConfigError("Import references unknown template: '" + name + "'")); - item->GetExpressionList()->Evaluate(locals, dhint); + item->GetExpressionList()->Evaluate(context, dhint); return Empty; } -Value Expression::FunctionWrapper(const std::vector& arguments, const Array::Ptr& funcargs, const Expression::Ptr& expr, const Dictionary::Ptr& scope) +Value Expression::FunctionWrapper(const std::vector& arguments, const Array::Ptr& funcargs, const Expression::Ptr& expr, const Object::Ptr& scope) { if (arguments.size() < funcargs->GetLength()) BOOST_THROW_EXCEPTION(ConfigError("Too few arguments for function")); - Dictionary::Ptr locals = make_shared(); - locals->Set("__parent", scope); + Dictionary::Ptr context = make_shared(); + context->Set("__parent", scope); for (std::vector::size_type i = 0; i < std::min(arguments.size(), funcargs->GetLength()); i++) - locals->Set(funcargs->Get(i), arguments[i]); + context->Set(funcargs->Get(i), arguments[i]); - expr->Evaluate(locals); - return locals->Get("__result"); + expr->Evaluate(context); + return context->Get("__result"); } -Value Expression::OpFunction(const Expression* expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpFunction(const Expression* expr, const Object::Ptr& context, DebugHint *dhint) { Array::Ptr left = expr->m_Operand1; Expression::Ptr aexpr = left->Get(1); String name = left->Get(0); Array::Ptr funcargs = expr->m_Operand2; - ScriptFunction::Ptr func = make_shared(boost::bind(&Expression::FunctionWrapper, _1, funcargs, aexpr, locals)); + ScriptFunction::Ptr func = make_shared(boost::bind(&Expression::FunctionWrapper, _1, funcargs, aexpr, context)); if (!name.IsEmpty()) ScriptFunction::Register(name, func); @@ -467,7 +466,7 @@ Value Expression::OpFunction(const Expression* expr, const Dictionary::Ptr& loca return func; } -Value Expression::OpApply(const Expression* expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpApply(const Expression* expr, const Object::Ptr& context, DebugHint *dhint) { Array::Ptr left = expr->m_Operand1; Expression::Ptr exprl = expr->m_Operand2; @@ -479,14 +478,14 @@ Value Expression::OpApply(const Expression* expr, const Dictionary::Ptr& locals, String fvvar = left->Get(5); Expression::Ptr fterm = left->Get(6); - String name = aname->Evaluate(locals, dhint); + String name = aname->Evaluate(context, dhint); - ApplyRule::AddRule(type, target, name, exprl, filter, fkvar, fvvar, fterm, expr->m_DebugInfo, locals); + ApplyRule::AddRule(type, target, name, exprl, filter, fkvar, fvvar, fterm, expr->m_DebugInfo, context); return Empty; } -Value Expression::OpObject(const Expression* expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpObject(const Expression* expr, const Object::Ptr& context, DebugHint *dhint) { Array::Ptr left = expr->m_Operand1; Expression::Ptr exprl = expr->m_Operand2; @@ -496,7 +495,7 @@ Value Expression::OpObject(const Expression* expr, const Dictionary::Ptr& locals Expression::Ptr filter = left->Get(3); String zone = left->Get(4); - String name = aname->Evaluate(locals, dhint); + String name = aname->Evaluate(context, dhint); ConfigItemBuilder::Ptr item = make_shared(expr->m_DebugInfo); @@ -531,16 +530,16 @@ Value Expression::OpObject(const Expression* expr, const Dictionary::Ptr& locals item->AddExpression(exprl); item->SetAbstract(abstract); - item->SetScope(locals); + item->SetScope(context); item->SetZone(zone); item->Compile()->Register(); - ObjectRule::AddRule(type, name, exprl, filter, expr->m_DebugInfo, locals); + ObjectRule::AddRule(type, name, exprl, filter, expr->m_DebugInfo, context); return Empty; } -Value Expression::OpFor(const Expression* expr, const Dictionary::Ptr& locals, DebugHint *dhint) +Value Expression::OpFor(const Expression* expr, const Object::Ptr& context, DebugHint *dhint) { Array::Ptr left = expr->m_Operand1; String kvar = left->Get(0); @@ -548,7 +547,7 @@ Value Expression::OpFor(const Expression* expr, const Dictionary::Ptr& locals, D Expression::Ptr aexpr = left->Get(2); Expression::Ptr ascope = expr->m_Operand2; - Value value = aexpr->Evaluate(locals, dhint); + Value value = aexpr->Evaluate(context, dhint); if (value.IsObjectType()) { if (!vvar.IsEmpty()) @@ -558,11 +557,11 @@ Value Expression::OpFor(const Expression* expr, const Dictionary::Ptr& locals, D ObjectLock olock(arr); BOOST_FOREACH(const Value& value, arr) { - Dictionary::Ptr xlocals = make_shared(); - xlocals->Set("__parent", locals); - xlocals->Set(kvar, value); + Dictionary::Ptr xcontext = make_shared(); + xcontext->Set("__parent", context); + xcontext->Set(kvar, value); - ascope->Evaluate(xlocals, dhint); + ascope->Evaluate(xcontext, dhint); } } else if (value.IsObjectType()) { if (vvar.IsEmpty()) @@ -572,12 +571,12 @@ Value Expression::OpFor(const Expression* expr, const Dictionary::Ptr& locals, D ObjectLock olock(dict); BOOST_FOREACH(const Dictionary::Pair& kv, dict) { - Dictionary::Ptr xlocals = make_shared(); - xlocals->Set("__parent", locals); - xlocals->Set(kvar, kv.first); - xlocals->Set(vvar, kv.second); + Dictionary::Ptr xcontext = make_shared(); + xcontext->Set("__parent", context); + xcontext->Set(kvar, kv.first); + xcontext->Set(vvar, kv.second); - ascope->Evaluate(xlocals, dhint); + ascope->Evaluate(xcontext, dhint); } } else BOOST_THROW_EXCEPTION(ConfigError("Invalid type in __for expression: " + value.GetTypeName()) << errinfo_debuginfo(expr->m_DebugInfo)); @@ -620,3 +619,68 @@ Expression::Ptr icinga::MakeLiteral(const Value& lit) { return make_shared(&Expression::OpLiteral, lit, DebugInfo()); } + +bool Expression::HasField(const Object::Ptr& context, const String& field) +{ + Dictionary::Ptr dict = dynamic_pointer_cast(context); + + if (dict) + return dict->Contains(field); + else { + Type::Ptr type = context->GetReflectionType(); + + if (!type) + return false; + + return type->GetFieldId(field) != -1; + } +} + +Value Expression::GetField(const Object::Ptr& context, const String& field) +{ + Dictionary::Ptr dict = dynamic_pointer_cast(context); + + if (dict) + return dict->Get(field); + else { + Type::Ptr type = context->GetReflectionType(); + + if (!type) + return Empty; + + int fid = type->GetFieldId(field); + + if (fid == -1) + return Empty; + + return context->GetField(fid); + } +} + +void Expression::SetField(const Object::Ptr& context, const String& field, const Value& value) +{ + Dictionary::Ptr dict = dynamic_pointer_cast(context); + + if (dict) + dict->Set(field, value); + else { + Type::Ptr type = context->GetReflectionType(); + + if (!type) + BOOST_THROW_EXCEPTION(ConfigError("Cannot set field on object.")); + + int fid = type->GetFieldId(field); + + if (fid == -1) + BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' does not exist.")); + + try { + context->SetField(fid, value); + } catch (const boost::bad_lexical_cast&) { + BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "'")); + } catch (const std::bad_cast&) { + BOOST_THROW_EXCEPTION(ConfigError("Attribute '" + field + "' cannot be set to value of type '" + value.GetTypeName() + "'")); + } + } +} + diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp index 3ef66761d..0a6a7348c 100644 --- a/lib/config/expression.hpp +++ b/lib/config/expression.hpp @@ -63,49 +63,49 @@ class I2_CONFIG_API Expression : public Object public: DECLARE_PTR_TYPEDEFS(Expression); - typedef Value (*OpCallback)(const Expression *, const Dictionary::Ptr&, DebugHint *dhint); + typedef Value (*OpCallback)(const Expression *, const Object::Ptr&, DebugHint *dhint); Expression(OpCallback op, const Value& operand1, const DebugInfo& di); Expression(OpCallback op, const Value& operand1, const Value& operand2, const DebugInfo& di); - Value Evaluate(const Dictionary::Ptr& locals, DebugHint *dhint = NULL) const; + Value Evaluate(const Object::Ptr& context, DebugHint *dhint = NULL) const; void MakeInline(void); void Dump(std::ostream& stream, int indent = 0) const; - static Value OpLiteral(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpVariable(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpNegate(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpLogicalNegate(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpAdd(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpSubtract(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpMultiply(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpDivide(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpBinaryAnd(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpBinaryOr(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpShiftLeft(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpShiftRight(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpEqual(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpNotEqual(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpLessThan(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpGreaterThan(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpLessThanOrEqual(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpGreaterThanOrEqual(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpIn(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpNotIn(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpLogicalAnd(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpLogicalOr(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpFunctionCall(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpArray(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpDict(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpSet(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpIndexer(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpImport(const Expression *expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpFunction(const Expression* expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpApply(const Expression* expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpObject(const Expression* expr, const Dictionary::Ptr& locals, DebugHint *dhint); - static Value OpFor(const Expression* expr, const Dictionary::Ptr& locals, DebugHint *dhint); + static Value OpLiteral(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpVariable(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpNegate(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpLogicalNegate(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpAdd(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpSubtract(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpMultiply(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpDivide(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpBinaryAnd(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpBinaryOr(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpShiftLeft(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpShiftRight(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpEqual(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpNotEqual(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpLessThan(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpGreaterThan(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpLessThanOrEqual(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpGreaterThanOrEqual(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpIn(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpNotIn(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpLogicalAnd(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpLogicalOr(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpFunctionCall(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpArray(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpDict(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpSet(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpIndexer(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpImport(const Expression *expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpFunction(const Expression* expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpApply(const Expression* expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpObject(const Expression* expr, const Object::Ptr& context, DebugHint *dhint); + static Value OpFor(const Expression* expr, const Object::Ptr& context, DebugHint *dhint); private: OpCallback m_Operator; @@ -113,13 +113,17 @@ private: Value m_Operand2; DebugInfo m_DebugInfo; - Value EvaluateOperand1(const Dictionary::Ptr& locals, DebugHint *dhint = NULL) const; - Value EvaluateOperand2(const Dictionary::Ptr& locals, DebugHint *dhint = NULL) const; + Value EvaluateOperand1(const Object::Ptr& context, DebugHint *dhint = NULL) const; + Value EvaluateOperand2(const Object::Ptr& context, DebugHint *dhint = NULL) const; static void DumpOperand(std::ostream& stream, const Value& operand, int indent); static Value FunctionWrapper(const std::vector& arguments, const Array::Ptr& funcargs, - const Expression::Ptr& expr, const Dictionary::Ptr& scope); + const Expression::Ptr& expr, const Object::Ptr& scope); + + static bool HasField(const Object::Ptr& context, const String& field); + static Value GetField(const Object::Ptr& context, const String& field); + static void SetField(const Object::Ptr& context, const String& field, const Value& value); }; I2_CONFIG_API Expression::Ptr MakeLiteral(const Value& lit = Value()); diff --git a/lib/config/objectrule.cpp b/lib/config/objectrule.cpp index de6247a4a..7fc03e3e5 100644 --- a/lib/config/objectrule.cpp +++ b/lib/config/objectrule.cpp @@ -27,7 +27,7 @@ ObjectRule::RuleMap ObjectRule::m_Rules; ObjectRule::CallbackMap ObjectRule::m_Callbacks; ObjectRule::ObjectRule(const String& name, const Expression::Ptr& expression, - const Expression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope) + const Expression::Ptr& filter, const DebugInfo& di, const Object::Ptr& scope) : m_Name(name), m_Expression(expression), m_Filter(filter), m_DebugInfo(di), m_Scope(scope) { } @@ -51,19 +51,19 @@ DebugInfo ObjectRule::GetDebugInfo(void) const return m_DebugInfo; } -Dictionary::Ptr ObjectRule::GetScope(void) const +Object::Ptr ObjectRule::GetScope(void) const { return m_Scope; } void ObjectRule::AddRule(const String& sourceType, const String& name, const Expression::Ptr& expression, const Expression::Ptr& filter, - const DebugInfo& di, const Dictionary::Ptr& scope) + const DebugInfo& di, const Object::Ptr& scope) { m_Rules[sourceType].push_back(ObjectRule(name, expression, filter, di, scope)); } -bool ObjectRule::EvaluateFilter(const Dictionary::Ptr& scope) const +bool ObjectRule::EvaluateFilter(const Object::Ptr& scope) const { return m_Filter->Evaluate(scope); } diff --git a/lib/config/objectrule.hpp b/lib/config/objectrule.hpp index 079a38983..3a0b5637b 100644 --- a/lib/config/objectrule.hpp +++ b/lib/config/objectrule.hpp @@ -42,12 +42,12 @@ public: Expression::Ptr GetExpression(void) const; Expression::Ptr GetFilter(void) const; DebugInfo GetDebugInfo(void) const; - Dictionary::Ptr GetScope(void) const; + Object::Ptr GetScope(void) const; - bool EvaluateFilter(const Dictionary::Ptr& scope) const; + bool EvaluateFilter(const Object::Ptr& scope) const; static void AddRule(const String& sourceType, const String& name, const Expression::Ptr& expression, - const Expression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope); + const Expression::Ptr& filter, const DebugInfo& di, const Object::Ptr& scope); static void EvaluateRules(bool clear); static void RegisterType(const String& sourceType, const ObjectRule::Callback& callback); @@ -58,13 +58,13 @@ private: Expression::Ptr m_Expression; Expression::Ptr m_Filter; DebugInfo m_DebugInfo; - Dictionary::Ptr m_Scope; + Object::Ptr m_Scope; static CallbackMap m_Callbacks; static RuleMap m_Rules; ObjectRule(const String& name, const Expression::Ptr& expression, - const Expression::Ptr& filter, const DebugInfo& di, const Dictionary::Ptr& scope); + const Expression::Ptr& filter, const DebugInfo& di, const Object::Ptr& scope); }; } diff --git a/lib/config/typerule.cpp b/lib/config/typerule.cpp index 4a0c3940f..8020af323 100644 --- a/lib/config/typerule.cpp +++ b/lib/config/typerule.cpp @@ -86,6 +86,9 @@ bool TypeRule::MatchValue(const Value& value, String *hint, const TypeRuleUtilit bool TypeRuleUtilities::ValidateName(const String& type, const String& name, String *hint) const { + if (name.IsEmpty()) + return true; + ConfigItem::Ptr item = ConfigItem::GetObject(type, name); if (!item) { diff --git a/lib/icinga/command.cpp b/lib/icinga/command.cpp index b7d979da2..ab0c72c48 100644 --- a/lib/icinga/command.cpp +++ b/lib/icinga/command.cpp @@ -46,7 +46,7 @@ void Command::SetModifiedAttributes(int flags, const MessageOrigin& origin) void Command::ValidateAttributes(const String& location, const Dictionary::Ptr& attrs) { - if (attrs->Contains("arguments") && !attrs->Get("command").IsObjectType()) { + if (attrs->Get("arguments") != Empty && !attrs->Get("command").IsObjectType()) { ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + location + ": Attribute 'command' must be an array if the 'arguments' attribute is set."); } diff --git a/lib/icinga/dependency-apply.cpp b/lib/icinga/dependency-apply.cpp index 5a2ef9c1a..097f64ebf 100644 --- a/lib/icinga/dependency-apply.cpp +++ b/lib/icinga/dependency-apply.cpp @@ -87,7 +87,6 @@ void Dependency::EvaluateApplyRuleOneInstance(const Checkable::Ptr& checkable, c builder->AddExpression(rule.GetExpression()); ConfigItem::Ptr dependencyItem = builder->Compile(); - dependencyItem->Register(); DynamicObject::Ptr dobj = dependencyItem->Commit(); dobj->OnConfigLoaded(); diff --git a/lib/icinga/dependency.cpp b/lib/icinga/dependency.cpp index 09310e0bc..842d7ec52 100644 --- a/lib/icinga/dependency.cpp +++ b/lib/icinga/dependency.cpp @@ -29,15 +29,17 @@ using namespace icinga; REGISTER_TYPE(Dependency); REGISTER_SCRIPTFUNCTION(ValidateDependencyFilters, &Dependency::ValidateFilters); -String DependencyNameComposer::MakeName(const String& shortName, const Dictionary::Ptr& props) const +String DependencyNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { - if (!props) + Dependency::Ptr dependency = dynamic_pointer_cast(context); + + if (!dependency) return ""; - String name = props->Get("child_host_name"); + String name = dependency->GetChildHostName(); - if (props->Contains("child_service_name")) - name += "!" + props->Get("child_service_name"); + if (!dependency->GetChildServiceName().IsEmpty()) + name += "!" + dependency->GetChildServiceName(); name += "!" + shortName; @@ -205,12 +207,12 @@ void Dependency::ValidateFilters(const String& location, const Dictionary::Ptr& { int sfilter = FilterArrayToInt(attrs->Get("state_filter"), 0); - if (!attrs->Contains("parent_service_name") && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) { + if (attrs->Get("parent_service_name") == Empty && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) { ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + location + ": State filter is invalid for host dependency."); } - if (attrs->Contains("parent_service_name") && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) { + if (attrs->Get("parent_service_name") != Empty && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) { ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + location + ": State filter is invalid for service dependency."); } diff --git a/lib/icinga/dependency.ti b/lib/icinga/dependency.ti index f3b05230e..da27eea03 100644 --- a/lib/icinga/dependency.ti +++ b/lib/icinga/dependency.ti @@ -27,7 +27,7 @@ code {{{ class I2_ICINGA_API DependencyNameComposer : public NameComposer { public: - virtual String MakeName(const String& shortName, const Dictionary::Ptr& props) const; + virtual String MakeName(const String& shortName, const Object::Ptr& context) const; }; }}} diff --git a/lib/icinga/notification-apply.cpp b/lib/icinga/notification-apply.cpp index 3cabfde89..f9765c10b 100644 --- a/lib/icinga/notification-apply.cpp +++ b/lib/icinga/notification-apply.cpp @@ -82,7 +82,6 @@ void Notification::EvaluateApplyRuleOneInstance(const Checkable::Ptr& checkable, builder->AddExpression(rule.GetExpression()); ConfigItem::Ptr notificationItem = builder->Compile(); - notificationItem->Register(); DynamicObject::Ptr dobj = notificationItem->Commit(); dobj->OnConfigLoaded(); diff --git a/lib/icinga/notification.cpp b/lib/icinga/notification.cpp index c7602b688..eefe413d0 100644 --- a/lib/icinga/notification.cpp +++ b/lib/icinga/notification.cpp @@ -39,15 +39,17 @@ INITIALIZE_ONCE(&Notification::StaticInitialize); boost::signals2::signal Notification::OnNextNotificationChanged; -String NotificationNameComposer::MakeName(const String& shortName, const Dictionary::Ptr& props) const +String NotificationNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { - if (!props) + Notification::Ptr notification = dynamic_pointer_cast(context); + + if (!notification) return ""; - String name = props->Get("host_name"); + String name = notification->GetHostName(); - if (props->Contains("service_name")) - name += "!" + props->Get("service_name"); + if (!notification->GetServiceName().IsEmpty()) + name += "!" + notification->GetServiceName(); name += "!" + shortName; @@ -450,12 +452,12 @@ void Notification::ValidateFilters(const String& location, const Dictionary::Ptr { int sfilter = FilterArrayToInt(attrs->Get("states"), 0); - if (!attrs->Contains("service_name") && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) { + if (attrs->Get("service_name") == Empty && (sfilter & ~(StateFilterUp | StateFilterDown)) != 0) { ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + location + ": State filter is invalid."); } - if (attrs->Contains("service_name") && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) { + if (attrs->Get("service_name") != Empty && (sfilter & ~(StateFilterOK | StateFilterWarning | StateFilterCritical | StateFilterUnknown)) != 0) { ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " + location + ": State filter is invalid."); } diff --git a/lib/icinga/notification.ti b/lib/icinga/notification.ti index 2db5f316c..dfe6be4be 100644 --- a/lib/icinga/notification.ti +++ b/lib/icinga/notification.ti @@ -26,7 +26,7 @@ code {{{ class I2_ICINGA_API NotificationNameComposer : public NameComposer { public: - virtual String MakeName(const String& shortName, const Dictionary::Ptr& props) const; + virtual String MakeName(const String& shortName, const Object::Ptr& context) const; }; }}} diff --git a/lib/icinga/scheduleddowntime-apply.cpp b/lib/icinga/scheduleddowntime-apply.cpp index a31710ce9..63fa43b40 100644 --- a/lib/icinga/scheduleddowntime-apply.cpp +++ b/lib/icinga/scheduleddowntime-apply.cpp @@ -81,7 +81,6 @@ void ScheduledDowntime::EvaluateApplyRuleOneInstance(const Checkable::Ptr& check builder->AddExpression(rule.GetExpression()); ConfigItem::Ptr downtimeItem = builder->Compile(); - downtimeItem->Register(); DynamicObject::Ptr dobj = downtimeItem->Commit(); dobj->OnConfigLoaded(); } diff --git a/lib/icinga/scheduleddowntime.cpp b/lib/icinga/scheduleddowntime.cpp index 34f6582f5..b9af506c9 100644 --- a/lib/icinga/scheduleddowntime.cpp +++ b/lib/icinga/scheduleddowntime.cpp @@ -39,15 +39,17 @@ INITIALIZE_ONCE(&ScheduledDowntime::StaticInitialize); static Timer::Ptr l_Timer; -String ScheduledDowntimeNameComposer::MakeName(const String& shortName, const Dictionary::Ptr& props) const +String ScheduledDowntimeNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const { - if (!props) + ScheduledDowntime::Ptr downtime = dynamic_pointer_cast(context); + + if (!downtime) return ""; - String name = props->Get("host_name"); + String name = downtime->GetHostName(); - if (props->Contains("service_name")) - name += "!" + props->Get("service_name"); + if (!downtime->GetServiceName().IsEmpty()) + name += "!" + downtime->GetServiceName(); name += "!" + shortName; diff --git a/lib/icinga/scheduleddowntime.ti b/lib/icinga/scheduleddowntime.ti index f79d47d6a..d463bdfa0 100644 --- a/lib/icinga/scheduleddowntime.ti +++ b/lib/icinga/scheduleddowntime.ti @@ -26,7 +26,7 @@ code {{{ class I2_ICINGA_API ScheduledDowntimeNameComposer : public NameComposer { public: - virtual String MakeName(const String& shortName, const Dictionary::Ptr& props) const; + virtual String MakeName(const String& shortName, const Object::Ptr& context) const; }; }}} diff --git a/lib/icinga/service-apply.cpp b/lib/icinga/service-apply.cpp index 079ddd59a..de9027a24 100644 --- a/lib/icinga/service-apply.cpp +++ b/lib/icinga/service-apply.cpp @@ -74,7 +74,6 @@ void Service::EvaluateApplyRuleOneInstance(const Host::Ptr& host, const String& builder->AddExpression(rule.GetExpression()); ConfigItem::Ptr serviceItem = builder->Compile(); - serviceItem->Register(); DynamicObject::Ptr dobj = serviceItem->Commit(); dobj->OnConfigLoaded(); } diff --git a/lib/icinga/service.cpp b/lib/icinga/service.cpp index ca498f0bf..432405967 100644 --- a/lib/icinga/service.cpp +++ b/lib/icinga/service.cpp @@ -30,11 +30,14 @@ using namespace icinga; REGISTER_TYPE(Service); -String ServiceNameComposer::MakeName(const String& shortName, const Dictionary::Ptr& props) const { - if (!props) +String ServiceNameComposer::MakeName(const String& shortName, const Object::Ptr& context) const +{ + Service::Ptr service = dynamic_pointer_cast(context); + + if (!service) return ""; - return props->Get("host_name") + "!" + shortName; + return service->GetHostName() + "!" + shortName; } void Service::OnConfigLoaded(void) diff --git a/lib/icinga/service.ti b/lib/icinga/service.ti index 3cf29aaa1..a3713009c 100644 --- a/lib/icinga/service.ti +++ b/lib/icinga/service.ti @@ -29,7 +29,7 @@ code {{{ class I2_ICINGA_API ServiceNameComposer : public NameComposer { public: - virtual String MakeName(const String& shortName, const Dictionary::Ptr& props) const; + virtual String MakeName(const String& shortName, const Object::Ptr& context) const; }; }}} diff --git a/tools/mkclass/classcompiler.cpp b/tools/mkclass/classcompiler.cpp index 5387b394f..f2fe69102 100644 --- a/tools/mkclass/classcompiler.cpp +++ b/tools/mkclass/classcompiler.cpp @@ -514,6 +514,12 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&) } } + if (klass.Name == "DynamicObject") + std::cout << "\t" << "friend class ConfigItem;" << std::endl; + + if (!klass.TypeBase.empty()) + std::cout << "\t" << "friend class " << klass.TypeBase << ";" << std::endl; + std::cout << "};" << std::endl << std::endl; }