Merge pull request #9603 from Icinga/remove-namespace-behavior

Namespace: replace behavior classes with a bool
This commit is contained in:
Julian Brost 2023-01-18 15:48:34 +01:00 committed by GitHub
commit c019f8c04a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 65 additions and 87 deletions

View File

@ -15,14 +15,13 @@ static String JsonEncodeShim(const Value& value)
} }
INITIALIZE_ONCE([]() { INITIALIZE_ONCE([]() {
auto jsonNSBehavior = new ConstNamespaceBehavior(); Namespace::Ptr jsonNS = new Namespace(true);
Namespace::Ptr jsonNS = new Namespace(jsonNSBehavior);
/* Methods */ /* Methods */
jsonNS->Set("encode", new Function("Json#encode", JsonEncodeShim, { "value" }, true)); jsonNS->Set("encode", new Function("Json#encode", JsonEncodeShim, { "value" }, true));
jsonNS->Set("decode", new Function("Json#decode", JsonDecode, { "value" }, true)); jsonNS->Set("decode", new Function("Json#decode", JsonDecode, { "value" }, true));
jsonNSBehavior->Freeze(); jsonNS->Freeze();
Namespace::Ptr systemNS = ScriptGlobal::Get("System"); Namespace::Ptr systemNS = ScriptGlobal::Get("System");
systemNS->SetAttribute("Json", new ConstEmbeddedNamespaceValue(jsonNS)); systemNS->SetAttribute("Json", new ConstEmbeddedNamespaceValue(jsonNS));

View File

@ -142,8 +142,7 @@ static double MathSign(double x)
} }
INITIALIZE_ONCE([]() { INITIALIZE_ONCE([]() {
auto mathNSBehavior = new ConstNamespaceBehavior(); Namespace::Ptr mathNS = new Namespace(true);
Namespace::Ptr mathNS = new Namespace(mathNSBehavior);
/* Constants */ /* Constants */
mathNS->Set("E", 2.71828182845904523536); mathNS->Set("E", 2.71828182845904523536);
@ -178,7 +177,7 @@ INITIALIZE_ONCE([]() {
mathNS->Set("isinf", new Function("Math#isinf", MathIsinf, { "x" }, true)); mathNS->Set("isinf", new Function("Math#isinf", MathIsinf, { "x" }, true));
mathNS->Set("sign", new Function("Math#sign", MathSign, { "x" }, true)); mathNS->Set("sign", new Function("Math#sign", MathSign, { "x" }, true));
mathNSBehavior->Freeze(); mathNS->Freeze();
Namespace::Ptr systemNS = ScriptGlobal::Get("System"); Namespace::Ptr systemNS = ScriptGlobal::Get("System");
systemNS->SetAttribute("Math", new ConstEmbeddedNamespaceValue(mathNS)); systemNS->SetAttribute("Math", new ConstEmbeddedNamespaceValue(mathNS));

View File

@ -14,8 +14,13 @@ template class std::map<icinga::String, std::shared_ptr<icinga::NamespaceValue>
REGISTER_PRIMITIVE_TYPE(Namespace, Object, Namespace::GetPrototype()); REGISTER_PRIMITIVE_TYPE(Namespace, Object, Namespace::GetPrototype());
Namespace::Namespace(NamespaceBehavior *behavior) /**
: m_Behavior(std::unique_ptr<NamespaceBehavior>(behavior)) * 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 Value Namespace::Get(const String& field) const
@ -71,7 +76,31 @@ void Namespace::Remove(const String& field, bool overrideFrozen)
{ {
ObjectLock olock(this); ObjectLock olock(this);
m_Behavior->Remove(this, field, overrideFrozen); 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<ConstEmbeddedNamespaceValue>(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) void Namespace::RemoveAttribute(const String& field)
@ -124,10 +153,19 @@ void Namespace::SetFieldByName(const String& field, const Value& value, bool ove
auto nsVal = GetAttribute(field); auto nsVal = GetAttribute(field);
if (!nsVal) if (!nsVal) {
m_Behavior->Register(this, field, value, overrideFrozen, debugInfo); if (m_Frozen && !overrideFrozen) {
else 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); nsVal->Set(value, overrideFrozen, debugInfo);
}
} }
bool Namespace::HasOwnField(const String& field) const bool Namespace::HasOwnField(const String& field) const
@ -172,44 +210,6 @@ void ConstEmbeddedNamespaceValue::Set(const Value& value, bool overrideFrozen, c
EmbeddedNamespaceValue::Set(value, overrideFrozen, debugInfo); EmbeddedNamespaceValue::Set(value, overrideFrozen, debugInfo);
} }
void NamespaceBehavior::Register(const Namespace::Ptr& ns, const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) const
{
ns->SetAttribute(field, new EmbeddedNamespaceValue(value));
}
void NamespaceBehavior::Remove(const Namespace::Ptr& ns, const String& field, bool overrideFrozen)
{
if (!overrideFrozen) {
auto attr = ns->GetAttribute(field);
if (dynamic_pointer_cast<ConstEmbeddedNamespaceValue>(attr))
BOOST_THROW_EXCEPTION(ScriptError("Constants must not be removed."));
}
ns->RemoveAttribute(field);
}
void ConstNamespaceBehavior::Register(const Namespace::Ptr& ns, const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) const
{
if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(ScriptError("Namespace is read-only and must not be modified.", debugInfo));
ns->SetAttribute(field, new ConstEmbeddedNamespaceValue(value));
}
void ConstNamespaceBehavior::Remove(const Namespace::Ptr& ns, const String& field, bool overrideFrozen)
{
if (m_Frozen && !overrideFrozen)
BOOST_THROW_EXCEPTION(ScriptError("Namespace is read-only and must not be modified."));
NamespaceBehavior::Remove(ns, field, overrideFrozen);
}
void ConstNamespaceBehavior::Freeze()
{
m_Frozen = true;
}
Namespace::Iterator Namespace::Begin() Namespace::Iterator Namespace::Begin()
{ {
ASSERT(OwnsLock()); ASSERT(OwnsLock());

View File

@ -41,24 +41,6 @@ struct ConstEmbeddedNamespaceValue : public EmbeddedNamespaceValue
void Set(const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) override; void Set(const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) override;
}; };
class Namespace;
struct NamespaceBehavior
{
virtual void Register(const boost::intrusive_ptr<Namespace>& ns, const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) const;
virtual void Remove(const boost::intrusive_ptr<Namespace>& ns, const String& field, bool overrideFrozen);
};
struct ConstNamespaceBehavior : public NamespaceBehavior
{
void Register(const boost::intrusive_ptr<Namespace>& ns, const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) const override;
void Remove(const boost::intrusive_ptr<Namespace>& ns, const String& field, bool overrideFrozen) override;
void Freeze();
private:
bool m_Frozen;
};
/** /**
* A namespace. * A namespace.
* *
@ -73,13 +55,14 @@ public:
typedef std::map<String, NamespaceValue::Ptr>::value_type Pair; typedef std::map<String, NamespaceValue::Ptr>::value_type Pair;
Namespace(NamespaceBehavior *behavior = new NamespaceBehavior); explicit Namespace(bool constValues = false);
Value Get(const String& field) const; Value Get(const String& field) const;
bool Get(const String& field, Value *value) const; bool Get(const String& field, Value *value) const;
void Set(const String& field, const Value& value, bool overrideFrozen = false); void Set(const String& field, const Value& value, bool overrideFrozen = false);
bool Contains(const String& field) const; bool Contains(const String& field) const;
void Remove(const String& field, bool overrideFrozen = false); void Remove(const String& field, bool overrideFrozen = false);
void Freeze();
NamespaceValue::Ptr GetAttribute(const String& field) const; NamespaceValue::Ptr GetAttribute(const String& field) const;
void SetAttribute(const String& field, const NamespaceValue::Ptr& nsVal); void SetAttribute(const String& field, const NamespaceValue::Ptr& nsVal);
@ -99,7 +82,8 @@ public:
private: private:
std::map<String, NamespaceValue::Ptr> m_Data; std::map<String, NamespaceValue::Ptr> m_Data;
std::unique_ptr<NamespaceBehavior> m_Behavior; bool m_ConstValues;
bool m_Frozen;
}; };
Namespace::Iterator begin(const Namespace::Ptr& x); Namespace::Iterator begin(const Namespace::Ptr& x);

View File

@ -10,7 +10,7 @@ using namespace icinga;
boost::thread_specific_ptr<std::stack<ScriptFrame *> > ScriptFrame::m_ScriptFrames; boost::thread_specific_ptr<std::stack<ScriptFrame *> > ScriptFrame::m_ScriptFrames;
static auto l_InternalNSBehavior = new ConstNamespaceBehavior(); static Namespace::Ptr l_InternalNS;
/* Ensure that this gets called with highest priority /* Ensure that this gets called with highest priority
* and wins against other static initializers in lib/icinga, etc. * and wins against other static initializers in lib/icinga, etc.
@ -19,29 +19,26 @@ static auto l_InternalNSBehavior = new ConstNamespaceBehavior();
INITIALIZE_ONCE_WITH_PRIORITY([]() { INITIALIZE_ONCE_WITH_PRIORITY([]() {
Namespace::Ptr globalNS = ScriptGlobal::GetGlobals(); Namespace::Ptr globalNS = ScriptGlobal::GetGlobals();
auto systemNSBehavior = new ConstNamespaceBehavior(); Namespace::Ptr systemNS = new Namespace(true);
systemNSBehavior->Freeze(); systemNS->Freeze();
Namespace::Ptr systemNS = new Namespace(systemNSBehavior);
globalNS->SetAttribute("System", new ConstEmbeddedNamespaceValue(systemNS)); globalNS->SetAttribute("System", new ConstEmbeddedNamespaceValue(systemNS));
systemNS->SetAttribute("Configuration", new EmbeddedNamespaceValue(new Configuration())); systemNS->SetAttribute("Configuration", new EmbeddedNamespaceValue(new Configuration()));
auto typesNSBehavior = new ConstNamespaceBehavior(); Namespace::Ptr typesNS = new Namespace(true);
typesNSBehavior->Freeze(); typesNS->Freeze();
Namespace::Ptr typesNS = new Namespace(typesNSBehavior);
globalNS->SetAttribute("Types", new ConstEmbeddedNamespaceValue(typesNS)); globalNS->SetAttribute("Types", new ConstEmbeddedNamespaceValue(typesNS));
auto statsNSBehavior = new ConstNamespaceBehavior(); Namespace::Ptr statsNS = new Namespace(true);
statsNSBehavior->Freeze(); statsNS->Freeze();
Namespace::Ptr statsNS = new Namespace(statsNSBehavior);
globalNS->SetAttribute("StatsFunctions", new ConstEmbeddedNamespaceValue(statsNS)); globalNS->SetAttribute("StatsFunctions", new ConstEmbeddedNamespaceValue(statsNS));
Namespace::Ptr internalNS = new Namespace(l_InternalNSBehavior); l_InternalNS = new Namespace(true);
globalNS->SetAttribute("Internal", new ConstEmbeddedNamespaceValue(internalNS)); globalNS->SetAttribute("Internal", new ConstEmbeddedNamespaceValue(l_InternalNS));
}, 1000); }, 1000);
INITIALIZE_ONCE_WITH_PRIORITY([]() { INITIALIZE_ONCE_WITH_PRIORITY([]() {
l_InternalNSBehavior->Freeze(); l_InternalNS->Freeze();
}, 0); }, 0);
ScriptFrame::ScriptFrame(bool allocLocals) ScriptFrame::ScriptFrame(bool allocLocals)

View File

@ -930,7 +930,7 @@ ExpressionResult ApplyExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhin
ExpressionResult NamespaceExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const ExpressionResult NamespaceExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const
{ {
Namespace::Ptr ns = new Namespace(new ConstNamespaceBehavior()); Namespace::Ptr ns = new Namespace(true);
ScriptFrame innerFrame(true, ns); ScriptFrame innerFrame(true, ns);
ExpressionResult result = m_Expression->Evaluate(innerFrame); ExpressionResult result = m_Expression->Evaluate(innerFrame);

View File

@ -58,9 +58,8 @@ void IcingaApplication::StaticInitialize()
Namespace::Ptr globalNS = ScriptGlobal::GetGlobals(); Namespace::Ptr globalNS = ScriptGlobal::GetGlobals();
VERIFY(globalNS); VERIFY(globalNS);
auto icingaNSBehavior = new ConstNamespaceBehavior(); Namespace::Ptr icingaNS = new Namespace(true);
icingaNSBehavior->Freeze(); icingaNS->Freeze();
Namespace::Ptr icingaNS = new Namespace(icingaNSBehavior);
globalNS->SetAttribute("Icinga", new ConstEmbeddedNamespaceValue(icingaNS)); globalNS->SetAttribute("Icinga", new ConstEmbeddedNamespaceValue(icingaNS));
} }