src/core/config.cc
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Sat, 04 Jul 2009 08:15:48 +0200
changeset 4654 2eaebe77d66b
parent 4147 5d8530130930
permissions -rw-r--r--
Added tag ns-3.5 for changeset c975274c9707
mathieu@2586
     1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
mathieu@2586
     2
/*
mathieu@2586
     3
 * Copyright (c) 2008 INRIA
mathieu@2586
     4
 *
mathieu@2586
     5
 * This program is free software; you can redistribute it and/or modify
mathieu@2586
     6
 * it under the terms of the GNU General Public License version 2 as
mathieu@2586
     7
 * published by the Free Software Foundation;
mathieu@2586
     8
 *
mathieu@2586
     9
 * This program is distributed in the hope that it will be useful,
mathieu@2586
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
mathieu@2586
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
mathieu@2586
    12
 * GNU General Public License for more details.
mathieu@2586
    13
 *
mathieu@2586
    14
 * You should have received a copy of the GNU General Public License
mathieu@2586
    15
 * along with this program; if not, write to the Free Software
mathieu@2586
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
mathieu@2586
    17
 *
mathieu@2586
    18
 * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
mathieu@2586
    19
 */
mathieu@2474
    20
#include "config.h"
mathieu@2474
    21
#include "singleton.h"
mathieu@2474
    22
#include "object.h"
mathieu@2474
    23
#include "global-value.h"
mathieu@2474
    24
#include "object-vector.h"
craigdo@4147
    25
#include "names.h"
mathieu@2927
    26
#include "pointer.h"
mathieu@2474
    27
#include "log.h"
mathieu@2474
    28
#include <sstream>
mathieu@2474
    29
mathieu@2474
    30
NS_LOG_COMPONENT_DEFINE ("Config");
mathieu@2474
    31
mathieu@2474
    32
namespace ns3 {
mathieu@2474
    33
mathieu@3787
    34
namespace Config {
mathieu@3787
    35
mathieu@3787
    36
MatchContainer::MatchContainer ()
mathieu@3787
    37
{}
mathieu@3787
    38
MatchContainer::MatchContainer (const std::vector<Ptr<Object> > &objects, 
mathieu@3787
    39
                                const std::vector<std::string> &contexts,
mathieu@3787
    40
                                std::string path)
mathieu@3787
    41
  : m_objects (objects),
mathieu@3787
    42
    m_contexts (contexts),
mathieu@3787
    43
    m_path (path)
mathieu@3787
    44
{}
mathieu@3787
    45
MatchContainer::Iterator 
mathieu@3787
    46
MatchContainer::Begin (void) const
mathieu@3787
    47
{
mathieu@3787
    48
  return m_objects.begin ();
mathieu@3787
    49
}
mathieu@3787
    50
MatchContainer::Iterator 
mathieu@3787
    51
MatchContainer::End (void) const
mathieu@3787
    52
{
mathieu@3787
    53
  return m_objects.end ();
mathieu@3787
    54
}
mathieu@3787
    55
uint32_t 
mathieu@3787
    56
MatchContainer::GetN (void) const
mathieu@3787
    57
{
mathieu@3787
    58
  return m_objects.size ();
mathieu@3787
    59
}
mathieu@3787
    60
Ptr<Object> 
mathieu@3787
    61
MatchContainer::Get (uint32_t i) const
mathieu@3787
    62
{
mathieu@3787
    63
  return m_objects[i];
mathieu@3787
    64
}
mathieu@3787
    65
std::string 
mathieu@3787
    66
MatchContainer::GetMatchedPath (uint32_t i) const
mathieu@3787
    67
{
mathieu@3787
    68
  return m_contexts[i];
mathieu@3787
    69
}
mathieu@3787
    70
std::string 
mathieu@3787
    71
MatchContainer::GetPath (void) const
mathieu@3787
    72
{
mathieu@3787
    73
  return m_path;
mathieu@3787
    74
}
mathieu@3787
    75
mathieu@3787
    76
void 
mathieu@3787
    77
MatchContainer::Set (std::string name, const AttributeValue &value)
mathieu@3787
    78
{
mathieu@3787
    79
  for (Iterator tmp = Begin (); tmp != End (); ++tmp)
mathieu@3787
    80
    {
mathieu@3787
    81
      Ptr<Object> object = *tmp;
mathieu@3787
    82
      object->SetAttribute (name, value);
mathieu@3787
    83
    }
mathieu@3787
    84
}
mathieu@3787
    85
void 
mathieu@3787
    86
MatchContainer::Connect (std::string name, const CallbackBase &cb)
mathieu@3787
    87
{
mathieu@3787
    88
  NS_ASSERT (m_objects.size () == m_contexts.size ());
mathieu@3787
    89
  for (uint32_t i = 0; i < m_objects.size (); ++i)
mathieu@3787
    90
    {
mathieu@3787
    91
      Ptr<Object> object = m_objects[i];
mathieu@3787
    92
      std::string ctx = m_contexts[i] + name;
mathieu@3787
    93
      object->TraceConnect (name, ctx, cb);
mathieu@3787
    94
    }
mathieu@3787
    95
}
mathieu@3787
    96
void 
mathieu@3787
    97
MatchContainer::ConnectWithoutContext (std::string name, const CallbackBase &cb)
mathieu@3787
    98
{
mathieu@3787
    99
  for (Iterator tmp = Begin (); tmp != End (); ++tmp)
mathieu@3787
   100
    {
mathieu@3787
   101
      Ptr<Object> object = *tmp;
mathieu@3787
   102
      object->TraceConnectWithoutContext (name, cb);
mathieu@3787
   103
    }
mathieu@3787
   104
}
mathieu@3787
   105
void 
mathieu@3787
   106
MatchContainer::Disconnect (std::string name, const CallbackBase &cb)
mathieu@3787
   107
{
mathieu@3787
   108
  NS_ASSERT (m_objects.size () == m_contexts.size ());
mathieu@3787
   109
  for (uint32_t i = 0; i < m_objects.size (); ++i)
mathieu@3787
   110
    {
mathieu@3787
   111
      Ptr<Object> object = m_objects[i];
mathieu@3787
   112
      std::string ctx = m_contexts[i] + name;
mathieu@3787
   113
      object->TraceDisconnect (name, ctx, cb);
mathieu@3787
   114
    }
mathieu@3787
   115
}
mathieu@3787
   116
void 
mathieu@3787
   117
MatchContainer::DisconnectWithoutContext (std::string name, const CallbackBase &cb)
mathieu@3787
   118
{
mathieu@3787
   119
  for (Iterator tmp = Begin (); tmp != End (); ++tmp)
mathieu@3787
   120
    {
mathieu@3787
   121
      Ptr<Object> object = *tmp;
mathieu@3787
   122
      object->TraceDisconnectWithoutContext (name, cb);
mathieu@3787
   123
    }
mathieu@3787
   124
}
mathieu@3787
   125
mathieu@3787
   126
} // namespace Config
mathieu@3787
   127
mathieu@2474
   128
class ArrayMatcher
mathieu@2474
   129
{
mathieu@2474
   130
public:
mathieu@2474
   131
  ArrayMatcher (std::string element);
mathieu@2474
   132
  bool Matches (uint32_t i) const;
mathieu@2474
   133
private:
mathieu@2474
   134
  bool StringToUint32 (std::string str, uint32_t *value) const;
mathieu@2474
   135
  std::string m_element;
mathieu@2474
   136
};
mathieu@2474
   137
mathieu@2474
   138
mathieu@2474
   139
ArrayMatcher::ArrayMatcher (std::string element)
mathieu@2474
   140
  : m_element (element)
mathieu@2474
   141
{}
mathieu@2474
   142
bool 
mathieu@2474
   143
ArrayMatcher::Matches (uint32_t i) const
mathieu@2474
   144
{
mathieu@2474
   145
  if (m_element == "*")
mathieu@2474
   146
    {
mathieu@2474
   147
      NS_LOG_DEBUG ("Array "<<i<<" matches *");
mathieu@2474
   148
      return true;
mathieu@2474
   149
    }
mathieu@2474
   150
  std::string::size_type tmp;
mathieu@2474
   151
  tmp = m_element.find ("|");
mathieu@2474
   152
  if (tmp != std::string::npos)
mathieu@2474
   153
    {
mathieu@2474
   154
      std::string left = m_element.substr (0, tmp-0);
mathieu@2474
   155
      std::string right = m_element.substr (tmp+1, m_element.size () - (tmp + 1));
mathieu@2474
   156
      ArrayMatcher matcher = ArrayMatcher (left);
mathieu@2474
   157
      if (matcher.Matches (i))
mathieu@2474
   158
	{
mathieu@2474
   159
	  NS_LOG_DEBUG ("Array "<<i<<" matches "<<left);
mathieu@2474
   160
	  return true;
mathieu@2474
   161
	}
mathieu@2474
   162
      matcher = ArrayMatcher (right);
mathieu@2474
   163
      if (matcher.Matches (i))
mathieu@2474
   164
	{
mathieu@2474
   165
	  NS_LOG_DEBUG ("Array "<<i<<" matches "<<right);
mathieu@2474
   166
	  return true;
mathieu@2474
   167
	}
mathieu@2474
   168
      NS_LOG_DEBUG ("Array "<<i<<" does not match "<<m_element);
mathieu@2474
   169
      return false;
mathieu@2474
   170
    }
mathieu@2474
   171
  std::string::size_type leftBracket = m_element.find ("[");
mathieu@2474
   172
  std::string::size_type rightBracket = m_element.find ("]");
mathieu@2474
   173
  std::string::size_type dash = m_element.find ("-");
mathieu@2474
   174
  if (leftBracket == 0 && rightBracket == m_element.size () - 1 &&
mathieu@2474
   175
      dash > leftBracket && dash < rightBracket)
mathieu@2474
   176
    {
mathieu@2474
   177
      std::string lowerBound = m_element.substr (leftBracket + 1, dash - (leftBracket + 1));
mathieu@2474
   178
      std::string upperBound = m_element.substr (dash + 1, rightBracket - (dash + 1));
mathieu@2474
   179
      uint32_t min;
mathieu@2474
   180
      uint32_t max;
mathieu@2474
   181
      if (StringToUint32 (lowerBound, &min) && 
mathieu@2474
   182
	  StringToUint32 (upperBound, &max) &&
mathieu@2474
   183
	  i >= min && i <= max)
mathieu@2474
   184
        {
mathieu@2474
   185
	  NS_LOG_DEBUG ("Array "<<i<<" matches "<<m_element);
mathieu@2474
   186
          return true;
mathieu@2474
   187
        }
mathieu@2474
   188
      else
mathieu@2474
   189
	{
mathieu@2474
   190
	  NS_LOG_DEBUG ("Array "<<i<<" does not "<<m_element);
mathieu@2474
   191
	  return false;
mathieu@2474
   192
	}
mathieu@2474
   193
    }
mathieu@2474
   194
  uint32_t value;
mathieu@2474
   195
  if (StringToUint32 (m_element, &value) &&
mathieu@2474
   196
      i == value)
mathieu@2474
   197
    {
mathieu@2474
   198
      NS_LOG_DEBUG ("Array "<<i<<" matches "<<m_element);
mathieu@2474
   199
      return true;
mathieu@2474
   200
    }
mathieu@2474
   201
  NS_LOG_DEBUG ("Array "<<i<<" does not match "<<m_element);
mathieu@2474
   202
  return false;
mathieu@2474
   203
}
mathieu@2474
   204
mathieu@2474
   205
bool
mathieu@2474
   206
ArrayMatcher::StringToUint32 (std::string str, uint32_t *value) const
mathieu@2474
   207
{
mathieu@2474
   208
  std::istringstream iss;
mathieu@2474
   209
  iss.str (str);
mathieu@2474
   210
  iss >> (*value);
mathieu@2474
   211
  return !iss.bad () && !iss.fail ();
mathieu@2474
   212
}
mathieu@2474
   213
mathieu@2474
   214
mathieu@2474
   215
class Resolver
mathieu@2474
   216
{
mathieu@2474
   217
public:
mathieu@2474
   218
  Resolver (std::string path);
mathieu@2474
   219
  virtual ~Resolver ();
mathieu@2474
   220
mathieu@2474
   221
  void Resolve (Ptr<Object> root);
mathieu@2474
   222
private:
mathieu@3787
   223
  void Canonicalize (void);
mathieu@2474
   224
  void DoResolve (std::string path, Ptr<Object> root);
mathieu@2965
   225
  void DoArrayResolve (std::string path, const ObjectVectorValue &vector);
mathieu@3787
   226
  void DoResolveOne (Ptr<Object> object);
mathieu@3787
   227
  std::string GetResolvedPath (void) const;
mathieu@3787
   228
  virtual void DoOne (Ptr<Object> object, std::string path) = 0;
mathieu@2474
   229
  std::vector<std::string> m_workStack;
mathieu@2474
   230
  std::string m_path;
mathieu@2474
   231
};
mathieu@2474
   232
mathieu@2474
   233
Resolver::Resolver (std::string path)
mathieu@2474
   234
  : m_path (path)
mathieu@3787
   235
{
mathieu@3787
   236
  Canonicalize ();
mathieu@3787
   237
}
mathieu@2474
   238
Resolver::~Resolver ()
mathieu@2474
   239
{}
mathieu@3787
   240
void
mathieu@3787
   241
Resolver::Canonicalize (void)
mathieu@3787
   242
{
mathieu@3787
   243
  // ensure that we start and end with a '/'
mathieu@3787
   244
  std::string::size_type tmp = m_path.find ("/");
mathieu@3787
   245
  if (tmp != 0)
mathieu@3787
   246
    {
mathieu@3787
   247
      // no slash at start
mathieu@3787
   248
      m_path = "/" + m_path;
mathieu@3787
   249
    }
mathieu@3787
   250
  tmp = m_path.find_last_of ("/");
mathieu@3787
   251
  if (tmp != (m_path.size () - 1))
mathieu@3787
   252
    {
mathieu@3787
   253
      // no slash at end
mathieu@3787
   254
      m_path = m_path + "/";
mathieu@3787
   255
    }
mathieu@3787
   256
}
mathieu@2474
   257
mathieu@2474
   258
void 
mathieu@2474
   259
Resolver::Resolve (Ptr<Object> root)
mathieu@2474
   260
{
mathieu@2474
   261
  DoResolve (m_path, root);
mathieu@2474
   262
}
mathieu@2474
   263
mathieu@2474
   264
std::string
mathieu@3787
   265
Resolver::GetResolvedPath (void) const
mathieu@2474
   266
{
mathieu@3787
   267
  std::string fullPath = "/";
mathieu@2474
   268
  for (std::vector<std::string>::const_iterator i = m_workStack.begin (); i != m_workStack.end (); i++)
mathieu@2474
   269
    {
mathieu@3787
   270
      fullPath += *i + "/";
mathieu@2474
   271
    }
mathieu@2474
   272
  return fullPath;
mathieu@2474
   273
}
mathieu@2474
   274
mathieu@2474
   275
void 
mathieu@3787
   276
Resolver::DoResolveOne (Ptr<Object> object)
mathieu@2474
   277
{
mathieu@3787
   278
  NS_LOG_DEBUG ("resolved="<<GetResolvedPath ());
mathieu@3787
   279
  DoOne (object, GetResolvedPath ());
mathieu@2474
   280
}
mathieu@2474
   281
mathieu@2474
   282
void
mathieu@2474
   283
Resolver::DoResolve (std::string path, Ptr<Object> root)
mathieu@2474
   284
{
mathieu@3787
   285
  NS_LOG_FUNCTION (path << root);
mathieu@3787
   286
  std::string::size_type tmp;
mathieu@3787
   287
  tmp = path.find ("/");
mathieu@3787
   288
  NS_ASSERT (tmp == 0);
mathieu@2474
   289
  std::string::size_type next = path.find ("/", 1);
craigdo@4143
   290
mathieu@2474
   291
  if (next == std::string::npos)
mathieu@2474
   292
    {
craigdo@4143
   293
      //
craigdo@4143
   294
      // If root is zero, we're beginning to see if we can use the object name 
craigdo@4143
   295
      // service to resolve this path.  It is impossible to have a object name 
craigdo@4143
   296
      // associated with the root of the object name service since that root
craigdo@4143
   297
      // is not an object.  This path must be referring to something in another
craigdo@4143
   298
      // namespace and it will have been found already since the name service
craigdo@4143
   299
      // is always consulted last.
craigdo@4143
   300
      // 
craigdo@4143
   301
      if (root)
craigdo@4143
   302
        {
craigdo@4143
   303
          DoResolveOne (root);
craigdo@4143
   304
        }
mathieu@2474
   305
      return;
mathieu@2474
   306
    }
mathieu@2474
   307
  std::string item = path.substr (1, next-1);
mathieu@2474
   308
  std::string pathLeft = path.substr (next, path.size ()-next);
mathieu@2474
   309
craigdo@4139
   310
  //
craigdo@4139
   311
  // If root is zero, we're beginning to see if we can use the object name 
craigdo@4139
   312
  // service to resolve this path.  In this case, we must see the name space 
craigdo@4139
   313
  // "/Names" on the front of this path.  There is no object associated with 
craigdo@4139
   314
  // the root of the "/Names" namespace, so we just ignore it and move on to 
craigdo@4139
   315
  // the next segment.
craigdo@4139
   316
  //
craigdo@4139
   317
  if (root == 0)
craigdo@4139
   318
    {
craigdo@4139
   319
      std::string::size_type offset = path.find ("/Names");
craigdo@4139
   320
      if (offset == 0)
craigdo@4139
   321
        {
craigdo@4139
   322
          m_workStack.push_back (item);
craigdo@4139
   323
          DoResolve (pathLeft, root);
craigdo@4139
   324
          m_workStack.pop_back ();
craigdo@4139
   325
          return;
craigdo@4139
   326
        }
craigdo@4139
   327
    }
craigdo@4139
   328
craigdo@4139
   329
  //
craigdo@4139
   330
  // We have an item (possibly a segment of a namespace path.  Check to see if
craigdo@4139
   331
  // we can determine that this segment refers to a named object.  If root is
craigdo@4139
   332
  // zero, this means to look in the root of the "/Names" name space, otherwise
craigdo@4139
   333
  // it refers to a name space context (level).
craigdo@4139
   334
  //
craigdo@4158
   335
  Ptr<Object> namedObject = Names::Find<Object> (root, item);
craigdo@4139
   336
  if (namedObject)
craigdo@4139
   337
    {
craigdo@4139
   338
      NS_LOG_DEBUG ("Name system resolved item = " << item << " to " << namedObject);
craigdo@4139
   339
      m_workStack.push_back (item);
craigdo@4139
   340
      DoResolve (pathLeft, namedObject);
craigdo@4139
   341
      m_workStack.pop_back ();
craigdo@4139
   342
      return;
craigdo@4139
   343
    }
craigdo@4139
   344
craigdo@4139
   345
  //
craigdo@4139
   346
  // We're done with the object name service hooks, so proceed down the path
craigdo@4142
   347
  // of types and attributes; but only if root is nonzero.  If root is zero
craigdo@4142
   348
  // and we find ourselves here, we are trying to check in the namespace for
craigdo@4142
   349
  // a path that is not in the "/Names" namespace.  We will have previously
craigdo@4142
   350
  // found any matches, so we just bail out.
craigdo@4139
   351
  //
craigdo@4142
   352
  if (root == 0)
craigdo@4142
   353
    {
craigdo@4142
   354
      return;
craigdo@4142
   355
    }
mathieu@2474
   356
  std::string::size_type dollarPos = item.find ("$");
mathieu@2474
   357
  if (dollarPos == 0)
mathieu@2474
   358
    {
mathieu@2474
   359
      // This is a call to GetObject
mathieu@2474
   360
      std::string tidString = item.substr (1, item.size () - 1);
mathieu@3787
   361
      NS_LOG_DEBUG ("GetObject="<<tidString<<" on path="<<GetResolvedPath ());
mathieu@2474
   362
      TypeId tid = TypeId::LookupByName (tidString);
mathieu@2474
   363
      Ptr<Object> object = root->GetObject<Object> (tid);
mathieu@2474
   364
      if (object == 0)
mathieu@2474
   365
	{
mathieu@3787
   366
	  NS_LOG_DEBUG ("GetObject ("<<tidString<<") failed on path="<<GetResolvedPath ());
mathieu@2474
   367
	  return;
mathieu@2474
   368
	}
mathieu@2474
   369
      m_workStack.push_back (item);
mathieu@2474
   370
      DoResolve (pathLeft, object);
mathieu@2474
   371
      m_workStack.pop_back ();
mathieu@2474
   372
    }
mathieu@2474
   373
  else 
mathieu@2474
   374
    {
mathieu@2474
   375
      // this is a normal attribute.
mathieu@2634
   376
      TypeId tid = root->GetInstanceTypeId ();
mathieu@2474
   377
      struct TypeId::AttributeInfo info;
mathieu@2474
   378
      if (!tid.LookupAttributeByName (item, &info))
mathieu@2474
   379
	{
mathieu@3787
   380
	  NS_LOG_DEBUG ("Requested item="<<item<<" does not exist on path="<<GetResolvedPath ());
mathieu@2474
   381
	  return;
mathieu@2474
   382
	}
mathieu@2474
   383
      // attempt to cast to a pointer checker.
mathieu@2927
   384
      const PointerChecker *ptr = dynamic_cast<const PointerChecker *> (PeekPointer (info.checker));
mathieu@2474
   385
      if (ptr != 0)
mathieu@2474
   386
	{
mathieu@3787
   387
	  NS_LOG_DEBUG ("GetAttribute(ptr)="<<item<<" on path="<<GetResolvedPath ());
mathieu@2965
   388
          PointerValue ptr;
mathieu@2965
   389
          root->GetAttribute (item, ptr);
mathieu@2965
   390
	  Ptr<Object> object = ptr.Get<Object> ();
mathieu@2474
   391
	  if (object == 0)
mathieu@2474
   392
	    {
mathieu@2474
   393
	      NS_LOG_ERROR ("Requested object name=\""<<item<<
mathieu@3787
   394
			    "\" exists on path=\""<<GetResolvedPath ()<<"\""
mathieu@2474
   395
			    " but is null.");
mathieu@2474
   396
	      return;
mathieu@2474
   397
	    }
mathieu@2474
   398
	  m_workStack.push_back (item);
mathieu@2474
   399
	  DoResolve (pathLeft, object);
mathieu@2474
   400
	  m_workStack.pop_back ();
mathieu@2474
   401
	}
mathieu@2474
   402
      // attempt to cast to an object vector.
mathieu@2474
   403
      const ObjectVectorChecker *vectorChecker = dynamic_cast<const ObjectVectorChecker *> (PeekPointer (info.checker));
mathieu@2474
   404
      if (vectorChecker != 0)
mathieu@2474
   405
	{
mathieu@3787
   406
	  NS_LOG_DEBUG ("GetAttribute(vector)="<<item<<" on path="<<GetResolvedPath ());
mathieu@2965
   407
	  ObjectVectorValue vector;
mathieu@2965
   408
          root->GetAttribute (item, vector);
mathieu@2474
   409
	  m_workStack.push_back (item);
mathieu@2474
   410
	  DoArrayResolve (pathLeft, vector);
mathieu@2474
   411
	  m_workStack.pop_back ();
mathieu@2474
   412
	}
mathieu@2474
   413
      // this could be anything else and we don't know what to do with it.
mathieu@2474
   414
      // So, we just ignore it.
mathieu@2474
   415
    }
mathieu@2474
   416
}
mathieu@2474
   417
mathieu@2474
   418
void 
mathieu@2965
   419
Resolver::DoArrayResolve (std::string path, const ObjectVectorValue &vector)
mathieu@2474
   420
{
mathieu@2474
   421
  NS_ASSERT (path != "");
mathieu@3787
   422
  std::string::size_type tmp;
mathieu@3787
   423
  tmp = path.find ("/");
mathieu@3787
   424
  NS_ASSERT (tmp == 0);
mathieu@2474
   425
  std::string::size_type next = path.find ("/", 1);
mathieu@2474
   426
  if (next == std::string::npos)
mathieu@2474
   427
    {
mathieu@3787
   428
      NS_FATAL_ERROR ("vector path includes no index data on path=\""<<path<<"\"");
mathieu@2474
   429
    }
mathieu@2474
   430
  std::string item = path.substr (1, next-1);
mathieu@2474
   431
  std::string pathLeft = path.substr (next, path.size ()-next);
mathieu@2474
   432
mathieu@2474
   433
  ArrayMatcher matcher = ArrayMatcher (item);
mathieu@2474
   434
  for (uint32_t i = 0; i < vector.GetN (); i++)
mathieu@2474
   435
    {
mathieu@2474
   436
      if (matcher.Matches (i))
mathieu@2474
   437
	{
mathieu@2474
   438
	  std::ostringstream oss;
mathieu@2474
   439
	  oss << i;
mathieu@2474
   440
	  m_workStack.push_back (oss.str ());
mathieu@2474
   441
	  DoResolve (pathLeft, vector.Get (i));
mathieu@2474
   442
	  m_workStack.pop_back ();
mathieu@2474
   443
	}
mathieu@2474
   444
    }
mathieu@2474
   445
}
mathieu@2474
   446
mathieu@2474
   447
mathieu@2474
   448
class ConfigImpl 
mathieu@2474
   449
{
mathieu@2474
   450
public:
mathieu@2965
   451
  void Set (std::string path, const AttributeValue &value);
mathieu@2594
   452
  void ConnectWithoutContext (std::string path, const CallbackBase &cb);
mathieu@2474
   453
  void Connect (std::string path, const CallbackBase &cb);
mathieu@2594
   454
  void DisconnectWithoutContext (std::string path, const CallbackBase &cb);
mathieu@2474
   455
  void Disconnect (std::string path, const CallbackBase &cb);
mathieu@3787
   456
  Config::MatchContainer LookupMatches (std::string path);
mathieu@2474
   457
mathieu@2474
   458
  void RegisterRootNamespaceObject (Ptr<Object> obj);
mathieu@2474
   459
  void UnregisterRootNamespaceObject (Ptr<Object> obj);
mathieu@2941
   460
mathieu@2941
   461
  uint32_t GetRootNamespaceObjectN (void) const;
mathieu@2941
   462
  Ptr<Object> GetRootNamespaceObject (uint32_t i) const;
mathieu@2474
   463
  
mathieu@2474
   464
private:
mathieu@3787
   465
  void ParsePath (std::string path, std::string *root, std::string *leaf) const;
mathieu@2474
   466
  typedef std::vector<Ptr<Object> > Roots;
mathieu@2474
   467
  Roots m_roots;
mathieu@2474
   468
};
mathieu@2474
   469
mathieu@2474
   470
void 
mathieu@3787
   471
ConfigImpl::ParsePath (std::string path, std::string *root, std::string *leaf) const
mathieu@3787
   472
{
mathieu@3787
   473
  std::string::size_type slash = path.find_last_of ("/");
mathieu@3787
   474
  NS_ASSERT (slash != std::string::npos);
mathieu@3787
   475
  *root = path.substr (0, slash);
mathieu@3787
   476
  *leaf = path.substr (slash+1, path.size ()-(slash+1));
mathieu@3787
   477
  NS_LOG_FUNCTION (path << *root << *leaf);
mathieu@3787
   478
}
mathieu@3787
   479
mathieu@3787
   480
void 
mathieu@2965
   481
ConfigImpl::Set (std::string path, const AttributeValue &value)
mathieu@2474
   482
{
mathieu@3787
   483
  std::string root, leaf;
mathieu@3787
   484
  ParsePath (path, &root, &leaf);
mathieu@3787
   485
  Config::MatchContainer container = LookupMatches (root);
mathieu@3787
   486
  container.Set (leaf, value);
mathieu@3787
   487
}
mathieu@3787
   488
void 
mathieu@3787
   489
ConfigImpl::ConnectWithoutContext (std::string path, const CallbackBase &cb)
mathieu@3787
   490
{
mathieu@3787
   491
  std::string root, leaf;
mathieu@3787
   492
  ParsePath (path, &root, &leaf);
mathieu@3787
   493
  Config::MatchContainer container = LookupMatches (root);
mathieu@3787
   494
  container.ConnectWithoutContext (leaf, cb);
mathieu@3787
   495
}
mathieu@3787
   496
void 
mathieu@3787
   497
ConfigImpl::DisconnectWithoutContext (std::string path, const CallbackBase &cb)
mathieu@3787
   498
{
mathieu@3787
   499
  std::string root, leaf;
mathieu@3787
   500
  ParsePath (path, &root, &leaf);
mathieu@3787
   501
  Config::MatchContainer container = LookupMatches (root);
mathieu@3787
   502
  container.DisconnectWithoutContext (leaf, cb);
mathieu@3787
   503
}
mathieu@3787
   504
void 
mathieu@3787
   505
ConfigImpl::Connect (std::string path, const CallbackBase &cb)
mathieu@3787
   506
{
mathieu@3787
   507
  std::string root, leaf;
mathieu@3787
   508
  ParsePath (path, &root, &leaf);
mathieu@3787
   509
  Config::MatchContainer container = LookupMatches (root);
mathieu@3787
   510
  container.Connect (leaf, cb);
mathieu@3787
   511
}
mathieu@3787
   512
void 
mathieu@3787
   513
ConfigImpl::Disconnect (std::string path, const CallbackBase &cb)
mathieu@3787
   514
{
mathieu@3787
   515
  std::string root, leaf;
mathieu@3787
   516
  ParsePath (path, &root, &leaf);
mathieu@3787
   517
  Config::MatchContainer container = LookupMatches (root);
mathieu@3787
   518
  container.Disconnect (leaf, cb);
mathieu@3787
   519
}
mathieu@3787
   520
mathieu@3787
   521
Config::MatchContainer 
mathieu@3787
   522
ConfigImpl::LookupMatches (std::string path)
mathieu@3787
   523
{
mathieu@3787
   524
  NS_LOG_FUNCTION (path);
mathieu@3787
   525
  class LookupMatchesResolver : public Resolver 
mathieu@2474
   526
  {
mathieu@2474
   527
  public:
mathieu@3787
   528
    LookupMatchesResolver (std::string path)
mathieu@3787
   529
      : Resolver (path)
mathieu@3787
   530
    {}
mathieu@3787
   531
    virtual void DoOne (Ptr<Object> object, std::string path) {
mathieu@3787
   532
      m_objects.push_back (object);
mathieu@3787
   533
      m_contexts.push_back (path);
mathieu@2474
   534
    }
mathieu@3787
   535
    std::vector<Ptr<Object> > m_objects;
mathieu@3787
   536
    std::vector<std::string> m_contexts;
mathieu@3787
   537
  } resolver = LookupMatchesResolver (path);
mathieu@2474
   538
  for (Roots::const_iterator i = m_roots.begin (); i != m_roots.end (); i++)
mathieu@2474
   539
    {
mathieu@2474
   540
      resolver.Resolve (*i);
mathieu@2474
   541
    }
craigdo@4139
   542
craigdo@4139
   543
  //
craigdo@4139
   544
  // See if we can do something with the object name service.  Starting with
craigdo@4139
   545
  // the root pointer zeroed indicates to the resolver that it should start
craigdo@4139
   546
  // looking at the root of the "/Names" namespace during this go.
craigdo@4139
   547
  //
craigdo@4139
   548
  resolver.Resolve (0);
craigdo@4139
   549
mathieu@3787
   550
  return Config::MatchContainer (resolver.m_objects, resolver.m_contexts, path);
mathieu@2474
   551
}
mathieu@3787
   552
mathieu@2569
   553
void 
mathieu@2474
   554
ConfigImpl::RegisterRootNamespaceObject (Ptr<Object> obj)
mathieu@2474
   555
{
mathieu@2474
   556
  m_roots.push_back (obj);
mathieu@2474
   557
}
mathieu@2474
   558
mathieu@2474
   559
void 
mathieu@2474
   560
ConfigImpl::UnregisterRootNamespaceObject (Ptr<Object> obj)
mathieu@2474
   561
{
mathieu@2474
   562
  for (std::vector<Ptr<Object> >::iterator i = m_roots.begin (); i != m_roots.end (); i++)
mathieu@2474
   563
    {
mathieu@2474
   564
      if (*i == obj)
mathieu@2474
   565
	{
mathieu@2474
   566
	  m_roots.erase (i);
mathieu@2474
   567
	  return;
mathieu@2474
   568
	}
mathieu@2474
   569
    }
mathieu@2474
   570
}
mathieu@2474
   571
mathieu@2941
   572
uint32_t 
mathieu@2941
   573
ConfigImpl::GetRootNamespaceObjectN (void) const
mathieu@2941
   574
{
mathieu@2941
   575
  return m_roots.size ();
mathieu@2941
   576
}
mathieu@2941
   577
Ptr<Object> 
mathieu@2941
   578
ConfigImpl::GetRootNamespaceObject (uint32_t i) const
mathieu@2941
   579
{
mathieu@2941
   580
  return m_roots[i];
mathieu@2941
   581
}
mathieu@2474
   582
mathieu@2474
   583
namespace Config {
mathieu@2474
   584
mathieu@2965
   585
void Set (std::string path, const AttributeValue &value)
mathieu@2474
   586
{
mathieu@2474
   587
  Singleton<ConfigImpl>::Get ()->Set (path, value);
mathieu@2474
   588
}
mathieu@2965
   589
void SetDefault (std::string name, const AttributeValue &value)
mathieu@2474
   590
{
mathieu@2474
   591
  AttributeList::GetGlobal ()->Set (name, value);
mathieu@2474
   592
}
mathieu@2965
   593
bool SetDefaultFailSafe (std::string name, const AttributeValue &value)
mathieu@2570
   594
{
mathieu@2570
   595
  return AttributeList::GetGlobal ()->SetFailSafe (name, value);
mathieu@2570
   596
}
mathieu@2965
   597
void SetGlobal (std::string name, const AttributeValue &value)
mathieu@2474
   598
{
mathieu@2474
   599
  GlobalValue::Bind (name, value);
mathieu@2474
   600
}
mathieu@2965
   601
bool SetGlobalFailSafe (std::string name, const AttributeValue &value)
mathieu@2570
   602
{
mathieu@2570
   603
  return GlobalValue::BindFailSafe (name, value);
mathieu@2570
   604
}
mathieu@2594
   605
void ConnectWithoutContext (std::string path, const CallbackBase &cb)
mathieu@2594
   606
{
mathieu@2594
   607
  Singleton<ConfigImpl>::Get ()->ConnectWithoutContext (path, cb);
mathieu@2594
   608
}
mathieu@2594
   609
void DisconnectWithoutContext (std::string path, const CallbackBase &cb)
mathieu@2594
   610
{
mathieu@2594
   611
  Singleton<ConfigImpl>::Get ()->DisconnectWithoutContext (path, cb);
mathieu@2594
   612
}
mathieu@2594
   613
void 
mathieu@2594
   614
Connect (std::string path, const CallbackBase &cb)
mathieu@2474
   615
{
mathieu@2474
   616
  Singleton<ConfigImpl>::Get ()->Connect (path, cb);
mathieu@2474
   617
}
mathieu@2594
   618
void 
mathieu@2594
   619
Disconnect (std::string path, const CallbackBase &cb)
mathieu@2474
   620
{
mathieu@2474
   621
  Singleton<ConfigImpl>::Get ()->Disconnect (path, cb);
mathieu@2474
   622
}
mathieu@3787
   623
Config::MatchContainer LookupMatches (std::string path)
mathieu@3787
   624
{
mathieu@3787
   625
  return Singleton<ConfigImpl>::Get ()->LookupMatches (path);
mathieu@3787
   626
}
mathieu@2474
   627
mathieu@2474
   628
void RegisterRootNamespaceObject (Ptr<Object> obj)
mathieu@2474
   629
{
mathieu@2474
   630
  Singleton<ConfigImpl>::Get ()->RegisterRootNamespaceObject (obj);
mathieu@2474
   631
}
mathieu@2474
   632
mathieu@2532
   633
void UnregisterRootNamespaceObject (Ptr<Object> obj)
mathieu@2474
   634
{
mathieu@2474
   635
  Singleton<ConfigImpl>::Get ()->UnregisterRootNamespaceObject (obj);
mathieu@2474
   636
}
mathieu@2474
   637
mathieu@2941
   638
uint32_t GetRootNamespaceObjectN (void)
mathieu@2941
   639
{
mathieu@2941
   640
  return Singleton<ConfigImpl>::Get ()->GetRootNamespaceObjectN ();
mathieu@2941
   641
}
mathieu@2941
   642
mathieu@2941
   643
Ptr<Object> GetRootNamespaceObject (uint32_t i)
mathieu@2941
   644
{
mathieu@2941
   645
  return Singleton<ConfigImpl>::Get ()->GetRootNamespaceObject (i);
mathieu@2941
   646
}
mathieu@2941
   647
mathieu@2941
   648
mathieu@2474
   649
} // namespace Config
mathieu@2474
   650
mathieu@2474
   651
} // namespace ns3
mathieu@2474
   652
mathieu@2474
   653
#ifdef RUN_SELF_TESTS
mathieu@2474
   654
mathieu@2474
   655
#include "test.h"
mathieu@2474
   656
#include "integer.h"
mathieu@2504
   657
#include "traced-value.h"
mathieu@2504
   658
#include "trace-source-accessor.h"
mathieu@2504
   659
#include "callback.h"
mathieu@2474
   660
mathieu@2474
   661
namespace ns3 {
mathieu@2474
   662
mathieu@2474
   663
class MyNode : public Object
mathieu@2474
   664
{
mathieu@2474
   665
public:
mathieu@2474
   666
  static TypeId GetTypeId (void);
mathieu@2474
   667
mathieu@2474
   668
  void AddNodeA (Ptr<MyNode> a);
mathieu@2474
   669
  void AddNodeB (Ptr<MyNode> b);
mathieu@2474
   670
mathieu@2474
   671
  void SetNodeA (Ptr<MyNode> a);
mathieu@2474
   672
  void SetNodeB (Ptr<MyNode> b);
mathieu@2474
   673
mathieu@2474
   674
  int8_t GetA (void) const;
mathieu@2474
   675
  int8_t GetB (void) const;
mathieu@2474
   676
mathieu@2474
   677
private:
mathieu@2474
   678
  std::vector<Ptr<MyNode> > m_nodesA;
mathieu@2474
   679
  std::vector<Ptr<MyNode> > m_nodesB;
mathieu@2474
   680
  Ptr<MyNode> m_nodeA;
mathieu@2474
   681
  Ptr<MyNode> m_nodeB;
mathieu@2474
   682
  int8_t m_a;
mathieu@2474
   683
  int8_t m_b;
mathieu@2504
   684
  TracedValue<int16_t> m_trace;
mathieu@2474
   685
};
mathieu@2474
   686
mathieu@2474
   687
TypeId MyNode::GetTypeId (void)
mathieu@2474
   688
{
mathieu@2474
   689
  static TypeId tid = TypeId ("MyNode")
mathieu@2474
   690
    .SetParent<Object> ()
mathieu@2474
   691
    .AddAttribute ("NodesA", "",
mathieu@2965
   692
		   ObjectVectorValue (),
mathieu@2474
   693
		   MakeObjectVectorAccessor (&MyNode::m_nodesA),
mathieu@2933
   694
		   MakeObjectVectorChecker<MyNode> ())
mathieu@2474
   695
    .AddAttribute ("NodesB", "",
mathieu@2965
   696
		   ObjectVectorValue (),
mathieu@2474
   697
		   MakeObjectVectorAccessor (&MyNode::m_nodesB),
mathieu@2933
   698
		   MakeObjectVectorChecker<MyNode> ())
mathieu@2474
   699
    .AddAttribute ("NodeA", "",
mathieu@2965
   700
                   PointerValue (),
mathieu@2927
   701
		   MakePointerAccessor (&MyNode::m_nodeA),
mathieu@2927
   702
		   MakePointerChecker<MyNode> ())
mathieu@2474
   703
    .AddAttribute ("NodeB", "",
mathieu@2965
   704
                   PointerValue (),
mathieu@2927
   705
		   MakePointerAccessor (&MyNode::m_nodeB),
mathieu@2927
   706
		   MakePointerChecker<MyNode> ())
mathieu@2474
   707
    .AddAttribute ("A", "",
mathieu@2965
   708
		   IntegerValue (10),
mathieu@2474
   709
		   MakeIntegerAccessor (&MyNode::m_a),
mathieu@2474
   710
		   MakeIntegerChecker<int8_t> ())
mathieu@2474
   711
    .AddAttribute ("B", "",
mathieu@2965
   712
		   IntegerValue (9),
mathieu@2474
   713
		   MakeIntegerAccessor (&MyNode::m_b),
mathieu@2474
   714
		   MakeIntegerChecker<int8_t> ())
mathieu@2504
   715
    .AddAttribute ("Source", "XX",
mathieu@2965
   716
		   IntegerValue (-1),
mathieu@2504
   717
		   MakeIntegerAccessor (&MyNode::m_trace),
mathieu@2504
   718
		   MakeIntegerChecker<int16_t> ())
mathieu@2504
   719
    .AddTraceSource ("Source", "XX",
mathieu@2504
   720
		     MakeTraceSourceAccessor (&MyNode::m_trace))
mathieu@2474
   721
    ;
mathieu@2474
   722
  return tid;
mathieu@2474
   723
}
mathieu@2474
   724
mathieu@2474
   725
void
mathieu@2474
   726
MyNode::SetNodeA (Ptr<MyNode> a)
mathieu@2474
   727
{
mathieu@2474
   728
  m_nodeA = a;
mathieu@2474
   729
}
mathieu@2474
   730
void
mathieu@2474
   731
MyNode::SetNodeB (Ptr<MyNode> b)
mathieu@2474
   732
{
mathieu@2474
   733
  m_nodeB = b;
mathieu@2474
   734
}
mathieu@2474
   735
void 
mathieu@2474
   736
MyNode::AddNodeA (Ptr<MyNode> a)
mathieu@2474
   737
{
mathieu@2474
   738
  m_nodesA.push_back (a);
mathieu@2474
   739
}
mathieu@2474
   740
void 
mathieu@2474
   741
MyNode::AddNodeB (Ptr<MyNode> b)
mathieu@2474
   742
{
mathieu@2474
   743
  m_nodesB.push_back (b);
mathieu@2474
   744
}
mathieu@2474
   745
int8_t 
mathieu@2474
   746
MyNode::GetA (void) const
mathieu@2474
   747
{
mathieu@2474
   748
  return m_a;
mathieu@2474
   749
}
mathieu@2474
   750
int8_t 
mathieu@2474
   751
MyNode::GetB (void) const
mathieu@2474
   752
{
mathieu@2474
   753
  return m_b;
mathieu@2474
   754
}
mathieu@2474
   755
mathieu@2474
   756
mathieu@2474
   757
class ConfigTest : public Test
mathieu@2474
   758
{
mathieu@2474
   759
public:
mathieu@2474
   760
  ConfigTest ();
mathieu@2474
   761
  virtual bool RunTests (void);
mathieu@2504
   762
private:
mathieu@2504
   763
  void ChangeNotification (int16_t old, int16_t newValue);
mathieu@2531
   764
  void ChangeNotificationWithPath (std::string path, int16_t old, int16_t newValue);
mathieu@2504
   765
  int16_t m_traceNotification;
mathieu@2531
   766
  std::string m_tracePath;
mathieu@2474
   767
};
mathieu@2474
   768
mathieu@2474
   769
static ConfigTest g_configTestUnique;
mathieu@2474
   770
mathieu@2474
   771
ConfigTest::ConfigTest ()
mathieu@2474
   772
  : Test ("Config")
mathieu@2474
   773
{}
mathieu@2474
   774
mathieu@2504
   775
void
mathieu@2504
   776
ConfigTest::ChangeNotification (int16_t oldValue, int16_t newValue)
mathieu@2504
   777
{
mathieu@2504
   778
  m_traceNotification = newValue;
mathieu@2504
   779
}
mathieu@2504
   780
mathieu@2531
   781
void 
mathieu@2531
   782
ConfigTest::ChangeNotificationWithPath (std::string path, int16_t old, int16_t newValue)
mathieu@2531
   783
{
mathieu@2531
   784
  m_traceNotification = newValue;
mathieu@2531
   785
  m_tracePath = path;
mathieu@2531
   786
}
mathieu@2531
   787
mathieu@2474
   788
bool
mathieu@2474
   789
ConfigTest::RunTests (void)
mathieu@2474
   790
{
mathieu@2474
   791
  bool result = true;
mathieu@2474
   792
mathieu@2474
   793
  Ptr<MyNode> root = CreateObject<MyNode> ();
mathieu@2474
   794
  Config::RegisterRootNamespaceObject (root);
mathieu@2965
   795
  Config::Set ("/A", IntegerValue (1));
mathieu@2965
   796
  Config::Set ("/B", IntegerValue (-1));
mathieu@2965
   797
  IntegerValue v;
mathieu@2965
   798
  root->GetAttribute ("A", v);
mathieu@2474
   799
  NS_TEST_ASSERT_EQUAL (v.Get (), 1);
mathieu@2965
   800
  root->GetAttribute ("B", v);
mathieu@2474
   801
  NS_TEST_ASSERT_EQUAL (v.Get (), -1);
mathieu@2474
   802
mathieu@2474
   803
  Ptr<MyNode> a = CreateObject<MyNode> ();
mathieu@2474
   804
  root->SetNodeA (a);
mathieu@2965
   805
  Config::Set ("/NodeA/A", IntegerValue (2));
mathieu@2965
   806
  Config::Set ("/NodeA/B", IntegerValue (-2));
mathieu@2965
   807
  a->GetAttribute ("A", v);
mathieu@2474
   808
  NS_TEST_ASSERT_EQUAL (v.Get (), 2);
mathieu@2965
   809
  a->GetAttribute ("B", v);
mathieu@2474
   810
  NS_TEST_ASSERT_EQUAL (v.Get (), -2);
mathieu@2965
   811
  Config::Set ("/NodeB/A", IntegerValue (3));
mathieu@2965
   812
  Config::Set ("/NodeB/B", IntegerValue (-3));
mathieu@2965
   813
  a->GetAttribute ("A", v);
mathieu@2474
   814
  NS_TEST_ASSERT_EQUAL (v.Get (), 2);
mathieu@2965
   815
  a->GetAttribute ("B", v);
mathieu@2474
   816
  NS_TEST_ASSERT_EQUAL (v.Get (), -2);
mathieu@2474
   817
mathieu@2474
   818
  Ptr<MyNode> b = CreateObject<MyNode> ();
mathieu@2474
   819
  a->SetNodeB (b);
mathieu@2965
   820
  Config::Set ("/NodeA/NodeB/A", IntegerValue (4));
mathieu@2965
   821
  Config::Set ("/NodeA/NodeB/B", IntegerValue (-4));
mathieu@2965
   822
  b->GetAttribute ("A", v);
mathieu@2474
   823
  NS_TEST_ASSERT_EQUAL (v.Get (), 4);
mathieu@2965
   824
  b->GetAttribute ("B", v);
mathieu@2474
   825
  NS_TEST_ASSERT_EQUAL (v.Get (), -4);
mathieu@2474
   826
mathieu@2474
   827
  Ptr<MyNode> c = CreateObject<MyNode> ();
mathieu@2474
   828
  root->SetNodeB (c);
mathieu@2965
   829
  Config::Set ("/NodeB/A", IntegerValue (5));
mathieu@2965
   830
  Config::Set ("/NodeB/B", IntegerValue (-5));
mathieu@2965
   831
  c->GetAttribute ("A", v);
mathieu@2474
   832
  NS_TEST_ASSERT_EQUAL (v.Get (), 5);
mathieu@2965
   833
  c->GetAttribute ("B", v);
mathieu@2474
   834
  NS_TEST_ASSERT_EQUAL (v.Get (), -5);
mathieu@2474
   835
mathieu@2474
   836
mathieu@2474
   837
  Ptr<MyNode> d0 = CreateObject<MyNode> ();
mathieu@2474
   838
  Ptr<MyNode> d1 = CreateObject<MyNode> ();
mathieu@2474
   839
  Ptr<MyNode> d2 = CreateObject<MyNode> ();
mathieu@2474
   840
  Ptr<MyNode> d3 = CreateObject<MyNode> ();
mathieu@2474
   841
  b->AddNodeB (d0);
mathieu@2474
   842
  b->AddNodeB (d1);
mathieu@2474
   843
  b->AddNodeB (d2);
mathieu@2474
   844
  b->AddNodeB (d3);
mathieu@2965
   845
  Config::Set ("/NodeA/NodeB/NodesB/0/A", IntegerValue (-11));
mathieu@2965
   846
  d0->GetAttribute ("A", v);
mathieu@2474
   847
  NS_TEST_ASSERT_EQUAL (v.Get (), -11);
mathieu@2965
   848
  d0->GetAttribute ("B", v);
mathieu@2474
   849
  NS_TEST_ASSERT_EQUAL (v.Get (), 9);
mathieu@2965
   850
  d1->GetAttribute ("A", v);
mathieu@2474
   851
  NS_TEST_ASSERT_EQUAL (v.Get (), 10);
mathieu@2965
   852
  d1->GetAttribute ("B", v);
mathieu@2474
   853
  NS_TEST_ASSERT_EQUAL (v.Get (), 9);
mathieu@2965
   854
  Config::Set ("/NodeA/NodeB/NodesB/0|1/A", IntegerValue (-12));
mathieu@2965
   855
  d0->GetAttribute ("A", v);
mathieu@2474
   856
  NS_TEST_ASSERT_EQUAL (v.Get (), -12);
mathieu@2965
   857
  d1->GetAttribute ("A", v);
mathieu@2474
   858
  NS_TEST_ASSERT_EQUAL (v.Get (), -12);
mathieu@2965
   859
  Config::Set ("/NodeA/NodeB/NodesB/|0|1|/A", IntegerValue (-13));
mathieu@2965
   860
  d0->GetAttribute ("A", v);
mathieu@2474
   861
  NS_TEST_ASSERT_EQUAL (v.Get (), -13);
mathieu@2965
   862
  d1->GetAttribute ("A", v);
mathieu@2474
   863
  NS_TEST_ASSERT_EQUAL (v.Get (), -13);
mathieu@2965
   864
  Config::Set ("/NodeA/NodeB/NodesB/[0-2]/A", IntegerValue (-14));
mathieu@2965
   865
  d0->GetAttribute ("A", v);
mathieu@2474
   866
  NS_TEST_ASSERT_EQUAL (v.Get (), -14);
mathieu@2965
   867
  d1->GetAttribute ("A", v);
mathieu@2474
   868
  NS_TEST_ASSERT_EQUAL (v.Get (), -14);
mathieu@2965
   869
  d2->GetAttribute ("A", v);
mathieu@2474
   870
  NS_TEST_ASSERT_EQUAL (v.Get (), -14);
mathieu@2965
   871
  Config::Set ("/NodeA/NodeB/NodesB/[1-3]/A", IntegerValue (-15));
mathieu@2965
   872
  d0->GetAttribute ("A", v);
mathieu@2474
   873
  NS_TEST_ASSERT_EQUAL (v.Get (), -14);
mathieu@2965
   874
  d1->GetAttribute ("A", v);
mathieu@2474
   875
  NS_TEST_ASSERT_EQUAL (v.Get (), -15);
mathieu@2965
   876
  d2->GetAttribute ("A", v);
mathieu@2474
   877
  NS_TEST_ASSERT_EQUAL (v.Get (), -15);
mathieu@2965
   878
  d3->GetAttribute ("A", v);
mathieu@2474
   879
  NS_TEST_ASSERT_EQUAL (v.Get (), -15);
mathieu@2965
   880
  Config::Set ("/NodeA/NodeB/NodesB/[0-1]|3/A", IntegerValue (-16));
mathieu@2965
   881
  d0->GetAttribute ("A", v);
mathieu@2474
   882
  NS_TEST_ASSERT_EQUAL (v.Get (), -16);
mathieu@2965
   883
  d1->GetAttribute ("A", v);
mathieu@2479
   884
  NS_TEST_ASSERT_EQUAL (v.Get (), -16);
mathieu@2965
   885
  d2->GetAttribute ("A", v);
mathieu@2474
   886
  NS_TEST_ASSERT_EQUAL (v.Get (), -15);
mathieu@2965
   887
  d3->GetAttribute ("A", v);
mathieu@2475
   888
  NS_TEST_ASSERT_EQUAL (v.Get (), -16);
mathieu@2474
   889
mathieu@2474
   890
mathieu@2594
   891
  Config::ConnectWithoutContext ("/NodeA/NodeB/NodesB/[0-1]|3/Source", 
mathieu@2504
   892
		   MakeCallback (&ConfigTest::ChangeNotification, this));
mathieu@2504
   893
  m_traceNotification = 0;
mathieu@2504
   894
  // this should trigger no notification
mathieu@2965
   895
  d2->SetAttribute ("Source", IntegerValue (-2));
mathieu@2504
   896
  NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
mathieu@2504
   897
  m_traceNotification = 0;
mathieu@2504
   898
  // this should trigger a notification
mathieu@2965
   899
  d1->SetAttribute ("Source", IntegerValue (-3));
mathieu@2504
   900
  NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
mathieu@2594
   901
  Config::DisconnectWithoutContext ("/NodeA/NodeB/NodesB/[0-1]|3/Source", 
mathieu@2504
   902
		      MakeCallback (&ConfigTest::ChangeNotification, this));
mathieu@2504
   903
  m_traceNotification = 0;
mathieu@2504
   904
  // this should _not_ trigger a notification
mathieu@2965
   905
  d1->SetAttribute ("Source", IntegerValue (-4));
mathieu@2504
   906
  NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
mathieu@2504
   907
mathieu@2531
   908
  
mathieu@2594
   909
  Config::Connect ("/NodeA/NodeB/NodesB/[0-1]|3/Source", 
mathieu@2531
   910
			      MakeCallback (&ConfigTest::ChangeNotificationWithPath, this));
mathieu@2531
   911
  m_traceNotification = 0;
mathieu@2531
   912
  // this should trigger no notification
mathieu@2965
   913
  d2->SetAttribute ("Source", IntegerValue (-2));
mathieu@2531
   914
  NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
mathieu@2531
   915
  m_traceNotification = 0;
mathieu@2531
   916
  m_tracePath = "";
mathieu@2531
   917
  // this should trigger a notification
mathieu@2965
   918
  d1->SetAttribute ("Source", IntegerValue (-3));
mathieu@2531
   919
  NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
mathieu@3033
   920
  NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/1/Source");
mathieu@2531
   921
  m_traceNotification = 0;
mathieu@2531
   922
  m_tracePath = "";
mathieu@2531
   923
  // this should trigger a notification
mathieu@2965
   924
  d3->SetAttribute ("Source", IntegerValue (-3));
mathieu@2531
   925
  NS_TEST_ASSERT_EQUAL (m_traceNotification, -3);
mathieu@2531
   926
  NS_TEST_ASSERT_EQUAL (m_tracePath, "/NodeA/NodeB/NodesB/3/Source");
mathieu@2594
   927
  Config::Disconnect ("/NodeA/NodeB/NodesB/[0-1]|3/Source", 
mathieu@2569
   928
				 MakeCallback (&ConfigTest::ChangeNotificationWithPath, this));
mathieu@2531
   929
  m_traceNotification = 0;
mathieu@2531
   930
  // this should _not_ trigger a notification
mathieu@2965
   931
  d1->SetAttribute ("Source", IntegerValue (-4));
mathieu@2531
   932
  NS_TEST_ASSERT_EQUAL (m_traceNotification, 0);
mathieu@2531
   933
craigdo@4145
   934
  //
craigdo@4145
   935
  // The Config system is intertwined with the Names system.  In the process
craigdo@4145
   936
  // of parsing the paths above, we also created a NamesPriv singleton.  In
craigdo@4145
   937
  // order to get a valgrind-clean run we need to clean up that singleton.
craigdo@4145
   938
  //
craigdo@4145
   939
  Names::Delete ();
mathieu@2474
   940
mathieu@2474
   941
  return result;
mathieu@2474
   942
}
mathieu@2474
   943
mathieu@2474
   944
} // namespace ns3
mathieu@2474
   945
mathieu@2474
   946
mathieu@2474
   947
#endif /* RUN_SELF_TEST */