/* Icinga 2 | (c) 2012 Icinga GmbH | GPLv2+ */ #include "base/namespace.hpp" #include "base/objectlock.hpp" #include "base/debug.hpp" #include "base/primitivetype.hpp" #include "base/debuginfo.hpp" #include "base/exception.hpp" #include using namespace icinga; template class std::map >; REGISTER_PRIMITIVE_TYPE(Namespace, Object, Namespace::GetPrototype()); /** * Creates a new namespace. * * @param constValues If true, all values inserted into the namespace are treated as constants and can't be updated. */ Namespace::Namespace(bool constValues) : m_ConstValues(constValues), m_Frozen(false) { } Value Namespace::Get(const String& field) const { ObjectLock olock(this); Value value; if (!GetOwnField(field, &value)) BOOST_THROW_EXCEPTION(ScriptError("Namespace does not contain field '" + field + "'")); return value; } bool Namespace::Get(const String& field, Value *value) const { ObjectLock olock(this); auto nsVal = GetAttribute(field); if (!nsVal) return false; *value = nsVal->Get(DebugInfo()); return true; } void Namespace::Set(const String& field, const Value& value, bool overrideFrozen) { ObjectLock olock(this); return SetFieldByName(field, value, overrideFrozen, DebugInfo()); } /** * Returns the number of elements in the namespace. * * @returns Number of elements. */ size_t Namespace::GetLength() const { ObjectLock olock(this); return m_Data.size(); } bool Namespace::Contains(const String& field) const { ObjectLock olock(this); return HasOwnField(field); } void Namespace::Remove(const String& field, bool overrideFrozen) { ObjectLock olock(this); if (m_Frozen && !overrideFrozen) { BOOST_THROW_EXCEPTION(ScriptError("Namespace is read-only and must not be modified.")); } if (!overrideFrozen) { auto attr = GetAttribute(field); if (dynamic_pointer_cast(attr)) { BOOST_THROW_EXCEPTION(ScriptError("Constants must not be removed.")); } } RemoveAttribute(field); } /** * Freeze the namespace, preventing further updates unless overrideFrozen is set. * * This only prevents inserting, replacing or deleting values from the namespace. This operation has no effect on * objects referenced by the values, these remain mutable if they were before. */ void Namespace::Freeze() { ObjectLock olock(this); m_Frozen = true; } void Namespace::RemoveAttribute(const String& field) { ObjectLock olock(this); Namespace::Iterator it; it = m_Data.find(field); if (it == m_Data.end()) return; m_Data.erase(it); } NamespaceValue::Ptr Namespace::GetAttribute(const String& key) const { ObjectLock olock(this); auto it = m_Data.find(key); if (it == m_Data.end()) return nullptr; return it->second; } void Namespace::SetAttribute(const String& key, const NamespaceValue::Ptr& nsVal) { ObjectLock olock(this); m_Data[key] = nsVal; } Value Namespace::GetFieldByName(const String& field, bool, const DebugInfo& debugInfo) const { ObjectLock olock(this); auto nsVal = GetAttribute(field); if (nsVal) return nsVal->Get(debugInfo); else return GetPrototypeField(const_cast(this), field, false, debugInfo); /* Ignore indexer not found errors similar to the Dictionary class. */ } void Namespace::SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) { ObjectLock olock(this); auto nsVal = GetAttribute(field); if (!nsVal) { if (m_Frozen && !overrideFrozen) { BOOST_THROW_EXCEPTION(ScriptError("Namespace is read-only and must not be modified.", debugInfo)); } if (m_ConstValues) { SetAttribute(field, new ConstEmbeddedNamespaceValue(value)); } else { SetAttribute(field, new EmbeddedNamespaceValue(value)); } } else { nsVal->Set(value, overrideFrozen, debugInfo); } } bool Namespace::HasOwnField(const String& field) const { ObjectLock olock(this); return GetAttribute(field) != nullptr; } bool Namespace::GetOwnField(const String& field, Value *result) const { ObjectLock olock(this); auto nsVal = GetAttribute(field); if (!nsVal) return false; *result = nsVal->Get(DebugInfo()); return true; } EmbeddedNamespaceValue::EmbeddedNamespaceValue(const Value& value) : m_Value(value) { } Value EmbeddedNamespaceValue::Get(const DebugInfo& debugInfo) const { return m_Value; } void EmbeddedNamespaceValue::Set(const Value& value, bool, const DebugInfo&) { m_Value = value; } void ConstEmbeddedNamespaceValue::Set(const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) { if (!overrideFrozen) BOOST_THROW_EXCEPTION(ScriptError("Constant must not be modified.", debugInfo)); EmbeddedNamespaceValue::Set(value, overrideFrozen, debugInfo); } Namespace::Iterator Namespace::Begin() { ASSERT(OwnsLock()); return m_Data.begin(); } Namespace::Iterator Namespace::End() { ASSERT(OwnsLock()); return m_Data.end(); } Namespace::Iterator icinga::begin(const Namespace::Ptr& x) { return x->Begin(); } Namespace::Iterator icinga::end(const Namespace::Ptr& x) { return x->End(); }