4 #include "global-value.h"
5 #include "object-vector.h"
9 NS_LOG_COMPONENT_DEFINE ("Config");
16 ArrayMatcher (std::string element);
17 bool Matches (uint32_t i) const;
19 bool StringToUint32 (std::string str, uint32_t *value) const;
20 std::string m_element;
24 ArrayMatcher::ArrayMatcher (std::string element)
28 ArrayMatcher::Matches (uint32_t i) const
32 NS_LOG_DEBUG ("Array "<<i<<" matches *");
35 std::string::size_type tmp;
36 tmp = m_element.find ("|");
37 if (tmp != std::string::npos)
39 std::string left = m_element.substr (0, tmp-0);
40 std::string right = m_element.substr (tmp+1, m_element.size () - (tmp + 1));
41 ArrayMatcher matcher = ArrayMatcher (left);
42 if (matcher.Matches (i))
44 NS_LOG_DEBUG ("Array "<<i<<" matches "<<left);
47 matcher = ArrayMatcher (right);
48 if (matcher.Matches (i))
50 NS_LOG_DEBUG ("Array "<<i<<" matches "<<right);
53 NS_LOG_DEBUG ("Array "<<i<<" does not match "<<m_element);
56 std::string::size_type leftBracket = m_element.find ("[");
57 std::string::size_type rightBracket = m_element.find ("]");
58 std::string::size_type dash = m_element.find ("-");
59 if (leftBracket == 0 && rightBracket == m_element.size () - 1 &&
60 dash > leftBracket && dash < rightBracket)
62 std::string lowerBound = m_element.substr (leftBracket + 1, dash - (leftBracket + 1));
63 std::string upperBound = m_element.substr (dash + 1, rightBracket - (dash + 1));
66 if (StringToUint32 (lowerBound, &min) &&
67 StringToUint32 (upperBound, &max) &&
70 NS_LOG_DEBUG ("Array "<<i<<" matches "<<m_element);
75 NS_LOG_DEBUG ("Array "<<i<<" does not "<<m_element);
80 if (StringToUint32 (m_element, &value) &&
83 NS_LOG_DEBUG ("Array "<<i<<" matches "<<m_element);
86 NS_LOG_DEBUG ("Array "<<i<<" does not match "<<m_element);
91 ArrayMatcher::StringToUint32 (std::string str, uint32_t *value) const
93 std::istringstream iss;
96 return !iss.bad () && !iss.fail ();
103 Resolver (std::string path);
104 virtual ~Resolver ();
106 void Resolve (Ptr<Object> root);
108 void DoResolve (std::string path, Ptr<Object> root);
109 void DoArrayResolve (std::string path, const ObjectVector &vector);
110 void DoResolveOne (Ptr<Object> object, std::string name);
111 std::string GetResolvedPath (std::string name) const;
112 virtual void DoOne (Ptr<Object> object, std::string path, std::string name) = 0;
113 std::vector<std::string> m_workStack;
117 Resolver::Resolver (std::string path)
120 Resolver::~Resolver ()
124 Resolver::Resolve (Ptr<Object> root)
126 DoResolve (m_path, root);
130 Resolver::GetResolvedPath (std::string name) const
132 std::string fullPath = "";
133 for (std::vector<std::string>::const_iterator i = m_workStack.begin (); i != m_workStack.end (); i++)
135 fullPath += "/" + *i;
137 fullPath += "/" + name;
142 Resolver::DoResolveOne (Ptr<Object> object, std::string name)
144 NS_LOG_DEBUG ("resolved="<<GetResolvedPath (name));
145 DoOne (object, GetResolvedPath (name), name);
149 Resolver::DoResolve (std::string path, Ptr<Object> root)
151 NS_ASSERT (path != "");
152 std::string::size_type pos = path.find ("/");
155 NS_FATAL_ERROR ("path does not start with a \"/\": \""<<path<<"\"");
158 std::string::size_type next = path.find ("/", 1);
159 if (next == std::string::npos)
161 std::string attributeName = path.substr (1, path.size ()-1);
162 NS_LOG_DEBUG ("handle attr="<<attributeName);
163 DoOne (root, GetResolvedPath (attributeName), attributeName);
166 std::string item = path.substr (1, next-1);
167 std::string pathLeft = path.substr (next, path.size ()-next);
169 std::string::size_type dollarPos = item.find ("$");
172 // This is a call to GetObject
173 std::string tidString = item.substr (1, item.size () - 1);
174 NS_LOG_DEBUG ("GetObject="<<tidString<<"on path="<<GetResolvedPath (""));
175 TypeId tid = TypeId::LookupByName (tidString);
176 Ptr<Object> object = root->GetObject<Object> (tid);
179 NS_LOG_DEBUG ("GetObject ("<<tidString<<") failed on path="<<GetResolvedPath (""));
182 m_workStack.push_back (item);
183 DoResolve (pathLeft, object);
184 m_workStack.pop_back ();
188 // this is a normal attribute.
189 TypeId tid = root->GetRealTypeId ();
190 struct TypeId::AttributeInfo info;
191 if (!tid.LookupAttributeByName (item, &info))
193 NS_LOG_DEBUG ("Requested item="<<item<<" does not exist on path="<<GetResolvedPath (""));
196 // attempt to cast to a pointer checker.
197 const PtrChecker *ptr = dynamic_cast<const PtrChecker *> (PeekPointer (info.checker));
200 NS_LOG_DEBUG ("GetAttribute(ptr)="<<item<<" on path="<<GetResolvedPath (""));
201 // XXX: This is not completely right because anything could be stored in a
202 // Ptr<>. We really need to fix this by thinking seriously about our
204 Ptr<Object> object = root->GetAttribute (item);
207 NS_LOG_ERROR ("Requested object name=\""<<item<<
208 "\" exists on path=\""<<GetResolvedPath ("")<<"\""
212 m_workStack.push_back (item);
213 DoResolve (pathLeft, object);
214 m_workStack.pop_back ();
216 // attempt to cast to an object vector.
217 const ObjectVectorChecker *vectorChecker = dynamic_cast<const ObjectVectorChecker *> (PeekPointer (info.checker));
218 if (vectorChecker != 0)
220 NS_LOG_DEBUG ("GetAttribute(vector)="<<item<<" on path="<<GetResolvedPath (""));
221 ObjectVector vector = root->GetAttribute (item);
222 m_workStack.push_back (item);
223 DoArrayResolve (pathLeft, vector);
224 m_workStack.pop_back ();
226 // this could be anything else and we don't know what to do with it.
227 // So, we just ignore it.
232 Resolver::DoArrayResolve (std::string path, const ObjectVector &vector)
234 NS_ASSERT (path != "");
235 std::string::size_type pos = path.find ("/");
238 NS_FATAL_ERROR ("path does not start with a \"/\": \""<<path<<"\"");
241 std::string::size_type next = path.find ("/", 1);
242 if (next == std::string::npos)
244 NS_LOG_DEBUG ("vector path includes no index data on path=\""<<path<<"\"");
247 std::string item = path.substr (1, next-1);
248 std::string pathLeft = path.substr (next, path.size ()-next);
250 ArrayMatcher matcher = ArrayMatcher (item);
251 for (uint32_t i = 0; i < vector.GetN (); i++)
253 if (matcher.Matches (i))
255 std::ostringstream oss;
257 m_workStack.push_back (oss.str ());
258 DoResolve (pathLeft, vector.Get (i));
259 m_workStack.pop_back ();
268 void Set (std::string path, Attribute value);
269 void Connect (std::string path, const CallbackBase &cb);
270 void ConnectWithContext (std::string path, const CallbackBase &cb);
271 void Disconnect (std::string path, const CallbackBase &cb);
273 void RegisterRootNamespaceObject (Ptr<Object> obj);
274 void UnregisterRootNamespaceObject (Ptr<Object> obj);
277 typedef std::vector<Ptr<Object> > Roots;
282 ConfigImpl::Set (std::string path, Attribute value)
284 class SetResolver : public Resolver
287 SetResolver (std::string path, Attribute value)
291 virtual void DoOne (Ptr<Object> object, std::string path, std::string name) {
292 object->SetAttribute (name, m_value);
295 } resolver = SetResolver (path, value);
296 for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
298 resolver.Resolve (*i);
302 ConfigImpl::Connect (std::string path, const CallbackBase &cb)
304 class ConnectResolver : public Resolver
307 ConnectResolver (std::string path, const CallbackBase &cb)
311 virtual void DoOne (Ptr<Object> object, std::string path, std::string name) {
312 object->TraceSourceConnect (name, m_cb);
315 } resolver = ConnectResolver (path, cb);
316 for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
318 resolver.Resolve (*i);
322 ConfigImpl::Disconnect (std::string path, const CallbackBase &cb)
324 class DisconnectResolver : public Resolver
327 DisconnectResolver (std::string path, const CallbackBase &cb)
331 virtual void DoOne (Ptr<Object> object, std::string path, std::string name) {
332 object->TraceSourceDisconnect (name, m_cb);
335 } resolver = DisconnectResolver (path, cb);
336 for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
338 resolver.Resolve (*i);
342 ConfigImpl::ConnectWithContext (std::string path, const CallbackBase &cb)
344 class ConnectWithContextResolver : public Resolver
347 ConnectWithContextResolver (std::string path, const CallbackBase &cb)
351 virtual void DoOne (Ptr<Object> object, std::string path, std::string name) {
352 object->TraceSourceConnectWithContext (name, path, m_cb);
355 } resolver = ConnectWithContextResolver (path, cb);
356 for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
358 resolver.Resolve (*i);
362 ConfigImpl::RegisterRootNamespaceObject (Ptr<Object> obj)
364 m_roots.push_back (obj);
368 ConfigImpl::UnregisterRootNamespaceObject (Ptr<Object> obj)
370 for (std::vector<Ptr<Object> >::iterator i = m_roots.begin (); i != m_roots.end (); i++)
383 void Set (std::string path, Attribute value)
385 Singleton<ConfigImpl>::Get ()->Set (path, value);
387 void SetDefault (std::string name, Attribute value)
389 AttributeList::GetGlobal ()->Set (name, value);
391 void SetGlobal (std::string name, Attribute value)
393 GlobalValue::Bind (name, value);
395 void Connect (std::string path, const CallbackBase &cb)
397 Singleton<ConfigImpl>::Get ()->Connect (path, cb);
399 void Disconnect (std::string path, const CallbackBase &cb)
401 Singleton<ConfigImpl>::Get ()->Disconnect (path, cb);
404 ConnectWithContext (std::string path, const CallbackBase &cb)
406 Singleton<ConfigImpl>::Get ()->ConnectWithContext (path, cb);
409 void RegisterRootNamespaceObject (Ptr<Object> obj)
411 Singleton<ConfigImpl>::Get ()->RegisterRootNamespaceObject (obj);
414 void Unregister (Ptr<Object> obj)
416 Singleton<ConfigImpl>::Get ()->UnregisterRootNamespaceObject (obj);
419 } // namespace Config
423 #ifdef RUN_SELF_TESTS
427 #include "traced-value.h"
428 #include "trace-source-accessor.h"
429 #include "callback.h"
433 class MyNode : public Object
436 static TypeId GetTypeId (void);
438 void AddNodeA (Ptr<MyNode> a);
439 void AddNodeB (Ptr<MyNode> b);
441 void SetNodeA (Ptr<MyNode> a);
442 void SetNodeB (Ptr<MyNode> b);
444 int8_t GetA (void) const;
445 int8_t GetB (void) const;
448 std::vector<Ptr<MyNode> > m_nodesA;
449 std::vector<Ptr<MyNode> > m_nodesB;
454 TracedValue<int16_t> m_trace;
457 TypeId MyNode::GetTypeId (void)
459 static TypeId tid = TypeId ("MyNode")
460 .SetParent<Object> ()
461 .AddAttribute ("NodesA", "",
463 MakeObjectVectorAccessor (&MyNode::m_nodesA),
464 MakeObjectVectorChecker ())
465 .AddAttribute ("NodesB", "",
467 MakeObjectVectorAccessor (&MyNode::m_nodesB),
468 MakeObjectVectorChecker ())
469 .AddAttribute ("NodeA", "",
471 MakePtrAccessor (&MyNode::m_nodeA),
472 MakePtrChecker<MyNode> ())
473 .AddAttribute ("NodeB", "",
475 MakePtrAccessor (&MyNode::m_nodeB),
476 MakePtrChecker<MyNode> ())
477 .AddAttribute ("A", "",
479 MakeIntegerAccessor (&MyNode::m_a),
480 MakeIntegerChecker<int8_t> ())
481 .AddAttribute ("B", "",
483 MakeIntegerAccessor (&MyNode::m_b),
484 MakeIntegerChecker<int8_t> ())
485 .AddAttribute ("Source", "XX",
487 MakeIntegerAccessor (&MyNode::m_trace),
488 MakeIntegerChecker<int16_t> ())
489 .AddTraceSource ("Source", "XX",
490 MakeTraceSourceAccessor (&MyNode::m_trace))
496 MyNode::SetNodeA (Ptr<MyNode> a)
501 MyNode::SetNodeB (Ptr<MyNode> b)
506 MyNode::AddNodeA (Ptr<MyNode> a)
508 m_nodesA.push_back (a);
511 MyNode::AddNodeB (Ptr<MyNode> b)
513 m_nodesB.push_back (b);
516 MyNode::GetA (void) const
521 MyNode::GetB (void) const
527 class ConfigTest : public Test
531 virtual bool RunTests (void);
533 void ChangeNotification (int16_t old, int16_t newValue);
534 void ChangeNotificationWithPath (std::string path, int16_t old, int16_t newValue);
535 int16_t m_traceNotification;
536 std::string m_tracePath;
539 static ConfigTest g_configTestUnique;
541 ConfigTest::ConfigTest ()
546 ConfigTest::ChangeNotification (int16_t oldValue, int16_t newValue)
548 m_traceNotification = newValue;
552 ConfigTest::ChangeNotificationWithPath (std::string path, int16_t old, int16_t newValue)
554 m_traceNotification = newValue;
559 ConfigTest::RunTests (void)
563 Ptr<MyNode> root = CreateObject<MyNode> ();
564 Config::RegisterRootNamespaceObject (root);
565 Config::Set ("/A", Integer (1));
566 Config::Set ("/B", Integer (-1));
567 Integer v = root->GetAttribute ("A");
568 NS_TEST_ASSERT_EQUAL (v.Get (), 1);
569 v = root->GetAttribute ("B");
570 NS_TEST_ASSERT_EQUAL (v.Get (), -1);
572 Ptr<MyNode> a = CreateObject<MyNode> ();
574 Config::Set ("/NodeA/A", Integer (2));
575 Config::Set ("/NodeA/B", Integer (-2));
576 v = a->GetAttribute ("A");
577 NS_TEST_ASSERT_EQUAL (v.Get (), 2);
578 v = a->GetAttribute ("B");
579 NS_TEST_ASSERT_EQUAL (v.Get (), -2);
580 Config::Set ("/NodeB/A", Integer (3));
581 Config::Set ("/NodeB/B", Integer (-3));
582 v = a->GetAttribute ("A");
583 NS_TEST_ASSERT_EQUAL (v.Get (), 2);
584 v = a->GetAttribute ("B");
585 NS_TEST_ASSERT_EQUAL (v.Get (), -2);
587 Ptr<MyNode> b = CreateObject<MyNode> ();
589 Config::Set ("/NodeA/NodeB/A", Integer (4));
590 Config::Set ("/NodeA/NodeB/B", Integer (-4));
591 v = b->GetAttribute ("A");
592 NS_TEST_ASSERT_EQUAL (v.Get (), 4);
593 v = b->GetAttribute ("B");
594 NS_TEST_ASSERT_EQUAL (v.Get (), -4);
596 Ptr<MyNode> c = CreateObject<MyNode> ();
598 Config::Set ("/NodeB/A", Integer (5));
599 Config::Set ("/NodeB/B", Integer (-5));
600 v = c->GetAttribute ("A");
601 NS_TEST_ASSERT_EQUAL (v.Get (), 5);
602 v = c->GetAttribute ("B");
603 NS_TEST_ASSERT_EQUAL (v.Get (), -5);
606 Ptr<MyNode> d0 = CreateObject<MyNode> ();
607 Ptr<MyNode> d1 = CreateObject<MyNode> ();
608 Ptr<MyNode> d2 = CreateObject<MyNode> ();
609 Ptr<MyNode> d3 = CreateObject<MyNode> ();
614 Config::Set ("/NodeA/NodeB/NodesB/0/A", Integer (-11));
615 v = d0->GetAttribute ("A");
616 NS_TEST_ASSERT_EQUAL (v.Get (), -11);
617 v = d0->GetAttribute ("B");
618 NS_TEST_ASSERT_EQUAL (v.Get (), 9);
619 v = d1->GetAttribute ("A");
620 NS_TEST_ASSERT_EQUAL (v.Get (), 10);
621 v = d1->GetAttribute ("B");
622 NS_TEST_ASSERT_EQUAL (v.Get (), 9);
623 Config::Set ("/NodeA/NodeB/NodesB/0|1/A", Integer (-12));
624 v = d0->GetAttribute ("A");
625 NS_TEST_ASSERT_EQUAL (v.Get (), -12);
626 v = d1->GetAttribute ("A");
627 NS_TEST_ASSERT_EQUAL (v.Get (), -12);
628 Config::Set ("/NodeA/NodeB/NodesB/|0|1|/A", Integer (-13));
629 v = d0->GetAttribute ("A");
630 NS_TEST_ASSERT_EQUAL (v.Get (), -13);
631 v = d1->GetAttribute ("A");
632 NS_TEST_ASSERT_EQUAL (v.Get (), -13);
633 Config::Set ("/NodeA/NodeB/NodesB/[0-2]/A", Integer (-14));
634 v = d0->GetAttribute ("A");
635 NS_TEST_ASSERT_EQUAL (v.Get (), -14);
636 v = d1->GetAttribute ("A");
637 NS_TEST_ASSERT_EQUAL (v.Get (), -14);
638 v = d2->GetAttribute ("A");
639 NS_TEST_ASSERT_EQUAL (v.Get (), -14);
640 Config::Set ("/NodeA/NodeB/NodesB/[1-3]/A", Integer (-15));
641 v = d0->GetAttribute ("A");
642 NS_TEST_ASSERT_EQUAL (v.Get (), -14);
643 v = d1->GetAttribute ("A");
644 NS_TEST_ASSERT_EQUAL (v.Get (), -15);
645 v = d2->GetAttribute ("A");
646 NS_TEST_ASSERT_EQUAL (v.Get (), -15);
647 v = d3->GetAttribute ("A");
648 NS_TEST_ASSERT_EQUAL (v.Get (), -15);
649 Config::Set ("/NodeA/NodeB/NodesB/[0-1]|3/A", Integer (-16));
650 v = d0->GetAttribute ("A");
651 NS_TEST_ASSERT_EQUAL (v.Get (), -16);
652 v = d1->GetAttribute ("A");
653 NS_TEST_ASSERT_EQUAL (v.Get (), -16);
654 v = d2->GetAttribute ("A");
655 NS_TEST_ASSERT_EQUAL (v.Get (), -15);
656 v = d3->GetAttribute ("A");
657 NS_TEST_ASSERT_EQUAL (v.Get (), -16);
660 Config::Connect ("/NodeA/NodeB/NodesB/[0-1]|3/Source",
661 MakeCallback (&ConfigTest::ChangeNotification, this));
662 m_traceNotification = 0;
663 // this should trigger no notification
664 d2->SetAttribute ("Source", Integer (-2));
665 NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
666 m_traceNotification = 0;
667 // this should trigger a notification
668 d1->SetAttribute ("Source", Integer (-3));
669 NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
670 Config::Disconnect ("/NodeA/NodeB/NodesB/[0-1]|3/Source",
671 MakeCallback (&ConfigTest::ChangeNotification, this));
672 m_traceNotification = 0;
673 // this should _not_ trigger a notification
674 d1->SetAttribute ("Source", Integer (-4));
675 NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
678 Config::ConnectWithContext ("/NodeA/NodeB/NodesB/[0-1]|3/Source",
679 MakeCallback (&ConfigTest::ChangeNotificationWithPath, this));
680 m_traceNotification = 0;
681 // this should trigger no notification
682 d2->SetAttribute ("Source", Integer (-2));
683 NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
684 m_traceNotification = 0;
686 // this should trigger a notification
687 d1->SetAttribute ("Source", Integer (-3));
688 NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
689 NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/1/Source")
690 m_traceNotification = 0;
692 // this should trigger a notification
693 d3->SetAttribute ("Source", Integer (-3));
694 NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
695 NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/3/Source");
696 // Yes, disconnection _cannot_ work with 'context-based connection.
697 // XXX: what do we do about this ?
698 Config::Disconnect ("/NodeA/NodeB/NodesB/[0-1]|3/Source",
699 MakeCallback (&ConfigTest::ChangeNotificationWithPath, this));
700 m_traceNotification = 0;
701 // this should _not_ trigger a notification
702 d1->SetAttribute ("Source", Integer (-4));
703 NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
713 #endif /* RUN_SELF_TEST */