config-store, core: (fixes #1091) Fix handling of deprecated and obsolete attributes
See also discussion in merge request !2109
This commit is contained in:
committed by
Tom Henderson
parent
67f958d52f
commit
8d4e8f60c9
@@ -220,8 +220,13 @@ AttributeIterator::DoIterate(Ptr<Object> object)
|
||||
if (ptrChecker != nullptr)
|
||||
{
|
||||
NS_LOG_DEBUG("pointer attribute " << info.name);
|
||||
if (info.supportLevel == TypeId::DEPRECATED ||
|
||||
info.supportLevel == TypeId::OBSOLETE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
PointerValue ptr;
|
||||
object->GetAttribute(info.name, ptr);
|
||||
object->GetAttribute(info.name, ptr, true);
|
||||
Ptr<Object> tmp = ptr.Get<Object>();
|
||||
if (tmp)
|
||||
{
|
||||
@@ -240,7 +245,7 @@ AttributeIterator::DoIterate(Ptr<Object> object)
|
||||
{
|
||||
NS_LOG_DEBUG("ObjectPtrContainer attribute " << info.name);
|
||||
ObjectPtrContainerValue vector;
|
||||
object->GetAttribute(info.name, vector);
|
||||
object->GetAttribute(info.name, vector, true);
|
||||
StartVisitArrayAttribute(object, info.name, vector);
|
||||
ObjectPtrContainerValue::Iterator it;
|
||||
for (it = vector.Begin(); it != vector.End(); ++it)
|
||||
|
||||
@@ -63,11 +63,15 @@ ConfigStore::GetTypeId()
|
||||
EnumValue(ConfigStore::RAW_TEXT),
|
||||
MakeEnumAccessor<FileFormat>(&ConfigStore::SetFileFormat),
|
||||
MakeEnumChecker(ConfigStore::RAW_TEXT, "RawText", ConfigStore::XML, "Xml"))
|
||||
.AddAttribute("SaveDeprecated",
|
||||
"Save DEPRECATED attributes",
|
||||
BooleanValue(true),
|
||||
MakeBooleanAccessor(&ConfigStore::SetSaveDeprecated),
|
||||
MakeBooleanChecker());
|
||||
.AddAttribute(
|
||||
"SaveDeprecated",
|
||||
"Save DEPRECATED attributes",
|
||||
BooleanValue(true),
|
||||
MakeBooleanAccessor(&ConfigStore::SetSaveDeprecated),
|
||||
MakeBooleanChecker(),
|
||||
TypeId::OBSOLETE,
|
||||
"OBSOLETE since ns-3.43 as it is no longer needed; deprecated attributes are saved "
|
||||
"only if their value differs from their respective original initial value");
|
||||
return tid;
|
||||
}
|
||||
|
||||
@@ -129,8 +133,6 @@ ConfigStore::ConfigStore()
|
||||
}
|
||||
}
|
||||
m_file->SetFilename(m_filename);
|
||||
m_file->SetSaveDeprecated(m_saveDeprecated);
|
||||
|
||||
NS_LOG_FUNCTION(this << ": format: " << m_fileFormat << ", mode: " << m_mode
|
||||
<< ", file name: " << m_filename);
|
||||
}
|
||||
|
||||
@@ -15,12 +15,6 @@ FileConfig::~FileConfig()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FileConfig::SetSaveDeprecated(bool saveDeprecated)
|
||||
{
|
||||
m_saveDeprecated = saveDeprecated;
|
||||
}
|
||||
|
||||
NoneFileConfig::NoneFileConfig()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -28,11 +28,6 @@ class FileConfig
|
||||
* \param filename the filename
|
||||
*/
|
||||
virtual void SetFilename(std::string filename) = 0;
|
||||
/**
|
||||
* Set if to save deprecated attributes
|
||||
* \param saveDeprecated the deprecated attributes save policy
|
||||
*/
|
||||
void SetSaveDeprecated(bool saveDeprecated);
|
||||
/**
|
||||
* Load or save the default values
|
||||
*/
|
||||
@@ -45,9 +40,6 @@ class FileConfig
|
||||
* Load or save the attributes values
|
||||
*/
|
||||
virtual void Attributes() = 0;
|
||||
|
||||
protected:
|
||||
bool m_saveDeprecated; ///< save deprecated attributes
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,11 +64,6 @@ RawTextConfigSave::Default()
|
||||
m_os = os;
|
||||
}
|
||||
|
||||
void SetSaveDeprecated(bool saveDeprecated)
|
||||
{
|
||||
m_saveDeprecated = saveDeprecated;
|
||||
}
|
||||
|
||||
private:
|
||||
void StartVisitTypeId(std::string name) override
|
||||
{
|
||||
@@ -80,39 +75,49 @@ RawTextConfigSave::Default()
|
||||
NS_LOG_DEBUG("Saving " << m_typeId << "::" << name);
|
||||
TypeId tid = TypeId::LookupByName(m_typeId);
|
||||
ns3::TypeId::SupportLevel supportLevel = TypeId::SupportLevel::SUPPORTED;
|
||||
std::string originalInitialValue;
|
||||
std::string valueTypeName;
|
||||
for (std::size_t i = 0; i < tid.GetAttributeN(); i++)
|
||||
{
|
||||
TypeId::AttributeInformation tmp = tid.GetAttribute(i);
|
||||
if (tmp.name == name)
|
||||
{
|
||||
supportLevel = tmp.supportLevel;
|
||||
originalInitialValue = tmp.originalInitialValue->SerializeToString(tmp.checker);
|
||||
valueTypeName = tmp.checker->GetValueTypeName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valueTypeName == "ns3::CallbackValue")
|
||||
{
|
||||
NS_LOG_WARN("Global attribute " << m_typeId << "::" << name
|
||||
<< " was not saved because it is a CallbackValue");
|
||||
return;
|
||||
}
|
||||
if (supportLevel == TypeId::SupportLevel::OBSOLETE)
|
||||
{
|
||||
NS_LOG_WARN("Global attribute " << m_typeId << "::" << name
|
||||
<< " was not saved because it is OBSOLETE");
|
||||
return;
|
||||
}
|
||||
else if (supportLevel == TypeId::SupportLevel::DEPRECATED && !m_saveDeprecated)
|
||||
if (supportLevel == TypeId::SupportLevel::DEPRECATED &&
|
||||
defaultValue == originalInitialValue)
|
||||
{
|
||||
NS_LOG_WARN("Global attribute " << m_typeId << "::" << name
|
||||
<< " was not saved because it is DEPRECATED");
|
||||
}
|
||||
else
|
||||
{
|
||||
*m_os << "default " << m_typeId << "::" << name << " \"" << defaultValue << "\""
|
||||
<< std::endl;
|
||||
NS_LOG_WARN("Global attribute "
|
||||
<< m_typeId << "::" << name
|
||||
<< " was not saved because it is DEPRECATED and its value has not "
|
||||
"changed from the original initial value");
|
||||
return;
|
||||
}
|
||||
*m_os << "default " << m_typeId << "::" << name << " \"" << defaultValue << "\""
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
std::string m_typeId;
|
||||
std::ostream* m_os;
|
||||
bool m_saveDeprecated;
|
||||
};
|
||||
|
||||
RawTextDefaultIterator iterator = RawTextDefaultIterator(m_os);
|
||||
iterator.SetSaveDeprecated(m_saveDeprecated);
|
||||
iterator.Iterate();
|
||||
}
|
||||
|
||||
@@ -142,52 +147,52 @@ RawTextConfigSave::Attributes()
|
||||
{
|
||||
}
|
||||
|
||||
void SetSaveDeprecated(bool saveDeprecated)
|
||||
{
|
||||
m_saveDeprecated = saveDeprecated;
|
||||
}
|
||||
|
||||
private:
|
||||
void DoVisitAttribute(Ptr<Object> object, std::string name) override
|
||||
{
|
||||
StringValue str;
|
||||
|
||||
ns3::TypeId::SupportLevel supportLevel = TypeId::SupportLevel::SUPPORTED;
|
||||
TypeId tid = object->GetInstanceTypeId();
|
||||
|
||||
for (std::size_t i = 0; i < tid.GetAttributeN(); i++)
|
||||
auto [found, inTid, attr] = TypeId::FindAttribute(tid, name);
|
||||
|
||||
if (found)
|
||||
{
|
||||
TypeId::AttributeInformation tmp = tid.GetAttribute(i);
|
||||
if (tmp.name == name)
|
||||
if (attr.checker && attr.checker->GetValueTypeName() == "ns3::CallbackValue")
|
||||
{
|
||||
supportLevel = tmp.supportLevel;
|
||||
break;
|
||||
NS_LOG_WARN("Attribute " << GetCurrentPath()
|
||||
<< " was not saved because it is a CallbackValue");
|
||||
return;
|
||||
}
|
||||
auto supportLevel = attr.supportLevel;
|
||||
if (supportLevel == TypeId::SupportLevel::OBSOLETE)
|
||||
{
|
||||
NS_LOG_WARN("Attribute " << GetCurrentPath()
|
||||
<< " was not saved because it is OBSOLETE");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string originalInitialValue =
|
||||
attr.originalInitialValue->SerializeToString(attr.checker);
|
||||
object->GetAttribute(name, str, true);
|
||||
|
||||
if (supportLevel == TypeId::SupportLevel::DEPRECATED &&
|
||||
str.Get() == originalInitialValue)
|
||||
{
|
||||
NS_LOG_WARN("Attribute "
|
||||
<< GetCurrentPath()
|
||||
<< " was not saved because it is DEPRECATED and its value has not "
|
||||
"changed from the original initial value");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (supportLevel == TypeId::SupportLevel::OBSOLETE)
|
||||
{
|
||||
NS_LOG_WARN("Attribute " << GetCurrentPath()
|
||||
<< " was not saved because it is OBSOLETE");
|
||||
}
|
||||
else if (supportLevel == TypeId::SupportLevel::DEPRECATED && !m_saveDeprecated)
|
||||
{
|
||||
NS_LOG_WARN("Attribute " << GetCurrentPath()
|
||||
<< " was not saved because it is DEPRECATED");
|
||||
}
|
||||
else
|
||||
{
|
||||
object->GetAttribute(name, str);
|
||||
NS_LOG_DEBUG("Saving " << GetCurrentPath());
|
||||
*m_os << "value " << GetCurrentPath() << " \"" << str.Get() << "\"" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream* m_os;
|
||||
bool m_saveDeprecated;
|
||||
};
|
||||
|
||||
RawTextAttributeIterator iter = RawTextAttributeIterator(m_os);
|
||||
iter.SetSaveDeprecated(m_saveDeprecated);
|
||||
iter.Iterate();
|
||||
}
|
||||
|
||||
|
||||
@@ -104,11 +104,6 @@ XmlConfigSave::Default()
|
||||
m_writer = writer;
|
||||
}
|
||||
|
||||
void SetSaveDeprecated(bool saveDeprecated)
|
||||
{
|
||||
m_saveDeprecated = saveDeprecated;
|
||||
}
|
||||
|
||||
private:
|
||||
void StartVisitTypeId(std::string name) override
|
||||
{
|
||||
@@ -119,25 +114,38 @@ XmlConfigSave::Default()
|
||||
{
|
||||
TypeId tid = TypeId::LookupByName(m_typeid);
|
||||
ns3::TypeId::SupportLevel supportLevel = TypeId::SupportLevel::SUPPORTED;
|
||||
std::string originalInitialValue;
|
||||
std::string valueTypeName;
|
||||
for (std::size_t i = 0; i < tid.GetAttributeN(); i++)
|
||||
{
|
||||
TypeId::AttributeInformation tmp = tid.GetAttribute(i);
|
||||
if (tmp.name == name)
|
||||
{
|
||||
supportLevel = tmp.supportLevel;
|
||||
originalInitialValue = tmp.originalInitialValue->SerializeToString(tmp.checker);
|
||||
valueTypeName = tmp.checker->GetValueTypeName();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valueTypeName == "ns3::CallbackValue")
|
||||
{
|
||||
NS_LOG_WARN("Global attribute " << m_typeid << "::" << name
|
||||
<< " was not saved because it is a CallbackValue");
|
||||
return;
|
||||
}
|
||||
if (supportLevel == TypeId::SupportLevel::OBSOLETE)
|
||||
{
|
||||
NS_LOG_WARN("Global attribute " << m_typeid << "::" << name
|
||||
<< " was not saved because it is OBSOLETE");
|
||||
return;
|
||||
}
|
||||
else if (supportLevel == TypeId::SupportLevel::DEPRECATED && !m_saveDeprecated)
|
||||
if (supportLevel == TypeId::SupportLevel::DEPRECATED &&
|
||||
defaultValue == originalInitialValue)
|
||||
{
|
||||
NS_LOG_WARN("Global attribute " << m_typeid << "::" << name
|
||||
<< " was not saved because it is DEPRECATED");
|
||||
NS_LOG_WARN("Global attribute "
|
||||
<< m_typeid << "::" << name
|
||||
<< " was not saved because it is DEPRECATED and its value has not "
|
||||
"changed from the original initial value");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -169,11 +177,9 @@ XmlConfigSave::Default()
|
||||
|
||||
xmlTextWriterPtr m_writer;
|
||||
std::string m_typeid;
|
||||
bool m_saveDeprecated;
|
||||
};
|
||||
|
||||
XmlDefaultIterator iterator = XmlDefaultIterator(m_writer);
|
||||
iterator.SetSaveDeprecated(m_saveDeprecated);
|
||||
iterator.Iterate();
|
||||
}
|
||||
|
||||
@@ -188,39 +194,45 @@ XmlConfigSave::Attributes()
|
||||
{
|
||||
}
|
||||
|
||||
void SetSaveDeprecated(bool saveDeprecated)
|
||||
{
|
||||
m_saveDeprecated = saveDeprecated;
|
||||
}
|
||||
|
||||
private:
|
||||
void DoVisitAttribute(Ptr<Object> object, std::string name) override
|
||||
{
|
||||
StringValue str;
|
||||
TypeId tid = object->GetInstanceTypeId();
|
||||
ns3::TypeId::SupportLevel supportLevel = TypeId::SupportLevel::SUPPORTED;
|
||||
for (std::size_t i = 0; i < tid.GetAttributeN(); i++)
|
||||
|
||||
auto [found, inTid, attr] = TypeId::FindAttribute(tid, name);
|
||||
|
||||
if (found)
|
||||
{
|
||||
TypeId::AttributeInformation tmp = tid.GetAttribute(i);
|
||||
if (tmp.name == name)
|
||||
if (attr.checker && attr.checker->GetValueTypeName() == "ns3::CallbackValue")
|
||||
{
|
||||
supportLevel = tmp.supportLevel;
|
||||
break;
|
||||
NS_LOG_WARN("Attribute " << GetCurrentPath()
|
||||
<< " was not saved because it is a CallbackValue");
|
||||
return;
|
||||
}
|
||||
auto supportLevel = attr.supportLevel;
|
||||
if (supportLevel == TypeId::SupportLevel::OBSOLETE)
|
||||
{
|
||||
NS_LOG_WARN("Attribute " << GetCurrentPath()
|
||||
<< " was not saved because it is OBSOLETE");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string originalInitialValue =
|
||||
attr.originalInitialValue->SerializeToString(attr.checker);
|
||||
object->GetAttribute(name, str, true);
|
||||
|
||||
if (supportLevel == TypeId::SupportLevel::DEPRECATED &&
|
||||
str.Get() == originalInitialValue)
|
||||
{
|
||||
NS_LOG_WARN("Attribute "
|
||||
<< GetCurrentPath()
|
||||
<< " was not saved because it is DEPRECATED and its value has not "
|
||||
"changed from the original initial value");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (supportLevel == TypeId::SupportLevel::OBSOLETE)
|
||||
{
|
||||
NS_LOG_WARN("Attribute " << GetCurrentPath()
|
||||
<< " was not saved because it is OBSOLETE");
|
||||
return;
|
||||
}
|
||||
else if (supportLevel == TypeId::SupportLevel::DEPRECATED && !m_saveDeprecated)
|
||||
{
|
||||
NS_LOG_WARN("Attribute " << GetCurrentPath()
|
||||
<< " was not saved because it is DEPRECATED");
|
||||
return;
|
||||
}
|
||||
StringValue str;
|
||||
object->GetAttribute(name, str);
|
||||
|
||||
int rc;
|
||||
rc = xmlTextWriterStartElement(m_writer, BAD_CAST "value");
|
||||
if (rc < 0)
|
||||
@@ -248,11 +260,9 @@ XmlConfigSave::Attributes()
|
||||
}
|
||||
|
||||
xmlTextWriterPtr m_writer;
|
||||
bool m_saveDeprecated;
|
||||
};
|
||||
|
||||
XmlTextAttributeIterator iter = XmlTextAttributeIterator(m_writer);
|
||||
iter.SetSaveDeprecated(m_saveDeprecated);
|
||||
iter.Iterate();
|
||||
}
|
||||
|
||||
|
||||
@@ -237,12 +237,12 @@ ObjectBase::SetAttributeFailSafe(std::string name, const AttributeValue& value)
|
||||
}
|
||||
|
||||
void
|
||||
ObjectBase::GetAttribute(std::string name, AttributeValue& value) const
|
||||
ObjectBase::GetAttribute(std::string name, AttributeValue& value, bool permissive) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << name << &value);
|
||||
TypeId::AttributeInformation info;
|
||||
TypeId tid = GetInstanceTypeId();
|
||||
if (!tid.LookupAttributeByName(name, &info))
|
||||
if (!tid.LookupAttributeByName(name, &info, permissive))
|
||||
{
|
||||
NS_FATAL_ERROR(
|
||||
"Attribute name=" << name << " does not exist for this object: tid=" << tid.GetName());
|
||||
|
||||
@@ -224,8 +224,11 @@ class ObjectBase
|
||||
*
|
||||
* \param [in] name The name of the attribute to read.
|
||||
* \param [out] value Where the result should be stored.
|
||||
* \param [in] permissive If false (by default), will generate warnings and errors for
|
||||
* deprecated and obsolete attributes, respectively. If set to true, warnings for deprecated
|
||||
* attributes will be suppressed.
|
||||
*/
|
||||
void GetAttribute(std::string name, AttributeValue& value) const;
|
||||
void GetAttribute(std::string name, AttributeValue& value, bool permissive = false) const;
|
||||
/**
|
||||
* Get the value of an attribute without raising errors.
|
||||
*
|
||||
|
||||
@@ -936,41 +936,64 @@ TypeId::GetRegistered(uint16_t i)
|
||||
return TypeId(IidManager::Get()->GetRegistered(i));
|
||||
}
|
||||
|
||||
bool
|
||||
TypeId::LookupAttributeByName(std::string name, TypeId::AttributeInformation* info) const
|
||||
std::tuple<bool, TypeId, TypeId::AttributeInformation>
|
||||
TypeId::FindAttribute(const TypeId& tid, const std::string& name)
|
||||
{
|
||||
NS_LOG_FUNCTION(this << name << info);
|
||||
TypeId tid;
|
||||
TypeId nextTid = *this;
|
||||
do
|
||||
TypeId currentTid = tid;
|
||||
TypeId parentTid;
|
||||
while (true)
|
||||
{
|
||||
tid = nextTid;
|
||||
for (std::size_t i = 0; i < tid.GetAttributeN(); i++)
|
||||
for (std::size_t i = 0; i < currentTid.GetAttributeN(); ++i)
|
||||
{
|
||||
TypeId::AttributeInformation tmp = tid.GetAttribute(i);
|
||||
if (tmp.name == name)
|
||||
const AttributeInformation& attributeInfo = currentTid.GetAttribute(i);
|
||||
if (attributeInfo.name == name)
|
||||
{
|
||||
if (tmp.supportLevel == TypeId::SUPPORTED)
|
||||
{
|
||||
*info = tmp;
|
||||
return true;
|
||||
}
|
||||
else if (tmp.supportLevel == TypeId::DEPRECATED)
|
||||
{
|
||||
std::cerr << "Attribute '" << name << "' is deprecated: " << tmp.supportMsg
|
||||
<< std::endl;
|
||||
*info = tmp;
|
||||
return true;
|
||||
}
|
||||
else if (tmp.supportLevel == TypeId::OBSOLETE)
|
||||
{
|
||||
NS_FATAL_ERROR("Attribute '" << name << "' is obsolete, with no fallback: "
|
||||
<< tmp.supportMsg);
|
||||
}
|
||||
return {true, currentTid, attributeInfo};
|
||||
}
|
||||
}
|
||||
nextTid = tid.GetParent();
|
||||
} while (nextTid != tid);
|
||||
|
||||
parentTid = currentTid.GetParent();
|
||||
|
||||
if (parentTid == currentTid)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
currentTid = parentTid;
|
||||
}
|
||||
return {false, TypeId(), AttributeInformation()};
|
||||
}
|
||||
|
||||
bool
|
||||
TypeId::LookupAttributeByName(std::string name,
|
||||
TypeId::AttributeInformation* info,
|
||||
bool permissive) const
|
||||
{
|
||||
NS_LOG_FUNCTION(this << name << info);
|
||||
auto [found, tid, attribute] = FindAttribute(*this, name);
|
||||
if (found)
|
||||
{
|
||||
if (attribute.supportLevel == TypeId::SUPPORTED)
|
||||
{
|
||||
*info = attribute;
|
||||
return true;
|
||||
}
|
||||
else if (attribute.supportLevel == TypeId::DEPRECATED)
|
||||
{
|
||||
if (!permissive)
|
||||
{
|
||||
std::cerr << "Attribute '" << name << "' is deprecated: " << attribute.supportMsg
|
||||
<< std::endl;
|
||||
}
|
||||
*info = attribute;
|
||||
return true;
|
||||
}
|
||||
else if (attribute.supportLevel == TypeId::OBSOLETE)
|
||||
{
|
||||
NS_FATAL_ERROR("Attribute '"
|
||||
<< name << "' is obsolete, with no fallback: " << attribute.supportMsg);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -467,6 +467,17 @@ class TypeId
|
||||
*/
|
||||
TypeId HideFromDocumentation();
|
||||
|
||||
/**
|
||||
* Find an attribute by name in the inheritance tree for a given TypeId.
|
||||
*
|
||||
* \param [in] tid The TypeId to start the search from.
|
||||
* \param [in] name The name of the attribute to search for.
|
||||
* \return A tuple containing a boolean that indicates whether the attribute was found, the
|
||||
* TypeId where the attribute was found, and the AttributeInformation of the found attribute.
|
||||
*/
|
||||
static std::tuple<bool, TypeId, AttributeInformation> FindAttribute(const TypeId& tid,
|
||||
const std::string& name);
|
||||
|
||||
/**
|
||||
* Find an Attribute by name, retrieving the associated AttributeInformation.
|
||||
*
|
||||
@@ -474,9 +485,14 @@ class TypeId
|
||||
* \param [in,out] info A pointer to the TypeId::AttributeInformation
|
||||
* data structure where the result value of this method
|
||||
* will be stored.
|
||||
* \param [in] permissive If false (by default), will generate warnings and errors for
|
||||
* deprecated and obsolete attributes, respectively. If set to true, warnings for deprecated
|
||||
* attributes will be suppressed.
|
||||
* \returns \c true if the requested attribute could be found.
|
||||
*/
|
||||
bool LookupAttributeByName(std::string name, AttributeInformation* info) const;
|
||||
bool LookupAttributeByName(std::string name,
|
||||
AttributeInformation* info,
|
||||
bool permissive = false) const;
|
||||
/**
|
||||
* Find a TraceSource by name.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user