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. */
if (!hasError)
context.Validate();
context.ValidateItems();
hasError = false;

View File

@ -109,7 +109,18 @@ String ConfigCompilerContext::GetUnit(void) const
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);
@ -137,6 +148,10 @@ void ConfigCompilerContext::ActivateItems(void)
ASSERT(m_Context == NULL);
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) {
item->Commit();
}

View File

@ -69,7 +69,8 @@ public:
String GetUnit(void) const;
void Validate(void);
void LinkItems(void);
void ValidateItems(void);
void ActivateItems(void);
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 std::vector<String>& parents, const DebugInfo& debuginfo)
: 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.
*/
std::vector<String> ConfigItem::GetParents(void) const
std::vector<ConfigItem::Ptr> ConfigItem::GetParents(void) const
{
return m_Parents;
}
Dictionary::Ptr ConfigItem::Link(void) const
{
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
void ConfigItem::Link(void)
{
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;
ConfigCompilerContext *context = ConfigCompilerContext::GetContext();
@ -162,10 +152,22 @@ void ConfigItem::InternalLink(const Dictionary::Ptr& dictionary) const
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);
/* Register this item with its parents. */
BOOST_FOREACH(const String& parentName, m_Parents) {
ConfigItem::Ptr parent = GetObject(m_Type, parentName);
BOOST_FOREACH(const ConfigItem::Ptr& parent, m_Parents) {
parent->m_ChildObjects.insert(self);
}
@ -244,7 +245,10 @@ DynamicObject::Ptr ConfigItem::Commit(void)
double tx = DynamicObject::GetCurrentTx();
Dictionary::Ptr properties = Link();
Link();
Dictionary::Ptr properties = boost::make_shared<Dictionary>();
GetLinkedExpressionList()->Execute(properties);
{
ObjectLock olock(properties);
@ -310,6 +314,20 @@ DynamicObject::Ptr ConfigItem::Commit(void)
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.
*/
@ -341,10 +359,7 @@ void ConfigItem::UnregisterFromParents(void)
{
ASSERT(OwnsLock());
BOOST_FOREACH(const String& parentName, m_Parents) {
ConfigItem::Ptr parent = GetObject(GetType(), parentName);
if (parent)
BOOST_FOREACH(const ConfigItem::Ptr& parent, m_Parents) {
parent->m_ChildObjects.erase(GetSelf());
}
}
@ -414,7 +429,7 @@ void ConfigItem::Dump(std::ostream& fp) const
fp << " inherits";
bool first = true;
BOOST_FOREACH(const String& name, m_Parents) {
BOOST_FOREACH(const String& name, m_ParentNames) {
if (!first)
fp << ",";
else

View File

@ -47,11 +47,15 @@ public:
String GetUnit(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);
void Register(void);
void Unregister(void);
void Dump(std::ostream& fp) const;
@ -60,8 +64,6 @@ public:
DebugInfo GetDebugInfo(void) const;
Dictionary::Ptr Link(void) const;
static ConfigItem::Ptr GetObject(const String& type,
const String& name);
@ -71,7 +73,7 @@ public:
static boost::signals2::signal<void (const ConfigItem::Ptr&)> OnRemoved;
private:
void InternalLink(const Dictionary::Ptr& dictionary) const;
ExpressionList::Ptr GetExpressionList(void) const;
void UnregisterFromParents(void);
@ -83,13 +85,15 @@ private:
bool m_Abstract; /**< Whether this is a template. */
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. */
std::vector<ConfigItem::Ptr> m_Parents;
DebugInfo m_DebugInfo; /**< Debug information. */
ExpressionList::Ptr m_LinkedExpressionList;
DynamicObject::WeakPtr m_DynamicObject; /**< The instantiated version
* of this configuration
* item */
* of this configuration item */
std::set<ConfigItem::WeakPtr> m_ChildObjects; /**< Instantiated items
* that inherit from this item */

View File

@ -110,26 +110,6 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void)
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>();
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
{
Dictionary::Ptr attrs = item->Link();
/* Don't validate abstract items. */
if (item->IsAbstract())
return;
Dictionary::Ptr attrs = boost::make_shared<Dictionary>();
item->GetLinkedExpressionList()->Execute(attrs);
std::vector<String> locations;
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";
}
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
};
class ExpressionList;
/**
* A configuration expression.
*
@ -57,6 +59,8 @@ public:
void Execute(const Dictionary::Ptr& dictionary) const;
void Dump(std::ostream& fp, int indent = 0) const;
void Extract(const std::vector<String>& path, const shared_ptr<ExpressionList>& result) const;
private:
String m_Key;
ExpressionOperator m_Operator;

View File

@ -67,3 +67,10 @@ void ExpressionList::Dump(std::ostream& fp, int indent) const
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;
void Extract(const std::vector<String>& path, const ExpressionList::Ptr& result) const;
private:
std::vector<Expression> m_Expressions;
};