src/core/config.cc
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Sun, 02 Mar 2008 21:00:37 +0100
changeset 2531 b451b5fc8b57
parent 2504 da3ec9cc3ba3
child 2532 86a40c7cbfe9
permissions -rw-r--r--
implement context-based trace connection
mathieu@2474
     1
#include "config.h"
mathieu@2474
     2
#include "singleton.h"
mathieu@2474
     3
#include "object.h"
mathieu@2474
     4
#include "global-value.h"
mathieu@2474
     5
#include "object-vector.h"
mathieu@2474
     6
#include "log.h"
mathieu@2474
     7
#include <sstream>
mathieu@2474
     8
mathieu@2474
     9
NS_LOG_COMPONENT_DEFINE ("Config");
mathieu@2474
    10
mathieu@2474
    11
namespace ns3 {
mathieu@2474
    12
mathieu@2474
    13
class ArrayMatcher
mathieu@2474
    14
{
mathieu@2474
    15
public:
mathieu@2474
    16
  ArrayMatcher (std::string element);
mathieu@2474
    17
  bool Matches (uint32_t i) const;
mathieu@2474
    18
private:
mathieu@2474
    19
  bool StringToUint32 (std::string str, uint32_t *value) const;
mathieu@2474
    20
  std::string m_element;
mathieu@2474
    21
};
mathieu@2474
    22
mathieu@2474
    23
mathieu@2474
    24
ArrayMatcher::ArrayMatcher (std::string element)
mathieu@2474
    25
  : m_element (element)
mathieu@2474
    26
{}
mathieu@2474
    27
bool 
mathieu@2474
    28
ArrayMatcher::Matches (uint32_t i) const
mathieu@2474
    29
{
mathieu@2474
    30
  if (m_element == "*")
mathieu@2474
    31
    {
mathieu@2474
    32
      NS_LOG_DEBUG ("Array "<<i<<" matches *");
mathieu@2474
    33
      return true;
mathieu@2474
    34
    }
mathieu@2474
    35
  std::string::size_type tmp;
mathieu@2474
    36
  tmp = m_element.find ("|");
mathieu@2474
    37
  if (tmp != std::string::npos)
mathieu@2474
    38
    {
mathieu@2474
    39
      std::string left = m_element.substr (0, tmp-0);
mathieu@2474
    40
      std::string right = m_element.substr (tmp+1, m_element.size () - (tmp + 1));
mathieu@2474
    41
      ArrayMatcher matcher = ArrayMatcher (left);
mathieu@2474
    42
      if (matcher.Matches (i))
mathieu@2474
    43
	{
mathieu@2474
    44
	  NS_LOG_DEBUG ("Array "<<i<<" matches "<<left);
mathieu@2474
    45
	  return true;
mathieu@2474
    46
	}
mathieu@2474
    47
      matcher = ArrayMatcher (right);
mathieu@2474
    48
      if (matcher.Matches (i))
mathieu@2474
    49
	{
mathieu@2474
    50
	  NS_LOG_DEBUG ("Array "<<i<<" matches "<<right);
mathieu@2474
    51
	  return true;
mathieu@2474
    52
	}
mathieu@2474
    53
      NS_LOG_DEBUG ("Array "<<i<<" does not match "<<m_element);
mathieu@2474
    54
      return false;
mathieu@2474
    55
    }
mathieu@2474
    56
  std::string::size_type leftBracket = m_element.find ("[");
mathieu@2474
    57
  std::string::size_type rightBracket = m_element.find ("]");
mathieu@2474
    58
  std::string::size_type dash = m_element.find ("-");
mathieu@2474
    59
  if (leftBracket == 0 && rightBracket == m_element.size () - 1 &&
mathieu@2474
    60
      dash > leftBracket && dash < rightBracket)
mathieu@2474
    61
    {
mathieu@2474
    62
      std::string lowerBound = m_element.substr (leftBracket + 1, dash - (leftBracket + 1));
mathieu@2474
    63
      std::string upperBound = m_element.substr (dash + 1, rightBracket - (dash + 1));
mathieu@2474
    64
      uint32_t min;
mathieu@2474
    65
      uint32_t max;
mathieu@2474
    66
      if (StringToUint32 (lowerBound, &min) && 
mathieu@2474
    67
	  StringToUint32 (upperBound, &max) &&
mathieu@2474
    68
	  i >= min && i <= max)
mathieu@2474
    69
        {
mathieu@2474
    70
	  NS_LOG_DEBUG ("Array "<<i<<" matches "<<m_element);
mathieu@2474
    71
          return true;
mathieu@2474
    72
        }
mathieu@2474
    73
      else
mathieu@2474
    74
	{
mathieu@2474
    75
	  NS_LOG_DEBUG ("Array "<<i<<" does not "<<m_element);
mathieu@2474
    76
	  return false;
mathieu@2474
    77
	}
mathieu@2474
    78
    }
mathieu@2474
    79
  uint32_t value;
mathieu@2474
    80
  if (StringToUint32 (m_element, &value) &&
mathieu@2474
    81
      i == value)
mathieu@2474
    82
    {
mathieu@2474
    83
      NS_LOG_DEBUG ("Array "<<i<<" matches "<<m_element);
mathieu@2474
    84
      return true;
mathieu@2474
    85
    }
mathieu@2474
    86
  NS_LOG_DEBUG ("Array "<<i<<" does not match "<<m_element);
mathieu@2474
    87
  return false;
mathieu@2474
    88
}
mathieu@2474
    89
mathieu@2474
    90
bool
mathieu@2474
    91
ArrayMatcher::StringToUint32 (std::string str, uint32_t *value) const
mathieu@2474
    92
{
mathieu@2474
    93
  std::istringstream iss;
mathieu@2474
    94
  iss.str (str);
mathieu@2474
    95
  iss >> (*value);
mathieu@2474
    96
  return !iss.bad () && !iss.fail ();
mathieu@2474
    97
}
mathieu@2474
    98
mathieu@2474
    99
mathieu@2474
   100
class Resolver
mathieu@2474
   101
{
mathieu@2474
   102
public:
mathieu@2474
   103
  Resolver (std::string path);
mathieu@2474
   104
  virtual ~Resolver ();
mathieu@2474
   105
mathieu@2474
   106
  void Resolve (Ptr<Object> root);
mathieu@2474
   107
private:
mathieu@2474
   108
  void DoResolve (std::string path, Ptr<Object> root);
mathieu@2474
   109
  void DoArrayResolve (std::string path, const ObjectVector &vector);
mathieu@2474
   110
  void DoResolveOne (Ptr<Object> object, std::string name);
mathieu@2474
   111
  std::string GetResolvedPath (std::string name) const;
mathieu@2531
   112
  virtual void DoOne (Ptr<Object> object, std::string path, std::string name) = 0;
mathieu@2474
   113
  std::vector<std::string> m_workStack;
mathieu@2474
   114
  std::string m_path;
mathieu@2474
   115
};
mathieu@2474
   116
mathieu@2474
   117
Resolver::Resolver (std::string path)
mathieu@2474
   118
  : m_path (path)
mathieu@2474
   119
{}
mathieu@2474
   120
Resolver::~Resolver ()
mathieu@2474
   121
{}
mathieu@2474
   122
mathieu@2474
   123
void 
mathieu@2474
   124
Resolver::Resolve (Ptr<Object> root)
mathieu@2474
   125
{
mathieu@2474
   126
  DoResolve (m_path, root);
mathieu@2474
   127
}
mathieu@2474
   128
mathieu@2474
   129
std::string
mathieu@2474
   130
Resolver::GetResolvedPath (std::string name) const
mathieu@2474
   131
{
mathieu@2474
   132
  std::string fullPath = "";
mathieu@2474
   133
  for (std::vector<std::string>::const_iterator i = m_workStack.begin (); i != m_workStack.end (); i++)
mathieu@2474
   134
    {
mathieu@2474
   135
      fullPath += "/" + *i;
mathieu@2474
   136
    }
mathieu@2474
   137
  fullPath += "/" + name;
mathieu@2474
   138
  return fullPath;
mathieu@2474
   139
}
mathieu@2474
   140
mathieu@2474
   141
void 
mathieu@2474
   142
Resolver::DoResolveOne (Ptr<Object> object, std::string name)
mathieu@2474
   143
{
mathieu@2474
   144
  NS_LOG_DEBUG ("resolved="<<GetResolvedPath (name));
mathieu@2531
   145
  DoOne (object, GetResolvedPath (name), name);
mathieu@2474
   146
}
mathieu@2474
   147
mathieu@2474
   148
void
mathieu@2474
   149
Resolver::DoResolve (std::string path, Ptr<Object> root)
mathieu@2474
   150
{
mathieu@2474
   151
  NS_ASSERT (path != "");
mathieu@2474
   152
  std::string::size_type pos = path.find ("/");
mathieu@2474
   153
  if (pos != 0)
mathieu@2474
   154
    {
mathieu@2474
   155
      NS_FATAL_ERROR ("path does not start with a \"/\": \""<<path<<"\"");
mathieu@2474
   156
      return;
mathieu@2474
   157
    }
mathieu@2474
   158
  std::string::size_type next = path.find ("/", 1);
mathieu@2474
   159
  if (next == std::string::npos)
mathieu@2474
   160
    {
mathieu@2474
   161
      std::string attributeName = path.substr (1, path.size ()-1);
mathieu@2474
   162
      NS_LOG_DEBUG ("handle attr="<<attributeName);
mathieu@2531
   163
      DoOne (root, GetResolvedPath (attributeName), attributeName);
mathieu@2474
   164
      return;
mathieu@2474
   165
    }
mathieu@2474
   166
  std::string item = path.substr (1, next-1);
mathieu@2474
   167
  std::string pathLeft = path.substr (next, path.size ()-next);
mathieu@2474
   168
mathieu@2474
   169
  std::string::size_type dollarPos = item.find ("$");
mathieu@2474
   170
  if (dollarPos == 0)
mathieu@2474
   171
    {
mathieu@2474
   172
      // This is a call to GetObject
mathieu@2474
   173
      std::string tidString = item.substr (1, item.size () - 1);
mathieu@2474
   174
      NS_LOG_DEBUG ("GetObject="<<tidString<<"on path="<<GetResolvedPath (""));
mathieu@2474
   175
      TypeId tid = TypeId::LookupByName (tidString);
mathieu@2474
   176
      Ptr<Object> object = root->GetObject<Object> (tid);
mathieu@2474
   177
      if (object == 0)
mathieu@2474
   178
	{
mathieu@2474
   179
	  NS_LOG_DEBUG ("GetObject ("<<tidString<<") failed on path="<<GetResolvedPath (""));
mathieu@2474
   180
	  return;
mathieu@2474
   181
	}
mathieu@2474
   182
      m_workStack.push_back (item);
mathieu@2474
   183
      DoResolve (pathLeft, object);
mathieu@2474
   184
      m_workStack.pop_back ();
mathieu@2474
   185
    }
mathieu@2474
   186
  else 
mathieu@2474
   187
    {
mathieu@2474
   188
      // this is a normal attribute.
mathieu@2474
   189
      TypeId tid = root->GetRealTypeId ();
mathieu@2474
   190
      struct TypeId::AttributeInfo info;
mathieu@2474
   191
      if (!tid.LookupAttributeByName (item, &info))
mathieu@2474
   192
	{
mathieu@2474
   193
	  NS_LOG_DEBUG ("Requested item="<<item<<" does not exist on path="<<GetResolvedPath (""));
mathieu@2474
   194
	  return;
mathieu@2474
   195
	}
mathieu@2474
   196
      // attempt to cast to a pointer checker.
mathieu@2474
   197
      const PtrChecker *ptr = dynamic_cast<const PtrChecker *> (PeekPointer (info.checker));
mathieu@2474
   198
      if (ptr != 0)
mathieu@2474
   199
	{
mathieu@2474
   200
	  NS_LOG_DEBUG ("GetAttribute(ptr)="<<item<<" on path="<<GetResolvedPath (""));
mathieu@2474
   201
	  // XXX: This is not completely right because anything could be stored in a
mathieu@2474
   202
	  // Ptr<>. We really need to fix this by thinking seriously about our
mathieu@2474
   203
	  // object hierarchy.
mathieu@2474
   204
	  Ptr<Object> object = root->GetAttribute (item);
mathieu@2474
   205
	  if (object == 0)
mathieu@2474
   206
	    {
mathieu@2474
   207
	      NS_LOG_ERROR ("Requested object name=\""<<item<<
mathieu@2474
   208
			    "\" exists on path=\""<<GetResolvedPath ("")<<"\""
mathieu@2474
   209
			    " but is null.");
mathieu@2474
   210
	      return;
mathieu@2474
   211
	    }
mathieu@2474
   212
	  m_workStack.push_back (item);
mathieu@2474
   213
	  DoResolve (pathLeft, object);
mathieu@2474
   214
	  m_workStack.pop_back ();
mathieu@2474
   215
	}
mathieu@2474
   216
      // attempt to cast to an object vector.
mathieu@2474
   217
      const ObjectVectorChecker *vectorChecker = dynamic_cast<const ObjectVectorChecker *> (PeekPointer (info.checker));
mathieu@2474
   218
      if (vectorChecker != 0)
mathieu@2474
   219
	{
mathieu@2474
   220
	  NS_LOG_DEBUG ("GetAttribute(vector)="<<item<<" on path="<<GetResolvedPath (""));
mathieu@2474
   221
	  ObjectVector vector = root->GetAttribute (item);
mathieu@2474
   222
	  m_workStack.push_back (item);
mathieu@2474
   223
	  DoArrayResolve (pathLeft, vector);
mathieu@2474
   224
	  m_workStack.pop_back ();
mathieu@2474
   225
	}
mathieu@2474
   226
      // this could be anything else and we don't know what to do with it.
mathieu@2474
   227
      // So, we just ignore it.
mathieu@2474
   228
    }
mathieu@2474
   229
}
mathieu@2474
   230
mathieu@2474
   231
void 
mathieu@2474
   232
Resolver::DoArrayResolve (std::string path, const ObjectVector &vector)
mathieu@2474
   233
{
mathieu@2474
   234
  NS_ASSERT (path != "");
mathieu@2474
   235
  std::string::size_type pos = path.find ("/");
mathieu@2474
   236
  if (pos != 0)
mathieu@2474
   237
    {
mathieu@2474
   238
      NS_FATAL_ERROR ("path does not start with a \"/\": \""<<path<<"\"");
mathieu@2474
   239
      return;
mathieu@2474
   240
    }
mathieu@2474
   241
  std::string::size_type next = path.find ("/", 1);
mathieu@2474
   242
  if (next == std::string::npos)
mathieu@2474
   243
    {
mathieu@2474
   244
      NS_LOG_DEBUG ("vector path includes no index data on path=\""<<path<<"\"");
mathieu@2474
   245
      return;
mathieu@2474
   246
    }
mathieu@2474
   247
  std::string item = path.substr (1, next-1);
mathieu@2474
   248
  std::string pathLeft = path.substr (next, path.size ()-next);
mathieu@2474
   249
mathieu@2474
   250
  ArrayMatcher matcher = ArrayMatcher (item);
mathieu@2474
   251
  for (uint32_t i = 0; i < vector.GetN (); i++)
mathieu@2474
   252
    {
mathieu@2474
   253
      if (matcher.Matches (i))
mathieu@2474
   254
	{
mathieu@2474
   255
	  std::ostringstream oss;
mathieu@2474
   256
	  oss << i;
mathieu@2474
   257
	  m_workStack.push_back (oss.str ());
mathieu@2474
   258
	  DoResolve (pathLeft, vector.Get (i));
mathieu@2474
   259
	  m_workStack.pop_back ();
mathieu@2474
   260
	}
mathieu@2474
   261
    }
mathieu@2474
   262
}
mathieu@2474
   263
mathieu@2474
   264
mathieu@2474
   265
class ConfigImpl 
mathieu@2474
   266
{
mathieu@2474
   267
public:
mathieu@2474
   268
  void Set (std::string path, Attribute value);
mathieu@2474
   269
  void Connect (std::string path, const CallbackBase &cb);
mathieu@2531
   270
  void ConnectWithContext (std::string path, const CallbackBase &cb);
mathieu@2474
   271
  void Disconnect (std::string path, const CallbackBase &cb);
mathieu@2474
   272
mathieu@2474
   273
  void RegisterRootNamespaceObject (Ptr<Object> obj);
mathieu@2474
   274
  void UnregisterRootNamespaceObject (Ptr<Object> obj);
mathieu@2474
   275
  
mathieu@2474
   276
private:
mathieu@2474
   277
  typedef std::vector<Ptr<Object> > Roots;
mathieu@2474
   278
  Roots m_roots;
mathieu@2474
   279
};
mathieu@2474
   280
mathieu@2474
   281
void 
mathieu@2474
   282
ConfigImpl::Set (std::string path, Attribute value)
mathieu@2474
   283
{
mathieu@2474
   284
  class SetResolver : public Resolver 
mathieu@2474
   285
  {
mathieu@2474
   286
  public:
mathieu@2474
   287
    SetResolver (std::string path, Attribute value)
mathieu@2474
   288
      : Resolver (path),
mathieu@2474
   289
	m_value (value) {}
mathieu@2474
   290
  private:
mathieu@2531
   291
    virtual void DoOne (Ptr<Object> object, std::string path, std::string name) {
mathieu@2474
   292
      object->SetAttribute (name, m_value);
mathieu@2474
   293
    }
mathieu@2474
   294
    Attribute m_value;
mathieu@2474
   295
  } resolver = SetResolver (path, value);
mathieu@2474
   296
  for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
mathieu@2474
   297
    {
mathieu@2474
   298
      resolver.Resolve (*i);
mathieu@2474
   299
    }
mathieu@2474
   300
}
mathieu@2474
   301
void 
mathieu@2474
   302
ConfigImpl::Connect (std::string path, const CallbackBase &cb)
mathieu@2474
   303
{
mathieu@2474
   304
  class ConnectResolver : public Resolver 
mathieu@2474
   305
  {
mathieu@2474
   306
  public:
mathieu@2474
   307
    ConnectResolver (std::string path, const CallbackBase &cb)
mathieu@2474
   308
      : Resolver (path),
mathieu@2474
   309
	m_cb (cb) {}
mathieu@2474
   310
  private:
mathieu@2531
   311
    virtual void DoOne (Ptr<Object> object, std::string path, std::string name) {
mathieu@2474
   312
      object->TraceSourceConnect (name, m_cb);
mathieu@2474
   313
    }
mathieu@2474
   314
    CallbackBase m_cb;
mathieu@2474
   315
  } resolver = ConnectResolver (path, cb);
mathieu@2474
   316
  for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
mathieu@2474
   317
    {
mathieu@2474
   318
      resolver.Resolve (*i);
mathieu@2474
   319
    }
mathieu@2474
   320
}
mathieu@2474
   321
void 
mathieu@2474
   322
ConfigImpl::Disconnect (std::string path, const CallbackBase &cb)
mathieu@2474
   323
{
mathieu@2474
   324
  class DisconnectResolver : public Resolver 
mathieu@2474
   325
  {
mathieu@2474
   326
  public:
mathieu@2474
   327
    DisconnectResolver (std::string path, const CallbackBase &cb)
mathieu@2474
   328
      : Resolver (path),
mathieu@2474
   329
	m_cb (cb) {}
mathieu@2474
   330
  private:
mathieu@2531
   331
    virtual void DoOne (Ptr<Object> object, std::string path, std::string name) {
mathieu@2474
   332
      object->TraceSourceDisconnect (name, m_cb);
mathieu@2474
   333
    }
mathieu@2474
   334
    CallbackBase m_cb;
mathieu@2474
   335
  } resolver = DisconnectResolver (path, cb);
mathieu@2474
   336
  for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
mathieu@2474
   337
    {
mathieu@2474
   338
      resolver.Resolve (*i);
mathieu@2474
   339
    }
mathieu@2474
   340
}
mathieu@2474
   341
void 
mathieu@2531
   342
ConfigImpl::ConnectWithContext (std::string path, const CallbackBase &cb)
mathieu@2531
   343
{
mathieu@2531
   344
  class ConnectWithContextResolver : public Resolver 
mathieu@2531
   345
  {
mathieu@2531
   346
  public:
mathieu@2531
   347
    ConnectWithContextResolver (std::string path, const CallbackBase &cb)
mathieu@2531
   348
      : Resolver (path),
mathieu@2531
   349
	m_cb (cb) {}
mathieu@2531
   350
  private:
mathieu@2531
   351
    virtual void DoOne (Ptr<Object> object, std::string path, std::string name) {
mathieu@2531
   352
      object->TraceSourceConnectWithContext (name, path, m_cb);
mathieu@2531
   353
    }
mathieu@2531
   354
    CallbackBase m_cb;
mathieu@2531
   355
  } resolver = ConnectWithContextResolver (path, cb);
mathieu@2531
   356
  for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
mathieu@2531
   357
    {
mathieu@2531
   358
      resolver.Resolve (*i);
mathieu@2531
   359
    }
mathieu@2531
   360
}
mathieu@2531
   361
void 
mathieu@2474
   362
ConfigImpl::RegisterRootNamespaceObject (Ptr<Object> obj)
mathieu@2474
   363
{
mathieu@2474
   364
  m_roots.push_back (obj);
mathieu@2474
   365
}
mathieu@2474
   366
mathieu@2474
   367
void 
mathieu@2474
   368
ConfigImpl::UnregisterRootNamespaceObject (Ptr<Object> obj)
mathieu@2474
   369
{
mathieu@2474
   370
  for (std::vector<Ptr<Object> >::iterator i = m_roots.begin (); i != m_roots.end (); i++)
mathieu@2474
   371
    {
mathieu@2474
   372
      if (*i == obj)
mathieu@2474
   373
	{
mathieu@2474
   374
	  m_roots.erase (i);
mathieu@2474
   375
	  return;
mathieu@2474
   376
	}
mathieu@2474
   377
    }
mathieu@2474
   378
}
mathieu@2474
   379
mathieu@2474
   380
mathieu@2474
   381
namespace Config {
mathieu@2474
   382
mathieu@2474
   383
void Set (std::string path, Attribute value)
mathieu@2474
   384
{
mathieu@2474
   385
  Singleton<ConfigImpl>::Get ()->Set (path, value);
mathieu@2474
   386
}
mathieu@2474
   387
void SetDefault (std::string name, Attribute value)
mathieu@2474
   388
{
mathieu@2474
   389
  AttributeList::GetGlobal ()->Set (name, value);
mathieu@2474
   390
}
mathieu@2474
   391
void SetGlobal (std::string name, Attribute value)
mathieu@2474
   392
{
mathieu@2474
   393
  GlobalValue::Bind (name, value);
mathieu@2474
   394
}
mathieu@2474
   395
void Connect (std::string path, const CallbackBase &cb)
mathieu@2474
   396
{
mathieu@2474
   397
  Singleton<ConfigImpl>::Get ()->Connect (path, cb);
mathieu@2474
   398
}
mathieu@2474
   399
void Disconnect (std::string path, const CallbackBase &cb)
mathieu@2474
   400
{
mathieu@2474
   401
  Singleton<ConfigImpl>::Get ()->Disconnect (path, cb);
mathieu@2474
   402
}
mathieu@2531
   403
void 
mathieu@2531
   404
ConnectWithContext (std::string path, const CallbackBase &cb)
mathieu@2531
   405
{
mathieu@2531
   406
  Singleton<ConfigImpl>::Get ()->ConnectWithContext (path, cb);
mathieu@2531
   407
}
mathieu@2474
   408
mathieu@2474
   409
void RegisterRootNamespaceObject (Ptr<Object> obj)
mathieu@2474
   410
{
mathieu@2474
   411
  Singleton<ConfigImpl>::Get ()->RegisterRootNamespaceObject (obj);
mathieu@2474
   412
}
mathieu@2474
   413
mathieu@2474
   414
void Unregister (Ptr<Object> obj)
mathieu@2474
   415
{
mathieu@2474
   416
  Singleton<ConfigImpl>::Get ()->UnregisterRootNamespaceObject (obj);
mathieu@2474
   417
}
mathieu@2474
   418
mathieu@2474
   419
} // namespace Config
mathieu@2474
   420
mathieu@2474
   421
} // namespace ns3
mathieu@2474
   422
mathieu@2474
   423
#ifdef RUN_SELF_TESTS
mathieu@2474
   424
mathieu@2474
   425
#include "test.h"
mathieu@2474
   426
#include "integer.h"
mathieu@2504
   427
#include "traced-value.h"
mathieu@2504
   428
#include "trace-source-accessor.h"
mathieu@2504
   429
#include "callback.h"
mathieu@2474
   430
mathieu@2474
   431
namespace ns3 {
mathieu@2474
   432
mathieu@2474
   433
class MyNode : public Object
mathieu@2474
   434
{
mathieu@2474
   435
public:
mathieu@2474
   436
  static TypeId GetTypeId (void);
mathieu@2474
   437
mathieu@2474
   438
  void AddNodeA (Ptr<MyNode> a);
mathieu@2474
   439
  void AddNodeB (Ptr<MyNode> b);
mathieu@2474
   440
mathieu@2474
   441
  void SetNodeA (Ptr<MyNode> a);
mathieu@2474
   442
  void SetNodeB (Ptr<MyNode> b);
mathieu@2474
   443
mathieu@2474
   444
  int8_t GetA (void) const;
mathieu@2474
   445
  int8_t GetB (void) const;
mathieu@2474
   446
mathieu@2474
   447
private:
mathieu@2474
   448
  std::vector<Ptr<MyNode> > m_nodesA;
mathieu@2474
   449
  std::vector<Ptr<MyNode> > m_nodesB;
mathieu@2474
   450
  Ptr<MyNode> m_nodeA;
mathieu@2474
   451
  Ptr<MyNode> m_nodeB;
mathieu@2474
   452
  int8_t m_a;
mathieu@2474
   453
  int8_t m_b;
mathieu@2504
   454
  TracedValue<int16_t> m_trace;
mathieu@2474
   455
};
mathieu@2474
   456
mathieu@2474
   457
TypeId MyNode::GetTypeId (void)
mathieu@2474
   458
{
mathieu@2474
   459
  static TypeId tid = TypeId ("MyNode")
mathieu@2474
   460
    .SetParent<Object> ()
mathieu@2474
   461
    .AddAttribute ("NodesA", "",
mathieu@2474
   462
		   ObjectVector (),
mathieu@2474
   463
		   MakeObjectVectorAccessor (&MyNode::m_nodesA),
mathieu@2474
   464
		   MakeObjectVectorChecker ())
mathieu@2474
   465
    .AddAttribute ("NodesB", "",
mathieu@2474
   466
		   ObjectVector (),
mathieu@2474
   467
		   MakeObjectVectorAccessor (&MyNode::m_nodesB),
mathieu@2474
   468
		   MakeObjectVectorChecker ())
mathieu@2474
   469
    .AddAttribute ("NodeA", "",
mathieu@2474
   470
		   Ptr<MyNode> (0),
mathieu@2474
   471
		   MakePtrAccessor (&MyNode::m_nodeA),
mathieu@2474
   472
		   MakePtrChecker<MyNode> ())
mathieu@2474
   473
    .AddAttribute ("NodeB", "",
mathieu@2474
   474
		   Ptr<MyNode> (0),
mathieu@2474
   475
		   MakePtrAccessor (&MyNode::m_nodeB),
mathieu@2474
   476
		   MakePtrChecker<MyNode> ())
mathieu@2474
   477
    .AddAttribute ("A", "",
mathieu@2474
   478
		   Integer (10),
mathieu@2474
   479
		   MakeIntegerAccessor (&MyNode::m_a),
mathieu@2474
   480
		   MakeIntegerChecker<int8_t> ())
mathieu@2474
   481
    .AddAttribute ("B", "",
mathieu@2474
   482
		   Integer (9),
mathieu@2474
   483
		   MakeIntegerAccessor (&MyNode::m_b),
mathieu@2474
   484
		   MakeIntegerChecker<int8_t> ())
mathieu@2504
   485
    .AddAttribute ("Source", "XX",
mathieu@2504
   486
		   Integer (-1),
mathieu@2504
   487
		   MakeIntegerAccessor (&MyNode::m_trace),
mathieu@2504
   488
		   MakeIntegerChecker<int16_t> ())
mathieu@2504
   489
    .AddTraceSource ("Source", "XX",
mathieu@2504
   490
		     MakeTraceSourceAccessor (&MyNode::m_trace))
mathieu@2474
   491
    ;
mathieu@2474
   492
  return tid;
mathieu@2474
   493
}
mathieu@2474
   494
mathieu@2474
   495
void
mathieu@2474
   496
MyNode::SetNodeA (Ptr<MyNode> a)
mathieu@2474
   497
{
mathieu@2474
   498
  m_nodeA = a;
mathieu@2474
   499
}
mathieu@2474
   500
void
mathieu@2474
   501
MyNode::SetNodeB (Ptr<MyNode> b)
mathieu@2474
   502
{
mathieu@2474
   503
  m_nodeB = b;
mathieu@2474
   504
}
mathieu@2474
   505
void 
mathieu@2474
   506
MyNode::AddNodeA (Ptr<MyNode> a)
mathieu@2474
   507
{
mathieu@2474
   508
  m_nodesA.push_back (a);
mathieu@2474
   509
}
mathieu@2474
   510
void 
mathieu@2474
   511
MyNode::AddNodeB (Ptr<MyNode> b)
mathieu@2474
   512
{
mathieu@2474
   513
  m_nodesB.push_back (b);
mathieu@2474
   514
}
mathieu@2474
   515
int8_t 
mathieu@2474
   516
MyNode::GetA (void) const
mathieu@2474
   517
{
mathieu@2474
   518
  return m_a;
mathieu@2474
   519
}
mathieu@2474
   520
int8_t 
mathieu@2474
   521
MyNode::GetB (void) const
mathieu@2474
   522
{
mathieu@2474
   523
  return m_b;
mathieu@2474
   524
}
mathieu@2474
   525
mathieu@2474
   526
mathieu@2474
   527
class ConfigTest : public Test
mathieu@2474
   528
{
mathieu@2474
   529
public:
mathieu@2474
   530
  ConfigTest ();
mathieu@2474
   531
  virtual bool RunTests (void);
mathieu@2504
   532
private:
mathieu@2504
   533
  void ChangeNotification (int16_t old, int16_t newValue);
mathieu@2531
   534
  void ChangeNotificationWithPath (std::string path, int16_t old, int16_t newValue);
mathieu@2504
   535
  int16_t m_traceNotification;
mathieu@2531
   536
  std::string m_tracePath;
mathieu@2474
   537
};
mathieu@2474
   538
mathieu@2474
   539
static ConfigTest g_configTestUnique;
mathieu@2474
   540
mathieu@2474
   541
ConfigTest::ConfigTest ()
mathieu@2474
   542
  : Test ("Config")
mathieu@2474
   543
{}
mathieu@2474
   544
mathieu@2504
   545
void
mathieu@2504
   546
ConfigTest::ChangeNotification (int16_t oldValue, int16_t newValue)
mathieu@2504
   547
{
mathieu@2504
   548
  m_traceNotification = newValue;
mathieu@2504
   549
}
mathieu@2504
   550
mathieu@2531
   551
void 
mathieu@2531
   552
ConfigTest::ChangeNotificationWithPath (std::string path, int16_t old, int16_t newValue)
mathieu@2531
   553
{
mathieu@2531
   554
  m_traceNotification = newValue;
mathieu@2531
   555
  m_tracePath = path;
mathieu@2531
   556
}
mathieu@2531
   557
mathieu@2474
   558
bool
mathieu@2474
   559
ConfigTest::RunTests (void)
mathieu@2474
   560
{
mathieu@2474
   561
  bool result = true;
mathieu@2474
   562
mathieu@2474
   563
  Ptr<MyNode> root = CreateObject<MyNode> ();
mathieu@2474
   564
  Config::RegisterRootNamespaceObject (root);
mathieu@2474
   565
  Config::Set ("/A", Integer (1));
mathieu@2474
   566
  Config::Set ("/B", Integer (-1));
mathieu@2474
   567
  Integer v = root->GetAttribute ("A");
mathieu@2474
   568
  NS_TEST_ASSERT_EQUAL (v.Get (), 1);
mathieu@2474
   569
  v = root->GetAttribute ("B");
mathieu@2474
   570
  NS_TEST_ASSERT_EQUAL (v.Get (), -1);
mathieu@2474
   571
mathieu@2474
   572
  Ptr<MyNode> a = CreateObject<MyNode> ();
mathieu@2474
   573
  root->SetNodeA (a);
mathieu@2474
   574
  Config::Set ("/NodeA/A", Integer (2));
mathieu@2474
   575
  Config::Set ("/NodeA/B", Integer (-2));
mathieu@2474
   576
  v = a->GetAttribute ("A");
mathieu@2474
   577
  NS_TEST_ASSERT_EQUAL (v.Get (), 2);
mathieu@2474
   578
  v = a->GetAttribute ("B");
mathieu@2474
   579
  NS_TEST_ASSERT_EQUAL (v.Get (), -2);
mathieu@2474
   580
  Config::Set ("/NodeB/A", Integer (3));
mathieu@2474
   581
  Config::Set ("/NodeB/B", Integer (-3));
mathieu@2474
   582
  v = a->GetAttribute ("A");
mathieu@2474
   583
  NS_TEST_ASSERT_EQUAL (v.Get (), 2);
mathieu@2474
   584
  v = a->GetAttribute ("B");
mathieu@2474
   585
  NS_TEST_ASSERT_EQUAL (v.Get (), -2);
mathieu@2474
   586
mathieu@2474
   587
  Ptr<MyNode> b = CreateObject<MyNode> ();
mathieu@2474
   588
  a->SetNodeB (b);
mathieu@2474
   589
  Config::Set ("/NodeA/NodeB/A", Integer (4));
mathieu@2474
   590
  Config::Set ("/NodeA/NodeB/B", Integer (-4));
mathieu@2474
   591
  v = b->GetAttribute ("A");
mathieu@2474
   592
  NS_TEST_ASSERT_EQUAL (v.Get (), 4);
mathieu@2474
   593
  v = b->GetAttribute ("B");
mathieu@2474
   594
  NS_TEST_ASSERT_EQUAL (v.Get (), -4);
mathieu@2474
   595
mathieu@2474
   596
  Ptr<MyNode> c = CreateObject<MyNode> ();
mathieu@2474
   597
  root->SetNodeB (c);
mathieu@2474
   598
  Config::Set ("/NodeB/A", Integer (5));
mathieu@2474
   599
  Config::Set ("/NodeB/B", Integer (-5));
mathieu@2474
   600
  v = c->GetAttribute ("A");
mathieu@2474
   601
  NS_TEST_ASSERT_EQUAL (v.Get (), 5);
mathieu@2474
   602
  v = c->GetAttribute ("B");
mathieu@2474
   603
  NS_TEST_ASSERT_EQUAL (v.Get (), -5);
mathieu@2474
   604
mathieu@2474
   605
mathieu@2474
   606
  Ptr<MyNode> d0 = CreateObject<MyNode> ();
mathieu@2474
   607
  Ptr<MyNode> d1 = CreateObject<MyNode> ();
mathieu@2474
   608
  Ptr<MyNode> d2 = CreateObject<MyNode> ();
mathieu@2474
   609
  Ptr<MyNode> d3 = CreateObject<MyNode> ();
mathieu@2474
   610
  b->AddNodeB (d0);
mathieu@2474
   611
  b->AddNodeB (d1);
mathieu@2474
   612
  b->AddNodeB (d2);
mathieu@2474
   613
  b->AddNodeB (d3);
mathieu@2474
   614
  Config::Set ("/NodeA/NodeB/NodesB/0/A", Integer (-11));
mathieu@2474
   615
  v = d0->GetAttribute ("A");
mathieu@2474
   616
  NS_TEST_ASSERT_EQUAL (v.Get (), -11);
mathieu@2474
   617
  v = d0->GetAttribute ("B");
mathieu@2474
   618
  NS_TEST_ASSERT_EQUAL (v.Get (), 9);
mathieu@2474
   619
  v = d1->GetAttribute ("A");
mathieu@2474
   620
  NS_TEST_ASSERT_EQUAL (v.Get (), 10);
mathieu@2474
   621
  v = d1->GetAttribute ("B");
mathieu@2474
   622
  NS_TEST_ASSERT_EQUAL (v.Get (), 9);
mathieu@2474
   623
  Config::Set ("/NodeA/NodeB/NodesB/0|1/A", Integer (-12));
mathieu@2474
   624
  v = d0->GetAttribute ("A");
mathieu@2474
   625
  NS_TEST_ASSERT_EQUAL (v.Get (), -12);
mathieu@2474
   626
  v = d1->GetAttribute ("A");
mathieu@2474
   627
  NS_TEST_ASSERT_EQUAL (v.Get (), -12);
mathieu@2474
   628
  Config::Set ("/NodeA/NodeB/NodesB/|0|1|/A", Integer (-13));
mathieu@2474
   629
  v = d0->GetAttribute ("A");
mathieu@2474
   630
  NS_TEST_ASSERT_EQUAL (v.Get (), -13);
mathieu@2474
   631
  v = d1->GetAttribute ("A");
mathieu@2474
   632
  NS_TEST_ASSERT_EQUAL (v.Get (), -13);
mathieu@2474
   633
  Config::Set ("/NodeA/NodeB/NodesB/[0-2]/A", Integer (-14));
mathieu@2474
   634
  v = d0->GetAttribute ("A");
mathieu@2474
   635
  NS_TEST_ASSERT_EQUAL (v.Get (), -14);
mathieu@2474
   636
  v = d1->GetAttribute ("A");
mathieu@2474
   637
  NS_TEST_ASSERT_EQUAL (v.Get (), -14);
mathieu@2474
   638
  v = d2->GetAttribute ("A");
mathieu@2474
   639
  NS_TEST_ASSERT_EQUAL (v.Get (), -14);
mathieu@2474
   640
  Config::Set ("/NodeA/NodeB/NodesB/[1-3]/A", Integer (-15));
mathieu@2474
   641
  v = d0->GetAttribute ("A");
mathieu@2474
   642
  NS_TEST_ASSERT_EQUAL (v.Get (), -14);
mathieu@2474
   643
  v = d1->GetAttribute ("A");
mathieu@2474
   644
  NS_TEST_ASSERT_EQUAL (v.Get (), -15);
mathieu@2474
   645
  v = d2->GetAttribute ("A");
mathieu@2474
   646
  NS_TEST_ASSERT_EQUAL (v.Get (), -15);
mathieu@2474
   647
  v = d3->GetAttribute ("A");
mathieu@2474
   648
  NS_TEST_ASSERT_EQUAL (v.Get (), -15);
mathieu@2474
   649
  Config::Set ("/NodeA/NodeB/NodesB/[0-1]|3/A", Integer (-16));
mathieu@2474
   650
  v = d0->GetAttribute ("A");
mathieu@2474
   651
  NS_TEST_ASSERT_EQUAL (v.Get (), -16);
mathieu@2474
   652
  v = d1->GetAttribute ("A");
mathieu@2479
   653
  NS_TEST_ASSERT_EQUAL (v.Get (), -16);
mathieu@2479
   654
  v = d2->GetAttribute ("A");
mathieu@2474
   655
  NS_TEST_ASSERT_EQUAL (v.Get (), -15);
mathieu@2475
   656
  v = d3->GetAttribute ("A");
mathieu@2475
   657
  NS_TEST_ASSERT_EQUAL (v.Get (), -16);
mathieu@2474
   658
mathieu@2474
   659
mathieu@2504
   660
  Config::Connect ("/NodeA/NodeB/NodesB/[0-1]|3/Source", 
mathieu@2504
   661
		   MakeCallback (&ConfigTest::ChangeNotification, this));
mathieu@2504
   662
  m_traceNotification = 0;
mathieu@2504
   663
  // this should trigger no notification
mathieu@2504
   664
  d2->SetAttribute ("Source", Integer (-2));
mathieu@2504
   665
  NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
mathieu@2504
   666
  m_traceNotification = 0;
mathieu@2504
   667
  // this should trigger a notification
mathieu@2504
   668
  d1->SetAttribute ("Source", Integer (-3));
mathieu@2504
   669
  NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
mathieu@2504
   670
  Config::Disconnect ("/NodeA/NodeB/NodesB/[0-1]|3/Source", 
mathieu@2504
   671
		      MakeCallback (&ConfigTest::ChangeNotification, this));
mathieu@2504
   672
  m_traceNotification = 0;
mathieu@2504
   673
  // this should _not_ trigger a notification
mathieu@2504
   674
  d1->SetAttribute ("Source", Integer (-4));
mathieu@2504
   675
  NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
mathieu@2504
   676
mathieu@2531
   677
  
mathieu@2531
   678
  Config::ConnectWithContext ("/NodeA/NodeB/NodesB/[0-1]|3/Source", 
mathieu@2531
   679
			      MakeCallback (&ConfigTest::ChangeNotificationWithPath, this));
mathieu@2531
   680
  m_traceNotification = 0;
mathieu@2531
   681
  // this should trigger no notification
mathieu@2531
   682
  d2->SetAttribute ("Source", Integer (-2));
mathieu@2531
   683
  NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
mathieu@2531
   684
  m_traceNotification = 0;
mathieu@2531
   685
  m_tracePath = "";
mathieu@2531
   686
  // this should trigger a notification
mathieu@2531
   687
  d1->SetAttribute ("Source", Integer (-3));
mathieu@2531
   688
  NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
mathieu@2531
   689
  NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/1/Source")
mathieu@2531
   690
  m_traceNotification = 0;
mathieu@2531
   691
  m_tracePath = "";
mathieu@2531
   692
  // this should trigger a notification
mathieu@2531
   693
  d3->SetAttribute ("Source", Integer (-3));
mathieu@2531
   694
  NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
mathieu@2531
   695
  NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/3/Source");
mathieu@2531
   696
  // Yes, disconnection _cannot_ work with 'context-based connection.
mathieu@2531
   697
  // XXX: what do we do about this ?
mathieu@2531
   698
  Config::Disconnect ("/NodeA/NodeB/NodesB/[0-1]|3/Source", 
mathieu@2531
   699
		      MakeCallback (&ConfigTest::ChangeNotificationWithPath, this));
mathieu@2531
   700
  m_traceNotification = 0;
mathieu@2531
   701
  // this should _not_ trigger a notification
mathieu@2531
   702
  d1->SetAttribute ("Source", Integer (-4));
mathieu@2531
   703
  NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
mathieu@2531
   704
mathieu@2504
   705
mathieu@2474
   706
mathieu@2474
   707
  return result;
mathieu@2474
   708
}
mathieu@2474
   709
mathieu@2474
   710
} // namespace ns3
mathieu@2474
   711
mathieu@2474
   712
mathieu@2474
   713
#endif /* RUN_SELF_TEST */