Fix: The order in which config items are defined should not matter

Fixes #3733
This commit is contained in:
Gunnar Beutner 2013-03-19 07:09:06 +01:00
parent 734f76af96
commit 6df051fad3
11 changed files with 111 additions and 65 deletions

View File

@ -71,9 +71,11 @@ static bool LoadConfigFiles(bool validateOnly)
} }
} }
context.LinkItems();
/* Don't validate if we have already encountered at least one error. */ /* Don't validate if we have already encountered at least one error. */
if (!hasError) if (!hasError)
context.Validate(); context.ValidateItems();
hasError = false; hasError = false;

View File

@ -109,7 +109,18 @@ String ConfigCompilerContext::GetUnit(void) const
return m_Unit; return m_Unit;
} }
void ConfigCompilerContext::Validate(void) void ConfigCompilerContext::LinkItems(void)
{
SetContext(this);
BOOST_FOREACH(const ConfigItem::Ptr& item, m_Items) {
item->Link();
}
SetContext(NULL);
}
void ConfigCompilerContext::ValidateItems(void)
{ {
SetContext(this); SetContext(this);
@ -137,6 +148,10 @@ void ConfigCompilerContext::ActivateItems(void)
ASSERT(m_Context == NULL); ASSERT(m_Context == NULL);
Log(LogInformation, "config", "Activating config items in compilation unit '" + m_Unit + "'"); Log(LogInformation, "config", "Activating config items in compilation unit '" + m_Unit + "'");
BOOST_FOREACH(const ConfigItem::Ptr& item, m_Items) {
item->Register();
}
BOOST_FOREACH(const ConfigItem::Ptr& item, m_Items) { BOOST_FOREACH(const ConfigItem::Ptr& item, m_Items) {
item->Commit(); item->Commit();
} }

View File

@ -69,7 +69,8 @@ public:
String GetUnit(void) const; String GetUnit(void) const;
void Validate(void); void LinkItems(void);
void ValidateItems(void);
void ActivateItems(void); void ActivateItems(void);
static void SetContext(ConfigCompilerContext *context); static void SetContext(ConfigCompilerContext *context);

View File

@ -50,7 +50,7 @@ ConfigItem::ConfigItem(const String& type, const String& name,
const String& unit, bool abstract, const ExpressionList::Ptr& exprl, const String& unit, bool abstract, const ExpressionList::Ptr& exprl,
const std::vector<String>& parents, const DebugInfo& debuginfo) const std::vector<String>& parents, const DebugInfo& debuginfo)
: m_Type(type), m_Name(name), m_Unit(unit), m_Abstract(abstract), : m_Type(type), m_Name(name), m_Unit(unit), m_Abstract(abstract),
m_ExpressionList(exprl), m_Parents(parents), m_DebugInfo(debuginfo) m_ExpressionList(exprl), m_ParentNames(parents), m_DebugInfo(debuginfo)
{ {
} }
@ -119,30 +119,20 @@ ExpressionList::Ptr ConfigItem::GetExpressionList(void) const
* *
* @returns The list of parents. * @returns The list of parents.
*/ */
std::vector<String> ConfigItem::GetParents(void) const std::vector<ConfigItem::Ptr> ConfigItem::GetParents(void) const
{ {
return m_Parents; return m_Parents;
} }
Dictionary::Ptr ConfigItem::Link(void) const void ConfigItem::Link(void)
{
Dictionary::Ptr attrs = boost::make_shared<Dictionary>();
InternalLink(attrs);
return attrs;
}
/**
* Calculates the object's properties based on parent objects and the object's
* expression list.
*
* @param dictionary The dictionary that should be used to store the
* properties.
*/
void ConfigItem::InternalLink(const Dictionary::Ptr& dictionary) const
{ {
ObjectLock olock(this); ObjectLock olock(this);
BOOST_FOREACH(const String& name, m_Parents) { m_LinkedExpressionList = boost::make_shared<ExpressionList>();
m_Parents.clear();
BOOST_FOREACH(const String& name, m_ParentNames) {
ConfigItem::Ptr parent; ConfigItem::Ptr parent;
ConfigCompilerContext *context = ConfigCompilerContext::GetContext(); ConfigCompilerContext *context = ConfigCompilerContext::GetContext();
@ -162,10 +152,22 @@ void ConfigItem::InternalLink(const Dictionary::Ptr& dictionary) const
BOOST_THROW_EXCEPTION(std::invalid_argument(message.str())); BOOST_THROW_EXCEPTION(std::invalid_argument(message.str()));
} }
parent->InternalLink(dictionary); parent->Link();
ExpressionList::Ptr pexprl = parent->GetLinkedExpressionList();
m_LinkedExpressionList->AddExpression(Expression("", OperatorExecute, pexprl, m_DebugInfo));
m_Parents.push_back(parent);
} }
m_ExpressionList->Execute(dictionary); m_LinkedExpressionList->AddExpression(Expression("", OperatorExecute, m_ExpressionList, m_DebugInfo));
}
ExpressionList::Ptr ConfigItem::GetLinkedExpressionList(void) const
{
ObjectLock olock(this);
return m_LinkedExpressionList;
} }
/** /**
@ -233,8 +235,7 @@ DynamicObject::Ptr ConfigItem::Commit(void)
dobj = dtype->GetObject(m_Name); dobj = dtype->GetObject(m_Name);
/* Register this item with its parents. */ /* Register this item with its parents. */
BOOST_FOREACH(const String& parentName, m_Parents) { BOOST_FOREACH(const ConfigItem::Ptr& parent, m_Parents) {
ConfigItem::Ptr parent = GetObject(m_Type, parentName);
parent->m_ChildObjects.insert(self); parent->m_ChildObjects.insert(self);
} }
@ -244,7 +245,10 @@ DynamicObject::Ptr ConfigItem::Commit(void)
double tx = DynamicObject::GetCurrentTx(); double tx = DynamicObject::GetCurrentTx();
Dictionary::Ptr properties = Link(); Link();
Dictionary::Ptr properties = boost::make_shared<Dictionary>();
GetLinkedExpressionList()->Execute(properties);
{ {
ObjectLock olock(properties); ObjectLock olock(properties);
@ -310,6 +314,20 @@ DynamicObject::Ptr ConfigItem::Commit(void)
return dobj; return dobj;
} }
/**
* Registers the configuration item.
*/
void ConfigItem::Register(void)
{
ASSERT(!OwnsLock());
{
ObjectLock olock(this);
m_Items[std::make_pair(m_Type, m_Name)] = GetSelf();
}
}
/** /**
* Unregisters the configuration item. * Unregisters the configuration item.
*/ */
@ -341,11 +359,8 @@ void ConfigItem::UnregisterFromParents(void)
{ {
ASSERT(OwnsLock()); ASSERT(OwnsLock());
BOOST_FOREACH(const String& parentName, m_Parents) { BOOST_FOREACH(const ConfigItem::Ptr& parent, m_Parents) {
ConfigItem::Ptr parent = GetObject(GetType(), parentName); parent->m_ChildObjects.erase(GetSelf());
if (parent)
parent->m_ChildObjects.erase(GetSelf());
} }
} }
@ -414,7 +429,7 @@ void ConfigItem::Dump(std::ostream& fp) const
fp << " inherits"; fp << " inherits";
bool first = true; bool first = true;
BOOST_FOREACH(const String& name, m_Parents) { BOOST_FOREACH(const String& name, m_ParentNames) {
if (!first) if (!first)
fp << ","; fp << ",";
else else

View File

@ -47,11 +47,15 @@ public:
String GetUnit(void) const; String GetUnit(void) const;
bool IsAbstract(void) const; bool IsAbstract(void) const;
std::vector<String> GetParents(void) const; std::vector<ConfigItem::Ptr> GetParents(void) const;
ExpressionList::Ptr GetExpressionList(void) const; void Link(void);
ExpressionList::Ptr GetLinkedExpressionList(void) const;
void GetProperties(void);
DynamicObject::Ptr Commit(void); DynamicObject::Ptr Commit(void);
void Register(void);
void Unregister(void); void Unregister(void);
void Dump(std::ostream& fp) const; void Dump(std::ostream& fp) const;
@ -60,8 +64,6 @@ public:
DebugInfo GetDebugInfo(void) const; DebugInfo GetDebugInfo(void) const;
Dictionary::Ptr Link(void) const;
static ConfigItem::Ptr GetObject(const String& type, static ConfigItem::Ptr GetObject(const String& type,
const String& name); const String& name);
@ -71,11 +73,11 @@ public:
static boost::signals2::signal<void (const ConfigItem::Ptr&)> OnRemoved; static boost::signals2::signal<void (const ConfigItem::Ptr&)> OnRemoved;
private: private:
void InternalLink(const Dictionary::Ptr& dictionary) const; ExpressionList::Ptr GetExpressionList(void) const;
void UnregisterFromParents(void); void UnregisterFromParents(void);
void OnParentCommitted(void); void OnParentCommitted(void);
String m_Type; /**< The object type. */ String m_Type; /**< The object type. */
String m_Name; /**< The name. */ String m_Name; /**< The name. */
@ -83,14 +85,16 @@ private:
bool m_Abstract; /**< Whether this is a template. */ bool m_Abstract; /**< Whether this is a template. */
ExpressionList::Ptr m_ExpressionList; ExpressionList::Ptr m_ExpressionList;
std::vector<String> m_Parents; /**< The names of parent configuration std::vector<String> m_ParentNames; /**< The names of parent configuration
items. */ items. */
std::vector<ConfigItem::Ptr> m_Parents;
DebugInfo m_DebugInfo; /**< Debug information. */ DebugInfo m_DebugInfo; /**< Debug information. */
ExpressionList::Ptr m_LinkedExpressionList;
DynamicObject::WeakPtr m_DynamicObject; /**< The instantiated version DynamicObject::WeakPtr m_DynamicObject; /**< The instantiated version
* of this configuration * of this configuration item */
* item */ std::set<ConfigItem::WeakPtr> m_ChildObjects; /**< Instantiated items
std::set<ConfigItem::WeakPtr> m_ChildObjects; /**< Instantiated items
* that inherit from this item */ * that inherit from this item */
static boost::mutex m_Mutex; static boost::mutex m_Mutex;

View File

@ -110,26 +110,6 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void)
BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str())); BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str()));
} }
BOOST_FOREACH(const String& parent, m_Parents) {
ConfigItem::Ptr item;
ConfigCompilerContext *context = ConfigCompilerContext::GetContext();
if (context)
item = context->GetItem(m_Type, parent);
/* ignore already active objects while we're in the compiler
* context and linking to existing items is disabled. */
if (!item && (!context || (context->GetFlags() & CompilerLinkExisting)))
item = ConfigItem::GetObject(m_Type, parent);
if (!item) {
std::ostringstream msgbuf;
msgbuf << "The parent config item '" + parent + "' does not exist: " << m_DebugInfo;
BOOST_THROW_EXCEPTION(std::invalid_argument(msgbuf.str()));
}
}
ExpressionList::Ptr exprl = boost::make_shared<ExpressionList>(); ExpressionList::Ptr exprl = boost::make_shared<ExpressionList>();
Expression execExpr("", OperatorExecute, m_ExpressionList, m_DebugInfo); Expression execExpr("", OperatorExecute, m_ExpressionList, m_DebugInfo);

View File

@ -59,12 +59,13 @@ DebugInfo ConfigType::GetDebugInfo(void) const
void ConfigType::ValidateItem(const ConfigItem::Ptr& item) const void ConfigType::ValidateItem(const ConfigItem::Ptr& item) const
{ {
Dictionary::Ptr attrs = item->Link();
/* Don't validate abstract items. */ /* Don't validate abstract items. */
if (item->IsAbstract()) if (item->IsAbstract())
return; return;
Dictionary::Ptr attrs = boost::make_shared<Dictionary>();
item->GetLinkedExpressionList()->Execute(attrs);
std::vector<String> locations; std::vector<String> locations;
locations.push_back("Object '" + item->GetName() + "' (Type: '" + item->GetType() + "')"); locations.push_back("Object '" + item->GetName() + "' (Type: '" + item->GetType() + "')");

View File

@ -213,3 +213,18 @@ void Expression::Dump(std::ostream& fp, int indent) const
fp << ", " << "\n"; fp << ", " << "\n";
} }
void Expression::Extract(const std::vector<String>& path, const ExpressionList::Ptr& result) const
{
ASSERT(!path.empty());
if (path[0] == m_Key) {
if (path.size() > 1)
BOOST_THROW_EXCEPTION(std::invalid_argument("Specified path does not exist."));
else
result->AddExpression(*this);
} else if (m_Operator == OperatorExecute) {
ExpressionList::Ptr exprl = m_Value;
exprl->Extract(path, result);
}
}

View File

@ -43,6 +43,8 @@ enum ExpressionOperator
OperatorDivide OperatorDivide
}; };
class ExpressionList;
/** /**
* A configuration expression. * A configuration expression.
* *
@ -57,6 +59,8 @@ public:
void Execute(const Dictionary::Ptr& dictionary) const; void Execute(const Dictionary::Ptr& dictionary) const;
void Dump(std::ostream& fp, int indent = 0) const; void Dump(std::ostream& fp, int indent = 0) const;
void Extract(const std::vector<String>& path, const shared_ptr<ExpressionList>& result) const;
private: private:
String m_Key; String m_Key;
ExpressionOperator m_Operator; ExpressionOperator m_Operator;

View File

@ -67,3 +67,10 @@ void ExpressionList::Dump(std::ostream& fp, int indent) const
expression.Dump(fp, indent); expression.Dump(fp, indent);
} }
} }
void ExpressionList::Extract(const std::vector<String>& path, const ExpressionList::Ptr& result) const
{
BOOST_FOREACH(const Expression& expression, m_Expressions) {
expression.Extract(path, result);
}
}

View File

@ -46,6 +46,8 @@ public:
size_t GetLength(void) const; size_t GetLength(void) const;
void Extract(const std::vector<String>& path, const ExpressionList::Ptr& result) const;
private: private:
std::vector<Expression> m_Expressions; std::vector<Expression> m_Expressions;
}; };