Improve config compiler's memory usage

This commit is contained in:
Gunnar Beutner 2014-11-06 19:35:47 +01:00 committed by Gunnar Beutner
parent 85a380c443
commit e1c95d4fa0
33 changed files with 442 additions and 396 deletions

View File

@ -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 {{{

View File

@ -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<DynamicObject>(object);
}
boost::mutex& DynamicType::GetStaticMutex(void)
{
static boost::mutex mutex;

View File

@ -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);

View File

@ -97,6 +97,9 @@ public:
if (IsEmpty())
return shared_ptr<T>();
if (!IsObject())
BOOST_THROW_EXCEPTION(std::runtime_error("Cannot convert value to object."));
Object::Ptr object = boost::get<Object::Ptr>(m_Value);
ASSERT(object);

View File

@ -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<std::vector<std::string> >()) {
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;

View File

@ -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);
}

View File

@ -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<String>& 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);
};
}

View File

@ -19,7 +19,10 @@
#include "config/configcompilercontext.hpp"
#include "base/singleton.hpp"
#include "base/json.hpp"
#include "base/netstring.hpp"
#include <boost/foreach.hpp>
#include <fstream>
using namespace icinga;
@ -61,3 +64,50 @@ ConfigCompilerContext *ConfigCompilerContext::GetInstance(void)
return Singleton<ConfigCompilerContext>::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<StdioStream>(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));
}
}

View File

@ -22,6 +22,8 @@
#include "config/i2-config.hpp"
#include "base/debuginfo.hpp"
#include "base/stdiostream.hpp"
#include "base/dictionary.hpp"
#include <boost/thread/mutex.hpp>
#include <vector>
@ -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<ConfigCompilerMessage> m_Messages;
String m_ObjectsPath;
StdioStream::Ptr m_ObjectsFP;
mutable boost::mutex m_Mutex;
};

View File

@ -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 <sstream>
@ -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<Dictionary>();
locals->Set("__parent", m_Scope);
locals->Set("name", m_Name);
m_Properties = make_shared<Dictionary>();
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<NameComposer> nc = dynamic_pointer_cast<NameComposer>(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<DynamicObject>(type->Instantiate());
dobj->SetDebugInfo(m_DebugInfo);
dobj->SetTypeName(m_Type);
dobj->SetZone(m_Zone);
Dictionary::Ptr locals = make_shared<Dictionary>();
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<errinfo_debuginfo>(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<NameComposer> nc = dynamic_pointer_cast<NameComposer>(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<Dictionary>();
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<errinfo_debuginfo>(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<NameComposer> nc = dynamic_pointer_cast<NameComposer>(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<String, String> 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<errinfo_debuginfo>(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<StdioStream>(&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<Dictionary>();
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();

View File

@ -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<ConfigItem::Ptr> 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<String> 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;

View File

@ -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;
}

View File

@ -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. */
};

View File

@ -33,6 +33,7 @@
#include "base/configerror.hpp"
#include <boost/foreach.hpp>
#include <boost/exception_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/exception/errinfo_nested_exception.hpp>
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<boost::errinfo_nested_exception>(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<Expression::Ptr>(m_Operand1)->Evaluate(locals, dhint);
return static_cast<Expression::Ptr>(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<Expression::Ptr>(m_Operand2)->Evaluate(locals, dhint);
return static_cast<Expression::Ptr>(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<Array>())
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<Value> 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<Array>();
@ -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<Dictionary>();
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>(&Expression::OpLiteral, tempindex, expr->m_DebugInfo);
Expression::Ptr eip = make_shared<Expression>(&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>();
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>(&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>()) {
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<Value>& arguments, const Array::Ptr& funcargs, const Expression::Ptr& expr, const Dictionary::Ptr& scope)
Value Expression::FunctionWrapper(const std::vector<Value>& 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<Dictionary>();
locals->Set("__parent", scope);
Dictionary::Ptr context = make_shared<Dictionary>();
context->Set("__parent", scope);
for (std::vector<Value>::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<ScriptFunction>(boost::bind(&Expression::FunctionWrapper, _1, funcargs, aexpr, locals));
ScriptFunction::Ptr func = make_shared<ScriptFunction>(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<ConfigItemBuilder>(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<Array>()) {
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<Dictionary>();
xlocals->Set("__parent", locals);
xlocals->Set(kvar, value);
Dictionary::Ptr xcontext = make_shared<Dictionary>();
xcontext->Set("__parent", context);
xcontext->Set(kvar, value);
ascope->Evaluate(xlocals, dhint);
ascope->Evaluate(xcontext, dhint);
}
} else if (value.IsObjectType<Dictionary>()) {
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<Dictionary>();
xlocals->Set("__parent", locals);
xlocals->Set(kvar, kv.first);
xlocals->Set(vvar, kv.second);
Dictionary::Ptr xcontext = make_shared<Dictionary>();
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>(&Expression::OpLiteral, lit, DebugInfo());
}
bool Expression::HasField(const Object::Ptr& context, const String& field)
{
Dictionary::Ptr dict = dynamic_pointer_cast<Dictionary>(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<Dictionary>(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<Dictionary>(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() + "'"));
}
}
}

View File

@ -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<Value>& 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());

View File

@ -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);
}

View File

@ -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);
};
}

View File

@ -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) {

View File

@ -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<Array>()) {
if (attrs->Get("arguments") != Empty && !attrs->Get("command").IsObjectType<Array>()) {
ConfigCompilerContext::GetInstance()->AddMessage(true, "Validation failed for " +
location + ": Attribute 'command' must be an array if the 'arguments' attribute is set.");
}

View File

@ -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();

View File

@ -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<Dependency>(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.");
}

View File

@ -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;
};
}}}

View File

@ -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();

View File

@ -39,15 +39,17 @@ INITIALIZE_ONCE(&Notification::StaticInitialize);
boost::signals2::signal<void (const Notification::Ptr&, double, const MessageOrigin&)> 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<Notification>(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.");
}

View File

@ -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;
};
}}}

View File

@ -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();
}

View File

@ -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<ScheduledDowntime>(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;

View File

@ -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;
};
}}}

View File

@ -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();
}

View File

@ -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<Service>(context);
if (!service)
return "";
return props->Get("host_name") + "!" + shortName;
return service->GetHostName() + "!" + shortName;
}
void Service::OnConfigLoaded(void)

View File

@ -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;
};
}}}

View File

@ -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;
}