00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "config.h"
00021 #include "singleton.h"
00022 #include "object.h"
00023 #include "global-value.h"
00024 #include "object-vector.h"
00025 #include "pointer.h"
00026 #include "log.h"
00027 #include <sstream>
00028
00029 NS_LOG_COMPONENT_DEFINE ("Config");
00030
00031 namespace ns3 {
00032
00033 namespace Config {
00034
00035 MatchContainer::MatchContainer ()
00036 {}
00037 MatchContainer::MatchContainer (const std::vector<Ptr<Object> > &objects,
00038 const std::vector<std::string> &contexts,
00039 std::string path)
00040 : m_objects (objects),
00041 m_contexts (contexts),
00042 m_path (path)
00043 {}
00044 MatchContainer::Iterator
00045 MatchContainer::Begin (void) const
00046 {
00047 return m_objects.begin ();
00048 }
00049 MatchContainer::Iterator
00050 MatchContainer::End (void) const
00051 {
00052 return m_objects.end ();
00053 }
00054 uint32_t
00055 MatchContainer::GetN (void) const
00056 {
00057 return m_objects.size ();
00058 }
00059 Ptr<Object>
00060 MatchContainer::Get (uint32_t i) const
00061 {
00062 return m_objects[i];
00063 }
00064 std::string
00065 MatchContainer::GetMatchedPath (uint32_t i) const
00066 {
00067 return m_contexts[i];
00068 }
00069 std::string
00070 MatchContainer::GetPath (void) const
00071 {
00072 return m_path;
00073 }
00074
00075 void
00076 MatchContainer::Set (std::string name, const AttributeValue &value)
00077 {
00078 for (Iterator tmp = Begin (); tmp != End (); ++tmp)
00079 {
00080 Ptr<Object> object = *tmp;
00081 object->SetAttribute (name, value);
00082 }
00083 }
00084 void
00085 MatchContainer::Connect (std::string name, const CallbackBase &cb)
00086 {
00087 NS_ASSERT (m_objects.size () == m_contexts.size ());
00088 for (uint32_t i = 0; i < m_objects.size (); ++i)
00089 {
00090 Ptr<Object> object = m_objects[i];
00091 std::string ctx = m_contexts[i] + name;
00092 object->TraceConnect (name, ctx, cb);
00093 }
00094 }
00095 void
00096 MatchContainer::ConnectWithoutContext (std::string name, const CallbackBase &cb)
00097 {
00098 for (Iterator tmp = Begin (); tmp != End (); ++tmp)
00099 {
00100 Ptr<Object> object = *tmp;
00101 object->TraceConnectWithoutContext (name, cb);
00102 }
00103 }
00104 void
00105 MatchContainer::Disconnect (std::string name, const CallbackBase &cb)
00106 {
00107 NS_ASSERT (m_objects.size () == m_contexts.size ());
00108 for (uint32_t i = 0; i < m_objects.size (); ++i)
00109 {
00110 Ptr<Object> object = m_objects[i];
00111 std::string ctx = m_contexts[i] + name;
00112 object->TraceDisconnect (name, ctx, cb);
00113 }
00114 }
00115 void
00116 MatchContainer::DisconnectWithoutContext (std::string name, const CallbackBase &cb)
00117 {
00118 for (Iterator tmp = Begin (); tmp != End (); ++tmp)
00119 {
00120 Ptr<Object> object = *tmp;
00121 object->TraceDisconnectWithoutContext (name, cb);
00122 }
00123 }
00124
00125 }
00126
00127 class ArrayMatcher
00128 {
00129 public:
00130 ArrayMatcher (std::string element);
00131 bool Matches (uint32_t i) const;
00132 private:
00133 bool StringToUint32 (std::string str, uint32_t *value) const;
00134 std::string m_element;
00135 };
00136
00137
00138 ArrayMatcher::ArrayMatcher (std::string element)
00139 : m_element (element)
00140 {}
00141 bool
00142 ArrayMatcher::Matches (uint32_t i) const
00143 {
00144 if (m_element == "*")
00145 {
00146 NS_LOG_DEBUG ("Array "<<i<<" matches *");
00147 return true;
00148 }
00149 std::string::size_type tmp;
00150 tmp = m_element.find ("|");
00151 if (tmp != std::string::npos)
00152 {
00153 std::string left = m_element.substr (0, tmp-0);
00154 std::string right = m_element.substr (tmp+1, m_element.size () - (tmp + 1));
00155 ArrayMatcher matcher = ArrayMatcher (left);
00156 if (matcher.Matches (i))
00157 {
00158 NS_LOG_DEBUG ("Array "<<i<<" matches "<<left);
00159 return true;
00160 }
00161 matcher = ArrayMatcher (right);
00162 if (matcher.Matches (i))
00163 {
00164 NS_LOG_DEBUG ("Array "<<i<<" matches "<<right);
00165 return true;
00166 }
00167 NS_LOG_DEBUG ("Array "<<i<<" does not match "<<m_element);
00168 return false;
00169 }
00170 std::string::size_type leftBracket = m_element.find ("[");
00171 std::string::size_type rightBracket = m_element.find ("]");
00172 std::string::size_type dash = m_element.find ("-");
00173 if (leftBracket == 0 && rightBracket == m_element.size () - 1 &&
00174 dash > leftBracket && dash < rightBracket)
00175 {
00176 std::string lowerBound = m_element.substr (leftBracket + 1, dash - (leftBracket + 1));
00177 std::string upperBound = m_element.substr (dash + 1, rightBracket - (dash + 1));
00178 uint32_t min;
00179 uint32_t max;
00180 if (StringToUint32 (lowerBound, &min) &&
00181 StringToUint32 (upperBound, &max) &&
00182 i >= min && i <= max)
00183 {
00184 NS_LOG_DEBUG ("Array "<<i<<" matches "<<m_element);
00185 return true;
00186 }
00187 else
00188 {
00189 NS_LOG_DEBUG ("Array "<<i<<" does not "<<m_element);
00190 return false;
00191 }
00192 }
00193 uint32_t value;
00194 if (StringToUint32 (m_element, &value) &&
00195 i == value)
00196 {
00197 NS_LOG_DEBUG ("Array "<<i<<" matches "<<m_element);
00198 return true;
00199 }
00200 NS_LOG_DEBUG ("Array "<<i<<" does not match "<<m_element);
00201 return false;
00202 }
00203
00204 bool
00205 ArrayMatcher::StringToUint32 (std::string str, uint32_t *value) const
00206 {
00207 std::istringstream iss;
00208 iss.str (str);
00209 iss >> (*value);
00210 return !iss.bad () && !iss.fail ();
00211 }
00212
00213
00214 class Resolver
00215 {
00216 public:
00217 Resolver (std::string path);
00218 virtual ~Resolver ();
00219
00220 void Resolve (Ptr<Object> root);
00221 private:
00222 void Canonicalize (void);
00223 void DoResolve (std::string path, Ptr<Object> root);
00224 void DoArrayResolve (std::string path, const ObjectVectorValue &vector);
00225 void DoResolveOne (Ptr<Object> object);
00226 std::string GetResolvedPath (void) const;
00227 virtual void DoOne (Ptr<Object> object, std::string path) = 0;
00228 std::vector<std::string> m_workStack;
00229 std::string m_path;
00230 };
00231
00232 Resolver::Resolver (std::string path)
00233 : m_path (path)
00234 {
00235 Canonicalize ();
00236 }
00237 Resolver::~Resolver ()
00238 {}
00239 void
00240 Resolver::Canonicalize (void)
00241 {
00242
00243 std::string::size_type tmp = m_path.find ("/");
00244 if (tmp != 0)
00245 {
00246
00247 m_path = "/" + m_path;
00248 }
00249 tmp = m_path.find_last_of ("/");
00250 if (tmp != (m_path.size () - 1))
00251 {
00252
00253 m_path = m_path + "/";
00254 }
00255 }
00256
00257 void
00258 Resolver::Resolve (Ptr<Object> root)
00259 {
00260 DoResolve (m_path, root);
00261 }
00262
00263 std::string
00264 Resolver::GetResolvedPath (void) const
00265 {
00266 std::string fullPath = "/";
00267 for (std::vector<std::string>::const_iterator i = m_workStack.begin (); i != m_workStack.end (); i++)
00268 {
00269 fullPath += *i + "/";
00270 }
00271 return fullPath;
00272 }
00273
00274 void
00275 Resolver::DoResolveOne (Ptr<Object> object)
00276 {
00277 NS_LOG_DEBUG ("resolved="<<GetResolvedPath ());
00278 DoOne (object, GetResolvedPath ());
00279 }
00280
00281 void
00282 Resolver::DoResolve (std::string path, Ptr<Object> root)
00283 {
00284 NS_LOG_FUNCTION (path << root);
00285 std::string::size_type tmp;
00286 tmp = path.find ("/");
00287 NS_ASSERT (tmp == 0);
00288 std::string::size_type next = path.find ("/", 1);
00289 if (next == std::string::npos)
00290 {
00291 DoResolveOne (root);
00292 return;
00293 }
00294 std::string item = path.substr (1, next-1);
00295 std::string pathLeft = path.substr (next, path.size ()-next);
00296
00297 std::string::size_type dollarPos = item.find ("$");
00298 if (dollarPos == 0)
00299 {
00300
00301 std::string tidString = item.substr (1, item.size () - 1);
00302 NS_LOG_DEBUG ("GetObject="<<tidString<<" on path="<<GetResolvedPath ());
00303 TypeId tid = TypeId::LookupByName (tidString);
00304 Ptr<Object> object = root->GetObject<Object> (tid);
00305 if (object == 0)
00306 {
00307 NS_LOG_DEBUG ("GetObject ("<<tidString<<") failed on path="<<GetResolvedPath ());
00308 return;
00309 }
00310 m_workStack.push_back (item);
00311 DoResolve (pathLeft, object);
00312 m_workStack.pop_back ();
00313 }
00314 else
00315 {
00316
00317 TypeId tid = root->GetInstanceTypeId ();
00318 struct TypeId::AttributeInfo info;
00319 if (!tid.LookupAttributeByName (item, &info))
00320 {
00321 NS_LOG_DEBUG ("Requested item="<<item<<" does not exist on path="<<GetResolvedPath ());
00322 return;
00323 }
00324
00325 const PointerChecker *ptr = dynamic_cast<const PointerChecker *> (PeekPointer (info.checker));
00326 if (ptr != 0)
00327 {
00328 NS_LOG_DEBUG ("GetAttribute(ptr)="<<item<<" on path="<<GetResolvedPath ());
00329 PointerValue ptr;
00330 root->GetAttribute (item, ptr);
00331 Ptr<Object> object = ptr.Get<Object> ();
00332 if (object == 0)
00333 {
00334 NS_LOG_ERROR ("Requested object name=\""<<item<<
00335 "\" exists on path=\""<<GetResolvedPath ()<<"\""
00336 " but is null.");
00337 return;
00338 }
00339 m_workStack.push_back (item);
00340 DoResolve (pathLeft, object);
00341 m_workStack.pop_back ();
00342 }
00343
00344 const ObjectVectorChecker *vectorChecker = dynamic_cast<const ObjectVectorChecker *> (PeekPointer (info.checker));
00345 if (vectorChecker != 0)
00346 {
00347 NS_LOG_DEBUG ("GetAttribute(vector)="<<item<<" on path="<<GetResolvedPath ());
00348 ObjectVectorValue vector;
00349 root->GetAttribute (item, vector);
00350 m_workStack.push_back (item);
00351 DoArrayResolve (pathLeft, vector);
00352 m_workStack.pop_back ();
00353 }
00354
00355
00356 }
00357 }
00358
00359 void
00360 Resolver::DoArrayResolve (std::string path, const ObjectVectorValue &vector)
00361 {
00362 NS_ASSERT (path != "");
00363 std::string::size_type tmp;
00364 tmp = path.find ("/");
00365 NS_ASSERT (tmp == 0);
00366 std::string::size_type next = path.find ("/", 1);
00367 if (next == std::string::npos)
00368 {
00369 NS_FATAL_ERROR ("vector path includes no index data on path=\""<<path<<"\"");
00370 }
00371 std::string item = path.substr (1, next-1);
00372 std::string pathLeft = path.substr (next, path.size ()-next);
00373
00374 ArrayMatcher matcher = ArrayMatcher (item);
00375 for (uint32_t i = 0; i < vector.GetN (); i++)
00376 {
00377 if (matcher.Matches (i))
00378 {
00379 std::ostringstream oss;
00380 oss << i;
00381 m_workStack.push_back (oss.str ());
00382 DoResolve (pathLeft, vector.Get (i));
00383 m_workStack.pop_back ();
00384 }
00385 }
00386 }
00387
00388
00389 class ConfigImpl
00390 {
00391 public:
00392 void Set (std::string path, const AttributeValue &value);
00393 void ConnectWithoutContext (std::string path, const CallbackBase &cb);
00394 void Connect (std::string path, const CallbackBase &cb);
00395 void DisconnectWithoutContext (std::string path, const CallbackBase &cb);
00396 void Disconnect (std::string path, const CallbackBase &cb);
00397 Config::MatchContainer LookupMatches (std::string path);
00398
00399 void RegisterRootNamespaceObject (Ptr<Object> obj);
00400 void UnregisterRootNamespaceObject (Ptr<Object> obj);
00401
00402 uint32_t GetRootNamespaceObjectN (void) const;
00403 Ptr<Object> GetRootNamespaceObject (uint32_t i) const;
00404
00405 private:
00406 void ParsePath (std::string path, std::string *root, std::string *leaf) const;
00407 typedef std::vector<Ptr<Object> > Roots;
00408 Roots m_roots;
00409 };
00410
00411 void
00412 ConfigImpl::ParsePath (std::string path, std::string *root, std::string *leaf) const
00413 {
00414 std::string::size_type slash = path.find_last_of ("/");
00415 NS_ASSERT (slash != std::string::npos);
00416 *root = path.substr (0, slash);
00417 *leaf = path.substr (slash+1, path.size ()-(slash+1));
00418 NS_LOG_FUNCTION (path << *root << *leaf);
00419 }
00420
00421 void
00422 ConfigImpl::Set (std::string path, const AttributeValue &value)
00423 {
00424 std::string root, leaf;
00425 ParsePath (path, &root, &leaf);
00426 Config::MatchContainer container = LookupMatches (root);
00427 container.Set (leaf, value);
00428 }
00429 void
00430 ConfigImpl::ConnectWithoutContext (std::string path, const CallbackBase &cb)
00431 {
00432 std::string root, leaf;
00433 ParsePath (path, &root, &leaf);
00434 Config::MatchContainer container = LookupMatches (root);
00435 container.ConnectWithoutContext (leaf, cb);
00436 }
00437 void
00438 ConfigImpl::DisconnectWithoutContext (std::string path, const CallbackBase &cb)
00439 {
00440 std::string root, leaf;
00441 ParsePath (path, &root, &leaf);
00442 Config::MatchContainer container = LookupMatches (root);
00443 container.DisconnectWithoutContext (leaf, cb);
00444 }
00445 void
00446 ConfigImpl::Connect (std::string path, const CallbackBase &cb)
00447 {
00448 std::string root, leaf;
00449 ParsePath (path, &root, &leaf);
00450 Config::MatchContainer container = LookupMatches (root);
00451 container.Connect (leaf, cb);
00452 }
00453 void
00454 ConfigImpl::Disconnect (std::string path, const CallbackBase &cb)
00455 {
00456 std::string root, leaf;
00457 ParsePath (path, &root, &leaf);
00458 Config::MatchContainer container = LookupMatches (root);
00459 container.Disconnect (leaf, cb);
00460 }
00461
00462 Config::MatchContainer
00463 ConfigImpl::LookupMatches (std::string path)
00464 {
00465 NS_LOG_FUNCTION (path);
00466 class LookupMatchesResolver : public Resolver
00467 {
00468 public:
00469 LookupMatchesResolver (std::string path)
00470 : Resolver (path)
00471 {}
00472 virtual void DoOne (Ptr<Object> object, std::string path) {
00473 m_objects.push_back (object);
00474 m_contexts.push_back (path);
00475 }
00476 std::vector<Ptr<Object> > m_objects;
00477 std::vector<std::string> m_contexts;
00478 } resolver = LookupMatchesResolver (path);
00479 for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
00480 {
00481 resolver.Resolve (*i);
00482 }
00483 return Config::MatchContainer (resolver.m_objects, resolver.m_contexts, path);
00484 }
00485
00486 void
00487 ConfigImpl::RegisterRootNamespaceObject (Ptr<Object> obj)
00488 {
00489 m_roots.push_back (obj);
00490 }
00491
00492 void
00493 ConfigImpl::UnregisterRootNamespaceObject (Ptr<Object> obj)
00494 {
00495 for (std::vector<Ptr<Object> >::iterator i = m_roots.begin (); i != m_roots.end (); i++)
00496 {
00497 if (*i == obj)
00498 {
00499 m_roots.erase (i);
00500 return;
00501 }
00502 }
00503 }
00504
00505 uint32_t
00506 ConfigImpl::GetRootNamespaceObjectN (void) const
00507 {
00508 return m_roots.size ();
00509 }
00510 Ptr<Object>
00511 ConfigImpl::GetRootNamespaceObject (uint32_t i) const
00512 {
00513 return m_roots[i];
00514 }
00515
00516 namespace Config {
00517
00518 void Set (std::string path, const AttributeValue &value)
00519 {
00520 Singleton<ConfigImpl>::Get ()->Set (path, value);
00521 }
00522 void SetDefault (std::string name, const AttributeValue &value)
00523 {
00524 AttributeList::GetGlobal ()->Set (name, value);
00525 }
00526 bool SetDefaultFailSafe (std::string name, const AttributeValue &value)
00527 {
00528 return AttributeList::GetGlobal ()->SetFailSafe (name, value);
00529 }
00530 void SetGlobal (std::string name, const AttributeValue &value)
00531 {
00532 GlobalValue::Bind (name, value);
00533 }
00534 bool SetGlobalFailSafe (std::string name, const AttributeValue &value)
00535 {
00536 return GlobalValue::BindFailSafe (name, value);
00537 }
00538 void ConnectWithoutContext (std::string path, const CallbackBase &cb)
00539 {
00540 Singleton<ConfigImpl>::Get ()->ConnectWithoutContext (path, cb);
00541 }
00542 void DisconnectWithoutContext (std::string path, const CallbackBase &cb)
00543 {
00544 Singleton<ConfigImpl>::Get ()->DisconnectWithoutContext (path, cb);
00545 }
00546 void
00547 Connect (std::string path, const CallbackBase &cb)
00548 {
00549 Singleton<ConfigImpl>::Get ()->Connect (path, cb);
00550 }
00551 void
00552 Disconnect (std::string path, const CallbackBase &cb)
00553 {
00554 Singleton<ConfigImpl>::Get ()->Disconnect (path, cb);
00555 }
00556 Config::MatchContainer LookupMatches (std::string path)
00557 {
00558 return Singleton<ConfigImpl>::Get ()->LookupMatches (path);
00559 }
00560
00561 void RegisterRootNamespaceObject (Ptr<Object> obj)
00562 {
00563 Singleton<ConfigImpl>::Get ()->RegisterRootNamespaceObject (obj);
00564 }
00565
00566 void UnregisterRootNamespaceObject (Ptr<Object> obj)
00567 {
00568 Singleton<ConfigImpl>::Get ()->UnregisterRootNamespaceObject (obj);
00569 }
00570
00571 uint32_t GetRootNamespaceObjectN (void)
00572 {
00573 return Singleton<ConfigImpl>::Get ()->GetRootNamespaceObjectN ();
00574 }
00575
00576 Ptr<Object> GetRootNamespaceObject (uint32_t i)
00577 {
00578 return Singleton<ConfigImpl>::Get ()->GetRootNamespaceObject (i);
00579 }
00580
00581
00582 }
00583
00584 }
00585
00586 #ifdef RUN_SELF_TESTS
00587
00588 #include "test.h"
00589 #include "integer.h"
00590 #include "traced-value.h"
00591 #include "trace-source-accessor.h"
00592 #include "callback.h"
00593
00594 namespace ns3 {
00595
00596 class MyNode : public Object
00597 {
00598 public:
00599 static TypeId GetTypeId (void);
00600
00601 void AddNodeA (Ptr<MyNode> a);
00602 void AddNodeB (Ptr<MyNode> b);
00603
00604 void SetNodeA (Ptr<MyNode> a);
00605 void SetNodeB (Ptr<MyNode> b);
00606
00607 int8_t GetA (void) const;
00608 int8_t GetB (void) const;
00609
00610 private:
00611 std::vector<Ptr<MyNode> > m_nodesA;
00612 std::vector<Ptr<MyNode> > m_nodesB;
00613 Ptr<MyNode> m_nodeA;
00614 Ptr<MyNode> m_nodeB;
00615 int8_t m_a;
00616 int8_t m_b;
00617 TracedValue<int16_t> m_trace;
00618 };
00619
00620 TypeId MyNode::GetTypeId (void)
00621 {
00622 static TypeId tid = TypeId ("MyNode")
00623 .SetParent<Object> ()
00624 .AddAttribute ("NodesA", "",
00625 ObjectVectorValue (),
00626 MakeObjectVectorAccessor (&MyNode::m_nodesA),
00627 MakeObjectVectorChecker<MyNode> ())
00628 .AddAttribute ("NodesB", "",
00629 ObjectVectorValue (),
00630 MakeObjectVectorAccessor (&MyNode::m_nodesB),
00631 MakeObjectVectorChecker<MyNode> ())
00632 .AddAttribute ("NodeA", "",
00633 PointerValue (),
00634 MakePointerAccessor (&MyNode::m_nodeA),
00635 MakePointerChecker<MyNode> ())
00636 .AddAttribute ("NodeB", "",
00637 PointerValue (),
00638 MakePointerAccessor (&MyNode::m_nodeB),
00639 MakePointerChecker<MyNode> ())
00640 .AddAttribute ("A", "",
00641 IntegerValue (10),
00642 MakeIntegerAccessor (&MyNode::m_a),
00643 MakeIntegerChecker<int8_t> ())
00644 .AddAttribute ("B", "",
00645 IntegerValue (9),
00646 MakeIntegerAccessor (&MyNode::m_b),
00647 MakeIntegerChecker<int8_t> ())
00648 .AddAttribute ("Source", "XX",
00649 IntegerValue (-1),
00650 MakeIntegerAccessor (&MyNode::m_trace),
00651 MakeIntegerChecker<int16_t> ())
00652 .AddTraceSource ("Source", "XX",
00653 MakeTraceSourceAccessor (&MyNode::m_trace))
00654 ;
00655 return tid;
00656 }
00657
00658 void
00659 MyNode::SetNodeA (Ptr<MyNode> a)
00660 {
00661 m_nodeA = a;
00662 }
00663 void
00664 MyNode::SetNodeB (Ptr<MyNode> b)
00665 {
00666 m_nodeB = b;
00667 }
00668 void
00669 MyNode::AddNodeA (Ptr<MyNode> a)
00670 {
00671 m_nodesA.push_back (a);
00672 }
00673 void
00674 MyNode::AddNodeB (Ptr<MyNode> b)
00675 {
00676 m_nodesB.push_back (b);
00677 }
00678 int8_t
00679 MyNode::GetA (void) const
00680 {
00681 return m_a;
00682 }
00683 int8_t
00684 MyNode::GetB (void) const
00685 {
00686 return m_b;
00687 }
00688
00689
00690 class ConfigTest : public Test
00691 {
00692 public:
00693 ConfigTest ();
00694 virtual bool RunTests (void);
00695 private:
00696 void ChangeNotification (int16_t old, int16_t newValue);
00697 void ChangeNotificationWithPath (std::string path, int16_t old, int16_t newValue);
00698 int16_t m_traceNotification;
00699 std::string m_tracePath;
00700 };
00701
00702 static ConfigTest g_configTestUnique;
00703
00704 ConfigTest::ConfigTest ()
00705 : Test ("Config")
00706 {}
00707
00708 void
00709 ConfigTest::ChangeNotification (int16_t oldValue, int16_t newValue)
00710 {
00711 m_traceNotification = newValue;
00712 }
00713
00714 void
00715 ConfigTest::ChangeNotificationWithPath (std::string path, int16_t old, int16_t newValue)
00716 {
00717 m_traceNotification = newValue;
00718 m_tracePath = path;
00719 }
00720
00721 bool
00722 ConfigTest::RunTests (void)
00723 {
00724 bool result = true;
00725
00726 Ptr<MyNode> root = CreateObject<MyNode> ();
00727 Config::RegisterRootNamespaceObject (root);
00728 Config::Set ("/A", IntegerValue (1));
00729 Config::Set ("/B", IntegerValue (-1));
00730 IntegerValue v;
00731 root->GetAttribute ("A", v);
00732 NS_TEST_ASSERT_EQUAL (v.Get (), 1);
00733 root->GetAttribute ("B", v);
00734 NS_TEST_ASSERT_EQUAL (v.Get (), -1);
00735
00736 Ptr<MyNode> a = CreateObject<MyNode> ();
00737 root->SetNodeA (a);
00738 Config::Set ("/NodeA/A", IntegerValue (2));
00739 Config::Set ("/NodeA/B", IntegerValue (-2));
00740 a->GetAttribute ("A", v);
00741 NS_TEST_ASSERT_EQUAL (v.Get (), 2);
00742 a->GetAttribute ("B", v);
00743 NS_TEST_ASSERT_EQUAL (v.Get (), -2);
00744 Config::Set ("/NodeB/A", IntegerValue (3));
00745 Config::Set ("/NodeB/B", IntegerValue (-3));
00746 a->GetAttribute ("A", v);
00747 NS_TEST_ASSERT_EQUAL (v.Get (), 2);
00748 a->GetAttribute ("B", v);
00749 NS_TEST_ASSERT_EQUAL (v.Get (), -2);
00750
00751 Ptr<MyNode> b = CreateObject<MyNode> ();
00752 a->SetNodeB (b);
00753 Config::Set ("/NodeA/NodeB/A", IntegerValue (4));
00754 Config::Set ("/NodeA/NodeB/B", IntegerValue (-4));
00755 b->GetAttribute ("A", v);
00756 NS_TEST_ASSERT_EQUAL (v.Get (), 4);
00757 b->GetAttribute ("B", v);
00758 NS_TEST_ASSERT_EQUAL (v.Get (), -4);
00759
00760 Ptr<MyNode> c = CreateObject<MyNode> ();
00761 root->SetNodeB (c);
00762 Config::Set ("/NodeB/A", IntegerValue (5));
00763 Config::Set ("/NodeB/B", IntegerValue (-5));
00764 c->GetAttribute ("A", v);
00765 NS_TEST_ASSERT_EQUAL (v.Get (), 5);
00766 c->GetAttribute ("B", v);
00767 NS_TEST_ASSERT_EQUAL (v.Get (), -5);
00768
00769
00770 Ptr<MyNode> d0 = CreateObject<MyNode> ();
00771 Ptr<MyNode> d1 = CreateObject<MyNode> ();
00772 Ptr<MyNode> d2 = CreateObject<MyNode> ();
00773 Ptr<MyNode> d3 = CreateObject<MyNode> ();
00774 b->AddNodeB (d0);
00775 b->AddNodeB (d1);
00776 b->AddNodeB (d2);
00777 b->AddNodeB (d3);
00778 Config::Set ("/NodeA/NodeB/NodesB/0/A", IntegerValue (-11));
00779 d0->GetAttribute ("A", v);
00780 NS_TEST_ASSERT_EQUAL (v.Get (), -11);
00781 d0->GetAttribute ("B", v);
00782 NS_TEST_ASSERT_EQUAL (v.Get (), 9);
00783 d1->GetAttribute ("A", v);
00784 NS_TEST_ASSERT_EQUAL (v.Get (), 10);
00785 d1->GetAttribute ("B", v);
00786 NS_TEST_ASSERT_EQUAL (v.Get (), 9);
00787 Config::Set ("/NodeA/NodeB/NodesB/0|1/A", IntegerValue (-12));
00788 d0->GetAttribute ("A", v);
00789 NS_TEST_ASSERT_EQUAL (v.Get (), -12);
00790 d1->GetAttribute ("A", v);
00791 NS_TEST_ASSERT_EQUAL (v.Get (), -12);
00792 Config::Set ("/NodeA/NodeB/NodesB/|0|1|/A", IntegerValue (-13));
00793 d0->GetAttribute ("A", v);
00794 NS_TEST_ASSERT_EQUAL (v.Get (), -13);
00795 d1->GetAttribute ("A", v);
00796 NS_TEST_ASSERT_EQUAL (v.Get (), -13);
00797 Config::Set ("/NodeA/NodeB/NodesB/[0-2]/A", IntegerValue (-14));
00798 d0->GetAttribute ("A", v);
00799 NS_TEST_ASSERT_EQUAL (v.Get (), -14);
00800 d1->GetAttribute ("A", v);
00801 NS_TEST_ASSERT_EQUAL (v.Get (), -14);
00802 d2->GetAttribute ("A", v);
00803 NS_TEST_ASSERT_EQUAL (v.Get (), -14);
00804 Config::Set ("/NodeA/NodeB/NodesB/[1-3]/A", IntegerValue (-15));
00805 d0->GetAttribute ("A", v);
00806 NS_TEST_ASSERT_EQUAL (v.Get (), -14);
00807 d1->GetAttribute ("A", v);
00808 NS_TEST_ASSERT_EQUAL (v.Get (), -15);
00809 d2->GetAttribute ("A", v);
00810 NS_TEST_ASSERT_EQUAL (v.Get (), -15);
00811 d3->GetAttribute ("A", v);
00812 NS_TEST_ASSERT_EQUAL (v.Get (), -15);
00813 Config::Set ("/NodeA/NodeB/NodesB/[0-1]|3/A", IntegerValue (-16));
00814 d0->GetAttribute ("A", v);
00815 NS_TEST_ASSERT_EQUAL (v.Get (), -16);
00816 d1->GetAttribute ("A", v);
00817 NS_TEST_ASSERT_EQUAL (v.Get (), -16);
00818 d2->GetAttribute ("A", v);
00819 NS_TEST_ASSERT_EQUAL (v.Get (), -15);
00820 d3->GetAttribute ("A", v);
00821 NS_TEST_ASSERT_EQUAL (v.Get (), -16);
00822
00823
00824 Config::ConnectWithoutContext ("/NodeA/NodeB/NodesB/[0-1]|3/Source",
00825 MakeCallback (&ConfigTest::ChangeNotification, this));
00826 m_traceNotification = 0;
00827
00828 d2->SetAttribute ("Source", IntegerValue (-2));
00829 NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
00830 m_traceNotification = 0;
00831
00832 d1->SetAttribute ("Source", IntegerValue (-3));
00833 NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
00834 Config::DisconnectWithoutContext ("/NodeA/NodeB/NodesB/[0-1]|3/Source",
00835 MakeCallback (&ConfigTest::ChangeNotification, this));
00836 m_traceNotification = 0;
00837
00838 d1->SetAttribute ("Source", IntegerValue (-4));
00839 NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
00840
00841
00842 Config::Connect ("/NodeA/NodeB/NodesB/[0-1]|3/Source",
00843 MakeCallback (&ConfigTest::ChangeNotificationWithPath, this));
00844 m_traceNotification = 0;
00845
00846 d2->SetAttribute ("Source", IntegerValue (-2));
00847 NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
00848 m_traceNotification = 0;
00849 m_tracePath = "";
00850
00851 d1->SetAttribute ("Source", IntegerValue (-3));
00852 NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
00853 NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/1/Source");
00854 m_traceNotification = 0;
00855 m_tracePath = "";
00856
00857 d3->SetAttribute ("Source", IntegerValue (-3));
00858 NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
00859 NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/3/Source");
00860 Config::Disconnect ("/NodeA/NodeB/NodesB/[0-1]|3/Source",
00861 MakeCallback (&ConfigTest::ChangeNotificationWithPath, this));
00862 m_traceNotification = 0;
00863
00864 d1->SetAttribute ("Source", IntegerValue (-4));
00865 NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
00866
00867
00868
00869 return result;
00870 }
00871
00872 }
00873
00874
00875 #endif